From 52a243afcabde3ccc375aaf6e79a9f50c046f54b Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Wed, 25 Aug 2021 21:42:15 +0300 Subject: [PATCH 0001/2686] Don't select random beatmap when previous was filtered --- .../SongSelect/TestSceneBeatmapCarousel.cs | 99 +++++++++++-------- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- .../Carousel/CarouselGroupEagerSelect.cs | 25 ++++- 3 files changed, 82 insertions(+), 44 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 78ddfa9ed2..f42ff3811a 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -616,55 +616,72 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1); } - [Test] - public void TestRandomFallbackOnNonMatchingPrevious() + [TestCase(10, 1)] + [TestCase(10, 10)] + public void TestCarouselSelectsNextWhenPreviousIsFiltered(int makeThisManyGroups, int haveThisManySetsInGroup) { - List manySets = new List(); + List sets = new List(); - AddStep("populate maps", () => + for (int i = 0; i < makeThisManyGroups; i++) { - for (int i = 0; i < 10; i++) + for (int j = 0; j < haveThisManySetsInGroup; j++) { - var set = createTestBeatmapSet(i); - - foreach (var b in set.Beatmaps) + var testBeatmap = createTestBeatmapSet(i * haveThisManySetsInGroup + j + 1); + var rulesetID = i % 3; + testBeatmap.Beatmaps.ForEach(b => { - // all taiko except for first - int ruleset = i > 0 ? 1 : 0; - - b.Ruleset = rulesets.GetRuleset(ruleset); - b.RulesetID = ruleset; - } - - manySets.Add(set); + b.Ruleset = rulesets.AvailableRulesets.ElementAt(rulesetID); + b.RulesetID = rulesetID; + }); + sets.Add(testBeatmap); } - }); - - loadBeatmaps(manySets); - - for (int i = 0; i < 10; i++) - { - AddStep("Reset filter", () => carousel.Filter(new FilterCriteria(), false)); - - AddStep("select first beatmap", () => carousel.SelectBeatmap(manySets.First().Beatmaps.First())); - - AddStep("Toggle non-matching filter", () => - { - carousel.Filter(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }, false); - }); - - AddAssert("selection lost", () => carousel.SelectedBeatmap == null); - - AddStep("Restore different ruleset filter", () => - { - carousel.Filter(new FilterCriteria { Ruleset = rulesets.GetRuleset(1) }, false); - eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID); - }); - - AddAssert("selection changed", () => carousel.SelectedBeatmap != manySets.First().Beatmaps.First()); } - AddAssert("Selection was random", () => eagerSelectedIDs.Count > 2); + loadBeatmaps(sets); + setSelected(1, 1); + advanceSelection(false); + + for (int i = 1; i < makeThisManyGroups; i++) + { + var rulesetID = i % 3; + AddStep($"Toggle filter to ruleset {rulesetID}", () => + { + carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(rulesetID) }, false); + carousel.Filter(new FilterCriteria(), false); + }); + waitForSelection(i * haveThisManySetsInGroup + 1); + } + } + + [Test] + public void TestCarouselSelectsBackwardsWhenPreviousIsFilteredNearTheEnd() + { + List sets = new List(); + + for (int i = 1; i <= 40; i++) + { + var testBeatmap = createTestBeatmapSet(i); + var rulesetID = (i - 1) / 10; + testBeatmap.Beatmaps.ForEach(b => + { + b.Ruleset = rulesets.AvailableRulesets.ElementAt(rulesetID); + b.RulesetID = rulesetID; + }); + sets.Add(testBeatmap); + } + + loadBeatmaps(sets); + + for (int i = 1; i < 4; i++) + { + setSelected(i * 10 + 1, 1); + AddStep("Toggle filter to ruleset 0", () => + { + carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false); + carousel.Filter(new FilterCriteria(), false); + }); + waitForSelection(10); + } } [Test] diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index b05b7aeb32..7c1403da82 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -911,7 +911,7 @@ namespace osu.Game.Screens.Select protected override void PerformSelection() { - if (LastSelected == null || LastSelected.Filtered.Value) + if (LastSelected == null) carousel?.SelectNextRandom(); else base.PerformSelection(); diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs index 9e8aad4b6f..79bcdbf1c1 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs @@ -101,8 +101,29 @@ namespace osu.Game.Screens.Select.Carousel protected virtual CarouselItem GetNextToSelect() { - return Children.Skip(lastSelectedIndex).FirstOrDefault(i => !i.Filtered.Value) ?? - Children.Reverse().Skip(InternalChildren.Count - lastSelectedIndex).FirstOrDefault(i => !i.Filtered.Value); + // our return value should be the item (that is not filtered and) that is nearest to the previously selected one + + // find nearest such item going forwards in selection + int forwardsDistance = 0; + var forwards = Children.Skip(lastSelectedIndex).SkipWhile((c) => + { + forwardsDistance++; + return c.Filtered.Value; + }).FirstOrDefault(); + // and backwards + int backwardsDistance = 0; + var backwards = Children.Reverse().Skip(InternalChildren.Count - lastSelectedIndex - 1).SkipWhile((c) => + { + backwardsDistance++; + return c.Filtered.Value; + }).FirstOrDefault(); + + // if only one direction had such an item, return that + if (forwards == null || backwards == null) + return forwards ?? backwards; + + // else return the closest item + return forwardsDistance < backwardsDistance ? forwards : backwards; } protected virtual void PerformSelection() From b484bd1af3ab2e49387d4eb9bb6f09b86b035cdf Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Wed, 25 Aug 2021 22:43:58 +0300 Subject: [PATCH 0002/2686] Rename parameter and remove redundant parentheses --- .../Screens/Select/Carousel/CarouselGroupEagerSelect.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs index 79bcdbf1c1..2894209206 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs @@ -105,17 +105,17 @@ namespace osu.Game.Screens.Select.Carousel // find nearest such item going forwards in selection int forwardsDistance = 0; - var forwards = Children.Skip(lastSelectedIndex).SkipWhile((c) => + var forwards = Children.Skip(lastSelectedIndex).SkipWhile(item => { forwardsDistance++; - return c.Filtered.Value; + return item.Filtered.Value; }).FirstOrDefault(); // and backwards int backwardsDistance = 0; - var backwards = Children.Reverse().Skip(InternalChildren.Count - lastSelectedIndex - 1).SkipWhile((c) => + var backwards = Children.Reverse().Skip(InternalChildren.Count - lastSelectedIndex - 1).SkipWhile(item => { backwardsDistance++; - return c.Filtered.Value; + return item.Filtered.Value; }).FirstOrDefault(); // if only one direction had such an item, return that From a8d869c31cace6e8b47bda6f972459b07af50119 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Thu, 26 Aug 2021 18:31:19 +0300 Subject: [PATCH 0003/2686] Replace `SkipWhile()` LINQ with a while loop --- .../Carousel/CarouselGroupEagerSelect.cs | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs index 2894209206..aedeac04d3 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs @@ -99,31 +99,32 @@ namespace osu.Game.Screens.Select.Carousel PerformSelection(); } + /// + /// Finds the item this group would select next if it attempted selection + /// + /// An unfiltered item nearest to the last selected one or null if all items are filtered protected virtual CarouselItem GetNextToSelect() { - // our return value should be the item (that is not filtered and) that is nearest to the previously selected one + int forwardsIndex = lastSelectedIndex; + int backwardsIndex = lastSelectedIndex; - // find nearest such item going forwards in selection - int forwardsDistance = 0; - var forwards = Children.Skip(lastSelectedIndex).SkipWhile(item => + while (true) { - forwardsDistance++; - return item.Filtered.Value; - }).FirstOrDefault(); - // and backwards - int backwardsDistance = 0; - var backwards = Children.Reverse().Skip(InternalChildren.Count - lastSelectedIndex - 1).SkipWhile(item => - { - backwardsDistance++; - return item.Filtered.Value; - }).FirstOrDefault(); + if (forwardsIndex >= Children.Count) + return Children.Reverse().Skip(Children.Count - backwardsIndex).FirstOrDefault(item => !item.Filtered.Value); - // if only one direction had such an item, return that - if (forwards == null || backwards == null) - return forwards ?? backwards; + if (backwardsIndex < 0) + return Children.Skip(forwardsIndex).FirstOrDefault(item => !item.Filtered.Value); - // else return the closest item - return forwardsDistance < backwardsDistance ? forwards : backwards; + if (!Children[forwardsIndex].Filtered.Value) + return Children[forwardsIndex]; + + if (!Children[backwardsIndex].Filtered.Value) + return Children[backwardsIndex]; + + forwardsIndex++; + backwardsIndex--; + } } protected virtual void PerformSelection() From 8bd7837bf747600e67ffdc8f06062b847e10cd20 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Thu, 26 Aug 2021 19:29:58 +0300 Subject: [PATCH 0004/2686] Fix off-by-one skip amount --- osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs index aedeac04d3..9793b69eca 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs @@ -111,7 +111,7 @@ namespace osu.Game.Screens.Select.Carousel while (true) { if (forwardsIndex >= Children.Count) - return Children.Reverse().Skip(Children.Count - backwardsIndex).FirstOrDefault(item => !item.Filtered.Value); + return Children.Reverse().Skip(Children.Count - backwardsIndex - 1).FirstOrDefault(item => !item.Filtered.Value); if (backwardsIndex < 0) return Children.Skip(forwardsIndex).FirstOrDefault(item => !item.Filtered.Value); From 43e8e3e9229cef1d5ac72203d8e71c0f7584c49f Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Fri, 27 Aug 2021 18:16:53 +0300 Subject: [PATCH 0005/2686] Add comments to `GetNextToSelect()` --- osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs index 9793b69eca..cdd6d48e66 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs @@ -110,18 +110,19 @@ namespace osu.Game.Screens.Select.Carousel while (true) { + // check if a direction has been exhausted and an item (or null) from the other direction should be returned if (forwardsIndex >= Children.Count) return Children.Reverse().Skip(Children.Count - backwardsIndex - 1).FirstOrDefault(item => !item.Filtered.Value); - if (backwardsIndex < 0) return Children.Skip(forwardsIndex).FirstOrDefault(item => !item.Filtered.Value); + // check if an unfiltered item has been reached if (!Children[forwardsIndex].Filtered.Value) return Children[forwardsIndex]; - if (!Children[backwardsIndex].Filtered.Value) return Children[backwardsIndex]; + // increment the indices forwardsIndex++; backwardsIndex--; } From 05b44f5df46697ef6989ad1cb5e934e85b734478 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Thu, 18 Nov 2021 09:55:04 +1100 Subject: [PATCH 0006/2686] Add slider bonus to Flashlight skill --- .../Difficulty/Skills/Flashlight.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 466f0556ab..53634e9125 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -24,6 +24,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double DecayWeight => 1.0; protected override int HistoryLength => 10; // Look back for 10 notes is added for the sake of flashlight calculations. + private const double min_velocity = 0.5; + private const double slider_multiplier = 2.5; + private double currentStrain; private double strainValueOf(DifficultyHitObject current) @@ -62,7 +65,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills } } - return Math.Pow(smallDistNerf * result, 2.0); + result = Math.Pow(smallDistNerf * result, 2.0); + + double sliderBonus = 0.0; + if (osuCurrent.TravelTime != 0) + { + // Reward sliders based on velocity. + double normalisedTravelDistance = osuCurrent.TravelDistance / scalingFactor; + sliderBonus = Math.Max(0.0, (normalisedTravelDistance) / osuCurrent.TravelTime - min_velocity); + // Longer sliders require more memorisation. + sliderBonus *= normalisedTravelDistance; + } + + result += sliderBonus * slider_multiplier; + + return result; } private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); From a77a9a2309ae0068c4a50689981959a85a8f8cf8 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Thu, 18 Nov 2021 10:13:25 +1100 Subject: [PATCH 0007/2686] Balancing slider bonus --- osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 53634e9125..29ad7b2911 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override int HistoryLength => 10; // Look back for 10 notes is added for the sake of flashlight calculations. private const double min_velocity = 0.5; - private const double slider_multiplier = 2.5; + private const double slider_multiplier = 1.3; private double currentStrain; @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills { // Reward sliders based on velocity. double normalisedTravelDistance = osuCurrent.TravelDistance / scalingFactor; - sliderBonus = Math.Max(0.0, (normalisedTravelDistance) / osuCurrent.TravelTime - min_velocity); + sliderBonus = Math.Pow(Math.Max(0.0, (normalisedTravelDistance) / osuCurrent.TravelTime - min_velocity), 0.5); // Longer sliders require more memorisation. sliderBonus *= normalisedTravelDistance; } From e42f28990b6db55357ca95fab01b192e9a91de73 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Thu, 18 Nov 2021 10:30:17 +1100 Subject: [PATCH 0008/2686] Add blank line --- osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 29ad7b2911..c926222875 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -68,6 +68,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills result = Math.Pow(smallDistNerf * result, 2.0); double sliderBonus = 0.0; + if (osuCurrent.TravelTime != 0) { // Reward sliders based on velocity. From b77e6f92b741a20adfd539d8fdbaf183fcbe8d13 Mon Sep 17 00:00:00 2001 From: StanR Date: Wed, 19 Jan 2022 22:31:11 +0300 Subject: [PATCH 0009/2686] Fix touch device difficulty reduction not affecting star rating --- .../Difficulty/OsuDifficultyCalculator.cs | 4 ++++ .../Difficulty/OsuPerformanceCalculator.cs | 7 +------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index c5b1baaad1..537d63356b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -40,6 +40,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; + if (mods.Any(m => m is OsuModTouchDevice)) + aimRating = Math.Pow(aimRating, 0.8); + if (mods.Any(h => h is OsuModRelax)) speedRating = 0.0; @@ -120,6 +123,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty protected override Mod[] DifficultyAdjustmentMods => new Mod[] { + new OsuModTouchDevice(), new OsuModDoubleTime(), new OsuModHalfTime(), new OsuModEasy(), diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 604ab73454..07be3571f6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -84,12 +84,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double computeAimValue() { - double rawAim = Attributes.AimDifficulty; - - if (mods.Any(m => m is OsuModTouchDevice)) - rawAim = Math.Pow(rawAim, 0.8); - - double aimValue = Math.Pow(5.0 * Math.Max(1.0, rawAim / 0.0675) - 4.0, 3.0) / 100000.0; + double aimValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.AimDifficulty / 0.0675) - 4.0, 3.0) / 100000.0; double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); From e3ba7d9ba56c334b2fe815ca1d15e59539bd9f65 Mon Sep 17 00:00:00 2001 From: mk-56 Date: Mon, 24 Jan 2022 10:24:40 +0100 Subject: [PATCH 0010/2686] Wiggle mod expansion Free dlc! --- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 31 ++++++++++++++++------ 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index ff6ba6e121..e0b09213b7 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -2,8 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; @@ -22,8 +24,21 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform) }; - private const int wiggle_duration = 90; // (ms) Higher = fewer wiggles - private const int wiggle_strength = 10; // Higher = stronger wiggles + [SettingSource("Wiggle strength", "something")] + public BindableDouble WiggleStrength { get; } = new BindableDouble(10) + { + MinValue = 1f, + MaxValue = 15f, + Precision = .5f + }; + + [SettingSource("Wiggle duration", "milliseconds per wiggle")] + public BindableInt WiggleDuration { get; } = new BindableInt(90) + { + MinValue = 40, + MaxValue = 300, + Precision = 5 + }; protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => drawableOnApplyCustomUpdateState(hitObject, state); @@ -42,18 +57,18 @@ namespace osu.Game.Rulesets.Osu.Mods Random objRand = new Random((int)osuObject.StartTime); // Wiggle all objects during TimePreempt - int amountWiggles = (int)osuObject.TimePreempt / wiggle_duration; + int amountWiggles = (int)osuObject.TimePreempt / WiggleDuration.Value; void wiggle() { float nextAngle = (float)(objRand.NextDouble() * 2 * Math.PI); - float nextDist = (float)(objRand.NextDouble() * wiggle_strength); - drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), wiggle_duration); + float nextDist = (float)(objRand.NextDouble() * WiggleStrength.Value); + drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), WiggleDuration.Value); } for (int i = 0; i < amountWiggles; i++) { - using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * wiggle_duration)) + using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * WiggleDuration.Value)) wiggle(); } @@ -61,11 +76,11 @@ namespace osu.Game.Rulesets.Osu.Mods if (!(osuObject is IHasDuration endTime)) return; - amountWiggles = (int)(endTime.Duration / wiggle_duration); + amountWiggles = (int)(endTime.Duration / WiggleDuration.Value); for (int i = 0; i < amountWiggles; i++) { - using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * wiggle_duration)) + using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * WiggleDuration.Value)) wiggle(); } } From a427e20090fc6ea3a3161f1f90bfa3df35bcf9ef Mon Sep 17 00:00:00 2001 From: mk-56 Date: Mon, 24 Jan 2022 10:38:11 +0100 Subject: [PATCH 0011/2686] Fixes --- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index e0b09213b7..7116ee819c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform) }; - [SettingSource("Wiggle strength", "something")] + [SettingSource("Strength")] public BindableDouble WiggleStrength { get; } = new BindableDouble(10) { MinValue = 1f, @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Mods Precision = .5f }; - [SettingSource("Wiggle duration", "milliseconds per wiggle")] + [SettingSource("Duration", "Milliseconds per wiggle")] public BindableInt WiggleDuration { get; } = new BindableInt(90) { MinValue = 40, From 836cb1ee323416b71d2f649bfd725d098fa8dad9 Mon Sep 17 00:00:00 2001 From: mk-56 Date: Mon, 24 Jan 2022 12:16:29 +0100 Subject: [PATCH 0012/2686] Suggested boundary change --- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index 7116ee819c..10806318b0 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -25,11 +25,11 @@ namespace osu.Game.Rulesets.Osu.Mods public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform) }; [SettingSource("Strength")] - public BindableDouble WiggleStrength { get; } = new BindableDouble(10) + public BindableDouble WiggleStrength { get; } = new BindableDouble(1) { - MinValue = 1f, - MaxValue = 15f, - Precision = .5f + MinValue = .1f, + MaxValue = 2f, + Precision = .1f }; [SettingSource("Duration", "Milliseconds per wiggle")] @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Osu.Mods void wiggle() { float nextAngle = (float)(objRand.NextDouble() * 2 * Math.PI); - float nextDist = (float)(objRand.NextDouble() * WiggleStrength.Value); + float nextDist = (float)(objRand.NextDouble() * WiggleStrength.Value * 7); drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), WiggleDuration.Value); } From 35be0f24d02a5474b05b997526f662021311bb4d Mon Sep 17 00:00:00 2001 From: mk-56 Date: Thu, 27 Jan 2022 00:10:15 +0100 Subject: [PATCH 0013/2686] fixed leading "0"s not being present infront of decimal floats --- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index 10806318b0..853c974a04 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -27,9 +27,9 @@ namespace osu.Game.Rulesets.Osu.Mods [SettingSource("Strength")] public BindableDouble WiggleStrength { get; } = new BindableDouble(1) { - MinValue = .1f, + MinValue = 0.1f, MaxValue = 2f, - Precision = .1f + Precision = 0.1f }; [SettingSource("Duration", "Milliseconds per wiggle")] From dd8fc710fafc1319bb16613f056b3cf9285d4308 Mon Sep 17 00:00:00 2001 From: mk-56 Date: Fri, 4 Feb 2022 15:48:46 +0100 Subject: [PATCH 0014/2686] removed wiggle duration --- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index 853c974a04..fae9d785fb 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -31,15 +31,6 @@ namespace osu.Game.Rulesets.Osu.Mods MaxValue = 2f, Precision = 0.1f }; - - [SettingSource("Duration", "Milliseconds per wiggle")] - public BindableInt WiggleDuration { get; } = new BindableInt(90) - { - MinValue = 40, - MaxValue = 300, - Precision = 5 - }; - protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => drawableOnApplyCustomUpdateState(hitObject, state); protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => drawableOnApplyCustomUpdateState(hitObject, state); @@ -57,18 +48,18 @@ namespace osu.Game.Rulesets.Osu.Mods Random objRand = new Random((int)osuObject.StartTime); // Wiggle all objects during TimePreempt - int amountWiggles = (int)osuObject.TimePreempt / WiggleDuration.Value; + int amountWiggles = (int)osuObject.TimePreempt / 70; void wiggle() { float nextAngle = (float)(objRand.NextDouble() * 2 * Math.PI); float nextDist = (float)(objRand.NextDouble() * WiggleStrength.Value * 7); - drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), WiggleDuration.Value); + drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), 70); } for (int i = 0; i < amountWiggles; i++) { - using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * WiggleDuration.Value)) + using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * 70)) wiggle(); } @@ -76,11 +67,11 @@ namespace osu.Game.Rulesets.Osu.Mods if (!(osuObject is IHasDuration endTime)) return; - amountWiggles = (int)(endTime.Duration / WiggleDuration.Value); + amountWiggles = (int)(endTime.Duration / 70); for (int i = 0; i < amountWiggles; i++) { - using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * WiggleDuration.Value)) + using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * 70)) wiggle(); } } From f01deae42819902b0b1920c3caa5070243a6a9ac Mon Sep 17 00:00:00 2001 From: vun Date: Tue, 24 May 2022 17:38:52 +0800 Subject: [PATCH 0015/2686] Colour compression preprocessing implementation --- .../TaikoDifficultyHitObjectColour.cs | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs new file mode 100644 index 0000000000..425f5a16a9 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -0,0 +1,78 @@ +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing +{ + /// + /// Stores colour compression information for a . + /// + public class TaikoDifficultyHitObjectColour + { + const int max_repetition_interval = 16; + + private TaikoDifficultyHitObjectColour previous; + + /// + /// True if the current colour is different from the previous colour. + /// + public bool Delta { get; private set; } + + /// + /// How many notes are Delta repeated + /// + public int DeltaRunLength { get; private set; } + + /// + /// How many notes between the current and previous identical . + /// Negative number means that there is no repetition in range. + /// + public int RepetitionInterval { get; private set; } + + /// + /// Get the instance for the given hitObject. This is implemented + /// as a static function instead of constructor to allow for reusing existing instances. + /// TODO: findRepetitionInterval needs to be called a final time after all hitObjects have been processed. + /// + public static TaikoDifficultyHitObjectColour GetInstanceFor( + TaikoDifficultyHitObject hitObject, TaikoDifficultyHitObject lastObject, TaikoDifficultyHitObjectColour previous) + { + bool delta = lastObject == null || hitObject.HitType != lastObject.HitType; + if (delta == previous.Delta) + { + previous.DeltaRunLength += 1; + return previous; + } + else + { + // Calculate RepetitionInterval for previous + previous.RepetitionInterval = findRepetitionInterval(previous); + + return new TaikoDifficultyHitObjectColour() + { + Delta = delta, + DeltaRunLength = 1, + RepetitionInterval = -1, + previous = previous + }; + } + } + + /// + /// Finds the closest previous that has the identical delta value + /// and run length to target, and returns the amount of notes between them. + /// + private static int findRepetitionInterval(TaikoDifficultyHitObjectColour target) { + if (target.previous == null || target.previous.previous == null) + return -1; + + int interval = target.previous.DeltaRunLength; + TaikoDifficultyHitObjectColour other = target.previous.previous; + while(other != null && interval < max_repetition_interval) { + if (other.Delta == target.Delta && other.DeltaRunLength == target.DeltaRunLength) + return interval; + else + interval += other.DeltaRunLength; + other = other.previous; + } + + return -1; + } + } +} \ No newline at end of file From 7b2a5d4f76bbacdd7707c98be261fc0158d5efb7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 25 May 2022 13:01:12 +0900 Subject: [PATCH 0016/2686] Adjust xmldoc for correctness --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index cf4802d282..abb9e64a65 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing public double TravelDistance { get; private set; } /// - /// The time taken to travel through , with a minimum value of 25ms for a non-zero distance. + /// The time taken to travel through , with a minimum value of 25ms for objects. /// public double TravelTime { get; private set; } From cde06ecf17093ec10e19190db6326e94bc1d0395 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 25 May 2022 13:03:08 +0900 Subject: [PATCH 0017/2686] Apply code reviews --- osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 6482f6c962..b8f5fd8461 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; @@ -89,13 +90,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills double sliderBonus = 0.0; - if (osuCurrent.TravelTime != 0) + if (osuCurrent.BaseObject is Slider) { + Debug.Assert(osuCurrent.TravelTime > 0); + // Reward sliders based on velocity. - double normalisedTravelDistance = osuCurrent.TravelDistance / scalingFactor; - sliderBonus = Math.Pow(Math.Max(0.0, (normalisedTravelDistance) / osuCurrent.TravelTime - min_velocity), 0.5); + sliderBonus = Math.Pow(Math.Max(0.0, osuCurrent.TravelDistance / osuCurrent.TravelTime - min_velocity), 0.5); + // Longer sliders require more memorisation. - sliderBonus *= normalisedTravelDistance; + sliderBonus *= osuCurrent.TravelDistance; } result += sliderBonus * slider_multiplier; From 8a4f52287c8d06dbe84120ab9f09e0e95f5cd05b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 25 May 2022 13:38:23 +0900 Subject: [PATCH 0018/2686] Re-invert distances, cleanup, use actual normalised distance --- .../Preprocessing/OsuDifficultyHitObject.cs | 16 ++++++++++------ .../Difficulty/Skills/Flashlight.cs | 14 ++++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index abb9e64a65..258df97a7c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -12,10 +12,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { public class OsuDifficultyHitObject : DifficultyHitObject { - private const int normalised_radius = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths. + /// + /// A distance by which all distances should be scaled in order to assume a uniform circle size. + /// + public const int NORMALISED_RADIUS = 50; // Change radius to 50 to make 100 the diameter. Easier for mental maths. + private const int min_delta_time = 25; - private const float maximum_slider_radius = normalised_radius * 2.4f; - private const float assumed_slider_radius = normalised_radius * 1.8f; + private const float maximum_slider_radius = NORMALISED_RADIUS * 2.4f; + private const float assumed_slider_radius = NORMALISED_RADIUS * 1.8f; protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject; @@ -129,7 +133,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing return; // We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps. - float scalingFactor = normalised_radius / (float)BaseObject.Radius; + float scalingFactor = NORMALISED_RADIUS / (float)BaseObject.Radius; if (BaseObject.Radius < 30) { @@ -203,7 +207,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing slider.LazyEndPosition = slider.StackedPosition + slider.Path.PositionAt(endTimeMin); // temporary lazy end position until a real result can be derived. var currCursorPosition = slider.StackedPosition; - double scalingFactor = normalised_radius / slider.Radius; // lazySliderDistance is coded to be sensitive to scaling, this makes the maths easier with the thresholds being used. + double scalingFactor = NORMALISED_RADIUS / slider.Radius; // lazySliderDistance is coded to be sensitive to scaling, this makes the maths easier with the thresholds being used. for (int i = 1; i < slider.NestedHitObjects.Count; i++) { @@ -231,7 +235,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing else if (currMovementObj is SliderRepeat) { // For a slider repeat, assume a tighter movement threshold to better assess repeat sliders. - requiredMovement = normalised_radius; + requiredMovement = NORMALISED_RADIUS; } if (currMovementLength > requiredMovement) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index b8f5fd8461..f850f45162 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills var osuCurrent = (OsuDifficultyHitObject)current; var osuHitObject = (OsuHitObject)(osuCurrent.BaseObject); - double scalingFactor = 52.0 / osuHitObject.Radius; + double scalingFactor = OsuDifficultyHitObject.NORMALISED_RADIUS / osuHitObject.Radius; double smallDistNerf = 1.0; double cumulativeStrainTime = 0.0; @@ -70,8 +70,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills if (i == 0) smallDistNerf = Math.Min(1.0, jumpDistance / 75.0); + // Invert the scaling factor to determine the true jump distance independent of circle size. + double pixelJumpDistance = osuCurrent.LazyJumpDistance / scalingFactor; + // We also want to nerf stacks so that only the first object of the stack is accounted for. - double stackNerf = Math.Min(1.0, (currentObj.LazyJumpDistance / scalingFactor) / 25.0); + double stackNerf = Math.Min(1.0, pixelJumpDistance / 25.0); // Bonus based on how visible the object is. double opacityBonus = 1.0 + max_opacity_bonus * (1.0 - osuCurrent.OpacityAt(currentHitObject.StartTime, hidden)); @@ -94,11 +97,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills { Debug.Assert(osuCurrent.TravelTime > 0); + // Invert the scaling factor to determine the true travel distance independent of circle size. + double pixelTravelDistance = osuCurrent.TravelDistance / scalingFactor; + // Reward sliders based on velocity. - sliderBonus = Math.Pow(Math.Max(0.0, osuCurrent.TravelDistance / osuCurrent.TravelTime - min_velocity), 0.5); + sliderBonus = Math.Pow(Math.Max(0.0, pixelTravelDistance / osuCurrent.TravelTime - min_velocity), 0.5); // Longer sliders require more memorisation. - sliderBonus *= osuCurrent.TravelDistance; + sliderBonus *= pixelTravelDistance; } result += sliderBonus * slider_multiplier; From 1972bdd6c7750b7a4f0170beeceebbe08c425906 Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 26 May 2022 18:04:25 +0800 Subject: [PATCH 0019/2686] Working colour encoding --- .../Preprocessing/TaikoDifficultyHitObject.cs | 15 ++++--- .../TaikoDifficultyHitObjectColour.cs | 39 ++++++++++++------- .../Difficulty/TaikoDifficultyCalculator.cs | 11 +++++- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index ae33c184d0..97b79f5eea 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -19,6 +19,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public readonly TaikoDifficultyHitObjectRhythm Rhythm; + public readonly TaikoDifficultyHitObjectColour Colour; + /// /// The hit type of this hit object. /// @@ -29,29 +31,26 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public readonly int ObjectIndex; - /// - /// Whether the object should carry a penalty due to being hittable using special techniques - /// making it easier to do so. - /// - public bool StaminaCheese; - /// /// Creates a new difficulty hit object. /// /// The gameplay associated with this difficulty object. /// The gameplay preceding . /// The gameplay preceding . + /// The for . /// The rate of the gameplay clock. Modified by speed-changing mods. /// The index of the object in the beatmap. - public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, int objectIndex) + public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, TaikoDifficultyHitObject lastDifficulty, double clockRate, int objectIndex) : base(hitObject, lastObject, clockRate) { var currentHit = hitObject as Hit; Rhythm = getClosestRhythm(lastObject, lastLastObject, clockRate); HitType = currentHit?.Type; - ObjectIndex = objectIndex; + + // Need to be done after HitType is set. + Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this, lastDifficulty); } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index 425f5a16a9..2fada1c543 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -31,10 +31,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// TODO: findRepetitionInterval needs to be called a final time after all hitObjects have been processed. /// public static TaikoDifficultyHitObjectColour GetInstanceFor( - TaikoDifficultyHitObject hitObject, TaikoDifficultyHitObject lastObject, TaikoDifficultyHitObjectColour previous) + TaikoDifficultyHitObject hitObject, TaikoDifficultyHitObject lastObject) { + TaikoDifficultyHitObjectColour previous = lastObject?.Colour; bool delta = lastObject == null || hitObject.HitType != lastObject.HitType; - if (delta == previous.Delta) + if (previous != null && delta == previous.Delta) { previous.DeltaRunLength += 1; return previous; @@ -42,7 +43,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing else { // Calculate RepetitionInterval for previous - previous.RepetitionInterval = findRepetitionInterval(previous); + previous?.FindRepetitionInterval(); return new TaikoDifficultyHitObjectColour() { @@ -56,23 +57,35 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// /// Finds the closest previous that has the identical delta value - /// and run length to target, and returns the amount of notes between them. + /// and run length with the current instance, and returns the amount of notes between them. /// - private static int findRepetitionInterval(TaikoDifficultyHitObjectColour target) { - if (target.previous == null || target.previous.previous == null) - return -1; + public void FindRepetitionInterval() + { + if (this.previous == null || this.previous.previous == null) + { + this.RepetitionInterval = -1; + return; + } - int interval = target.previous.DeltaRunLength; - TaikoDifficultyHitObjectColour other = target.previous.previous; - while(other != null && interval < max_repetition_interval) { - if (other.Delta == target.Delta && other.DeltaRunLength == target.DeltaRunLength) - return interval; + + int interval = this.previous.DeltaRunLength; + TaikoDifficultyHitObjectColour other = this.previous.previous; + while (other != null && interval < max_repetition_interval) + { + if (other.Delta == this.Delta && other.DeltaRunLength == this.DeltaRunLength) + { + this.RepetitionInterval = interval; + return; + } else + { interval += other.DeltaRunLength; + } + other = other.previous; } - return -1; + this.RepetitionInterval = -1; } } } \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 1aa31c6fe4..6697ad0509 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -52,11 +52,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { taikoDifficultyHitObjects.Add( new TaikoDifficultyHitObject( - beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, i + beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], taikoDifficultyHitObjects.DefaultIfEmpty(null).LastOrDefault(), clockRate, i ) ); } + // Find repetition interval for the final TaikoDifficultyHitObjectColour + // TODO: Might be a good idea to refactor this + taikoDifficultyHitObjects.Last().Colour.FindRepetitionInterval(); + + taikoDifficultyHitObjects.ForEach((item) => + { + Console.WriteLine($"{item.StartTime}, {item.Colour.GetHashCode()}, {item.Colour.Delta}, {item.Colour.DeltaRunLength}, {item.Colour.RepetitionInterval}"); + }); + return taikoDifficultyHitObjects; } From 86ffa810a9628ace6daaee54244e41dde0297563 Mon Sep 17 00:00:00 2001 From: vun Date: Tue, 31 May 2022 23:17:39 +0800 Subject: [PATCH 0020/2686] Implement stamina evaluator (untested yet) --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 64 +++++++++++++++++++ .../Difficulty/Skills/SingleKeyStamina.cs | 42 ------------ .../Difficulty/Skills/Stamina.cs | 48 +------------- 3 files changed, 66 insertions(+), 88 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs delete mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs new file mode 100644 index 0000000000..a2f6b860f6 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -0,0 +1,64 @@ +// 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.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Objects; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators +{ + public class StaminaEvaluator + { + /// + /// Applies a speed bonus dependent on the time since the last hit performed using this key. + /// + /// The duration between the current and previous note hit using the same key. + private static double speedBonus(double notePairDuration) + { + return 175 / (notePairDuration + 100); + } + + /// + /// Evaluates the minimum mechanical stamina required to play the current object. This is calculated using the + /// maximum possible interval between two hits using the same key, by alternating 2 keys for each colour. + /// + public static double EvaluateDifficultyOf(DifficultyHitObject current) + { + if (!(current.BaseObject is Hit)) + { + return 0.0; + } + + // Find the previous hit object hit by the current key, which is two notes of the same colour prior. + // TODO: This could result in potential performance issue where it has to check the colour of a large amount + // of objects due to previous objects being mono of the other colour. A potential fix for this would be + // to store two separate lists of previous objects, one for each colour. + TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; + TaikoDifficultyHitObject previous = taikoCurrent; + int monoNoteInterval = 2; // The amount of same-colour notes to go back + double currentKeyInterval = 0; // Interval of the current key being pressed + do + { + previous = (TaikoDifficultyHitObject)previous.Previous(1); + if (previous.BaseObject is Hit && previous.HitType == taikoCurrent.HitType) + { + --monoNoteInterval; + } + currentKeyInterval += previous.DeltaTime; + + } while (previous != null && monoNoteInterval > 0); + + // This note is the first press of the current key + if (monoNoteInterval > 0) + { + return 0; + } + + double objectStrain = 0.5; + objectStrain += speedBonus(currentKeyInterval); + return objectStrain; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs deleted file mode 100644 index cabfd231d8..0000000000 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs +++ /dev/null @@ -1,42 +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.Game.Rulesets.Difficulty.Preprocessing; -using osu.Game.Rulesets.Difficulty.Skills; - -namespace osu.Game.Rulesets.Taiko.Difficulty.Skills -{ - /// - /// Stamina of a single key, calculated based on repetition speed. - /// - public class SingleKeyStamina - { - private double? previousHitTime; - - /// - /// Similar to - /// - public double StrainValueOf(DifficultyHitObject current) - { - if (previousHitTime == null) - { - previousHitTime = current.StartTime; - return 0; - } - - double objectStrain = 0.5; - objectStrain += speedBonus(current.StartTime - previousHitTime.Value); - previousHitTime = current.StartTime; - return objectStrain; - } - - /// - /// Applies a speed bonus dependent on the time since the last hit performed using this key. - /// - /// The duration between the current and previous note hit using the same key. - private double speedBonus(double notePairDuration) - { - return 175 / (notePairDuration + 100); - } - } -} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 61bcbfa59d..71713bcd56 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -4,6 +4,7 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Objects; @@ -20,28 +21,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double SkillMultiplier => 1; protected override double StrainDecayBase => 0.4; - private readonly SingleKeyStamina[] centreKeyStamina = - { - new SingleKeyStamina(), - new SingleKeyStamina() - }; - - private readonly SingleKeyStamina[] rimKeyStamina = - { - new SingleKeyStamina(), - new SingleKeyStamina() - }; - - /// - /// Current index into for a centre hit. - /// - private int centreKeyIndex; - - /// - /// Current index into for a rim hit. - /// - private int rimKeyIndex; - /// /// Creates a skill. /// @@ -51,32 +30,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { } - /// - /// Get the next to use for the given . - /// - /// The current . - private SingleKeyStamina getNextSingleKeyStamina(TaikoDifficultyHitObject current) - { - // Alternate key for the same color. - if (current.HitType == HitType.Centre) - { - centreKeyIndex = (centreKeyIndex + 1) % 2; - return centreKeyStamina[centreKeyIndex]; - } - - rimKeyIndex = (rimKeyIndex + 1) % 2; - return rimKeyStamina[rimKeyIndex]; - } - protected override double StrainValueOf(DifficultyHitObject current) { - if (!(current.BaseObject is Hit)) - { - return 0.0; - } - - TaikoDifficultyHitObject hitObject = (TaikoDifficultyHitObject)current; - return getNextSingleKeyStamina(hitObject).StrainValueOf(hitObject); + return StaminaEvaluator.EvaluateDifficultyOf(current); } } } From 8bbe70bff0ad69fc2cde3fe24281617dc18d3840 Mon Sep 17 00:00:00 2001 From: vun Date: Wed, 1 Jun 2022 04:33:37 +0800 Subject: [PATCH 0021/2686] Fix NullPointerReference --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index a2f6b860f6..59d3e61a27 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -2,8 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Rulesets.Difficulty.Preprocessing; -using osu.Game.Rulesets.Difficulty.Skills; -using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Objects; @@ -42,19 +40,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators do { previous = (TaikoDifficultyHitObject)previous.Previous(1); + if (previous == null) return 0; // No previous (The note is the first press of the current key) if (previous.BaseObject is Hit && previous.HitType == taikoCurrent.HitType) { --monoNoteInterval; } currentKeyInterval += previous.DeltaTime; - } while (previous != null && monoNoteInterval > 0); - - // This note is the first press of the current key - if (monoNoteInterval > 0) - { - return 0; - } + } while (monoNoteInterval > 0); double objectStrain = 0.5; objectStrain += speedBonus(currentKeyInterval); From 0a21f7c30dd15dbde01690de9a240b6e11e6b8a5 Mon Sep 17 00:00:00 2001 From: vun Date: Wed, 1 Jun 2022 05:20:08 +0800 Subject: [PATCH 0022/2686] Implement mono history in TaikoDifficultyHitObject --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 23 +++++------------ .../Preprocessing/TaikoDifficultyHitObject.cs | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 59d3e61a27..6f141f50ae 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -30,27 +30,16 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators } // Find the previous hit object hit by the current key, which is two notes of the same colour prior. - // TODO: This could result in potential performance issue where it has to check the colour of a large amount - // of objects due to previous objects being mono of the other colour. A potential fix for this would be - // to store two separate lists of previous objects, one for each colour. TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; - TaikoDifficultyHitObject previous = taikoCurrent; - int monoNoteInterval = 2; // The amount of same-colour notes to go back - double currentKeyInterval = 0; // Interval of the current key being pressed - do + TaikoDifficultyHitObject keyPrevious = taikoCurrent.PreviousMono(1); + if (keyPrevious == null) { - previous = (TaikoDifficultyHitObject)previous.Previous(1); - if (previous == null) return 0; // No previous (The note is the first press of the current key) - if (previous.BaseObject is Hit && previous.HitType == taikoCurrent.HitType) - { - --monoNoteInterval; - } - currentKeyInterval += previous.DeltaTime; - - } while (monoNoteInterval > 0); + // There is no previous hit object hit by the current key + return 0.0; + } double objectStrain = 0.5; - objectStrain += speedBonus(currentKeyInterval); + objectStrain += speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime); return objectStrain; } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 450eb63636..699d08e7bc 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -15,6 +15,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public class TaikoDifficultyHitObject : DifficultyHitObject { + // TODO: Review this - these was originally handled in TaikodifficultyCalculator.CreateDifficultyHitObjects, but + // it might be a good idea to encapsulate as much detail within the class as possible. + private static List centreHitObjects = new List(); + private static List rimHitObjects = new List(); + + private readonly IReadOnlyList monoDifficultyHitObjects; + public readonly int MonoPosition; + /// /// The rhythm required to hit this hit object. /// @@ -47,6 +55,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing Rhythm = getClosestRhythm(lastObject, lastLastObject, clockRate); HitType = currentHit?.Type; + + if (HitType == Objects.HitType.Centre) + { + MonoPosition = centreHitObjects.Count(); + centreHitObjects.Add(this); + monoDifficultyHitObjects = centreHitObjects; + } + else if (HitType == Objects.HitType.Rim) + { + MonoPosition = rimHitObjects.Count(); + rimHitObjects.Add(this); + monoDifficultyHitObjects = rimHitObjects; + } } /// @@ -85,5 +106,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing return common_rhythms.OrderBy(x => Math.Abs(x.Ratio - ratio)).First(); } + + public TaikoDifficultyHitObject PreviousMono(int backwardsIndex) => monoDifficultyHitObjects.ElementAtOrDefault(MonoPosition - (backwardsIndex + 1)); + + public TaikoDifficultyHitObject NextMono(int forwardsIndex) => monoDifficultyHitObjects.ElementAtOrDefault(MonoPosition + (forwardsIndex + 1)); } } From 56a4034c2260f8f6d4c2e0e37b4119e912fed021 Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 2 Jun 2022 18:48:36 +0800 Subject: [PATCH 0023/2686] Change RepetitionInterval to have max_repetition_interval + 1 when no repetition is found. --- .../Preprocessing/TaikoDifficultyHitObjectColour.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index 2fada1c543..a55fdc6e9f 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -1,3 +1,5 @@ +using System; + namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { /// @@ -22,6 +24,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// /// How many notes between the current and previous identical . /// Negative number means that there is no repetition in range. + /// If no repetition is found this will have a value of + 1. /// public int RepetitionInterval { get; private set; } @@ -49,7 +52,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { Delta = delta, DeltaRunLength = 1, - RepetitionInterval = -1, + RepetitionInterval = max_repetition_interval + 1, previous = previous }; } @@ -63,7 +66,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { if (this.previous == null || this.previous.previous == null) { - this.RepetitionInterval = -1; + this.RepetitionInterval = max_repetition_interval + 1; return; } @@ -74,7 +77,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { if (other.Delta == this.Delta && other.DeltaRunLength == this.DeltaRunLength) { - this.RepetitionInterval = interval; + this.RepetitionInterval = Math.Max(interval, max_repetition_interval); return; } else @@ -85,7 +88,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing other = other.previous; } - this.RepetitionInterval = -1; + this.RepetitionInterval = max_repetition_interval + 1; } } } \ No newline at end of file From 3dd0c4aec87c66c0527f9444a0a9bc9a80dbbfff Mon Sep 17 00:00:00 2001 From: vun Date: Mon, 6 Jun 2022 12:42:49 +0800 Subject: [PATCH 0024/2686] [WIP] Colour rework --- .../Difficulty/Evaluators/ColourEvaluator.cs | 33 +++++ .../Preprocessing/TaikoDifficultyHitObject.cs | 18 ++- .../TaikoDifficultyHitObjectColour.cs | 4 +- .../Difficulty/Skills/Colour.cs | 113 +----------------- .../Difficulty/Skills/SingleKeyStamina.cs | 20 +++- .../Difficulty/Skills/Stamina.cs | 9 +- .../Difficulty/TaikoDifficultyCalculator.cs | 26 ++-- 7 files changed, 88 insertions(+), 135 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs new file mode 100644 index 0000000000..159f9a4508 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -0,0 +1,33 @@ +using System; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators +{ + public class ColourEvaluator + { + private static double sigmoid(double val, double center, double width) + { + return Math.Tanh(Math.E * -(val - center) / width); + } + + public static double EvaluateDifficultyOf(DifficultyHitObject current) + { + TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; + TaikoDifficultyHitObjectColour colour = taikoCurrent.Colour; + if (colour == null) return 0; + double objectStrain = 1; + if (colour.Delta) + { + objectStrain /= Math.Pow(colour.DeltaRunLength, 0.25); + } + else + { + objectStrain *= sigmoid(colour.DeltaRunLength, 3, 3) * 0.3 + 0.3; + } + objectStrain *= -sigmoid(colour.RepetitionInterval, 8, 8); + // Console.WriteLine($"{current.StartTime},{colour.GetHashCode()},{colour.Delta},{colour.DeltaRunLength},{colour.RepetitionInterval},{objectStrain}"); + return objectStrain; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index b34e87bc83..8d2eadafe1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -20,6 +20,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public readonly TaikoDifficultyHitObjectRhythm Rhythm; + /// + /// Colour data for this hit object. This is used by colour evaluator to calculate colour, but can be used + /// differently by other skills in the future. + /// public readonly TaikoDifficultyHitObjectColour Colour; /// @@ -45,7 +49,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing HitType = currentHit?.Type; // Need to be done after HitType is set. - Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this, (TaikoDifficultyHitObject) objects.LastOrDefault()); + if (HitType != null) + { + // Get previous hit object, while skipping one that does not have defined colour (sliders and spinners). + // Without skipping through these, sliders and spinners would have contributed to a colour change for the next note. + TaikoDifficultyHitObject previousHitObject = (TaikoDifficultyHitObject)objects.LastOrDefault(); + while (previousHitObject != null && previousHitObject.Colour == null) + { + previousHitObject = (TaikoDifficultyHitObject)previousHitObject.Previous(0); + } + + Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this); + } + } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index a55fdc6e9f..ce65fd0552 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// as a static function instead of constructor to allow for reusing existing instances. /// TODO: findRepetitionInterval needs to be called a final time after all hitObjects have been processed. /// - public static TaikoDifficultyHitObjectColour GetInstanceFor( - TaikoDifficultyHitObject hitObject, TaikoDifficultyHitObject lastObject) + public static TaikoDifficultyHitObjectColour GetInstanceFor(TaikoDifficultyHitObject hitObject) { + TaikoDifficultyHitObject lastObject = (TaikoDifficultyHitObject) hitObject.Previous(0); TaikoDifficultyHitObjectColour previous = lastObject?.Colour; bool delta = lastObject == null || hitObject.HitType != lastObject.HitType; if (previous != null && delta == previous.Delta) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index 0c17ca66b9..9a8b350e22 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills @@ -19,27 +19,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double SkillMultiplier => 1; protected override double StrainDecayBase => 0.4; - /// - /// Maximum number of entries to keep in . - /// - private const int mono_history_max_length = 5; - - /// - /// Queue with the lengths of the last most recent mono (single-colour) patterns, - /// with the most recent value at the end of the queue. - /// - private readonly LimitedCapacityQueue monoHistory = new LimitedCapacityQueue(mono_history_max_length); - - /// - /// The of the last object hit before the one being considered. - /// - private HitType? previousHitType; - - /// - /// Length of the current mono pattern. - /// - private int currentMonoLength; - public Colour(Mod[] mods) : base(mods) { @@ -47,95 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double StrainValueOf(DifficultyHitObject current) { - // changing from/to a drum roll or a swell does not constitute a colour change. - // hits spaced more than a second apart are also exempt from colour strain. - if (!(current.LastObject is Hit && current.BaseObject is Hit && current.DeltaTime < 1000)) - { - monoHistory.Clear(); - - var currentHit = current.BaseObject as Hit; - currentMonoLength = currentHit != null ? 1 : 0; - previousHitType = currentHit?.Type; - - return 0.0; - } - - var taikoCurrent = (TaikoDifficultyHitObject)current; - - double objectStrain = 0.0; - - if (previousHitType != null && taikoCurrent.HitType != previousHitType) - { - // The colour has changed. - objectStrain = 1.0; - - if (monoHistory.Count < 2) - { - // There needs to be at least two streaks to determine a strain. - objectStrain = 0.0; - } - else if ((monoHistory[^1] + currentMonoLength) % 2 == 0) - { - // The last streak in the history is guaranteed to be a different type to the current streak. - // If the total number of notes in the two streaks is even, nullify this object's strain. - objectStrain = 0.0; - } - - objectStrain *= repetitionPenalties(); - currentMonoLength = 1; - } - else - { - currentMonoLength += 1; - } - - previousHitType = taikoCurrent.HitType; - return objectStrain; + return ColourEvaluator.EvaluateDifficultyOf(current); } - - /// - /// The penalty to apply due to the length of repetition in colour streaks. - /// - private double repetitionPenalties() - { - const int most_recent_patterns_to_compare = 2; - double penalty = 1.0; - - monoHistory.Enqueue(currentMonoLength); - - for (int start = monoHistory.Count - most_recent_patterns_to_compare - 1; start >= 0; start--) - { - if (!isSamePattern(start, most_recent_patterns_to_compare)) - continue; - - int notesSince = 0; - for (int i = start; i < monoHistory.Count; i++) notesSince += monoHistory[i]; - penalty *= repetitionPenalty(notesSince); - break; - } - - return penalty; - } - - /// - /// Determines whether the last patterns have repeated in the history - /// of single-colour note sequences, starting from . - /// - private bool isSamePattern(int start, int mostRecentPatternsToCompare) - { - for (int i = 0; i < mostRecentPatternsToCompare; i++) - { - if (monoHistory[start + i] != monoHistory[monoHistory.Count - mostRecentPatternsToCompare + i]) - return false; - } - - return true; - } - - /// - /// Calculates the strain penalty for a colour pattern repetition. - /// - /// The number of notes since the last repetition of the pattern. - private double repetitionPenalty(int notesSince) => Math.Min(1.0, 0.032 * notesSince); } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs index cabfd231d8..4b8a8033a4 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/SingleKeyStamina.cs @@ -1,8 +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; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { @@ -11,6 +13,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// public class SingleKeyStamina { + private const double StrainDecayBase = 0.4; + + private double CurrentStrain = 0; + private double? previousHitTime; /// @@ -24,19 +30,23 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills return 0; } - double objectStrain = 0.5; - objectStrain += speedBonus(current.StartTime - previousHitTime.Value); + // CurrentStrain += strainDecay(current.StartTime - current.Previous(0).StartTime); + // CurrentStrain += 0.5 + 0.5 * strainDecay(current.StartTime - current.Previous(0).StartTime); + CurrentStrain += 1; + CurrentStrain *= ColourEvaluator.EvaluateDifficultyOf(current) * 0.1 + 0.9; + CurrentStrain *= strainDecay(current.StartTime - previousHitTime.Value); previousHitTime = current.StartTime; - return objectStrain; + return CurrentStrain; } /// /// Applies a speed bonus dependent on the time since the last hit performed using this key. /// /// The duration between the current and previous note hit using the same key. - private double speedBonus(double notePairDuration) + private double strainDecay(double notePairDuration) { - return 175 / (notePairDuration + 100); + return Math.Pow(StrainDecayBase, notePairDuration / 1000); + // return 175 / (notePairDuration + 100); } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 61bcbfa59d..7196b68df2 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -5,6 +5,7 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills @@ -17,8 +18,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// public class Stamina : StrainDecaySkill { - protected override double SkillMultiplier => 1; - protected override double StrainDecayBase => 0.4; + protected override double SkillMultiplier => 3.6; + protected override double StrainDecayBase => 0; private readonly SingleKeyStamina[] centreKeyStamina = { @@ -76,7 +77,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills } TaikoDifficultyHitObject hitObject = (TaikoDifficultyHitObject)current; - return getNextSingleKeyStamina(hitObject).StrainValueOf(hitObject); + double objectStrain = getNextSingleKeyStamina(hitObject).StrainValueOf(hitObject); + // objectStrain *= ColourEvaluator.EvaluateDifficultyOf(current) * 0.3 + 0.7; + return objectStrain; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 4dd3b0b8cc..423903db2f 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -20,8 +20,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { public class TaikoDifficultyCalculator : DifficultyCalculator { - private const double rhythm_skill_multiplier = 0.014; - private const double colour_skill_multiplier = 0.01; + private const double rhythm_skill_multiplier = 0.017; + private const double colour_skill_multiplier = 0.028; private const double stamina_skill_multiplier = 0.021; public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty // Find repetition interval for the final TaikoDifficultyHitObjectColour // TODO: Might be a good idea to refactor this - ((TaikoDifficultyHitObject)difficultyHitObject.Last()).Colour.FindRepetitionInterval(); + ((TaikoDifficultyHitObject)difficultyHitObject.Last()).Colour?.FindRepetitionInterval(); return difficultyHitObject; } @@ -76,18 +76,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double rhythmRating = rhythm.DifficultyValue() * rhythm_skill_multiplier; double staminaRating = stamina.DifficultyValue() * stamina_skill_multiplier; - double staminaPenalty = simpleColourPenalty(staminaRating, colourRating); - staminaRating *= staminaPenalty; + // double staminaPenalty = simpleColourPenalty(staminaRating, colourRating); + // staminaRating *= staminaPenalty; //TODO : This is a temporary fix for the stamina rating of converts, due to their low colour variance. - if (beatmap.BeatmapInfo.Ruleset.OnlineID == 0 && colourRating < 0.05) - { - staminaPenalty *= 0.25; - } + // if (beatmap.BeatmapInfo.Ruleset.OnlineID == 0 && colourRating < 0.05) + // { + // staminaPenalty *= 0.25; + // } - double combinedRating = locallyCombinedDifficulty(colour, rhythm, stamina, staminaPenalty); + double combinedRating = locallyCombinedDifficulty(colour, rhythm, stamina); double separatedRating = norm(1.5, colourRating, rhythmRating, staminaRating); - double starRating = 1.4 * separatedRating + 0.5 * combinedRating; + double starRating = 1.9 * combinedRating; starRating = rescale(starRating); HitWindows hitWindows = new TaikoHitWindows(); @@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty /// For each section, the peak strains of all separate skills are combined into a single peak strain for the section. /// The resulting partial rating of the beatmap is a weighted sum of the combined peaks (higher peaks are weighted more). /// - private double locallyCombinedDifficulty(Colour colour, Rhythm rhythm, Stamina stamina, double staminaPenalty) + private double locallyCombinedDifficulty(Colour colour, Rhythm rhythm, Stamina stamina) { List peaks = new List(); @@ -145,7 +145,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { double colourPeak = colourPeaks[i] * colour_skill_multiplier; double rhythmPeak = rhythmPeaks[i] * rhythm_skill_multiplier; - double staminaPeak = staminaPeaks[i] * stamina_skill_multiplier * staminaPenalty; + double staminaPeak = staminaPeaks[i] * stamina_skill_multiplier; double peak = norm(2, colourPeak, rhythmPeak, staminaPeak); From 07d3a7bd2ecd9dd585539285a2fb374847929ebf Mon Sep 17 00:00:00 2001 From: vun Date: Mon, 6 Jun 2022 16:11:26 +0800 Subject: [PATCH 0025/2686] Fix logic error, minor stamina changes --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 6 ++-- .../Preprocessing/TaikoDifficultyHitObject.cs | 29 ++++++++++++++----- .../Difficulty/Skills/Stamina.cs | 4 +-- .../Difficulty/TaikoDifficultyCalculator.cs | 11 ++++--- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 6f141f50ae..0c33a952a5 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.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 osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Objects; @@ -15,7 +16,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// The duration between the current and previous note hit using the same key. private static double speedBonus(double notePairDuration) { - return 175 / (notePairDuration + 100); + return Math.Pow(0.4, notePairDuration / 1000); } /// @@ -38,7 +39,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return 0.0; } - double objectStrain = 0.5; + double objectStrain = 0; + // Console.WriteLine(speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime)); objectStrain += speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime); return objectStrain; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 0949b8349a..cb57c7bccc 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Objects; @@ -15,13 +16,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public class TaikoDifficultyHitObject : DifficultyHitObject { - // TODO: Review this - these was originally handled in TaikodifficultyCalculator.CreateDifficultyHitObjects, but - // it might be a good idea to encapsulate as much detail within the class as possible. - private static List centreHitObjects = new List(); - private static List rimHitObjects = new List(); - private readonly IReadOnlyList monoDifficultyHitObjects; public readonly int MonoPosition; + private readonly IReadOnlyList noteObjects; + public readonly int NotePosition; /// /// The rhythm required to hit this hit object. @@ -46,12 +44,21 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// The gameplay preceding . /// The gameplay preceding . /// The rate of the gameplay clock. Modified by speed-changing mods. - /// The list of s in the current beatmap. - /// /// The position of this in the list. - public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, List objects, int position) + /// The list of all s in the current beatmap. + /// The list of centre (don) s in the current beatmap. + /// The list of rim (kat) s in the current beatmap. + /// The list of s that is a hit (i.e. not a slider or spinner) in the current beatmap. + /// The position of this in the list. + /// + /// TODO: This argument list is getting long, we might want to refactor this into a static method that create + /// all s from a . + public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, + List objects, List centreHitObjects, List rimHitObjects, + List noteObjects, int position) : base(hitObject, lastObject, clockRate, objects, position) { var currentHit = hitObject as Hit; + this.noteObjects = noteObjects; Rhythm = getClosestRhythm(lastObject, lastLastObject, clockRate); HitType = currentHit?.Type; @@ -68,6 +75,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing } Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this); + this.NotePosition = noteObjects.Count(); + noteObjects.Add(this); } if (HitType == Objects.HitType.Centre) @@ -124,5 +133,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing public TaikoDifficultyHitObject PreviousMono(int backwardsIndex) => monoDifficultyHitObjects.ElementAtOrDefault(MonoPosition - (backwardsIndex + 1)); public TaikoDifficultyHitObject NextMono(int forwardsIndex) => monoDifficultyHitObjects.ElementAtOrDefault(MonoPosition + (forwardsIndex + 1)); + + public TaikoDifficultyHitObject PreviousNote(int backwardsIndex) => noteObjects.ElementAtOrDefault(NotePosition - (backwardsIndex + 1)); + + public TaikoDifficultyHitObject NextNote(int forwardsIndex) => noteObjects.ElementAtOrDefault(NotePosition + (forwardsIndex + 1)); } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 713944a6e0..ee5e257811 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -18,8 +18,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// public class Stamina : StrainDecaySkill { - protected override double SkillMultiplier => 3.6; - protected override double StrainDecayBase => 0; + protected override double SkillMultiplier => 1.2; + protected override double StrainDecayBase => 0.4; /// /// Creates a skill. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 423903db2f..187fa4a070 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -21,8 +21,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty public class TaikoDifficultyCalculator : DifficultyCalculator { private const double rhythm_skill_multiplier = 0.017; - private const double colour_skill_multiplier = 0.028; - private const double stamina_skill_multiplier = 0.021; + private const double colour_skill_multiplier = 0.027; + private const double stamina_skill_multiplier = 0.017; public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) @@ -47,13 +47,16 @@ namespace osu.Game.Rulesets.Taiko.Difficulty protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { List difficultyHitObject = new List(); + List centreObjects = new List(); + List rimObjects = new List(); + List noteObjects = new List(); for (int i = 2; i < beatmap.HitObjects.Count; i++) { difficultyHitObject.Add( new TaikoDifficultyHitObject( - beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObject, difficultyHitObject.Count - ) + beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObject, + centreObjects, rimObjects, noteObjects, difficultyHitObject.Count) ); } From fd49a27cf99729b9e463ad34ea85082be789550b Mon Sep 17 00:00:00 2001 From: vun Date: Tue, 7 Jun 2022 13:30:24 +0800 Subject: [PATCH 0026/2686] Fix encoding repetition, parameter adjustments --- .../Difficulty/Evaluators/ColourEvaluator.cs | 8 +++--- .../Preprocessing/TaikoDifficultyHitObject.cs | 26 +++++++------------ .../TaikoDifficultyHitObjectColour.cs | 9 +++---- .../Difficulty/TaikoDifficultyCalculator.cs | 6 ++--- 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 159f9a4508..c534b5bd9f 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -16,16 +16,16 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; TaikoDifficultyHitObjectColour colour = taikoCurrent.Colour; if (colour == null) return 0; - double objectStrain = 1; + double objectStrain = 1.6; if (colour.Delta) { - objectStrain /= Math.Pow(colour.DeltaRunLength, 0.25); + objectStrain /= Math.Pow(colour.DeltaRunLength, 0.7); } else { - objectStrain *= sigmoid(colour.DeltaRunLength, 3, 3) * 0.3 + 0.3; + objectStrain *= sigmoid(colour.DeltaRunLength, 4, 4) * 0.5 + 0.5; } - objectStrain *= -sigmoid(colour.RepetitionInterval, 8, 8); + objectStrain *= -sigmoid(colour.RepetitionInterval, 8, 8) * 0.5 + 0.5; // Console.WriteLine($"{current.StartTime},{colour.GetHashCode()},{colour.Delta},{colour.DeltaRunLength},{colour.RepetitionInterval},{objectStrain}"); return objectStrain; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index cb57c7bccc..537eafe396 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -63,22 +63,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing Rhythm = getClosestRhythm(lastObject, lastLastObject, clockRate); HitType = currentHit?.Type; - // Need to be done after HitType is set. - if (HitType != null) - { - // Get previous hit object, while skipping one that does not have defined colour (sliders and spinners). - // Without skipping through these, sliders and spinners would have contributed to a colour change for the next note. - TaikoDifficultyHitObject previousHitObject = (TaikoDifficultyHitObject)objects.LastOrDefault(); - while (previousHitObject != null && previousHitObject.Colour == null) - { - previousHitObject = (TaikoDifficultyHitObject)previousHitObject.Previous(0); - } - - Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this); - this.NotePosition = noteObjects.Count(); - noteObjects.Add(this); - } - if (HitType == Objects.HitType.Centre) { MonoPosition = centreHitObjects.Count(); @@ -91,6 +75,16 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing rimHitObjects.Add(this); monoDifficultyHitObjects = rimHitObjects; } + + // Need to be done after HitType is set. + if (HitType != null) + { + this.NotePosition = noteObjects.Count(); + noteObjects.Add(this); + + // Need to be done after NotePosition is set. + Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this); + } } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index ce65fd0552..f9a586f877 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public static TaikoDifficultyHitObjectColour GetInstanceFor(TaikoDifficultyHitObject hitObject) { - TaikoDifficultyHitObject lastObject = (TaikoDifficultyHitObject) hitObject.Previous(0); + TaikoDifficultyHitObject lastObject = hitObject.PreviousNote(0); TaikoDifficultyHitObjectColour previous = lastObject?.Colour; bool delta = lastObject == null || hitObject.HitType != lastObject.HitType; if (previous != null && delta == previous.Delta) @@ -75,15 +75,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing TaikoDifficultyHitObjectColour other = this.previous.previous; while (other != null && interval < max_repetition_interval) { + interval += other.DeltaRunLength; if (other.Delta == this.Delta && other.DeltaRunLength == this.DeltaRunLength) { - this.RepetitionInterval = Math.Max(interval, max_repetition_interval); + this.RepetitionInterval = Math.Min(interval, max_repetition_interval); return; } - else - { - interval += other.DeltaRunLength; - } other = other.previous; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 187fa4a070..706fde77d2 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -21,8 +21,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty public class TaikoDifficultyCalculator : DifficultyCalculator { private const double rhythm_skill_multiplier = 0.017; - private const double colour_skill_multiplier = 0.027; - private const double stamina_skill_multiplier = 0.017; + private const double colour_skill_multiplier = 0.026; + private const double stamina_skill_multiplier = 0.018; public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) @@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty // } double combinedRating = locallyCombinedDifficulty(colour, rhythm, stamina); - double separatedRating = norm(1.5, colourRating, rhythmRating, staminaRating); + // double separatedRating = norm(2, colourRating, rhythmRating, staminaRating); double starRating = 1.9 * combinedRating; starRating = rescale(starRating); From d8d4ac431e804bfa8d644e1ca78c58591bfbe7a3 Mon Sep 17 00:00:00 2001 From: vun Date: Wed, 8 Jun 2022 13:24:51 +0800 Subject: [PATCH 0027/2686] Refactor LocallyCombinedDifficulty to an external skill --- .../Difficulty/Skills/CombinedStrain.cs | 86 +++++++++++++++ .../Difficulty/TaikoDifficultyCalculator.cs | 101 ++---------------- 2 files changed, 97 insertions(+), 90 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs new file mode 100644 index 0000000000..e5052c3359 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Skills +{ + public class CombinedStrain : Skill + { + private const double rhythm_skill_multiplier = 0.017; + private const double colour_skill_multiplier = 0.026; + private const double stamina_skill_multiplier = 0.018; + + private Rhythm rhythm; + private Colour colour; + private Stamina stamina; + + public double ColourDifficultyValue => colour.DifficultyValue() * colour_skill_multiplier; + public double RhythmDifficultyValue => rhythm.DifficultyValue() * rhythm_skill_multiplier; + public double StaminaDifficultyValue => stamina.DifficultyValue() * stamina_skill_multiplier; + + public CombinedStrain(Mod[] mods) : base(mods) + { + rhythm = new Rhythm(mods); + colour = new Colour(mods); + stamina = new Stamina(mods); + } + + /// + /// Returns the p-norm of an n-dimensional vector. + /// + /// The value of p to calculate the norm for. + /// The coefficients of the vector. + private double norm(double p, params double[] values) => Math.Pow(values.Sum(x => Math.Pow(x, p)), 1 / p); + + public override void Process(DifficultyHitObject current) + { + rhythm.Process(current); + colour.Process(current); + stamina.Process(current); + } + + /// + /// Returns the combined star rating of the beatmap, calculated using peak strains from all sections of the map. + /// + /// + /// For each section, the peak strains of all separate skills are combined into a single peak strain for the section. + /// The resulting partial rating of the beatmap is a weighted sum of the combined peaks (higher peaks are weighted more). + /// + public override double DifficultyValue() + { + List peaks = new List(); + + var colourPeaks = colour.GetCurrentStrainPeaks().ToList(); + var rhythmPeaks = rhythm.GetCurrentStrainPeaks().ToList(); + var staminaPeaks = stamina.GetCurrentStrainPeaks().ToList(); + + for (int i = 0; i < colourPeaks.Count; i++) + { + double colourPeak = colourPeaks[i] * colour_skill_multiplier; + double rhythmPeak = rhythmPeaks[i] * rhythm_skill_multiplier; + double staminaPeak = staminaPeaks[i] * stamina_skill_multiplier; + + double peak = norm(2, colourPeak, rhythmPeak, staminaPeak); + + // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). + // These sections will not contribute to the difficulty. + if (peak > 0) + peaks.Add(peak); + } + + double difficulty = 0; + double weight = 1; + + foreach (double strain in peaks.OrderByDescending(d => d)) + { + difficulty += strain * weight; + weight *= 0.9; + } + + return difficulty; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 706fde77d2..f4a23930b3 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -20,21 +20,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { public class TaikoDifficultyCalculator : DifficultyCalculator { - private const double rhythm_skill_multiplier = 0.017; - private const double colour_skill_multiplier = 0.026; - private const double stamina_skill_multiplier = 0.018; - public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) { } - protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) => new Skill[] + protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) { - new Colour(mods), - new Rhythm(mods), - new Stamina(mods) - }; + return new Skill[] + { + new CombinedStrain(mods) + }; + } protected override Mod[] DifficultyAdjustmentMods => new Mod[] { @@ -71,27 +68,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (beatmap.HitObjects.Count == 0) return new TaikoDifficultyAttributes { Mods = mods }; - var colour = (Colour)skills[0]; - var rhythm = (Rhythm)skills[1]; - var stamina = (Stamina)skills[2]; + var combined = (CombinedStrain)skills[0]; - double colourRating = colour.DifficultyValue() * colour_skill_multiplier; - double rhythmRating = rhythm.DifficultyValue() * rhythm_skill_multiplier; - double staminaRating = stamina.DifficultyValue() * stamina_skill_multiplier; + double colourRating = combined.ColourDifficultyValue; + double rhythmRating = combined.RhythmDifficultyValue; + double staminaRating = combined.StaminaDifficultyValue; - // double staminaPenalty = simpleColourPenalty(staminaRating, colourRating); - // staminaRating *= staminaPenalty; - - //TODO : This is a temporary fix for the stamina rating of converts, due to their low colour variance. - // if (beatmap.BeatmapInfo.Ruleset.OnlineID == 0 && colourRating < 0.05) - // { - // staminaPenalty *= 0.25; - // } - - double combinedRating = locallyCombinedDifficulty(colour, rhythm, stamina); - // double separatedRating = norm(2, colourRating, rhythmRating, staminaRating); - double starRating = 1.9 * combinedRating; - starRating = rescale(starRating); + double starRating = rescale(1.9 * combined.DifficultyValue()); HitWindows hitWindows = new TaikoHitWindows(); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); @@ -108,68 +91,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty }; } - /// - /// Calculates the penalty for the stamina skill for maps with low colour difficulty. - /// - /// - /// Some maps (especially converts) can be easy to read despite a high note density. - /// This penalty aims to reduce the star rating of such maps by factoring in colour difficulty to the stamina skill. - /// - private double simpleColourPenalty(double staminaDifficulty, double colorDifficulty) - { - if (colorDifficulty <= 0) return 0.79 - 0.25; - - return 0.79 - Math.Atan(staminaDifficulty / colorDifficulty - 12) / Math.PI / 2; - } - - /// - /// Returns the p-norm of an n-dimensional vector. - /// - /// The value of p to calculate the norm for. - /// The coefficients of the vector. - private double norm(double p, params double[] values) => Math.Pow(values.Sum(x => Math.Pow(x, p)), 1 / p); - - /// - /// Returns the partial star rating of the beatmap, calculated using peak strains from all sections of the map. - /// - /// - /// For each section, the peak strains of all separate skills are combined into a single peak strain for the section. - /// The resulting partial rating of the beatmap is a weighted sum of the combined peaks (higher peaks are weighted more). - /// - private double locallyCombinedDifficulty(Colour colour, Rhythm rhythm, Stamina stamina) - { - List peaks = new List(); - - var colourPeaks = colour.GetCurrentStrainPeaks().ToList(); - var rhythmPeaks = rhythm.GetCurrentStrainPeaks().ToList(); - var staminaPeaks = stamina.GetCurrentStrainPeaks().ToList(); - - for (int i = 0; i < colourPeaks.Count; i++) - { - double colourPeak = colourPeaks[i] * colour_skill_multiplier; - double rhythmPeak = rhythmPeaks[i] * rhythm_skill_multiplier; - double staminaPeak = staminaPeaks[i] * stamina_skill_multiplier; - - double peak = norm(2, colourPeak, rhythmPeak, staminaPeak); - - // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). - // These sections will not contribute to the difficulty. - if (peak > 0) - peaks.Add(peak); - } - - double difficulty = 0; - double weight = 1; - - foreach (double strain in peaks.OrderByDescending(d => d)) - { - difficulty += strain * weight; - weight *= 0.9; - } - - return difficulty; - } - /// /// Applies a final re-scaling of the star rating to bring maps with recorded full combos below 9.5 stars. /// From 5793ca5534e9a9d17f9e2bc94581051fbf082012 Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 9 Jun 2022 12:35:26 +0800 Subject: [PATCH 0028/2686] Parameter tweaks --- .../Difficulty/Evaluators/ColourEvaluator.cs | 6 +++--- .../Difficulty/Skills/CombinedStrain.cs | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index c534b5bd9f..2ecef3690b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -16,14 +16,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; TaikoDifficultyHitObjectColour colour = taikoCurrent.Colour; if (colour == null) return 0; - double objectStrain = 1.6; + double objectStrain = 1.8; if (colour.Delta) { - objectStrain /= Math.Pow(colour.DeltaRunLength, 0.7); + objectStrain *= sigmoid(colour.DeltaRunLength, 6, 4) * 0.5 + 0.5; } else { - objectStrain *= sigmoid(colour.DeltaRunLength, 4, 4) * 0.5 + 0.5; + objectStrain *= sigmoid(colour.DeltaRunLength, 2, 2) * 0.5 + 0.5; } objectStrain *= -sigmoid(colour.RepetitionInterval, 8, 8) * 0.5 + 0.5; // Console.WriteLine($"{current.StartTime},{colour.GetHashCode()},{colour.Delta},{colour.DeltaRunLength},{colour.RepetitionInterval},{objectStrain}"); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs index e5052c3359..bf62cb1fbd 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs @@ -9,9 +9,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { public class CombinedStrain : Skill { - private const double rhythm_skill_multiplier = 0.017; - private const double colour_skill_multiplier = 0.026; - private const double stamina_skill_multiplier = 0.018; + private const double final_multiplier = 0.00925; + private const double rhythm_skill_multiplier = 1.6 * final_multiplier; + private const double colour_skill_multiplier = 1.85 * final_multiplier; + private const double stamina_skill_multiplier = 1.85 * final_multiplier; private Rhythm rhythm; private Colour colour; @@ -63,7 +64,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills double rhythmPeak = rhythmPeaks[i] * rhythm_skill_multiplier; double staminaPeak = staminaPeaks[i] * stamina_skill_multiplier; - double peak = norm(2, colourPeak, rhythmPeak, staminaPeak); + double peak = norm(1.5, colourPeak, staminaPeak); + peak = norm(2, peak, rhythmPeak); // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). // These sections will not contribute to the difficulty. From 6dbaf0a03084e07ec8c287c7d739bee4453384b2 Mon Sep 17 00:00:00 2001 From: Jay L Date: Thu, 9 Jun 2022 19:22:55 +1000 Subject: [PATCH 0029/2686] Refactor --- .../Difficulty/Evaluators/ColourEvaluator.cs | 7 ++- .../Difficulty/Evaluators/StaminaEvaluator.cs | 1 + .../Preprocessing/TaikoDifficultyHitObject.cs | 23 +++++----- .../TaikoDifficultyHitObjectColour.cs | 44 +++++++++---------- .../Difficulty/Skills/Colour.cs | 3 -- .../Skills/{CombinedStrain.cs => Peaks.cs} | 16 ++++--- .../Difficulty/Skills/Stamina.cs | 2 - .../Difficulty/TaikoDifficultyAttributes.cs | 9 ++-- .../Difficulty/TaikoDifficultyCalculator.cs | 16 ++++--- .../Difficulty/TaikoPerformanceCalculator.cs | 28 ++++++------ 10 files changed, 76 insertions(+), 73 deletions(-) rename osu.Game.Rulesets.Taiko/Difficulty/Skills/{CombinedStrain.cs => Peaks.cs} (94%) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 2ecef3690b..01410af459 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -6,6 +6,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators { public class ColourEvaluator { + // TODO - Share this sigmoid private static double sigmoid(double val, double center, double width) { return Math.Tanh(Math.E * -(val - center) / width); @@ -16,7 +17,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; TaikoDifficultyHitObjectColour colour = taikoCurrent.Colour; if (colour == null) return 0; + double objectStrain = 1.8; + if (colour.Delta) { objectStrain *= sigmoid(colour.DeltaRunLength, 6, 4) * 0.5 + 0.5; @@ -25,9 +28,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators { objectStrain *= sigmoid(colour.DeltaRunLength, 2, 2) * 0.5 + 0.5; } + objectStrain *= -sigmoid(colour.RepetitionInterval, 8, 8) * 0.5 + 0.5; - // Console.WriteLine($"{current.StartTime},{colour.GetHashCode()},{colour.Delta},{colour.DeltaRunLength},{colour.RepetitionInterval},{objectStrain}"); return objectStrain; } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 0c33a952a5..6c0c01cb2d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -33,6 +33,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators // Find the previous hit object hit by the current key, which is two notes of the same colour prior. TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; TaikoDifficultyHitObject keyPrevious = taikoCurrent.PreviousMono(1); + if (keyPrevious == null) { // There is no previous hit object hit by the current key diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 537eafe396..54e314f722 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -53,8 +53,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// TODO: This argument list is getting long, we might want to refactor this into a static method that create /// all s from a . public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, - List objects, List centreHitObjects, List rimHitObjects, - List noteObjects, int position) + List objects, + List centreHitObjects, + List rimHitObjects, + List noteObjects, int position) : base(hitObject, lastObject, clockRate, objects, position) { var currentHit = hitObject as Hit; @@ -65,26 +67,25 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing if (HitType == Objects.HitType.Centre) { - MonoPosition = centreHitObjects.Count(); + MonoPosition = centreHitObjects.Count; centreHitObjects.Add(this); monoDifficultyHitObjects = centreHitObjects; } else if (HitType == Objects.HitType.Rim) { - MonoPosition = rimHitObjects.Count(); + MonoPosition = rimHitObjects.Count; rimHitObjects.Add(this); monoDifficultyHitObjects = rimHitObjects; } // Need to be done after HitType is set. - if (HitType != null) - { - this.NotePosition = noteObjects.Count(); - noteObjects.Add(this); + if (HitType == null) return; - // Need to be done after NotePosition is set. - Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this); - } + NotePosition = noteObjects.Count; + noteObjects.Add(this); + + // Need to be done after NotePosition is set. + Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this); } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index f9a586f877..a5ca0964df 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public class TaikoDifficultyHitObjectColour { - const int max_repetition_interval = 16; + private const int max_repetition_interval = 16; private TaikoDifficultyHitObjectColour previous; @@ -38,54 +38,54 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing TaikoDifficultyHitObject lastObject = hitObject.PreviousNote(0); TaikoDifficultyHitObjectColour previous = lastObject?.Colour; bool delta = lastObject == null || hitObject.HitType != lastObject.HitType; + if (previous != null && delta == previous.Delta) { previous.DeltaRunLength += 1; return previous; } - else - { - // Calculate RepetitionInterval for previous - previous?.FindRepetitionInterval(); - return new TaikoDifficultyHitObjectColour() - { - Delta = delta, - DeltaRunLength = 1, - RepetitionInterval = max_repetition_interval + 1, - previous = previous - }; - } + // Calculate RepetitionInterval for previous + previous?.FindRepetitionInterval(); + + return new TaikoDifficultyHitObjectColour() + { + Delta = delta, + DeltaRunLength = 1, + RepetitionInterval = max_repetition_interval + 1, + previous = previous + }; } /// - /// Finds the closest previous that has the identical delta value + /// Finds the closest previous that has the identical delta value /// and run length with the current instance, and returns the amount of notes between them. /// public void FindRepetitionInterval() { - if (this.previous == null || this.previous.previous == null) + if (previous?.previous == null) { - this.RepetitionInterval = max_repetition_interval + 1; + RepetitionInterval = max_repetition_interval + 1; return; } + int interval = previous.DeltaRunLength; + TaikoDifficultyHitObjectColour other = previous.previous; - int interval = this.previous.DeltaRunLength; - TaikoDifficultyHitObjectColour other = this.previous.previous; while (other != null && interval < max_repetition_interval) { interval += other.DeltaRunLength; - if (other.Delta == this.Delta && other.DeltaRunLength == this.DeltaRunLength) + + if (other.Delta == Delta && other.DeltaRunLength == DeltaRunLength) { - this.RepetitionInterval = Math.Min(interval, max_repetition_interval); + RepetitionInterval = Math.Min(interval, max_repetition_interval); return; } other = other.previous; } - this.RepetitionInterval = max_repetition_interval + 1; + RepetitionInterval = max_repetition_interval + 1; } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index 9a8b350e22..1c992df179 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -1,13 +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; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; -using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; -using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs similarity index 94% rename from osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index bf62cb1fbd..4d4089cba7 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -7,22 +7,24 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { - public class CombinedStrain : Skill + public class Peaks : Skill { - private const double final_multiplier = 0.00925; private const double rhythm_skill_multiplier = 1.6 * final_multiplier; private const double colour_skill_multiplier = 1.85 * final_multiplier; private const double stamina_skill_multiplier = 1.85 * final_multiplier; - private Rhythm rhythm; - private Colour colour; - private Stamina stamina; + private const double final_multiplier = 0.00925; + + private readonly Rhythm rhythm; + private readonly Colour colour; + private readonly Stamina stamina; public double ColourDifficultyValue => colour.DifficultyValue() * colour_skill_multiplier; public double RhythmDifficultyValue => rhythm.DifficultyValue() * rhythm_skill_multiplier; public double StaminaDifficultyValue => stamina.DifficultyValue() * stamina_skill_multiplier; - public CombinedStrain(Mod[] mods) : base(mods) + public Peaks(Mod[] mods) + : base(mods) { rhythm = new Rhythm(mods); colour = new Colour(mods); @@ -85,4 +87,4 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills return difficulty; } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index ee5e257811..57c82bf97b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -5,8 +5,6 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; -using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; -using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs index 3dc5438072..c7342554da 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -28,13 +28,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty public double ColourDifficulty { get; set; } /// - /// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc). + /// The difficulty corresponding to the hardest parts of the map. /// - /// - /// Rate-adjusting mods don't directly affect the approach rate difficulty value, but have a perceived effect as a result of adjusting audio timing. - /// - [JsonProperty("approach_rate")] - public double ApproachRate { get; set; } + [JsonProperty("peak_difficulty")] + public double PeakDifficulty { get; set; } /// /// The perceived hit window for a GREAT hit inclusive of rate-adjusting mods (DT/HT/etc). diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index f4a23930b3..91ae1c4ed2 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { public class TaikoDifficultyCalculator : DifficultyCalculator { + private const double difficulty_multiplier = 1.9; + public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) { @@ -29,7 +31,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { return new Skill[] { - new CombinedStrain(mods) + new Peaks(mods) }; } @@ -68,13 +70,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (beatmap.HitObjects.Count == 0) return new TaikoDifficultyAttributes { Mods = mods }; - var combined = (CombinedStrain)skills[0]; + var combined = (Peaks)skills[0]; - double colourRating = combined.ColourDifficultyValue; - double rhythmRating = combined.RhythmDifficultyValue; - double staminaRating = combined.StaminaDifficultyValue; + double colourRating = Math.Sqrt(combined.ColourDifficultyValue * difficulty_multiplier); + double rhythmRating = Math.Sqrt(combined.RhythmDifficultyValue * difficulty_multiplier); + double staminaRating = Math.Sqrt(combined.StaminaDifficultyValue * difficulty_multiplier); - double starRating = rescale(1.9 * combined.DifficultyValue()); + double combinedRating = combined.DifficultyValue(); + double starRating = rescale(combinedRating * difficulty_multiplier); HitWindows hitWindows = new TaikoHitWindows(); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); @@ -86,6 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty StaminaDifficulty = staminaRating, RhythmDifficulty = rhythmRating, ColourDifficulty = colourRating, + PeakDifficulty = combinedRating, GreatHitWindow = hitWindows.WindowFor(HitResult.Great) / clockRate, MaxCombo = beatmap.HitObjects.Count(h => h is Hit), }; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 8d99fd3b87..f551d8cd93 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -33,21 +33,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); - double multiplier = 1.1; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things - - if (score.Mods.Any(m => m is ModNoFail)) - multiplier *= 0.90; - - if (score.Mods.Any(m => m is ModHidden)) - multiplier *= 1.10; - double difficultyValue = computeDifficultyValue(score, taikoAttributes); double accuracyValue = computeAccuracyValue(score, taikoAttributes); double totalValue = Math.Pow( Math.Pow(difficultyValue, 1.1) + Math.Pow(accuracyValue, 1.1), 1.0 / 1.1 - ) * multiplier; + ) * 1.1; return new TaikoPerformanceAttributes { @@ -59,7 +51,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes) { - double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.175) - 4.0, 2.25) / 450.0; + double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.190) - 4.0, 2.25) / 450.0; double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0); difficultyValue *= lengthBonus; @@ -67,7 +59,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty difficultyValue *= Math.Pow(0.985, countMiss); if (score.Mods.Any(m => m is ModHidden)) - difficultyValue *= 1.025; + difficultyValue *= 1.125; if (score.Mods.Any(m => m is ModFlashlight)) difficultyValue *= 1.05 * lengthBonus; @@ -80,10 +72,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (attributes.GreatHitWindow <= 0) return 0; - double accValue = Math.Pow(150.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 15) * 22.0; + double accuracyValue = Math.Pow(150.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 15) * 40.0; - // Bonus for many objects - it's harder to keep good accuracy up for longer - return accValue * Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); + double accuracylengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); + accuracyValue *= accuracylengthBonus; + + if (score.Mods.Any(m => m is ModHidden)) + accuracyValue *= 1.225; + + if (score.Mods.Any(m => m is ModFlashlight)) + accuracyValue *= 1.15 * accuracylengthBonus; + + return accuracyValue; } private int totalHits => countGreat + countOk + countMeh + countMiss; From 4c574eb044ed64b595145169bb1a6d8a561d028e Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 9 Jun 2022 17:31:54 +0800 Subject: [PATCH 0030/2686] Rescale multipliers (values unaffected) --- .../Difficulty/Skills/CombinedStrain.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs index bf62cb1fbd..265f526367 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/CombinedStrain.cs @@ -9,10 +9,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { public class CombinedStrain : Skill { - private const double final_multiplier = 0.00925; - private const double rhythm_skill_multiplier = 1.6 * final_multiplier; - private const double colour_skill_multiplier = 1.85 * final_multiplier; - private const double stamina_skill_multiplier = 1.85 * final_multiplier; + private const double final_multiplier = 0.04625; + private const double rhythm_skill_multiplier = 0.32 * final_multiplier; + private const double colour_skill_multiplier = 0.37 * final_multiplier; + private const double stamina_skill_multiplier = 0.37 * final_multiplier; private Rhythm rhythm; private Colour colour; From 2881406f6b2912c708a186f1de0e1ebc4f0739dc Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 9 Jun 2022 19:41:59 +0800 Subject: [PATCH 0031/2686] Nerf alternating pattern slightly, value rescale --- .../Difficulty/Evaluators/ColourEvaluator.cs | 5 +++-- osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 01410af459..8c225c8459 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -18,11 +18,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators TaikoDifficultyHitObjectColour colour = taikoCurrent.Colour; if (colour == null) return 0; - double objectStrain = 1.8; + double objectStrain = 2.1; if (colour.Delta) { - objectStrain *= sigmoid(colour.DeltaRunLength, 6, 4) * 0.5 + 0.5; + objectStrain *= sigmoid(colour.DeltaRunLength, 4, 4) * 0.5 + 0.5; } else { @@ -30,6 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators } objectStrain *= -sigmoid(colour.RepetitionInterval, 8, 8) * 0.5 + 0.5; + // Console.WriteLine($"{current.StartTime},{colour.Delta},{colour.RepetitionInterval},{objectStrain}"); return objectStrain; } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index d11aaef230..171278b4dd 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills private const double colour_skill_multiplier = 0.37 * final_multiplier; private const double stamina_skill_multiplier = 0.37 * final_multiplier; - private const double final_multiplier = 0.04625; + private const double final_multiplier = 0.047; private readonly Rhythm rhythm; private readonly Colour colour; From 2b2150ac04d93e86ba285a52fda237160f76d6a9 Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 10 Jun 2022 14:58:50 +0800 Subject: [PATCH 0032/2686] Refactor TaikoDifficultyHitObject creation into the class as a static method --- .../Preprocessing/TaikoDifficultyHitObject.cs | 32 ++++++++++++++++++- .../Difficulty/TaikoDifficultyCalculator.cs | 19 +---------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 54e314f722..1da4a6e994 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -37,6 +37,36 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public readonly HitType? HitType; + /// + /// Creates a list of s from a s. + /// TODO: Review this - this is moved here from TaikoDifficultyCalculator so that TaikoDifficultyCalculator can + /// have less knowledge of implementation details (i.e. creating all the different hitObject lists, and + /// calling FindRepetitionInterval for the final object). The down side of this is + /// TaikoDifficultyHitObejct.CreateDifficultyHitObjects is now pretty much a proxy for this. + /// + /// The beatmap from which the list of is created. + /// The rate at which the gameplay clock is run at. + public static List Create(IBeatmap beatmap, double clockRate) + { + List difficultyHitObject = new List(); + List centreObjects = new List(); + List rimObjects = new List(); + List noteObjects = new List(); + + for (int i = 2; i < beatmap.HitObjects.Count; i++) + { + difficultyHitObject.Add( + new TaikoDifficultyHitObject( + beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObject, + centreObjects, rimObjects, noteObjects, difficultyHitObject.Count) + ); + } + + // Find repetition interval for the final TaikoDifficultyHitObjectColour + ((TaikoDifficultyHitObject)difficultyHitObject.Last()).Colour?.FindRepetitionInterval(); + return difficultyHitObject; + } + /// /// Creates a new difficulty hit object. /// @@ -52,7 +82,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// /// TODO: This argument list is getting long, we might want to refactor this into a static method that create /// all s from a . - public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, + private TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, List objects, List centreHitObjects, List rimHitObjects, diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 91ae1c4ed2..7898b7994e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -45,24 +45,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { - List difficultyHitObject = new List(); - List centreObjects = new List(); - List rimObjects = new List(); - List noteObjects = new List(); - - for (int i = 2; i < beatmap.HitObjects.Count; i++) - { - difficultyHitObject.Add( - new TaikoDifficultyHitObject( - beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObject, - centreObjects, rimObjects, noteObjects, difficultyHitObject.Count) - ); - } - - // Find repetition interval for the final TaikoDifficultyHitObjectColour - // TODO: Might be a good idea to refactor this - ((TaikoDifficultyHitObject)difficultyHitObject.Last()).Colour?.FindRepetitionInterval(); - return difficultyHitObject; + return TaikoDifficultyHitObject.Create(beatmap, clockRate); } protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) From d6b9f385c17e3cc78ee19962a5cfed2db7fff6d7 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 27 Nov 2021 23:58:08 -0800 Subject: [PATCH 0033/2686] Add failing play button by touch input test --- .../Visual/Beatmaps/TestSceneBeatmapCard.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs index 6cb171974a..959e118fac 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs @@ -13,12 +13,14 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables.Cards; +using osu.Game.Beatmaps.Drawables.Cards.Buttons; using osu.Game.Graphics.Containers; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osuTK; +using osuTK.Input; namespace osu.Game.Tests.Visual.Beatmaps { @@ -293,5 +295,22 @@ namespace osu.Game.Tests.Visual.Beatmaps BeatmapCardNormal firstCard() => this.ChildrenOfType().First(); } + + [Test] + public void TestPlayButtonByTouchInput() + { + AddStep("create cards", () => Child = createContent(OverlayColourScheme.Blue, beatmapSetInfo => new BeatmapCardNormal(beatmapSetInfo))); + + // mimics touch input + AddStep("touch play button area on first card", () => + { + InputManager.MoveMouseTo(firstCard().ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("first card is playing", () => firstCard().ChildrenOfType().Single().Playing.Value); + + BeatmapCardNormal firstCard() => this.ChildrenOfType().First(); + } } } From 1107e267e3fd4f181c6bff925eaf1ed564d0dd1c Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 10 Jun 2022 14:04:03 -0700 Subject: [PATCH 0034/2686] Fix beatmap card play button not working with touch inputs when not hovered --- osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs index f7bab26666..51e690d156 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs @@ -43,6 +43,9 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons Anchor = Origin = Anchor.Centre; + // needed for touch input to work when card is not hovered/expanded + AlwaysPresent = true; + Children = new Drawable[] { icon = new SpriteIcon From a5bf16e87345d488ff5f95578002a9be29276f47 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Sun, 19 Jun 2022 02:10:23 +0200 Subject: [PATCH 0035/2686] Make drum rolls and swells optional with `Classic` mod --- .../Judgements/TaikoDrumRollJudgement.cs | 4 ++++ .../Judgements/TaikoDrumRollTickJudgement.cs | 4 +++- .../Judgements/TaikoSwellJudgement.cs | 4 ++++ .../Mods/TaikoModClassic.cs | 11 ++++++++++- .../Objects/Drawables/DrawableDrumRoll.cs | 9 ++++++++- .../Objects/Drawables/DrawableSwell.cs | 11 +++++++++-- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 18 +++++++++++++++++- .../Objects/DrumRollTick.cs | 7 ++++++- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 12 +++++++++++- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 9 +++++++++ 10 files changed, 81 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index be128d85b5..93891769ec 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -9,6 +9,10 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoDrumRollJudgement : TaikoJudgement { + public bool IsBonus = false; + + public override HitResult MaxResult => IsBonus ? HitResult.LargeBonus : HitResult.Great; + protected override double HealthIncreaseFor(HitResult result) { // Drum rolls can be ignored with no health penalty diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs index 5f2587a5d5..d6fb8dc2c9 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs @@ -9,7 +9,9 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoDrumRollTickJudgement : TaikoJudgement { - public override HitResult MaxResult => HitResult.SmallTickHit; + public bool IsBonus = false; + + public override HitResult MaxResult => IsBonus ? HitResult.LargeBonus : HitResult.SmallTickHit; protected override double HealthIncreaseFor(HitResult result) { diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs index b2ac0b7f03..a2572133f2 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs @@ -9,6 +9,10 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoSwellJudgement : TaikoJudgement { + public bool IsBonus = false; + + public override HitResult MaxResult => IsBonus ? HitResult.LargeBonus : HitResult.Great; + protected override double HealthIncreaseFor(HitResult result) { switch (result) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index 6d1a18bb78..2564fd32ab 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -4,13 +4,14 @@ #nullable disable using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset, IUpdatableByPlayfield + public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset, IUpdatableByPlayfield, IApplicableToHitObject { private DrawableTaikoRuleset drawableTaikoRuleset; @@ -20,6 +21,14 @@ namespace osu.Game.Rulesets.Taiko.Mods drawableTaikoRuleset.LockPlayfieldAspect.Value = false; } + public void ApplyToHitObject(HitObject hitObject) + { + if (hitObject is DrumRoll drumRoll) + drumRoll.SetBonus(true); + else if (hitObject is Swell swell) + swell.SetBonus(true); + } + public void Update(Playfield playfield) { // Classic taiko scrolls at a constant 100px per 1000ms. More notes become visible as the playfield is lengthened. diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 04ed6d0b87..fd8b8196cd 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -144,7 +144,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables if (countHit >= HitObject.RequiredGoodHits) { - ApplyResult(r => r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Ok); + ApplyResult(r => + { + // With the Classic mod, don't award points for a finished drum roll, only for ticks. + if (r.Judgement.MaxResult == HitResult.LargeBonus) + r.Type = HitResult.IgnoreMiss; + else + r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Ok; + }); } else ApplyResult(r => r.Type = r.Judgement.MinResult); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 2451c79772..238aa2189f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -201,7 +201,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); if (numHits == HitObject.RequiredHits) - ApplyResult(r => r.Type = HitResult.Great); + ApplyResult(r => r.Type = r.Judgement.MaxResult); } else { @@ -222,7 +222,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables tick.TriggerResult(false); } - ApplyResult(r => r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.Ok : r.Judgement.MinResult); + ApplyResult(r => + { + // With the Classic mod, don't award combo or accuracy for a finished swell. + if (r.Judgement.MaxResult == HitResult.LargeBonus) + r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.LargeBonus : r.Judgement.MinResult; + else + r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.Ok : r.Judgement.MinResult; + }); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index e1619e2857..47ccb9cc72 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -52,6 +52,11 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public double RequiredGreatHits { get; protected set; } + /// + /// Defines if drum rolls are affected by the Classic mod, making them bonus only. + /// + private bool isBonus; + /// /// The length (in milliseconds) between ticks of this drumroll. /// Half of this value is the hit window of the ticks. @@ -106,7 +111,18 @@ namespace osu.Game.Rulesets.Taiko.Objects } } - public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); + public void SetBonus(bool bonus) + { + isBonus = bonus; + + foreach (HitObject hitObject in NestedHitObjects) + { + if (hitObject is DrumRollTick drumRollTick) + drumRollTick.IsBonus = bonus; + } + } + + public override Judgement CreateJudgement() => new TaikoDrumRollJudgement { IsBonus = isBonus }; protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs index 433fdab908..6aa08e7c76 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs @@ -27,7 +27,12 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public double HitWindow => TickSpacing / 2; - public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement(); + /// + /// Defines if ticks are affected by the Classic mod, making them bonus only. + /// + public bool IsBonus = false; + + public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement { IsBonus = IsBonus }; protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index cb91c46b4d..bd91fcd076 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -26,6 +26,16 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public int RequiredHits = 10; + /// + /// Defines if swells are affected by the Classic mod, making them bonus only. + /// + private bool isBonus; + + public void SetBonus(bool bonus) + { + isBonus = bonus; + } + protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { base.CreateNestedHitObjects(cancellationToken); @@ -37,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Objects } } - public override Judgement CreateJudgement() => new TaikoSwellJudgement(); + public override Judgement CreateJudgement() => new TaikoSwellJudgement { IsBonus = isBonus }; protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 4e0c8029fb..7719f51f2f 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -295,6 +295,15 @@ namespace osu.Game.Rulesets.Taiko.UI break; default: + // Don't draw judgement results for bonus sliderticks with the Classic mod. + switch (result.Type) + { + case HitResult.IgnoreHit: + case HitResult.IgnoreMiss: + case HitResult.LargeBonus: + return; + } + judgementContainer.Add(judgementPools[result.Type].Get(j => { j.Apply(result, judgedObject); From da1d99d5b66aad2fb2fc8ed4fe096309784eed62 Mon Sep 17 00:00:00 2001 From: vun Date: Sun, 19 Jun 2022 17:14:31 +0800 Subject: [PATCH 0036/2686] Parameter tweaks, change repetition interval definition --- .../Difficulty/Evaluators/ColourEvaluator.cs | 6 +++--- .../Preprocessing/TaikoDifficultyHitObjectColour.cs | 6 ++++-- osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs | 5 +++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 8c225c8459..32bc8429b8 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -18,18 +18,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators TaikoDifficultyHitObjectColour colour = taikoCurrent.Colour; if (colour == null) return 0; - double objectStrain = 2.1; + double objectStrain = 1.85; if (colour.Delta) { - objectStrain *= sigmoid(colour.DeltaRunLength, 4, 4) * 0.5 + 0.5; + objectStrain *= sigmoid(colour.DeltaRunLength, 3, 3) * 0.5 + 0.5; } else { objectStrain *= sigmoid(colour.DeltaRunLength, 2, 2) * 0.5 + 0.5; } - objectStrain *= -sigmoid(colour.RepetitionInterval, 8, 8) * 0.5 + 0.5; + objectStrain *= -sigmoid(colour.RepetitionInterval, 1, 8); // * 0.5 + 0.5; // Console.WriteLine($"{current.StartTime},{colour.Delta},{colour.RepetitionInterval},{objectStrain}"); return objectStrain; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index a5ca0964df..8be803fd05 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -28,6 +28,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public int RepetitionInterval { get; private set; } + public TaikoDifficultyHitObjectColour repeatedColour { get; private set; } + /// /// Get the instance for the given hitObject. This is implemented /// as a static function instead of constructor to allow for reusing existing instances. @@ -74,14 +76,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing while (other != null && interval < max_repetition_interval) { - interval += other.DeltaRunLength; - if (other.Delta == Delta && other.DeltaRunLength == DeltaRunLength) { RepetitionInterval = Math.Min(interval, max_repetition_interval); + repeatedColour = other; return; } + interval += other.DeltaRunLength; other = other.previous; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index 171278b4dd..ebbe027f9e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -4,14 +4,15 @@ using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { public class Peaks : Skill { private const double rhythm_skill_multiplier = 0.32 * final_multiplier; - private const double colour_skill_multiplier = 0.37 * final_multiplier; - private const double stamina_skill_multiplier = 0.37 * final_multiplier; + private const double colour_skill_multiplier = 0.33 * final_multiplier; + private const double stamina_skill_multiplier = 0.4 * final_multiplier; private const double final_multiplier = 0.047; From 57964311be3410c7df1b563b3fb5b1daa19a752b Mon Sep 17 00:00:00 2001 From: vun Date: Sun, 19 Jun 2022 17:20:53 +0800 Subject: [PATCH 0037/2686] Revert performance calculator to upstream --- .../Difficulty/TaikoPerformanceCalculator.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 9eca59bfd7..a9cde62f44 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -35,13 +35,21 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); + double multiplier = 1.1; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things + + if (score.Mods.Any(m => m is ModNoFail)) + multiplier *= 0.90; + + if (score.Mods.Any(m => m is ModHidden)) + multiplier *= 1.10; + double difficultyValue = computeDifficultyValue(score, taikoAttributes); double accuracyValue = computeAccuracyValue(score, taikoAttributes); double totalValue = Math.Pow( Math.Pow(difficultyValue, 1.1) + Math.Pow(accuracyValue, 1.1), 1.0 / 1.1 - ) * 1.1; + ) * multiplier; return new TaikoPerformanceAttributes { @@ -53,7 +61,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes) { - double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.190) - 4.0, 2.25) / 450.0; + double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.175) - 4.0, 2.25) / 450.0; double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0); difficultyValue *= lengthBonus; @@ -61,7 +69,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty difficultyValue *= Math.Pow(0.985, countMiss); if (score.Mods.Any(m => m is ModHidden)) - difficultyValue *= 1.125; + difficultyValue *= 1.025; if (score.Mods.Any(m => m is ModFlashlight)) difficultyValue *= 1.05 * lengthBonus; @@ -74,18 +82,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (attributes.GreatHitWindow <= 0) return 0; - double accuracyValue = Math.Pow(150.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 15) * 40.0; + double accValue = Math.Pow(150.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 15) * 22.0; - double accuracylengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); - accuracyValue *= accuracylengthBonus; - - if (score.Mods.Any(m => m is ModHidden)) - accuracyValue *= 1.225; - - if (score.Mods.Any(m => m is ModFlashlight)) - accuracyValue *= 1.15 * accuracylengthBonus; - - return accuracyValue; + // Bonus for many objects - it's harder to keep good accuracy up for longer + return accValue * Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); } private int totalHits => countGreat + countOk + countMeh + countMiss; From 3529514587a5099a54b9e02c6d62321dcd66444e Mon Sep 17 00:00:00 2001 From: vun Date: Sun, 19 Jun 2022 17:26:11 +0800 Subject: [PATCH 0038/2686] Disablle nullable in TaikoDifficultyHitObjectColour --- .../Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index 8be803fd05..8304c0b126 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -1,3 +1,5 @@ +#nullable disable + using System; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing From c6ac60c0b5d5c88cb5d7fa611858507fa7f3c734 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sun, 19 Jun 2022 13:07:10 +0200 Subject: [PATCH 0039/2686] Enhance target angle calculation --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 48 +++++++++++++++---- .../Utils/OsuHitObjectGenerationUtils.cs | 33 +++++++++++++ 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 4f83154728..475d5a2a67 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -37,23 +37,51 @@ namespace osu.Game.Rulesets.Osu.Mods var positionInfos = OsuHitObjectGenerationUtils.GeneratePositionInfos(osuBeatmap.HitObjects); - float rateOfChangeMultiplier = 0; + float sequenceOffset = 0; + bool flowDirection = false; - foreach (var positionInfo in positionInfos) + for (int i = 0; i < positionInfos.Count; i++) { - // rateOfChangeMultiplier only changes every 5 iterations in a combo - // to prevent shaky-line-shaped streams - if (positionInfo.HitObject.IndexInCurrentCombo % 5 == 0) - rateOfChangeMultiplier = (float)rng.NextDouble() * 2 - 1; + bool invertFlow = false; - if (positionInfo == positionInfos.First()) + if (i == 0 || + (positionInfos[i - 1].HitObject.NewCombo && (i <= 1 || !positionInfos[i - 2].HitObject.NewCombo) && (i <= 2 || !positionInfos[i - 3].HitObject.NewCombo)) || + OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject, true) || + (OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject) && rng.NextDouble() < 0.25)) { - positionInfo.DistanceFromPrevious = (float)(rng.NextDouble() * OsuPlayfield.BASE_SIZE.Y / 2); - positionInfo.RelativeAngle = (float)(rng.NextDouble() * 2 * Math.PI - Math.PI); + sequenceOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.02f); + + if (rng.NextDouble() < 0.6) + invertFlow = true; + } + + if (i == 0) + { + positionInfos[i].DistanceFromPrevious = (float)(rng.NextDouble() * OsuPlayfield.BASE_SIZE.Y / 2); + positionInfos[i].RelativeAngle = (float)(rng.NextDouble() * 2 * Math.PI - Math.PI); } else { - positionInfo.RelativeAngle = rateOfChangeMultiplier * 2 * (float)Math.PI * Math.Min(1f, positionInfo.DistanceFromPrevious / (playfield_diagonal * 0.5f)); + float flowChangeOffset = 0; + float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.03f); + + if (positionInfos[i - 1].HitObject.NewCombo && (i <= 1 || !positionInfos[i - 2].HitObject.NewCombo) && rng.NextDouble() < 0.6) + { + flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.05f); + + if (rng.NextDouble() < 0.8) + invertFlow = true; + } + + if (invertFlow) + flowDirection ^= true; + + positionInfos[i].RelativeAngle = OsuHitObjectGenerationUtils.GetRelativeTargetAngle( + positionInfos[i].DistanceFromPrevious, + (sequenceOffset + oneTimeOffset) * (float)Math.Sqrt(positionInfos[i].DistanceFromPrevious) + + flowChangeOffset * (float)Math.Sqrt(640 - positionInfos[i].DistanceFromPrevious), + flowDirection + ); } } diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index 5e827d4782..9044fe142b 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -8,6 +8,7 @@ using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Objects; using osuTK; @@ -186,5 +187,37 @@ namespace osu.Game.Rulesets.Osu.Utils length * MathF.Sin(angle) ); } + + public static bool IsHitObjectOnBeat(OsuBeatmap beatmap, OsuHitObject hitObject, bool downbeatsOnly = false) + { + var timingPoints = beatmap.ControlPointInfo.TimingPoints; + var currentTimingPoint = timingPoints.Reverse().FirstOrDefault(p => p.Time <= hitObject.StartTime); + + if (currentTimingPoint == null) + return false; + + double timeSinceTimingPoint = hitObject.StartTime - currentTimingPoint.Time; + + double length = downbeatsOnly + ? currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator + : currentTimingPoint.BeatLength; + + return (timeSinceTimingPoint + 1) % length < 2; + } + + public static float GetRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) + { + float angle = (float)(3.3 / (1 + 200 * Math.Pow(MathHelper.E, 0.016 * (targetDistance - 466))) + 0.45 + offset); + float relativeAngle = MathHelper.Pi - angle; + return flowDirection ? -relativeAngle : relativeAngle; + } + + public static float RandomGaussian(Random rng, float mean = 0, float stdDev = 1) + { + double x1 = 1 - rng.NextDouble(); + double x2 = 1 - rng.NextDouble(); + double stdNormal = Math.Sqrt(-2 * Math.Log(x1)) * Math.Sin(MathHelper.TwoPi * x2); + return mean + stdDev * (float)stdNormal; + } } } From 33c6c6af6b2995f4717009a2cc646775e32d419b Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sun, 19 Jun 2022 13:50:09 +0200 Subject: [PATCH 0040/2686] Adjust target angle calculation parameters --- osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index 9044fe142b..b9c384f842 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -207,7 +207,7 @@ namespace osu.Game.Rulesets.Osu.Utils public static float GetRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) { - float angle = (float)(3.3 / (1 + 200 * Math.Pow(MathHelper.E, 0.016 * (targetDistance - 466))) + 0.45 + offset); + float angle = (float)(3 / (1 + 200 * Math.Pow(MathHelper.E, 0.016 * (targetDistance - 466))) + 0.45 + offset); float relativeAngle = MathHelper.Pi - angle; return flowDirection ? -relativeAngle : relativeAngle; } From 7317b9b90960a2b326ec858e61b668375fa7e0ac Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sun, 19 Jun 2022 14:59:28 +0200 Subject: [PATCH 0041/2686] Remove unused field --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 475d5a2a67..2560ed921d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -22,8 +22,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTarget)).ToArray(); - private static readonly float playfield_diagonal = OsuPlayfield.BASE_SIZE.LengthFast; - private Random? rng; public void ApplyToBeatmap(IBeatmap beatmap) From 98527fec26e7d88af58edd376a6d2da0ef4f32ff Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Sun, 19 Jun 2022 15:11:12 +0200 Subject: [PATCH 0042/2686] Make mod selfcontained --- .../Judgements/TaikoDrumRollJudgement.cs | 4 - .../Judgements/TaikoDrumRollTickJudgement.cs | 4 +- .../Judgements/TaikoSwellJudgement.cs | 4 - .../Mods/TaikoModClassic.cs | 184 +++++++++++++++++- .../Objects/Drawables/DrawableDrumRoll.cs | 9 +- .../Objects/Drawables/DrawableSwell.cs | 50 +++-- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 32 +-- .../Objects/DrumRollTick.cs | 7 +- osu.Game.Rulesets.Taiko/Objects/Swell.cs | 12 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 9 - 10 files changed, 213 insertions(+), 102 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index 93891769ec..be128d85b5 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -9,10 +9,6 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoDrumRollJudgement : TaikoJudgement { - public bool IsBonus = false; - - public override HitResult MaxResult => IsBonus ? HitResult.LargeBonus : HitResult.Great; - protected override double HealthIncreaseFor(HitResult result) { // Drum rolls can be ignored with no health penalty diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs index d6fb8dc2c9..5f2587a5d5 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs @@ -9,9 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoDrumRollTickJudgement : TaikoJudgement { - public bool IsBonus = false; - - public override HitResult MaxResult => IsBonus ? HitResult.LargeBonus : HitResult.SmallTickHit; + public override HitResult MaxResult => HitResult.SmallTickHit; protected override double HealthIncreaseFor(HitResult result) { diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs index a2572133f2..b2ac0b7f03 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs @@ -9,10 +9,6 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoSwellJudgement : TaikoJudgement { - public bool IsBonus = false; - - public override HitResult MaxResult => IsBonus ? HitResult.LargeBonus : HitResult.Great; - protected override double HealthIncreaseFor(HitResult result) { switch (result) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index 2564fd32ab..7141afe791 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -3,15 +3,22 @@ #nullable disable +using System.Linq; +using System.Threading; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Beatmaps; +using osu.Game.Rulesets.Taiko.Judgements; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset, IUpdatableByPlayfield, IApplicableToHitObject + public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset, IUpdatableByPlayfield, IApplicableAfterBeatmapConversion { private DrawableTaikoRuleset drawableTaikoRuleset; @@ -19,14 +26,177 @@ namespace osu.Game.Rulesets.Taiko.Mods { drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset; drawableTaikoRuleset.LockPlayfieldAspect.Value = false; + + drawableTaikoRuleset.Playfield.RegisterPool(5); + drawableTaikoRuleset.Playfield.RegisterPool(100); + drawableTaikoRuleset.Playfield.RegisterPool(5); } - public void ApplyToHitObject(HitObject hitObject) + public void ApplyToBeatmap(IBeatmap beatmap) { - if (hitObject is DrumRoll drumRoll) - drumRoll.SetBonus(true); - else if (hitObject is Swell swell) - swell.SetBonus(true); + var taikoBeatmap = (TaikoBeatmap)beatmap; + + if (taikoBeatmap.HitObjects.Count == 0) return; + + var hitObjects = taikoBeatmap.HitObjects.Select(ho => + { + if (ho is DrumRoll drumRoll) + { + var newDrumRoll = new ClassicDrumRoll(drumRoll); + return newDrumRoll; + } + + if (ho is Swell swell) + { + var newSwell = new ClassicSwell(swell); + return newSwell; + } + + return ho; + }).ToList(); + + taikoBeatmap.HitObjects = hitObjects; + } + + private class ClassicDrumRoll : DrumRoll + { + public ClassicDrumRoll(DrumRoll original) + { + StartTime = original.StartTime; + Samples = original.Samples; + EndTime = original.EndTime; + Duration = original.Duration; + TickRate = original.TickRate; + RequiredGoodHits = original.RequiredGoodHits; + RequiredGreatHits = original.RequiredGreatHits; + } + + public override Judgement CreateJudgement() => new TaikoClassicDrumRollJudgement(); + + protected override void CreateTicks(CancellationToken cancellationToken) + { + if (TickSpacing == 0) + return; + + bool first = true; + + for (double t = StartTime; t < EndTime + TickSpacing / 2; t += TickSpacing) + { + cancellationToken.ThrowIfCancellationRequested(); + + AddNested(new ClassicDrumRollTick + { + FirstTick = first, + TickSpacing = TickSpacing, + StartTime = t, + IsStrong = IsStrong + }); + + first = false; + } + } + } + + private class ClassicDrumRollTick : DrumRollTick + { + public override Judgement CreateJudgement() => new TaikoClassicDrumRollTickJudgement(); + } + + private class ClassicSwell : Swell + { + public ClassicSwell(Swell original) + { + StartTime = original.StartTime; + Samples = original.Samples; + EndTime = original.EndTime; + Duration = original.Duration; + RequiredHits = original.RequiredHits; + } + + public override Judgement CreateJudgement() => new TaikoClassicSwellJudgement(); + } + + private class TaikoClassicDrumRollJudgement : TaikoDrumRollJudgement + { + public override HitResult MaxResult => HitResult.LargeBonus; + } + + private class TaikoClassicDrumRollTickJudgement : TaikoDrumRollTickJudgement + { + public override HitResult MaxResult => HitResult.LargeBonus; + } + + private class TaikoClassicSwellJudgement : TaikoSwellJudgement + { + public override HitResult MaxResult => HitResult.LargeBonus; + } + + private class ClassicDrawableDrumRoll : DrawableDrumRoll + { + public override bool DisplayResult => false; + + protected override void CheckForResult(bool userTriggered, double timeOffset) + { + if (userTriggered) + return; + + if (timeOffset < 0) + return; + + ApplyResult(r => r.Type = HitResult.IgnoreMiss); + } + } + + private class ClassicDrawableSwell : DrawableSwell + { + public override bool DisplayResult => false; + + protected override void CheckForResult(bool userTriggered, double timeOffset) + { + if (userTriggered) + { + DrawableSwellTick nextTick = null; + + foreach (var t in Ticks) + { + if (!t.Result.HasResult) + { + nextTick = t; + break; + } + } + + nextTick?.TriggerResult(true); + + int numHits = Ticks.Count(r => r.IsHit); + + AnimateCompletion(numHits); + + if (numHits == HitObject.RequiredHits) + ApplyResult(r => r.Type = HitResult.LargeBonus); + } + else + { + if (timeOffset < 0) + return; + + int numHits = 0; + + foreach (var tick in Ticks) + { + if (tick.IsHit) + { + numHits++; + continue; + } + + if (!tick.Result.HasResult) + tick.TriggerResult(false); + } + + ApplyResult(r => r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.SmallBonus : HitResult.IgnoreMiss); + } + } } public void Update(Playfield playfield) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index fd8b8196cd..04ed6d0b87 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -144,14 +144,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables if (countHit >= HitObject.RequiredGoodHits) { - ApplyResult(r => - { - // With the Classic mod, don't award points for a finished drum roll, only for ticks. - if (r.Judgement.MaxResult == HitResult.LargeBonus) - r.Type = HitResult.IgnoreMiss; - else - r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Ok; - }); + ApplyResult(r => r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Ok); } else ApplyResult(r => r.Type = r.Judgement.MinResult); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 238aa2189f..34fe6c5a73 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private const double ring_appear_offset = 100; - private readonly Container ticks; + protected readonly Container Ticks; private readonly Container bodyContainer; private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } }); - AddInternal(ticks = new Container { RelativeSizeAxes = Axes.Both }); + AddInternal(Ticks = new Container { RelativeSizeAxes = Axes.Both }); } [BackgroundDependencyLoader] @@ -132,6 +132,20 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Origin = Anchor.Centre, }); + protected void AnimateCompletion(int numHits) + { + float completion = (float)numHits / HitObject.RequiredHits; + + expandingRing + .FadeTo(expandingRing.Alpha + Math.Clamp(completion / 16, 0.1f, 0.6f), 50) + .Then() + .FadeTo(completion / 8, 2000, Easing.OutQuint); + + MainPiece.Drawable.RotateTo((float)(completion * HitObject.Duration / 8), 4000, Easing.OutQuint); + + expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); + } + protected override void OnFree() { base.OnFree(); @@ -148,7 +162,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (hitObject) { case DrawableSwellTick tick: - ticks.Add(tick); + Ticks.Add(tick); break; } } @@ -156,7 +170,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override void ClearNestedHitObjects() { base.ClearNestedHitObjects(); - ticks.Clear(false); + Ticks.Clear(false); } protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject) @@ -176,7 +190,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { DrawableSwellTick nextTick = null; - foreach (var t in ticks) + foreach (var t in Ticks) { if (!t.Result.HasResult) { @@ -187,21 +201,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables nextTick?.TriggerResult(true); - int numHits = ticks.Count(r => r.IsHit); + int numHits = Ticks.Count(r => r.IsHit); - float completion = (float)numHits / HitObject.RequiredHits; - - expandingRing - .FadeTo(expandingRing.Alpha + Math.Clamp(completion / 16, 0.1f, 0.6f), 50) - .Then() - .FadeTo(completion / 8, 2000, Easing.OutQuint); - - MainPiece.Drawable.RotateTo((float)(completion * HitObject.Duration / 8), 4000, Easing.OutQuint); - - expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); + AnimateCompletion(numHits); if (numHits == HitObject.RequiredHits) - ApplyResult(r => r.Type = r.Judgement.MaxResult); + ApplyResult(r => r.Type = HitResult.Great); } else { @@ -210,7 +215,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables int numHits = 0; - foreach (var tick in ticks) + foreach (var tick in Ticks) { if (tick.IsHit) { @@ -222,14 +227,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables tick.TriggerResult(false); } - ApplyResult(r => - { - // With the Classic mod, don't award combo or accuracy for a finished swell. - if (r.Judgement.MaxResult == HitResult.LargeBonus) - r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.LargeBonus : r.Judgement.MinResult; - else - r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.Ok : r.Judgement.MinResult; - }); + ApplyResult(r => r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.Ok : r.Judgement.MinResult); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 47ccb9cc72..80e8bec0cb 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -52,16 +52,11 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public double RequiredGreatHits { get; protected set; } - /// - /// Defines if drum rolls are affected by the Classic mod, making them bonus only. - /// - private bool isBonus; - /// /// The length (in milliseconds) between ticks of this drumroll. /// Half of this value is the hit window of the ticks. /// - private double tickSpacing = 100; + protected double TickSpacing = 100; private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY; @@ -74,13 +69,13 @@ namespace osu.Game.Rulesets.Taiko.Objects double scoringDistance = base_distance * difficulty.SliderMultiplier * DifficultyControlPoint.SliderVelocity; Velocity = scoringDistance / timingPoint.BeatLength; - tickSpacing = timingPoint.BeatLength / TickRate; + TickSpacing = timingPoint.BeatLength / TickRate; overallDifficulty = difficulty.OverallDifficulty; } protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { - createTicks(cancellationToken); + CreateTicks(cancellationToken); RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * overallDifficulty); RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * overallDifficulty); @@ -88,21 +83,21 @@ namespace osu.Game.Rulesets.Taiko.Objects base.CreateNestedHitObjects(cancellationToken); } - private void createTicks(CancellationToken cancellationToken) + protected virtual void CreateTicks(CancellationToken cancellationToken) { - if (tickSpacing == 0) + if (TickSpacing == 0) return; bool first = true; - for (double t = StartTime; t < EndTime + tickSpacing / 2; t += tickSpacing) + for (double t = StartTime; t < EndTime + TickSpacing / 2; t += TickSpacing) { cancellationToken.ThrowIfCancellationRequested(); AddNested(new DrumRollTick { FirstTick = first, - TickSpacing = tickSpacing, + TickSpacing = TickSpacing, StartTime = t, IsStrong = IsStrong }); @@ -111,18 +106,7 @@ namespace osu.Game.Rulesets.Taiko.Objects } } - public void SetBonus(bool bonus) - { - isBonus = bonus; - - foreach (HitObject hitObject in NestedHitObjects) - { - if (hitObject is DrumRollTick drumRollTick) - drumRollTick.IsBonus = bonus; - } - } - - public override Judgement CreateJudgement() => new TaikoDrumRollJudgement { IsBonus = isBonus }; + public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs index 6aa08e7c76..433fdab908 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRollTick.cs @@ -27,12 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public double HitWindow => TickSpacing / 2; - /// - /// Defines if ticks are affected by the Classic mod, making them bonus only. - /// - public bool IsBonus = false; - - public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement { IsBonus = IsBonus }; + public override Judgement CreateJudgement() => new TaikoDrumRollTickJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs index bd91fcd076..cb91c46b4d 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs @@ -26,16 +26,6 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public int RequiredHits = 10; - /// - /// Defines if swells are affected by the Classic mod, making them bonus only. - /// - private bool isBonus; - - public void SetBonus(bool bonus) - { - isBonus = bonus; - } - protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { base.CreateNestedHitObjects(cancellationToken); @@ -47,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Objects } } - public override Judgement CreateJudgement() => new TaikoSwellJudgement { IsBonus = isBonus }; + public override Judgement CreateJudgement() => new TaikoSwellJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 7719f51f2f..4e0c8029fb 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -295,15 +295,6 @@ namespace osu.Game.Rulesets.Taiko.UI break; default: - // Don't draw judgement results for bonus sliderticks with the Classic mod. - switch (result.Type) - { - case HitResult.IgnoreHit: - case HitResult.IgnoreMiss: - case HitResult.LargeBonus: - return; - } - judgementContainer.Add(judgementPools[result.Type].Get(j => { j.Apply(result, judgedObject); From 9090e7502075ed9731f75408b43f5d9afe35646d Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sun, 19 Jun 2022 20:43:17 +0200 Subject: [PATCH 0043/2686] Add XML documentation --- .../Utils/OsuHitObjectGenerationUtils.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index b9c384f842..f503956aee 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -188,6 +188,11 @@ namespace osu.Game.Rulesets.Osu.Utils ); } + /// The beatmap hitObject is a part of. + /// The that should be checked. + /// If true, this method only returns true if hitObject is on a downbeat. + /// If false, it returns true if hitObject is on any beat. + /// true if hitObject is on a (down-)beat, false otherwise. public static bool IsHitObjectOnBeat(OsuBeatmap beatmap, OsuHitObject hitObject, bool downbeatsOnly = false) { var timingPoints = beatmap.ControlPointInfo.TimingPoints; @@ -205,6 +210,9 @@ namespace osu.Game.Rulesets.Osu.Utils return (timeSinceTimingPoint + 1) % length < 2; } + /// The target distance between the previous and the current . + /// The angle (in rad) by which the target angle should be offset. + /// Whether the relative angle should be positive or negative. public static float GetRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) { float angle = (float)(3 / (1 + 200 * Math.Pow(MathHelper.E, 0.016 * (targetDistance - 466))) + 0.45 + offset); From 1bb27cd4880f4dd4766d1cace022c37e0f23585b Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sun, 19 Jun 2022 23:03:41 +0200 Subject: [PATCH 0044/2686] Code optimisation --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 23 +++++++++++++++---- .../Utils/OsuHitObjectGenerationUtils.cs | 18 ++++----------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 2560ed921d..55151ae2c1 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -8,6 +8,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Osu.Utils; @@ -22,6 +23,8 @@ namespace osu.Game.Rulesets.Osu.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTarget)).ToArray(); + private static readonly float playfield_diagonal = OsuPlayfield.BASE_SIZE.LengthFast; + private Random? rng; public void ApplyToBeatmap(IBeatmap beatmap) @@ -43,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Mods bool invertFlow = false; if (i == 0 || - (positionInfos[i - 1].HitObject.NewCombo && (i <= 1 || !positionInfos[i - 2].HitObject.NewCombo) && (i <= 2 || !positionInfos[i - 3].HitObject.NewCombo)) || + (positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo && rng.NextDouble() < 0.6) || OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject, true) || (OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject) && rng.NextDouble() < 0.25)) { @@ -63,7 +66,7 @@ namespace osu.Game.Rulesets.Osu.Mods float flowChangeOffset = 0; float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.03f); - if (positionInfos[i - 1].HitObject.NewCombo && (i <= 1 || !positionInfos[i - 2].HitObject.NewCombo) && rng.NextDouble() < 0.6) + if (positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo && rng.NextDouble() < 0.6) { flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.05f); @@ -72,12 +75,12 @@ namespace osu.Game.Rulesets.Osu.Mods } if (invertFlow) - flowDirection ^= true; + flowDirection = !flowDirection; - positionInfos[i].RelativeAngle = OsuHitObjectGenerationUtils.GetRelativeTargetAngle( + positionInfos[i].RelativeAngle = getRelativeTargetAngle( positionInfos[i].DistanceFromPrevious, (sequenceOffset + oneTimeOffset) * (float)Math.Sqrt(positionInfos[i].DistanceFromPrevious) + - flowChangeOffset * (float)Math.Sqrt(640 - positionInfos[i].DistanceFromPrevious), + flowChangeOffset * (float)Math.Sqrt(playfield_diagonal - positionInfos[i].DistanceFromPrevious), flowDirection ); } @@ -85,5 +88,15 @@ namespace osu.Game.Rulesets.Osu.Mods osuBeatmap.HitObjects = OsuHitObjectGenerationUtils.RepositionHitObjects(positionInfos); } + + /// The target distance between the previous and the current . + /// The angle (in rad) by which the target angle should be offset. + /// Whether the relative angle should be positive or negative. + private static float getRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) + { + float angle = (float)(3 / (1 + 200 * Math.Exp(0.016 * (targetDistance - 466))) + 0.45 + offset); + float relativeAngle = (float)Math.PI - angle; + return flowDirection ? -relativeAngle : relativeAngle; + } } } diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index f503956aee..117d6f3a80 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -196,7 +196,7 @@ namespace osu.Game.Rulesets.Osu.Utils public static bool IsHitObjectOnBeat(OsuBeatmap beatmap, OsuHitObject hitObject, bool downbeatsOnly = false) { var timingPoints = beatmap.ControlPointInfo.TimingPoints; - var currentTimingPoint = timingPoints.Reverse().FirstOrDefault(p => p.Time <= hitObject.StartTime); + var currentTimingPoint = timingPoints.LastOrDefault(p => p.Time <= hitObject.StartTime); if (currentTimingPoint == null) return false; @@ -210,21 +210,11 @@ namespace osu.Game.Rulesets.Osu.Utils return (timeSinceTimingPoint + 1) % length < 2; } - /// The target distance between the previous and the current . - /// The angle (in rad) by which the target angle should be offset. - /// Whether the relative angle should be positive or negative. - public static float GetRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) - { - float angle = (float)(3 / (1 + 200 * Math.Pow(MathHelper.E, 0.016 * (targetDistance - 466))) + 0.45 + offset); - float relativeAngle = MathHelper.Pi - angle; - return flowDirection ? -relativeAngle : relativeAngle; - } - public static float RandomGaussian(Random rng, float mean = 0, float stdDev = 1) { - double x1 = 1 - rng.NextDouble(); - double x2 = 1 - rng.NextDouble(); - double stdNormal = Math.Sqrt(-2 * Math.Log(x1)) * Math.Sin(MathHelper.TwoPi * x2); + double x1 = rng.NextDouble(); + double x2 = rng.NextDouble(); + double stdNormal = Math.Sqrt(-2 * Math.Log(x1)) * Math.Sin(2 * Math.PI * x2); return mean + stdDev * (float)stdNormal; } } From 3356742ba2d5b74372c6641a4d857cf6138ad44f Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Mon, 20 Jun 2022 00:05:03 +0200 Subject: [PATCH 0045/2686] Adjust angle offset caluclations --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 55151ae2c1..ef3eaf2a9d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Mods OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject, true) || (OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject) && rng.NextDouble() < 0.25)) { - sequenceOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.02f); + sequenceOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.0015f); if (rng.NextDouble() < 0.6) invertFlow = true; @@ -64,11 +64,11 @@ namespace osu.Game.Rulesets.Osu.Mods else { float flowChangeOffset = 0; - float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.03f); + float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.0015f); if (positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo && rng.NextDouble() < 0.6) { - flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.05f); + flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.002f); if (rng.NextDouble() < 0.8) invertFlow = true; @@ -79,8 +79,8 @@ namespace osu.Game.Rulesets.Osu.Mods positionInfos[i].RelativeAngle = getRelativeTargetAngle( positionInfos[i].DistanceFromPrevious, - (sequenceOffset + oneTimeOffset) * (float)Math.Sqrt(positionInfos[i].DistanceFromPrevious) + - flowChangeOffset * (float)Math.Sqrt(playfield_diagonal - positionInfos[i].DistanceFromPrevious), + (sequenceOffset + oneTimeOffset) * positionInfos[i].DistanceFromPrevious + + flowChangeOffset * (playfield_diagonal - positionInfos[i].DistanceFromPrevious), flowDirection ); } From a912bcadf82aa7eb4e885cf81da35e980824dd55 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Mon, 20 Jun 2022 00:19:29 +0200 Subject: [PATCH 0046/2686] Fix possible exception caused by `log(0)` --- osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index 117d6f3a80..ce7f39cdf8 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -212,8 +212,8 @@ namespace osu.Game.Rulesets.Osu.Utils public static float RandomGaussian(Random rng, float mean = 0, float stdDev = 1) { - double x1 = rng.NextDouble(); - double x2 = rng.NextDouble(); + double x1 = 1 - rng.NextDouble(); + double x2 = 1 - rng.NextDouble(); double stdNormal = Math.Sqrt(-2 * Math.Log(x1)) * Math.Sin(2 * Math.PI * x2); return mean + stdDev * (float)stdNormal; } From 6c8042642aaf4e04c32a98e45ee330945bc280e9 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Mon, 20 Jun 2022 17:22:41 +0200 Subject: [PATCH 0047/2686] Reduce code duplication --- .../Mods/TaikoModClassic.cs | 106 +++++------------- .../Objects/Drawables/DrawableSwell.cs | 44 ++++---- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 16 ++- 3 files changed, 63 insertions(+), 103 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index 7141afe791..704185cc3c 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -4,6 +4,7 @@ #nullable disable using System.Linq; +using System.Collections.Generic; using System.Threading; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; @@ -40,19 +41,17 @@ namespace osu.Game.Rulesets.Taiko.Mods var hitObjects = taikoBeatmap.HitObjects.Select(ho => { - if (ho is DrumRoll drumRoll) + switch (ho) { - var newDrumRoll = new ClassicDrumRoll(drumRoll); - return newDrumRoll; - } + case DrumRoll drumRoll: + return new ClassicDrumRoll(drumRoll); - if (ho is Swell swell) - { - var newSwell = new ClassicSwell(swell); - return newSwell; - } + case Swell swell: + return new ClassicSwell(swell); - return ho; + default: + return ho; + } }).ToList(); taikoBeatmap.HitObjects = hitObjects; @@ -73,33 +72,35 @@ namespace osu.Game.Rulesets.Taiko.Mods public override Judgement CreateJudgement() => new TaikoClassicDrumRollJudgement(); - protected override void CreateTicks(CancellationToken cancellationToken) + protected override List CreateTicks(CancellationToken cancellationToken) { - if (TickSpacing == 0) - return; + List oldTicks = base.CreateTicks(cancellationToken); - bool first = true; - - for (double t = StartTime; t < EndTime + TickSpacing / 2; t += TickSpacing) + List newTicks = oldTicks.Select(oldTick => { - cancellationToken.ThrowIfCancellationRequested(); - - AddNested(new ClassicDrumRollTick + if (oldTick is DrumRollTick drumRollTick) { - FirstTick = first, - TickSpacing = TickSpacing, - StartTime = t, - IsStrong = IsStrong - }); + return new ClassicDrumRollTick(drumRollTick); + } - first = false; - } + return oldTick; + }).ToList(); + + return newTicks; } } private class ClassicDrumRollTick : DrumRollTick { public override Judgement CreateJudgement() => new TaikoClassicDrumRollTickJudgement(); + + public ClassicDrumRollTick(DrumRollTick original) + { + StartTime = original.StartTime; + Samples = original.Samples; + FirstTick = original.FirstTick; + TickSpacing = original.TickSpacing; + } } private class ClassicSwell : Swell @@ -118,12 +119,12 @@ namespace osu.Game.Rulesets.Taiko.Mods private class TaikoClassicDrumRollJudgement : TaikoDrumRollJudgement { - public override HitResult MaxResult => HitResult.LargeBonus; + public override HitResult MaxResult => HitResult.IgnoreHit; } private class TaikoClassicDrumRollTickJudgement : TaikoDrumRollTickJudgement { - public override HitResult MaxResult => HitResult.LargeBonus; + public override HitResult MaxResult => HitResult.SmallBonus; } private class TaikoClassicSwellJudgement : TaikoSwellJudgement @@ -143,7 +144,7 @@ namespace osu.Game.Rulesets.Taiko.Mods if (timeOffset < 0) return; - ApplyResult(r => r.Type = HitResult.IgnoreMiss); + ApplyResult(r => r.Type = HitResult.IgnoreHit); } } @@ -151,52 +152,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public override bool DisplayResult => false; - protected override void CheckForResult(bool userTriggered, double timeOffset) - { - if (userTriggered) - { - DrawableSwellTick nextTick = null; - - foreach (var t in Ticks) - { - if (!t.Result.HasResult) - { - nextTick = t; - break; - } - } - - nextTick?.TriggerResult(true); - - int numHits = Ticks.Count(r => r.IsHit); - - AnimateCompletion(numHits); - - if (numHits == HitObject.RequiredHits) - ApplyResult(r => r.Type = HitResult.LargeBonus); - } - else - { - if (timeOffset < 0) - return; - - int numHits = 0; - - foreach (var tick in Ticks) - { - if (tick.IsHit) - { - numHits++; - continue; - } - - if (!tick.Result.HasResult) - tick.TriggerResult(false); - } - - ApplyResult(r => r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.SmallBonus : HitResult.IgnoreMiss); - } - } + protected override HitResult OkResult => HitResult.SmallBonus; } public void Update(Playfield playfield) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 34fe6c5a73..5b70c59376 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -34,7 +34,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private const double ring_appear_offset = 100; - protected readonly Container Ticks; + protected virtual HitResult OkResult => HitResult.Ok; + private readonly Container ticks; private readonly Container bodyContainer; private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; @@ -114,7 +115,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } }); - AddInternal(Ticks = new Container { RelativeSizeAxes = Axes.Both }); + AddInternal(ticks = new Container { RelativeSizeAxes = Axes.Both }); } [BackgroundDependencyLoader] @@ -132,20 +133,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Origin = Anchor.Centre, }); - protected void AnimateCompletion(int numHits) - { - float completion = (float)numHits / HitObject.RequiredHits; - - expandingRing - .FadeTo(expandingRing.Alpha + Math.Clamp(completion / 16, 0.1f, 0.6f), 50) - .Then() - .FadeTo(completion / 8, 2000, Easing.OutQuint); - - MainPiece.Drawable.RotateTo((float)(completion * HitObject.Duration / 8), 4000, Easing.OutQuint); - - expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); - } - protected override void OnFree() { base.OnFree(); @@ -162,7 +149,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (hitObject) { case DrawableSwellTick tick: - Ticks.Add(tick); + ticks.Add(tick); break; } } @@ -170,7 +157,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override void ClearNestedHitObjects() { base.ClearNestedHitObjects(); - Ticks.Clear(false); + ticks.Clear(false); } protected override DrawableHitObject CreateNestedHitObject(HitObject hitObject) @@ -190,7 +177,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { DrawableSwellTick nextTick = null; - foreach (var t in Ticks) + foreach (var t in ticks) { if (!t.Result.HasResult) { @@ -201,12 +188,21 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables nextTick?.TriggerResult(true); - int numHits = Ticks.Count(r => r.IsHit); + int numHits = ticks.Count(r => r.IsHit); - AnimateCompletion(numHits); + float completion = (float)numHits / HitObject.RequiredHits; + + expandingRing + .FadeTo(expandingRing.Alpha + Math.Clamp(completion / 16, 0.1f, 0.6f), 50) + .Then() + .FadeTo(completion / 8, 2000, Easing.OutQuint); + + MainPiece.Drawable.RotateTo((float)(completion * HitObject.Duration / 8), 4000, Easing.OutQuint); + + expandingRing.ScaleTo(1f + Math.Min(target_ring_scale - 1f, (target_ring_scale - 1f) * completion * 1.3f), 260, Easing.OutQuint); if (numHits == HitObject.RequiredHits) - ApplyResult(r => r.Type = HitResult.Great); + ApplyResult(r => r.Type = r.Judgement.MaxResult); } else { @@ -215,7 +211,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables int numHits = 0; - foreach (var tick in Ticks) + foreach (var tick in ticks) { if (tick.IsHit) { @@ -227,7 +223,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables tick.TriggerResult(false); } - ApplyResult(r => r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.Ok : r.Judgement.MinResult); + ApplyResult(r => r.Type = numHits > HitObject.RequiredHits / 2 ? OkResult : r.Judgement.MinResult); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 80e8bec0cb..5e5d9daeb1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -5,6 +5,7 @@ using osu.Game.Rulesets.Objects.Types; using System; +using System.Collections.Generic; using System.Threading; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -75,7 +76,10 @@ namespace osu.Game.Rulesets.Taiko.Objects protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { - CreateTicks(cancellationToken); + foreach (TaikoHitObject tick in CreateTicks(cancellationToken)) + { + AddNested(tick); + } RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * overallDifficulty); RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * overallDifficulty); @@ -83,10 +87,12 @@ namespace osu.Game.Rulesets.Taiko.Objects base.CreateNestedHitObjects(cancellationToken); } - protected virtual void CreateTicks(CancellationToken cancellationToken) + protected virtual List CreateTicks(CancellationToken cancellationToken) { + List ticks = new List(); + if (TickSpacing == 0) - return; + return ticks; bool first = true; @@ -94,7 +100,7 @@ namespace osu.Game.Rulesets.Taiko.Objects { cancellationToken.ThrowIfCancellationRequested(); - AddNested(new DrumRollTick + ticks.Add(new DrumRollTick { FirstTick = first, TickSpacing = TickSpacing, @@ -104,6 +110,8 @@ namespace osu.Game.Rulesets.Taiko.Objects first = false; } + + return ticks; } public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); From c5fd48372ba8d94f39ecfb62d899474ccc32eca7 Mon Sep 17 00:00:00 2001 From: vun Date: Wed, 22 Jun 2022 17:17:19 +0800 Subject: [PATCH 0048/2686] Flatten speed bonus for stamina --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 6c0c01cb2d..be1514891c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -13,10 +13,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// /// Applies a speed bonus dependent on the time since the last hit performed using this key. /// - /// The duration between the current and previous note hit using the same key. - private static double speedBonus(double notePairDuration) + /// The interval between the current and previous note hit using the same key. + private static double speedBonus(double interval) { - return Math.Pow(0.4, notePairDuration / 1000); + return Math.Pow(0.8, interval / 1000); } /// @@ -40,9 +40,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return 0.0; } - double objectStrain = 0; - // Console.WriteLine(speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime)); - objectStrain += speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime); + double objectStrain = 0.85; + objectStrain *= speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime); return objectStrain; } } From 2f1186d3284b8cad32d7c6ae83a50bc72d00b326 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Wed, 22 Jun 2022 16:49:07 +0200 Subject: [PATCH 0049/2686] Add comments and XML doc --- osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index ce7f39cdf8..a890dbde43 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -210,10 +210,16 @@ namespace osu.Game.Rulesets.Osu.Utils return (timeSinceTimingPoint + 1) % length < 2; } + /// + /// Generates a random number from a normal distribution using the Box-Muller transform. + /// public static float RandomGaussian(Random rng, float mean = 0, float stdDev = 1) { + // Generate 2 random numbers in the interval (0,1]. + // x1 must not be 0 since log(0) = undefined. double x1 = 1 - rng.NextDouble(); double x2 = 1 - rng.NextDouble(); + double stdNormal = Math.Sqrt(-2 * Math.Log(x1)) * Math.Sin(2 * Math.PI * x2); return mean + stdDev * (float)stdNormal; } From f42aac99546889a66303521674283e92e0a240bf Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 23 Jun 2022 17:10:30 +0800 Subject: [PATCH 0050/2686] TAIKO-6 Pre-evaluate colour to avoid per-note evaluation --- .../Difficulty/Evaluators/ColourEvaluator.cs | 12 ++-- .../Preprocessing/TaikoDifficultyHitObject.cs | 21 +++--- .../TaikoDifficultyHitObjectColour.cs | 65 ++++++++++++------- .../Difficulty/Skills/Colour.cs | 11 +++- 4 files changed, 72 insertions(+), 37 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 32bc8429b8..14f95fbdd5 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -12,10 +12,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return Math.Tanh(Math.E * -(val - center) / width); } - public static double EvaluateDifficultyOf(DifficultyHitObject current) + public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour colour) { - TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; - TaikoDifficultyHitObjectColour colour = taikoCurrent.Colour; if (colour == null) return 0; double objectStrain = 1.85; @@ -29,9 +27,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators objectStrain *= sigmoid(colour.DeltaRunLength, 2, 2) * 0.5 + 0.5; } - objectStrain *= -sigmoid(colour.RepetitionInterval, 1, 8); // * 0.5 + 0.5; - // Console.WriteLine($"{current.StartTime},{colour.Delta},{colour.RepetitionInterval},{objectStrain}"); + objectStrain *= -sigmoid(colour.RepetitionInterval, 1, 8); return objectStrain; } + + public static double EvaluateDifficultyOf(DifficultyHitObject current) + { + return EvaluateDifficultyOf(((TaikoDifficultyHitObject)current).Colour); + } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index ed93595e93..f35cf1d8b9 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -10,6 +10,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { @@ -29,10 +30,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing public readonly TaikoDifficultyHitObjectRhythm Rhythm; /// - /// Colour data for this hit object. This is used by colour evaluator to calculate colour, but can be used - /// differently by other skills in the future. + /// Colour data for this hit object. This is used by colour evaluator to calculate colour difficulty, but can be used + /// by other skills in the future. + /// This need to be writeable by TaikoDifficultyHitObjectColour so that it can assign potentially reused instances /// - public readonly TaikoDifficultyHitObjectColour Colour; + public TaikoDifficultyHitObjectColour Colour; /// /// The hit type of this hit object. @@ -64,8 +66,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing ); } - // Find repetition interval for the final TaikoDifficultyHitObjectColour - ((TaikoDifficultyHitObject)difficultyHitObject.Last()).Colour?.FindRepetitionInterval(); + List colours = TaikoDifficultyHitObjectColour.CreateColoursFor(difficultyHitObject); + + // Pre-evaluate colours + for (int i = 0; i < colours.Count; i++) + { + colours[i].EvaluatedDifficulty = ColourEvaluator.EvaluateDifficultyOf(colours[i]); + } + return difficultyHitObject; } @@ -115,9 +123,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing NoteIndex = noteObjects.Count; noteObjects.Add(this); - - // Need to be done after NoteIndex is set. - Colour = TaikoDifficultyHitObjectColour.GetInstanceFor(this); } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index 8304c0b126..74b8899c60 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -1,6 +1,8 @@ #nullable disable using System; +using System.Collections.Generic; +using osu.Game.Rulesets.Difficulty.Preprocessing; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { @@ -11,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { private const int max_repetition_interval = 16; - private TaikoDifficultyHitObjectColour previous; + public TaikoDifficultyHitObjectColour Previous { get; private set; } /// /// True if the current colour is different from the previous colour. @@ -30,35 +32,54 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public int RepetitionInterval { get; private set; } + /// + /// Evaluated colour difficulty is cached here, as difficulty don't need to be calculated per-note. + /// + /// TODO: Consider having all evaluated difficulty cached in TaikoDifficultyHitObject instead, since we may be + /// reusing evaluator results in the future. + public double EvaluatedDifficulty; + public TaikoDifficultyHitObjectColour repeatedColour { get; private set; } /// /// Get the instance for the given hitObject. This is implemented /// as a static function instead of constructor to allow for reusing existing instances. - /// TODO: findRepetitionInterval needs to be called a final time after all hitObjects have been processed. /// - public static TaikoDifficultyHitObjectColour GetInstanceFor(TaikoDifficultyHitObject hitObject) + public static List CreateColoursFor(List hitObjects) { - TaikoDifficultyHitObject lastObject = hitObject.PreviousNote(0); - TaikoDifficultyHitObjectColour previous = lastObject?.Colour; - bool delta = lastObject == null || hitObject.HitType != lastObject.HitType; + List colours = new List(); - if (previous != null && delta == previous.Delta) + for (int i = 0; i < hitObjects.Count; i++) { - previous.DeltaRunLength += 1; - return previous; + TaikoDifficultyHitObject hitObject = (TaikoDifficultyHitObject)hitObjects[i]; + TaikoDifficultyHitObject lastObject = hitObject.PreviousNote(0); + TaikoDifficultyHitObjectColour previous = lastObject?.Colour; + bool delta = lastObject == null || hitObject.HitType != lastObject.HitType; + + if (previous != null && delta == previous.Delta) + { + previous.DeltaRunLength += 1; + hitObject.Colour = previous; + continue; + } + + TaikoDifficultyHitObjectColour colour = new TaikoDifficultyHitObjectColour() + { + Delta = delta, + DeltaRunLength = 1, + RepetitionInterval = max_repetition_interval + 1, + Previous = previous + }; + hitObject.Colour = colour; + colours.Add(colour); } - // Calculate RepetitionInterval for previous - previous?.FindRepetitionInterval(); - - return new TaikoDifficultyHitObjectColour() + for (int i = 0; i < colours.Count; i++) { - Delta = delta, - DeltaRunLength = 1, - RepetitionInterval = max_repetition_interval + 1, - previous = previous - }; + colours[i].FindRepetitionInterval(); + } + + return colours; } /// @@ -67,14 +88,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public void FindRepetitionInterval() { - if (previous?.previous == null) + if (Previous?.Previous == null) { RepetitionInterval = max_repetition_interval + 1; return; } - int interval = previous.DeltaRunLength; - TaikoDifficultyHitObjectColour other = previous.previous; + int interval = Previous.DeltaRunLength; + TaikoDifficultyHitObjectColour other = Previous.Previous; while (other != null && interval < max_repetition_interval) { @@ -86,7 +107,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing } interval += other.DeltaRunLength; - other = other.previous; + other = other.Previous; } RepetitionInterval = max_repetition_interval + 1; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index a4f3f460c7..0d69104a58 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { @@ -25,7 +25,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double StrainValueOf(DifficultyHitObject current) { - return ColourEvaluator.EvaluateDifficultyOf(current); + TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)current).Colour; + double difficulty = colour == null ? 0 : colour.EvaluatedDifficulty; + // if (current != null && colour != null) + // { + // System.Console.WriteLine($"{current.StartTime},{colour.Delta},{colour.RepetitionInterval},{difficulty}"); + // } + + return difficulty; } } } From 52de8bae9bfa6e1d6859e64335366bd445bbcf8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 24 Jun 2022 12:54:33 +0200 Subject: [PATCH 0051/2686] Apply NRT to `TaikoModClassic` --- osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index 704185cc3c..9f82d54e65 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.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. -#nullable disable - using System.Linq; using System.Collections.Generic; +using System.Diagnostics; using System.Threading; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; @@ -21,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset, IUpdatableByPlayfield, IApplicableAfterBeatmapConversion { - private DrawableTaikoRuleset drawableTaikoRuleset; + private DrawableTaikoRuleset? drawableTaikoRuleset; public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { @@ -160,6 +159,8 @@ namespace osu.Game.Rulesets.Taiko.Mods // Classic taiko scrolls at a constant 100px per 1000ms. More notes become visible as the playfield is lengthened. const float scroll_rate = 10; + Debug.Assert(drawableTaikoRuleset != null); + // Since the time range will depend on a positional value, it is referenced to the x480 pixel space. float ratio = drawableTaikoRuleset.DrawHeight / 480; From bcb9cba2d7019473679e8eaf9c4c22dcbc61fa94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 24 Jun 2022 12:56:47 +0200 Subject: [PATCH 0052/2686] Reorder classes for legibility, group into regions --- .../Mods/TaikoModClassic.cs | 66 +++++++++++-------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index 9f82d54e65..f5541f5191 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -56,6 +56,13 @@ namespace osu.Game.Rulesets.Taiko.Mods taikoBeatmap.HitObjects = hitObjects; } + #region Classic drum roll + + private class TaikoClassicDrumRollJudgement : TaikoDrumRollJudgement + { + public override HitResult MaxResult => HitResult.IgnoreHit; + } + private class ClassicDrumRoll : DrumRoll { public ClassicDrumRoll(DrumRoll original) @@ -89,6 +96,11 @@ namespace osu.Game.Rulesets.Taiko.Mods } } + private class TaikoClassicDrumRollTickJudgement : TaikoDrumRollTickJudgement + { + public override HitResult MaxResult => HitResult.SmallBonus; + } + private class ClassicDrumRollTick : DrumRollTick { public override Judgement CreateJudgement() => new TaikoClassicDrumRollTickJudgement(); @@ -102,35 +114,6 @@ namespace osu.Game.Rulesets.Taiko.Mods } } - private class ClassicSwell : Swell - { - public ClassicSwell(Swell original) - { - StartTime = original.StartTime; - Samples = original.Samples; - EndTime = original.EndTime; - Duration = original.Duration; - RequiredHits = original.RequiredHits; - } - - public override Judgement CreateJudgement() => new TaikoClassicSwellJudgement(); - } - - private class TaikoClassicDrumRollJudgement : TaikoDrumRollJudgement - { - public override HitResult MaxResult => HitResult.IgnoreHit; - } - - private class TaikoClassicDrumRollTickJudgement : TaikoDrumRollTickJudgement - { - public override HitResult MaxResult => HitResult.SmallBonus; - } - - private class TaikoClassicSwellJudgement : TaikoSwellJudgement - { - public override HitResult MaxResult => HitResult.LargeBonus; - } - private class ClassicDrawableDrumRoll : DrawableDrumRoll { public override bool DisplayResult => false; @@ -147,6 +130,29 @@ namespace osu.Game.Rulesets.Taiko.Mods } } + #endregion + + #region Classic swell + + private class TaikoClassicSwellJudgement : TaikoSwellJudgement + { + public override HitResult MaxResult => HitResult.LargeBonus; + } + + private class ClassicSwell : Swell + { + public ClassicSwell(Swell original) + { + StartTime = original.StartTime; + Samples = original.Samples; + EndTime = original.EndTime; + Duration = original.Duration; + RequiredHits = original.RequiredHits; + } + + public override Judgement CreateJudgement() => new TaikoClassicSwellJudgement(); + } + private class ClassicDrawableSwell : DrawableSwell { public override bool DisplayResult => false; @@ -154,6 +160,8 @@ namespace osu.Game.Rulesets.Taiko.Mods protected override HitResult OkResult => HitResult.SmallBonus; } + #endregion + public void Update(Playfield playfield) { // Classic taiko scrolls at a constant 100px per 1000ms. More notes become visible as the playfield is lengthened. From f47b74a93882444db536c2764bd531a6a712d820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 24 Jun 2022 13:00:12 +0200 Subject: [PATCH 0053/2686] Move `OkResult` from drawable swell to judgement --- .../Judgements/TaikoSwellJudgement.cs | 5 +++++ osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs | 4 ++-- .../Objects/Drawables/DrawableSwell.cs | 9 ++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs index b2ac0b7f03..90ba7e276c 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs @@ -9,6 +9,11 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoSwellJudgement : TaikoJudgement { + /// + /// The to grant when the player has hit more than half of swell ticks. + /// + public virtual HitResult OkResult => HitResult.Ok; + protected override double HealthIncreaseFor(HitResult result) { switch (result) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index f5541f5191..9100c0b4be 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -137,6 +137,8 @@ namespace osu.Game.Rulesets.Taiko.Mods private class TaikoClassicSwellJudgement : TaikoSwellJudgement { public override HitResult MaxResult => HitResult.LargeBonus; + + public override HitResult OkResult => HitResult.SmallBonus; } private class ClassicSwell : Swell @@ -156,8 +158,6 @@ namespace osu.Game.Rulesets.Taiko.Mods private class ClassicDrawableSwell : DrawableSwell { public override bool DisplayResult => false; - - protected override HitResult OkResult => HitResult.SmallBonus; } #endregion diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 5b70c59376..cb0f59a9fb 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Judgements; using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; @@ -34,7 +34,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private const double ring_appear_offset = 100; - protected virtual HitResult OkResult => HitResult.Ok; private readonly Container ticks; private readonly Container bodyContainer; private readonly CircularContainer targetRing; @@ -223,7 +222,11 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables tick.TriggerResult(false); } - ApplyResult(r => r.Type = numHits > HitObject.RequiredHits / 2 ? OkResult : r.Judgement.MinResult); + ApplyResult(r => + { + var swellJudgement = (TaikoSwellJudgement)r.Judgement; + r.Type = numHits > HitObject.RequiredHits / 2 ? swellJudgement.OkResult : swellJudgement.MinResult; + }); } } From 3497e966fd97a834c17ad2046e59f37ba14f56c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 24 Jun 2022 13:01:16 +0200 Subject: [PATCH 0054/2686] Revert no longer needed access modifier change --- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 5e5d9daeb1..21c7f13fec 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Taiko.Objects /// The length (in milliseconds) between ticks of this drumroll. /// Half of this value is the hit window of the ticks. /// - protected double TickSpacing = 100; + private double tickSpacing = 100; private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY; @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Taiko.Objects double scoringDistance = base_distance * difficulty.SliderMultiplier * DifficultyControlPoint.SliderVelocity; Velocity = scoringDistance / timingPoint.BeatLength; - TickSpacing = timingPoint.BeatLength / TickRate; + tickSpacing = timingPoint.BeatLength / TickRate; overallDifficulty = difficulty.OverallDifficulty; } @@ -91,19 +91,19 @@ namespace osu.Game.Rulesets.Taiko.Objects { List ticks = new List(); - if (TickSpacing == 0) + if (tickSpacing == 0) return ticks; bool first = true; - for (double t = StartTime; t < EndTime + TickSpacing / 2; t += TickSpacing) + for (double t = StartTime; t < EndTime + tickSpacing / 2; t += tickSpacing) { cancellationToken.ThrowIfCancellationRequested(); ticks.Add(new DrumRollTick { FirstTick = first, - TickSpacing = TickSpacing, + TickSpacing = tickSpacing, StartTime = t, IsStrong = IsStrong }); From 09768cd74054e6cb806f0858bb5732bc9b27fd61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 24 Jun 2022 13:43:02 +0200 Subject: [PATCH 0055/2686] Add test coverage --- .../Mods/TestSceneTaikoModClassic.cs | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModClassic.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModClassic.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModClassic.cs new file mode 100644 index 0000000000..9028f411ce --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModClassic.cs @@ -0,0 +1,80 @@ +// 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 NUnit.Framework; +using osu.Game.Rulesets.Replays; +using osu.Game.Rulesets.Taiko.Beatmaps; +using osu.Game.Rulesets.Taiko.Mods; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Replays; + +namespace osu.Game.Rulesets.Taiko.Tests.Mods +{ + public class TestSceneTaikoModClassic : TaikoModTestScene + { + [Test] + public void TestHittingDrumRollsIsOptional() => CreateModTest(new ModTestData + { + Mod = new TaikoModClassic(), + Autoplay = false, + Beatmap = new TaikoBeatmap + { + BeatmapInfo = { Ruleset = CreatePlayerRuleset().RulesetInfo }, + HitObjects = new List + { + new Hit + { + StartTime = 1000, + Type = HitType.Centre + }, + new DrumRoll + { + StartTime = 3000, + EndTime = 6000 + } + } + }, + ReplayFrames = new List + { + new TaikoReplayFrame(1000, TaikoAction.LeftCentre), + new TaikoReplayFrame(1001) + }, + PassCondition = () => Player.ScoreProcessor.HasCompleted.Value + && Player.ScoreProcessor.Combo.Value == 1 + && Player.ScoreProcessor.Accuracy.Value == 1 + }); + + [Test] + public void TestHittingSwellsIsOptional() => CreateModTest(new ModTestData + { + Mod = new TaikoModClassic(), + Autoplay = false, + Beatmap = new TaikoBeatmap + { + BeatmapInfo = { Ruleset = CreatePlayerRuleset().RulesetInfo }, + HitObjects = new List + { + new Hit + { + StartTime = 1000, + Type = HitType.Centre + }, + new Swell + { + StartTime = 3000, + EndTime = 6000 + } + } + }, + ReplayFrames = new List + { + new TaikoReplayFrame(1000, TaikoAction.LeftCentre), + new TaikoReplayFrame(1001) + }, + PassCondition = () => Player.ScoreProcessor.HasCompleted.Value + && Player.ScoreProcessor.Combo.Value == 1 + && Player.ScoreProcessor.Accuracy.Value == 1 + }); + } +} From 15372267e17c78c919c764362d0d32c5c98d99cd Mon Sep 17 00:00:00 2001 From: vun Date: Sat, 25 Jun 2022 22:42:56 +0800 Subject: [PATCH 0056/2686] Implement new colour encoding --- .../Difficulty/Evaluators/ColourEvaluator.cs | 16 +--- .../Preprocessing/ColourEncoding.cs | 68 ++++++++++++++++ .../Preprocessing/CoupledColourEncoding.cs | 73 +++++++++++++++++ .../Preprocessing/TaikoDifficultyHitObject.cs | 12 +-- .../TaikoDifficultyHitObjectColour.cs | 81 +++++++------------ .../Difficulty/Skills/Colour.cs | 15 +++- 6 files changed, 188 insertions(+), 77 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/CoupledColourEncoding.cs diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 14f95fbdd5..1627833e8a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -14,21 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour colour) { - if (colour == null) return 0; - - double objectStrain = 1.85; - - if (colour.Delta) - { - objectStrain *= sigmoid(colour.DeltaRunLength, 3, 3) * 0.5 + 0.5; - } - else - { - objectStrain *= sigmoid(colour.DeltaRunLength, 2, 2) * 0.5 + 0.5; - } - - objectStrain *= -sigmoid(colour.RepetitionInterval, 1, 8); - return objectStrain; + return 1; } public static double EvaluateDifficultyOf(DifficultyHitObject current) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs new file mode 100644 index 0000000000..e2ac40170e --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using osu.Game.Rulesets.Difficulty.Preprocessing; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing +{ + public class ColourEncoding + { + /// + /// Amount consecutive notes of the same colour + /// + public int MonoRunLength = 1; + + /// + /// Amount of consecutive encoding with the same + /// + public int EncodingRunLength = 1; + + /// + /// Beginning index in the data that this encodes + /// + public int StartIndex = 0; + + public bool isIdenticalTo(ColourEncoding other) + { + return other.MonoRunLength == MonoRunLength && other.EncodingRunLength == EncodingRunLength; + } + + public static List Encode(List data) + { + // Encoding mono lengths + List firstPass = new List(); + ColourEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) + { + TaikoDifficultyHitObject taikoObject = (TaikoDifficultyHitObject)data[i]; + // This ignores all non-note objects, which may or may not be the desired behaviour + TaikoDifficultyHitObject previousObject = (TaikoDifficultyHitObject)taikoObject.PreviousNote(0); + + if (previousObject == null || lastEncoded == null || taikoObject.HitType != previousObject.HitType) + { + lastEncoded = new ColourEncoding(); + lastEncoded.StartIndex = i; + firstPass.Add(lastEncoded); + continue; + } + + lastEncoded.MonoRunLength += 1; + } + + // Encode encoding lengths + List secondPass = new List(); + lastEncoded = null; + for (int i = 0; i < firstPass.Count; i++) + { + if (i == 0 || lastEncoded == null || firstPass[i].MonoRunLength != firstPass[i - 1].MonoRunLength) + { + lastEncoded = firstPass[i]; + secondPass.Add(firstPass[i]); + continue; + } + + lastEncoded.EncodingRunLength += 1; + } + + return secondPass; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/CoupledColourEncoding.cs new file mode 100644 index 0000000000..81e8ae006f --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/CoupledColourEncoding.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing +{ + public class CoupledColourEncoding + { + public int RunLength = 1; + + public ColourEncoding[] Payload; + + /// + /// Beginning index in the data that this encodes + /// + public int StartIndex { get; private set; } = 0; + + public int EndIndex { get; private set; } = 0; + + private CoupledColourEncoding(ColourEncoding[] payload) + { + Payload = payload; + } + + public static List Encode(List data) + { + List encoded = new List(); + + CoupledColourEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) + { + if (lastEncoded != null) lastEncoded.EndIndex = data[i].StartIndex - 1; + + if (i >= data.Count - 2 || !data[i].isIdenticalTo(data[i + 2])) + { + lastEncoded = new CoupledColourEncoding(new ColourEncoding[] { data[i] }); + lastEncoded.StartIndex = data[i].StartIndex; + } + else + { + lastEncoded = new CoupledColourEncoding(new ColourEncoding[] { data[i], data[i + 1] }); + lastEncoded.StartIndex = data[i].StartIndex; + lastEncoded.RunLength = 3; + i++; + + // Peek 2 indices ahead + while (i < data.Count - 2 && data[i].isIdenticalTo(data[i + 2])) + { + lastEncoded.RunLength += 1; + i++; + } + + // Skip over peeked data + i++; + } + + encoded.Add(lastEncoded); + } + + return encoded; + } + + public bool hasIdenticalPayload(CoupledColourEncoding other) + { + if (this.Payload.Length != other.Payload.Length) return false; + + for (int i = 0; i < this.Payload.Length; i++) + { + if (!this.Payload[i].isIdenticalTo(other.Payload[i])) return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index f35cf1d8b9..1ee905d94c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -52,21 +52,21 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// The rate at which the gameplay clock is run at. public static List Create(IBeatmap beatmap, double clockRate) { - List difficultyHitObject = new List(); + List difficultyHitObjects = new List(); List centreObjects = new List(); List rimObjects = new List(); List noteObjects = new List(); for (int i = 2; i < beatmap.HitObjects.Count; i++) { - difficultyHitObject.Add( + difficultyHitObjects.Add( new TaikoDifficultyHitObject( - beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObject, - centreObjects, rimObjects, noteObjects, difficultyHitObject.Count) + beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObjects, + centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count) ); } - List colours = TaikoDifficultyHitObjectColour.CreateColoursFor(difficultyHitObject); + List colours = TaikoDifficultyHitObjectColour.EncodeAndAssign(difficultyHitObjects); // Pre-evaluate colours for (int i = 0; i < colours.Count; i++) @@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing colours[i].EvaluatedDifficulty = ColourEvaluator.EvaluateDifficultyOf(colours[i]); } - return difficultyHitObject; + return difficultyHitObjects; } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index 74b8899c60..6bd99550be 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; @@ -11,72 +9,51 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public class TaikoDifficultyHitObjectColour { + public CoupledColourEncoding Encoding { get; private set; } + private const int max_repetition_interval = 16; - public TaikoDifficultyHitObjectColour Previous { get; private set; } - - /// - /// True if the current colour is different from the previous colour. - /// - public bool Delta { get; private set; } - - /// - /// How many notes are Delta repeated - /// - public int DeltaRunLength { get; private set; } - /// /// How many notes between the current and previous identical . /// Negative number means that there is no repetition in range. /// If no repetition is found this will have a value of + 1. /// - public int RepetitionInterval { get; private set; } + public int RepetitionInterval { get; private set; } = max_repetition_interval + 1; /// /// Evaluated colour difficulty is cached here, as difficulty don't need to be calculated per-note. /// /// TODO: Consider having all evaluated difficulty cached in TaikoDifficultyHitObject instead, since we may be /// reusing evaluator results in the future. - public double EvaluatedDifficulty; + public double EvaluatedDifficulty = 0; - public TaikoDifficultyHitObjectColour repeatedColour { get; private set; } + public TaikoDifficultyHitObjectColour? Previous { get; private set; } = null; - /// - /// Get the instance for the given hitObject. This is implemented - /// as a static function instead of constructor to allow for reusing existing instances. - /// - public static List CreateColoursFor(List hitObjects) + public TaikoDifficultyHitObjectColour? repeatedColour { get; private set; } = null; + + public TaikoDifficultyHitObjectColour(CoupledColourEncoding encoding) + { + Encoding = encoding; + } + + public static List EncodeAndAssign(List hitObjects) { List colours = new List(); - - for (int i = 0; i < hitObjects.Count; i++) + List encodings = CoupledColourEncoding.Encode(ColourEncoding.Encode(hitObjects)); + TaikoDifficultyHitObjectColour? lastColour = null; + for (int i = 0; i < encodings.Count; i++) { - TaikoDifficultyHitObject hitObject = (TaikoDifficultyHitObject)hitObjects[i]; - TaikoDifficultyHitObject lastObject = hitObject.PreviousNote(0); - TaikoDifficultyHitObjectColour previous = lastObject?.Colour; - bool delta = lastObject == null || hitObject.HitType != lastObject.HitType; - - if (previous != null && delta == previous.Delta) + lastColour = new TaikoDifficultyHitObjectColour(encodings[i]) { - previous.DeltaRunLength += 1; - hitObject.Colour = previous; - continue; - } - - TaikoDifficultyHitObjectColour colour = new TaikoDifficultyHitObjectColour() - { - Delta = delta, - DeltaRunLength = 1, - RepetitionInterval = max_repetition_interval + 1, - Previous = previous + Previous = lastColour }; - hitObject.Colour = colour; - colours.Add(colour); + colours.Add(lastColour); } - for (int i = 0; i < colours.Count; i++) + foreach (TaikoDifficultyHitObjectColour colour in colours) { - colours[i].FindRepetitionInterval(); + colour.FindRepetitionInterval(); + ((TaikoDifficultyHitObject)hitObjects[colour.Encoding.StartIndex]).Colour = colour; } return colours; @@ -94,23 +71,23 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing return; } - int interval = Previous.DeltaRunLength; - TaikoDifficultyHitObjectColour other = Previous.Previous; - - while (other != null && interval < max_repetition_interval) + TaikoDifficultyHitObjectColour? other = Previous.Previous; + int interval = this.Encoding.StartIndex - other.Encoding.EndIndex; + while (interval < max_repetition_interval) { - if (other.Delta == Delta && other.DeltaRunLength == DeltaRunLength) + if (Encoding.hasIdenticalPayload(other.Encoding)) { RepetitionInterval = Math.Min(interval, max_repetition_interval); repeatedColour = other; return; } - interval += other.DeltaRunLength; other = other.Previous; + if (other == null) break; + interval = this.Encoding.StartIndex - other.Encoding.EndIndex; } RepetitionInterval = max_repetition_interval + 1; } } -} +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index 0d69104a58..13d5cd673e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -27,10 +27,17 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)current).Colour; double difficulty = colour == null ? 0 : colour.EvaluatedDifficulty; - // if (current != null && colour != null) - // { - // System.Console.WriteLine($"{current.StartTime},{colour.Delta},{colour.RepetitionInterval},{difficulty}"); - // } + if (current != null && colour != null) + { + ColourEncoding[] payload = colour.Encoding.Payload; + string payloadDisplay = ""; + for (int i = 0; i < payload.Length; ++i) + { + payloadDisplay += $",({payload[i].MonoRunLength},{payload[i].EncodingRunLength})"; + } + + System.Console.WriteLine($"{current.StartTime},{colour.RepetitionInterval},{colour.Encoding.RunLength}{payloadDisplay}"); + } return difficulty; } From 8c162585b8ebcf37f50009d17e44cff55d732784 Mon Sep 17 00:00:00 2001 From: vun Date: Sat, 25 Jun 2022 22:49:19 +0800 Subject: [PATCH 0057/2686] Comment out logging for debugging purposes --- .../Difficulty/Skills/Colour.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index 13d5cd673e..bf359f0d64 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -27,17 +27,17 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)current).Colour; double difficulty = colour == null ? 0 : colour.EvaluatedDifficulty; - if (current != null && colour != null) - { - ColourEncoding[] payload = colour.Encoding.Payload; - string payloadDisplay = ""; - for (int i = 0; i < payload.Length; ++i) - { - payloadDisplay += $",({payload[i].MonoRunLength},{payload[i].EncodingRunLength})"; - } + // if (current != null && colour != null) + // { + // ColourEncoding[] payload = colour.Encoding.Payload; + // string payloadDisplay = ""; + // for (int i = 0; i < payload.Length; ++i) + // { + // payloadDisplay += $",({payload[i].MonoRunLength},{payload[i].EncodingRunLength})"; + // } - System.Console.WriteLine($"{current.StartTime},{colour.RepetitionInterval},{colour.Encoding.RunLength}{payloadDisplay}"); - } + // System.Console.WriteLine($"{current.StartTime},{colour.RepetitionInterval},{colour.Encoding.RunLength}{payloadDisplay}"); + // } return difficulty; } From cba47f82020b6c283e3b01c341c41949d5fb88da Mon Sep 17 00:00:00 2001 From: vun Date: Tue, 28 Jun 2022 10:38:58 +0800 Subject: [PATCH 0058/2686] [WIP] Colour evaluator for new colour encoding --- .../Difficulty/Evaluators/ColourEvaluator.cs | 14 +++++++++-- .../Difficulty/Evaluators/StaminaEvaluator.cs | 5 ++-- .../Preprocessing/ColourEncoding.cs | 17 ++++++++++--- .../Preprocessing/TaikoDifficultyHitObject.cs | 15 +++-------- .../TaikoDifficultyHitObjectColour.cs | 19 ++++++-------- .../Difficulty/Skills/Colour.cs | 25 +++++++++++++------ .../Difficulty/Skills/Peaks.cs | 9 +++---- 7 files changed, 61 insertions(+), 43 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 1627833e8a..60898fe92d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -12,9 +12,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return Math.Tanh(Math.E * -(val - center) / width); } - public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour colour) + public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour? colour) { - return 1; + if (colour == null) return 0; + + double difficulty = 7.5 * Math.Log(colour.Encoding.Payload.Length + 1, 10); + // foreach (ColourEncoding encoding in colour.Encoding.Payload) + // { + // difficulty += sigmoid(encoding.MonoRunLength, 1, 1) * 0.4 + 0.6; + // } + difficulty *= -sigmoid(colour.RepetitionInterval, 1, 7); + // difficulty *= -sigmoid(colour.RepetitionInterval, 2, 2) * 0.5 + 0.5; + + return difficulty; } public static double EvaluateDifficultyOf(DifficultyHitObject current) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index be1514891c..9ebdc90eb8 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -16,7 +16,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// The interval between the current and previous note hit using the same key. private static double speedBonus(double interval) { - return Math.Pow(0.8, interval / 1000); + // return 10 / Math.Pow(interval, 0.6); + return Math.Pow(0.1, interval / 1000); } /// @@ -40,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return 0.0; } - double objectStrain = 0.85; + double objectStrain = 1; objectStrain *= speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime); return objectStrain; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs index e2ac40170e..c090e7aada 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs @@ -14,7 +14,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// Amount of consecutive encoding with the same /// public int EncodingRunLength = 1; - + + /// + /// How many notes are encoded with this encoding + /// + public int NoteLength => MonoRunLength + EncodingRunLength; + /// /// Beginning index in the data that this encodes /// @@ -27,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing public static List Encode(List data) { - // Encoding mono lengths + // Compute mono lengths List firstPass = new List(); ColourEncoding? lastEncoded = null; for (int i = 0; i < data.Count; i++) @@ -36,7 +41,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing // This ignores all non-note objects, which may or may not be the desired behaviour TaikoDifficultyHitObject previousObject = (TaikoDifficultyHitObject)taikoObject.PreviousNote(0); - if (previousObject == null || lastEncoded == null || taikoObject.HitType != previousObject.HitType) + if ( + previousObject == null || + lastEncoded == null || + taikoObject.HitType != previousObject.HitType || + taikoObject.Rhythm.Ratio > 1.9) // Reset colour after a slow down of 2x (set as 1.9x for margin of error) { lastEncoded = new ColourEncoding(); lastEncoded.StartIndex = i; @@ -47,7 +56,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing lastEncoded.MonoRunLength += 1; } - // Encode encoding lengths + // Compute encoding lengths List secondPass = new List(); lastEncoded = null; for (int i = 0; i < firstPass.Count; i++) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 1ee905d94c..7c9188b100 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -19,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public class TaikoDifficultyHitObject : DifficultyHitObject { - private readonly IReadOnlyList monoDifficultyHitObjects; + private readonly IReadOnlyList? monoDifficultyHitObjects; public readonly int MonoIndex; private readonly IReadOnlyList noteObjects; public readonly int NoteIndex; @@ -34,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// by other skills in the future. /// This need to be writeable by TaikoDifficultyHitObjectColour so that it can assign potentially reused instances /// - public TaikoDifficultyHitObjectColour Colour; + public TaikoDifficultyHitObjectColour? Colour; /// /// The hit type of this hit object. @@ -65,14 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count) ); } - - List colours = TaikoDifficultyHitObjectColour.EncodeAndAssign(difficultyHitObjects); - - // Pre-evaluate colours - for (int i = 0; i < colours.Count; i++) - { - colours[i].EvaluatedDifficulty = ColourEvaluator.EvaluateDifficultyOf(colours[i]); - } + TaikoDifficultyHitObjectColour.EncodeAndAssign(difficultyHitObjects); return difficultyHitObjects; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs index 6bd99550be..7e18332fab 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs @@ -5,12 +5,11 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { /// - /// Stores colour compression information for a . + /// Stores colour compression information for a . This is only present for the + /// first in a chunk. /// public class TaikoDifficultyHitObjectColour { - public CoupledColourEncoding Encoding { get; private set; } - private const int max_repetition_interval = 16; /// @@ -21,11 +20,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing public int RepetitionInterval { get; private set; } = max_repetition_interval + 1; /// - /// Evaluated colour difficulty is cached here, as difficulty don't need to be calculated per-note. + /// Encoding information of . /// - /// TODO: Consider having all evaluated difficulty cached in TaikoDifficultyHitObject instead, since we may be - /// reusing evaluator results in the future. - public double EvaluatedDifficulty = 0; + public CoupledColourEncoding Encoding { get; private set; } public TaikoDifficultyHitObjectColour? Previous { get; private set; } = null; @@ -60,8 +57,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing } /// - /// Finds the closest previous that has the identical delta value - /// and run length with the current instance, and returns the amount of notes between them. + /// Finds the closest previous that has the identical . + /// Interval is defined as the amount of chunks between the current and repeated encoding. /// public void FindRepetitionInterval() { @@ -72,7 +69,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing } TaikoDifficultyHitObjectColour? other = Previous.Previous; - int interval = this.Encoding.StartIndex - other.Encoding.EndIndex; + int interval = 2; while (interval < max_repetition_interval) { if (Encoding.hasIdenticalPayload(other.Encoding)) @@ -84,7 +81,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing other = other.Previous; if (other == null) break; - interval = this.Encoding.StartIndex - other.Encoding.EndIndex; + ++interval; } RepetitionInterval = max_repetition_interval + 1; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index bf359f0d64..c0dafc73b5 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -1,12 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { @@ -18,6 +18,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double SkillMultiplier => 1; protected override double StrainDecayBase => 0.4; + /// + /// Applies a speed bonus dependent on the time since the last hit. + /// + /// The interval between the current and previous note hit using the same key. + private static double speedBonus(double interval) + { + return Math.Pow(0.4, interval / 1000); + } + public Colour(Mod[] mods) : base(mods) { @@ -25,18 +34,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double StrainValueOf(DifficultyHitObject current) { - TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)current).Colour; - double difficulty = colour == null ? 0 : colour.EvaluatedDifficulty; - // if (current != null && colour != null) + double difficulty = ColourEvaluator.EvaluateDifficultyOf(current); + // difficulty *= speedBonus(current.DeltaTime); + // TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current; + // TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour; + // if (taikoCurrent != null && colour != null) // { // ColourEncoding[] payload = colour.Encoding.Payload; // string payloadDisplay = ""; // for (int i = 0; i < payload.Length; ++i) // { - // payloadDisplay += $",({payload[i].MonoRunLength},{payload[i].EncodingRunLength})"; + // payloadDisplay += $",({payload[i].MonoRunLength}|{payload[i].EncodingRunLength})"; // } - // System.Console.WriteLine($"{current.StartTime},{colour.RepetitionInterval},{colour.Encoding.RunLength}{payloadDisplay}"); + // System.Console.WriteLine($"{current.StartTime},{difficulty},{colour.RepetitionInterval},{colour.Encoding.RunLength}{payloadDisplay}"); // } return difficulty; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index ebbe027f9e..7b6fb7d102 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -4,17 +4,16 @@ using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { public class Peaks : Skill { - private const double rhythm_skill_multiplier = 0.32 * final_multiplier; - private const double colour_skill_multiplier = 0.33 * final_multiplier; - private const double stamina_skill_multiplier = 0.4 * final_multiplier; + private const double rhythm_skill_multiplier = 0.3 * final_multiplier; + private const double colour_skill_multiplier = 0.39 * final_multiplier; + private const double stamina_skill_multiplier = 0.33 * final_multiplier; - private const double final_multiplier = 0.047; + private const double final_multiplier = 0.06; private readonly Rhythm rhythm; private readonly Colour colour; From 2b42dfb9cbc81f2d567f56bda28f4ebf2bcaf199 Mon Sep 17 00:00:00 2001 From: 63411 <62799417+molneya@users.noreply.github.com> Date: Tue, 28 Jun 2022 20:32:35 +0800 Subject: [PATCH 0059/2686] apply individualStrain decay only when a note appears in that column --- .../Difficulty/Skills/Strain.cs | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs index c2e532430c..74334c90e4 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs @@ -21,7 +21,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills protected override double SkillMultiplier => 1; protected override double StrainDecayBase => 1; - private readonly double[] holdEndTimes; + private readonly double[] startTimes; + private readonly double[] endTimes; private readonly double[] individualStrains; private double individualStrain; @@ -30,7 +31,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills public Strain(Mod[] mods, int totalColumns) : base(mods) { - holdEndTimes = new double[totalColumns]; + startTimes = new double[totalColumns]; + endTimes = new double[totalColumns]; individualStrains = new double[totalColumns]; overallStrain = 1; } @@ -38,32 +40,27 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills protected override double StrainValueOf(DifficultyHitObject current) { var maniaCurrent = (ManiaDifficultyHitObject)current; + double startTime = maniaCurrent.StartTime; double endTime = maniaCurrent.EndTime; int column = maniaCurrent.BaseObject.Column; - double closestEndTime = Math.Abs(endTime - maniaCurrent.LastObject.StartTime); // Lowest value we can assume with the current information - - double holdFactor = 1.0; // Factor to all additional strains in case something else is held - double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly bool isOverlapping = false; - // Fill up the holdEndTimes array - for (int i = 0; i < holdEndTimes.Length; ++i) + double closestEndTime = Math.Abs(endTime - startTime); // Lowest value we can assume with the current information + double holdFactor = 1.0; // Factor to all additional strains in case something else is held + double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly + + for (int i = 0; i < endTimes.Length; ++i) { // The current note is overlapped if a previous note or end is overlapping the current note body - isOverlapping |= Precision.DefinitelyBigger(holdEndTimes[i], maniaCurrent.StartTime, 1) && Precision.DefinitelyBigger(endTime, holdEndTimes[i], 1); + isOverlapping |= Precision.DefinitelyBigger(endTimes[i], startTime, 1) && Precision.DefinitelyBigger(endTime, endTimes[i], 1); // We give a slight bonus to everything if something is held meanwhile - if (Precision.DefinitelyBigger(holdEndTimes[i], endTime, 1)) + if (Precision.DefinitelyBigger(endTimes[i], endTime, 1)) holdFactor = 1.25; - closestEndTime = Math.Min(closestEndTime, Math.Abs(endTime - holdEndTimes[i])); - - // Decay individual strains - individualStrains[i] = applyDecay(individualStrains[i], current.DeltaTime, individual_decay_base); + closestEndTime = Math.Min(closestEndTime, Math.Abs(endTime - endTimes[i])); } - holdEndTimes[column] = endTime; - // The hold addition is given if there was an overlap, however it is only valid if there are no other note with a similar ending. // Releasing multiple notes is just as easy as releasing 1. Nerfs the hold addition by half if the closest release is release_threshold away. // holdAddition @@ -77,11 +74,19 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills if (isOverlapping) holdAddition = 1 / (1 + Math.Exp(0.5 * (release_threshold - closestEndTime))); - // Increase individual strain in own column + // Decay and increase individualStrains in own column + individualStrains[column] = applyDecay(individualStrains[column], startTime - startTimes[column], individual_decay_base); individualStrains[column] += 2.0 * holdFactor; + individualStrain = individualStrains[column]; - overallStrain = applyDecay(overallStrain, current.DeltaTime, overall_decay_base) + (1 + holdAddition) * holdFactor; + // Decay and increase overallStrain + overallStrain = applyDecay(overallStrain, current.DeltaTime, overall_decay_base); + overallStrain += (1 + holdAddition) * holdFactor; + + // Update startTimes and endTimes arrays + startTimes[column] = startTime; + endTimes[column] = endTime; return individualStrain + overallStrain - CurrentStrain; } From 5f8d21f33d60c422eb44d5736e6a66aad41290f2 Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 1 Jul 2022 14:27:23 +0800 Subject: [PATCH 0060/2686] Per encoding evaluation --- .../Difficulty/Evaluators/ColourEvaluator.cs | 22 +++++++++-- .../Difficulty/Skills/Colour.cs | 39 ++++++++++++------- .../Difficulty/Skills/Peaks.cs | 27 +++++++++++-- .../Difficulty/TaikoDifficultyCalculator.cs | 2 +- 4 files changed, 68 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 60898fe92d..8d9f50eee5 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -12,17 +12,33 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return Math.Tanh(Math.E * -(val - center) / width); } + public static double EvaluateDifficultyOf(ColourEncoding encoding) + { + return 1 / Math.Pow(encoding.MonoRunLength, 0.5); + } + + public static double EvaluateDifficultyOf(CoupledColourEncoding coupledEncoding) + { + double difficulty = 0; + for (int i = 0; i < coupledEncoding.Payload.Length; i++) + { + difficulty += EvaluateDifficultyOf(coupledEncoding.Payload[i]); + } + return difficulty; + } + public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour? colour) { if (colour == null) return 0; - double difficulty = 7.5 * Math.Log(colour.Encoding.Payload.Length + 1, 10); + // double difficulty = 9.5 * Math.Log(colour.Encoding.Payload.Length + 1, 10); + double difficulty = 3 * EvaluateDifficultyOf(colour.Encoding); // foreach (ColourEncoding encoding in colour.Encoding.Payload) // { // difficulty += sigmoid(encoding.MonoRunLength, 1, 1) * 0.4 + 0.6; // } - difficulty *= -sigmoid(colour.RepetitionInterval, 1, 7); - // difficulty *= -sigmoid(colour.RepetitionInterval, 2, 2) * 0.5 + 0.5; + // difficulty *= -sigmoid(colour.RepetitionInterval, 1, 7); + difficulty *= -sigmoid(colour.RepetitionInterval, 6, 5) * 0.5 + 0.5; return difficulty; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index c0dafc73b5..6b7138fa92 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -35,22 +35,31 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double StrainValueOf(DifficultyHitObject current) { double difficulty = ColourEvaluator.EvaluateDifficultyOf(current); - // difficulty *= speedBonus(current.DeltaTime); - // TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current; - // TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour; - // if (taikoCurrent != null && colour != null) - // { - // ColourEncoding[] payload = colour.Encoding.Payload; - // string payloadDisplay = ""; - // for (int i = 0; i < payload.Length; ++i) - // { - // payloadDisplay += $",({payload[i].MonoRunLength}|{payload[i].EncodingRunLength})"; - // } - - // System.Console.WriteLine($"{current.StartTime},{difficulty},{colour.RepetitionInterval},{colour.Encoding.RunLength}{payloadDisplay}"); - // } - return difficulty; } + + // TODO: Remove befor pr + public string GetDebugString(DifficultyHitObject current) + { + double difficulty = ColourEvaluator.EvaluateDifficultyOf(current); + difficulty *= speedBonus(current.DeltaTime); + TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current; + TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour; + if (taikoCurrent != null && colour != null) + { + ColourEncoding[] payload = colour.Encoding.Payload; + string payloadDisplay = ""; + for (int i = 0; i < payload.Length; ++i) + { + payloadDisplay += $"({payload[i].MonoRunLength}|{payload[i].EncodingRunLength})"; + } + + return $"{current.StartTime},{difficulty},{CurrentStrain},{colour.RepetitionInterval},{colour.Encoding.RunLength},{payloadDisplay}"; + } + else + { + return $"{current.StartTime},{difficulty},{CurrentStrain},0,0,0"; + } + } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index 7b6fb7d102..1086cf5f72 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -1,17 +1,19 @@ using System; +using System.IO; using System.Collections.Generic; using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; +using osu.Game.Beatmaps; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { public class Peaks : Skill { private const double rhythm_skill_multiplier = 0.3 * final_multiplier; - private const double colour_skill_multiplier = 0.39 * final_multiplier; - private const double stamina_skill_multiplier = 0.33 * final_multiplier; + private const double colour_skill_multiplier = 0.375 * final_multiplier; + private const double stamina_skill_multiplier = 0.375 * final_multiplier; private const double final_multiplier = 0.06; @@ -23,12 +25,25 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills public double RhythmDifficultyValue => rhythm.DifficultyValue() * rhythm_skill_multiplier; public double StaminaDifficultyValue => stamina.DifficultyValue() * stamina_skill_multiplier; - public Peaks(Mod[] mods) + // TODO: remove before pr + private StreamWriter? colourDebugOutput; + bool debugColour = false; + + public Peaks(Mod[] mods, IBeatmap beatmap) : base(mods) { rhythm = new Rhythm(mods); colour = new Colour(mods); stamina = new Stamina(mods); + + if (debugColour) + { + String filename = $"{beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv"; + filename = filename.Replace('/', '_'); + colourDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/colour-debug/{filename}")); + colourDebugOutput.WriteLine("StartTime,Raw,Decayed,RepetitionInterval,EncodingRunLength,Payload"); + } + } /// @@ -43,6 +58,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills rhythm.Process(current); colour.Process(current); stamina.Process(current); + + if (debugColour && colourDebugOutput != null) + { + colourDebugOutput.WriteLine(colour.GetDebugString(current)); + colourDebugOutput.Flush(); + } } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index ace3599f28..2982861e0b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { return new Skill[] { - new Peaks(mods) + new Peaks(mods, beatmap) }; } From 45258b3f14b3a0e0847b7f9159bc6eed7a15afba Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 4 Jul 2022 19:53:34 +0300 Subject: [PATCH 0061/2686] Buff aim slightly --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 4 ++-- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 0694746cbf..6c2ef12b1d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -13,8 +13,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators public static class AimEvaluator { private const double wide_angle_multiplier = 1.5; - private const double acute_angle_multiplier = 2.0; - private const double slider_multiplier = 1.5; + private const double acute_angle_multiplier = 1.95; + private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; /// diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index c3b7834009..21ff566b00 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); effectiveMissCount = calculateEffectiveMissCount(osuAttributes); - double multiplier = 1.12; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. + double multiplier = 1.11; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. if (score.Mods.Any(m => m is OsuModNoFail)) multiplier *= Math.Max(0.90, 1.0 - 0.02 * effectiveMissCount); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 9b1fbf9a2e..e4f61b65cd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private double currentStrain; - private double skillMultiplier => 23.25; + private double skillMultiplier => 24.15; private double strainDecayBase => 0.15; private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); From 212360f67e5c73f1f06e78314fd2d0e95f1b79f3 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 4 Jul 2022 19:59:30 +0300 Subject: [PATCH 0062/2686] Make relax ok/meh nerfs less drastic, add flashlight nerf, remove ar bonus for relax --- .../Difficulty/OsuDifficultyCalculator.cs | 3 +++ .../Difficulty/OsuPerformanceCalculator.cs | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 75d9469da3..7d00f59a9b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -44,7 +44,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; if (mods.Any(h => h is OsuModRelax)) + { speedRating = 0.0; + flashlightRating *= 0.75; + } double baseAimPerformance = Math.Pow(5 * Math.Max(1, aimRating / 0.0675) - 4, 3) / 100000; double baseSpeedPerformance = Math.Pow(5 * Math.Max(1, speedRating / 0.0675) - 4, 3) / 100000; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 21ff566b00..2cd1d11cbe 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -52,9 +52,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (score.Mods.Any(h => h is OsuModRelax)) { // As we're adding Oks and Mehs to an approximated number of combo breaks the result can be higher than total hits in specific scenarios (which breaks some calculations) so we need to clamp it. - effectiveMissCount = Math.Min(effectiveMissCount + countOk + countMeh, totalHits); + effectiveMissCount = Math.Min(effectiveMissCount + countOk * 0.33 + countMeh * 0.66, totalHits); - multiplier *= 0.6; + multiplier *= 0.7; } double aimValue = computeAimValue(score, osuAttributes); @@ -105,6 +105,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty else if (attributes.ApproachRate < 8.0) approachRateFactor = 0.1 * (8.0 - attributes.ApproachRate); + if (score.Mods.Any(h => h is OsuModRelax)) + approachRateFactor = 0.0; + aimValue *= 1.0 + approachRateFactor * lengthBonus; // Buff for longer maps with high AR. if (score.Mods.Any(m => m is OsuModBlinds)) @@ -134,6 +137,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double computeSpeedValue(ScoreInfo score, OsuDifficultyAttributes attributes) { + if (score.Mods.Any(h => h is OsuModRelax)) + return 0.0; + double speedValue = Math.Pow(5.0 * Math.Max(1.0, attributes.SpeedDifficulty / 0.0675) - 4.0, 3.0) / 100000.0; double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + From db8bb07c782cc09d8ab10a7d525ddd3e5123dbcd Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 4 Jul 2022 20:10:26 +0300 Subject: [PATCH 0063/2686] Reduce 50s nerf effect --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 2cd1d11cbe..e879fd233b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -180,7 +180,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty speedValue *= (0.95 + Math.Pow(attributes.OverallDifficulty, 2) / 750) * Math.Pow((accuracy + relevantAccuracy) / 2.0, (14.5 - Math.Max(attributes.OverallDifficulty, 8)) / 2); // Scale the speed value with # of 50s to punish doubletapping. - speedValue *= Math.Pow(0.98, countMeh < totalHits / 500.0 ? 0 : countMeh - totalHits / 500.0); + speedValue *= Math.Pow(0.99, countMeh < totalHits / 500.0 ? 0 : countMeh - totalHits / 500.0); return speedValue; } From 11eb344476e4afa4bd4c71ab5037d2870b17d6a7 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 4 Jul 2022 20:28:15 +0300 Subject: [PATCH 0064/2686] Reduce 50s nerf further --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index e879fd233b..083c7e9b44 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -180,7 +180,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty speedValue *= (0.95 + Math.Pow(attributes.OverallDifficulty, 2) / 750) * Math.Pow((accuracy + relevantAccuracy) / 2.0, (14.5 - Math.Max(attributes.OverallDifficulty, 8)) / 2); // Scale the speed value with # of 50s to punish doubletapping. - speedValue *= Math.Pow(0.99, countMeh < totalHits / 500.0 ? 0 : countMeh - totalHits / 500.0); + speedValue *= Math.Pow(0.995, countMeh < totalHits / 500.0 ? 0 : countMeh - totalHits / 500.0); return speedValue; } From afa3f8cda38c9fef3f27ae61b9b1b7abec467319 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 4 Jul 2022 20:53:20 +0300 Subject: [PATCH 0065/2686] Make relax ok/meh multipliers dependent on OD --- .../Difficulty/OsuPerformanceCalculator.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 083c7e9b44..6f747e4904 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -51,8 +51,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (score.Mods.Any(h => h is OsuModRelax)) { + // https://www.desmos.com/calculator/adhhgjtuyp + double okMultiplier = osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 12.0, 2) : 1.0; + double mehMultiplier = osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 12.0, 6) : 1.0; + // As we're adding Oks and Mehs to an approximated number of combo breaks the result can be higher than total hits in specific scenarios (which breaks some calculations) so we need to clamp it. - effectiveMissCount = Math.Min(effectiveMissCount + countOk * 0.33 + countMeh * 0.66, totalHits); + effectiveMissCount = Math.Min(effectiveMissCount + countOk * okMultiplier + countMeh * mehMultiplier, totalHits); multiplier *= 0.7; } From 6e1d32dc6ddc7f8a037c898974b84f218972ff20 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 4 Jul 2022 21:00:11 +0300 Subject: [PATCH 0066/2686] Update tests --- .../OsuDifficultyCalculatorTest.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs index bb593c2fb3..b7fafc0fcd 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs @@ -17,18 +17,18 @@ namespace osu.Game.Rulesets.Osu.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Osu"; - [TestCase(6.6972307565739273d, 206, "diffcalc-test")] - [TestCase(1.4484754139145539d, 45, "zero-length-sliders")] + [TestCase(6.8043847243906566d, 206, "diffcalc-test")] + [TestCase(1.449091582269485d, 45, "zero-length-sliders")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(8.9382559208689809d, 206, "diffcalc-test")] - [TestCase(1.7548875851757628d, 45, "zero-length-sliders")] + [TestCase(9.0768518847360937d, 206, "diffcalc-test")] + [TestCase(1.7555890739194639d, 45, "zero-length-sliders")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new OsuModDoubleTime()); - [TestCase(6.6972307218715166d, 239, "diffcalc-test")] - [TestCase(1.4484754139145537d, 54, "zero-length-sliders")] + [TestCase(6.8043847243906566d, 239, "diffcalc-test")] + [TestCase(1.449091582269485d, 54, "zero-length-sliders")] public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic()); From bf738aa04fd241eece09ab37a91d6471325ee3c5 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 4 Jul 2022 21:49:45 +0300 Subject: [PATCH 0067/2686] Account for extreme ODs in relax multipliers --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 6f747e4904..f0d4bb5252 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -52,8 +52,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (score.Mods.Any(h => h is OsuModRelax)) { // https://www.desmos.com/calculator/adhhgjtuyp - double okMultiplier = osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 12.0, 2) : 1.0; - double mehMultiplier = osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 12.0, 6) : 1.0; + double okMultiplier = Math.Max(0.0, osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 13.33, 1.8) : 1.0); + double mehMultiplier = Math.Max(0.0, osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 13.33, 5) : 1.0); // As we're adding Oks and Mehs to an approximated number of combo breaks the result can be higher than total hits in specific scenarios (which breaks some calculations) so we need to clamp it. effectiveMissCount = Math.Min(effectiveMissCount + countOk * okMultiplier + countMeh * mehMultiplier, totalHits); From 4f7763794642fb412722b07004e6d02b3ae48092 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 4 Jul 2022 21:52:57 +0300 Subject: [PATCH 0068/2686] Update desmos --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index f0d4bb5252..bf5a6e517a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (score.Mods.Any(h => h is OsuModRelax)) { - // https://www.desmos.com/calculator/adhhgjtuyp + // https://www.desmos.com/calculator/bc9eybdthb double okMultiplier = Math.Max(0.0, osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 13.33, 1.8) : 1.0); double mehMultiplier = Math.Max(0.0, osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 13.33, 5) : 1.0); From 505a24a68ef4239df119aec3227f8a9afa15be95 Mon Sep 17 00:00:00 2001 From: vun Date: Tue, 5 Jul 2022 14:41:40 +0800 Subject: [PATCH 0069/2686] Implement new colour encoding and evaluator --- .../Difficulty/Evaluators/ColourEvaluator.cs | 79 ++++++++---- .../Preprocessing/Colour/ColourEncoding.cs | 42 ++++++ .../Colour/CoupledColourEncoding.cs | 122 ++++++++++++++++++ .../Preprocessing/Colour/MonoEncoding.cs | 40 ++++++ .../Colour/TaikoDifficultyHitObjectColour.cs | 50 +++++++ .../Preprocessing/ColourEncoding.cs | 77 ----------- .../Preprocessing/CoupledColourEncoding.cs | 73 ----------- .../Preprocessing/TaikoDifficultyHitObject.cs | 3 +- .../TaikoDifficultyHitObjectColour.cs | 90 ------------- .../Difficulty/Skills/Colour.cs | 19 ++- .../Difficulty/Skills/Peaks.cs | 4 +- 11 files changed, 326 insertions(+), 273 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs delete mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs delete mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/CoupledColourEncoding.cs delete mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 8d9f50eee5..d33f2a85b9 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -1,6 +1,7 @@ using System; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators { @@ -12,40 +13,70 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return Math.Tanh(Math.E * -(val - center) / width); } - public static double EvaluateDifficultyOf(ColourEncoding encoding) + private static double sigmoid(double val, double center, double width, double middle, double height) { - return 1 / Math.Pow(encoding.MonoRunLength, 0.5); + return sigmoid(val, center, width) * (height / 2) + middle; } - public static double EvaluateDifficultyOf(CoupledColourEncoding coupledEncoding) + /// + /// Evaluate the difficulty of the first note of a . + /// The encoding to evaluate. + /// The index of the mono encoding within it's parent . + /// + public static double EvaluateDifficultyOf(MonoEncoding encoding, int i) { - double difficulty = 0; - for (int i = 0; i < coupledEncoding.Payload.Length; i++) + return sigmoid(i, 2, 2, 0.5, 1); + } + + /// + /// Evaluate the difficulty of the first note of a . + /// + /// The encoding to evaluate. + /// The index of the colour encoding within it's parent . + public static double EvaluateDifficultyOf(ColourEncoding encoding, int i) + { + return sigmoid(i, 2, 2, 0.5, 1); + } + + /// + /// Evaluate the difficulty of the first note of a . + /// + public static double EvaluateDifficultyOf(CoupledColourEncoding encoding) + { + return 1 - sigmoid(encoding.RepetitionInterval, 2, 2, 0.5, 1); + } + + /// + /// Pre-evaluate and *assign* difficulty values of all hit objects encoded in a . + /// Difficulty values are assigned to of each + /// encoded within. + /// + public static void PreEvaluateDifficulties(CoupledColourEncoding encoding) + { + double coupledEncodingDifficulty = EvaluateDifficultyOf(encoding); + encoding.Payload[0].Payload[0].EncodedData[0].Colour!.EvaluatedDifficulty += coupledEncodingDifficulty; + for (int i = 0; i < encoding.Payload.Count; i++) { - difficulty += EvaluateDifficultyOf(coupledEncoding.Payload[i]); + ColourEncoding colourEncoding = encoding.Payload[i]; + double colourEncodingDifficulty = EvaluateDifficultyOf(colourEncoding, i) * coupledEncodingDifficulty; + colourEncoding.Payload[0].EncodedData[0].Colour!.EvaluatedDifficulty += colourEncodingDifficulty; + for (int j = 0; j < colourEncoding.Payload.Count; j++) + { + MonoEncoding monoEncoding = colourEncoding.Payload[j]; + monoEncoding.EncodedData[0].Colour!.EvaluatedDifficulty += EvaluateDifficultyOf(monoEncoding, j) * colourEncodingDifficulty; + } } - return difficulty; - } - - public static double EvaluateDifficultyOf(TaikoDifficultyHitObjectColour? colour) - { - if (colour == null) return 0; - - // double difficulty = 9.5 * Math.Log(colour.Encoding.Payload.Length + 1, 10); - double difficulty = 3 * EvaluateDifficultyOf(colour.Encoding); - // foreach (ColourEncoding encoding in colour.Encoding.Payload) - // { - // difficulty += sigmoid(encoding.MonoRunLength, 1, 1) * 0.4 + 0.6; - // } - // difficulty *= -sigmoid(colour.RepetitionInterval, 1, 7); - difficulty *= -sigmoid(colour.RepetitionInterval, 6, 5) * 0.5 + 0.5; - - return difficulty; } public static double EvaluateDifficultyOf(DifficultyHitObject current) { - return EvaluateDifficultyOf(((TaikoDifficultyHitObject)current).Colour); + TaikoDifficultyHitObject? taikoObject = current as TaikoDifficultyHitObject; + if (taikoObject != null && taikoObject.Colour != null) + { + return taikoObject.Colour.EvaluatedDifficulty; + } + + return 0; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs new file mode 100644 index 0000000000..bc427d87ae --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using osu.Game.Rulesets.Difficulty.Preprocessing; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour +{ + public class ColourEncoding + { + public List Payload { get; private set; } = new List(); + + public bool isIdenticalTo(ColourEncoding other) + { + return other.Payload[0].RunLength == Payload[0].RunLength && + other.Payload[0].EncodedData[0].HitType == Payload[0].EncodedData[0].HitType; + } + + public bool hasIdenticalMonoLength(ColourEncoding other) + { + return other.Payload[0].RunLength == Payload[0].RunLength; + } + + public static List Encode(List data) + { + // Compute encoding lengths + List encoded = new List(); + ColourEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) + { + if (i == 0 || lastEncoded == null || data[i].RunLength != data[i - 1].RunLength) + { + lastEncoded = new ColourEncoding(); + lastEncoded.Payload.Add(data[i]); + encoded.Add(lastEncoded); + continue; + } + + lastEncoded.Payload.Add(data[i]); + } + + return encoded; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs new file mode 100644 index 0000000000..7bdcf50055 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using osu.Game.Rulesets.Difficulty.Preprocessing; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour +{ + public class CoupledColourEncoding + { + private const int max_repetition_interval = 16; + + public List Payload = new List(); + + public CoupledColourEncoding? Previous { get; private set; } = null; + + /// + /// How many notes between the current and previous identical . + /// Negative number means that there is no repetition in range. + /// If no repetition is found this will have a value of + 1. + /// + public int RepetitionInterval { get; private set; } = max_repetition_interval + 1; + + public static List Encode(List data) + { + List firstPass = MonoEncoding.Encode(data); + List secondPass = ColourEncoding.Encode(firstPass); + List thirdPass = CoupledColourEncoding.Encode(secondPass); + + return thirdPass; + } + + public static List Encode(List data) + { + List encoded = new List(); + + CoupledColourEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) + { + lastEncoded = new CoupledColourEncoding() + { + Previous = lastEncoded + }; + + bool isCoupled = i < data.Count - 2 && data[i].isIdenticalTo(data[i + 2]); + if (!isCoupled) + { + lastEncoded.Payload.Add(data[i]); + } + else + { + while (isCoupled) + { + lastEncoded.Payload.Add(data[i]); + i++; + + isCoupled = i < data.Count - 2 && data[i].isIdenticalTo(data[i + 2]); + } + + // Skip over peeked data and add the rest to the payload + lastEncoded.Payload.Add(data[i]); + lastEncoded.Payload.Add(data[i + 1]); + i++; + } + + encoded.Add(lastEncoded); + } + + // Final pass to find repetition interval + for (int i = 0; i < encoded.Count; i++) + { + encoded[i].FindRepetitionInterval(); + } + + return encoded; + } + + /// + /// Returns true if other is considered a repetition of this encoding. This is true if other's first two payload + /// identical mono lengths. + /// + public bool isRepetitionOf(CoupledColourEncoding other) + { + if (this.Payload.Count != other.Payload.Count) return false; + + for (int i = 0; i < Math.Min(this.Payload.Count, 2); i++) + { + if (!this.Payload[i].hasIdenticalMonoLength(other.Payload[i])) return false; + } + + return true; + } + + /// + /// Finds the closest previous that has the identical . + /// Interval is defined as the amount of chunks between the current and repeated encoding. + /// + public void FindRepetitionInterval() + { + if (Previous?.Previous == null) + { + RepetitionInterval = max_repetition_interval + 1; + return; + } + + CoupledColourEncoding? other = Previous.Previous; + int interval = 2; + while (interval < max_repetition_interval) + { + if (this.isRepetitionOf(other)) + { + RepetitionInterval = Math.Min(interval, max_repetition_interval); + return; + } + + other = other.Previous; + if (other == null) break; + ++interval; + } + + RepetitionInterval = max_repetition_interval + 1; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs new file mode 100644 index 0000000000..92cdb0667b --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs @@ -0,0 +1,40 @@ +using osu.Game.Rulesets.Difficulty.Preprocessing; +using System.Collections.Generic; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour +{ + public class MonoEncoding + { + public List EncodedData { get; private set; } = new List(); + + public int RunLength => EncodedData.Count; + + public static List Encode(List data) + { + List encoded = new List(); + + MonoEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) + { + TaikoDifficultyHitObject taikoObject = (TaikoDifficultyHitObject)data[i]; + // This ignores all non-note objects, which may or may not be the desired behaviour + TaikoDifficultyHitObject previousObject = (TaikoDifficultyHitObject)taikoObject.PreviousNote(0); + + if ( + previousObject == null || + lastEncoded == null || + taikoObject.HitType != previousObject.HitType) + { + lastEncoded = new MonoEncoding(); + lastEncoded.EncodedData.Add(taikoObject); + encoded.Add(lastEncoded); + continue; + } + + lastEncoded.EncodedData.Add(taikoObject); + } + + return encoded; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs new file mode 100644 index 0000000000..7dfd0fdbd4 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour +{ + /// + /// Stores colour compression information for a . This is only present for the + /// first in a chunk. + /// + public class TaikoDifficultyHitObjectColour + { + public CoupledColourEncoding Encoding { get; private set; } + + public double EvaluatedDifficulty = 0; + + private TaikoDifficultyHitObjectColour(CoupledColourEncoding encoding) + { + Encoding = encoding; + } + + // TODO: Might wanna move this somewhere else as it is introducing circular references + public static List EncodeAndAssign(List hitObjects) + { + List colours = new List(); + List encodings = CoupledColourEncoding.Encode(hitObjects); + + // Assign colour to objects + encodings.ForEach(coupledEncoding => + { + coupledEncoding.Payload.ForEach(encoding => + { + encoding.Payload.ForEach(mono => + { + mono.EncodedData.ForEach(hitObject => + { + hitObject.Colour = new TaikoDifficultyHitObjectColour(coupledEncoding); + }); + }); + }); + + // Preevaluate and assign difficulty values + ColourEvaluator.PreEvaluateDifficulties(coupledEncoding); + }); + + return colours; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs deleted file mode 100644 index c090e7aada..0000000000 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/ColourEncoding.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System.Collections.Generic; -using osu.Game.Rulesets.Difficulty.Preprocessing; - -namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing -{ - public class ColourEncoding - { - /// - /// Amount consecutive notes of the same colour - /// - public int MonoRunLength = 1; - - /// - /// Amount of consecutive encoding with the same - /// - public int EncodingRunLength = 1; - - /// - /// How many notes are encoded with this encoding - /// - public int NoteLength => MonoRunLength + EncodingRunLength; - - /// - /// Beginning index in the data that this encodes - /// - public int StartIndex = 0; - - public bool isIdenticalTo(ColourEncoding other) - { - return other.MonoRunLength == MonoRunLength && other.EncodingRunLength == EncodingRunLength; - } - - public static List Encode(List data) - { - // Compute mono lengths - List firstPass = new List(); - ColourEncoding? lastEncoded = null; - for (int i = 0; i < data.Count; i++) - { - TaikoDifficultyHitObject taikoObject = (TaikoDifficultyHitObject)data[i]; - // This ignores all non-note objects, which may or may not be the desired behaviour - TaikoDifficultyHitObject previousObject = (TaikoDifficultyHitObject)taikoObject.PreviousNote(0); - - if ( - previousObject == null || - lastEncoded == null || - taikoObject.HitType != previousObject.HitType || - taikoObject.Rhythm.Ratio > 1.9) // Reset colour after a slow down of 2x (set as 1.9x for margin of error) - { - lastEncoded = new ColourEncoding(); - lastEncoded.StartIndex = i; - firstPass.Add(lastEncoded); - continue; - } - - lastEncoded.MonoRunLength += 1; - } - - // Compute encoding lengths - List secondPass = new List(); - lastEncoded = null; - for (int i = 0; i < firstPass.Count; i++) - { - if (i == 0 || lastEncoded == null || firstPass[i].MonoRunLength != firstPass[i - 1].MonoRunLength) - { - lastEncoded = firstPass[i]; - secondPass.Add(firstPass[i]); - continue; - } - - lastEncoded.EncodingRunLength += 1; - } - - return secondPass; - } - } -} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/CoupledColourEncoding.cs deleted file mode 100644 index 81e8ae006f..0000000000 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/CoupledColourEncoding.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Collections.Generic; - -namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing -{ - public class CoupledColourEncoding - { - public int RunLength = 1; - - public ColourEncoding[] Payload; - - /// - /// Beginning index in the data that this encodes - /// - public int StartIndex { get; private set; } = 0; - - public int EndIndex { get; private set; } = 0; - - private CoupledColourEncoding(ColourEncoding[] payload) - { - Payload = payload; - } - - public static List Encode(List data) - { - List encoded = new List(); - - CoupledColourEncoding? lastEncoded = null; - for (int i = 0; i < data.Count; i++) - { - if (lastEncoded != null) lastEncoded.EndIndex = data[i].StartIndex - 1; - - if (i >= data.Count - 2 || !data[i].isIdenticalTo(data[i + 2])) - { - lastEncoded = new CoupledColourEncoding(new ColourEncoding[] { data[i] }); - lastEncoded.StartIndex = data[i].StartIndex; - } - else - { - lastEncoded = new CoupledColourEncoding(new ColourEncoding[] { data[i], data[i + 1] }); - lastEncoded.StartIndex = data[i].StartIndex; - lastEncoded.RunLength = 3; - i++; - - // Peek 2 indices ahead - while (i < data.Count - 2 && data[i].isIdenticalTo(data[i + 2])) - { - lastEncoded.RunLength += 1; - i++; - } - - // Skip over peeked data - i++; - } - - encoded.Add(lastEncoded); - } - - return encoded; - } - - public bool hasIdenticalPayload(CoupledColourEncoding other) - { - if (this.Payload.Length != other.Payload.Length) return false; - - for (int i = 0; i < this.Payload.Length; i++) - { - if (!this.Payload[i].isIdenticalTo(other.Payload[i])) return false; - } - - return true; - } - } -} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 7c9188b100..919770afc8 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -8,6 +8,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing @@ -63,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count) ); } - TaikoDifficultyHitObjectColour.EncodeAndAssign(difficultyHitObjects); + var encoded = TaikoDifficultyHitObjectColour.EncodeAndAssign(difficultyHitObjects); return difficultyHitObjects; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs deleted file mode 100644 index 7e18332fab..0000000000 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using osu.Game.Rulesets.Difficulty.Preprocessing; - -namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing -{ - /// - /// Stores colour compression information for a . This is only present for the - /// first in a chunk. - /// - public class TaikoDifficultyHitObjectColour - { - private const int max_repetition_interval = 16; - - /// - /// How many notes between the current and previous identical . - /// Negative number means that there is no repetition in range. - /// If no repetition is found this will have a value of + 1. - /// - public int RepetitionInterval { get; private set; } = max_repetition_interval + 1; - - /// - /// Encoding information of . - /// - public CoupledColourEncoding Encoding { get; private set; } - - public TaikoDifficultyHitObjectColour? Previous { get; private set; } = null; - - public TaikoDifficultyHitObjectColour? repeatedColour { get; private set; } = null; - - public TaikoDifficultyHitObjectColour(CoupledColourEncoding encoding) - { - Encoding = encoding; - } - - public static List EncodeAndAssign(List hitObjects) - { - List colours = new List(); - List encodings = CoupledColourEncoding.Encode(ColourEncoding.Encode(hitObjects)); - TaikoDifficultyHitObjectColour? lastColour = null; - for (int i = 0; i < encodings.Count; i++) - { - lastColour = new TaikoDifficultyHitObjectColour(encodings[i]) - { - Previous = lastColour - }; - colours.Add(lastColour); - } - - foreach (TaikoDifficultyHitObjectColour colour in colours) - { - colour.FindRepetitionInterval(); - ((TaikoDifficultyHitObject)hitObjects[colour.Encoding.StartIndex]).Colour = colour; - } - - return colours; - } - - /// - /// Finds the closest previous that has the identical . - /// Interval is defined as the amount of chunks between the current and repeated encoding. - /// - public void FindRepetitionInterval() - { - if (Previous?.Previous == null) - { - RepetitionInterval = max_repetition_interval + 1; - return; - } - - TaikoDifficultyHitObjectColour? other = Previous.Previous; - int interval = 2; - while (interval < max_repetition_interval) - { - if (Encoding.hasIdenticalPayload(other.Encoding)) - { - RepetitionInterval = Math.Min(interval, max_repetition_interval); - repeatedColour = other; - return; - } - - other = other.Previous; - if (other == null) break; - ++interval; - } - - RepetitionInterval = max_repetition_interval + 1; - } - } -} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index 6b7138fa92..ba4c066a67 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills @@ -15,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// public class Colour : StrainDecaySkill { - protected override double SkillMultiplier => 1; + protected override double SkillMultiplier => 0.7; protected override double StrainDecayBase => 0.4; /// @@ -38,6 +40,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills return difficulty; } + public static String GetDebugHeaderLabels() + { + return "StartTime,Raw,Decayed,CoupledRunLength,RepetitionInterval,EncodingRunLength,Payload(MonoRunLength|MonoCount)"; + } + // TODO: Remove befor pr public string GetDebugString(DifficultyHitObject current) { @@ -47,18 +54,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour; if (taikoCurrent != null && colour != null) { - ColourEncoding[] payload = colour.Encoding.Payload; + List payload = colour.Encoding.Payload; string payloadDisplay = ""; - for (int i = 0; i < payload.Length; ++i) + for (int i = 0; i < payload.Count; ++i) { - payloadDisplay += $"({payload[i].MonoRunLength}|{payload[i].EncodingRunLength})"; + payloadDisplay += $"({payload[i].Payload[0].RunLength}|{payload[i].Payload.Count})"; } - return $"{current.StartTime},{difficulty},{CurrentStrain},{colour.RepetitionInterval},{colour.Encoding.RunLength},{payloadDisplay}"; + return $"{current.StartTime},{difficulty},{CurrentStrain},{colour.Encoding.Payload[0].Payload.Count},{colour.Encoding.RepetitionInterval},{colour.Encoding.Payload.Count},{payloadDisplay}"; } else { - return $"{current.StartTime},{difficulty},{CurrentStrain},0,0,0"; + return $"{current.StartTime},{difficulty},{CurrentStrain},0,0,0,0,0"; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index 1086cf5f72..434474055e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -38,10 +38,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills if (debugColour) { - String filename = $"{beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv"; + String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv"; filename = filename.Replace('/', '_'); colourDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/colour-debug/{filename}")); - colourDebugOutput.WriteLine("StartTime,Raw,Decayed,RepetitionInterval,EncodingRunLength,Payload"); + colourDebugOutput.WriteLine(Colour.GetDebugHeaderLabels()); } } From f6dedc77fbc892339c642b6aa154e69ae3dd206b Mon Sep 17 00:00:00 2001 From: vun Date: Tue, 5 Jul 2022 17:01:11 +0800 Subject: [PATCH 0070/2686] Fixed encoding logic, parameter adjustments --- .../Difficulty/Preprocessing/Colour/ColourEncoding.cs | 3 ++- osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs | 4 ++-- osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs index bc427d87ae..47523189e1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs @@ -9,7 +9,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour public bool isIdenticalTo(ColourEncoding other) { - return other.Payload[0].RunLength == Payload[0].RunLength && + return hasIdenticalMonoLength(other) && + other.Payload.Count == Payload.Count && other.Payload[0].EncodedData[0].HitType == Payload[0].EncodedData[0].HitType; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index ba4c066a67..5f9185a547 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -17,8 +17,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// public class Colour : StrainDecaySkill { - protected override double SkillMultiplier => 0.7; - protected override double StrainDecayBase => 0.4; + protected override double SkillMultiplier => 0.2; + protected override double StrainDecayBase => 0.8; /// /// Applies a speed bonus dependent on the time since the last hit. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index 434474055e..16e5306d5d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -12,8 +12,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills public class Peaks : Skill { private const double rhythm_skill_multiplier = 0.3 * final_multiplier; - private const double colour_skill_multiplier = 0.375 * final_multiplier; - private const double stamina_skill_multiplier = 0.375 * final_multiplier; + private const double colour_skill_multiplier = 0.4 * final_multiplier; + private const double stamina_skill_multiplier = 0.35 * final_multiplier; private const double final_multiplier = 0.06; From 6660379a0eedb15fef1b6fccedcbd58b8c4cfd98 Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 7 Jul 2022 16:04:46 +0800 Subject: [PATCH 0071/2686] TAIKO-6 Tweak encoding and parameters, reduce rhythm weight --- .../Difficulty/Evaluators/ColourEvaluator.cs | 4 +- .../Difficulty/Evaluators/StaminaEvaluator.cs | 4 +- .../Preprocessing/Colour/ColourEncoding.cs | 2 +- .../Colour/CoupledColourEncoding.cs | 4 +- .../Difficulty/Skills/Colour.cs | 58 +++++++++---------- .../Difficulty/Skills/Peaks.cs | 36 ++++++------ .../Difficulty/Skills/Stamina.cs | 2 +- 7 files changed, 54 insertions(+), 56 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index d33f2a85b9..388858a337 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// public static void PreEvaluateDifficulties(CoupledColourEncoding encoding) { - double coupledEncodingDifficulty = EvaluateDifficultyOf(encoding); + double coupledEncodingDifficulty = 2 * EvaluateDifficultyOf(encoding); encoding.Payload[0].Payload[0].EncodedData[0].Colour!.EvaluatedDifficulty += coupledEncodingDifficulty; for (int i = 0; i < encoding.Payload.Count; i++) { @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators for (int j = 0; j < colourEncoding.Payload.Count; j++) { MonoEncoding monoEncoding = colourEncoding.Payload[j]; - monoEncoding.EncodedData[0].Colour!.EvaluatedDifficulty += EvaluateDifficultyOf(monoEncoding, j) * colourEncodingDifficulty; + monoEncoding.EncodedData[0].Colour!.EvaluatedDifficulty += EvaluateDifficultyOf(monoEncoding, j) * colourEncodingDifficulty * 0.5; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 9ebdc90eb8..6889f0f5e9 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -16,8 +16,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// The interval between the current and previous note hit using the same key. private static double speedBonus(double interval) { - // return 10 / Math.Pow(interval, 0.6); - return Math.Pow(0.1, interval / 1000); + // return 15 / Math.Pow(interval, 0.6); + return Math.Pow(0.2, interval / 1000); } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs index 47523189e1..18f9d4cf7d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs @@ -7,7 +7,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { public List Payload { get; private set; } = new List(); - public bool isIdenticalTo(ColourEncoding other) + public bool isRepetitionOf(ColourEncoding other) { return hasIdenticalMonoLength(other) && other.Payload.Count == Payload.Count && diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs index 7bdcf50055..83fd75efa0 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour Previous = lastEncoded }; - bool isCoupled = i < data.Count - 2 && data[i].isIdenticalTo(data[i + 2]); + bool isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]); if (!isCoupled) { lastEncoded.Payload.Add(data[i]); @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour lastEncoded.Payload.Add(data[i]); i++; - isCoupled = i < data.Count - 2 && data[i].isIdenticalTo(data[i + 2]); + isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]); } // Skip over peeked data and add the rest to the payload diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index 5f9185a547..d8f445f37c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -2,12 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; -using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills @@ -17,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// public class Colour : StrainDecaySkill { - protected override double SkillMultiplier => 0.2; + protected override double SkillMultiplier => 0.12; protected override double StrainDecayBase => 0.8; /// @@ -40,33 +37,34 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills return difficulty; } - public static String GetDebugHeaderLabels() - { - return "StartTime,Raw,Decayed,CoupledRunLength,RepetitionInterval,EncodingRunLength,Payload(MonoRunLength|MonoCount)"; - } + // TODO: Remove before pr + // public static String GetDebugHeaderLabels() + // { + // return "StartTime,Raw,Decayed,CoupledRunLength,RepetitionInterval,EncodingRunLength,Payload(MonoRunLength|MonoCount)"; + // } - // TODO: Remove befor pr - public string GetDebugString(DifficultyHitObject current) - { - double difficulty = ColourEvaluator.EvaluateDifficultyOf(current); - difficulty *= speedBonus(current.DeltaTime); - TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current; - TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour; - if (taikoCurrent != null && colour != null) - { - List payload = colour.Encoding.Payload; - string payloadDisplay = ""; - for (int i = 0; i < payload.Count; ++i) - { - payloadDisplay += $"({payload[i].Payload[0].RunLength}|{payload[i].Payload.Count})"; - } + // // TODO: Remove before pr + // public string GetDebugString(DifficultyHitObject current) + // { + // double difficulty = ColourEvaluator.EvaluateDifficultyOf(current); + // difficulty *= speedBonus(current.DeltaTime); + // TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current; + // TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour; + // if (taikoCurrent != null && colour != null) + // { + // List payload = colour.Encoding.Payload; + // string payloadDisplay = ""; + // for (int i = 0; i < payload.Count; ++i) + // { + // payloadDisplay += $"({payload[i].Payload[0].RunLength}|{payload[i].Payload.Count})"; + // } - return $"{current.StartTime},{difficulty},{CurrentStrain},{colour.Encoding.Payload[0].Payload.Count},{colour.Encoding.RepetitionInterval},{colour.Encoding.Payload.Count},{payloadDisplay}"; - } - else - { - return $"{current.StartTime},{difficulty},{CurrentStrain},0,0,0,0,0"; - } - } + // return $"{current.StartTime},{difficulty},{CurrentStrain},{colour.Encoding.Payload[0].Payload.Count},{colour.Encoding.RepetitionInterval},{colour.Encoding.Payload.Count},{payloadDisplay}"; + // } + // else + // { + // return $"{current.StartTime},{difficulty},{CurrentStrain},0,0,0,0,0"; + // } + // } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index 16e5306d5d..09d9720a4f 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -11,11 +11,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { public class Peaks : Skill { - private const double rhythm_skill_multiplier = 0.3 * final_multiplier; - private const double colour_skill_multiplier = 0.4 * final_multiplier; - private const double stamina_skill_multiplier = 0.35 * final_multiplier; + private const double rhythm_skill_multiplier = 0.2 * final_multiplier; + private const double colour_skill_multiplier = 0.375 * final_multiplier; + private const double stamina_skill_multiplier = 0.375 * final_multiplier; - private const double final_multiplier = 0.06; + private const double final_multiplier = 0.0625; private readonly Rhythm rhythm; private readonly Colour colour; @@ -26,8 +26,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills public double StaminaDifficultyValue => stamina.DifficultyValue() * stamina_skill_multiplier; // TODO: remove before pr - private StreamWriter? colourDebugOutput; - bool debugColour = false; + // private StreamWriter? colourDebugOutput; + // bool debugColour = false; public Peaks(Mod[] mods, IBeatmap beatmap) : base(mods) @@ -36,13 +36,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills colour = new Colour(mods); stamina = new Stamina(mods); - if (debugColour) - { - String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv"; - filename = filename.Replace('/', '_'); - colourDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/colour-debug/{filename}")); - colourDebugOutput.WriteLine(Colour.GetDebugHeaderLabels()); - } + // if (debugColour) + // { + // String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv"; + // filename = filename.Replace('/', '_'); + // colourDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/colour-debug/{filename}")); + // colourDebugOutput.WriteLine(Colour.GetDebugHeaderLabels()); + // } } @@ -59,11 +59,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills colour.Process(current); stamina.Process(current); - if (debugColour && colourDebugOutput != null) - { - colourDebugOutput.WriteLine(colour.GetDebugString(current)); - colourDebugOutput.Flush(); - } + // if (debugColour && colourDebugOutput != null) + // { + // colourDebugOutput.WriteLine(colour.GetDebugString(current)); + // colourDebugOutput.Flush(); + // } } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 777bd97f81..344004bcf6 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// public class Stamina : StrainDecaySkill { - protected override double SkillMultiplier => 1.2; + protected override double SkillMultiplier => 1.1; protected override double StrainDecayBase => 0.4; /// From 8e84f76bf9547d349e25090423468c9e2efb71fd Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Fri, 8 Jul 2022 15:49:10 -0400 Subject: [PATCH 0072/2686] add hidden item toggle to directory/file selectors --- .../UserInterfaceV2/OsuDirectorySelector.cs | 2 ++ .../OsuDirectorySelectorHiddenToggle.cs | 29 +++++++++++++++++++ .../UserInterfaceV2/OsuFileSelector.cs | 2 ++ 3 files changed, 33 insertions(+) create mode 100644 osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelector.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelector.cs index 42e1073baf..0e348108aa 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelector.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelector.cs @@ -31,6 +31,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 protected override DirectorySelectorBreadcrumbDisplay CreateBreadcrumb() => new OsuDirectorySelectorBreadcrumbDisplay(); + protected override Drawable CreateHiddenToggleButton() => new OsuDirectorySelectorHiddenToggle { Current = { BindTarget = ShowHiddenItems } }; + protected override DirectorySelectorDirectory CreateParentDirectoryItem(DirectoryInfo directory) => new OsuDirectorySelectorParentDirectory(directory); protected override DirectorySelectorDirectory CreateDirectoryItem(DirectoryInfo directory, string displayName = null) => new OsuDirectorySelectorDirectory(directory, displayName); diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs new file mode 100644 index 0000000000..bb582cad8f --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; +using osuTK.Graphics; + +namespace osu.Game.Graphics.UserInterfaceV2 +{ + internal class OsuDirectorySelectorHiddenToggle : OsuCheckbox + { + public OsuDirectorySelectorHiddenToggle() + { + RelativeSizeAxes = Axes.None; + AutoSizeAxes = Axes.Both; + Anchor = Anchor.CentreLeft; + Origin = Anchor.CentreLeft; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Nub.AccentColour = colours.GreySeaFoamLighter; + Nub.GlowingAccentColour = Color4.White; + Nub.GlowColour = Color4.White; + } + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs b/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs index 3e8b7dc209..70af68d595 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs @@ -33,6 +33,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 protected override DirectorySelectorBreadcrumbDisplay CreateBreadcrumb() => new OsuDirectorySelectorBreadcrumbDisplay(); + protected override Drawable CreateHiddenToggleButton() => new OsuDirectorySelectorHiddenToggle { Current = { BindTarget = ShowHiddenItems } }; + protected override DirectorySelectorDirectory CreateParentDirectoryItem(DirectoryInfo directory) => new OsuDirectorySelectorParentDirectory(directory); protected override DirectorySelectorDirectory CreateDirectoryItem(DirectoryInfo directory, string displayName = null) => new OsuDirectorySelectorDirectory(directory, displayName); From b92979acd69b61330d1456a15dafe682df5756bd Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Fri, 8 Jul 2022 16:00:48 -0400 Subject: [PATCH 0073/2686] add tooltip to checkbox --- .../UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs index bb582cad8f..5b5af1d71d 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs @@ -3,13 +3,17 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; using osuTK.Graphics; namespace osu.Game.Graphics.UserInterfaceV2 { - internal class OsuDirectorySelectorHiddenToggle : OsuCheckbox + internal class OsuDirectorySelectorHiddenToggle : OsuCheckbox, IHasTooltip { + public LocalisableString TooltipText => @"Show hidden items"; + public OsuDirectorySelectorHiddenToggle() { RelativeSizeAxes = Axes.None; From 855debd5f66c2c1a4cd25d63bfd61d0dc477fbaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 09:29:17 +0800 Subject: [PATCH 0074/2686] Remove nullable disable annotation and mark some return value as nullable. --- osu.Game/Rulesets/Ruleset.cs | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index c1ec6c30ef..7130f4bc35 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.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. -#nullable disable - using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -81,7 +79,7 @@ namespace osu.Game.Rulesets /// Returns a fresh instance of the mod matching the specified acronym. /// /// The acronym to query for . - public Mod CreateModFromAcronym(string acronym) + public Mod? CreateModFromAcronym(string acronym) { return AllMods.FirstOrDefault(m => m.Acronym == acronym)?.CreateInstance(); } @@ -89,7 +87,7 @@ namespace osu.Game.Rulesets /// /// Returns a fresh instance of the mod matching the specified type. /// - public T CreateMod() + public T? CreateMod() where T : Mod { return AllMods.FirstOrDefault(m => m is T)?.CreateInstance() as T; @@ -183,10 +181,9 @@ namespace osu.Game.Rulesets return value; } - [CanBeNull] - public ModAutoplay GetAutoplayMod() => CreateMod(); + public ModAutoplay? GetAutoplayMod() => CreateMod(); - public virtual ISkin CreateLegacySkinProvider([NotNull] ISkin skin, IBeatmap beatmap) => null; + public virtual ISkin? CreateLegacySkinProvider([NotNull] ISkin skin, IBeatmap beatmap) => null; protected Ruleset() { @@ -206,7 +203,7 @@ namespace osu.Game.Rulesets /// The beatmap to create the hit renderer for. /// The s to apply. /// Unable to successfully load the beatmap to be usable with this ruleset. - public abstract DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null); + public abstract DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList? mods = null); /// /// Creates a for this . @@ -240,8 +237,7 @@ namespace osu.Game.Rulesets /// Optionally creates a to generate performance data from the provided score. /// /// A performance calculator instance for the provided score. - [CanBeNull] - public virtual PerformanceCalculator CreatePerformanceCalculator() => null; + public virtual PerformanceCalculator? CreatePerformanceCalculator() => null; public virtual HitObjectComposer CreateHitObjectComposer() => null; @@ -253,7 +249,7 @@ namespace osu.Game.Rulesets public abstract string Description { get; } - public virtual RulesetSettingsSubsection CreateSettings() => null; + public virtual RulesetSettingsSubsection? CreateSettings() => null; /// /// Creates the for this . @@ -303,7 +299,6 @@ namespace osu.Game.Rulesets /// The to create the statistics for. The score is guaranteed to have populated. /// The , converted for this with all relevant s applied. /// The s to display. Each may contain 0 or more . - [NotNull] public virtual StatisticRow[] CreateStatisticsForScore(ScoreInfo score, IBeatmap playableBeatmap) => Array.Empty(); /// @@ -356,13 +351,11 @@ namespace osu.Game.Rulesets /// /// Creates ruleset-specific beatmap filter criteria to be used on the song select screen. /// - [CanBeNull] - public virtual IRulesetFilterCriteria CreateRulesetFilterCriteria() => null; + public virtual IRulesetFilterCriteria? CreateRulesetFilterCriteria() => null; /// /// Can be overridden to add a ruleset-specific section to the editor beatmap setup screen. /// - [CanBeNull] - public virtual RulesetSetupSection CreateEditorSetupSection() => null; + public virtual RulesetSetupSection? CreateEditorSetupSection() => null; } } From 4a503bab0a3d520965efeb54594053baaacc348c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 09:29:59 +0800 Subject: [PATCH 0075/2686] Remove unnecessary attribute. --- osu.Game/Rulesets/Ruleset.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 7130f4bc35..af8ff10fa1 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -23,7 +23,6 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Skinning; using osu.Game.Users; -using JetBrains.Annotations; using osu.Framework.Extensions; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Testing; @@ -101,7 +100,6 @@ namespace osu.Game.Rulesets /// then the proper behaviour is to return an empty enumerable. /// mods should not be present in the returned enumerable. /// - [ItemNotNull] public abstract IEnumerable GetModsFor(ModType type); /// @@ -183,7 +181,7 @@ namespace osu.Game.Rulesets public ModAutoplay? GetAutoplayMod() => CreateMod(); - public virtual ISkin? CreateLegacySkinProvider([NotNull] ISkin skin, IBeatmap beatmap) => null; + public virtual ISkin? CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => null; protected Ruleset() { From e67cb4c90520e4c328c653372bd11b20a67a9935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 09:35:46 +0800 Subject: [PATCH 0076/2686] Mark create beatmap verifier as nullable because seems it's not requirement to be implemented. --- osu.Game/Rulesets/Ruleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index af8ff10fa1..14513b06b8 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -239,7 +239,7 @@ namespace osu.Game.Rulesets public virtual HitObjectComposer CreateHitObjectComposer() => null; - public virtual IBeatmapVerifier CreateBeatmapVerifier() => null; + public virtual IBeatmapVerifier? CreateBeatmapVerifier() => null; public virtual Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.Solid.QuestionCircle }; From 857377e1451402cb8848da21c9cd0d00c01dbb15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 09:53:05 +0800 Subject: [PATCH 0077/2686] Move CreateConvertibleReplayFrame() into legacy ruleset interface because technically only legacy ruleset use it to convert the legacy frame. But seems some of the customized ruleset use it for save the replay frame. --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- osu.Game/Rulesets/ILegacyRuleset.cs | 9 ++++++++- osu.Game/Rulesets/Ruleset.cs | 8 -------- osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 2 +- osu.Game/Screens/Play/SpectatorPlayer.cs | 6 +++++- 8 files changed, 18 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index f832d99807..766b5f6f58 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -187,7 +187,7 @@ namespace osu.Game.Rulesets.Catch public int LegacyID => 2; - public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame(); + public IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame(); public override HitObjectComposer CreateHitObjectComposer() => new CatchHitObjectComposer(this); diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 4723416c30..f45a2517df 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -280,7 +280,7 @@ namespace osu.Game.Rulesets.Mania public int LegacyID => 3; - public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame(); + public IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame(); public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaRulesetConfigManager(settings, RulesetInfo); diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 120ce32612..392574ef03 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -234,7 +234,7 @@ namespace osu.Game.Rulesets.Osu public int LegacyID => 0; - public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new OsuReplayFrame(); + public IConvertibleReplayFrame CreateConvertibleReplayFrame() => new OsuReplayFrame(); public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new OsuRulesetConfigManager(settings, RulesetInfo); diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 223e268d7f..66fc64c018 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -177,7 +177,7 @@ namespace osu.Game.Rulesets.Taiko public int LegacyID => 1; - public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame(); + public IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame(); protected override IEnumerable GetValidHitResults() { diff --git a/osu.Game/Rulesets/ILegacyRuleset.cs b/osu.Game/Rulesets/ILegacyRuleset.cs index a8cfed4866..c2617a065c 100644 --- a/osu.Game/Rulesets/ILegacyRuleset.cs +++ b/osu.Game/Rulesets/ILegacyRuleset.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable +using osu.Game.Rulesets.Replays.Types; namespace osu.Game.Rulesets { @@ -13,5 +13,12 @@ namespace osu.Game.Rulesets /// Identifies the server-side ID of a legacy ruleset. /// int LegacyID { get; } + + /// + /// For rulesets which support legacy (osu-stable) replay conversion, this method will create an empty replay frame + /// for conversion use. + /// + /// An empty frame for the current ruleset, or null if unsupported. + IConvertibleReplayFrame CreateConvertibleReplayFrame(); } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 14513b06b8..89ef6d2d54 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -13,7 +13,6 @@ using osu.Game.Beatmaps; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.UI; using osu.Game.Beatmaps.Legacy; using osu.Game.Configuration; @@ -284,13 +283,6 @@ namespace osu.Game.Rulesets /// A descriptive name of the variant. public virtual string GetVariantName(int variant) => string.Empty; - /// - /// For rulesets which support legacy (osu-stable) replay conversion, this method will create an empty replay frame - /// for conversion use. - /// - /// An empty frame for the current ruleset, or null if unsupported. - public virtual IConvertibleReplayFrame CreateConvertibleReplayFrame() => null; - /// /// Creates the statistics for a to be displayed in the results screen. /// diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs index f64e730c06..2b22b4abc7 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs @@ -282,7 +282,7 @@ namespace osu.Game.Scoring.Legacy private ReplayFrame convertFrame(LegacyReplayFrame currentFrame, ReplayFrame lastFrame) { - var convertible = currentRuleset.CreateConvertibleReplayFrame(); + var convertible = (currentRuleset as ILegacyRuleset)?.CreateConvertibleReplayFrame(); if (convertible == null) throw new InvalidOperationException($"Legacy replay cannot be converted for the ruleset: {currentRuleset.Description}"); diff --git a/osu.Game/Screens/Play/SpectatorPlayer.cs b/osu.Game/Screens/Play/SpectatorPlayer.cs index 797787b194..f59fd9559c 100644 --- a/osu.Game/Screens/Play/SpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SpectatorPlayer.cs @@ -10,6 +10,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.Spectator; +using osu.Game.Rulesets; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays.Types; using osu.Game.Scoring; @@ -79,11 +80,14 @@ namespace osu.Game.Screens.Play if (!this.IsCurrentScreen()) return; + if (GameplayState.Ruleset is not ILegacyRuleset legacyRuleset) + return; + bool isFirstBundle = score.Replay.Frames.Count == 0; foreach (var frame in bundle.Frames) { - IConvertibleReplayFrame convertibleFrame = GameplayState.Ruleset.CreateConvertibleReplayFrame(); + IConvertibleReplayFrame convertibleFrame = legacyRuleset.CreateConvertibleReplayFrame(); convertibleFrame.FromLegacy(frame, GameplayState.Beatmap); var convertedFrame = (ReplayFrame)convertibleFrame; From d39f53f1f0e2ab307c593eb928078f0c55a13684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 10:01:56 +0800 Subject: [PATCH 0078/2686] Mark `CreateConfig()` return type as nullable because it's not required all ruleset to implement. Also, remove nullable disable annotation for all using classes. Setting store can be nullable because `RulesetConfigManager()` can accept null setting store. --- osu.Game/Rulesets/Ruleset.cs | 2 +- osu.Game/Rulesets/RulesetConfigCache.cs | 6 ++---- osu.Game/Tests/Rulesets/TestRulesetConfigCache.cs | 6 ++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 89ef6d2d54..cd3ab4f726 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -252,7 +252,7 @@ namespace osu.Game.Rulesets /// Creates the for this . /// /// The to store the settings. - public virtual IRulesetConfigManager CreateConfig(SettingsStore settings) => null; + public virtual IRulesetConfigManager? CreateConfig(SettingsStore? settings) => null; /// /// A unique short name to reference this ruleset in online requests. diff --git a/osu.Game/Rulesets/RulesetConfigCache.cs b/osu.Game/Rulesets/RulesetConfigCache.cs index 017214df61..ab44e86048 100644 --- a/osu.Game/Rulesets/RulesetConfigCache.cs +++ b/osu.Game/Rulesets/RulesetConfigCache.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. -#nullable disable - using System; using System.Collections.Generic; using osu.Framework.Graphics; @@ -18,7 +16,7 @@ namespace osu.Game.Rulesets private readonly RealmAccess realm; private readonly RulesetStore rulesets; - private readonly Dictionary configCache = new Dictionary(); + private readonly Dictionary configCache = new Dictionary(); public RulesetConfigCache(RealmAccess realm, RulesetStore rulesets) { @@ -42,7 +40,7 @@ namespace osu.Game.Rulesets } } - public IRulesetConfigManager GetConfigFor(Ruleset ruleset) + public IRulesetConfigManager? GetConfigFor(Ruleset ruleset) { if (!IsLoaded) throw new InvalidOperationException($@"Cannot retrieve {nameof(IRulesetConfigManager)} before {nameof(RulesetConfigCache)} has loaded"); diff --git a/osu.Game/Tests/Rulesets/TestRulesetConfigCache.cs b/osu.Game/Tests/Rulesets/TestRulesetConfigCache.cs index a80154c38e..cf637983d9 100644 --- a/osu.Game/Tests/Rulesets/TestRulesetConfigCache.cs +++ b/osu.Game/Tests/Rulesets/TestRulesetConfigCache.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. -#nullable disable - using System.Collections.Concurrent; using osu.Game.Rulesets; using osu.Game.Rulesets.Configuration; @@ -14,8 +12,8 @@ namespace osu.Game.Tests.Rulesets /// public class TestRulesetConfigCache : IRulesetConfigCache { - private readonly ConcurrentDictionary configCache = new ConcurrentDictionary(); + private readonly ConcurrentDictionary configCache = new ConcurrentDictionary(); - public IRulesetConfigManager GetConfigFor(Ruleset ruleset) => configCache.GetOrAdd(ruleset.ShortName, _ => ruleset.CreateConfig(null)); + public IRulesetConfigManager? GetConfigFor(Ruleset ruleset) => configCache.GetOrAdd(ruleset.ShortName, _ => ruleset.CreateConfig(null)); } } From 57c6763556920d09399fe679c1dfc8d386686759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 10:07:09 +0800 Subject: [PATCH 0079/2686] Mark the `CreateBeatmapProcessor()` as nullable. Also, should add the null check in the working beatmap. --- osu.Game/Beatmaps/WorkingBeatmap.cs | 11 +++++++---- osu.Game/Rulesets/Ruleset.cs | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 16464932e0..22c3ad43e6 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -279,12 +279,15 @@ namespace osu.Game.Beatmaps } } - IBeatmapProcessor processor = rulesetInstance.CreateBeatmapProcessor(converted); + var processor = rulesetInstance.CreateBeatmapProcessor(converted); - foreach (var mod in mods.OfType()) - mod.ApplyToBeatmapProcessor(processor); + if (processor != null) + { + foreach (var mod in mods.OfType()) + mod.ApplyToBeatmapProcessor(processor); - processor?.PreProcess(); + processor.PreProcess(); + } // Compute default values for hitobjects, including creating nested hitobjects in-case they're needed foreach (var obj in converted.HitObjects) diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index cd3ab4f726..bd2d147a08 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -226,7 +226,7 @@ namespace osu.Game.Rulesets /// /// The to be processed. /// The . - public virtual IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => null; + public virtual IBeatmapProcessor? CreateBeatmapProcessor(IBeatmap beatmap) => null; public abstract DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap); From 8e1ed1c621d12c4b1a1f97812968043b8eb7017c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 10:09:32 +0800 Subject: [PATCH 0080/2686] Mark CreateHitObjectComposer() accept null. And add the null check in the test case. --- osu.Game.Tests/Visual/Editing/TimelineTestScene.cs | 8 +++++++- osu.Game/Rulesets/Ruleset.cs | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs index 437f06c47f..7c11b4aa56 100644 --- a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs +++ b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs @@ -39,7 +39,13 @@ namespace osu.Game.Tests.Visual.Editing Dependencies.Cache(EditorBeatmap); Dependencies.CacheAs(EditorBeatmap); - Composer = playable.BeatmapInfo.Ruleset.CreateInstance().CreateHitObjectComposer().With(d => d.Alpha = 0); + Composer = playable.BeatmapInfo.Ruleset.CreateInstance().CreateHitObjectComposer().With(d => + { + if (d == null) + return; + + d.Alpha = 0; + }); Add(new OsuContextMenuContainer { diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index bd2d147a08..2cab529a4b 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -236,7 +236,7 @@ namespace osu.Game.Rulesets /// A performance calculator instance for the provided score. public virtual PerformanceCalculator? CreatePerformanceCalculator() => null; - public virtual HitObjectComposer CreateHitObjectComposer() => null; + public virtual HitObjectComposer? CreateHitObjectComposer() => null; public virtual IBeatmapVerifier? CreateBeatmapVerifier() => null; From 1725a76fa0183cd9e9c9b7a2139ee498f525a11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 10:15:02 +0800 Subject: [PATCH 0081/2686] Remove the nullable disable annotation for all rulesets. --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 4 +--- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 6 ++---- osu.Game.Rulesets.Osu/OsuRuleset.cs | 6 ++---- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 4 +--- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 766b5f6f58..964598dcaf 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.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. -#nullable disable - using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets.Catch.Mods; @@ -32,7 +30,7 @@ namespace osu.Game.Rulesets.Catch { public class CatchRuleset : Ruleset, ILegacyRuleset { - public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => new DrawableCatchRuleset(this, beatmap, mods); + public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList? mods = null) => new DrawableCatchRuleset(this, beatmap, mods); public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(); diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index f45a2517df..b391c64572 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.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. -#nullable disable - using System; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Mods; @@ -47,7 +45,7 @@ namespace osu.Game.Rulesets.Mania /// public const int MAX_STAGE_KEYS = 10; - public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => new DrawableManiaRuleset(this, beatmap, mods); + public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList? mods = null) => new DrawableManiaRuleset(this, beatmap, mods); public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(); @@ -282,7 +280,7 @@ namespace osu.Game.Rulesets.Mania public IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame(); - public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new ManiaRulesetConfigManager(settings, RulesetInfo); + public override IRulesetConfigManager CreateConfig(SettingsStore? settings) => new ManiaRulesetConfigManager(settings, RulesetInfo); public override RulesetSettingsSubsection CreateSettings() => new ManiaSettingsSubsection(this); diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 392574ef03..458a0a12f4 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.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. -#nullable disable - using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; @@ -43,7 +41,7 @@ namespace osu.Game.Rulesets.Osu { public class OsuRuleset : Ruleset, ILegacyRuleset { - public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => new DrawableOsuRuleset(this, beatmap, mods); + public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList? mods = null) => new DrawableOsuRuleset(this, beatmap, mods); public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor(); @@ -236,7 +234,7 @@ namespace osu.Game.Rulesets.Osu public IConvertibleReplayFrame CreateConvertibleReplayFrame() => new OsuReplayFrame(); - public override IRulesetConfigManager CreateConfig(SettingsStore settings) => new OsuRulesetConfigManager(settings, RulesetInfo); + public override IRulesetConfigManager CreateConfig(SettingsStore? settings) => new OsuRulesetConfigManager(settings, RulesetInfo); protected override IEnumerable GetValidHitResults() { diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 66fc64c018..19aa3e1016 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.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. -#nullable disable - using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; @@ -36,7 +34,7 @@ namespace osu.Game.Rulesets.Taiko { public class TaikoRuleset : Ruleset, ILegacyRuleset { - public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => new DrawableTaikoRuleset(this, beatmap, mods); + public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList? mods = null) => new DrawableTaikoRuleset(this, beatmap, mods); public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(); From 84002aefae779efefc9602215716e43542a9d0ac Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 11 Jul 2022 20:18:50 +0300 Subject: [PATCH 0082/2686] Update file/directory selector tests to use `ThemeComparisonTestScene` --- .../Settings/TestSceneDirectorySelector.cs | 11 +++--- .../Visual/Settings/TestSceneFileSelector.cs | 34 +++++++++++++++---- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneDirectorySelector.cs b/osu.Game.Tests/Visual/Settings/TestSceneDirectorySelector.cs index 4f05194e08..16110e5595 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneDirectorySelector.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneDirectorySelector.cs @@ -3,18 +3,17 @@ #nullable disable -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Tests.Visual.UserInterface; namespace osu.Game.Tests.Visual.Settings { - public class TestSceneDirectorySelector : OsuTestScene + public class TestSceneDirectorySelector : ThemeComparisonTestScene { - [BackgroundDependencyLoader] - private void load() + protected override Drawable CreateContent() => new OsuDirectorySelector { - Add(new OsuDirectorySelector { RelativeSizeAxes = Axes.Both }); - } + RelativeSizeAxes = Axes.Both + }; } } diff --git a/osu.Game.Tests/Visual/Settings/TestSceneFileSelector.cs b/osu.Game.Tests/Visual/Settings/TestSceneFileSelector.cs index 6f25012bfa..97bf0d212a 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneFileSelector.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneFileSelector.cs @@ -4,23 +4,43 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Tests.Visual.UserInterface; namespace osu.Game.Tests.Visual.Settings { - public class TestSceneFileSelector : OsuTestScene + public class TestSceneFileSelector : ThemeComparisonTestScene { - [Test] - public void TestAllFiles() - { - AddStep("create", () => Child = new OsuFileSelector { RelativeSizeAxes = Axes.Both }); - } + [Resolved] + private OsuColour colours { get; set; } [Test] public void TestJpgFilesOnly() { - AddStep("create", () => Child = new OsuFileSelector(validFileExtensions: new[] { ".jpg" }) { RelativeSizeAxes = Axes.Both }); + AddStep("create", () => + { + Cell(0, 0).Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.GreySeaFoam + }, + new OsuFileSelector(validFileExtensions: new[] { ".jpg" }) + { + RelativeSizeAxes = Axes.Both, + }, + }; + }); } + + protected override Drawable CreateContent() => new OsuFileSelector + { + RelativeSizeAxes = Axes.Both, + }; } } From 7d26f178c6c1b8b3bc7b56e20352c52389c3bd75 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Mon, 11 Jul 2022 16:36:17 -0400 Subject: [PATCH 0083/2686] use `OverlayColourProvider` for nub colors when possible --- .../UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs index 5b5af1d71d..74e9312eda 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; using osuTK.Graphics; namespace osu.Game.Graphics.UserInterfaceV2 @@ -22,9 +23,12 @@ namespace osu.Game.Graphics.UserInterfaceV2 Origin = Anchor.CentreLeft; } - [BackgroundDependencyLoader] - private void load(OsuColour colours) + [BackgroundDependencyLoader(true)] + private void load(OverlayColourProvider? overlayColourProvider, OsuColour colours) { + if (overlayColourProvider != null) + return; + Nub.AccentColour = colours.GreySeaFoamLighter; Nub.GlowingAccentColour = Color4.White; Nub.GlowColour = Color4.White; From 77f5ec3a4ec24dcc6b5df8b7b7fd2dd1a8657dd4 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Mon, 11 Jul 2022 16:39:53 -0400 Subject: [PATCH 0084/2686] use checkbox label instead of tooltip --- .../OsuDirectorySelectorHiddenToggle.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs index 74e9312eda..38ec602fe7 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs @@ -3,24 +3,23 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; +using osuTK; using osuTK.Graphics; namespace osu.Game.Graphics.UserInterfaceV2 { - internal class OsuDirectorySelectorHiddenToggle : OsuCheckbox, IHasTooltip + internal class OsuDirectorySelectorHiddenToggle : OsuCheckbox { - public LocalisableString TooltipText => @"Show hidden items"; - public OsuDirectorySelectorHiddenToggle() { RelativeSizeAxes = Axes.None; - AutoSizeAxes = Axes.Both; + AutoSizeAxes = Axes.None; + Size = new Vector2(100, 50); Anchor = Anchor.CentreLeft; Origin = Anchor.CentreLeft; + LabelText = "Show hidden items"; } [BackgroundDependencyLoader(true)] From 8617b94c9d6865a65007acbc79010f89b2c04be8 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Mon, 11 Jul 2022 17:12:14 -0400 Subject: [PATCH 0085/2686] shorten label --- .../UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs index 38ec602fe7..28f6049683 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs @@ -19,7 +19,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 Size = new Vector2(100, 50); Anchor = Anchor.CentreLeft; Origin = Anchor.CentreLeft; - LabelText = "Show hidden items"; + LabelText = @"Show hidden"; } [BackgroundDependencyLoader(true)] From d6abdc597d68459fd6539d49123a5e5cec7f7051 Mon Sep 17 00:00:00 2001 From: Gabe Livengood <47010459+ggliv@users.noreply.github.com> Date: Mon, 11 Jul 2022 17:12:41 -0400 Subject: [PATCH 0086/2686] correct label positioning --- .../Graphics/UserInterface/OsuCheckbox.cs | 20 +++++++++---------- .../OsuDirectorySelectorHiddenToggle.cs | 2 ++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs index bbd8f8ecea..8772c1e2d9 100644 --- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs @@ -26,24 +26,24 @@ namespace osu.Game.Graphics.UserInterface { set { - if (labelText != null) - labelText.Text = value; + if (LabelTextFlowContainer != null) + LabelTextFlowContainer.Text = value; } } public MarginPadding LabelPadding { - get => labelText?.Padding ?? new MarginPadding(); + get => LabelTextFlowContainer?.Padding ?? new MarginPadding(); set { - if (labelText != null) - labelText.Padding = value; + if (LabelTextFlowContainer != null) + LabelTextFlowContainer.Padding = value; } } protected readonly Nub Nub; - private readonly OsuTextFlowContainer labelText; + protected readonly OsuTextFlowContainer LabelTextFlowContainer; private Sample sampleChecked; private Sample sampleUnchecked; @@ -56,7 +56,7 @@ namespace osu.Game.Graphics.UserInterface Children = new Drawable[] { - labelText = new OsuTextFlowContainer(ApplyLabelParameters) + LabelTextFlowContainer = new OsuTextFlowContainer(ApplyLabelParameters) { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, @@ -70,19 +70,19 @@ namespace osu.Game.Graphics.UserInterface Nub.Anchor = Anchor.CentreRight; Nub.Origin = Anchor.CentreRight; Nub.Margin = new MarginPadding { Right = nub_padding }; - labelText.Padding = new MarginPadding { Right = Nub.EXPANDED_SIZE + nub_padding * 2 }; + LabelTextFlowContainer.Padding = new MarginPadding { Right = Nub.EXPANDED_SIZE + nub_padding * 2 }; } else { Nub.Anchor = Anchor.CentreLeft; Nub.Origin = Anchor.CentreLeft; Nub.Margin = new MarginPadding { Left = nub_padding }; - labelText.Padding = new MarginPadding { Left = Nub.EXPANDED_SIZE + nub_padding * 2 }; + LabelTextFlowContainer.Padding = new MarginPadding { Left = Nub.EXPANDED_SIZE + nub_padding * 2 }; } Nub.Current.BindTo(Current); - Current.DisabledChanged += disabled => labelText.Alpha = Nub.Alpha = disabled ? 0.3f : 1; + Current.DisabledChanged += disabled => LabelTextFlowContainer.Alpha = Nub.Alpha = disabled ? 0.3f : 1; } /// diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs index 28f6049683..7aaf12ca34 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs @@ -19,6 +19,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 Size = new Vector2(100, 50); Anchor = Anchor.CentreLeft; Origin = Anchor.CentreLeft; + LabelTextFlowContainer.Anchor = Anchor.CentreLeft; + LabelTextFlowContainer.Origin = Anchor.CentreLeft; LabelText = @"Show hidden"; } From 3dbd0c9055dac6c32e9b8bd31baad2d6d42ac7cb Mon Sep 17 00:00:00 2001 From: andy Date: Tue, 12 Jul 2022 09:37:16 +0800 Subject: [PATCH 0087/2686] Update osu.Game.Tests/Visual/Editing/TimelineTestScene.cs Co-authored-by: Salman Ahmed --- osu.Game.Tests/Visual/Editing/TimelineTestScene.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs index 7c11b4aa56..40d91dcbaa 100644 --- a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs +++ b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs @@ -39,13 +39,10 @@ namespace osu.Game.Tests.Visual.Editing Dependencies.Cache(EditorBeatmap); Dependencies.CacheAs(EditorBeatmap); - Composer = playable.BeatmapInfo.Ruleset.CreateInstance().CreateHitObjectComposer().With(d => - { - if (d == null) - return; + Composer = playable.BeatmapInfo.Ruleset.CreateInstance().CreateHitObjectComposer(); + Debug.Assert(Composer != null); - d.Alpha = 0; - }); + Composer.Alpha = 0; Add(new OsuContextMenuContainer { From 079fcf13a6245a987e12fa7db7a06401452be51f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Tue, 12 Jul 2022 09:41:03 +0800 Subject: [PATCH 0088/2686] Add missing import. --- osu.Game.Tests/Visual/Editing/TimelineTestScene.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs index 40d91dcbaa..d4c96a837b 100644 --- a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs +++ b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs @@ -3,6 +3,7 @@ #nullable disable +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; From 6a643cb6eae329fe7e434c07392f195f283890ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Tue, 12 Jul 2022 09:41:19 +0800 Subject: [PATCH 0089/2686] Use Debug.Assert instead. --- osu.Game/Screens/Play/SpectatorPlayer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/SpectatorPlayer.cs b/osu.Game/Screens/Play/SpectatorPlayer.cs index f59fd9559c..659d7d5d6c 100644 --- a/osu.Game/Screens/Play/SpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SpectatorPlayer.cs @@ -3,6 +3,7 @@ #nullable disable +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Screens; @@ -80,8 +81,8 @@ namespace osu.Game.Screens.Play if (!this.IsCurrentScreen()) return; - if (GameplayState.Ruleset is not ILegacyRuleset legacyRuleset) - return; + var legacyRuleset = GameplayState.Ruleset as ILegacyRuleset; + Debug.Assert(legacyRuleset != null); bool isFirstBundle = score.Replay.Frames.Count == 0; From 58c687172b311e248b20629495ac64f5d8f2892f Mon Sep 17 00:00:00 2001 From: StanR Date: Tue, 12 Jul 2022 10:52:44 +0300 Subject: [PATCH 0090/2686] Reduce low AR bonus --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index bf5a6e517a..1f94defb67 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -52,6 +52,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (score.Mods.Any(h => h is OsuModRelax)) { // https://www.desmos.com/calculator/bc9eybdthb + // we use OD13.3 as maximum since it's the value at which great hitwidow becomes 0 + // this is well beyond currently maximum achievable OD which is 12.17 (DTx2 + DA with OD11) double okMultiplier = Math.Max(0.0, osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 13.33, 1.8) : 1.0); double mehMultiplier = Math.Max(0.0, osuAttributes.OverallDifficulty > 0.0 ? 1 - Math.Pow(osuAttributes.OverallDifficulty / 13.33, 5) : 1.0); @@ -107,7 +109,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (attributes.ApproachRate > 10.33) approachRateFactor = 0.3 * (attributes.ApproachRate - 10.33); else if (attributes.ApproachRate < 8.0) - approachRateFactor = 0.1 * (8.0 - attributes.ApproachRate); + approachRateFactor = 0.05 * (8.0 - attributes.ApproachRate); if (score.Mods.Any(h => h is OsuModRelax)) approachRateFactor = 0.0; From 0983e4f81e7296c419cfb85a0bc6a30586c57b4f Mon Sep 17 00:00:00 2001 From: StanR Date: Tue, 12 Jul 2022 17:57:00 +0300 Subject: [PATCH 0091/2686] Increase 50s nerf again --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 1f94defb67..7eed5749b6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -186,7 +186,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty speedValue *= (0.95 + Math.Pow(attributes.OverallDifficulty, 2) / 750) * Math.Pow((accuracy + relevantAccuracy) / 2.0, (14.5 - Math.Max(attributes.OverallDifficulty, 8)) / 2); // Scale the speed value with # of 50s to punish doubletapping. - speedValue *= Math.Pow(0.995, countMeh < totalHits / 500.0 ? 0 : countMeh - totalHits / 500.0); + speedValue *= Math.Pow(0.99, countMeh < totalHits / 500.0 ? 0 : countMeh - totalHits / 500.0); return speedValue; } From 760742e358a3a12d995bdf544baf87871a178df3 Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 14 Jul 2022 00:42:50 +0300 Subject: [PATCH 0092/2686] Move relax global multiplier to diffcalc --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 3 ++- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 7d00f59a9b..9748a00b12 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -45,8 +45,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(h => h is OsuModRelax)) { + aimRating *= 0.9; speedRating = 0.0; - flashlightRating *= 0.75; + flashlightRating *= 0.7; } double baseAimPerformance = Math.Pow(5 * Math.Max(1, aimRating / 0.0675) - 4, 3) / 100000; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 7eed5749b6..6eed778561 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -59,8 +59,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty // As we're adding Oks and Mehs to an approximated number of combo breaks the result can be higher than total hits in specific scenarios (which breaks some calculations) so we need to clamp it. effectiveMissCount = Math.Min(effectiveMissCount + countOk * okMultiplier + countMeh * mehMultiplier, totalHits); - - multiplier *= 0.7; } double aimValue = computeAimValue(score, osuAttributes); From 4fdbf3ff247921129865b79236596bf2b1f6e66e Mon Sep 17 00:00:00 2001 From: 63411 <62799417+molneya@users.noreply.github.com> Date: Thu, 14 Jul 2022 15:07:58 +0800 Subject: [PATCH 0093/2686] individualStrain should be the hardest individualStrain column for notes in a chord --- osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs index 74334c90e4..657dfbb575 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs @@ -78,7 +78,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills individualStrains[column] = applyDecay(individualStrains[column], startTime - startTimes[column], individual_decay_base); individualStrains[column] += 2.0 * holdFactor; - individualStrain = individualStrains[column]; + // individualStrain should be the hardest individualStrain column for notes in a chord + individualStrain = maniaCurrent.DeltaTime == 0 ? Math.Max(individualStrain, individualStrains[column]) : individualStrains[column]; // Decay and increase overallStrain overallStrain = applyDecay(overallStrain, current.DeltaTime, overall_decay_base); From 1cb18f84743840a43ced5cc5cae9f9cce78807e1 Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 14 Jul 2022 16:29:23 +0800 Subject: [PATCH 0094/2686] Refactor colour encoding to avoid circular dependencies --- .../Difficulty/Evaluators/ColourEvaluator.cs | 12 -- .../Difficulty/Evaluators/StaminaEvaluator.cs | 14 +- .../Preprocessing/Colour/ColourEncoding.cs | 41 ++--- .../Colour/CoupledColourEncoding.cs | 75 ++------ .../Preprocessing/Colour/MonoEncoding.cs | 38 ++-- .../TaikoColourDifficultyPreprocessor.cs | 170 ++++++++++++++++++ .../Colour/TaikoDifficultyHitObjectColour.cs | 34 +--- .../Preprocessing/TaikoDifficultyHitObject.cs | 49 +---- .../TaikoDifficultyPreprocessor.cs | 38 ++++ .../Difficulty/Skills/Colour.cs | 70 ++++---- .../Difficulty/Skills/Peaks.cs | 33 ++-- .../Difficulty/TaikoDifficultyCalculator.cs | 2 +- 12 files changed, 326 insertions(+), 250 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 388858a337..2193184355 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -1,5 +1,4 @@ using System; -using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; @@ -67,16 +66,5 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators } } } - - public static double EvaluateDifficultyOf(DifficultyHitObject current) - { - TaikoDifficultyHitObject? taikoObject = current as TaikoDifficultyHitObject; - if (taikoObject != null && taikoObject.Colour != null) - { - return taikoObject.Colour.EvaluatedDifficulty; - } - - return 0; - } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 6889f0f5e9..e47e131350 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -16,8 +16,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// The interval between the current and previous note hit using the same key. private static double speedBonus(double interval) { + // Cap to 300bpm 1/4, 50ms note interval, 100ms key interval + // This is a temporary measure to prevent absurdly high speed mono convert maps being rated too high + // There is a plan to replace this with detecting mono that can be hit by special techniques, and this will + // be removed when that is implemented. + interval = Math.Max(interval, 100); + // return 15 / Math.Pow(interval, 0.6); - return Math.Pow(0.2, interval / 1000); + // return Math.Pow(0.2, interval / 1000); + return 30 / interval; } /// @@ -41,8 +48,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return 0.0; } - double objectStrain = 1; - objectStrain *= speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime); + double objectStrain = 0.5; // Add a base strain to all objects + // double objectStrain = 0; + objectStrain += speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime); return objectStrain; } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs index 18f9d4cf7d..052af7a2d1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs @@ -1,43 +1,38 @@ using System.Collections.Generic; -using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { + /// + /// Encodes a list of s. + /// s with the same are grouped together. + /// public class ColourEncoding { + /// + /// s that are grouped together within this . + /// public List Payload { get; private set; } = new List(); + /// + /// Determine if this is a repetition of another . This + /// is a strict comparison and is true if and only if the colour sequence is exactly the same. + /// This does not require the s to have the same amount of s. + /// public bool isRepetitionOf(ColourEncoding other) { return hasIdenticalMonoLength(other) && other.Payload.Count == Payload.Count && - other.Payload[0].EncodedData[0].HitType == Payload[0].EncodedData[0].HitType; + (other.Payload[0].EncodedData[0].BaseObject as Hit)?.Type == + (Payload[0].EncodedData[0].BaseObject as Hit)?.Type; } + /// + /// Determine if this has the same mono length of another . + /// public bool hasIdenticalMonoLength(ColourEncoding other) { return other.Payload[0].RunLength == Payload[0].RunLength; } - - public static List Encode(List data) - { - // Compute encoding lengths - List encoded = new List(); - ColourEncoding? lastEncoded = null; - for (int i = 0; i < data.Count; i++) - { - if (i == 0 || lastEncoded == null || data[i].RunLength != data[i - 1].RunLength) - { - lastEncoded = new ColourEncoding(); - lastEncoded.Payload.Add(data[i]); - encoded.Add(lastEncoded); - continue; - } - - lastEncoded.Payload.Add(data[i]); - } - - return encoded; - } } } \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs index 83fd75efa0..85a5f14a5d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs @@ -1,78 +1,35 @@ using System; using System.Collections.Generic; -using osu.Game.Rulesets.Difficulty.Preprocessing; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { + /// + /// Encodes a list of s, grouped together by back and forth repetition of the same + /// . Also stores the repetition interval between this and the previous . + /// public class CoupledColourEncoding { + /// + /// Maximum amount of s to look back to find a repetition. + /// private const int max_repetition_interval = 16; + /// + /// The s that are grouped together within this . + /// public List Payload = new List(); - public CoupledColourEncoding? Previous { get; private set; } = null; + /// + /// The previous . This is used to determine the repetition interval. + /// + public CoupledColourEncoding? Previous = null; /// - /// How many notes between the current and previous identical . - /// Negative number means that there is no repetition in range. + /// How many between the current and previous identical . /// If no repetition is found this will have a value of + 1. /// public int RepetitionInterval { get; private set; } = max_repetition_interval + 1; - public static List Encode(List data) - { - List firstPass = MonoEncoding.Encode(data); - List secondPass = ColourEncoding.Encode(firstPass); - List thirdPass = CoupledColourEncoding.Encode(secondPass); - - return thirdPass; - } - - public static List Encode(List data) - { - List encoded = new List(); - - CoupledColourEncoding? lastEncoded = null; - for (int i = 0; i < data.Count; i++) - { - lastEncoded = new CoupledColourEncoding() - { - Previous = lastEncoded - }; - - bool isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]); - if (!isCoupled) - { - lastEncoded.Payload.Add(data[i]); - } - else - { - while (isCoupled) - { - lastEncoded.Payload.Add(data[i]); - i++; - - isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]); - } - - // Skip over peeked data and add the rest to the payload - lastEncoded.Payload.Add(data[i]); - lastEncoded.Payload.Add(data[i + 1]); - i++; - } - - encoded.Add(lastEncoded); - } - - // Final pass to find repetition interval - for (int i = 0; i < encoded.Count; i++) - { - encoded[i].FindRepetitionInterval(); - } - - return encoded; - } - /// /// Returns true if other is considered a repetition of this encoding. This is true if other's first two payload /// identical mono lengths. @@ -90,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour } /// - /// Finds the closest previous that has the identical . + /// Finds the closest previous that has the identical . /// Interval is defined as the amount of chunks between the current and repeated encoding. /// public void FindRepetitionInterval() diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs index 92cdb0667b..98d66f0aa2 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs @@ -1,40 +1,22 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Objects; using System.Collections.Generic; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { + /// + /// Encode colour information for a sequence of s. Consecutive s + /// of the same are encoded within the same . + /// public class MonoEncoding { + /// + /// List of s that are encoded within this . + /// This is not declared as to avoid circular dependencies. + /// TODO: Review this, are circular dependencies within data-only classes are acceptable? + /// public List EncodedData { get; private set; } = new List(); public int RunLength => EncodedData.Count; - - public static List Encode(List data) - { - List encoded = new List(); - - MonoEncoding? lastEncoded = null; - for (int i = 0; i < data.Count; i++) - { - TaikoDifficultyHitObject taikoObject = (TaikoDifficultyHitObject)data[i]; - // This ignores all non-note objects, which may or may not be the desired behaviour - TaikoDifficultyHitObject previousObject = (TaikoDifficultyHitObject)taikoObject.PreviousNote(0); - - if ( - previousObject == null || - lastEncoded == null || - taikoObject.HitType != previousObject.HitType) - { - lastEncoded = new MonoEncoding(); - lastEncoded.EncodedData.Add(taikoObject); - encoded.Add(lastEncoded); - continue; - } - - lastEncoded.EncodedData.Add(taikoObject); - } - - return encoded; - } } } \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs new file mode 100644 index 0000000000..17337281e2 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -0,0 +1,170 @@ +using System.Collections.Generic; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; +using osu.Game.Rulesets.Taiko.Objects; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour +{ + /// + /// Utility class to perform various encodings. This is separated out from the encoding classes to prevent circular + /// dependencies. + /// + public class TaikoColourDifficultyPreprocessor + { + /// + /// Process and encode a list of s into a list of s, + /// assign the appropriate s to each , + /// and preevaluate colour difficulty of each . + /// + public static List ProcessAndAssign(List hitObjects) + { + List colours = new List(); + List encodings = Encode(hitObjects); + + // Assign colour to objects + encodings.ForEach(coupledEncoding => + { + coupledEncoding.Payload.ForEach(encoding => + { + encoding.Payload.ForEach(mono => + { + mono.EncodedData.ForEach(hitObject => + { + hitObject.Colour = new TaikoDifficultyHitObjectColour(coupledEncoding); + }); + }); + }); + + // Preevaluate and assign difficulty values + ColourEvaluator.PreEvaluateDifficulties(coupledEncoding); + }); + + return colours; + } + + /// + /// Encodes a list of s into a list of s. + /// + public static List EncodeMono(List data) + { + List encoded = new List(); + + MonoEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) + { + TaikoDifficultyHitObject taikoObject = (TaikoDifficultyHitObject)data[i]; + // This ignores all non-note objects, which may or may not be the desired behaviour + TaikoDifficultyHitObject previousObject = taikoObject.PreviousNote(0); + + // If the colour changed, or if this is the first object in the run, create a new mono encoding + if ( + previousObject == null || // First object in the list + (taikoObject.BaseObject as Hit)?.Type != (previousObject.BaseObject as Hit)?.Type) + { + lastEncoded = new MonoEncoding(); + lastEncoded.EncodedData.Add(taikoObject); + encoded.Add(lastEncoded); + continue; + } + + // If we're here, we're in the same encoding as the previous object, thus lastEncoded is not null. Add + // the current object to the encoded payload. + lastEncoded!.EncodedData.Add(taikoObject); + } + + return encoded; + } + + /// + /// Encodes a list of s into a list of s. + /// + public static List EncodeColour(List data) + { + List encoded = new List(); + ColourEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) + { + // Starts a new ColourEncoding if the previous MonoEncoding has a different mono length, or if this is + // the first MonoEncoding in the list. + if (lastEncoded == null || data[i].RunLength != data[i - 1].RunLength) + { + lastEncoded = new ColourEncoding(); + lastEncoded.Payload.Add(data[i]); + encoded.Add(lastEncoded); + continue; + } + + // If we're here, we're in the same encoding as the previous object. Add the current MonoEncoding to the + // encoded payload. + lastEncoded.Payload.Add(data[i]); + } + + return encoded; + } + + /// + /// Encodes a list of s into a list of s. + /// + public static List Encode(List data) + { + List firstPass = EncodeMono(data); + List secondPass = EncodeColour(firstPass); + List thirdPass = EncodeCoupledColour(secondPass); + + return thirdPass; + } + + /// + /// Encodes a list of s into a list of s. + /// + public static List EncodeCoupledColour(List data) + { + List encoded = new List(); + CoupledColourEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) + { + // Starts a new CoupledColourEncoding. ColourEncodings that should be grouped together will be handled + // later within this loop. + lastEncoded = new CoupledColourEncoding() + { + Previous = lastEncoded + }; + + // Determine if future ColourEncodings should be grouped. + bool isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]); + if (!isCoupled) + { + // If not, add the current ColourEncoding to the encoded payload and continue. + lastEncoded.Payload.Add(data[i]); + } + else + { + // If so, add the current ColourEncoding to the encoded payload and start repeatedly checking if + // subsequent ColourEncodings should be grouped by increasing i and doing the appropriate isCoupled + // check; + while (isCoupled) + { + lastEncoded.Payload.Add(data[i]); + i++; + isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]); + } + + // Skip over peeked data and add the rest to the payload + lastEncoded.Payload.Add(data[i]); + lastEncoded.Payload.Add(data[i + 1]); + i++; + } + + encoded.Add(lastEncoded); + } + + // Final pass to find repetition intervals + for (int i = 0; i < encoded.Count; i++) + { + encoded[i].FindRepetitionInterval(); + } + + return encoded; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs index 7dfd0fdbd4..9c2e0cc206 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs @@ -1,8 +1,3 @@ -using System; -using System.Collections.Generic; -using osu.Game.Rulesets.Difficulty.Preprocessing; -using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; - namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { /// @@ -15,36 +10,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour public double EvaluatedDifficulty = 0; - private TaikoDifficultyHitObjectColour(CoupledColourEncoding encoding) + public TaikoDifficultyHitObjectColour(CoupledColourEncoding encoding) { Encoding = encoding; } - - // TODO: Might wanna move this somewhere else as it is introducing circular references - public static List EncodeAndAssign(List hitObjects) - { - List colours = new List(); - List encodings = CoupledColourEncoding.Encode(hitObjects); - - // Assign colour to objects - encodings.ForEach(coupledEncoding => - { - coupledEncoding.Payload.ForEach(encoding => - { - encoding.Payload.ForEach(mono => - { - mono.EncodedData.ForEach(hitObject => - { - hitObject.Colour = new TaikoDifficultyHitObjectColour(coupledEncoding); - }); - }); - }); - - // Preevaluate and assign difficulty values - ColourEvaluator.PreEvaluateDifficulties(coupledEncoding); - }); - - return colours; - } } } \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 919770afc8..e490d310fd 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -4,12 +4,10 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; -using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { @@ -35,40 +33,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public TaikoDifficultyHitObjectColour? Colour; - /// - /// The hit type of this hit object. - /// - public readonly HitType? HitType; - - /// - /// Creates a list of s from a s. - /// TODO: Review this - this is moved here from TaikoDifficultyCalculator so that TaikoDifficultyCalculator can - /// have less knowledge of implementation details (i.e. creating all the different hitObject lists, and - /// calling FindRepetitionInterval for the final object). The down side of this is - /// TaikoDifficultyHitObejct.CreateDifficultyHitObjects is now pretty much a proxy for this. - /// - /// The beatmap from which the list of is created. - /// The rate at which the gameplay clock is run at. - public static List Create(IBeatmap beatmap, double clockRate) - { - List difficultyHitObjects = new List(); - List centreObjects = new List(); - List rimObjects = new List(); - List noteObjects = new List(); - - for (int i = 2; i < beatmap.HitObjects.Count; i++) - { - difficultyHitObjects.Add( - new TaikoDifficultyHitObject( - beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObjects, - centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count) - ); - } - var encoded = TaikoDifficultyHitObjectColour.EncodeAndAssign(difficultyHitObjects); - - return difficultyHitObjects; - } - /// /// Creates a new difficulty hit object. /// @@ -81,10 +45,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// The list of rim (kat) s in the current beatmap. /// The list of s that is a hit (i.e. not a slider or spinner) in the current beatmap. /// The position of this in the list. - /// - /// TODO: This argument list is getting long, we might want to refactor this into a static method that create - /// all s from a . - private TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, + public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, List objects, List centreHitObjects, List rimHitObjects, @@ -95,15 +56,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing this.noteObjects = noteObjects; Rhythm = getClosestRhythm(lastObject, lastLastObject, clockRate); - HitType = currentHit?.Type; + HitType? hitType = currentHit?.Type; - if (HitType == Objects.HitType.Centre) + if (hitType == Objects.HitType.Centre) { MonoIndex = centreHitObjects.Count; centreHitObjects.Add(this); monoDifficultyHitObjects = centreHitObjects; } - else if (HitType == Objects.HitType.Rim) + else if (hitType == Objects.HitType.Rim) { MonoIndex = rimHitObjects.Count; rimHitObjects.Add(this); @@ -111,7 +72,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing } // Need to be done after HitType is set. - if (HitType == null) return; + if (hitType == null) return; NoteIndex = noteObjects.Count; noteObjects.Add(this); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs new file mode 100644 index 0000000000..e37690d7e8 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing +{ + public class TaikoDifficultyPreprocessor + { + /// + /// Creates a list of s from a s. + /// This is placed here in a separate class to avoid having to know + /// too much implementation details of the preprocessing, and avoid + /// having circular dependencies with various preprocessing and evaluator classes. + /// + /// The beatmap from which the list of is created. + /// The rate at which the gameplay clock is run at. + public static List CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) + { + List difficultyHitObjects = new List(); + List centreObjects = new List(); + List rimObjects = new List(); + List noteObjects = new List(); + + for (int i = 2; i < beatmap.HitObjects.Count; i++) + { + difficultyHitObjects.Add( + new TaikoDifficultyHitObject( + beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObjects, + centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count) + ); + } + var encoded = TaikoColourDifficultyPreprocessor.ProcessAndAssign(difficultyHitObjects); + + return difficultyHitObjects; + } + } +} \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index d8f445f37c..e2147fdd85 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { @@ -15,16 +17,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills public class Colour : StrainDecaySkill { protected override double SkillMultiplier => 0.12; - protected override double StrainDecayBase => 0.8; - /// - /// Applies a speed bonus dependent on the time since the last hit. - /// - /// The interval between the current and previous note hit using the same key. - private static double speedBonus(double interval) - { - return Math.Pow(0.4, interval / 1000); - } + // This is set to decay slower than other skills, due to the fact that only the first note of each Mono/Colour/Coupled + // encoding having any difficulty values, and we want to allow colour difficulty to be able to build up even on + // slower maps. + protected override double StrainDecayBase => 0.8; public Colour(Mod[] mods) : base(mods) @@ -33,38 +30,37 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double StrainValueOf(DifficultyHitObject current) { - double difficulty = ColourEvaluator.EvaluateDifficultyOf(current); + double difficulty = ((TaikoDifficultyHitObject)current).Colour?.EvaluatedDifficulty ?? 0; return difficulty; } // TODO: Remove before pr - // public static String GetDebugHeaderLabels() - // { - // return "StartTime,Raw,Decayed,CoupledRunLength,RepetitionInterval,EncodingRunLength,Payload(MonoRunLength|MonoCount)"; - // } + public static String GetDebugHeaderLabels() + { + return "StartTime,Raw,Decayed,CoupledRunLength,RepetitionInterval,EncodingRunLength,Payload(MonoRunLength|MonoCount)"; + } - // // TODO: Remove before pr - // public string GetDebugString(DifficultyHitObject current) - // { - // double difficulty = ColourEvaluator.EvaluateDifficultyOf(current); - // difficulty *= speedBonus(current.DeltaTime); - // TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current; - // TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour; - // if (taikoCurrent != null && colour != null) - // { - // List payload = colour.Encoding.Payload; - // string payloadDisplay = ""; - // for (int i = 0; i < payload.Count; ++i) - // { - // payloadDisplay += $"({payload[i].Payload[0].RunLength}|{payload[i].Payload.Count})"; - // } + // TODO: Remove before pr + public string GetDebugString(DifficultyHitObject current) + { + double difficulty = ((TaikoDifficultyHitObject)current).Colour?.EvaluatedDifficulty ?? 0; + TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current; + TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour; + if (taikoCurrent != null && colour != null) + { + List payload = colour.Encoding.Payload; + string payloadDisplay = ""; + for (int i = 0; i < payload.Count; ++i) + { + payloadDisplay += $"({payload[i].Payload[0].RunLength}|{payload[i].Payload.Count})"; + } - // return $"{current.StartTime},{difficulty},{CurrentStrain},{colour.Encoding.Payload[0].Payload.Count},{colour.Encoding.RepetitionInterval},{colour.Encoding.Payload.Count},{payloadDisplay}"; - // } - // else - // { - // return $"{current.StartTime},{difficulty},{CurrentStrain},0,0,0,0,0"; - // } - // } + return $"{current.StartTime},{difficulty},{CurrentStrain},{colour.Encoding.Payload[0].Payload.Count},{colour.Encoding.RepetitionInterval},{colour.Encoding.Payload.Count},{payloadDisplay}"; + } + else + { + return $"{current.StartTime},{difficulty},{CurrentStrain},0,0,0,0,0"; + } + } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index 09d9720a4f..18200fe1bb 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -26,8 +26,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills public double StaminaDifficultyValue => stamina.DifficultyValue() * stamina_skill_multiplier; // TODO: remove before pr - // private StreamWriter? colourDebugOutput; - // bool debugColour = false; + private StreamWriter? colourDebugOutput; + bool debugColour = false; + private StreamWriter? strainPeakDebugOutput; + bool debugStrain = false; public Peaks(Mod[] mods, IBeatmap beatmap) : base(mods) @@ -36,14 +38,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills colour = new Colour(mods); stamina = new Stamina(mods); - // if (debugColour) - // { - // String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv"; - // filename = filename.Replace('/', '_'); - // colourDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/colour-debug/{filename}")); - // colourDebugOutput.WriteLine(Colour.GetDebugHeaderLabels()); - // } - + if (debugColour) + { + String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv"; + filename = filename.Replace('/', '_'); + colourDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/colour-debug/{filename}")); + colourDebugOutput.WriteLine(Colour.GetDebugHeaderLabels()); + } + if (debugStrain) + { + String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv"; + filename = filename.Replace('/', '_'); + strainPeakDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/strain-debug/{filename}")); + strainPeakDebugOutput.WriteLine("Colour,Stamina,Rhythm,Combined"); + } } /// @@ -90,6 +98,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills double peak = norm(1.5, colourPeak, staminaPeak); peak = norm(2, peak, rhythmPeak); + if (debugStrain && strainPeakDebugOutput != null) + { + strainPeakDebugOutput.WriteLine($"{colourPeak},{staminaPeak},{rhythmPeak},{peak}"); + } + // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). // These sections will not contribute to the difficulty. if (peak > 0) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 2982861e0b..195ec92835 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { - return TaikoDifficultyHitObject.Create(beatmap, clockRate); + return TaikoDifficultyPreprocessor.CreateDifficultyHitObjects(beatmap, clockRate); } protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) From 45c055bfa1f4f5f569fc4c1d24582ee322f0076a Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 14 Jul 2022 17:25:21 +0800 Subject: [PATCH 0095/2686] Move rhythm preprocessing to its own folder --- .../{ => Rhythm}/TaikoDifficultyHitObjectRhythm.cs | 2 +- .../Difficulty/Preprocessing/TaikoDifficultyHitObject.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) rename osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/{ => Rhythm}/TaikoDifficultyHitObjectRhythm.cs (95%) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectRhythm.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.cs similarity index 95% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectRhythm.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.cs index 526d20e7d7..bf136b9fa6 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectRhythm.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.cs @@ -3,7 +3,7 @@ #nullable disable -namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm { /// /// Represents a rhythm change in a taiko map. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index e490d310fd..1b5de64ed3 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -8,6 +8,7 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { From 7e3f62a5a54000d74f0ad4b1ec5f69f74ac96cb5 Mon Sep 17 00:00:00 2001 From: Jay L Date: Fri, 15 Jul 2022 21:07:01 +1000 Subject: [PATCH 0096/2686] Codequality parse --- .../Difficulty/Evaluators/ColourEvaluator.cs | 7 +++- .../Difficulty/Evaluators/StaminaEvaluator.cs | 7 +--- .../Colour/{ => Data}/ColourEncoding.cs | 19 +++++---- .../{ => Data}/CoupledColourEncoding.cs | 21 ++++++---- .../Colour/{ => Data}/MonoEncoding.cs | 7 +++- .../TaikoColourDifficultyPreprocessor.cs | 30 +++++++++----- .../Colour/TaikoDifficultyHitObjectColour.cs | 9 +++- .../Rhythm/TaikoDifficultyHitObjectRhythm.cs | 2 - .../Preprocessing/TaikoDifficultyHitObject.cs | 20 ++++----- .../TaikoDifficultyPreprocessor.cs | 8 +++- .../Difficulty/Skills/Colour.cs | 34 +-------------- .../Difficulty/Skills/Peaks.cs | 41 +++---------------- .../Difficulty/TaikoDifficultyCalculator.cs | 2 +- 13 files changed, 89 insertions(+), 118 deletions(-) rename osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/{ => Data}/ColourEncoding.cs (70%) rename osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/{ => Data}/CoupledColourEncoding.cs (83%) rename osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/{ => Data}/MonoEncoding.cs (86%) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 2193184355..1d857a1dbb 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -1,12 +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 System; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data; namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators { public class ColourEvaluator { - // TODO - Share this sigmoid private static double sigmoid(double val, double center, double width) { return Math.Tanh(Math.E * -(val - center) / width); @@ -54,11 +57,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators { double coupledEncodingDifficulty = 2 * EvaluateDifficultyOf(encoding); encoding.Payload[0].Payload[0].EncodedData[0].Colour!.EvaluatedDifficulty += coupledEncodingDifficulty; + for (int i = 0; i < encoding.Payload.Count; i++) { ColourEncoding colourEncoding = encoding.Payload[i]; double colourEncodingDifficulty = EvaluateDifficultyOf(colourEncoding, i) * coupledEncodingDifficulty; colourEncoding.Payload[0].EncodedData[0].Colour!.EvaluatedDifficulty += colourEncodingDifficulty; + for (int j = 0; j < colourEncoding.Payload.Count; j++) { MonoEncoding monoEncoding = colourEncoding.Payload[j]; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index e47e131350..30918681f6 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -22,8 +22,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators // be removed when that is implemented. interval = Math.Max(interval, 100); - // return 15 / Math.Pow(interval, 0.6); - // return Math.Pow(0.2, interval / 1000); return 30 / interval; } @@ -33,14 +31,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// public static double EvaluateDifficultyOf(DifficultyHitObject current) { - if (!(current.BaseObject is Hit)) + if (current.BaseObject is not Hit) { return 0.0; } // Find the previous hit object hit by the current key, which is two notes of the same colour prior. TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; - TaikoDifficultyHitObject keyPrevious = taikoCurrent.PreviousMono(1); + TaikoDifficultyHitObject? keyPrevious = taikoCurrent.PreviousMono(1); if (keyPrevious == null) { @@ -49,7 +47,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators } double objectStrain = 0.5; // Add a base strain to all objects - // double objectStrain = 0; objectStrain += speedBonus(taikoCurrent.StartTime - keyPrevious.StartTime); return objectStrain; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs similarity index 70% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs index 052af7a2d1..cddf8816f5 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.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.Collections.Generic; using osu.Game.Rulesets.Taiko.Objects; -namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { /// /// Encodes a list of s. @@ -19,20 +22,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// is a strict comparison and is true if and only if the colour sequence is exactly the same. /// This does not require the s to have the same amount of s. /// - public bool isRepetitionOf(ColourEncoding other) + public bool IsRepetitionOf(ColourEncoding other) { - return hasIdenticalMonoLength(other) && - other.Payload.Count == Payload.Count && - (other.Payload[0].EncodedData[0].BaseObject as Hit)?.Type == - (Payload[0].EncodedData[0].BaseObject as Hit)?.Type; + return HasIdenticalMonoLength(other) && + other.Payload.Count == Payload.Count && + (other.Payload[0].EncodedData[0].BaseObject as Hit)?.Type == + (Payload[0].EncodedData[0].BaseObject as Hit)?.Type; } /// /// Determine if this has the same mono length of another . /// - public bool hasIdenticalMonoLength(ColourEncoding other) + public bool HasIdenticalMonoLength(ColourEncoding other) { return other.Payload[0].RunLength == Payload[0].RunLength; } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs similarity index 83% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs index 85a5f14a5d..188d1b686b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/CoupledColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs @@ -1,10 +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 System.Collections.Generic; -namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { /// - /// Encodes a list of s, grouped together by back and forth repetition of the same + /// Encodes a list of s, grouped together by back and forth repetition of the same /// . Also stores the repetition interval between this and the previous . /// public class CoupledColourEncoding @@ -34,13 +37,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// Returns true if other is considered a repetition of this encoding. This is true if other's first two payload /// identical mono lengths. /// - public bool isRepetitionOf(CoupledColourEncoding other) + private bool isRepetitionOf(CoupledColourEncoding other) { - if (this.Payload.Count != other.Payload.Count) return false; + if (Payload.Count != other.Payload.Count) return false; - for (int i = 0; i < Math.Min(this.Payload.Count, 2); i++) + for (int i = 0; i < Math.Min(Payload.Count, 2); i++) { - if (!this.Payload[i].hasIdenticalMonoLength(other.Payload[i])) return false; + if (!Payload[i].HasIdenticalMonoLength(other.Payload[i])) return false; } return true; @@ -60,9 +63,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour CoupledColourEncoding? other = Previous.Previous; int interval = 2; + while (interval < max_repetition_interval) { - if (this.isRepetitionOf(other)) + if (isRepetitionOf(other)) { RepetitionInterval = Math.Min(interval, max_repetition_interval); return; @@ -70,10 +74,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour other = other.Previous; if (other == null) break; + ++interval; } RepetitionInterval = max_repetition_interval + 1; } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs similarity index 86% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs index 98d66f0aa2..9e60946bd1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/MonoEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs @@ -1,8 +1,11 @@ +// 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.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Objects; using System.Collections.Generic; -namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour +namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { /// /// Encode colour information for a sequence of s. Consecutive s @@ -19,4 +22,4 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour public int RunLength => EncodedData.Count; } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 17337281e2..a699422d2c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -1,6 +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.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data; using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour @@ -50,16 +54,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour List encoded = new List(); MonoEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) { TaikoDifficultyHitObject taikoObject = (TaikoDifficultyHitObject)data[i]; // This ignores all non-note objects, which may or may not be the desired behaviour - TaikoDifficultyHitObject previousObject = taikoObject.PreviousNote(0); + TaikoDifficultyHitObject? previousObject = taikoObject.PreviousNote(0); // If the colour changed, or if this is the first object in the run, create a new mono encoding - if ( + if + ( previousObject == null || // First object in the list - (taikoObject.BaseObject as Hit)?.Type != (previousObject.BaseObject as Hit)?.Type) + (taikoObject.BaseObject as Hit)?.Type != (previousObject.BaseObject as Hit)?.Type + ) + { lastEncoded = new MonoEncoding(); lastEncoded.EncodedData.Add(taikoObject); @@ -82,6 +90,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { List encoded = new List(); ColourEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) { // Starts a new ColourEncoding if the previous MonoEncoding has a different mono length, or if this is @@ -121,17 +130,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { List encoded = new List(); CoupledColourEncoding? lastEncoded = null; + for (int i = 0; i < data.Count; i++) { // Starts a new CoupledColourEncoding. ColourEncodings that should be grouped together will be handled // later within this loop. - lastEncoded = new CoupledColourEncoding() + lastEncoded = new CoupledColourEncoding { Previous = lastEncoded }; // Determine if future ColourEncodings should be grouped. - bool isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]); + bool isCoupled = i < data.Count - 2 && data[i].IsRepetitionOf(data[i + 2]); + if (!isCoupled) { // If not, add the current ColourEncoding to the encoded payload and continue. @@ -139,14 +150,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour } else { - // If so, add the current ColourEncoding to the encoded payload and start repeatedly checking if - // subsequent ColourEncodings should be grouped by increasing i and doing the appropriate isCoupled - // check; + // If so, add the current ColourEncoding to the encoded payload and start repeatedly checking if the + // subsequent ColourEncodings should be grouped by increasing i and doing the appropriate isCoupled check. while (isCoupled) { lastEncoded.Payload.Add(data[i]); i++; - isCoupled = i < data.Count - 2 && data[i].isRepetitionOf(data[i + 2]); + isCoupled = i < data.Count - 2 && data[i].IsRepetitionOf(data[i + 2]); } // Skip over peeked data and add the rest to the payload @@ -167,4 +177,4 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour return encoded; } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs index 9c2e0cc206..9fc7a1dacb 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs @@ -1,3 +1,8 @@ +// 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.Taiko.Difficulty.Preprocessing.Colour.Data; + namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { /// @@ -6,7 +11,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// public class TaikoDifficultyHitObjectColour { - public CoupledColourEncoding Encoding { get; private set; } + public CoupledColourEncoding Encoding { get; } public double EvaluatedDifficulty = 0; @@ -15,4 +20,4 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour Encoding = encoding; } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.cs index bf136b9fa6..a273d7e2ea 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/TaikoDifficultyHitObjectRhythm.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. -#nullable disable - namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm { /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 1b5de64ed3..a0d2fc7797 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -47,10 +47,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// The list of s that is a hit (i.e. not a slider or spinner) in the current beatmap. /// The position of this in the list. public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, - List objects, - List centreHitObjects, - List rimHitObjects, - List noteObjects, int index) + List objects, + List centreHitObjects, + List rimHitObjects, + List noteObjects, int index) : base(hitObject, lastObject, clockRate, objects, index) { var currentHit = hitObject as Hit; @@ -59,13 +59,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing Rhythm = getClosestRhythm(lastObject, lastLastObject, clockRate); HitType? hitType = currentHit?.Type; - if (hitType == Objects.HitType.Centre) + if (hitType == HitType.Centre) { MonoIndex = centreHitObjects.Count; centreHitObjects.Add(this); monoDifficultyHitObjects = centreHitObjects; } - else if (hitType == Objects.HitType.Rim) + else if (hitType == HitType.Rim) { MonoIndex = rimHitObjects.Count; rimHitObjects.Add(this); @@ -116,12 +116,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing return common_rhythms.OrderBy(x => Math.Abs(x.Ratio - ratio)).First(); } - public TaikoDifficultyHitObject PreviousMono(int backwardsIndex) => monoDifficultyHitObjects.ElementAtOrDefault(MonoIndex - (backwardsIndex + 1)); + public TaikoDifficultyHitObject? PreviousMono(int backwardsIndex) => monoDifficultyHitObjects?.ElementAtOrDefault(MonoIndex - (backwardsIndex + 1)); - public TaikoDifficultyHitObject NextMono(int forwardsIndex) => monoDifficultyHitObjects.ElementAtOrDefault(MonoIndex + (forwardsIndex + 1)); + public TaikoDifficultyHitObject? NextMono(int forwardsIndex) => monoDifficultyHitObjects?.ElementAtOrDefault(MonoIndex + (forwardsIndex + 1)); - public TaikoDifficultyHitObject PreviousNote(int backwardsIndex) => noteObjects.ElementAtOrDefault(NoteIndex - (backwardsIndex + 1)); + public TaikoDifficultyHitObject? PreviousNote(int backwardsIndex) => noteObjects.ElementAtOrDefault(NoteIndex - (backwardsIndex + 1)); - public TaikoDifficultyHitObject NextNote(int forwardsIndex) => noteObjects.ElementAtOrDefault(NoteIndex + (forwardsIndex + 1)); + public TaikoDifficultyHitObject? NextNote(int forwardsIndex) => noteObjects.ElementAtOrDefault(NoteIndex + (forwardsIndex + 1)); } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs index e37690d7e8..fa8e6a8a26 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs @@ -1,3 +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 System.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Beatmaps; @@ -30,9 +33,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count) ); } - var encoded = TaikoColourDifficultyPreprocessor.ProcessAndAssign(difficultyHitObjects); + + TaikoColourDifficultyPreprocessor.ProcessAndAssign(difficultyHitObjects); return difficultyHitObjects; } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index e2147fdd85..8f8f62d214 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -1,13 +1,12 @@ // 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; +#nullable disable + using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; -using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { @@ -33,34 +32,5 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills double difficulty = ((TaikoDifficultyHitObject)current).Colour?.EvaluatedDifficulty ?? 0; return difficulty; } - - // TODO: Remove before pr - public static String GetDebugHeaderLabels() - { - return "StartTime,Raw,Decayed,CoupledRunLength,RepetitionInterval,EncodingRunLength,Payload(MonoRunLength|MonoCount)"; - } - - // TODO: Remove before pr - public string GetDebugString(DifficultyHitObject current) - { - double difficulty = ((TaikoDifficultyHitObject)current).Colour?.EvaluatedDifficulty ?? 0; - TaikoDifficultyHitObject? taikoCurrent = (TaikoDifficultyHitObject)current; - TaikoDifficultyHitObjectColour? colour = taikoCurrent?.Colour; - if (taikoCurrent != null && colour != null) - { - List payload = colour.Encoding.Payload; - string payloadDisplay = ""; - for (int i = 0; i < payload.Count; ++i) - { - payloadDisplay += $"({payload[i].Payload[0].RunLength}|{payload[i].Payload.Count})"; - } - - return $"{current.StartTime},{difficulty},{CurrentStrain},{colour.Encoding.Payload[0].Payload.Count},{colour.Encoding.RepetitionInterval},{colour.Encoding.Payload.Count},{payloadDisplay}"; - } - else - { - return $"{current.StartTime},{difficulty},{CurrentStrain},0,0,0,0,0"; - } - } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index 18200fe1bb..3e3bc543e1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs @@ -1,11 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + using System; -using System.IO; using System.Collections.Generic; using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; -using osu.Game.Beatmaps; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { @@ -25,33 +28,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills public double RhythmDifficultyValue => rhythm.DifficultyValue() * rhythm_skill_multiplier; public double StaminaDifficultyValue => stamina.DifficultyValue() * stamina_skill_multiplier; - // TODO: remove before pr - private StreamWriter? colourDebugOutput; - bool debugColour = false; - private StreamWriter? strainPeakDebugOutput; - bool debugStrain = false; - - public Peaks(Mod[] mods, IBeatmap beatmap) + public Peaks(Mod[] mods) : base(mods) { rhythm = new Rhythm(mods); colour = new Colour(mods); stamina = new Stamina(mods); - - if (debugColour) - { - String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv"; - filename = filename.Replace('/', '_'); - colourDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/colour-debug/{filename}")); - colourDebugOutput.WriteLine(Colour.GetDebugHeaderLabels()); - } - if (debugStrain) - { - String filename = $"{beatmap.BeatmapInfo.OnlineID} - {beatmap.BeatmapInfo.Metadata.Title}[{beatmap.BeatmapInfo.DifficultyName}].csv"; - filename = filename.Replace('/', '_'); - strainPeakDebugOutput = new StreamWriter(File.OpenWrite($"/run/mount/secondary/workspace/osu/output/strain-debug/{filename}")); - strainPeakDebugOutput.WriteLine("Colour,Stamina,Rhythm,Combined"); - } } /// @@ -66,12 +48,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills rhythm.Process(current); colour.Process(current); stamina.Process(current); - - // if (debugColour && colourDebugOutput != null) - // { - // colourDebugOutput.WriteLine(colour.GetDebugString(current)); - // colourDebugOutput.Flush(); - // } } /// @@ -98,11 +74,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills double peak = norm(1.5, colourPeak, staminaPeak); peak = norm(2, peak, rhythmPeak); - if (debugStrain && strainPeakDebugOutput != null) - { - strainPeakDebugOutput.WriteLine($"{colourPeak},{staminaPeak},{rhythmPeak},{peak}"); - } - // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). // These sections will not contribute to the difficulty. if (peak > 0) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 195ec92835..22976d6a0b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { return new Skill[] { - new Peaks(mods, beatmap) + new Peaks(mods) }; } From c8b7902a630f5a2b532ca411d6146f3a37ae640c Mon Sep 17 00:00:00 2001 From: Jay L Date: Fri, 15 Jul 2022 22:10:20 +1000 Subject: [PATCH 0097/2686] Reintroduce Convert Nerf, Rescale Multiplier --- .../Difficulty/TaikoDifficultyCalculator.cs | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 22976d6a0b..a70d3d9a38 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { public class TaikoDifficultyCalculator : DifficultyCalculator { - private const double difficulty_multiplier = 1.9; + private const double difficulty_multiplier = 1.35; public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) @@ -57,12 +57,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty var combined = (Peaks)skills[0]; - double colourRating = Math.Sqrt(combined.ColourDifficultyValue * difficulty_multiplier); - double rhythmRating = Math.Sqrt(combined.RhythmDifficultyValue * difficulty_multiplier); - double staminaRating = Math.Sqrt(combined.StaminaDifficultyValue * difficulty_multiplier); + double colourRating = combined.ColourDifficultyValue * difficulty_multiplier; + double rhythmRating = combined.RhythmDifficultyValue * difficulty_multiplier; + double staminaRating = combined.StaminaDifficultyValue * difficulty_multiplier; - double combinedRating = combined.DifficultyValue(); - double starRating = rescale(combinedRating * difficulty_multiplier); + double combinedRating = combined.DifficultyValue() * difficulty_multiplier; + double starRating = rescale(combinedRating * 1.4); + + // TODO: This is temporary measure as we don't detect abuse-type playstyles of converts within the current system. + if (beatmap.BeatmapInfo.Ruleset.OnlineID == 0) + { + starRating *= 0.80; + } HitWindows hitWindows = new TaikoHitWindows(); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); @@ -81,7 +87,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty } /// - /// Applies a final re-scaling of the star rating to bring maps with recorded full combos below 9.5 stars. + /// Applies a final re-scaling of the star rating. /// /// The raw star rating value before re-scaling. private double rescale(double sr) From 8a17b509d91d6924ec79181c4b4c99f264d0694c Mon Sep 17 00:00:00 2001 From: Jay L Date: Sat, 16 Jul 2022 21:20:25 +1000 Subject: [PATCH 0098/2686] Increase SpeedBonus Cap to 600BPM --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 30918681f6..5906f39c33 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -16,13 +16,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// The interval between the current and previous note hit using the same key. private static double speedBonus(double interval) { - // Cap to 300bpm 1/4, 50ms note interval, 100ms key interval - // This is a temporary measure to prevent absurdly high speed mono convert maps being rated too high - // There is a plan to replace this with detecting mono that can be hit by special techniques, and this will - // be removed when that is implemented. + // Cap to 600bpm 1/4, 25ms note interval, 50ms key interval + // This is a measure to prevent absurdly high speed maps giving infinity/negative values. interval = Math.Max(interval, 100); - return 30 / interval; + return 60 / interval; } /// From 8beb5568b82108664ff3f97b9bee0808477f5bd8 Mon Sep 17 00:00:00 2001 From: vun Date: Sat, 16 Jul 2022 19:45:35 +0800 Subject: [PATCH 0099/2686] Fix speed bonus --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 5906f39c33..35f1d386a4 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -17,10 +17,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators private static double speedBonus(double interval) { // Cap to 600bpm 1/4, 25ms note interval, 50ms key interval - // This is a measure to prevent absurdly high speed maps giving infinity/negative values. - interval = Math.Max(interval, 100); + // This is temporary measure to prevent mono abuses. Once that is properly addressed, interval will be + // capped at a very small value to avoid infinite/negative speed bonuses. + interval = Math.Max(interval, 50); - return 60 / interval; + return 30 / interval; } /// From a66fd87274ee4576cb3744f9040980d85a3600ba Mon Sep 17 00:00:00 2001 From: vun Date: Sat, 16 Jul 2022 19:48:29 +0800 Subject: [PATCH 0100/2686] Fix speed bonus comment --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 35f1d386a4..f9f27de9c4 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators private static double speedBonus(double interval) { // Cap to 600bpm 1/4, 25ms note interval, 50ms key interval - // This is temporary measure to prevent mono abuses. Once that is properly addressed, interval will be + // This a is temporary measure to prevent mono abuses. Once that is properly addressed, interval will be // capped at a very small value to avoid infinite/negative speed bonuses. interval = Math.Max(interval, 50); From e82e11ead59a298e6a7e507d271b8eec8b9c0535 Mon Sep 17 00:00:00 2001 From: Jay L Date: Sun, 17 Jul 2022 14:56:07 +1000 Subject: [PATCH 0101/2686] Fix SpeedBonus xml --- .idea/.idea.osu/.idea/discord.xml | 7 +++++++ .../Difficulty/Evaluators/StaminaEvaluator.cs | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .idea/.idea.osu/.idea/discord.xml diff --git a/.idea/.idea.osu/.idea/discord.xml b/.idea/.idea.osu/.idea/discord.xml new file mode 100644 index 0000000000..30bab2abb1 --- /dev/null +++ b/.idea/.idea.osu/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index f9f27de9c4..954c1661dd 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -17,8 +17,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators private static double speedBonus(double interval) { // Cap to 600bpm 1/4, 25ms note interval, 50ms key interval - // This a is temporary measure to prevent mono abuses. Once that is properly addressed, interval will be - // capped at a very small value to avoid infinite/negative speed bonuses. + // Interval will be capped at a very small value to avoid infinite/negative speed bonuses. + // TODO - This is a temporary measure as we need to implement methods of detecting playstyle-abuse of SpeedBonus. interval = Math.Max(interval, 50); return 30 / interval; From 77fa5674532cdd9c21e2e7697e86eeca8f14356a Mon Sep 17 00:00:00 2001 From: Jay L Date: Sun, 17 Jul 2022 14:56:25 +1000 Subject: [PATCH 0102/2686] Adjust tests --- .../TaikoDifficultyCalculatorTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs index 579b461624..425f72cadc 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs @@ -16,13 +16,13 @@ namespace osu.Game.Rulesets.Taiko.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; - [TestCase(1.9971301024093662d, 200, "diffcalc-test")] - [TestCase(1.9971301024093662d, 200, "diffcalc-test-strong")] + [TestCase(3.1098944660126882d, 200, "diffcalc-test")] + [TestCase(3.1098944660126882d, 200, "diffcalc-test-strong")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(3.1645810961313674d, 200, "diffcalc-test")] - [TestCase(3.1645810961313674d, 200, "diffcalc-test-strong")] + [TestCase(4.0974106752474251d, 200, "diffcalc-test")] + [TestCase(4.0974106752474251d, 200, "diffcalc-test-strong")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime()); From a950deb7db021d3c499b3231dd0f270ab94470c4 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Sun, 17 Jul 2022 16:27:55 +1000 Subject: [PATCH 0103/2686] Re-implement slider changes to FlashlightEvaluator --- .../Evaluators/FlashlightEvaluator.cs | 22 +++++++++++++++++++ .../Difficulty/Skills/Flashlight.cs | 1 - 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 3b0826394c..e60695f94f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Diagnostics; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; @@ -15,6 +16,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators private const double max_opacity_bonus = 0.4; private const double hidden_bonus = 0.2; + private const double min_velocity = 0.5; + private const double slider_multiplier = 1.3; + /// /// Evaluates the difficulty of memorising and hitting an object, based on: /// @@ -73,6 +77,24 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (hidden) result *= 1.0 + hidden_bonus; + double sliderBonus = 0.0; + + if (osuCurrent.BaseObject is Slider) + { + Debug.Assert(osuCurrent.TravelTime > 0); + + // Invert the scaling factor to determine the true travel distance independent of circle size. + double pixelTravelDistance = osuCurrent.TravelDistance / scalingFactor; + + // Reward sliders based on velocity. + sliderBonus = Math.Pow(Math.Max(0.0, pixelTravelDistance / osuCurrent.TravelTime - min_velocity), 0.5); + + // Longer sliders require more memorisation. + sliderBonus *= pixelTravelDistance; + } + + result += sliderBonus * slider_multiplier; + return result; } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 0c84ace1c7..84ef109598 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -4,7 +4,6 @@ #nullable disable using System; -using System.Diagnostics; using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; From dae698638ce59aae208cad6d67076d602ce71f87 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Sun, 17 Jul 2022 16:56:05 +1000 Subject: [PATCH 0104/2686] Add repeat bonus to Flashlight, move repeat multiplier to AimEvaluator --- .../Difficulty/Evaluators/AimEvaluator.cs | 8 +++++++- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 7 +++++++ .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 -- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 0694746cbf..911b7d10fd 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Diagnostics; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; @@ -120,10 +121,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2); } - if (osuLastObj.TravelTime != 0) + if (osuLastObj.BaseObject is Slider) { + Debug.Assert(osuLastObj.TravelTime > 0); + // Reward sliders based on velocity. sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime; + + Slider osuSlider = (Slider)(osuLastObj.BaseObject); + sliderBonus *= (float)Math.Pow(1 + osuSlider.RepeatCount / 2.5, 1.0 / 2.5); // Bonus for repeat sliders until a better per nested object strain system can be achieved. } // Add in acute angle bonus or wide angle bonus + velocity change bonus, whichever is larger. diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index e60695f94f..444c2db884 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -18,6 +18,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators private const double min_velocity = 0.5; private const double slider_multiplier = 1.3; + private const double repeat_bonus = 3.0; /// /// Evaluates the difficulty of memorising and hitting an object, based on: @@ -83,6 +84,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { Debug.Assert(osuCurrent.TravelTime > 0); + Slider osuSlider = (Slider)(osuCurrent.BaseObject); + // Invert the scaling factor to determine the true travel distance independent of circle size. double pixelTravelDistance = osuCurrent.TravelDistance / scalingFactor; @@ -91,6 +94,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // Longer sliders require more memorisation. sliderBonus *= pixelTravelDistance; + + // Reward sliders with repeats. + if (osuSlider.RepeatCount > 0) + sliderBonus *= repeat_bonus; } result += sliderBonus * slider_multiplier; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 1aa085a629..107fae709b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -252,8 +252,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing if (i == slider.NestedHitObjects.Count - 1) slider.LazyEndPosition = currCursorPosition; } - - slider.LazyTravelDistance *= (float)Math.Pow(1 + slider.RepeatCount / 2.5, 1.0 / 2.5); // Bonus for repeat sliders until a better per nested object strain system can be achieved. } private Vector2 getEndCursorPosition(OsuHitObject hitObject) From 68caafa210f4dd234e2acabd4e04b8a6871d1ea6 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Sun, 17 Jul 2022 17:02:30 +1000 Subject: [PATCH 0105/2686] Update xmldoc --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 444c2db884..4d9afb4fb2 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -23,8 +23,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators /// /// Evaluates the difficulty of memorising and hitting an object, based on: /// - /// distance between the previous and current object, + /// distance between previous objects and the current object, /// the visual opacity of the current object, + /// length and speed of the current object (for sliders), /// and whether the hidden mod is enabled. /// /// From 9e299bb88b3d1938fb25ef18ec29aa49396d45bd Mon Sep 17 00:00:00 2001 From: Jay L Date: Sun, 17 Jul 2022 18:54:26 +1000 Subject: [PATCH 0106/2686] Delete Idea Project Notation --- .idea/.idea.osu/.idea/discord.xml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .idea/.idea.osu/.idea/discord.xml diff --git a/.idea/.idea.osu/.idea/discord.xml b/.idea/.idea.osu/.idea/discord.xml deleted file mode 100644 index 30bab2abb1..0000000000 --- a/.idea/.idea.osu/.idea/discord.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file From dcce14ae8fef76b19f632e12117b3f8ee705eb8b Mon Sep 17 00:00:00 2001 From: tsunyoku Date: Sun, 17 Jul 2022 21:15:29 +0100 Subject: [PATCH 0107/2686] rename `NoConflictingModAcronyms` to `ModValidity`, add test for two-way mod incompatibility --- .../Visual/Gameplay/TestSceneModValidity.cs | 47 +++++++++++++++++++ .../TestSceneNoConflictingModAcronyms.cs | 27 ----------- 2 files changed, 47 insertions(+), 27 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneNoConflictingModAcronyms.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs new file mode 100644 index 0000000000..b37b3dd93e --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs @@ -0,0 +1,47 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Tests.Visual.Gameplay +{ + [HeadlessTest] + public class TestSceneModValidity : TestSceneAllRulesetPlayers + { + protected override void AddCheckSteps() + { + AddStep("Check all mod acronyms are unique", () => + { + var mods = Ruleset.Value.CreateInstance().AllMods; + + IEnumerable acronyms = mods.Select(m => m.Acronym); + + Assert.That(acronyms, Is.Unique); + }); + + AddStep("Check all mods are two-way incompatible", () => + { + var mods = Ruleset.Value.CreateInstance().AllMods; + + IEnumerable modInstances = mods.Select(mod => mod.CreateInstance()); + + foreach (var mod in modInstances) + { + var modIncompatibilities = mod.IncompatibleMods; + + foreach (var incompatibleModType in modIncompatibilities) + { + var incompatibleMod = (Mod)Activator.CreateInstance(incompatibleModType); + Assert.That(incompatibleMod?.IncompatibleMods.Contains(mod.GetType()) ?? false); + } + } + }); + } + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneNoConflictingModAcronyms.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneNoConflictingModAcronyms.cs deleted file mode 100644 index b2ba3d99ad..0000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneNoConflictingModAcronyms.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable -using System.Collections.Generic; -using System.Linq; -using NUnit.Framework; -using osu.Framework.Testing; - -namespace osu.Game.Tests.Visual.Gameplay -{ - [HeadlessTest] - public class TestSceneNoConflictingModAcronyms : TestSceneAllRulesetPlayers - { - protected override void AddCheckSteps() - { - AddStep("Check all mod acronyms are unique", () => - { - var mods = Ruleset.Value.CreateInstance().AllMods; - - IEnumerable acronyms = mods.Select(m => m.Acronym); - - Assert.That(acronyms, Is.Unique); - }); - } - } -} From 0c50931d2f072b36a1b0e4e4ff292e493dc549cd Mon Sep 17 00:00:00 2001 From: tsunyoku Date: Sun, 17 Jul 2022 22:10:35 +0100 Subject: [PATCH 0108/2686] change method of finding `incompatibleMod` --- osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs index b37b3dd93e..4bb1b69853 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. #nullable disable -using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -37,8 +36,8 @@ namespace osu.Game.Tests.Visual.Gameplay foreach (var incompatibleModType in modIncompatibilities) { - var incompatibleMod = (Mod)Activator.CreateInstance(incompatibleModType); - Assert.That(incompatibleMod?.IncompatibleMods.Contains(mod.GetType()) ?? false); + var incompatibleMod = modInstances.First(m => m.GetType().IsInstanceOfType(incompatibleModType)); + Assert.That(incompatibleMod.IncompatibleMods.Contains(mod.GetType())); } } }); From 92513dc9367741de62159775f3db15c5810bf253 Mon Sep 17 00:00:00 2001 From: tsunyoku Date: Sun, 17 Jul 2022 22:49:09 +0100 Subject: [PATCH 0109/2686] reverse IsInstanceOfType logic --- osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs index 4bb1b69853..5ccfd87ca7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.Gameplay foreach (var incompatibleModType in modIncompatibilities) { - var incompatibleMod = modInstances.First(m => m.GetType().IsInstanceOfType(incompatibleModType)); + var incompatibleMod = modInstances.First(m => incompatibleModType.IsInstanceOfType(m)); Assert.That(incompatibleMod.IncompatibleMods.Contains(mod.GetType())); } } From d17acd0f45cf54325f08981088991a52a7b5ea53 Mon Sep 17 00:00:00 2001 From: tsunyoku Date: Sun, 17 Jul 2022 23:16:27 +0100 Subject: [PATCH 0110/2686] add message to Assert.That --- osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs index 5ccfd87ca7..33e88d9ddb 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs @@ -37,7 +37,10 @@ namespace osu.Game.Tests.Visual.Gameplay foreach (var incompatibleModType in modIncompatibilities) { var incompatibleMod = modInstances.First(m => incompatibleModType.IsInstanceOfType(m)); - Assert.That(incompatibleMod.IncompatibleMods.Contains(mod.GetType())); + Assert.That( + incompatibleMod.IncompatibleMods.Contains(mod.GetType()), + $"{mod} has {incompatibleMod} in it's incompatible mods, but {incompatibleMod} does not have {mod} in it's incompatible mods." + ); } } }); From d1c60b5741c7f28e1b795e35a1d5d0d268994d31 Mon Sep 17 00:00:00 2001 From: tsunyoku Date: Sun, 17 Jul 2022 23:53:35 +0100 Subject: [PATCH 0111/2686] correct assertion logic --- osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs index 33e88d9ddb..aa8dfaaa7e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay { var incompatibleMod = modInstances.First(m => incompatibleModType.IsInstanceOfType(m)); Assert.That( - incompatibleMod.IncompatibleMods.Contains(mod.GetType()), + incompatibleMod.IncompatibleMods.Any(m => m.IsInstanceOfType(mod)), $"{mod} has {incompatibleMod} in it's incompatible mods, but {incompatibleMod} does not have {mod} in it's incompatible mods." ); } From 8413c40442cc1bd033b8b403f422caff8e50a47c Mon Sep 17 00:00:00 2001 From: MBmasher Date: Mon, 18 Jul 2022 15:58:09 +1000 Subject: [PATCH 0112/2686] Remove debug code --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 911b7d10fd..0b6a9fb59b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -4,7 +4,6 @@ #nullable disable using System; -using System.Diagnostics; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; @@ -123,8 +122,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (osuLastObj.BaseObject is Slider) { - Debug.Assert(osuLastObj.TravelTime > 0); - // Reward sliders based on velocity. sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime; From 204fbde07b38762900ba9a3b95ba4b35d5da3096 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Mon, 18 Jul 2022 15:58:32 +1000 Subject: [PATCH 0113/2686] Remove debug code --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 4d9afb4fb2..bd516382d7 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -4,7 +4,6 @@ #nullable disable using System; -using System.Diagnostics; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; @@ -83,8 +82,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (osuCurrent.BaseObject is Slider) { - Debug.Assert(osuCurrent.TravelTime > 0); - Slider osuSlider = (Slider)(osuCurrent.BaseObject); // Invert the scaling factor to determine the true travel distance independent of circle size. From 7c680afc3c1f7f189a6f4731fc1cd29b872f4512 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Mon, 18 Jul 2022 15:59:00 +1000 Subject: [PATCH 0114/2686] Change initialisation of osuSlider --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 4 +--- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 0b6a9fb59b..79f1f95017 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -120,12 +120,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2); } - if (osuLastObj.BaseObject is Slider) + if (osuLastObj.BaseObject is Slider osuSlider) { // Reward sliders based on velocity. sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime; - - Slider osuSlider = (Slider)(osuLastObj.BaseObject); sliderBonus *= (float)Math.Pow(1 + osuSlider.RepeatCount / 2.5, 1.0 / 2.5); // Bonus for repeat sliders until a better per nested object strain system can be achieved. } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index bd516382d7..217ef2a46f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -80,10 +80,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double sliderBonus = 0.0; - if (osuCurrent.BaseObject is Slider) + if (osuCurrent.BaseObject is Slider osuSlider) { - Slider osuSlider = (Slider)(osuCurrent.BaseObject); - // Invert the scaling factor to determine the true travel distance independent of circle size. double pixelTravelDistance = osuCurrent.TravelDistance / scalingFactor; From 72c096f9af1e83a4fb6c75af3d3fc5c8f462b639 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Mon, 18 Jul 2022 15:59:20 +1000 Subject: [PATCH 0115/2686] Update xmldoc --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 217ef2a46f..042ce7a1f7 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators /// /// Evaluates the difficulty of memorising and hitting an object, based on: /// - /// distance between previous objects and the current object, + /// distance between a number of previous objects and the current object, /// the visual opacity of the current object, /// length and speed of the current object (for sliders), /// and whether the hidden mod is enabled. From 42b9dc877dff4c64c7b00a999d8e1dae633f5f0d Mon Sep 17 00:00:00 2001 From: MBmasher Date: Mon, 18 Jul 2022 16:14:06 +1000 Subject: [PATCH 0116/2686] Divide slider bonus by repeat count --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 042ce7a1f7..cfdcd0af9a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -17,7 +17,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators private const double min_velocity = 0.5; private const double slider_multiplier = 1.3; - private const double repeat_bonus = 3.0; /// /// Evaluates the difficulty of memorising and hitting an object, based on: @@ -91,9 +90,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // Longer sliders require more memorisation. sliderBonus *= pixelTravelDistance; - // Reward sliders with repeats. + // Nerf sliders with repeats, as less memorisation is required. if (osuSlider.RepeatCount > 0) - sliderBonus *= repeat_bonus; + sliderBonus /= (osuSlider.RepeatCount + 1); } result += sliderBonus * slider_multiplier; From 633f6fe62082bfdea5e5be38434e233b6a9d6777 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 18 Jul 2022 21:58:11 +0300 Subject: [PATCH 0117/2686] Increase global multiplier --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 6eed778561..ee5ff3596a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); effectiveMissCount = calculateEffectiveMissCount(osuAttributes); - double multiplier = 1.11; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. + double multiplier = 1.125; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. if (score.Mods.Any(m => m is OsuModNoFail)) multiplier *= Math.Max(0.90, 1.0 - 0.02 * effectiveMissCount); @@ -276,6 +276,5 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double getComboScalingFactor(OsuDifficultyAttributes attributes) => attributes.MaxCombo <= 0 ? 1.0 : Math.Min(Math.Pow(scoreMaxCombo, 0.8) / Math.Pow(attributes.MaxCombo, 0.8), 1.0); private int totalHits => countGreat + countOk + countMeh + countMiss; - private int totalSuccessfulHits => countGreat + countOk + countMeh; } } From d213f56f79001d79267940372a472238a58d7df8 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 19 Jul 2022 02:08:53 -0700 Subject: [PATCH 0118/2686] Align legacy followcircle anims to slider ticks --- .../Skinning/Default/DefaultFollowCircle.cs | 42 ++++++-------- .../Skinning/FollowCircle.cs | 31 +++++++--- .../Skinning/Legacy/LegacyFollowCircle.cs | 39 +++++++------ .../Skinning/TickFollowCircle.cs | 58 +++++++++++++++++++ 4 files changed, 119 insertions(+), 51 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs index b77d4addee..0acd1a56b6 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.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 System.Diagnostics; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -32,37 +30,31 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default }; } - protected override void OnTrackingChanged(ValueChangedEvent tracking) + protected override void OnSliderPress() { - Debug.Assert(ParentObject != null); - const float duration = 300f; - if (ParentObject.Judged) - return; + if (Precision.AlmostEquals(0, Alpha)) + this.ScaleTo(1); - if (tracking.NewValue) - { - if (Precision.AlmostEquals(0, Alpha)) - this.ScaleTo(1); - - this.ScaleTo(DrawableSliderBall.FOLLOW_AREA, duration, Easing.OutQuint) - .FadeTo(1f, duration, Easing.OutQuint); - } - else - { - this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.2f, duration / 2, Easing.OutQuint) - .FadeTo(0, duration / 2, Easing.OutQuint); - } + this.ScaleTo(DrawableSliderBall.FOLLOW_AREA, duration, Easing.OutQuint) + .FadeIn(duration, Easing.OutQuint); } - protected override void OnSliderEnd() + protected override void OnSliderRelease() { - const float fade_duration = 300; + const float duration = 150; - // intentionally pile on an extra FadeOut to make it happen much faster - this.ScaleTo(1, fade_duration, Easing.OutQuint); - this.FadeOut(fade_duration / 2, Easing.OutQuint); + this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.2f, duration, Easing.OutQuint) + .FadeTo(0, duration, Easing.OutQuint); + } + + protected override void OnSliderTail() + { + const float duration = 300; + + this.ScaleTo(1, duration, Easing.OutQuint) + .FadeOut(duration / 2, Easing.OutQuint); } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs index 321705d25e..ca903b678d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs @@ -1,8 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Diagnostics; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; @@ -23,7 +23,17 @@ namespace osu.Game.Rulesets.Osu.Skinning [BackgroundDependencyLoader] private void load() { - ((DrawableSlider?)ParentObject)?.Tracking.BindValueChanged(OnTrackingChanged, true); + ((DrawableSlider?)ParentObject)?.Tracking.BindValueChanged(tracking => + { + Debug.Assert(ParentObject != null); + if (ParentObject.Judged) + return; + + if (tracking.NewValue) + OnSliderPress(); + else + OnSliderRelease(); + }, true); } protected override void LoadComplete() @@ -48,13 +58,18 @@ namespace osu.Game.Rulesets.Osu.Skinning private void updateStateTransforms(DrawableHitObject drawableObject, ArmedState state) { - // Gets called by slider ticks, tails, etc., leading to duplicated - // animations which may negatively affect performance if (drawableObject is not DrawableSlider) return; using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) - OnSliderEnd(); + { + switch (state) + { + case ArmedState.Hit: + OnSliderTail(); + break; + } + } } protected override void Dispose(bool isDisposing) @@ -68,8 +83,10 @@ namespace osu.Game.Rulesets.Osu.Skinning } } - protected abstract void OnTrackingChanged(ValueChangedEvent tracking); + protected abstract void OnSliderPress(); - protected abstract void OnSliderEnd(); + protected abstract void OnSliderRelease(); + + protected abstract void OnSliderTail(); } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs index 5b7da5a1ba..965f2a9cbe 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs @@ -3,12 +3,11 @@ using System; using System.Diagnostics; -using osu.Framework.Bindables; using osu.Framework.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyFollowCircle : FollowCircle + public class LegacyFollowCircle : TickFollowCircle { public LegacyFollowCircle(Drawable animationContent) { @@ -21,35 +20,37 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy InternalChild = animationContent; } - protected override void OnTrackingChanged(ValueChangedEvent tracking) + protected override void OnSliderPress() { Debug.Assert(ParentObject != null); - if (ParentObject.Judged) - return; - double remainingTime = Math.Max(0, ParentObject.HitStateUpdateTime - Time.Current); // Note that the scale adjust here is 2 instead of DrawableSliderBall.FOLLOW_AREA to match legacy behaviour. // This means the actual tracking area for gameplay purposes is larger than the sprite (but skins may be accounting for this). - if (tracking.NewValue) - { - // TODO: Follow circle should bounce on each slider tick. - this.ScaleTo(0.5f).ScaleTo(2f, Math.Min(180f, remainingTime), Easing.Out) - .FadeTo(0).FadeTo(1f, Math.Min(60f, remainingTime)); - } - else - { - // TODO: Should animate only at the next slider tick if we want to match stable perfectly. - this.ScaleTo(4f, 100) - .FadeTo(0f, 100); - } + this.ScaleTo(0.5f).ScaleTo(2f, Math.Min(180f, remainingTime), Easing.Out) + .FadeTo(0).FadeTo(1f, Math.Min(60f, remainingTime)); } - protected override void OnSliderEnd() + protected override void OnSliderTail() { this.ScaleTo(1.6f, 200, Easing.Out) .FadeOut(200, Easing.In); } + + protected override void OnSliderTick() + { + // TODO: Follow circle should bounce on each slider tick. + + // TEMP DUMMY ANIMS + this.ScaleTo(2.2f) + .ScaleTo(2f, 175f); + } + + protected override void OnSliderBreak() + { + this.ScaleTo(4f, 100) + .FadeTo(0f, 100); + } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs new file mode 100644 index 0000000000..39d62064ab --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.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 osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Skinning +{ + public abstract class TickFollowCircle : FollowCircle + { + protected override void LoadComplete() + { + base.LoadComplete(); + + if (ParentObject != null) + ParentObject.ApplyCustomUpdateState += updateStateTransforms; + } + + private void updateStateTransforms(DrawableHitObject drawableObject, ArmedState state) + { + using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) + { + switch (state) + { + case ArmedState.Hit: + if (drawableObject is DrawableSliderTick or DrawableSliderRepeat) + OnSliderTick(); + break; + + case ArmedState.Miss: + if (drawableObject is DrawableSlider or DrawableSliderTick or DrawableSliderRepeat) + OnSliderBreak(); + break; + } + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (ParentObject != null) + ParentObject.ApplyCustomUpdateState -= updateStateTransforms; + } + + /// + /// Sealed empty. Override instead, since animations + /// should only play on slider ticks. + /// + protected sealed override void OnSliderRelease() + { + } + + protected abstract void OnSliderTick(); + + protected abstract void OnSliderBreak(); + } +} From e1f7db6e7df40777fb743e90e50cf51251c301aa Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 19 Jul 2022 02:25:14 -0700 Subject: [PATCH 0119/2686] Fix around some comments --- osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs | 3 +++ osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs index ca903b678d..ec9d188c6b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs @@ -58,6 +58,9 @@ namespace osu.Game.Rulesets.Osu.Skinning private void updateStateTransforms(DrawableHitObject drawableObject, ArmedState state) { + // We only want DrawableSlider here. DrawableSliderTail doesn't quite work because its + // HitStateUpdateTime is ~36ms before DrawableSlider's HitStateUpdateTime (aka slider + // end leniency). if (drawableObject is not DrawableSlider) return; diff --git a/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs index 39d62064ab..3aeb0c7c0a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs @@ -44,8 +44,8 @@ namespace osu.Game.Rulesets.Osu.Skinning } /// - /// Sealed empty. Override instead, since animations - /// should only play on slider ticks. + /// Sealed empty intentionally. Override instead, since + /// animations should only play on slider ticks. /// protected sealed override void OnSliderRelease() { From 5cb0920cfbdd18da5b3254f27bdbeb94dd281880 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 19 Jul 2022 02:27:04 -0700 Subject: [PATCH 0120/2686] Revert OnSliderTail() to OnSliderEnd() In light of the comment added in the previous commit, slider tail and end are not actually the same. --- osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs | 2 +- osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs | 4 ++-- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs index 0acd1a56b6..51cfb2568b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default .FadeTo(0, duration, Easing.OutQuint); } - protected override void OnSliderTail() + protected override void OnSliderEnd() { const float duration = 300; diff --git a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs index ec9d188c6b..d7685c1724 100644 --- a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.Skinning switch (state) { case ArmedState.Hit: - OnSliderTail(); + OnSliderEnd(); break; } } @@ -90,6 +90,6 @@ namespace osu.Game.Rulesets.Osu.Skinning protected abstract void OnSliderRelease(); - protected abstract void OnSliderTail(); + protected abstract void OnSliderEnd(); } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs index 965f2a9cbe..9e1c2e7e9d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy .FadeTo(0).FadeTo(1f, Math.Min(60f, remainingTime)); } - protected override void OnSliderTail() + protected override void OnSliderEnd() { this.ScaleTo(1.6f, 200, Easing.Out) .FadeOut(200, Easing.In); From 35e841de95966b96bc78f349ea784207ed9c7646 Mon Sep 17 00:00:00 2001 From: StanR Date: Wed, 20 Jul 2022 15:54:49 +0300 Subject: [PATCH 0121/2686] Move base performance multiplier to a const --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 9748a00b12..5b91ff3fce 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty Math.Pow(baseFlashlightPerformance, 1.1), 1.0 / 1.1 ); - double starRating = basePerformance > 0.00001 ? Math.Cbrt(1.12) * 0.027 * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) : 0; + double starRating = basePerformance > 0.00001 ? Math.Cbrt(OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER) * 0.027 * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) : 0; double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate; double drainRate = beatmap.Difficulty.DrainRate; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index ee5ff3596a..1c19325891 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuPerformanceCalculator : PerformanceCalculator { + public const double PERFORMANCE_BASE_MULTIPLIER = 1.125; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. + private double accuracy; private int scoreMaxCombo; private int countGreat; @@ -41,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); effectiveMissCount = calculateEffectiveMissCount(osuAttributes); - double multiplier = 1.125; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. + double multiplier = PERFORMANCE_BASE_MULTIPLIER; if (score.Mods.Any(m => m is OsuModNoFail)) multiplier *= Math.Max(0.90, 1.0 - 0.02 * effectiveMissCount); From 163c3f9c2d821a3b74c18b3df9e92e77f826e66a Mon Sep 17 00:00:00 2001 From: StanR Date: Wed, 20 Jul 2022 16:10:34 +0300 Subject: [PATCH 0122/2686] Adjust multipliers to account for speed changes --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 1c19325891..3c82c2dc33 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuPerformanceCalculator : PerformanceCalculator { - public const double PERFORMANCE_BASE_MULTIPLIER = 1.125; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. + public const double PERFORMANCE_BASE_MULTIPLIER = 1.14; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. private double accuracy; private int scoreMaxCombo; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index e4f61b65cd..38e0e5b677 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private double currentStrain; - private double skillMultiplier => 24.15; + private double skillMultiplier => 23.55; private double strainDecayBase => 0.15; private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); From cb63ec282e135d19bb7330a518c186f24a8f4e5f Mon Sep 17 00:00:00 2001 From: Jay L Date: Wed, 20 Jul 2022 23:33:38 +1000 Subject: [PATCH 0123/2686] Partial Review changes --- .../Difficulty/Evaluators/ColourEvaluator.cs | 24 +++++++++++-------- .../Difficulty/Evaluators/StaminaEvaluator.cs | 2 +- .../Colour/Data/CoupledColourEncoding.cs | 4 ++-- .../Preprocessing/Colour/Data/MonoEncoding.cs | 1 - .../Preprocessing/TaikoDifficultyHitObject.cs | 8 +++---- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 1d857a1dbb..bda161bf63 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -10,14 +10,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators { public class ColourEvaluator { - private static double sigmoid(double val, double center, double width) + /// + /// A sigmoid function. It gives a value between (middle - height/2) and (middle + height/2). + /// + /// The input value. + /// The center of the sigmoid, where the largest gradient occurs and value is equal to middle. + /// The radius of the sigmoid, outside of which values are near the minimum/maximum. + /// The middle of the sigmoid output. + /// The height of the sigmoid output. This will be equal to max value - min value. + public static double Sigmoid(double val, double center, double width, double middle, double height) { - return Math.Tanh(Math.E * -(val - center) / width); - } - - private static double sigmoid(double val, double center, double width, double middle, double height) - { - return sigmoid(val, center, width) * (height / 2) + middle; + double sigmoid = Math.Tanh(Math.E * -(val - center) / width); + return sigmoid * (height / 2) + middle; } /// @@ -27,7 +31,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// public static double EvaluateDifficultyOf(MonoEncoding encoding, int i) { - return sigmoid(i, 2, 2, 0.5, 1); + return Sigmoid(i, 2, 2, 0.5, 1); } /// @@ -37,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// The index of the colour encoding within it's parent . public static double EvaluateDifficultyOf(ColourEncoding encoding, int i) { - return sigmoid(i, 2, 2, 0.5, 1); + return Sigmoid(i, 2, 2, 0.5, 1); } /// @@ -45,7 +49,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// public static double EvaluateDifficultyOf(CoupledColourEncoding encoding) { - return 1 - sigmoid(encoding.RepetitionInterval, 2, 2, 0.5, 1); + return 1 - Sigmoid(encoding.RepetitionInterval, 2, 2, 0.5, 1); } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 954c1661dd..49b3ae2e19 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// /// Evaluates the minimum mechanical stamina required to play the current object. This is calculated using the - /// maximum possible interval between two hits using the same key, by alternating 2 keys for each colour. + /// maximum possible interval between two hits using the same key, by alternating 2 keys for each colour. /// public static double EvaluateDifficultyOf(DifficultyHitObject current) { diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs index 188d1b686b..9d204225fc 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs @@ -34,8 +34,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data public int RepetitionInterval { get; private set; } = max_repetition_interval + 1; /// - /// Returns true if other is considered a repetition of this encoding. This is true if other's first two payload - /// identical mono lengths. + /// Returns true if other is considered a repetition of this encoding. This is true if other's first two payloads + /// have identical mono lengths. /// private bool isRepetitionOf(CoupledColourEncoding other) { diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs index 9e60946bd1..f42f968657 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs @@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// /// List of s that are encoded within this . /// This is not declared as to avoid circular dependencies. - /// TODO: Review this, are circular dependencies within data-only classes are acceptable? /// public List EncodedData { get; private set; } = new List(); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index a0d2fc7797..6619a54a7a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { private readonly IReadOnlyList? monoDifficultyHitObjects; public readonly int MonoIndex; - private readonly IReadOnlyList noteObjects; + private readonly IReadOnlyList noteDifficultyHitObjects; public readonly int NoteIndex; /// @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing : base(hitObject, lastObject, clockRate, objects, index) { var currentHit = hitObject as Hit; - this.noteObjects = noteObjects; + noteDifficultyHitObjects = noteObjects; Rhythm = getClosestRhythm(lastObject, lastLastObject, clockRate); HitType? hitType = currentHit?.Type; @@ -120,8 +120,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing public TaikoDifficultyHitObject? NextMono(int forwardsIndex) => monoDifficultyHitObjects?.ElementAtOrDefault(MonoIndex + (forwardsIndex + 1)); - public TaikoDifficultyHitObject? PreviousNote(int backwardsIndex) => noteObjects.ElementAtOrDefault(NoteIndex - (backwardsIndex + 1)); + public TaikoDifficultyHitObject? PreviousNote(int backwardsIndex) => noteDifficultyHitObjects.ElementAtOrDefault(NoteIndex - (backwardsIndex + 1)); - public TaikoDifficultyHitObject? NextNote(int forwardsIndex) => noteObjects.ElementAtOrDefault(NoteIndex + (forwardsIndex + 1)); + public TaikoDifficultyHitObject? NextNote(int forwardsIndex) => noteDifficultyHitObjects.ElementAtOrDefault(NoteIndex + (forwardsIndex + 1)); } } From 08dd9c79db55bcee648c2ae891c5969a63315ae5 Mon Sep 17 00:00:00 2001 From: Jay L Date: Thu, 21 Jul 2022 09:55:19 +1000 Subject: [PATCH 0124/2686] Fix Convert-related nerf This addresses recent player unsatisfaction with converts being underweighted. --- .../Difficulty/TaikoDifficultyCalculator.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index a70d3d9a38..3a230f7b91 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -64,10 +64,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double combinedRating = combined.DifficultyValue() * difficulty_multiplier; double starRating = rescale(combinedRating * 1.4); - // TODO: This is temporary measure as we don't detect abuse-type playstyles of converts within the current system. + // TODO: This is temporary measure as we don't detect abuse of multiple-input playstyles of converts within the current system. if (beatmap.BeatmapInfo.Ruleset.OnlineID == 0) { - starRating *= 0.80; + starRating *= 0.925; + // For maps with low colour variance and high stamina requirement, multiple inputs are more likely to be abused. + if (colourRating < 2 && staminaRating > 8) + starRating *= 0.80; } HitWindows hitWindows = new TaikoHitWindows(); From b7567f7db2f3714693de8244d53f5192a69e19ab Mon Sep 17 00:00:00 2001 From: Jay L Date: Thu, 21 Jul 2022 10:52:41 +1000 Subject: [PATCH 0125/2686] Share sigmoid, Fix Preprocessor XML --- .../Difficulty/Evaluators/ColourEvaluator.cs | 21 +++++-------------- .../TaikoColourDifficultyPreprocessor.cs | 16 +++++++------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index bda161bf63..f677fe8b25 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -25,21 +25,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators } /// - /// Evaluate the difficulty of the first note of a . - /// The encoding to evaluate. - /// The index of the mono encoding within it's parent . + /// Evaluate the difficulty of the first note of a or a . + /// The index of either encoding within it's respective parent. /// - public static double EvaluateDifficultyOf(MonoEncoding encoding, int i) - { - return Sigmoid(i, 2, 2, 0.5, 1); - } - - /// - /// Evaluate the difficulty of the first note of a . - /// - /// The encoding to evaluate. - /// The index of the colour encoding within it's parent . - public static double EvaluateDifficultyOf(ColourEncoding encoding, int i) + public static double EvaluateDifficultyOf(int i) { return Sigmoid(i, 2, 2, 0.5, 1); } @@ -65,13 +54,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators for (int i = 0; i < encoding.Payload.Count; i++) { ColourEncoding colourEncoding = encoding.Payload[i]; - double colourEncodingDifficulty = EvaluateDifficultyOf(colourEncoding, i) * coupledEncodingDifficulty; + double colourEncodingDifficulty = EvaluateDifficultyOf(i) * coupledEncodingDifficulty; colourEncoding.Payload[0].EncodedData[0].Colour!.EvaluatedDifficulty += colourEncodingDifficulty; for (int j = 0; j < colourEncoding.Payload.Count; j++) { MonoEncoding monoEncoding = colourEncoding.Payload[j]; - monoEncoding.EncodedData[0].Colour!.EvaluatedDifficulty += EvaluateDifficultyOf(monoEncoding, j) * colourEncodingDifficulty * 0.5; + monoEncoding.EncodedData[0].Colour!.EvaluatedDifficulty += EvaluateDifficultyOf(j) * colourEncodingDifficulty * 0.5; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index a699422d2c..a3238efc65 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -16,9 +16,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour public class TaikoColourDifficultyPreprocessor { /// - /// Process and encode a list of s into a list of s, - /// assign the appropriate s to each , - /// and preevaluate colour difficulty of each . + /// Processes and encodes a list of s into a list of s, + /// assigning the appropriate s to each , + /// and pre-evaluating colour difficulty of each . /// public static List ProcessAndAssign(List hitObjects) { @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour }); }); - // Preevaluate and assign difficulty values + // Pre-evaluate and assign difficulty values ColourEvaluator.PreEvaluateDifficulties(coupledEncoding); }); @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour // This ignores all non-note objects, which may or may not be the desired behaviour TaikoDifficultyHitObject? previousObject = taikoObject.PreviousNote(0); - // If the colour changed, or if this is the first object in the run, create a new mono encoding + // If the colour changed or if this is the first object in the run, create a new mono encoding if ( previousObject == null || // First object in the list @@ -75,8 +75,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour continue; } - // If we're here, we're in the same encoding as the previous object, thus lastEncoded is not null. Add - // the current object to the encoded payload. + // If we're here, we're in the same encoding as the previous object, thus lastEncoded is not null. + // Add the current object to the encoded payload. lastEncoded!.EncodedData.Add(taikoObject); } @@ -159,7 +159,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour isCoupled = i < data.Count - 2 && data[i].IsRepetitionOf(data[i + 2]); } - // Skip over peeked data and add the rest to the payload + // Skip over viewed data and add the rest to the payload lastEncoded.Payload.Add(data[i]); lastEncoded.Payload.Add(data[i + 1]); i++; From 23fd514ca3b691c6e6043288c8d49b2204030477 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Wed, 20 Jul 2022 18:07:02 -0700 Subject: [PATCH 0126/2686] Use DrawableSliderTail instead of DrawableSlider --- osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs | 11 ++++++----- osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs | 4 +++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs index d7685c1724..06fa381cbb 100644 --- a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs @@ -58,13 +58,14 @@ namespace osu.Game.Rulesets.Osu.Skinning private void updateStateTransforms(DrawableHitObject drawableObject, ArmedState state) { - // We only want DrawableSlider here. DrawableSliderTail doesn't quite work because its - // HitStateUpdateTime is ~36ms before DrawableSlider's HitStateUpdateTime (aka slider - // end leniency). - if (drawableObject is not DrawableSlider) + if (drawableObject is not DrawableSliderTail) return; - using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) + Debug.Assert(ParentObject != null); + + // Use ParentObject instead of drawableObject because slider tail hit state update time + // is ~36ms before the actual slider end (aka slider tail leniency) + using (BeginAbsoluteSequence(ParentObject.HitStateUpdateTime)) { switch (state) { diff --git a/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs index 3aeb0c7c0a..de8a8150d0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs @@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Osu.Skinning private void updateStateTransforms(DrawableHitObject drawableObject, ArmedState state) { + // Fine to use drawableObject.HitStateUpdateTime even for DrawableSliderTail, since on + // stable, the break anim plays right when the tail is missed, not when the slider ends using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) { switch (state) @@ -28,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Skinning break; case ArmedState.Miss: - if (drawableObject is DrawableSlider or DrawableSliderTick or DrawableSliderRepeat) + if (drawableObject is DrawableSliderTail or DrawableSliderTick or DrawableSliderRepeat) OnSliderBreak(); break; } From 7917a60e3c18c1f9f9d9c54fc7f1ae811b6cc470 Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 21 Jul 2022 15:45:03 +0800 Subject: [PATCH 0127/2686] Move TaikoDifficultyHitObject creation back to TaikoDifficultyCalculator --- .../TaikoDifficultyPreprocessor.cs | 26 +++---------------- .../Difficulty/TaikoDifficultyCalculator.cs | 16 +++++++++++- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs index fa8e6a8a26..bd703b7263 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; -using osu.Game.Beatmaps; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing @@ -11,31 +10,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing public class TaikoDifficultyPreprocessor { /// - /// Creates a list of s from a s. - /// This is placed here in a separate class to avoid having to know - /// too much implementation details of the preprocessing, and avoid - /// having circular dependencies with various preprocessing and evaluator classes. + /// Does preprocessing on a list of s. + /// TODO: Review this - this is currently only a one-step process, but will potentially be expanded in the future. /// - /// The beatmap from which the list of is created. - /// The rate at which the gameplay clock is run at. - public static List CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) + public static List Process(List difficultyHitObjects) { - List difficultyHitObjects = new List(); - List centreObjects = new List(); - List rimObjects = new List(); - List noteObjects = new List(); - - for (int i = 2; i < beatmap.HitObjects.Count; i++) - { - difficultyHitObjects.Add( - new TaikoDifficultyHitObject( - beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObjects, - centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count) - ); - } - TaikoColourDifficultyPreprocessor.ProcessAndAssign(difficultyHitObjects); - return difficultyHitObjects; } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 3a230f7b91..716a016b12 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -47,7 +47,21 @@ namespace osu.Game.Rulesets.Taiko.Difficulty protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { - return TaikoDifficultyPreprocessor.CreateDifficultyHitObjects(beatmap, clockRate); + List difficultyHitObjects = new List(); + List centreObjects = new List(); + List rimObjects = new List(); + List noteObjects = new List(); + + for (int i = 2; i < beatmap.HitObjects.Count; i++) + { + difficultyHitObjects.Add( + new TaikoDifficultyHitObject( + beatmap.HitObjects[i], beatmap.HitObjects[i - 1], beatmap.HitObjects[i - 2], clockRate, difficultyHitObjects, + centreObjects, rimObjects, noteObjects, difficultyHitObjects.Count) + ); + } + + return TaikoDifficultyPreprocessor.Process(difficultyHitObjects); } protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) From a5a8fac66f6e58afd9b4984c94be0dedef7a2e4a Mon Sep 17 00:00:00 2001 From: solstice23 Date: Thu, 21 Jul 2022 18:24:31 +0800 Subject: [PATCH 0128/2686] Add multiple units support in search length criteria --- osu.Game/Screens/Select/FilterQueryParser.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 03b72bf5e9..436beae30d 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -312,11 +312,18 @@ namespace osu.Game.Screens.Select private static bool tryUpdateLengthRange(FilterCriteria criteria, Operator op, string val) { - if (!tryParseDoubleWithPoint(val.TrimEnd('m', 's', 'h'), out double length)) - return false; - - int scale = getLengthScale(val); - return tryUpdateCriteriaRange(ref criteria.Length, op, length * scale, scale / 2.0); + string[] parts = Regex.Split(val, @"(?<=[msh])").Where(x => x.Length > 0).ToArray(); + double totalLength = 0; + int minScale = 1000; + foreach (string part in parts) + { + if (!tryParseDoubleWithPoint(part.TrimEnd('m', 's', 'h'), out double length)) + return false; + int scale = getLengthScale(part); + totalLength += length * scale; + minScale = Math.Min(minScale, scale); + } + return tryUpdateCriteriaRange(ref criteria.Length, op, totalLength, minScale / 2.0); } } } From 6baaef432f086209c163b52d5393d3d32ce62e7c Mon Sep 17 00:00:00 2001 From: solstice23 Date: Thu, 21 Jul 2022 18:49:13 +0800 Subject: [PATCH 0129/2686] Add colon parsing support in search length criteria --- osu.Game/Screens/Select/FilterQueryParser.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 436beae30d..ee7a1617cd 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -312,9 +312,25 @@ namespace osu.Game.Screens.Select private static bool tryUpdateLengthRange(FilterCriteria criteria, Operator op, string val) { + if (val.Contains(':')) + { + if (val.Contains('h') || val.Contains('m') || val.Contains('s')) + return false; + + int count = val.Count(c => c == ':'); + if (count > 3) + return false; + + if (count > 2) + val = val.Replace(':', 'h'); + + val = val.Replace(':', 'm'); + } + string[] parts = Regex.Split(val, @"(?<=[msh])").Where(x => x.Length > 0).ToArray(); double totalLength = 0; int minScale = 1000; + foreach (string part in parts) { if (!tryParseDoubleWithPoint(part.TrimEnd('m', 's', 'h'), out double length)) @@ -323,6 +339,7 @@ namespace osu.Game.Screens.Select totalLength += length * scale; minScale = Math.Min(minScale, scale); } + return tryUpdateCriteriaRange(ref criteria.Length, op, totalLength, minScale / 2.0); } } From 52fad1e14d4292f0c867cb099eb1fcee1b6b960f Mon Sep 17 00:00:00 2001 From: solstice23 Date: Thu, 21 Jul 2022 18:59:48 +0800 Subject: [PATCH 0130/2686] Add test cases for search length criteria --- osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index bd0617515b..9f97c39462 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -125,6 +125,10 @@ namespace osu.Game.Tests.NonVisual.Filtering new object[] { "9m", TimeSpan.FromMinutes(9), TimeSpan.FromMinutes(1) }, new object[] { "0.25h", TimeSpan.FromHours(0.25), TimeSpan.FromHours(1) }, new object[] { "70", TimeSpan.FromSeconds(70), TimeSpan.FromSeconds(1) }, + new object[] { "7m27s", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1) }, + new object[] { "6h5m", TimeSpan.FromMinutes(365), TimeSpan.FromMinutes(1) }, + new object[] { "7:27", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1) }, + new object[] { "0:2:35", TimeSpan.FromSeconds(155), TimeSpan.FromSeconds(1) }, }; [Test] From e4086b058bb3052a89c41c709bd6483b3fe15809 Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 21 Jul 2022 19:15:22 +0800 Subject: [PATCH 0131/2686] Implement stateless colour evaluator and required encoding changes --- .../Difficulty/Evaluators/ColourEvaluator.cs | 49 +++++++------- .../Colour/Data/ColourEncoding.cs | 7 ++ .../Preprocessing/Colour/Data/MonoEncoding.cs | 7 ++ .../TaikoColourDifficultyPreprocessor.cs | 66 +++++++++++-------- .../Colour/TaikoDifficultyHitObjectColour.cs | 24 ++++--- .../Preprocessing/TaikoDifficultyHitObject.cs | 5 +- .../Difficulty/Skills/Colour.cs | 5 +- 7 files changed, 99 insertions(+), 64 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index f677fe8b25..30094dc869 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data; @@ -18,19 +19,26 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// The radius of the sigmoid, outside of which values are near the minimum/maximum. /// The middle of the sigmoid output. /// The height of the sigmoid output. This will be equal to max value - min value. - public static double Sigmoid(double val, double center, double width, double middle, double height) + private static double sigmoid(double val, double center, double width, double middle, double height) { double sigmoid = Math.Tanh(Math.E * -(val - center) / width); return sigmoid * (height / 2) + middle; } /// - /// Evaluate the difficulty of the first note of a or a . - /// The index of either encoding within it's respective parent. + /// Evaluate the difficulty of the first note of a . /// - public static double EvaluateDifficultyOf(int i) + public static double EvaluateDifficultyOf(MonoEncoding encoding) { - return Sigmoid(i, 2, 2, 0.5, 1); + return sigmoid(encoding.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(encoding.Parent!) * 0.5; + } + + /// + /// Evaluate the difficulty of the first note of a . + /// + public static double EvaluateDifficultyOf(ColourEncoding encoding) + { + return sigmoid(encoding.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(encoding.Parent!); } /// @@ -38,31 +46,22 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// public static double EvaluateDifficultyOf(CoupledColourEncoding encoding) { - return 1 - Sigmoid(encoding.RepetitionInterval, 2, 2, 0.5, 1); + return 2 * (1 - sigmoid(encoding.RepetitionInterval, 2, 2, 0.5, 1)); } - /// - /// Pre-evaluate and *assign* difficulty values of all hit objects encoded in a . - /// Difficulty values are assigned to of each - /// encoded within. - /// - public static void PreEvaluateDifficulties(CoupledColourEncoding encoding) + public static double EvaluateDifficultyOf(DifficultyHitObject hitObject) { - double coupledEncodingDifficulty = 2 * EvaluateDifficultyOf(encoding); - encoding.Payload[0].Payload[0].EncodedData[0].Colour!.EvaluatedDifficulty += coupledEncodingDifficulty; + TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)hitObject).Colour; + double difficulty = 0.0d; - for (int i = 0; i < encoding.Payload.Count; i++) - { - ColourEncoding colourEncoding = encoding.Payload[i]; - double colourEncodingDifficulty = EvaluateDifficultyOf(i) * coupledEncodingDifficulty; - colourEncoding.Payload[0].EncodedData[0].Colour!.EvaluatedDifficulty += colourEncodingDifficulty; + if (colour.MonoEncoding != null) // Difficulty for MonoEncoding + difficulty += EvaluateDifficultyOf(colour.MonoEncoding); + if (colour.ColourEncoding != null) // Difficulty for ColourEncoding + difficulty += EvaluateDifficultyOf(colour.ColourEncoding); + if (colour.CoupledColourEncoding != null) // Difficulty for CoupledColourEncoding + difficulty += EvaluateDifficultyOf(colour.CoupledColourEncoding); - for (int j = 0; j < colourEncoding.Payload.Count; j++) - { - MonoEncoding monoEncoding = colourEncoding.Payload[j]; - monoEncoding.EncodedData[0].Colour!.EvaluatedDifficulty += EvaluateDifficultyOf(j) * colourEncodingDifficulty * 0.5; - } - } + return difficulty; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs index cddf8816f5..23c5fa8b4a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs @@ -17,6 +17,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public List Payload { get; private set; } = new List(); + public CoupledColourEncoding? Parent; + + /// + /// Index of this encoding within it's parent encoding + /// + public int Index; + /// /// Determine if this is a repetition of another . This /// is a strict comparison and is true if and only if the colour sequence is exactly the same. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs index f42f968657..abeba53e9a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs @@ -19,6 +19,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public List EncodedData { get; private set; } = new List(); + public ColourEncoding? Parent; + + /// + /// Index of this encoding within it's parent encoding + /// + public int Index; + public int RunLength => EncodedData.Count; } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index a3238efc65..d775246a2e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; -using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data; using osu.Game.Rulesets.Taiko.Objects; @@ -25,22 +24,36 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour List colours = new List(); List encodings = Encode(hitObjects); - // Assign colour to objects + // Assign indexing and encoding data to all relevant objects. Only the first note of each encoding type is + // assigned with the relevant encodings. encodings.ForEach(coupledEncoding => { - coupledEncoding.Payload.ForEach(encoding => - { - encoding.Payload.ForEach(mono => - { - mono.EncodedData.ForEach(hitObject => - { - hitObject.Colour = new TaikoDifficultyHitObjectColour(coupledEncoding); - }); - }); - }); + coupledEncoding.Payload[0].Payload[0].EncodedData[0].Colour.CoupledColourEncoding = coupledEncoding; - // Pre-evaluate and assign difficulty values - ColourEvaluator.PreEvaluateDifficulties(coupledEncoding); + // TODO: Review this - + // The outermost loop is kept a ForEach loop since it doesn't need index information, and we want to + // keep i and j for ColourEncoding's and MonoEncoding's index respectively, to keep it in line with + // documentation. + // If we want uniformity for the outermost loop, it can be switched to a for loop with h or something + // else as an index + // + // While parent and index should be part of the encoding process, they are assigned here instead due to + // this being a simple one location to assign them. + for (int i = 0; i < coupledEncoding.Payload.Count; ++i) + { + ColourEncoding colourEncoding = coupledEncoding.Payload[i]; + colourEncoding.Parent = coupledEncoding; + colourEncoding.Index = i; + colourEncoding.Payload[0].EncodedData[0].Colour.ColourEncoding = colourEncoding; + + for (int j = 0; j < colourEncoding.Payload.Count; ++j) + { + MonoEncoding monoEncoding = colourEncoding.Payload[j]; + monoEncoding.Parent = colourEncoding; + monoEncoding.Index = j; + monoEncoding.EncodedData[0].Colour.MonoEncoding = monoEncoding; + } + } }); return colours; @@ -67,7 +80,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour previousObject == null || // First object in the list (taikoObject.BaseObject as Hit)?.Type != (previousObject.BaseObject as Hit)?.Type ) - { lastEncoded = new MonoEncoding(); lastEncoded.EncodedData.Add(taikoObject); @@ -111,18 +123,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour return encoded; } - /// - /// Encodes a list of s into a list of s. - /// - public static List Encode(List data) - { - List firstPass = EncodeMono(data); - List secondPass = EncodeColour(firstPass); - List thirdPass = EncodeCoupledColour(secondPass); - - return thirdPass; - } - /// /// Encodes a list of s into a list of s. /// @@ -176,5 +176,17 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour return encoded; } + + /// + /// Encodes a list of s into a list of s. + /// + public static List Encode(List data) + { + List firstPass = EncodeMono(data); + List secondPass = EncodeColour(firstPass); + List thirdPass = EncodeCoupledColour(secondPass); + + return thirdPass; + } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs index 9fc7a1dacb..6a6b427393 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs @@ -6,18 +6,26 @@ using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { /// - /// Stores colour compression information for a . This is only present for the - /// first in a chunk. + /// Stores colour compression information for a . /// public class TaikoDifficultyHitObjectColour { - public CoupledColourEncoding Encoding { get; } + /// + /// encoding that encodes this note, only present if this is the first note within a + /// + /// + public MonoEncoding? MonoEncoding; - public double EvaluatedDifficulty = 0; + /// + /// encoding that encodes this note, only present if this is the first note within + /// a + /// + public ColourEncoding? ColourEncoding; - public TaikoDifficultyHitObjectColour(CoupledColourEncoding encoding) - { - Encoding = encoding; - } + /// + /// encoding that encodes this note, only present if this is the first note + /// within a + /// + public CoupledColourEncoding? CoupledColourEncoding; } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 6619a54a7a..14fd67be33 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// by other skills in the future. /// This need to be writeable by TaikoDifficultyHitObjectColour so that it can assign potentially reused instances /// - public TaikoDifficultyHitObjectColour? Colour; + public TaikoDifficultyHitObjectColour Colour; /// /// Creates a new difficulty hit object. @@ -53,6 +53,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing List noteObjects, int index) : base(hitObject, lastObject, clockRate, objects, index) { + // Create the Colour object, its properties should be filled in by TaikoDifficultyPreprocessor + Colour = new TaikoDifficultyHitObjectColour(); + var currentHit = hitObject as Hit; noteDifficultyHitObjects = noteObjects; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index 8f8f62d214..386135ea4d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Evaluators; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { @@ -29,8 +29,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double StrainValueOf(DifficultyHitObject current) { - double difficulty = ((TaikoDifficultyHitObject)current).Colour?.EvaluatedDifficulty ?? 0; - return difficulty; + return ColourEvaluator.EvaluateDifficultyOf(current); } } } From 726042d9ec2d8eef2a3549fe665d69ba8c51cc15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Jul 2022 23:16:28 +0900 Subject: [PATCH 0132/2686] Use switch instead of `or` --- .../Skinning/TickFollowCircle.cs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs index de8a8150d0..ca1959a561 100644 --- a/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs @@ -25,13 +25,26 @@ namespace osu.Game.Rulesets.Osu.Skinning switch (state) { case ArmedState.Hit: - if (drawableObject is DrawableSliderTick or DrawableSliderRepeat) - OnSliderTick(); + switch (drawableObject) + { + case DrawableSliderTick: + case DrawableSliderRepeat: + OnSliderTick(); + break; + } + break; case ArmedState.Miss: - if (drawableObject is DrawableSliderTail or DrawableSliderTick or DrawableSliderRepeat) - OnSliderBreak(); + switch (drawableObject) + { + case DrawableSliderTail: + case DrawableSliderTick: + case DrawableSliderRepeat: + OnSliderBreak(); + break; + } + break; } } From ae0902ca86e30d690459c1dedb28a9d01f0d6ff7 Mon Sep 17 00:00:00 2001 From: solstice23 Date: Fri, 22 Jul 2022 02:55:11 +0800 Subject: [PATCH 0133/2686] Fix lax in search criteria parsing --- osu.Game/Screens/Select/FilterQueryParser.cs | 49 +++++++++++++------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index ee7a1617cd..25dd342353 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; @@ -312,34 +313,50 @@ namespace osu.Game.Screens.Select private static bool tryUpdateLengthRange(FilterCriteria criteria, Operator op, string val) { - if (val.Contains(':')) + List parts = new List(); + + if (Regex.IsMatch(val, @"^\d+(:\d+(:\d+)?)?$")) // formats like 12:34 { - if (val.Contains('h') || val.Contains('m') || val.Contains('s')) + string[] splited = val.Split(':'); + for (int i = splited.Length - 1; i >= 0; i--) + parts.Add(splited[i] + "smh"[splited.Length - i - 1]); + } + else if (Regex.IsMatch(val, @"^(\d+(\.\d+)?[hms]){1,3}$")) // formats like 1h2m3s + { + if (!"hms".Contains(Regex.Replace(val, @"[\d\.]", ""))) return false; - int count = val.Count(c => c == ':'); - if (count > 3) - return false; - - if (count > 2) - val = val.Replace(':', 'h'); - - val = val.Replace(':', 'm'); + string[] splited = Regex.Split(val, @"(?<=[hms])").Where(x => x.Length > 0).ToArray(); + for (int i = splited.Length - 1; i >= 0; i--) + parts.Add(splited[i]); + } + else if (Regex.IsMatch(val, @"^\d+(\.\d+)?$")) // only one number + { + parts.Add(val + 's'); } - string[] parts = Regex.Split(val, @"(?<=[msh])").Where(x => x.Length > 0).ToArray(); - double totalLength = 0; - int minScale = 1000; + if (parts.Count == 0) + return false; - foreach (string part in parts) + double totalLength = 0; + int minScale = 3600000; + + for (int i = 0; i < parts.Count; i++) { - if (!tryParseDoubleWithPoint(part.TrimEnd('m', 's', 'h'), out double length)) + string part = parts[i]; + string partNoUnit = part.TrimEnd('m', 's', 'h'); + if (!tryParseDoubleWithPoint(partNoUnit, out double length)) return false; + + if (i != parts.Count - 1 && length >= 60) + return false; + if (i != 0 && partNoUnit.Contains('.')) + return false; + int scale = getLengthScale(part); totalLength += length * scale; minScale = Math.Min(minScale, scale); } - return tryUpdateCriteriaRange(ref criteria.Length, op, totalLength, minScale / 2.0); } } From de25830b2ba1b0a696331d79da54f2ea7605a8e2 Mon Sep 17 00:00:00 2001 From: solstice23 Date: Fri, 22 Jul 2022 03:27:08 +0800 Subject: [PATCH 0134/2686] Add more test cases --- .../NonVisual/Filtering/FilterQueryParserTest.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 9f97c39462..8f17410cad 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -126,9 +126,16 @@ namespace osu.Game.Tests.NonVisual.Filtering new object[] { "0.25h", TimeSpan.FromHours(0.25), TimeSpan.FromHours(1) }, new object[] { "70", TimeSpan.FromSeconds(70), TimeSpan.FromSeconds(1) }, new object[] { "7m27s", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1) }, - new object[] { "6h5m", TimeSpan.FromMinutes(365), TimeSpan.FromMinutes(1) }, new object[] { "7:27", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1) }, - new object[] { "0:2:35", TimeSpan.FromSeconds(155), TimeSpan.FromSeconds(1) }, + new object[] { "1h2m3s", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1) }, + new object[] { "1h2m3.5s", TimeSpan.FromSeconds(3723.5), TimeSpan.FromSeconds(1) }, + new object[] { "1:2:3", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1) }, + new object[] { "1:02:03", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1) }, + new object[] { "6", TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(1) }, + new object[] { "6.5", TimeSpan.FromSeconds(6.5), TimeSpan.FromSeconds(1) }, + new object[] { "6.5s", TimeSpan.FromSeconds(6.5), TimeSpan.FromSeconds(1) }, + new object[] { "6.5m", TimeSpan.FromMinutes(6.5), TimeSpan.FromMinutes(1) }, + new object[] { "6h5m", TimeSpan.FromMinutes(365), TimeSpan.FromMinutes(1) }, }; [Test] From b36e23c0da7c02e61d87862bbe30eb5f8b3ccc1e Mon Sep 17 00:00:00 2001 From: solstice23 Date: Fri, 22 Jul 2022 03:30:31 +0800 Subject: [PATCH 0135/2686] Simplify the regex expression --- osu.Game/Screens/Select/FilterQueryParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 25dd342353..9245c13243 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -315,7 +315,7 @@ namespace osu.Game.Screens.Select { List parts = new List(); - if (Regex.IsMatch(val, @"^\d+(:\d+(:\d+)?)?$")) // formats like 12:34 + if (Regex.IsMatch(val, @"^\d+(:\d+){1,2}$")) // formats like 12:34 { string[] splited = val.Split(':'); for (int i = splited.Length - 1; i >= 0; i--) From c2c2c505a4f2ab578afaff235e3c042e1e42bf00 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Thu, 21 Jul 2022 19:46:46 -0700 Subject: [PATCH 0136/2686] Combine FollowCircle and TickFollowCircle classes --- .../Skinning/Default/DefaultFollowCircle.cs | 13 ++++ .../Skinning/FollowCircle.cs | 52 ++++++++++--- .../Skinning/Legacy/LegacyFollowCircle.cs | 6 +- .../Skinning/TickFollowCircle.cs | 73 ------------------- 4 files changed, 58 insertions(+), 86 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs index 51cfb2568b..3b087245e9 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs @@ -56,5 +56,18 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default this.ScaleTo(1, duration, Easing.OutQuint) .FadeOut(duration / 2, Easing.OutQuint); } + + protected override void OnSliderTick() + { + // TODO: Follow circle should bounce on each slider tick. + + // TEMP DUMMY ANIMS + this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.1f) + .ScaleTo(DrawableSliderBall.FOLLOW_AREA, 175f); + } + + protected override void OnSliderBreak() + { + } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs index 06fa381cbb..9eb8e66c83 100644 --- a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs @@ -58,21 +58,45 @@ namespace osu.Game.Rulesets.Osu.Skinning private void updateStateTransforms(DrawableHitObject drawableObject, ArmedState state) { - if (drawableObject is not DrawableSliderTail) - return; - Debug.Assert(ParentObject != null); - // Use ParentObject instead of drawableObject because slider tail hit state update time - // is ~36ms before the actual slider end (aka slider tail leniency) - using (BeginAbsoluteSequence(ParentObject.HitStateUpdateTime)) + switch (state) { - switch (state) - { - case ArmedState.Hit: - OnSliderEnd(); - break; - } + case ArmedState.Hit: + switch (drawableObject) + { + case DrawableSliderTail: + // Use ParentObject instead of drawableObject because slider tail's + // HitStateUpdateTime is ~36ms before the actual slider end (aka slider + // tail leniency) + using (BeginAbsoluteSequence(ParentObject.HitStateUpdateTime)) + OnSliderEnd(); + break; + + case DrawableSliderTick: + case DrawableSliderRepeat: + using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) + OnSliderTick(); + break; + } + + break; + + case ArmedState.Miss: + switch (drawableObject) + { + case DrawableSliderTail: + case DrawableSliderTick: + case DrawableSliderRepeat: + // Despite above comment, ok to use drawableObject.HitStateUpdateTime + // here, since on stable, the break anim plays right when the tail is + // missed, not when the slider ends + using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) + OnSliderBreak(); + break; + } + + break; } } @@ -92,5 +116,9 @@ namespace osu.Game.Rulesets.Osu.Skinning protected abstract void OnSliderRelease(); protected abstract void OnSliderEnd(); + + protected abstract void OnSliderTick(); + + protected abstract void OnSliderBreak(); } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs index 9e1c2e7e9d..6d16596ed2 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyFollowCircle : TickFollowCircle + public class LegacyFollowCircle : FollowCircle { public LegacyFollowCircle(Drawable animationContent) { @@ -32,6 +32,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy .FadeTo(0).FadeTo(1f, Math.Min(60f, remainingTime)); } + protected override void OnSliderRelease() + { + } + protected override void OnSliderEnd() { this.ScaleTo(1.6f, 200, Easing.Out) diff --git a/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs deleted file mode 100644 index ca1959a561..0000000000 --- a/osu.Game.Rulesets.Osu/Skinning/TickFollowCircle.cs +++ /dev/null @@ -1,73 +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.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Objects.Drawables; - -namespace osu.Game.Rulesets.Osu.Skinning -{ - public abstract class TickFollowCircle : FollowCircle - { - protected override void LoadComplete() - { - base.LoadComplete(); - - if (ParentObject != null) - ParentObject.ApplyCustomUpdateState += updateStateTransforms; - } - - private void updateStateTransforms(DrawableHitObject drawableObject, ArmedState state) - { - // Fine to use drawableObject.HitStateUpdateTime even for DrawableSliderTail, since on - // stable, the break anim plays right when the tail is missed, not when the slider ends - using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) - { - switch (state) - { - case ArmedState.Hit: - switch (drawableObject) - { - case DrawableSliderTick: - case DrawableSliderRepeat: - OnSliderTick(); - break; - } - - break; - - case ArmedState.Miss: - switch (drawableObject) - { - case DrawableSliderTail: - case DrawableSliderTick: - case DrawableSliderRepeat: - OnSliderBreak(); - break; - } - - break; - } - } - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (ParentObject != null) - ParentObject.ApplyCustomUpdateState -= updateStateTransforms; - } - - /// - /// Sealed empty intentionally. Override instead, since - /// animations should only play on slider ticks. - /// - protected sealed override void OnSliderRelease() - { - } - - protected abstract void OnSliderTick(); - - protected abstract void OnSliderBreak(); - } -} From 4433f902ea4a20a6ec7bbcf70ee03ce1c26134a3 Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 22 Jul 2022 10:49:53 +0800 Subject: [PATCH 0137/2686] Fix and add comments --- .../Preprocessing/Colour/Data/MonoEncoding.cs | 3 +++ .../Colour/TaikoColourDifficultyPreprocessor.cs | 3 --- .../Preprocessing/TaikoDifficultyHitObject.cs | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs index abeba53e9a..6f25eea51e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs @@ -26,6 +26,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public int Index; + /// + /// How long the mono pattern encoded within is + /// public int RunLength => EncodedData.Count; } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index d775246a2e..3772013e7a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -30,12 +30,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { coupledEncoding.Payload[0].Payload[0].EncodedData[0].Colour.CoupledColourEncoding = coupledEncoding; - // TODO: Review this - // The outermost loop is kept a ForEach loop since it doesn't need index information, and we want to // keep i and j for ColourEncoding's and MonoEncoding's index respectively, to keep it in line with // documentation. - // If we want uniformity for the outermost loop, it can be switched to a for loop with h or something - // else as an index // // While parent and index should be part of the encoding process, they are assigned here instead due to // this being a simple one location to assign them. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index 14fd67be33..fd9a225f6a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -17,9 +17,24 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// public class TaikoDifficultyHitObject : DifficultyHitObject { + /// + /// The list of all of the same colour as this in the beatmap. + /// private readonly IReadOnlyList? monoDifficultyHitObjects; + + /// + /// The index of this in . + /// public readonly int MonoIndex; + + /// + /// The list of all that is either a regular note or finisher in the beatmap + /// private readonly IReadOnlyList noteDifficultyHitObjects; + + /// + /// The index of this in . + /// public readonly int NoteIndex; /// From 80e82763e35304022e9c42a35a4f4c18fba7ef2e Mon Sep 17 00:00:00 2001 From: solstice23 Date: Fri, 22 Jul 2022 12:09:47 +0800 Subject: [PATCH 0138/2686] Add negative test cases --- .../Filtering/FilterQueryParserTest.cs | 61 ++++++++++++------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 8f17410cad..4b20fc42c9 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -120,35 +120,54 @@ namespace osu.Game.Tests.NonVisual.Filtering private static readonly object[] length_query_examples = { - new object[] { "6ms", TimeSpan.FromMilliseconds(6), TimeSpan.FromMilliseconds(1) }, - new object[] { "23s", TimeSpan.FromSeconds(23), TimeSpan.FromSeconds(1) }, - new object[] { "9m", TimeSpan.FromMinutes(9), TimeSpan.FromMinutes(1) }, - new object[] { "0.25h", TimeSpan.FromHours(0.25), TimeSpan.FromHours(1) }, - new object[] { "70", TimeSpan.FromSeconds(70), TimeSpan.FromSeconds(1) }, - new object[] { "7m27s", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1) }, - new object[] { "7:27", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1) }, - new object[] { "1h2m3s", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1) }, - new object[] { "1h2m3.5s", TimeSpan.FromSeconds(3723.5), TimeSpan.FromSeconds(1) }, - new object[] { "1:2:3", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1) }, - new object[] { "1:02:03", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1) }, - new object[] { "6", TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(1) }, - new object[] { "6.5", TimeSpan.FromSeconds(6.5), TimeSpan.FromSeconds(1) }, - new object[] { "6.5s", TimeSpan.FromSeconds(6.5), TimeSpan.FromSeconds(1) }, - new object[] { "6.5m", TimeSpan.FromMinutes(6.5), TimeSpan.FromMinutes(1) }, - new object[] { "6h5m", TimeSpan.FromMinutes(365), TimeSpan.FromMinutes(1) }, + new object[] { "23s", TimeSpan.FromSeconds(23), TimeSpan.FromSeconds(1), true }, + new object[] { "9m", TimeSpan.FromMinutes(9), TimeSpan.FromMinutes(1), true }, + new object[] { "0.25h", TimeSpan.FromHours(0.25), TimeSpan.FromHours(1), true }, + new object[] { "70", TimeSpan.FromSeconds(70), TimeSpan.FromSeconds(1), true }, + new object[] { "7m27s", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1), true }, + new object[] { "7:27", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1), true }, + new object[] { "1h2m3s", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1), true }, + new object[] { "1h2m3.5s", TimeSpan.FromSeconds(3723.5), TimeSpan.FromSeconds(1), true }, + new object[] { "1:2:3", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1), true }, + new object[] { "1:02:03", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1), true }, + new object[] { "6", TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(1), true }, + new object[] { "6.5", TimeSpan.FromSeconds(6.5), TimeSpan.FromSeconds(1), true }, + new object[] { "6.5s", TimeSpan.FromSeconds(6.5), TimeSpan.FromSeconds(1), true }, + new object[] { "6.5m", TimeSpan.FromMinutes(6.5), TimeSpan.FromMinutes(1), true }, + new object[] { "6h5m", TimeSpan.FromMinutes(365), TimeSpan.FromMinutes(1), true }, + new object[] { "65m", TimeSpan.FromMinutes(65), TimeSpan.FromMinutes(1), true }, + new object[] { "90s", TimeSpan.FromSeconds(90), TimeSpan.FromSeconds(1), true }, + new object[] { "80m20s", TimeSpan.FromSeconds(4820), TimeSpan.FromSeconds(1), true }, + new object[] { "7.5m27s", new TimeSpan(), new TimeSpan(), false }, + new object[] { "7m27", new TimeSpan(), new TimeSpan(), false }, + new object[] { "7m7m7m", new TimeSpan(), new TimeSpan(), false }, + new object[] { "7m70s", new TimeSpan(), new TimeSpan(), false }, + new object[] { "5s6m", new TimeSpan(), new TimeSpan(), false }, + new object[] { "0:", new TimeSpan(), new TimeSpan(), false }, + new object[] { ":0", new TimeSpan(), new TimeSpan(), false }, + new object[] { "0:3:", new TimeSpan(), new TimeSpan(), false }, + new object[] { "3:15.5", new TimeSpan(), new TimeSpan(), false }, }; [Test] [TestCaseSource(nameof(length_query_examples))] - public void TestApplyLengthQueries(string lengthQuery, TimeSpan expectedLength, TimeSpan scale) + public void TestApplyLengthQueries(string lengthQuery, TimeSpan expectedLength, TimeSpan scale, bool isValid) { string query = $"length={lengthQuery} time"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - Assert.AreEqual("time", filterCriteria.SearchText.Trim()); - Assert.AreEqual(1, filterCriteria.SearchTerms.Length); - Assert.AreEqual(expectedLength.TotalMilliseconds - scale.TotalMilliseconds / 2.0, filterCriteria.Length.Min); - Assert.AreEqual(expectedLength.TotalMilliseconds + scale.TotalMilliseconds / 2.0, filterCriteria.Length.Max); + if (isValid) + { + Assert.AreEqual("time", filterCriteria.SearchText.Trim()); + Assert.AreEqual(1, filterCriteria.SearchTerms.Length); + Assert.AreEqual(expectedLength.TotalMilliseconds - scale.TotalMilliseconds / 2.0, filterCriteria.Length.Min); + Assert.AreEqual(expectedLength.TotalMilliseconds + scale.TotalMilliseconds / 2.0, filterCriteria.Length.Max); + } + else + { + Assert.AreEqual(false, filterCriteria.Length.HasFilter); + } + } [Test] From 7c222505e941f0afd2f4925cacb3922c6d10938a Mon Sep 17 00:00:00 2001 From: solstice23 Date: Fri, 22 Jul 2022 14:24:17 +0800 Subject: [PATCH 0139/2686] Simplify length parsing --- .../Filtering/FilterQueryParserTest.cs | 1 - osu.Game/Screens/Select/FilterQueryParser.cs | 22 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 4b20fc42c9..f08bd09cf5 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -167,7 +167,6 @@ namespace osu.Game.Tests.NonVisual.Filtering { Assert.AreEqual(false, filterCriteria.Length.HasFilter); } - } [Test] diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 9245c13243..b8c85c5ce0 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -317,18 +317,18 @@ namespace osu.Game.Screens.Select if (Regex.IsMatch(val, @"^\d+(:\d+){1,2}$")) // formats like 12:34 { - string[] splited = val.Split(':'); - for (int i = splited.Length - 1; i >= 0; i--) - parts.Add(splited[i] + "smh"[splited.Length - i - 1]); - } - else if (Regex.IsMatch(val, @"^(\d+(\.\d+)?[hms]){1,3}$")) // formats like 1h2m3s - { - if (!"hms".Contains(Regex.Replace(val, @"[\d\.]", ""))) - return false; + List splitted = val.Split(':').ToList(); + while (splitted.Count < 3) + splitted.Insert(0, "0"); - string[] splited = Regex.Split(val, @"(?<=[hms])").Where(x => x.Length > 0).ToArray(); - for (int i = splited.Length - 1; i >= 0; i--) - parts.Add(splited[i]); + parts.Add(splitted[2] + 's'); + parts.Add(splitted[1] + 'm'); + parts.Add(splitted[0] + 'h'); + } + else if (Regex.IsMatch(val, @"^(\d+(\.\d+)?[hms]){1,3}$") && "hms".Contains(Regex.Replace(val, @"[\d\.]", ""))) // formats like 1h2m3s + { + string[] splitted = Regex.Split(val, @"(?<=[hms])").Where(x => x.Length > 0).Reverse().ToArray(); + parts.AddRange(splitted); } else if (Regex.IsMatch(val, @"^\d+(\.\d+)?$")) // only one number { From 6359c1a4fea5ec9790cbf276804a4f9a2233228d Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 22 Jul 2022 16:31:19 +0800 Subject: [PATCH 0140/2686] Fix outdated comment --- .../Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs index 23c5fa8b4a..9415769dab 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs @@ -27,7 +27,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// /// Determine if this is a repetition of another . This /// is a strict comparison and is true if and only if the colour sequence is exactly the same. - /// This does not require the s to have the same amount of s. /// public bool IsRepetitionOf(ColourEncoding other) { From 7d4593eb6ddbbc1d4a257d2bf8a3622f39a79ce0 Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 22 Jul 2022 18:20:35 +0800 Subject: [PATCH 0141/2686] Fix comments --- .../Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs | 3 +++ .../Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs | 3 +++ .../Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs | 1 - 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs index 9415769dab..04066e7539 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs @@ -17,6 +17,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public List Payload { get; private set; } = new List(); + /// + /// The parent that contains this + /// public CoupledColourEncoding? Parent; /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs index 6f25eea51e..7eee8896ac 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs @@ -19,6 +19,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public List EncodedData { get; private set; } = new List(); + /// + /// The parent that contains this + /// public ColourEncoding? Parent; /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs index bd703b7263..c5ee8de809 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs @@ -11,7 +11,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { /// /// Does preprocessing on a list of s. - /// TODO: Review this - this is currently only a one-step process, but will potentially be expanded in the future. /// public static List Process(List difficultyHitObjects) { From fc08d77090b6cdd0de9dca93dfe2c3bfb2b85647 Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 22 Jul 2022 18:31:59 +0800 Subject: [PATCH 0142/2686] Remove review-specific comment --- .../Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 3772013e7a..517e240682 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -33,9 +33,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour // The outermost loop is kept a ForEach loop since it doesn't need index information, and we want to // keep i and j for ColourEncoding's and MonoEncoding's index respectively, to keep it in line with // documentation. - // - // While parent and index should be part of the encoding process, they are assigned here instead due to - // this being a simple one location to assign them. for (int i = 0; i < coupledEncoding.Payload.Count; ++i) { ColourEncoding colourEncoding = coupledEncoding.Payload[i]; From f44a5def90d8a52f737fc5a6b33af45380f8e39f Mon Sep 17 00:00:00 2001 From: MBmasher Date: Sat, 23 Jul 2022 14:40:16 +1000 Subject: [PATCH 0143/2686] Move repeat bonus to TravelDistance --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 1 - .../Difficulty/Evaluators/FlashlightEvaluator.cs | 2 +- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 3 ++- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 79f1f95017..fac7cd549a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -124,7 +124,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { // Reward sliders based on velocity. sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime; - sliderBonus *= (float)Math.Pow(1 + osuSlider.RepeatCount / 2.5, 1.0 / 2.5); // Bonus for repeat sliders until a better per nested object strain system can be achieved. } // Add in acute angle bonus or wide angle bonus + velocity change bonus, whichever is larger. diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index cfdcd0af9a..fcf4179a3b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -82,7 +82,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (osuCurrent.BaseObject is Slider osuSlider) { // Invert the scaling factor to determine the true travel distance independent of circle size. - double pixelTravelDistance = osuCurrent.TravelDistance / scalingFactor; + double pixelTravelDistance = osuSlider.LazyTravelDistance / scalingFactor; // Reward sliders based on velocity. sliderBonus = Math.Pow(Math.Max(0.0, pixelTravelDistance / osuCurrent.TravelTime - min_velocity), 0.5); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 107fae709b..c7c5650184 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -127,7 +127,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing if (BaseObject is Slider currentSlider) { computeSliderCursorPosition(currentSlider); - TravelDistance = currentSlider.LazyTravelDistance; + // Bonus for repeat sliders until a better per nested object strain system can be achieved. + TravelDistance = currentSlider.LazyTravelDistance * (float)Math.Pow(1 + currentSlider.RepeatCount / 2.5, 1.0 / 2.5); TravelTime = Math.Max(currentSlider.LazyTravelTime / clockRate, min_delta_time); } From 267d55a6a8f46598c4d7b016129459a92d09160e Mon Sep 17 00:00:00 2001 From: MBmasher Date: Sat, 23 Jul 2022 14:48:39 +1000 Subject: [PATCH 0144/2686] Remove osuSlider from statement --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 9c832a04fc..b2d6aaf83c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2); } - if (osuLastObj.BaseObject is Slider osuSlider) + if (osuLastObj.BaseObject is Slider) { // Reward sliders based on velocity. sliderBonus = osuLastObj.TravelDistance / osuLastObj.TravelTime; From 1220250bb677567498a10e4f9604ce8291bc8b3d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 23 Jul 2022 07:26:34 +0300 Subject: [PATCH 0145/2686] Improve test scene and add failing test case --- osu.Game.Tests/Resources/TestResources.cs | 2 +- .../SongSelect/TestSceneTopLocalRank.cs | 79 ++++++++++++++++--- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index ee29cc8644..37bcef0414 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -190,7 +190,7 @@ namespace osu.Game.Tests.Resources [HitResult.SmallTickMiss] = 25, [HitResult.LargeTickHit] = 100, [HitResult.LargeTickMiss] = 50, - [HitResult.SmallBonus] = 10, + [HitResult.LargeBonus] = 10, [HitResult.SmallBonus] = 50 }, }; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs index 05b5c5c0cd..d998c4e161 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs @@ -3,6 +3,8 @@ #nullable disable +using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -13,6 +15,7 @@ using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Rulesets; +using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Select.Carousel; using osu.Game.Tests.Resources; @@ -54,6 +57,8 @@ namespace osu.Game.Tests.Visual.SongSelect Scale = new Vector2(10), }); }); + + AddAssert("No rank displayed initially", () => topLocalRank.Rank == null); } [Test] @@ -61,8 +66,6 @@ namespace osu.Game.Tests.Visual.SongSelect { ScoreInfo testScoreInfo = null; - AddAssert("Initially not present", () => !topLocalRank.IsPresent); - AddStep("Add score for current user", () => { testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); @@ -73,15 +76,14 @@ namespace osu.Game.Tests.Visual.SongSelect scoreManager.Import(testScoreInfo); }); - AddUntilStep("Became present", () => topLocalRank.IsPresent); - AddAssert("Correct rank", () => topLocalRank.Rank == ScoreRank.B); + AddUntilStep("B rank displayed", () => topLocalRank.Rank == ScoreRank.B); AddStep("Delete score", () => { scoreManager.Delete(testScoreInfo); }); - AddUntilStep("Became not present", () => !topLocalRank.IsPresent); + AddUntilStep("No rank displayed", () => topLocalRank.Rank == null); } [Test] @@ -99,13 +101,13 @@ namespace osu.Game.Tests.Visual.SongSelect scoreManager.Import(testScoreInfo); }); - AddUntilStep("Wait for initial presence", () => topLocalRank.IsPresent); + AddUntilStep("Wait for initial display", () => topLocalRank.Rank == ScoreRank.B); AddStep("Change ruleset", () => Ruleset.Value = rulesets.GetRuleset("fruits")); - AddUntilStep("Became not present", () => !topLocalRank.IsPresent); + AddUntilStep("No rank displayed", () => topLocalRank.Rank == null); AddStep("Change ruleset back", () => Ruleset.Value = rulesets.GetRuleset("osu")); - AddUntilStep("Became present", () => topLocalRank.IsPresent); + AddUntilStep("B rank displayed", () => topLocalRank.Rank == ScoreRank.B); } [Test] @@ -113,8 +115,6 @@ namespace osu.Game.Tests.Visual.SongSelect { ScoreInfo testScoreInfo = null; - AddAssert("Initially not present", () => !topLocalRank.IsPresent); - AddStep("Add score for current user", () => { testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); @@ -125,8 +125,7 @@ namespace osu.Game.Tests.Visual.SongSelect scoreManager.Import(testScoreInfo); }); - AddUntilStep("Became present", () => topLocalRank.IsPresent); - AddUntilStep("Correct rank", () => topLocalRank.Rank == ScoreRank.B); + AddUntilStep("B rank displayed", () => topLocalRank.Rank == ScoreRank.B); AddStep("Add higher score for current user", () => { @@ -135,11 +134,65 @@ namespace osu.Game.Tests.Visual.SongSelect testScoreInfo2.User = API.LocalUser.Value; testScoreInfo2.Rank = ScoreRank.S; testScoreInfo2.TotalScore = testScoreInfo.TotalScore + 1; + testScoreInfo2.Statistics = new Dictionary + { + [HitResult.Miss] = 0, + [HitResult.Perfect] = 970, + [HitResult.SmallTickHit] = 75, + [HitResult.LargeTickHit] = 150, + [HitResult.LargeBonus] = 10, + [HitResult.SmallBonus] = 50 + }; scoreManager.Import(testScoreInfo2); }); - AddUntilStep("Correct rank", () => topLocalRank.Rank == ScoreRank.S); + AddUntilStep("S rank displayed", () => topLocalRank.Rank == ScoreRank.S); + } + + [Test] + public void TestLegacyScore() + { + ScoreInfo testScoreInfo = null; + + AddStep("Add legacy score for current user", () => + { + testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); + + testScoreInfo.User = API.LocalUser.Value; + testScoreInfo.Rank = ScoreRank.B; + testScoreInfo.TotalScore = scoreManager.GetTotalScoreAsync(testScoreInfo, ScoringMode.Classic).GetResultSafely(); + + scoreManager.Import(testScoreInfo); + }); + + AddUntilStep("B rank displayed", () => topLocalRank.Rank == ScoreRank.B); + + AddStep("Add higher score for current user", () => + { + var testScoreInfo2 = TestResources.CreateTestScoreInfo(importedBeatmap); + + testScoreInfo2.User = API.LocalUser.Value; + testScoreInfo2.Rank = ScoreRank.S; + testScoreInfo2.Statistics = new Dictionary + { + [HitResult.Miss] = 0, + [HitResult.Perfect] = 970, + [HitResult.SmallTickHit] = 75, + [HitResult.LargeTickHit] = 150, + [HitResult.LargeBonus] = 10, + [HitResult.SmallBonus] = 50 + }; + + testScoreInfo2.TotalScore = scoreManager.GetTotalScoreAsync(testScoreInfo).GetResultSafely(); + + // ensure standardised total score is less than classic, otherwise this test is pointless. + Debug.Assert(testScoreInfo2.TotalScore < testScoreInfo.TotalScore); + + scoreManager.Import(testScoreInfo2); + }); + + AddUntilStep("S rank displayed", () => topLocalRank.Rank == ScoreRank.S); } } } From 727fe76b6090e2071507e1e1622e1f79fd2d22ca Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 23 Jul 2022 08:09:00 +0300 Subject: [PATCH 0146/2686] Fix `TopLocalRank` hacking around presence to hide on null rank Fixed this here because that blocks `Schedule` from running, and I don't want to add another override to the `IsPresent` flag. --- .../SongSelect/TestSceneTopLocalRank.cs | 20 ++++++------- .../Online/Leaderboards/UpdateableRank.cs | 2 +- .../Screens/Select/Carousel/TopLocalRank.cs | 29 ++++++++++++++----- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs index d998c4e161..90d7aaacc3 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.SongSelect }); }); - AddAssert("No rank displayed initially", () => topLocalRank.Rank == null); + AddAssert("No rank displayed initially", () => topLocalRank.DisplayedRank == null); } [Test] @@ -76,14 +76,14 @@ namespace osu.Game.Tests.Visual.SongSelect scoreManager.Import(testScoreInfo); }); - AddUntilStep("B rank displayed", () => topLocalRank.Rank == ScoreRank.B); + AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); AddStep("Delete score", () => { scoreManager.Delete(testScoreInfo); }); - AddUntilStep("No rank displayed", () => topLocalRank.Rank == null); + AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank == null); } [Test] @@ -101,13 +101,13 @@ namespace osu.Game.Tests.Visual.SongSelect scoreManager.Import(testScoreInfo); }); - AddUntilStep("Wait for initial display", () => topLocalRank.Rank == ScoreRank.B); + AddUntilStep("Wait for initial display", () => topLocalRank.DisplayedRank == ScoreRank.B); AddStep("Change ruleset", () => Ruleset.Value = rulesets.GetRuleset("fruits")); - AddUntilStep("No rank displayed", () => topLocalRank.Rank == null); + AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank == null); AddStep("Change ruleset back", () => Ruleset.Value = rulesets.GetRuleset("osu")); - AddUntilStep("B rank displayed", () => topLocalRank.Rank == ScoreRank.B); + AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); } [Test] @@ -125,7 +125,7 @@ namespace osu.Game.Tests.Visual.SongSelect scoreManager.Import(testScoreInfo); }); - AddUntilStep("B rank displayed", () => topLocalRank.Rank == ScoreRank.B); + AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); AddStep("Add higher score for current user", () => { @@ -147,7 +147,7 @@ namespace osu.Game.Tests.Visual.SongSelect scoreManager.Import(testScoreInfo2); }); - AddUntilStep("S rank displayed", () => topLocalRank.Rank == ScoreRank.S); + AddUntilStep("S rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.S); } [Test] @@ -166,7 +166,7 @@ namespace osu.Game.Tests.Visual.SongSelect scoreManager.Import(testScoreInfo); }); - AddUntilStep("B rank displayed", () => topLocalRank.Rank == ScoreRank.B); + AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); AddStep("Add higher score for current user", () => { @@ -192,7 +192,7 @@ namespace osu.Game.Tests.Visual.SongSelect scoreManager.Import(testScoreInfo2); }); - AddUntilStep("S rank displayed", () => topLocalRank.Rank == ScoreRank.S); + AddUntilStep("S rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.S); } } } diff --git a/osu.Game/Online/Leaderboards/UpdateableRank.cs b/osu.Game/Online/Leaderboards/UpdateableRank.cs index e4f5f72886..e640fe8494 100644 --- a/osu.Game/Online/Leaderboards/UpdateableRank.cs +++ b/osu.Game/Online/Leaderboards/UpdateableRank.cs @@ -17,7 +17,7 @@ namespace osu.Game.Online.Leaderboards set => Model = value; } - public UpdateableRank(ScoreRank? rank) + public UpdateableRank(ScoreRank? rank = null) { Rank = rank; } diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs index cc01f61c57..033da61461 100644 --- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs +++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs @@ -5,9 +5,12 @@ using System; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Models; @@ -20,7 +23,7 @@ using Realms; namespace osu.Game.Screens.Select.Carousel { - public class TopLocalRank : UpdateableRank + public class TopLocalRank : CompositeDrawable { private readonly BeatmapInfo beatmapInfo; @@ -34,13 +37,25 @@ namespace osu.Game.Screens.Select.Carousel private IAPIProvider api { get; set; } private IDisposable scoreSubscription; + private CancellationTokenSource scoreOrderCancellationSource; + + private readonly UpdateableRank updateable; + + public ScoreRank? DisplayedRank => updateable.Rank; public TopLocalRank(BeatmapInfo beatmapInfo) - : base(null) { this.beatmapInfo = beatmapInfo; - Size = new Vector2(40, 20); + AutoSizeAxes = Axes.Both; + + InternalChild = updateable = new UpdateableRank + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(40, 20), + Alpha = 0, + }; } protected override void LoadComplete() @@ -59,19 +74,17 @@ namespace osu.Game.Screens.Select.Carousel .OrderByDescending(s => s.TotalScore), (items, _, _) => { - Rank = items.FirstOrDefault()?.Rank; - // Required since presence is changed via IsPresent override - Invalidate(Invalidation.Presence); + updateable.Rank = items.FirstOrDefault()?.Rank; + updateable.Alpha = updateable.Rank != null ? 1 : 0; }); }, true); } - public override bool IsPresent => base.IsPresent && Rank != null; - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); + scoreOrderCancellationSource?.Cancel(); scoreSubscription?.Dispose(); } } From 1d0306810ab63e471a459c5488bef69cfe96610c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 23 Jul 2022 08:13:05 +0300 Subject: [PATCH 0147/2686] Fix `TopLocalRank` not handling legacy scores properly --- .../Screens/Select/Carousel/TopLocalRank.cs | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs index 033da61461..d372cb8dbc 100644 --- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs +++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; @@ -33,6 +34,9 @@ namespace osu.Game.Screens.Select.Carousel [Resolved] private RealmAccess realm { get; set; } + [Resolved] + private ScoreManager scoreManager { get; set; } + [Resolved] private IAPIProvider api { get; set; } @@ -70,14 +74,29 @@ namespace osu.Game.Screens.Select.Carousel .Filter($"{nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} == $0" + $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $1" + $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $2" - + $" && {nameof(ScoreInfo.DeletePending)} == false", api.LocalUser.Value.Id, beatmapInfo.ID, ruleset.Value.ShortName) - .OrderByDescending(s => s.TotalScore), - (items, _, _) => - { - updateable.Rank = items.FirstOrDefault()?.Rank; - updateable.Alpha = updateable.Rank != null ? 1 : 0; - }); + + $" && {nameof(ScoreInfo.DeletePending)} == false", api.LocalUser.Value.Id, beatmapInfo.ID, ruleset.Value.ShortName), + localScoresChanged); }, true); + + void localScoresChanged(IRealmCollection sender, ChangeSet changes, Exception error) + { + // This subscription may fire from changes to linked beatmaps, which we don't care about. + // It's currently not possible for a score to be modified after insertion, so we can safely ignore callbacks with only modifications. + if (changes?.HasCollectionChanges() == false) + return; + + scoreOrderCancellationSource?.Cancel(); + + scoreManager.OrderByTotalScoreAsync(sender.Detach().ToArray(), (scoreOrderCancellationSource = new CancellationTokenSource()).Token) + .ContinueWith(ordered => Schedule(() => + { + if (scoreOrderCancellationSource.IsCancellationRequested) + return; + + updateable.Rank = ordered.GetResultSafely().FirstOrDefault()?.Rank; + updateable.Alpha = updateable.Rank != null ? 1 : 0; + }), TaskContinuationOptions.OnlyOnRanToCompletion); + } } protected override void Dispose(bool isDisposing) From 3aecd288e22d985bb42b934bfc749fbe2f73b97d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 23 Jul 2022 09:25:06 +0300 Subject: [PATCH 0148/2686] Enable NRT on `TopLocalRank` --- .../SongSelect/TestSceneTopLocalRank.cs | 25 +++++++++---------- .../Screens/Select/Carousel/TopLocalRank.cs | 16 ++++++------ 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs index 90d7aaacc3..b122898346 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.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. -#nullable disable - using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -10,6 +8,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Framework.Testing; @@ -25,10 +24,10 @@ namespace osu.Game.Tests.Visual.SongSelect { public class TestSceneTopLocalRank : OsuTestScene { - private RulesetStore rulesets; - private BeatmapManager beatmapManager; - private ScoreManager scoreManager; - private TopLocalRank topLocalRank; + private RulesetStore rulesets = null!; + private BeatmapManager beatmapManager = null!; + private ScoreManager scoreManager = null!; + private TopLocalRank topLocalRank = null!; [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) @@ -64,7 +63,7 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestBasicImportDelete() { - ScoreInfo testScoreInfo = null; + ScoreInfo? testScoreInfo = null; AddStep("Add score for current user", () => { @@ -80,7 +79,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("Delete score", () => { - scoreManager.Delete(testScoreInfo); + scoreManager.Delete(testScoreInfo.AsNonNull()); }); AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank == null); @@ -113,7 +112,7 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestHigherScoreSet() { - ScoreInfo testScoreInfo = null; + ScoreInfo? testScoreInfo = null; AddStep("Add score for current user", () => { @@ -133,7 +132,7 @@ namespace osu.Game.Tests.Visual.SongSelect testScoreInfo2.User = API.LocalUser.Value; testScoreInfo2.Rank = ScoreRank.S; - testScoreInfo2.TotalScore = testScoreInfo.TotalScore + 1; + testScoreInfo2.TotalScore = testScoreInfo.AsNonNull().TotalScore + 1; testScoreInfo2.Statistics = new Dictionary { [HitResult.Miss] = 0, @@ -153,7 +152,7 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestLegacyScore() { - ScoreInfo testScoreInfo = null; + ScoreInfo? testScoreInfo = null; AddStep("Add legacy score for current user", () => { @@ -184,10 +183,10 @@ namespace osu.Game.Tests.Visual.SongSelect [HitResult.SmallBonus] = 50 }; - testScoreInfo2.TotalScore = scoreManager.GetTotalScoreAsync(testScoreInfo).GetResultSafely(); + testScoreInfo2.TotalScore = scoreManager.GetTotalScoreAsync(testScoreInfo.AsNonNull()).GetResultSafely(); // ensure standardised total score is less than classic, otherwise this test is pointless. - Debug.Assert(testScoreInfo2.TotalScore < testScoreInfo.TotalScore); + Debug.Assert(testScoreInfo2.TotalScore < testScoreInfo.AsNonNull().TotalScore); scoreManager.Import(testScoreInfo2); }); diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs index d372cb8dbc..2a9dae6712 100644 --- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs +++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.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. -#nullable disable - using System; using System.Linq; using System.Threading; @@ -29,19 +27,19 @@ namespace osu.Game.Screens.Select.Carousel private readonly BeatmapInfo beatmapInfo; [Resolved] - private IBindable ruleset { get; set; } + private IBindable ruleset { get; set; } = null!; [Resolved] - private RealmAccess realm { get; set; } + private RealmAccess realm { get; set; } = null!; [Resolved] - private ScoreManager scoreManager { get; set; } + private ScoreManager scoreManager { get; set; } = null!; [Resolved] - private IAPIProvider api { get; set; } + private IAPIProvider api { get; set; } = null!; - private IDisposable scoreSubscription; - private CancellationTokenSource scoreOrderCancellationSource; + private IDisposable? scoreSubscription; + private CancellationTokenSource? scoreOrderCancellationSource; private readonly UpdateableRank updateable; @@ -78,7 +76,7 @@ namespace osu.Game.Screens.Select.Carousel localScoresChanged); }, true); - void localScoresChanged(IRealmCollection sender, ChangeSet changes, Exception error) + void localScoresChanged(IRealmCollection sender, ChangeSet? changes, Exception _) { // This subscription may fire from changes to linked beatmaps, which we don't care about. // It's currently not possible for a score to be modified after insertion, so we can safely ignore callbacks with only modifications. From 33b442d5d094fc8744bc655b000b6c571b9009ac Mon Sep 17 00:00:00 2001 From: LukynkaCZE <48604271+LukynkaCZE@users.noreply.github.com> Date: Sat, 23 Jul 2022 12:06:30 +0200 Subject: [PATCH 0149/2686] Add missing icons to UserProfileRecentSection --- .../Profile/Sections/Recent/BeatmapIcon.cs | 93 ++++++++++++++++ .../Sections/Recent/DrawableRecentActivity.cs | 101 ++++++++++++++++++ .../Profile/Sections/Recent/OtherIcon.cs | 26 +++++ .../Profile/Sections/Recent/SupporterIcon.cs | 59 ++++++++++ 4 files changed, 279 insertions(+) create mode 100644 osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs diff --git a/osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs new file mode 100644 index 0000000000..fd2000a556 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs @@ -0,0 +1,93 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Allocation; +using osu.Game.Graphics; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Profile.Sections.Recent +{ + public class BeatmapIcon : Container + { + private SpriteIcon icon; + private BeatmapActionType type; + + public enum BeatmapActionType + { + PlayedTimes, + Qualified, + Deleted, + Revived, + Updated, + Submitted + } + + public BeatmapIcon(BeatmapActionType type) + { + this.type = type; + Child = icon = new SpriteIcon + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + icon.Icon = getIcon(type); + icon.Colour = getColor(type, colours); + } + + private IconUsage getIcon(BeatmapActionType type) + { + switch (type) + { + case BeatmapActionType.Qualified: + + case BeatmapActionType.Submitted: + return FontAwesome.Solid.ArrowUp; + + case BeatmapActionType.Updated: + return FontAwesome.Solid.SyncAlt; + + case BeatmapActionType.Revived: + return FontAwesome.Solid.TrashRestore; + + case BeatmapActionType.Deleted: + return FontAwesome.Solid.TrashAlt; + + case BeatmapActionType.PlayedTimes: + return FontAwesome.Solid.Play; + + default: + return FontAwesome.Solid.Map; + } + } + + private Color4 getColor(BeatmapActionType type, OsuColour colours) + { + switch (type) + { + case BeatmapActionType.Qualified: + return colours.Blue1; + + case BeatmapActionType.Submitted: + return colours.Yellow; + + case BeatmapActionType.Updated: + return colours.Lime1; + + case BeatmapActionType.Deleted: + return colours.Red1; + + default: + return Color4.White; + } + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 943c105008..5acbb58049 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -16,6 +16,8 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Online.Leaderboards; using osu.Game.Rulesets; +using static osu.Game.Overlays.Profile.Sections.Recent.BeatmapIcon; +using static osu.Game.Overlays.Profile.Sections.Recent.SupporterIcon; namespace osu.Game.Overlays.Profile.Sections.Recent { @@ -119,6 +121,105 @@ namespace osu.Game.Overlays.Profile.Sections.Recent Height = 18 }; + case RecentActivityType.UserSupportAgain: + return new SupporterIcon(SupporterType.SupportAgain) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + + case RecentActivityType.UserSupportFirst: + return new SupporterIcon(SupporterType.SupportFirst) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + + case RecentActivityType.UserSupportGift: + return new SupporterIcon(SupporterType.SupportGift) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + + case RecentActivityType.BeatmapsetUpload: + return new BeatmapIcon(BeatmapActionType.Submitted) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + + case RecentActivityType.BeatmapsetUpdate: + return new BeatmapIcon(BeatmapActionType.Updated) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + + case RecentActivityType.BeatmapsetRevive: + return new BeatmapIcon(BeatmapActionType.Revived) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + + case RecentActivityType.BeatmapsetDelete: + return new BeatmapIcon(BeatmapActionType.Deleted) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + + case RecentActivityType.BeatmapsetApprove: + return new BeatmapIcon(BeatmapActionType.Qualified) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + + case RecentActivityType.BeatmapPlaycount: + return new BeatmapIcon(BeatmapActionType.PlayedTimes) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + + case RecentActivityType.RankLost: + return new OtherIcon(FontAwesome.Solid.AngleDoubleDown) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + + case RecentActivityType.UsernameChange: + return new OtherIcon(FontAwesome.Solid.Tag) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; + default: return Empty(); } diff --git a/osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs new file mode 100644 index 0000000000..dbdee9cd7f --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs @@ -0,0 +1,26 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; + +namespace osu.Game.Overlays.Profile.Sections.Recent +{ + public class OtherIcon : Container + { + public OtherIcon(IconUsage inputIcon) + { + { + Child = new SpriteIcon + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Icon = inputIcon, + + }; + } + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs new file mode 100644 index 0000000000..6b9c45d7d6 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs @@ -0,0 +1,59 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Allocation; +using osu.Game.Graphics; + +namespace osu.Game.Overlays.Profile.Sections.Recent +{ + public class SupporterIcon : Container + { + private SpriteIcon icon; + private SupporterType type; + + public enum SupporterType + { + SupportFirst, + SupportAgain, + SupportGift + } + + public SupporterIcon(SupporterType type) + { + this.type = type; + Child = icon = new SpriteIcon + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + icon.Icon = getIcon(type); + icon.Colour = colours.Pink; + } + + private IconUsage getIcon(SupporterType type) + { + switch (type) + { + case SupporterType.SupportFirst: + + case SupporterType.SupportAgain: + return FontAwesome.Solid.Heart; + + case SupporterType.SupportGift: + return FontAwesome.Solid.Gift; + + default: + return FontAwesome.Solid.Heart; + } + } + } +} From 3f2c3413691d1745b7688b01b0fbe159cc633ec2 Mon Sep 17 00:00:00 2001 From: solstice23 Date: Sat, 23 Jul 2022 18:13:19 +0800 Subject: [PATCH 0150/2686] Simplify length parsing --- .../Filtering/FilterQueryParserTest.cs | 1 + osu.Game/Screens/Select/FilterQueryParser.cs | 42 ++++++++++--------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index f08bd09cf5..181b740729 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -138,6 +138,7 @@ namespace osu.Game.Tests.NonVisual.Filtering new object[] { "65m", TimeSpan.FromMinutes(65), TimeSpan.FromMinutes(1), true }, new object[] { "90s", TimeSpan.FromSeconds(90), TimeSpan.FromSeconds(1), true }, new object[] { "80m20s", TimeSpan.FromSeconds(4820), TimeSpan.FromSeconds(1), true }, + new object[] { "1h20s", TimeSpan.FromSeconds(3620), TimeSpan.FromSeconds(1), true }, new object[] { "7.5m27s", new TimeSpan(), new TimeSpan(), false }, new object[] { "7m27", new TimeSpan(), new TimeSpan(), false }, new object[] { "7m7m7m", new TimeSpan(), new TimeSpan(), false }, diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index b8c85c5ce0..19fb8665d2 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -129,6 +129,16 @@ namespace osu.Game.Screens.Select value = Enum.GetNames(typeof(TEnum)).FirstOrDefault(name => name.StartsWith(value, true, CultureInfo.InvariantCulture)); return Enum.TryParse(value, true, out result); } + private static bool tryMatchRegex(string value, string regex, ref GroupCollection result) + { + Match matchs = Regex.Match(value, regex); + if (matchs.Success) + { + result = matchs.Groups; + return true; + } + return false; + } /// /// Attempts to parse a keyword filter with the specified and textual . @@ -314,28 +324,22 @@ namespace osu.Game.Screens.Select private static bool tryUpdateLengthRange(FilterCriteria criteria, Operator op, string val) { List parts = new List(); + GroupCollection groups = null; - if (Regex.IsMatch(val, @"^\d+(:\d+){1,2}$")) // formats like 12:34 + if ( + tryMatchRegex(val, @"^((?\d+):)?(?\d+):(?\d+)$", ref groups) || + tryMatchRegex(val, @"^((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$", ref groups) || + tryMatchRegex(val, @"^(?\d+(\.\d+)?)$", ref groups) + ) { - List splitted = val.Split(':').ToList(); - while (splitted.Count < 3) - splitted.Insert(0, "0"); - - parts.Add(splitted[2] + 's'); - parts.Add(splitted[1] + 'm'); - parts.Add(splitted[0] + 'h'); + if (groups["seconds"].Success) + parts.Add(groups["seconds"].Value + "s"); + if (groups["minutes"].Success) + parts.Add(groups["minutes"].Value + "m"); + if (groups["hours"].Success) + parts.Add(groups["hours"].Value + "h"); } - else if (Regex.IsMatch(val, @"^(\d+(\.\d+)?[hms]){1,3}$") && "hms".Contains(Regex.Replace(val, @"[\d\.]", ""))) // formats like 1h2m3s - { - string[] splitted = Regex.Split(val, @"(?<=[hms])").Where(x => x.Length > 0).Reverse().ToArray(); - parts.AddRange(splitted); - } - else if (Regex.IsMatch(val, @"^\d+(\.\d+)?$")) // only one number - { - parts.Add(val + 's'); - } - - if (parts.Count == 0) + else return false; double totalLength = 0; From 9db06fafd0b615b648076d1d875a7ea6fbc98d2d Mon Sep 17 00:00:00 2001 From: LukynkaCZE <48604271+LukynkaCZE@users.noreply.github.com> Date: Sat, 23 Jul 2022 12:16:11 +0200 Subject: [PATCH 0151/2686] Fix code formatting --- osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs index dbdee9cd7f..57513b3132 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs @@ -18,7 +18,6 @@ namespace osu.Game.Overlays.Profile.Sections.Recent Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = inputIcon, - }; } } From 1aa0d49d818fb23910dd3593be545ce2e8d87631 Mon Sep 17 00:00:00 2001 From: LukynkaCZE <48604271+LukynkaCZE@users.noreply.github.com> Date: Sat, 23 Jul 2022 12:27:24 +0200 Subject: [PATCH 0152/2686] Code Quality --- osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs | 4 ++-- osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs index fd2000a556..9fac1caff4 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs @@ -12,8 +12,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent { public class BeatmapIcon : Container { - private SpriteIcon icon; - private BeatmapActionType type; + private readonly SpriteIcon icon; + private readonly BeatmapActionType type; public enum BeatmapActionType { diff --git a/osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs index 6b9c45d7d6..fa9b5641f0 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs @@ -11,8 +11,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent { public class SupporterIcon : Container { - private SpriteIcon icon; - private SupporterType type; + private readonly SpriteIcon icon; + private readonly SupporterType type; public enum SupporterType { From aaad2e474ce271166de0aa9655352cc70cd4db07 Mon Sep 17 00:00:00 2001 From: solstice23 Date: Sat, 23 Jul 2022 21:43:27 +0800 Subject: [PATCH 0153/2686] Refactor the multiple regex checks in criteria parsing --- osu.Game/Screens/Select/FilterQueryParser.cs | 35 +++++++++----------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 19fb8665d2..75574c061d 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -129,15 +129,14 @@ namespace osu.Game.Screens.Select value = Enum.GetNames(typeof(TEnum)).FirstOrDefault(name => name.StartsWith(value, true, CultureInfo.InvariantCulture)); return Enum.TryParse(value, true, out result); } - private static bool tryMatchRegex(string value, string regex, ref GroupCollection result) + private static GroupCollection tryMatchRegex(string value, string regex) { Match matchs = Regex.Match(value, regex); if (matchs.Success) { - result = matchs.Groups; - return true; + return matchs.Groups; } - return false; + return null; } /// @@ -324,24 +323,22 @@ namespace osu.Game.Screens.Select private static bool tryUpdateLengthRange(FilterCriteria criteria, Operator op, string val) { List parts = new List(); - GroupCollection groups = null; - if ( - tryMatchRegex(val, @"^((?\d+):)?(?\d+):(?\d+)$", ref groups) || - tryMatchRegex(val, @"^((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$", ref groups) || - tryMatchRegex(val, @"^(?\d+(\.\d+)?)$", ref groups) - ) - { - if (groups["seconds"].Success) - parts.Add(groups["seconds"].Value + "s"); - if (groups["minutes"].Success) - parts.Add(groups["minutes"].Value + "m"); - if (groups["hours"].Success) - parts.Add(groups["hours"].Value + "h"); - } - else + GroupCollection match = null; + match ??= tryMatchRegex(val, @"^((?\d+):)?(?\d+):(?\d+)$"); + match ??= tryMatchRegex(val, @"^((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); + match ??= tryMatchRegex(val, @"^(?\d+(\.\d+)?)$"); + + if (match == null) return false; + if (match["seconds"].Success) + parts.Add(match["seconds"].Value + "s"); + if (match["minutes"].Success) + parts.Add(match["minutes"].Value + "m"); + if (match["hours"].Success) + parts.Add(match["hours"].Value + "h"); + double totalLength = 0; int minScale = 3600000; From ea97122425706078cd91944eb099dff9f4d8311d Mon Sep 17 00:00:00 2001 From: solstice23 Date: Sat, 23 Jul 2022 21:47:51 +0800 Subject: [PATCH 0154/2686] Separate positive and negative test cases --- .../Filtering/FilterQueryParserTest.cs | 91 ++++++++++--------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 181b740729..ac16c59e5b 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -118,56 +118,63 @@ namespace osu.Game.Tests.NonVisual.Filtering Assert.IsNull(filterCriteria.BPM.Max); } - private static readonly object[] length_query_examples = + private static readonly object[] correct_length_query_examples = { - new object[] { "23s", TimeSpan.FromSeconds(23), TimeSpan.FromSeconds(1), true }, - new object[] { "9m", TimeSpan.FromMinutes(9), TimeSpan.FromMinutes(1), true }, - new object[] { "0.25h", TimeSpan.FromHours(0.25), TimeSpan.FromHours(1), true }, - new object[] { "70", TimeSpan.FromSeconds(70), TimeSpan.FromSeconds(1), true }, - new object[] { "7m27s", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1), true }, - new object[] { "7:27", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1), true }, - new object[] { "1h2m3s", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1), true }, - new object[] { "1h2m3.5s", TimeSpan.FromSeconds(3723.5), TimeSpan.FromSeconds(1), true }, - new object[] { "1:2:3", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1), true }, - new object[] { "1:02:03", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1), true }, - new object[] { "6", TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(1), true }, - new object[] { "6.5", TimeSpan.FromSeconds(6.5), TimeSpan.FromSeconds(1), true }, - new object[] { "6.5s", TimeSpan.FromSeconds(6.5), TimeSpan.FromSeconds(1), true }, - new object[] { "6.5m", TimeSpan.FromMinutes(6.5), TimeSpan.FromMinutes(1), true }, - new object[] { "6h5m", TimeSpan.FromMinutes(365), TimeSpan.FromMinutes(1), true }, - new object[] { "65m", TimeSpan.FromMinutes(65), TimeSpan.FromMinutes(1), true }, - new object[] { "90s", TimeSpan.FromSeconds(90), TimeSpan.FromSeconds(1), true }, - new object[] { "80m20s", TimeSpan.FromSeconds(4820), TimeSpan.FromSeconds(1), true }, - new object[] { "1h20s", TimeSpan.FromSeconds(3620), TimeSpan.FromSeconds(1), true }, - new object[] { "7.5m27s", new TimeSpan(), new TimeSpan(), false }, - new object[] { "7m27", new TimeSpan(), new TimeSpan(), false }, - new object[] { "7m7m7m", new TimeSpan(), new TimeSpan(), false }, - new object[] { "7m70s", new TimeSpan(), new TimeSpan(), false }, - new object[] { "5s6m", new TimeSpan(), new TimeSpan(), false }, - new object[] { "0:", new TimeSpan(), new TimeSpan(), false }, - new object[] { ":0", new TimeSpan(), new TimeSpan(), false }, - new object[] { "0:3:", new TimeSpan(), new TimeSpan(), false }, - new object[] { "3:15.5", new TimeSpan(), new TimeSpan(), false }, + new object[] { "23s", TimeSpan.FromSeconds(23), TimeSpan.FromSeconds(1) }, + new object[] { "9m", TimeSpan.FromMinutes(9), TimeSpan.FromMinutes(1) }, + new object[] { "0.25h", TimeSpan.FromHours(0.25), TimeSpan.FromHours(1) }, + new object[] { "70", TimeSpan.FromSeconds(70), TimeSpan.FromSeconds(1) }, + new object[] { "7m27s", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1) }, + new object[] { "7:27", TimeSpan.FromSeconds(447), TimeSpan.FromSeconds(1) }, + new object[] { "1h2m3s", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1) }, + new object[] { "1h2m3.5s", TimeSpan.FromSeconds(3723.5), TimeSpan.FromSeconds(1) }, + new object[] { "1:2:3", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1) }, + new object[] { "1:02:03", TimeSpan.FromSeconds(3723), TimeSpan.FromSeconds(1) }, + new object[] { "6", TimeSpan.FromSeconds(6), TimeSpan.FromSeconds(1) }, + new object[] { "6.5", TimeSpan.FromSeconds(6.5), TimeSpan.FromSeconds(1) }, + new object[] { "6.5s", TimeSpan.FromSeconds(6.5), TimeSpan.FromSeconds(1) }, + new object[] { "6.5m", TimeSpan.FromMinutes(6.5), TimeSpan.FromMinutes(1) }, + new object[] { "6h5m", TimeSpan.FromMinutes(365), TimeSpan.FromMinutes(1) }, + new object[] { "65m", TimeSpan.FromMinutes(65), TimeSpan.FromMinutes(1) }, + new object[] { "90s", TimeSpan.FromSeconds(90), TimeSpan.FromSeconds(1) }, + new object[] { "80m20s", TimeSpan.FromSeconds(4820), TimeSpan.FromSeconds(1) }, + new object[] { "1h20s", TimeSpan.FromSeconds(3620), TimeSpan.FromSeconds(1) }, }; [Test] - [TestCaseSource(nameof(length_query_examples))] - public void TestApplyLengthQueries(string lengthQuery, TimeSpan expectedLength, TimeSpan scale, bool isValid) + [TestCaseSource(nameof(correct_length_query_examples))] + public void TestApplyLengthQueries(string lengthQuery, TimeSpan expectedLength, TimeSpan scale) { string query = $"length={lengthQuery} time"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); - if (isValid) - { - Assert.AreEqual("time", filterCriteria.SearchText.Trim()); - Assert.AreEqual(1, filterCriteria.SearchTerms.Length); - Assert.AreEqual(expectedLength.TotalMilliseconds - scale.TotalMilliseconds / 2.0, filterCriteria.Length.Min); - Assert.AreEqual(expectedLength.TotalMilliseconds + scale.TotalMilliseconds / 2.0, filterCriteria.Length.Max); - } - else - { - Assert.AreEqual(false, filterCriteria.Length.HasFilter); - } + Assert.AreEqual("time", filterCriteria.SearchText.Trim()); + Assert.AreEqual(1, filterCriteria.SearchTerms.Length); + Assert.AreEqual(expectedLength.TotalMilliseconds - scale.TotalMilliseconds / 2.0, filterCriteria.Length.Min); + Assert.AreEqual(expectedLength.TotalMilliseconds + scale.TotalMilliseconds / 2.0, filterCriteria.Length.Max); + } + + private static readonly object[] incorrect_length_query_examples = + { + new object[] { "7.5m27s" }, + new object[] { "7m27" }, + new object[] { "7m7m7m" }, + new object[] { "7m70s" }, + new object[] { "5s6m" }, + new object[] { "0:" }, + new object[] { ":0" }, + new object[] { "0:3:" }, + new object[] { "3:15.5" }, + }; + + [Test] + [TestCaseSource(nameof(incorrect_length_query_examples))] + public void TestInvalidLengthQueries(string lengthQuery) + { + string query = $"length={lengthQuery} time"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual(false, filterCriteria.Length.HasFilter); } [Test] From 16e655766eeb253f4a127bdc34d2dc3247092ba2 Mon Sep 17 00:00:00 2001 From: mk-56 Date: Sat, 23 Jul 2022 23:30:57 +0200 Subject: [PATCH 0155/2686] Addressed pertinent issues --- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index 185751cf3d..52ed843c4c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -26,13 +26,16 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform), typeof(OsuModMagnetised), typeof(OsuModRepel) }; - [SettingSource("Strength")] + private const int wiggle_duration = 100; // (ms) Higher = fewer wiggles + + [SettingSource("Strength", "Multiplier applied to the wiggling strength.")] public BindableDouble WiggleStrength { get; } = new BindableDouble(1) { MinValue = 0.1f, MaxValue = 2f, Precision = 0.1f }; + protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => drawableOnApplyCustomUpdateState(hitObject, state); protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => drawableOnApplyCustomUpdateState(hitObject, state); @@ -50,18 +53,18 @@ namespace osu.Game.Rulesets.Osu.Mods Random objRand = new Random((int)osuObject.StartTime); // Wiggle all objects during TimePreempt - int amountWiggles = (int)osuObject.TimePreempt / 70; + int amountWiggles = (int)osuObject.TimePreempt / wiggle_duration; void wiggle() { float nextAngle = (float)(objRand.NextDouble() * 2 * Math.PI); float nextDist = (float)(objRand.NextDouble() * WiggleStrength.Value * 7); - drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), 70); + drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), wiggle_duration); } for (int i = 0; i < amountWiggles; i++) { - using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * 70)) + using (drawable.BeginAbsoluteSequence(osuObject.StartTime - osuObject.TimePreempt + i * wiggle_duration)) wiggle(); } @@ -69,11 +72,11 @@ namespace osu.Game.Rulesets.Osu.Mods if (!(osuObject is IHasDuration endTime)) return; - amountWiggles = (int)(endTime.Duration / 70); + amountWiggles = (int)(endTime.Duration / wiggle_duration); for (int i = 0; i < amountWiggles; i++) { - using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * 70)) + using (drawable.BeginAbsoluteSequence(osuObject.StartTime + i * wiggle_duration)) wiggle(); } } From 0a0f3c93ddf5574feb583b036808945f2a7be073 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Sun, 24 Jul 2022 20:55:13 +0200 Subject: [PATCH 0156/2686] Rename OkResult, rephrase "strong bonus" --- osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs | 2 +- osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs index 90ba7e276c..6d469bd1d7 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements /// /// The to grant when the player has hit more than half of swell ticks. /// - public virtual HitResult OkResult => HitResult.Ok; + public virtual HitResult PartialCompletionResult => HitResult.Ok; protected override double HealthIncreaseFor(HitResult result) { diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index ec4ad18080..efb67825db 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public override HitResult MaxResult => HitResult.LargeBonus; - public override HitResult OkResult => HitResult.SmallBonus; + public override HitResult PartialCompletionResult => HitResult.SmallBonus; } private class ClassicSwell : Swell diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index cb0f59a9fb..a90e9ce676 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -225,7 +225,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables ApplyResult(r => { var swellJudgement = (TaikoSwellJudgement)r.Judgement; - r.Type = numHits > HitObject.RequiredHits / 2 ? swellJudgement.OkResult : swellJudgement.MinResult; + r.Type = numHits > HitObject.RequiredHits / 2 ? swellJudgement.PartialCompletionResult : swellJudgement.MinResult; }); } } diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 223e268d7f..eb0706f131 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -200,7 +200,7 @@ namespace osu.Game.Rulesets.Taiko return "drum tick"; case HitResult.SmallBonus: - return "strong bonus"; + return "bonus"; } return base.GetDisplayNameForHitResult(result); From f68c4e889017b5dc9e4fa01fdd253bf13cf4681f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 25 Jul 2022 06:36:21 +0300 Subject: [PATCH 0157/2686] Fix code formatting --- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index 52ed843c4c..e22ba5c1db 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform), typeof(OsuModMagnetised), typeof(OsuModRepel) }; - private const int wiggle_duration = 100; // (ms) Higher = fewer wiggles + private const int wiggle_duration = 100; // (ms) Higher = fewer wiggles [SettingSource("Strength", "Multiplier applied to the wiggling strength.")] public BindableDouble WiggleStrength { get; } = new BindableDouble(1) From e28584da89b2694ebbaff3e75c91a7747594207e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 23:44:14 +0800 Subject: [PATCH 0158/2686] Remove nullable disable annotation in the Osu ruleset. --- osu.Game.Rulesets.Osu/Mods/IHidesApproachCircles.cs | 2 -- osu.Game.Rulesets.Osu/Mods/IRequiresApproachCircles.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModDaycore.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModDoubleTime.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModHalfTime.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModNightcore.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModNoFail.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModPerfect.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 4 +--- osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 2 -- 37 files changed, 1 insertion(+), 75 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/IHidesApproachCircles.cs b/osu.Game.Rulesets.Osu/Mods/IHidesApproachCircles.cs index affc0bae6a..4a3b187e83 100644 --- a/osu.Game.Rulesets.Osu/Mods/IHidesApproachCircles.cs +++ b/osu.Game.Rulesets.Osu/Mods/IHidesApproachCircles.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. -#nullable disable - namespace osu.Game.Rulesets.Osu.Mods { /// diff --git a/osu.Game.Rulesets.Osu/Mods/IRequiresApproachCircles.cs b/osu.Game.Rulesets.Osu/Mods/IRequiresApproachCircles.cs index a108f5fd14..1458abfe05 100644 --- a/osu.Game.Rulesets.Osu/Mods/IRequiresApproachCircles.cs +++ b/osu.Game.Rulesets.Osu/Mods/IRequiresApproachCircles.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. -#nullable disable - namespace osu.Game.Rulesets.Osu.Mods { /// diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs index e25845f5ab..e6889403a3 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.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. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index a3f6448457..2d579e511e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs index c4de77b8a3..7c1f6be9ed 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutoplay.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs index 71bdd98457..9e71f657ce 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.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. -#nullable disable - using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 17a9a81de8..e3aa8f93d0 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs b/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs index d5096619b9..769694baf4 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModCinema.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModCinema.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs index 00009f4c3d..e021992f86 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModClassic.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModClassic.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. -#nullable disable - using System; using System.Linq; using osu.Framework.Bindables; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDaycore.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDaycore.cs index c4cc0b4f48..371dfe6a1a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDaycore.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDaycore.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. -#nullable disable - using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Osu.Mods diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs index e95e61312e..ee6a7815e2 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.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. -#nullable disable - using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs index be159523b7..3a6b232f9f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.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. -#nullable disable - using System.Linq; using osu.Game.Beatmaps; using osu.Game.Configuration; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDoubleTime.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDoubleTime.cs index b86efe84ee..700a3f44bc 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDoubleTime.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDoubleTime.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. -#nullable disable - using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Osu.Mods diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs b/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs index 90b22e8d9c..06b5b6cfb8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModEasy.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. -#nullable disable - using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Osu.Mods diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index b72e6b4dcb..25b900752c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.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. -#nullable disable - using System; using System.Linq; using osu.Framework.Bindables; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index 34840de983..182d6eeb4b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.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. -#nullable disable - using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHalfTime.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHalfTime.cs index 54c5c56ca6..4769e7660b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHalfTime.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHalfTime.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. -#nullable disable - using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Osu.Mods diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index 1f25655c8c..5430929143 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.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. -#nullable disable - using System; using System.Linq; using osu.Game.Rulesets.Mods; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index 253eaf473b..97f201b2cc 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.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. -#nullable disable - using System; using System.Diagnostics; using System.Linq; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs index f9a74d2a3a..97a573f1b4 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.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. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs index 1d822a2d4c..3faca0b01f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.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. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Game.Configuration; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs index 1d4650a379..5e3ee37b61 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMuted.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. -#nullable disable - using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNightcore.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNightcore.cs index b1fe066a1e..b7838ebaa7 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModNightcore.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModNightcore.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. -#nullable disable - using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoFail.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoFail.cs index c20fcf0b1b..9f707a5aa6 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModNoFail.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoFail.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. -#nullable disable - using System; using System.Linq; using osu.Game.Rulesets.Mods; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs index fe415cb967..8e377ea632 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.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. -#nullable disable - using System; using System.Linq; using osu.Framework.Bindables; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs index 44942e9e37..59984f9a7b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.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. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModPerfect.cs b/osu.Game.Rulesets.Osu/Mods/OsuModPerfect.cs index bde7718da5..33581405a6 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModPerfect.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModPerfect.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. -#nullable disable - using System; using System.Linq; using osu.Game.Rulesets.Mods; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 2030156f2e..4c70b8f22c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.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. -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs index 16e7780af0..95e7d13ee7 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.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. -#nullable disable - using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index 61028a1ee8..d9ab749ad3 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.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. -#nullable disable - using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index 565ff415be..0b34ab28a3 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.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. -#nullable disable - using System; using System.Linq; using System.Threading; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs index 4eb7659152..429fe30fc5 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.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. -#nullable disable - using System; using System.Linq; using osu.Game.Rulesets.Mods; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index f03bcffdc8..43169dac68 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs index f8c1e1639d..7276cc753c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.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. -#nullable disable - using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Osu.Mods diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index 6e5dd45a7a..d862d36670 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.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. -#nullable disable - using System; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -59,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Mods } } - private void applyCirclePieceState(DrawableOsuHitObject hitObject, IDrawable hitCircle = null) + private void applyCirclePieceState(DrawableOsuHitObject hitObject, IDrawable? hitCircle = null) { var h = hitObject.HitObject; using (hitObject.BeginAbsoluteSequence(h.StartTime - h.TimePreempt)) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs index 84906f6eed..4354ecbe9a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.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. -#nullable disable - using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index 8acd4fc422..6bfbe25471 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.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. -#nullable disable - using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; From deb39bd33030194a3d35a3167441333af07d9805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 23:49:38 +0800 Subject: [PATCH 0159/2686] Mark the property as nullable or non-nullable. --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 4 ++-- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index e3aa8f93d0..39234147a9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -53,9 +53,9 @@ namespace osu.Game.Rulesets.Osu.Mods /// /// Black background boxes behind blind panel textures. /// - private Box blackBoxLeft, blackBoxRight; + private Box blackBoxLeft = null!, blackBoxRight = null!; - private Drawable panelLeft, panelRight, bgPanelLeft, bgPanelRight; + private Drawable panelLeft = null!, panelRight = null!, bgPanelLeft = null!, bgPanelRight = null!; private readonly Beatmap beatmap; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 4c70b8f22c..c9c3fdfc89 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Mods private OsuInputManager osuInputManager; - private ReplayState state; + private ReplayState? state; private double lastStateChangeTime; private bool hasReplay; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 43169dac68..29f5b8f512 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -403,7 +403,7 @@ namespace osu.Game.Rulesets.Osu.Mods /// The list of hit objects in a beatmap, ordered by StartTime /// The point in time to get samples for /// Hit samples - private IList getSamplesAtTime(IEnumerable hitObjects, double time) + private IList? getSamplesAtTime(IEnumerable hitObjects, double time) { // Get a hit object that // either has StartTime equal to the target time From 9134525111130704a23ab0788c549449b6e1763b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=82=BA=E4=BB=80=E9=BA=BC?= Date: Sun, 10 Jul 2022 23:47:57 +0800 Subject: [PATCH 0160/2686] Mark the property as nullable and add some assert check. --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 12 +++++++--- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 5 ++++- .../Mods/OsuModFlashlight.cs | 5 +++-- .../Mods/OsuModMagnetised.cs | 5 ++++- osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs | 5 +++-- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 6 ++++- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 22 ++++++++++++++----- 7 files changed, 45 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 2d579e511e..03cc1a9305 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -3,7 +3,9 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.StateChanges; using osu.Game.Graphics; @@ -28,16 +30,20 @@ namespace osu.Game.Rulesets.Osu.Mods public bool RestartOnFail => false; - private OsuInputManager inputManager; + private OsuInputManager? inputManager; - private IFrameStableClock gameplayClock; + private IFrameStableClock? gameplayClock; - private List replayFrames; + private List? replayFrames; private int currentFrame; public void Update(Playfield playfield) { + Debug.Assert(inputManager != null); + Debug.Assert(gameplayClock != null); + Debug.Assert(replayFrames != null); + if (currentFrame == replayFrames.Count - 1) return; double time = gameplayClock.CurrentTime; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 39234147a9..35054a50db 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -31,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModFlashlight) }; - private DrawableOsuBlinds blinds; + private DrawableOsuBlinds? blinds; public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { @@ -40,6 +41,8 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToHealthProcessor(HealthProcessor healthProcessor) { + Debug.Assert(blinds != null); + healthProcessor.Health.ValueChanged += health => { blinds.AnimateClosedness((float)health.NewValue); }; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index 25b900752c..510e95b13f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Events; @@ -51,14 +52,14 @@ namespace osu.Game.Rulesets.Osu.Mods public override float DefaultFlashlightSize => 180; - private OsuFlashlight flashlight; + private OsuFlashlight? flashlight; protected override Flashlight CreateFlashlight() => flashlight = new OsuFlashlight(this); public void ApplyToDrawableHitObject(DrawableHitObject drawable) { if (drawable is DrawableSlider s) - s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange; + s.Tracking.ValueChanged += flashlight.AsNonNull().OnSliderTrackingChange; } private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs index 97a573f1b4..107eac6430 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; @@ -26,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel) }; - private IFrameStableClock gameplayClock; + private IFrameStableClock? gameplayClock; [SettingSource("Attraction strength", "How strong the pull is.", 0)] public BindableFloat AttractionStrength { get; } = new BindableFloat(0.5f) @@ -74,6 +75,8 @@ namespace osu.Game.Rulesets.Osu.Mods { double dampLength = Interpolation.Lerp(3000, 40, AttractionStrength.Value); + Debug.Assert(gameplayClock != null); + float x = (float)Interpolation.DampContinuously(hitObject.X, destination.X, dampLength, gameplayClock.ElapsedFrameTime); float y = (float)Interpolation.DampContinuously(hitObject.Y, destination.Y, dampLength, gameplayClock.ElapsedFrameTime); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs index 8e377ea632..0197b7cb1b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -19,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Description => "Where's the cursor?"; - private PeriodTracker spinnerPeriods; + private PeriodTracker? spinnerPeriods; [SettingSource( "Hidden at combo", @@ -41,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void Update(Playfield playfield) { - bool shouldAlwaysShowCursor = IsBreakTime.Value || spinnerPeriods.IsInAny(playfield.Clock.CurrentTime); + bool shouldAlwaysShowCursor = IsBreakTime.Value || spinnerPeriods.AsNonNull().IsInAny(playfield.Clock.CurrentTime); float targetAlpha = shouldAlwaysShowCursor ? 1 : ComboBasedAlpha; playfield.Cursor.Alpha = (float)Interpolation.Lerp(playfield.Cursor.Alpha, targetAlpha, Math.Clamp(playfield.Time.Elapsed / TRANSITION_DURATION, 0, 1)); } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index c9c3fdfc89..ac45ce2ade 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Mods private bool isDownState; private bool wasLeft; - private OsuInputManager osuInputManager; + private OsuInputManager? osuInputManager; private ReplayState? state; private double lastStateChangeTime; @@ -44,6 +44,8 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToPlayer(Player player) { + Debug.Assert(osuInputManager != null); + if (osuInputManager.ReplayInputHandler != null) { hasReplay = true; @@ -132,6 +134,8 @@ namespace osu.Game.Rulesets.Osu.Mods wasLeft = !wasLeft; } + Debug.Assert(osuInputManager != null); + state?.Apply(osuInputManager.CurrentState, osuInputManager); } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 29f5b8f512..36f21ba291 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -3,8 +3,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; @@ -94,11 +96,11 @@ namespace osu.Game.Rulesets.Osu.Mods #region Private Fields - private ControlPointInfo controlPointInfo; + private ControlPointInfo? controlPointInfo; - private List originalHitObjects; + private List? originalHitObjects; - private Random rng; + private Random? rng; #endregion @@ -158,7 +160,7 @@ namespace osu.Game.Rulesets.Osu.Mods circle.ApproachCircle.Hide(); } - using (circle.BeginAbsoluteSequence(startTime - controlPointInfo.TimingPointAt(startTime).BeatLength - undim_duration)) + using (circle.BeginAbsoluteSequence(startTime - controlPointInfo.AsNonNull().TimingPointAt(startTime).BeatLength - undim_duration)) circle.FadeColour(Color4.White, undim_duration); } @@ -200,6 +202,8 @@ namespace osu.Game.Rulesets.Osu.Mods private IEnumerable generateBeats(IBeatmap beatmap) { + Debug.Assert(originalHitObjects != null); + double startTime = originalHitObjects.First().StartTime; double endTime = originalHitObjects.Last().GetEndTime(); @@ -228,6 +232,8 @@ namespace osu.Game.Rulesets.Osu.Mods private void addHitSamples(IEnumerable hitObjects) { + Debug.Assert(originalHitObjects != null); + foreach (var obj in hitObjects) { var samples = getSamplesAtTime(originalHitObjects, obj.StartTime); @@ -240,6 +246,8 @@ namespace osu.Game.Rulesets.Osu.Mods private void fixComboInfo(List hitObjects) { + Debug.Assert(originalHitObjects != null); + // Copy combo indices from an original object at the same time or from the closest preceding object // (Objects lying between two combos are assumed to belong to the preceding combo) hitObjects.ForEach(newObj => @@ -276,7 +284,7 @@ namespace osu.Game.Rulesets.Osu.Mods { if (hitObjects.Count == 0) return; - float nextSingle(float max = 1f) => (float)(rng.NextDouble() * max); + float nextSingle(float max = 1f) => (float)(rng.AsNonNull().NextDouble() * max); const float two_pi = MathF.PI * 2; @@ -357,6 +365,8 @@ namespace osu.Game.Rulesets.Osu.Mods /// The time to be checked.= private bool isInsideBreakPeriod(IEnumerable breaks, double time) { + Debug.Assert(originalHitObjects != null); + return breaks.Any(breakPeriod => { var firstObjAfterBreak = originalHitObjects.First(obj => almostBigger(obj.StartTime, breakPeriod.EndTime)); @@ -372,6 +382,8 @@ namespace osu.Game.Rulesets.Osu.Mods int i = 0; double currentTime = timingPoint.Time; + Debug.Assert(controlPointInfo != null); + while (!definitelyBigger(currentTime, mapEndTime) && ReferenceEquals(controlPointInfo.TimingPointAt(currentTime), timingPoint)) { beats.Add(Math.Floor(currentTime)); From 8fa576557398ce1e51ee262430fdab07ab7bd15e Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 20 Jul 2022 20:34:55 +0800 Subject: [PATCH 0161/2686] Remove nullable disable annotation in the Osu test case. --- osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs | 2 -- .../Mods/TestSceneOsuModAlternate.cs | 2 -- .../Mods/TestSceneOsuModAutoplay.cs | 7 +++---- .../Mods/TestSceneOsuModDifficultyAdjust.cs | 2 -- .../Mods/TestSceneOsuModDoubleTime.cs | 2 -- .../Mods/TestSceneOsuModHidden.cs | 4 +--- .../Mods/TestSceneOsuModMagnetised.cs | 2 -- .../Mods/TestSceneOsuModMuted.cs | 4 +--- .../Mods/TestSceneOsuModNoScope.cs | 2 -- .../Mods/TestSceneOsuModPerfect.cs | 2 -- .../Mods/TestSceneOsuModSpunOut.cs | 12 +++++------- 11 files changed, 10 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs b/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs index 4f005a0c70..d3cb3bcf59 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.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. -#nullable disable - using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests.Mods diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs index 3d59e4fb51..5e46498aca 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.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. -#nullable disable - using System.Collections.Generic; using NUnit.Framework; using osu.Game.Beatmaps; diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs index 378b71ccf7..3563995234 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.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. -#nullable disable - using System.Linq; using NUnit.Framework; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; @@ -35,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods private void runSpmTest(Mod mod) { - SpinnerSpmCalculator spmCalculator = null; + SpinnerSpmCalculator? spmCalculator = null; CreateModTest(new ModTestData { @@ -61,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods return spmCalculator != null; }); - AddUntilStep("SPM is correct", () => Precision.AlmostEquals(spmCalculator.Result.Value, 477, 5)); + AddUntilStep("SPM is correct", () => Precision.AlmostEquals(spmCalculator.AsNonNull().Result.Value, 477, 5)); } } } diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs index 80dc83d7dc..9d06ff5801 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs index e1bed5153b..335ef31019 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.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. -#nullable disable - using NUnit.Framework; using osu.Framework.Utils; using osu.Game.Rulesets.Osu.Mods; diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs index 5ed25baca3..e692f8ecbc 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -162,7 +160,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods private class TestOsuModHidden : OsuModHidden { - public new HitObject FirstObject => base.FirstObject; + public new HitObject? FirstObject => base.FirstObject; } } } diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs index 1f1db04c24..9b49e60363 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.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. -#nullable disable - using NUnit.Framework; using osu.Game.Rulesets.Osu.Mods; diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs index 99c9036ac0..68669d1a53 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.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. -#nullable disable - using System.Linq; using NUnit.Framework; using osu.Framework.Testing; @@ -33,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods [Test] public void TestModCopy() { - OsuModMuted muted = null; + OsuModMuted muted = null!; AddStep("create inversed mod", () => muted = new OsuModMuted { diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs index 47e7ad320c..44404ca245 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs index b7669624ff..985baa8cf5 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.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. -#nullable disable - using NUnit.Framework; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs index 4f6d6376bf..e121e6103d 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -30,8 +28,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods [Test] public void TestSpinnerAutoCompleted() { - DrawableSpinner spinner = null; - JudgementResult lastResult = null; + DrawableSpinner? spinner = null; + JudgementResult? lastResult = null; CreateModTest(new ModTestData { @@ -63,11 +61,11 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods [TestCase(null)] [TestCase(typeof(OsuModDoubleTime))] [TestCase(typeof(OsuModHalfTime))] - public void TestSpinRateUnaffectedByMods(Type additionalModType) + public void TestSpinRateUnaffectedByMods(Type? additionalModType) { var mods = new List { new OsuModSpunOut() }; if (additionalModType != null) - mods.Add((Mod)Activator.CreateInstance(additionalModType)); + mods.Add((Mod)Activator.CreateInstance(additionalModType)!); CreateModTest(new ModTestData { @@ -96,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods [Test] public void TestSpinnerGetsNoBonusScore() { - DrawableSpinner spinner = null; + DrawableSpinner? spinner = null; List results = new List(); CreateModTest(new ModTestData From 0fe64d1e803202028ca9d20c4006641bad961675 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 27 Jul 2022 01:05:50 +0800 Subject: [PATCH 0162/2686] Remove unused namespace. --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 03cc1a9305..83c1deb3b9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.StateChanges; using osu.Game.Graphics; From da7d297d85e4ae5d59747dac3ae8686e1849433f Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Tue, 26 Jul 2022 19:07:25 +0200 Subject: [PATCH 0163/2686] Adjust parameters --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index ef3eaf2a9d..716fa990c9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -43,17 +43,13 @@ namespace osu.Game.Rulesets.Osu.Mods for (int i = 0; i < positionInfos.Count; i++) { - bool invertFlow = false; - if (i == 0 || (positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo && rng.NextDouble() < 0.6) || OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject, true) || - (OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject) && rng.NextDouble() < 0.25)) + (OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject) && rng.NextDouble() < 0.3)) { - sequenceOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.0015f); - - if (rng.NextDouble() < 0.6) - invertFlow = true; + sequenceOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.0012f); + flowDirection = !flowDirection; } if (i == 0) @@ -64,18 +60,13 @@ namespace osu.Game.Rulesets.Osu.Mods else { float flowChangeOffset = 0; - float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.0015f); + float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.002f); if (positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo && rng.NextDouble() < 0.6) { flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.002f); - - if (rng.NextDouble() < 0.8) - invertFlow = true; - } - - if (invertFlow) flowDirection = !flowDirection; + } positionInfos[i].RelativeAngle = getRelativeTargetAngle( positionInfos[i].DistanceFromPrevious, @@ -94,7 +85,7 @@ namespace osu.Game.Rulesets.Osu.Mods /// Whether the relative angle should be positive or negative. private static float getRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) { - float angle = (float)(3 / (1 + 200 * Math.Exp(0.016 * (targetDistance - 466))) + 0.45 + offset); + float angle = (float)(2.16 / (1 + 200 * Math.Exp(0.036 * (targetDistance - 320))) + 0.5 + offset); float relativeAngle = (float)Math.PI - angle; return flowDirection ? -relativeAngle : relativeAngle; } From 8105d4854a53c48617ca7638a989a9442174e69a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Jul 2022 13:30:38 +0900 Subject: [PATCH 0164/2686] Fix beatmap carousel not maintaining selection if currently selected beatmap is updated --- osu.Game/Screens/Select/BeatmapCarousel.cs | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 75caa3c9a3..c6f2b61049 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -265,6 +265,38 @@ namespace osu.Game.Screens.Select foreach (int i in changes.InsertedIndices) UpdateBeatmapSet(sender[i].Detach()); + + if (changes.DeletedIndices.Length > 0) + { + // To handle the beatmap update flow, attempt to track selection changes across delete-insert transactions. + // When an update occurs, the previous beatmap set is either soft or hard deleted. + // Check if the current selection was potentially deleted by re-querying its validity. + bool selectedSetMarkedDeleted = realm.Run(r => r.Find(SelectedBeatmapSet.ID))?.DeletePending != false; + + if (selectedSetMarkedDeleted) + { + // If it is no longer valid, make the bold assumption that an updated version will be available in the modified indices. + // This relies on the full update operation being in a single transaction, so please don't change that. + foreach (int i in changes.NewModifiedIndices) + { + var beatmapSetInfo = sender[i]; + + foreach (var beatmapInfo in beatmapSetInfo.Beatmaps) + { + // Best effort matching. We can't use ID because in the update flow a new version will get its own GUID. + bool selectionMatches = + ((IBeatmapMetadataInfo)beatmapInfo.Metadata).Equals(SelectedBeatmapInfo.Metadata) + && beatmapInfo.DifficultyName == SelectedBeatmapInfo.DifficultyName; + + if (selectionMatches) + { + SelectBeatmap(beatmapInfo); + break; + } + } + } + } + } } private void beatmapsChanged(IRealmCollection sender, ChangeSet changes, Exception error) From 24d75612e222fe3e055d1f5fabf623727dc81727 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Jul 2022 14:18:53 +0900 Subject: [PATCH 0165/2686] Always attempt to follow selection, even if difficulty name / metadata change --- osu.Game/Screens/Select/BeatmapCarousel.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index c6f2b61049..0430c15a1d 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -283,18 +283,21 @@ namespace osu.Game.Screens.Select foreach (var beatmapInfo in beatmapSetInfo.Beatmaps) { - // Best effort matching. We can't use ID because in the update flow a new version will get its own GUID. - bool selectionMatches = - ((IBeatmapMetadataInfo)beatmapInfo.Metadata).Equals(SelectedBeatmapInfo.Metadata) - && beatmapInfo.DifficultyName == SelectedBeatmapInfo.DifficultyName; + if (!((IBeatmapMetadataInfo)beatmapInfo.Metadata).Equals(SelectedBeatmapInfo.Metadata)) + continue; - if (selectionMatches) + // Best effort matching. We can't use ID because in the update flow a new version will get its own GUID. + if (beatmapInfo.DifficultyName == SelectedBeatmapInfo.DifficultyName) { SelectBeatmap(beatmapInfo); - break; + return; } } } + + // If a direct selection couldn't be made, it's feasible that the difficulty name (or beatmap metadata) changed. + // Let's attempt to follow set-level selection anyway. + SelectBeatmap(sender[changes.NewModifiedIndices.First()].Beatmaps.First()); } } } From e6a3659581e62b9c181d1c0ffe4f82a8988a8d05 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 27 Jul 2022 14:23:47 +0900 Subject: [PATCH 0166/2686] Guard against `NewModifiedIndices` being empty --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 0430c15a1d..e9419e7156 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -273,7 +273,7 @@ namespace osu.Game.Screens.Select // Check if the current selection was potentially deleted by re-querying its validity. bool selectedSetMarkedDeleted = realm.Run(r => r.Find(SelectedBeatmapSet.ID))?.DeletePending != false; - if (selectedSetMarkedDeleted) + if (selectedSetMarkedDeleted && changes.NewModifiedIndices.Any()) { // If it is no longer valid, make the bold assumption that an updated version will be available in the modified indices. // This relies on the full update operation being in a single transaction, so please don't change that. From 89644a652e09be0fa46f446921f1e92a094e4a9c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 27 Jul 2022 10:13:40 +0300 Subject: [PATCH 0167/2686] Separate combined fields --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 35054a50db..808e7720a4 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -58,7 +58,10 @@ namespace osu.Game.Rulesets.Osu.Mods /// private Box blackBoxLeft = null!, blackBoxRight = null!; - private Drawable panelLeft = null!, panelRight = null!, bgPanelLeft = null!, bgPanelRight = null!; + private Drawable panelLeft = null!; + private Drawable panelRight = null!; + private Drawable bgPanelLeft = null!; + private Drawable bgPanelRight = null!; private readonly Beatmap beatmap; From e6fad601cc2106e983d13ba9a2383f8500b917ba Mon Sep 17 00:00:00 2001 From: Micahel Kelly Date: Wed, 27 Jul 2022 19:15:43 +1000 Subject: [PATCH 0168/2686] Adds delete difficulty option to editor --- osu.Game/Screens/Edit/Editor.cs | 18 ++++++++++ .../Edit/PromptForDifficultyDeleteDialog.cs | 33 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 3e3940c5ba..5cee634fd8 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -849,6 +849,20 @@ namespace osu.Game.Screens.Edit new LegacyBeatmapExporter(storage).Export(Beatmap.Value.BeatmapSetInfo); } + private void deleteDifficulty() + { + dialogOverlay?.Push(new PromptForDifficultyDeleteDialog(confirmDifficultyDelete, () => { })); + } + + private void confirmDifficultyDelete() + { + var current = playableBeatmap.BeatmapInfo; + if (current is null) return; + + beatmapManager.Hide(current); + this.Exit(); + } + private void updateLastSavedHash() { lastSavedHash = changeHandler?.CurrentStateHash; @@ -869,6 +883,10 @@ namespace osu.Game.Screens.Edit fileMenuItems.Add(createDifficultyCreationMenu()); fileMenuItems.Add(createDifficultySwitchMenu()); + fileMenuItems.Add(new EditorMenuItemSpacer()); + + fileMenuItems.Add(new EditorMenuItem("Delete difficulty", MenuItemType.Standard, deleteDifficulty)); + fileMenuItems.Add(new EditorMenuItemSpacer()); fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit)); return fileMenuItems; diff --git a/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs b/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs new file mode 100644 index 0000000000..abf66d7a5b --- /dev/null +++ b/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs @@ -0,0 +1,33 @@ +// 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.Sprites; +using osu.Game.Overlays.Dialog; + +namespace osu.Game.Screens.Edit +{ + public class PromptForDifficultyDeleteDialog : PopupDialog + { + public PromptForDifficultyDeleteDialog(Action delete, Action cancel) + { + HeaderText = "Are you sure you want to delete this difficulty?"; + + Icon = FontAwesome.Regular.Save; + + Buttons = new PopupDialogButton[] + { + new PopupDialogDangerousButton + { + Text = @"Yes delete this difficulty!", + Action = delete + }, + new PopupDialogCancelButton + { + Text = @"Oops, continue editing", + Action = cancel + }, + }; + } + } +} From 3febd6d6443a75ea3e6d9ff29c390301f0a03872 Mon Sep 17 00:00:00 2001 From: Micahel Kelly Date: Wed, 27 Jul 2022 19:23:55 +1000 Subject: [PATCH 0169/2686] Dialogue touchups --- osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs b/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs index abf66d7a5b..a8f8afd47c 100644 --- a/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs +++ b/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs @@ -13,13 +13,13 @@ namespace osu.Game.Screens.Edit { HeaderText = "Are you sure you want to delete this difficulty?"; - Icon = FontAwesome.Regular.Save; + Icon = FontAwesome.Regular.TrashAlt; Buttons = new PopupDialogButton[] { new PopupDialogDangerousButton { - Text = @"Yes delete this difficulty!", + Text = @"Yes, delete this difficulty!", Action = delete }, new PopupDialogCancelButton From dd315ff97b3d0f6c96fcd75796738f9e909e88f1 Mon Sep 17 00:00:00 2001 From: Micahel Kelly Date: Wed, 27 Jul 2022 21:21:16 +1000 Subject: [PATCH 0170/2686] Adds hard-delete for a beatmap diff --- osu.Game/Beatmaps/BeatmapManager.cs | 25 ++++++++++++++++++ osu.Game/Screens/Edit/Editor.cs | 26 ++++++++++++++++--- .../Edit/PromptForDifficultyDeleteDialog.cs | 9 +++++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index debe4c6829..6db038355f 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -358,6 +358,31 @@ namespace osu.Game.Beatmaps }); } + /// + /// Hard-Delete a beatmap difficulty locally. + /// + /// is generally preferred as it keeps the local beatmap set in sync with the server. + /// The beatmap difficulty to hide. + public void DeleteLocal(BeatmapInfo beatmapInfo) + { + Realm.Run(r => + { + using (var transaction = r.BeginWrite()) + { + if (!beatmapInfo.IsManaged) + beatmapInfo = r.Find(beatmapInfo.ID); + + var setInfo = beatmapInfo.BeatmapSet!; + DeleteFile(setInfo, beatmapInfo.File!); + setInfo.Beatmaps.Remove(beatmapInfo); + + var liveSetInfo = r.Find(setInfo.ID); + setInfo.CopyChangesToRealm(liveSetInfo); + transaction.Commit(); + } + }); + } + /// /// Delete videos from a list of beatmaps. /// This will post notifications tracking progress. diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 5cee634fd8..129e71ea30 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -851,7 +851,16 @@ namespace osu.Game.Screens.Edit private void deleteDifficulty() { - dialogOverlay?.Push(new PromptForDifficultyDeleteDialog(confirmDifficultyDelete, () => { })); + dialogOverlay?.Push(new PromptForDifficultyDeleteDialog(confirmDifficultyHide, confirmDifficultyDelete, () => { })); + } + + private void confirmDifficultyHide() + { + var current = playableBeatmap.BeatmapInfo; + if (current is null) return; + + beatmapManager.Hide(current); + switchBeatmapOrExit(current.BeatmapSet); } private void confirmDifficultyDelete() @@ -859,8 +868,19 @@ namespace osu.Game.Screens.Edit var current = playableBeatmap.BeatmapInfo; if (current is null) return; - beatmapManager.Hide(current); - this.Exit(); + beatmapManager.DeleteLocal(current); + switchBeatmapOrExit(current.BeatmapSet); + } + + private void switchBeatmapOrExit([CanBeNull] BeatmapSetInfo setInfo) + { + if (setInfo is null || setInfo.Beatmaps.Count() <= 1) + this.Exit(); + var nextBeatmap = setInfo!.Beatmaps.First(); + + // Force a refresh of the beatmap (and beatmap set) so the `Change difficulty` list is also updated. + Beatmap.Value = beatmapManager.GetWorkingBeatmap(nextBeatmap, true); + SwitchToDifficulty(Beatmap.Value.BeatmapInfo); } private void updateLastSavedHash() diff --git a/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs b/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs index a8f8afd47c..dcea9f1210 100644 --- a/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs +++ b/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs @@ -9,7 +9,7 @@ namespace osu.Game.Screens.Edit { public class PromptForDifficultyDeleteDialog : PopupDialog { - public PromptForDifficultyDeleteDialog(Action delete, Action cancel) + public PromptForDifficultyDeleteDialog(Action hide, Action delete, Action cancel) { HeaderText = "Are you sure you want to delete this difficulty?"; @@ -17,9 +17,14 @@ namespace osu.Game.Screens.Edit Buttons = new PopupDialogButton[] { + new PopupDialogOkButton + { + Text = @"Hide this difficulty instead (recommended)", + Action = hide + }, new PopupDialogDangerousButton { - Text = @"Yes, delete this difficulty!", + Text = @"Yes, DELETE this difficulty!", Action = delete }, new PopupDialogCancelButton From 537f64c75ecd9608b7f8f2b0e184dc18ba4bfa58 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 27 Jul 2022 22:12:52 +0800 Subject: [PATCH 0171/2686] Make original hit objects and random properties as local variable. --- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 37 ++++++++-------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 36f21ba291..9e5d997353 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -98,10 +98,6 @@ namespace osu.Game.Rulesets.Osu.Mods private ControlPointInfo? controlPointInfo; - private List? originalHitObjects; - - private Random? rng; - #endregion #region Sudden Death (IApplicableFailOverride) @@ -171,16 +167,16 @@ namespace osu.Game.Rulesets.Osu.Mods public override void ApplyToBeatmap(IBeatmap beatmap) { Seed.Value ??= RNG.Next(); - rng = new Random(Seed.Value.Value); + var rng = new Random(Seed.Value.Value); var osuBeatmap = (OsuBeatmap)beatmap; if (osuBeatmap.HitObjects.Count == 0) return; controlPointInfo = osuBeatmap.ControlPointInfo; - originalHitObjects = osuBeatmap.HitObjects.OrderBy(x => x.StartTime).ToList(); - var hitObjects = generateBeats(osuBeatmap) + var originalHitObjects = osuBeatmap.HitObjects.OrderBy(x => x.StartTime).ToList(); + var hitObjects = generateBeats(osuBeatmap, originalHitObjects) .Select(beat => { var newCircle = new HitCircle(); @@ -189,21 +185,19 @@ namespace osu.Game.Rulesets.Osu.Mods return (OsuHitObject)newCircle; }).ToList(); - addHitSamples(hitObjects); + addHitSamples(originalHitObjects, hitObjects); - fixComboInfo(hitObjects); + fixComboInfo(originalHitObjects, hitObjects); - randomizeCirclePos(hitObjects); + randomizeCirclePos(rng, hitObjects); osuBeatmap.HitObjects = hitObjects; base.ApplyToBeatmap(beatmap); } - private IEnumerable generateBeats(IBeatmap beatmap) + private IEnumerable generateBeats(IBeatmap beatmap, IReadOnlyCollection originalHitObjects) { - Debug.Assert(originalHitObjects != null); - double startTime = originalHitObjects.First().StartTime; double endTime = originalHitObjects.Last().GetEndTime(); @@ -215,7 +209,7 @@ namespace osu.Game.Rulesets.Osu.Mods // Remove beats before startTime .Where(beat => almostBigger(beat, startTime)) // Remove beats during breaks - .Where(beat => !isInsideBreakPeriod(beatmap.Breaks, beat)) + .Where(beat => !isInsideBreakPeriod(originalHitObjects, beatmap.Breaks, beat)) .ToList(); // Remove beats that are too close to the next one (e.g. due to timing point changes) @@ -230,10 +224,8 @@ namespace osu.Game.Rulesets.Osu.Mods return beats; } - private void addHitSamples(IEnumerable hitObjects) + private void addHitSamples(List originalHitObjects, IEnumerable hitObjects) { - Debug.Assert(originalHitObjects != null); - foreach (var obj in hitObjects) { var samples = getSamplesAtTime(originalHitObjects, obj.StartTime); @@ -244,10 +236,8 @@ namespace osu.Game.Rulesets.Osu.Mods } } - private void fixComboInfo(List hitObjects) + private void fixComboInfo(List originalHitObjects, List hitObjects) { - Debug.Assert(originalHitObjects != null); - // Copy combo indices from an original object at the same time or from the closest preceding object // (Objects lying between two combos are assumed to belong to the preceding combo) hitObjects.ForEach(newObj => @@ -280,7 +270,7 @@ namespace osu.Game.Rulesets.Osu.Mods } } - private void randomizeCirclePos(IReadOnlyList hitObjects) + private void randomizeCirclePos(Random rng, IReadOnlyList hitObjects) { if (hitObjects.Count == 0) return; @@ -361,12 +351,11 @@ namespace osu.Game.Rulesets.Osu.Mods /// The given time is also considered to be inside a break if it is earlier than the /// start time of the first original hit object after the break. /// + /// Hit objects order by time. /// The breaks of the beatmap. /// The time to be checked.= - private bool isInsideBreakPeriod(IEnumerable breaks, double time) + private bool isInsideBreakPeriod(IReadOnlyCollection originalHitObjects, IEnumerable breaks, double time) { - Debug.Assert(originalHitObjects != null); - return breaks.Any(breakPeriod => { var firstObjAfterBreak = originalHitObjects.First(obj => almostBigger(obj.StartTime, breakPeriod.EndTime)); From 72961ec3362168e058f16c45f69e1e1f4c7bd5b8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 28 Jul 2022 08:04:53 +0300 Subject: [PATCH 0172/2686] Flip method parameters to make sense See https://github.com/ppy/osu/pull/19407/commits/537f64c75ecd9608b7f8f2b0e184dc18ba4bfa58#r931785228 --- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 9e5d997353..c793ed4937 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -167,6 +167,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override void ApplyToBeatmap(IBeatmap beatmap) { Seed.Value ??= RNG.Next(); + var rng = new Random(Seed.Value.Value); var osuBeatmap = (OsuBeatmap)beatmap; @@ -185,11 +186,11 @@ namespace osu.Game.Rulesets.Osu.Mods return (OsuHitObject)newCircle; }).ToList(); - addHitSamples(originalHitObjects, hitObjects); + addHitSamples(hitObjects, originalHitObjects); - fixComboInfo(originalHitObjects, hitObjects); + fixComboInfo(hitObjects, originalHitObjects); - randomizeCirclePos(rng, hitObjects); + randomizeCirclePos(hitObjects, rng); osuBeatmap.HitObjects = hitObjects; @@ -224,7 +225,7 @@ namespace osu.Game.Rulesets.Osu.Mods return beats; } - private void addHitSamples(List originalHitObjects, IEnumerable hitObjects) + private void addHitSamples(IEnumerable hitObjects, List originalHitObjects) { foreach (var obj in hitObjects) { @@ -236,7 +237,7 @@ namespace osu.Game.Rulesets.Osu.Mods } } - private void fixComboInfo(List originalHitObjects, List hitObjects) + private void fixComboInfo(List hitObjects, List originalHitObjects) { // Copy combo indices from an original object at the same time or from the closest preceding object // (Objects lying between two combos are assumed to belong to the preceding combo) @@ -270,7 +271,7 @@ namespace osu.Game.Rulesets.Osu.Mods } } - private void randomizeCirclePos(Random rng, IReadOnlyList hitObjects) + private void randomizeCirclePos(IReadOnlyList hitObjects, Random rng) { if (hitObjects.Count == 0) return; From b2e7da5aa06189bf52e0f5e38bf7cb9bd8b6a712 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 28 Jul 2022 18:37:12 +0200 Subject: [PATCH 0173/2686] Add basic Queue based implementation of KPS --- .../Gameplay/TestSceneKeysPerSecondCounter.cs | 10 ++ .../Screens/Play/HUD/KeysPerSecondCounter.cs | 125 ++++++++++++++++++ osu.Game/Screens/Play/KeyCounter.cs | 2 + 3 files changed, 137 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs create mode 100644 osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs new file mode 100644 index 0000000000..451e297e05 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs @@ -0,0 +1,10 @@ +// 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.Tests.Visual.Gameplay +{ + public class TestSceneKeysPerSecondCounter + { + + } +} diff --git a/osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs new file mode 100644 index 0000000000..dc9a51dbf3 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs @@ -0,0 +1,125 @@ +// 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; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Screens.Play.HUD +{ + public class KeysPerSecondCounter : RollingCounter, ISkinnableDrawable + { + private static Queue? timestamps; + + private static event Action? onNewInput; + private readonly TimeSpan refreshSpan = TimeSpan.FromSeconds(1); + + private const float alpha_when_invalid = 0.3f; + private readonly Bindable valid = new Bindable(); + + public static void AddTimestamp() + { + timestamps?.Enqueue(DateTime.Now); + onNewInput?.Invoke(); + } + + protected override double RollingDuration => 250; + + public bool UsesFixedAnchor { get; set; } + + public KeysPerSecondCounter() + { + timestamps ??= new Queue(); + Current.Value = 0; + onNewInput += updateCounter; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.BlueLighter; + valid.BindValueChanged(e => + DrawableCount.FadeTo(e.NewValue ? 1 : alpha_when_invalid, 1000, Easing.OutQuint)); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updateCounter(); + } + + protected override void Update() + { + if (timestamps != null) + { + if (timestamps.TryPeek(out var earliest) && DateTime.Now - earliest >= refreshSpan) + timestamps.Dequeue(); + } + + updateCounter(); + + base.Update(); + } + + private void updateCounter() + { + valid.Value = timestamps != null; + Current.Value = timestamps?.Count ?? 0; + } + + protected override IHasText CreateText() => new TextComponent + { + Alpha = alpha_when_invalid + }; + + private class TextComponent : CompositeDrawable, IHasText + { + public LocalisableString Text + { + get => text.Text; + set => text.Text = value; + } + + private readonly OsuSpriteText text; + + public TextComponent() + { + AutoSizeAxes = Axes.Both; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(2), + Children = new Drawable[] + { + text = new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = OsuFont.Numeric.With(size: 16, fixedWidth: true) + }, + new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = OsuFont.Numeric.With(size: 8, fixedWidth: true), + Text = @"KPS", + Padding = new MarginPadding { Bottom = 1.5f }, // align baseline better + } + } + }; + } + } + } +} diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs index 1e5ada5295..b8bbac9a7e 100644 --- a/osu.Game/Screens/Play/KeyCounter.cs +++ b/osu.Game/Screens/Play/KeyCounter.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Screens.Play.HUD; using osuTK; using osuTK.Graphics; @@ -55,6 +56,7 @@ namespace osu.Game.Screens.Play public void Increment() { + KeysPerSecondCounter.AddTimestamp(); if (!IsCounting) return; From 079150849a53ee3545a8b58c137bb7648fdb4b3d Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 28 Jul 2022 18:37:50 +0200 Subject: [PATCH 0174/2686] Add some tests --- .../Gameplay/TestSceneKeysPerSecondCounter.cs | 69 ++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs index 451e297e05..e20a83b54a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs @@ -1,10 +1,75 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable disable + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; +using osuTK; +using osuTK.Input; + namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneKeysPerSecondCounter + public class TestSceneKeysPerSecondCounter : OsuManualInputManagerTestScene { - + private KeysPerSecondCounter counter; + + [SetUpSteps] + public void Setup() + { + createCounter(); + } + + private void createCounter() => AddStep("Create counter", () => + { + Child = counter = new KeysPerSecondCounter + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(5) + }; + }); + + [Test] + public void TestManualTrigger() + { + AddAssert("Counter = 0", () => counter.Current.Value == 0); + AddRepeatStep("manual trigger", KeysPerSecondCounter.AddTimestamp, 20); + AddAssert("Counter is not 0", () => counter.Current.Value > 0); + } + + [Test] + public void TestKpsAsideKeyCounter() + { + AddStep("Create key counter display", () => + Add(new KeyCounterDisplay + { + Origin = Anchor.BottomCentre, + Anchor = Anchor.BottomCentre, + Y = 100, + Children = new KeyCounter[] + { + new KeyCounterKeyboard(Key.W), + new KeyCounterKeyboard(Key.X), + new KeyCounterKeyboard(Key.C), + new KeyCounterKeyboard(Key.V) + } + }) + ); + AddAssert("Counter = 0", () => counter.Current.Value == 0); + addPressKeyStep(Key.W); + addPressKeyStep(Key.X); + addPressKeyStep(Key.C); + addPressKeyStep(Key.V); + AddAssert("Counter = 4", () => counter.Current.Value == 4); + } + + private void addPressKeyStep(Key key) + { + AddStep($"Press {key} key", () => InputManager.Key(key)); + } } } From 155dac55d0953fec674bf1e8e59c27d23bf2e889 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 29 Jul 2022 22:33:34 +0900 Subject: [PATCH 0175/2686] Apply DrawNode parameter changes --- osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs | 5 +++-- osu.Game/Graphics/Backgrounds/Triangles.cs | 5 +++-- osu.Game/Graphics/ParticleExplosion.cs | 10 +++++----- osu.Game/Graphics/ParticleSpewer.cs | 10 +++++----- osu.Game/Graphics/Sprites/LogoAnimation.cs | 7 +++---- osu.Game/Rulesets/Mods/ModFlashlight.cs | 5 +++-- osu.Game/Screens/Menu/LogoVisualisation.cs | 5 +++-- 7 files changed, 25 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index c1d518a843..01d0b66e7b 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Batches; using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; using osu.Framework.Input; @@ -254,9 +255,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor Source.parts.CopyTo(parts, 0); } - public override void Draw(Action vertexAction) + public override void Draw(IRenderer renderer) { - base.Draw(vertexAction); + base.Draw(renderer); shader.Bind(); shader.GetUniform("g_FadeClock").UpdateValue(ref time); diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index b83df45bd7..d4fe0a75f3 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using osu.Framework.Graphics.Batches; using osu.Framework.Graphics.OpenGL.Buffers; using osu.Framework.Graphics.OpenGL.Vertices; +using osu.Framework.Graphics.Rendering; using osu.Framework.Lists; namespace osu.Game.Graphics.Backgrounds @@ -270,9 +271,9 @@ namespace osu.Game.Graphics.Backgrounds parts.AddRange(Source.parts); } - public override void Draw(Action vertexAction) + public override void Draw(IRenderer renderer) { - base.Draw(vertexAction); + base.Draw(renderer); if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount)) { diff --git a/osu.Game/Graphics/ParticleExplosion.cs b/osu.Game/Graphics/ParticleExplosion.cs index c6f9c1343b..5c59b4efb2 100644 --- a/osu.Game/Graphics/ParticleExplosion.cs +++ b/osu.Game/Graphics/ParticleExplosion.cs @@ -6,8 +6,8 @@ using System; using System.Collections.Generic; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; @@ -89,7 +89,7 @@ namespace osu.Game.Graphics currentTime = source.Time.Current; } - protected override void Blit(Action vertexAction) + protected override void Blit(IRenderer renderer) { double time = currentTime - startTime; @@ -112,9 +112,9 @@ namespace osu.Game.Graphics Vector2Extensions.Transform(rect.BottomRight, DrawInfo.Matrix) ); - DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), null, vertexAction, - new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height), - null, TextureCoords); + DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), + inflationPercentage: new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height), + textureCoords: TextureCoords); } } diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 06c9882d72..5008f52a5a 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -7,8 +7,8 @@ using System; using osu.Framework.Bindables; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; @@ -107,7 +107,7 @@ namespace osu.Game.Graphics sourceSize = Source.DrawSize; } - protected override void Blit(Action vertexAction) + protected override void Blit(IRenderer renderer) { foreach (var p in particles) { @@ -136,9 +136,9 @@ namespace osu.Game.Graphics transformPosition(rect.BottomRight, rect.Centre, angle) ); - DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), null, vertexAction, - new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height), - null, TextureCoords); + DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), + inflationPercentage: new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height), + textureCoords: TextureCoords); } } diff --git a/osu.Game/Graphics/Sprites/LogoAnimation.cs b/osu.Game/Graphics/Sprites/LogoAnimation.cs index 13733bb3ad..14d78b4dee 100644 --- a/osu.Game/Graphics/Sprites/LogoAnimation.cs +++ b/osu.Game/Graphics/Sprites/LogoAnimation.cs @@ -3,10 +3,9 @@ #nullable disable -using System; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Vertices; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Sprites; @@ -57,11 +56,11 @@ namespace osu.Game.Graphics.Sprites progress = source.animationProgress; } - protected override void Blit(Action vertexAction) + protected override void Blit(IRenderer renderer) { Shader.GetUniform("progress").UpdateValue(ref progress); - base.Blit(vertexAction); + base.Blit(renderer); } protected override bool CanDrawOpaqueInterior => false; diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index e8bc6c2026..fc5be8c592 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Batches; using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; @@ -235,9 +236,9 @@ namespace osu.Game.Rulesets.Mods flashlightDim = Source.FlashlightDim; } - public override void Draw(Action vertexAction) + public override void Draw(IRenderer renderer) { - base.Draw(vertexAction); + base.Draw(renderer); shader.Bind(); diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index c66bd3639a..972399bfac 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -22,6 +22,7 @@ using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Utils; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics.Rendering; namespace osu.Game.Screens.Menu { @@ -198,9 +199,9 @@ namespace osu.Game.Screens.Menu Source.frequencyAmplitudes.AsSpan().CopyTo(audioData); } - public override void Draw(Action vertexAction) + public override void Draw(IRenderer renderer) { - base.Draw(vertexAction); + base.Draw(renderer); shader.Bind(); From 09979d44aa1826d7707a12652a3d02058be77336 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 29 Jul 2022 23:32:06 +0900 Subject: [PATCH 0176/2686] Apply DrawNode batching changes --- .../UI/Cursor/CursorTrail.cs | 7 +++--- osu.Game/Graphics/Backgrounds/Triangles.cs | 10 ++++----- osu.Game/Rulesets/Mods/ModFlashlight.cs | 22 +++++++++++-------- osu.Game/Screens/Menu/LogoVisualisation.cs | 7 +++--- 4 files changed, 25 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 01d0b66e7b..95db785840 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -9,7 +9,6 @@ using System.Runtime.InteropServices; using osu.Framework.Allocation; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Batches; using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; @@ -223,7 +222,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private Vector2 size; private Vector2 originPosition; - private readonly QuadBatch vertexBatch = new QuadBatch(max_sprites, 1); + private IVertexBatch vertexBatch; public TrailDrawNode(CursorTrail source) : base(source) @@ -259,6 +258,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor { base.Draw(renderer); + vertexBatch ??= renderer.CreateQuadBatch(max_sprites, 1); + shader.Bind(); shader.GetUniform("g_FadeClock").UpdateValue(ref time); shader.GetUniform("g_FadeExponent").UpdateValue(ref fadeExponent); @@ -320,7 +321,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor { base.Dispose(isDisposing); - vertexBatch.Dispose(); + vertexBatch?.Dispose(); } } diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index d4fe0a75f3..0df90fd770 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -14,8 +14,6 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Primitives; using osu.Framework.Allocation; using System.Collections.Generic; -using osu.Framework.Graphics.Batches; -using osu.Framework.Graphics.OpenGL.Buffers; using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Rendering; using osu.Framework.Lists; @@ -185,8 +183,8 @@ namespace osu.Game.Graphics.Backgrounds private void addTriangles(bool randomY) { - // limited by the maximum size of QuadVertexBuffer for safety. - const int max_triangles = QuadVertexBuffer.MAX_QUADS; + // Limited by the maximum size of QuadVertexBuffer for safety. + const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2); AimCount = (int)Math.Min(max_triangles, (DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio)); @@ -252,7 +250,7 @@ namespace osu.Game.Graphics.Backgrounds private readonly List parts = new List(); private Vector2 size; - private QuadBatch vertexBatch; + private IVertexBatch vertexBatch; public TrianglesDrawNode(Triangles source) : base(source) @@ -278,7 +276,7 @@ namespace osu.Game.Graphics.Backgrounds if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount)) { vertexBatch?.Dispose(); - vertexBatch = new QuadBatch(Source.AimCount, 1); + vertexBatch = renderer.CreateQuadBatch(Source.AimCount, 1); } shader.Bind(); diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index fc5be8c592..8e433ccb97 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Batches; using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; @@ -212,17 +211,12 @@ namespace osu.Game.Rulesets.Mods private Vector2 flashlightSize; private float flashlightDim; - private readonly VertexBatch quadBatch = new QuadBatch(1, 1); - private readonly Action addAction; + private IVertexBatch? quadBatch; + private Action? addAction; public FlashlightDrawNode(Flashlight source) : base(source) { - addAction = v => quadBatch.Add(new PositionAndColourVertex - { - Position = v.Position, - Colour = v.Colour - }); } public override void ApplyState() @@ -240,6 +234,16 @@ namespace osu.Game.Rulesets.Mods { base.Draw(renderer); + if (quadBatch == null) + { + quadBatch = renderer.CreateQuadBatch(1, 1); + addAction = v => quadBatch.Add(new PositionAndColourVertex + { + Position = v.Position, + Colour = v.Colour + }); + } + shader.Bind(); shader.GetUniform("flashlightPos").UpdateValue(ref flashlightPosition); @@ -254,7 +258,7 @@ namespace osu.Game.Rulesets.Mods protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - quadBatch.Dispose(); + quadBatch?.Dispose(); } } } diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 972399bfac..71f9799ed0 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -6,7 +6,6 @@ using osuTK; using osuTK.Graphics; using osu.Framework.Graphics; -using osu.Framework.Graphics.Batches; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; @@ -181,7 +180,7 @@ namespace osu.Game.Screens.Menu private readonly float[] audioData = new float[256]; - private readonly QuadBatch vertexBatch = new QuadBatch(100, 10); + private IVertexBatch vertexBatch; public VisualisationDrawNode(LogoVisualisation source) : base(source) @@ -203,6 +202,8 @@ namespace osu.Game.Screens.Menu { base.Draw(renderer); + vertexBatch ??= renderer.CreateQuadBatch(100, 10); + shader.Bind(); Vector2 inflation = DrawInfo.MatrixInverse.ExtractScale().Xy; @@ -257,7 +258,7 @@ namespace osu.Game.Screens.Menu { base.Dispose(isDisposing); - vertexBatch.Dispose(); + vertexBatch?.Dispose(); } } } From e06f39a69f1cf760e679e71283c9bafdae3fe7d2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sat, 30 Jul 2022 01:29:11 +0900 Subject: [PATCH 0177/2686] Apply IRenderer shader changes --- .../Rulesets/TestSceneDrawableRulesetDependencies.cs | 8 +++++--- osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs | 11 +++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs b/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs index 9f732be9e3..42d65ead2b 100644 --- a/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs +++ b/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs @@ -16,10 +16,12 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.UI; @@ -79,7 +81,7 @@ namespace osu.Game.Tests.Rulesets dependencies.CacheAs(ParentTextureStore = new TestTextureStore()); dependencies.CacheAs(ParentSampleStore = new TestSampleStore()); - dependencies.CacheAs(ParentShaderManager = new TestShaderManager()); + dependencies.CacheAs(ParentShaderManager = new TestShaderManager(parent.Get().Renderer)); return new DrawableRulesetDependencies(new OsuRuleset(), dependencies); } @@ -148,8 +150,8 @@ namespace osu.Game.Tests.Rulesets private class TestShaderManager : ShaderManager { - public TestShaderManager() - : base(new ResourceStore()) + public TestShaderManager(IRenderer renderer) + : base(renderer, new ResourceStore()) { } diff --git a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs index 6a7369a150..bd36255c02 100644 --- a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs +++ b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs @@ -13,6 +13,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; @@ -55,6 +56,8 @@ namespace osu.Game.Rulesets.UI if (resources != null) { + var host = parent.Get(); + TextureStore = new TextureStore(parent.Get().CreateTextureLoaderStore(new NamespacedResourceStore(resources, @"Textures"))); CacheAs(TextureStore = new FallbackTextureStore(TextureStore, parent.Get())); @@ -62,8 +65,8 @@ namespace osu.Game.Rulesets.UI SampleStore.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY; CacheAs(SampleStore = new FallbackSampleStore(SampleStore, parent.Get())); - ShaderManager = new ShaderManager(new NamespacedResourceStore(resources, @"Shaders")); - CacheAs(ShaderManager = new FallbackShaderManager(ShaderManager, parent.Get())); + ShaderManager = new ShaderManager(host.Renderer, new NamespacedResourceStore(resources, @"Shaders")); + CacheAs(ShaderManager = new FallbackShaderManager(host.Renderer, ShaderManager, parent.Get())); } RulesetConfigManager = parent.Get().GetConfigFor(ruleset); @@ -191,8 +194,8 @@ namespace osu.Game.Rulesets.UI private readonly ShaderManager primary; private readonly ShaderManager fallback; - public FallbackShaderManager(ShaderManager primary, ShaderManager fallback) - : base(new ResourceStore()) + public FallbackShaderManager(IRenderer renderer, ShaderManager primary, ShaderManager fallback) + : base(renderer, new ResourceStore()) { this.primary = primary; this.fallback = fallback; From 0940e703b3bf8ff4a6b23be6d3d49f40905a91c4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 30 Jul 2022 09:14:55 +0300 Subject: [PATCH 0178/2686] Fix normal skin hitsounds prioritised over default taiko hitsounds --- .../Skinning/Legacy/TaikoLegacySkinTransformer.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 888271f32d..c49884c00f 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -173,9 +173,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { foreach (string name in base.LookupNames) yield return name.Insert(name.LastIndexOf('/') + 1, "taiko-"); - - foreach (string name in base.LookupNames) - yield return name; } } } From 40858c4cb7afec09e6a3b4a54b2d2e5c1f6e31f8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 30 Jul 2022 09:32:39 +0300 Subject: [PATCH 0179/2686] Adjust existing test coverage --- .../TestSceneTaikoHitObjectSamples.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs index 674ac5670f..f8e04df78f 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs @@ -17,7 +17,6 @@ namespace osu.Game.Rulesets.Taiko.Tests protected override IResourceStore RulesetResources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneTaikoHitObjectSamples))); [TestCase("taiko-normal-hitnormal")] - [TestCase("normal-hitnormal")] [TestCase("hitnormal")] public void TestDefaultCustomSampleFromBeatmap(string expectedSample) { @@ -29,7 +28,6 @@ namespace osu.Game.Rulesets.Taiko.Tests } [TestCase("taiko-normal-hitnormal")] - [TestCase("normal-hitnormal")] [TestCase("hitnormal")] public void TestDefaultCustomSampleFromUserSkinFallback(string expectedSample) { @@ -41,7 +39,6 @@ namespace osu.Game.Rulesets.Taiko.Tests } [TestCase("taiko-normal-hitnormal2")] - [TestCase("normal-hitnormal2")] public void TestUserSkinLookupIgnoresSampleBank(string unwantedSample) { SetupSkins(string.Empty, unwantedSample); From b32ff68a9517990dcb02484981ec9d2aaa5ae609 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 30 Jul 2022 09:33:23 +0300 Subject: [PATCH 0180/2686] Enable NRT on taiko legacy skin transformer and tests --- .../TestSceneTaikoHitObjectSamples.cs | 2 -- .../Skinning/Legacy/TaikoLegacySkinTransformer.cs | 6 ++---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs index f8e04df78f..c674f87f80 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.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. -#nullable disable - using System.Reflection; using NUnit.Framework; using osu.Framework.IO.Stores; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index c49884c00f..992316ca53 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.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. -#nullable disable - using System; using System.Collections.Generic; using osu.Framework.Audio.Sample; @@ -24,7 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy hasExplosion = new Lazy(() => GetTexture(getHitName(TaikoSkinComponents.TaikoExplosionGreat)) != null); } - public override Drawable GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinComponent component) { if (component is GameplaySkinComponent) { @@ -151,7 +149,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy throw new ArgumentOutOfRangeException(nameof(component), $"Invalid component type: {component}"); } - public override ISample GetSample(ISampleInfo sampleInfo) + public override ISample? GetSample(ISampleInfo sampleInfo) { if (sampleInfo is HitSampleInfo hitSampleInfo) return base.GetSample(new LegacyTaikoSampleInfo(hitSampleInfo)); From b95aff3e5f4bae1917cc8c546dab295bc9874201 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 30 Jul 2022 18:50:41 +0300 Subject: [PATCH 0181/2686] Add failing test case --- .../SongSelect/TestScenePlaySongSelect.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 12f15b04dc..3d8f496c9a 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -10,6 +10,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics.Containers; using osu.Framework.Platform; using osu.Framework.Screens; @@ -282,6 +283,28 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("filter count is 2", () => songSelect.FilterCount == 2); } + [Test] + public void TestCarouselSelectionUpdatesOnResume() + { + addRulesetImportStep(0); + + createSongSelect(); + + AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child"))); + AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen()); + + AddStep("update beatmap", () => + { + var selectedBeatmap = Beatmap.Value.BeatmapInfo; + var anotherBeatmap = Beatmap.Value.BeatmapSetInfo.Beatmaps.Except(selectedBeatmap.Yield()).First(); + Beatmap.Value = manager.GetWorkingBeatmap(anotherBeatmap); + }); + + AddStep("return", () => songSelect.MakeCurrent()); + AddUntilStep("wait for current", () => songSelect.IsCurrentScreen()); + AddAssert("carousel updated", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(Beatmap.Value.BeatmapInfo)); + } + [Test] public void TestAudioResuming() { From faefda9143ec1185cecc5ea445d6825cd67d3830 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 30 Jul 2022 18:51:19 +0300 Subject: [PATCH 0182/2686] Fix song select not updating selected beatmap card on editor resume --- osu.Game/Screens/Select/SongSelect.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 7abcbfca42..596a8eb896 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -405,20 +405,21 @@ namespace osu.Game.Screens.Select private ScheduledDelegate selectionChangedDebounce; - private void workingBeatmapChanged(ValueChangedEvent e) + private void updateCarouselSelection(ValueChangedEvent e = null) { - if (e.NewValue is DummyWorkingBeatmap || !this.IsCurrentScreen()) return; + var beatmap = e?.NewValue ?? Beatmap.Value; + if (beatmap is DummyWorkingBeatmap || !this.IsCurrentScreen()) return; - Logger.Log($"Song select working beatmap updated to {e.NewValue}"); + Logger.Log($"Song select working beatmap updated to {beatmap}"); - if (!Carousel.SelectBeatmap(e.NewValue.BeatmapInfo, false)) + if (!Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) { // A selection may not have been possible with filters applied. // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. - if (!e.NewValue.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) + if (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) { - Ruleset.Value = e.NewValue.BeatmapInfo.Ruleset; + Ruleset.Value = beatmap.BeatmapInfo.Ruleset; transferRulesetValue(); } @@ -426,10 +427,10 @@ namespace osu.Game.Screens.Select // we still want to temporarily show the new beatmap, bypassing filters. // This will be undone the next time the user changes the filter. var criteria = FilterControl.CreateCriteria(); - criteria.SelectedBeatmapSet = e.NewValue.BeatmapInfo.BeatmapSet; + criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; Carousel.Filter(criteria); - Carousel.SelectBeatmap(e.NewValue.BeatmapInfo); + Carousel.SelectBeatmap(beatmap.BeatmapInfo); } } @@ -597,6 +598,8 @@ namespace osu.Game.Screens.Select if (Beatmap != null && !Beatmap.Value.BeatmapSetInfo.DeletePending) { + updateCarouselSelection(); + updateComponentFromBeatmap(Beatmap.Value); if (ControlGlobalMusic) @@ -805,7 +808,7 @@ namespace osu.Game.Screens.Select }; decoupledRuleset.DisabledChanged += r => Ruleset.Disabled = r; - Beatmap.BindValueChanged(workingBeatmapChanged); + Beatmap.BindValueChanged(updateCarouselSelection); boundLocalBindables = true; } From 89855cc1d6af208b5e132264e610b16a2386c8c4 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Sun, 31 Jul 2022 01:29:57 +0200 Subject: [PATCH 0183/2686] Change KPS Counter implementation base and add better replay integration The counter implementaiton is now list based, and will not invalidate previous hits by removing them but by testing if they are within the 1 second span, allowing better integration with replays and spectators. --- .../Screens/Play/HUD/KeysPerSecondCounter.cs | 67 ++++++++++++++----- osu.Game/Screens/Play/KeyCounterDisplay.cs | 2 + osu.Game/Screens/Play/Player.cs | 4 ++ 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs index dc9a51dbf3..d32ca1410a 100644 --- a/osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs @@ -1,17 +1,24 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable disable + using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Framework.Logging; +using osu.Framework.Timing; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.UI; using osu.Game.Skinning; using osuTK; @@ -19,37 +26,71 @@ namespace osu.Game.Screens.Play.HUD { public class KeysPerSecondCounter : RollingCounter, ISkinnableDrawable { - private static Queue? timestamps; + private static List timestamps; + private static double maxTime = double.NegativeInfinity; - private static event Action? onNewInput; - private readonly TimeSpan refreshSpan = TimeSpan.FromSeconds(1); + private static event Action onNewInput; + private const int invalidation_timeout = 1000; private const float alpha_when_invalid = 0.3f; + private readonly Bindable valid = new Bindable(); + private static GameplayClock gameplayClock; + private static IClock referenceClock; + + private static IClock clock => referenceClock ?? gameplayClock; + + [Resolved(canBeNull: true)] + private DrawableRuleset drawableRuleset { get; set; } + + [SettingSource("Smoothing time", "How smooth the counter should change\nThe more it is smooth, the less it's accurate.")] + public BindableNumber SmoothingTime { get; } = new BindableNumber(350) + { + MaxValue = 1000, + MinValue = 0 + }; + public static void AddTimestamp() { - timestamps?.Enqueue(DateTime.Now); + Logger.Log($"Input timestamp attempt C: {clock.CurrentTime}ms | GC: {gameplayClock.CurrentTime} | RC: {referenceClock?.CurrentTime ?? -1} | Max: {maxTime})", level: LogLevel.Debug); + + if (clock.CurrentTime >= maxTime) + { + Logger.Log("Input timestamp added.", level: LogLevel.Debug); + timestamps?.Add(clock.CurrentTime); + maxTime = timestamps?.Max() ?? clock.CurrentTime; + } + onNewInput?.Invoke(); } - protected override double RollingDuration => 250; + public static void Reset() + { + timestamps?.Clear(); + maxTime = int.MinValue; + } + + protected override double RollingDuration => SmoothingTime.Value; public bool UsesFixedAnchor { get; set; } public KeysPerSecondCounter() { - timestamps ??= new Queue(); + timestamps ??= new List(); Current.Value = 0; onNewInput += updateCounter; + Scheduler.AddOnce(updateCounter); } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, GameplayClock clock) { + gameplayClock = clock; Colour = colours.BlueLighter; valid.BindValueChanged(e => DrawableCount.FadeTo(e.NewValue ? 1 : alpha_when_invalid, 1000, Easing.OutQuint)); + referenceClock = drawableRuleset?.FrameStableClock; } protected override void LoadComplete() @@ -61,21 +102,15 @@ namespace osu.Game.Screens.Play.HUD protected override void Update() { - if (timestamps != null) - { - if (timestamps.TryPeek(out var earliest) && DateTime.Now - earliest >= refreshSpan) - timestamps.Dequeue(); - } + base.Update(); updateCounter(); - - base.Update(); } private void updateCounter() { - valid.Value = timestamps != null; - Current.Value = timestamps?.Count ?? 0; + valid.Value = timestamps != null && MathHelper.ApproximatelyEquivalent(gameplayClock.CurrentTime, referenceClock.CurrentTime, 500); + Current.Value = timestamps?.Count(timestamp => clock.CurrentTime - timestamp is >= 0 and <= invalidation_timeout) ?? 0; } protected override IHasText CreateText() => new TextComponent diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs index b6094726c0..aaf2e997f2 100644 --- a/osu.Game/Screens/Play/KeyCounterDisplay.cs +++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Configuration; +using osu.Game.Screens.Play.HUD; using osuTK; using osuTK.Graphics; @@ -65,6 +66,7 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load(OsuConfigManager config) { + KeysPerSecondCounter.Reset(); config.BindWith(OsuSetting.KeyOverlay, configVisibility); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9a058e45c5..fb2f556611 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -34,6 +34,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; +using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Users; @@ -1044,6 +1045,9 @@ namespace osu.Game.Screens.Play musicController.ResetTrackAdjustments(); fadeOut(); + + KeysPerSecondCounter.Reset(); + return base.OnExiting(e); } From 632577389df1890a6c3a987954156c8cb4634a4b Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 31 Jul 2022 21:43:16 +0800 Subject: [PATCH 0184/2686] Mark the property as non-nullable. --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 11 +++-------- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 5 +---- osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs | 5 ++--- osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs | 5 +---- osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs | 5 ++--- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 10 +++------- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 7 ++----- 7 files changed, 14 insertions(+), 34 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 83c1deb3b9..872fcf7e9b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.StateChanges; @@ -29,20 +28,16 @@ namespace osu.Game.Rulesets.Osu.Mods public bool RestartOnFail => false; - private OsuInputManager? inputManager; + private OsuInputManager inputManager = null!; - private IFrameStableClock? gameplayClock; + private IFrameStableClock gameplayClock = null!; - private List? replayFrames; + private List replayFrames = null!; private int currentFrame; public void Update(Playfield playfield) { - Debug.Assert(inputManager != null); - Debug.Assert(gameplayClock != null); - Debug.Assert(replayFrames != null); - if (currentFrame == replayFrames.Count - 1) return; double time = gameplayClock.CurrentTime; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 808e7720a4..56665db770 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -32,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModFlashlight) }; - private DrawableOsuBlinds? blinds; + private DrawableOsuBlinds blinds = null!; public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { @@ -41,8 +40,6 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToHealthProcessor(HealthProcessor healthProcessor) { - Debug.Assert(blinds != null); - healthProcessor.Health.ValueChanged += health => { blinds.AnimateClosedness((float)health.NewValue); }; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index 510e95b13f..e5a458488e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -4,7 +4,6 @@ using System; using System.Linq; using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Events; @@ -52,14 +51,14 @@ namespace osu.Game.Rulesets.Osu.Mods public override float DefaultFlashlightSize => 180; - private OsuFlashlight? flashlight; + private OsuFlashlight flashlight = null!; protected override Flashlight CreateFlashlight() => flashlight = new OsuFlashlight(this); public void ApplyToDrawableHitObject(DrawableHitObject drawable) { if (drawable is DrawableSlider s) - s.Tracking.ValueChanged += flashlight.AsNonNull().OnSliderTrackingChange; + s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange; } private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs index 107eac6430..9316f9ed74 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; @@ -27,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel) }; - private IFrameStableClock? gameplayClock; + private IFrameStableClock gameplayClock = null!; [SettingSource("Attraction strength", "How strong the pull is.", 0)] public BindableFloat AttractionStrength { get; } = new BindableFloat(0.5f) @@ -75,8 +74,6 @@ namespace osu.Game.Rulesets.Osu.Mods { double dampLength = Interpolation.Lerp(3000, 40, AttractionStrength.Value); - Debug.Assert(gameplayClock != null); - float x = (float)Interpolation.DampContinuously(hitObject.X, destination.X, dampLength, gameplayClock.ElapsedFrameTime); float y = (float)Interpolation.DampContinuously(hitObject.Y, destination.Y, dampLength, gameplayClock.ElapsedFrameTime); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs index 0197b7cb1b..3eb8982f5d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs @@ -4,7 +4,6 @@ using System; using System.Linq; using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -20,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Description => "Where's the cursor?"; - private PeriodTracker? spinnerPeriods; + private PeriodTracker spinnerPeriods = null!; [SettingSource( "Hidden at combo", @@ -42,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void Update(Playfield playfield) { - bool shouldAlwaysShowCursor = IsBreakTime.Value || spinnerPeriods.AsNonNull().IsInAny(playfield.Clock.CurrentTime); + bool shouldAlwaysShowCursor = IsBreakTime.Value || spinnerPeriods.IsInAny(playfield.Clock.CurrentTime); float targetAlpha = shouldAlwaysShowCursor ? 1 : ComboBasedAlpha; playfield.Cursor.Alpha = (float)Interpolation.Lerp(playfield.Cursor.Alpha, targetAlpha, Math.Clamp(playfield.Time.Elapsed / TRANSITION_DURATION, 0, 1)); } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index ac45ce2ade..908bb34ed6 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -29,9 +29,9 @@ namespace osu.Game.Rulesets.Osu.Mods private bool isDownState; private bool wasLeft; - private OsuInputManager? osuInputManager; + private OsuInputManager osuInputManager = null!; - private ReplayState? state; + private ReplayState state = null!; private double lastStateChangeTime; private bool hasReplay; @@ -44,8 +44,6 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToPlayer(Player player) { - Debug.Assert(osuInputManager != null); - if (osuInputManager.ReplayInputHandler != null) { hasReplay = true; @@ -134,9 +132,7 @@ namespace osu.Game.Rulesets.Osu.Mods wasLeft = !wasLeft; } - Debug.Assert(osuInputManager != null); - - state?.Apply(osuInputManager.CurrentState, osuInputManager); + state.Apply(osuInputManager.CurrentState, osuInputManager); } } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index c793ed4937..c273da2462 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; @@ -96,7 +95,7 @@ namespace osu.Game.Rulesets.Osu.Mods #region Private Fields - private ControlPointInfo? controlPointInfo; + private ControlPointInfo controlPointInfo = null!; #endregion @@ -156,7 +155,7 @@ namespace osu.Game.Rulesets.Osu.Mods circle.ApproachCircle.Hide(); } - using (circle.BeginAbsoluteSequence(startTime - controlPointInfo.AsNonNull().TimingPointAt(startTime).BeatLength - undim_duration)) + using (circle.BeginAbsoluteSequence(startTime - controlPointInfo.TimingPointAt(startTime).BeatLength - undim_duration)) circle.FadeColour(Color4.White, undim_duration); } @@ -372,8 +371,6 @@ namespace osu.Game.Rulesets.Osu.Mods int i = 0; double currentTime = timingPoint.Time; - Debug.Assert(controlPointInfo != null); - while (!definitelyBigger(currentTime, mapEndTime) && ReferenceEquals(controlPointInfo.TimingPointAt(currentTime), timingPoint)) { beats.Add(Math.Floor(currentTime)); From 6c964dee308a48b57699fa5877e846e2cfda3ce9 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 31 Jul 2022 22:00:14 +0800 Subject: [PATCH 0185/2686] Rename the nullable disable annotation in the Audio namespace and mark some properties as nullable. --- osu.Game/Audio/Effects/AudioFilter.cs | 2 -- osu.Game/Audio/Effects/ITransformableFilter.cs | 2 -- osu.Game/Audio/IPreviewTrackOwner.cs | 2 -- osu.Game/Audio/ISampleInfo.cs | 2 -- osu.Game/Audio/ISamplePlaybackDisabler.cs | 2 -- osu.Game/Audio/PreviewTrack.cs | 6 ++---- osu.Game/Audio/PreviewTrackManager.cs | 8 +++----- osu.Game/Audio/SampleInfo.cs | 4 +--- 8 files changed, 6 insertions(+), 22 deletions(-) diff --git a/osu.Game/Audio/Effects/AudioFilter.cs b/osu.Game/Audio/Effects/AudioFilter.cs index 5c318eb957..9446967173 100644 --- a/osu.Game/Audio/Effects/AudioFilter.cs +++ b/osu.Game/Audio/Effects/AudioFilter.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. -#nullable disable - using System.Diagnostics; using ManagedBass.Fx; using osu.Framework.Audio.Mixing; diff --git a/osu.Game/Audio/Effects/ITransformableFilter.cs b/osu.Game/Audio/Effects/ITransformableFilter.cs index 02149b362c..fb6a924f68 100644 --- a/osu.Game/Audio/Effects/ITransformableFilter.cs +++ b/osu.Game/Audio/Effects/ITransformableFilter.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. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Transforms; diff --git a/osu.Game/Audio/IPreviewTrackOwner.cs b/osu.Game/Audio/IPreviewTrackOwner.cs index 6a3acc2059..8ab93257a5 100644 --- a/osu.Game/Audio/IPreviewTrackOwner.cs +++ b/osu.Game/Audio/IPreviewTrackOwner.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. -#nullable disable - namespace osu.Game.Audio { /// diff --git a/osu.Game/Audio/ISampleInfo.cs b/osu.Game/Audio/ISampleInfo.cs index 8f58415587..4f81d37e78 100644 --- a/osu.Game/Audio/ISampleInfo.cs +++ b/osu.Game/Audio/ISampleInfo.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. -#nullable disable - using System.Collections.Generic; namespace osu.Game.Audio diff --git a/osu.Game/Audio/ISamplePlaybackDisabler.cs b/osu.Game/Audio/ISamplePlaybackDisabler.cs index 250e004b05..4167316780 100644 --- a/osu.Game/Audio/ISamplePlaybackDisabler.cs +++ b/osu.Game/Audio/ISamplePlaybackDisabler.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Skinning; diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 8ff8cd5c54..cfedd581e5 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Audio.Track; @@ -18,13 +16,13 @@ namespace osu.Game.Audio /// Invoked when this has stopped playing. /// Not invoked in a thread-safe context. /// - public event Action Stopped; + public event Action? Stopped; /// /// Invoked when this has started playing. /// Not invoked in a thread-safe context. /// - public event Action Started; + public event Action? Started; protected Track Track { get; private set; } diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index d19fdbd94c..a0537d7a4e 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; @@ -20,9 +18,9 @@ namespace osu.Game.Audio private readonly BindableDouble muteBindable = new BindableDouble(); - private ITrackStore trackStore; + private ITrackStore trackStore = null!; - protected TrackManagerPreviewTrack CurrentTrack; + protected TrackManagerPreviewTrack? CurrentTrack; public PreviewTrackManager(IAdjustableAudioComponent mainTrackAdjustments) { @@ -90,7 +88,7 @@ namespace osu.Game.Audio public class TrackManagerPreviewTrack : PreviewTrack { [Resolved(canBeNull: true)] - public IPreviewTrackOwner Owner { get; private set; } + public IPreviewTrackOwner? Owner { get; private set; } private readonly IBeatmapSetInfo beatmapSetInfo; private readonly ITrackStore trackManager; diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 54b380f23a..19c78f34b2 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.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. -#nullable disable - using System; using System.Collections; using System.Collections.Generic; @@ -34,7 +32,7 @@ namespace osu.Game.Audio Volume); } - public bool Equals(SampleInfo other) + public bool Equals(SampleInfo? other) => other != null && sampleNames.SequenceEqual(other.sampleNames); public override bool Equals(object obj) From 094793bbe3fdfcdc5769e821a5d19bf3c0d5e843 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 31 Jul 2022 22:01:30 +0800 Subject: [PATCH 0186/2686] Mark the GetTrack() return type as nullable. --- osu.Game/Audio/PreviewTrack.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index cfedd581e5..7fb92f9f9d 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -24,7 +24,7 @@ namespace osu.Game.Audio /// public event Action? Started; - protected Track Track { get; private set; } + protected Track? Track { get; private set; } private bool hasStarted; @@ -56,7 +56,7 @@ namespace osu.Game.Audio /// public bool IsRunning => Track?.IsRunning ?? false; - private ScheduledDelegate startDelegate; + private ScheduledDelegate? startDelegate; /// /// Starts playing this . @@ -104,6 +104,6 @@ namespace osu.Game.Audio /// /// Retrieves the audio track. /// - protected abstract Track GetTrack(); + protected abstract Track? GetTrack(); } } From 5dd641bc60065e5555a8c50b04387cdd0febe33b Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 31 Jul 2022 22:02:07 +0800 Subject: [PATCH 0187/2686] Remove the nullable disable annotation in the test project. --- osu.Game.Tests/Audio/SampleInfoEqualityTest.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Audio/SampleInfoEqualityTest.cs b/osu.Game.Tests/Audio/SampleInfoEqualityTest.cs index d05eb7994b..149096608f 100644 --- a/osu.Game.Tests/Audio/SampleInfoEqualityTest.cs +++ b/osu.Game.Tests/Audio/SampleInfoEqualityTest.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. -#nullable disable - using NUnit.Framework; using osu.Game.Audio; From db4c6aa3d3aaaa570d6800ec8219a2ac4682e247 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 31 Jul 2022 23:47:48 +0900 Subject: [PATCH 0188/2686] Add test skin layout json resources --- .../Archives/modified-classic-20220723.osk | Bin 0 -> 32757 bytes .../Archives/modified-default-20220723.osk | Bin 0 -> 1383 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 osu.Game.Tests/Resources/Archives/modified-classic-20220723.osk create mode 100644 osu.Game.Tests/Resources/Archives/modified-default-20220723.osk diff --git a/osu.Game.Tests/Resources/Archives/modified-classic-20220723.osk b/osu.Game.Tests/Resources/Archives/modified-classic-20220723.osk new file mode 100644 index 0000000000000000000000000000000000000000..8e7a1b42df38ea5d2f9a0c325c1fabf3ade153f0 GIT binary patch literal 32757 zcmV)KK)SzBO9KQH0000800;>IRfyT-wTu7&0H*)|00;m80CQ_;ZZ2tVX&uZl4#F@D zK+!#?FdImS?A@5ym|#K-ZtT*C#72pus%K;1NL+!I`9J;d`{O-aMutIC(kaRVf{L*i zOjrS%X-10yQTM zyE`wU`;S7xT4R81R*FMp+PP!1QA-C`d5TWreo#vT1QY-O00;mG2?14X;C7sG0001n z0000D0001UYiVw2Zf0*TYIARHHOxT@!axj0;eAgLvr;H?0JjQK5I5oh!gQvDwtt|L zA|l>h2X*`Sc+ZB2FES_I6I)p~agtIr(ss69v!;H>Z8e7_iQ7`y4I}K1Z|_iC;3}?$ z4%vRAaQaNcbyPqxgk#FGPJT{<#7C_y{Sh~>H&9Ch1QY-O00;mG2?13vP#|?sdH?|D zd;kCr0001RaCu*BZ)a~UGA?j#XMDK@P+UQ`EsVPdcNyH>-4h_e-3Qm;7Cg8O8ax34 z!QCY|gF|qKAPKI)A@7iTzx!_e_18NE#mwpM-Q9byz4qEg^gA_0Of*t77#J8#WhFTc z7#P^AmtPb(;Eh~^(i-rG#6w=sL(|3D!`s}=3Pu|2VqrzC>|}0ZrD0_b_I*EWB?bcn ze`%+s=b@*nB4X*{#9{t2hr`Fo73Sp;lk{;lw{)=bpti8Gv2zxuJ#GI^OKk@hr`6?G zcD900x|_Jj|(moE)9qMSR3*|JfA*KEJ%? zq^15h#lu0I_P-9Lr}~as*2T?=T9AW_-I9xoi&{{a18i<#ZfRk`M$N;;!_CRX$H~pd z&c!9dD=fmtNB!RqEwG&%*jhwGPT{{d1HOsV+Io1nig0pzdwX+u^K!Vj*>G|T3k!2{ z@o@6+umdyL-F=-s%zfCM-Rb^gLC(tE(#_7*!_LK-`sKU1g^Q<$I4$je?%?FAs`@{M zo!$T2Q-IGneau}sxjDEvot!xTGuz!m!^-;qJ= zX$KY&;FlNR73LBU5|CBk=9ZI@7LezW6A}`Xm6w*4;o}ngkAeTa5O~7@2G$D7@X7JY zN%JZw@bPhT%gYM$@(2hCbIZuc^T-R!ax462t+KPbhq<$*)qmF7{ol1b|If7|vTj!9 z9xiTLE-sG$!HTk@qo=!v+skWe9sv$sY9?JfXRwR6JM&8@|NF33ZgyT)UpF+VUFm5fQPVEe;yP{=0wjDT;D3|0HVvy{H%# z=dzfkOqG&i+Fzv>;w`teSMUK=vCbR&kcgAVJuhrAM z?QhjCtTOc_^b}ar+ohqBTmI~SryweW@FC}5o{%u8gLAU7zE|rS!C8E9&~H~Ei`sWw zLZ};A2c9_-cqKC>p5xtz;eGCBh#Q+_Qws>>a1XtTkOCh>Y1X>(2X?%3M!fgrvVjU* zA{bni1hX&-^uvgz2Ay!H3(*SZR!gH&7~AJ4j#^+1 zq%mAB9f3F<{QM;bltn2JPxX@~J)(5zf--FrT}z>raul_K^~zre)CjLRizYyjGEt!r zHd1yErM42g2*1)GN}VAYYJj&s@}I!u1@( zr2I3~RU1#$TM9%Jre8-=XXM!QCJ$KPm1H)^Y5;ieE*vRU(qPRkNj}E9eMk9_b%#3E zgU(mcRk3h&e3T{Vs_=1IWeMZK=t6}8)ZbYBi?*bm*a`xy)O!AHl_qIHLgIdBM`nBh zPL)sALwFfML1qeSAo6XVp`X-hgnqjY3r7fUXDVRB>*)-xrPxhu>hrz^4#8n1q7Uk) z#V8-!!l^X?h5FOXc%@1%xerj{Y5`G?>guwz1cU}K4aEf18c4=|43wQ`WmSh48plb}q<{Q2dUIJTl| z&5jpCz8Ef*h^Jm{JDJJyJPW!~`k>JET!^@`j&SxPchrRxD5zd=h%FL3uNI*$1%eP;=q>@8}=3*bkO9~M zGPL%64#@C$CiRg!u3?R1XU#c7EHe{%gcf)8xb`bz#dB1XP>Dd>PU|9fgfwC4KQk8% zxlk%Aq-88NPRc~!aMn9(CUr{x)}Z6BxI-j)O2?3Le;7kYKLiG;LxsZ=a2h^ zkxSJ;p6B5CEeKC2qN(V#^i3X?s_>PTK%Y}D!}7V09BaqSf1xhD|2kDB)53#ilyeaz z_e?Ce>}=?vTTkL%+KxVa^j%{Kqkfo{h;@OH|3i<^r^;h|AboX^9&pMf3%-t8!)#fN zSVvipTH{J{wOJ%|!%)Jjr=pH6a% zR6js_#yG5CpWqQ4h2lR=?JmgggiQLA-Vdp=Avb+k;m*>0`o>2Ljo2yC5lNWaqMR^O z?gem5wZ`}a5nX?Z?k&U3QwsGd*N8ZL8HfQcIN~=H2-B&uAwzCrp#Uy|L~=PTX}1^L z@D(Q>N=u?Pz5itMN?_VLU0&p0K$w+9N2sRtV7Vh5BS@?ujw&DfX(cMHpf7o*Hv^X~ z#h$6cg)7Ks$Q@<`hFGtlIo2s9&!xVkjC0#KYODqhD1yT;yz$Fp?bNWp*hJv4Ccg0t z{go5i4Td2g+=LEZYyC1EZx8-MDw2g6f44dio+0)s8sShnGD6RMX>LcQ zRLKJNdaW$AOM4!3fiNhoevEDj7;+-B4mjZM7en%nMT%tI9Dy_|%mpQsCfi&@AIvwx z6bs5Jb)~`T5kGYx+D){*=S2bt&!c~vdw%2(B0I40md-1xj3A%w`F3xU17{UyfU$R8PQ=A#1jI{+qn3@Myki zYhk6NBAJ(@{Dlc5Wz--U4v>KlBuD6Bi#zRasS5ekU`g z;UO%7A#xq>q;@EJ#Idv40jq4zMaQ#lZ?3bkHRZa5$SC^BsD|yld}Zu*7`;DQpvn1ClMB+!i_fR zk`YNwh1~E3odEs{r-cRdi%?ksN?9?Fg|r8;1?1;Me*pr!cH}wy3hE!O3KXgD2t5?+ z?n=Mm_9j?@;x>g@3=;kkv3sgKTIkak?4GrnMu0~f9(gfdDo{Ex2vIuK>S6TdM9W%^ z(Qklo@2mbJJYR1d{UTj_r++YkThXTnij>?81&)*FFfX!xk!<>ZjhHO2&l`~g#yeV( zTX#x5-!o7ofcB}atL8G5`Zb?^@^`BB4!+P)LW8loSWzyfERi^HwfDa$0n$_kL+p3` zj(5aqMk&=(k2B!pU4MOiK~`ozhOMmuth&?SC`;^B7JD`zPrp`%Q!Ys|%?!G}1}1KwQtP`*POgfXxUxSBVs zkri z-XN?6F8IW@yaLFD0{z*e)NyL3$V@AUn!3jlwQ$&G6`3Yf^`%TCqB7yV;= zf9JT>okUyP;!P%?jwxF~UgSj6BTHzzxZMl?9d)Z80Tt0xp4H^j%Y1Ppb!hD!Kdoq1 z^qAUG961&qLVaVdjO!%4(XHb4 z;pB0P7jdTbjWE7$m{y+!p0>phWyw8N(gL_LYqIx?ynN3_s1LejLI1}mF%vcSbXi}8 zF-K^X*(|=k+<{FcT>F_=9=L(La6E7W0FEjwG04>Gc#P#JCk9C9K>mD;Jq0*cxd~*r z>(>*Ic8I&`UJNKeIaaXGzYyr40a_{<4EutcV#FALI%F9Bt-!`37Q=G1a!WG1rikCH zVr~HF+(0@T*oLQ>lR>uu|5EoQZag@$0L^Euarh>OAxOgC(AFu{{~NHE1}=%oKBVoW zrVnzMByV)yB{cFJI_*fs`6R=NEQlIY0=4 zJ{&v&e*NKvmf6n#4{K989Ik-Bi|U|yar%V&d^T=KJ>oN~wZl}(8SsvQ@zyRE6CAO8 zyY!PFLpB*J$lmHc%1Nd!&2~dAJ3bICl0*8*B4$os4SjGFAWpM2Uk*gG>6RSKD$S(O zWLhJj6cu@)$oG(PGfO{7tLl$%jlX1Mogyy+%`I*z_NJ*$K`^C9DeluixM|?Ud^Na7 zpacZ0A=FH|B13Hdna7Z-%LmlU6w7B0@WRa;tU)?}>xe=A>@T0{48T(YbuVv`r_opj$9I!Ua={R+`j=4adiDYVk{!*PsYx5;-3EGwVH`sJBDQuF`dEBG z85!lh`GsP^D$hJEB3*-T79H8=uCy|Zme^6gY^v@dLS9fD4=>4vq9I1f%<}pZb4n&c zjDm&&1|7}dHVycMfxqb>(X40_3GgNw@4Bkg;>Zs17*lNAP$AGEM6vx~d+8H0ro9+t z&E#cUeZ=B^eX~V;vp!51wfNPb$WK0&9K@wnb@NFMaNYBdoDrVFM@W3r=PygqWRMhX z!Z-o*(^xrLHI7UNN(9>2tG(=wa!*{qA`i+-U~Ap!%ubqGca))`mW@iGpu1Fg5%RJy zY1g+Oxd2&E8;3z^F#To;qjEOpdW)BgoZdZ2ey`H)!|PK<>K0B4tQQ;m$>U}afC`p4 zd}Y}1Vg`CukWm2=+Y9RmB0!>Pnb}JEG|{4sNGyx3z{h8pa`QRY&ooId{HvR|aQ7%Y z58J^L&Z;RX)^P(x`3uzg8gn>&v&Ibvw$&NnGKlm+j~W>u=Bo^VgIIz9HjHR;bm;Cf zJN~dW0<_WYYy!kO}z31d#qYt_Igv?|(u@!8hMpK)4q*&wb@c{H1*y>2q zzwg|+6-l@(har^R80uKmyY`3^415L>D&AC}uPs9?!;()}iK~Ro?T?`uBKpbLG}Vjc zI>u9-&Yjk>UFz5!1Jj<`vh}xY92}fuX}>(uljaJSdbjlJOs1!%>R{~~131DgU4{Df z*uZre(W2yV`_Ej zAqvgbHs>bGey=FcaY`BtF^PKc1f8BKR^3BD9cFfmujOTBSrdgNpT zQUAQY+kW$xlY^QMc;Hnw>>=eNRDe>Pnwq+hStn5U*#81&(2gPzDoRR9nq_`#Qp98; z9=z~{$stu#&Q(!XR+blQ9Z`CYY0oW3sz`2v|4$&G>w!lh`DUQ~yrO6gqVpWJnGg{X zkuC`DVO>=%6%gic_eT-I`(?-aByWw@ysrje>pQxCTNnfmxBJnK%*IV+?|Pd4o75nd z=?J(zu)WU)FtxytN5SzaC61U;LM)hQ~ht>pCdgeT13=ya#w;EgM@2Kk6H1b_At5=&V^27h~o60D|p8MWx$zkhGOMf?eQ!tuAU(vM8l zbBgAnXFLRwt{=LwDs`Uz>7hN!h9^{d+#I^h@Lh~4(XKx8j_hz#Q;r9AvmeSD(~zHb zw$40gA)5=QKe!CwtEB=n=+=f{ma!z>u`Q(s3v@_onp>VrTl zL`v%N;~;9F_o}V981oH>uZVf`!Qw-24xQXiGFF5E;0%UxLKl0u1+IbJk&+(RSL&G*u$`RiO*lY?8aHh!zf@7WBv^d-xnB@Dk_tVF>puS zq$`{@qs4u7BuHMs#EqfIMi@6_36SU11>7l&0*vxr zCUYokD+wfc=!!srCFjN05CHKW5!_b!h-Zv}v9KzZ#!U;05vu^NWk9!RD`bn`CqQ0P z_HHpDB7K8B2gc0ev))c}$&kY82lZ#@=bKoLJQI{_QY@lF*Kk1nf7#9Lc%?3zx(}YC zkBKpcK7>9(LN*m>P4}OUGz}w0s7N$icF6f#LB!!UpjW7W5<#`{p?}@FZ|ADr0<7Sk zs8+ufqwUY$setpw3%>rcKO=@|Yc*k(l|_sY3&D%P&w++yE{3X6U!JHL*^~ z%&wcSc%DTwS(lhv30Z_;Ize3vQM$iT=P7=)T6*DlO%PLD17}J@T`@+a4)O z7w=x{NqSFLPk@O~Y$nvPp8Vs-NK6drEem^P@LvxR@jA8=quMY9kvBo|_Ba&G#rdD7 za8Sl3##GeQ5`Z6-w~2^w?zMVjO!JykS7Kje{Kz9naXQM%3JNTY<>lE`Sc6knjuCV4 z5R`Fr^2h04l|765YO#@HA%?jJJJi@QGMaYhUtaRo_%l!a`q8=Wh{TBwucy0E=X;rV ze~)QWotXFb2TcJ!B@+#XyvynKP@)Um$S)N0OktrU?_|sAtQ_?|?_jgF6yBOf^C!pE z7XR(RiGu?qGyj^5jBr0JJlAmZQAvNVo27cuknWBGCY6tswto~MrOq*aN)h|=GUaX}rdDL0ROlS5T1y^TVTUBkX z=UUtS&!2dD6*Z~Dx*9H#*x5bOyzgP8r0z{RejgwD!%1NuQA!A~A&yP_k`dTK7t-?d z6hG>Wh!Bus()Z#R9tL@u+Oe22R-irdZHkWVZEjv>0?nVQQJn=C35xY8@Mux6WBrFM zU(WdF9-MBWu#|_Z8PoVg?B1IkFM%Tm7|{r0R4&B>n!UEx-@=&P_f^J<=5ER=HBCKT zNLeW7;~&vady=g4dqX#N-R>5(XtvH)M*>nCdngoo_OGnc?`N*iG2UxyJGr|9rH;3M zKU{w(`f>WxwrAR(?&nBs__*rtfAw`2)*z5Tl$+a+&0b#*xU#uE5D*+17&bRGIEJ`% z%f5Q16g*-;->NBdiP*%53ea8X3<;?+bET9(jsIH_dbHAXEa`VeHmh%c-&|MG-5zwi z^)@mh@3Pz5uL`Qe&O?YEDN`@Z!&nv{_-D?=d8v*F>9wZ1g2vS#Ki3(?Ao9=bqcd@4 z6f|LF>*^u_Yy@(V zW7VolmCVd7+*}R&ywqU# ztLwwi%1X0ur$p$V^A1zZVmpgl)BNg=Mo;tr;oOtVOy$iF*MyckJQkpS$nuIerSJt| zKa_xgpDSKUPi0DzUU|mPxw*NvwzKntqMhBquGCVzxhDIk% z{F~WXTc(`_d3Fafcs=B(qu-0Z0D40dd^_pE0+!b8RWfc*+>67FjpJu_Z{D!>n8T0E zXzJGszq!5ak9N`3p6j(9cETLmQr*G?PT`KCLmqx9LtG@xMy*JP8u9RM_EKA`Le%#{ z6k|M5C*iH?xL?$?omd9Vv%AO#72VeDb5>S}<^%`;l0=aC(f2 zf7MfT@eAZk(sNZ+kJ;G`H(jWqh;sGs4$@Pm=`_y*synYMb43$<#0KQt^0@vw_L_WT z$7G}Y{n+2H#AVA7iJ4u{=y{kYUM*iJVssZm^5vFaT)gU`;3GGD0BFa!J~$kOq!)u1 zC5TcIE3cYEaWdnzi84@rCiB*eeO;W-1>uzGPob_3%rM!sYd`8hEhQ0sjY8x*c&{6p zyu`cj_r`O>D;3$bm=Z!mM|WWZs;f6PZzkbl1!?wqxv&clE)&S_?w_ArQd3jIn(MXB zsXPT>_en_wVB&gjwzp;F!d&nobHzMTn0L(K=BPIbdEMZkKZN z##N<4C8R`%67{A`kn0s;-$O7vf-0R}UG>|eOI1Gq_8{bqR}mx6n>=$%NATt$@1noN z^=virzb0R5ztMJ0o)7(#_N8-D7prLUkez~z3Q>Vk@95)%WwL~d;@%ZXLZGSMb(AfymQ7S5 z!>kv{NDUGx{N11KF@1G=e>Z4v5+r+ijhj%rv$w&5B`XxN?n2))cZZ>pAVFGBJg2ixK*U^dWgCjxKux zHi%sE`S{>KWQ`~fGz>(P9#M^)6Inc_z$bGj5m&>Jdd6QLYjq9{4=kjG1t(^^P$m0t z^Bw6CiX>GNXWnW=DTRDjDXH9Q_<5mC=K&<>UL+_g1q z=>Dk2_Y;`qiKgnltvi0x5x=oqj7S7?HD%?y=|Y?3<)$C#zpwj5{l@FQn9CX)k3yl{ zkB@Q2ntU*aINnsk7xP^oO3eNozF|>K`&wF2VQ04_A}Gku&7G5hkE!fS!NkF_AU>!{ zZxiF^pMR$Jt%gF+3i2bXPU%zD#f3cz$sbiHoB4@`=>{N^s(+m1>?F=3dTT#3jZ&hl zFH~=w9h93^fBS}%+U#8nmu{@AjMzV2U#|&3_WIT9AN4acB|*)VPNFnNsD_i)tNR{3 z*}XTivTNXK(u{&H1Fu6`0To6W5CyU!rQzF3%GqLyEo%I%EK{7P2^airEnh_~fej0t z5$NzZol7fef(v5@Xbqc=0*@P;SDmYmA>xQZxFs`BgJc^Uoe$b>Mvhds@RDm&Q_t}( zk1fT;%;Z?hjqy)BE|}Clo89}b7}sfZi!BwNufJ-m`6f9;m0?rdlL~RI!q7U8ko5ES;f$nkN-P_m#E-J%GcB1t3N=&`k+U<{Jh4`OUS2g=3ZqSp zPSfj2ea&ZEwh)UDXz0Lpg1C8MU<5vZUkJK!us+dZJ3_{ z`qovvX)7xyWT;+X8p-RoerD2A#~nd((w5Mzlqp)o9lp47Js#reGjh>uv#)2co- zyX*-SE2COKdt;i5#uy9I*jGTLRaCT<{KDPuwD|gnQ3-cF!a9UaDVAGxDjhOzy?Xcu z_9GSf5iOoF53({kw>dLO++;DXd@`bBTIEtE15eQW+X@W z@`0Y7po3Qnh7~~n_BN-_sQn$i4KxaoxYv6*(xn#DjfG}=n_M(h@U@q>q>@!+j^lW> zWi1y3#UV;xWqj4nQUztb*?CQ|jHQr$`xLW=&)<&{kGmT23bL8k?6~B8^;=L0*Guj? z~~2h_hhy(iIBJ@hkkAf zVP`EDdjC_jfXR)4#NKi)mS}^Dj0^`MTJw+MVTfo=$9T4>aKNoLl2Zw@F z)-KkA-e)s&bAL+S{;dKre+&q1v*y#$*WdOcO0kX8m8N;U{%fyTsg(?QVdS=9Zw#um zF*X+7HH3Mc@>PBm8H`T@u#G!HIJBi%1L9-piDrhG)w+9CX zCP7c_tqY@^2o8>pWMpJHd6c}2UGR*a?VZ5Bfy&Ch(q)v53YMx;Gf2qox8n?(N3*k^ zMtALOZFh5XARrPk9o+@v4}G`>>>Bv|y0Hk3fXrI}a>!>i#VjerGgtJ+eX}%_S}1n_ zIs8 zG~U0U>9b`OJ|WEgM6M#BKR?IuKZL{k{I(ogzrGu}gOJ@4e0jI|bD;ienQ=j|fM~wk za{oDV!UtNkObU6d>B37-Y6j8c%N0rc#6{mH*|E+HuM&aKIZ4n z4ij}Q_i$zm+EWTI0_=7Xv!Osa_wss|6Ch;=L12kzJyobwcz^qSA%8bTO=(-(R)4g2 zj0Q4;HCN;2-_V|l=pqif02h%zG;w;y#+PTVr>m=}Br)In1S0gVW=l_rh%&MmJNNWH ziFpd_$Nkt>)t==^Yp%lncuSeq*Pa-6MV6Ao%vv69`o-IAP&zxmf;m=&9y~#ulGN&R zZhC*8H&Q24cRV;urHXb^L|MAMGkltwRypb-@1mW^^17RUGd4Vs8-*^k$M?Hwr|i+q zWJDj$vML-Q+8EX2Cu$`GisU;AsavkyT|jTPTS`^rVmfU!pQfVX@z_^`MY3yVV9+-& zVQi7$xW4d$1>n1DloB-~MGouW>feqi5$t}Daj?(2f5`7u-1SI>i$z%f;FZo|(<1ti zmGy_yFCQdG_BP-GZANm=H7ERvoftF^dNa|AOJqSGxyMS6gQ zAN)~`<&Z<}9GpW@YE>rSfCxfd&HqGvvhRx^iDZTrV)NmHgXYZO!2#0kTaC^iwyJ_` zrZ6{od6Al$zM2ZXEj`ui-~Zy{m~T6r%#_u@(5Ivn!o$CPcxY!}G(`vt%sMt!`o^x@ z3ySJ#>6z^Q{O3lpFbP>*4CmM0UOdn+X|-4dxS{5}bHCiXzRpdg+CX>>-EW2&>Ii(& z+|=IPoih@oemA|m{HJCd_SpkO1rn!t?OmV0ip6?*BqoP;e69-Zu0uBA=jTUrLC!~j z!iEjP&NIlRw6?p~7g?FDkV`x=P#5-Ws$HSJ%3JRa+$3XAqdz?=rKY#LMEpp#} zWnr;57qF}){_dcP!;#{kD(Y)fAVhCt`_pPJMVsyw&)OO~D#<4%GvdKfDplkYP`HaY zphX~KQEpDbe?+}GawPwr%#<{5`Qt%HOSk#Qu|bQU88%>d0Y3Hi-oXC&*d3u^JdP3S zb8DQI#&2mECS{EIji=?JxqWSYd+0mn&H_~Pz3Y#fKtNr6cz%@J==4Xe347<0S;@Wi z)3KLo%M~Z!y58m{7!uNlM2bQ-&lQPj`TH`hmlAfc`;S42`3Q*~v6gV*;c(J26pn#B z)Rl)nq2MFj@2!M{V>y~WaT?hwwx`fleq6ghL$ky2^R7;Lj^u{HqAG*6mM$4-+GI#4 zAjh{70Y1AkZ-WqLF#~>Z=Sc<-H!H)!CY7aIz}ngr6?T1fd}k{m))M|+CAMGc zvmg!P9sW1mKXCXhW=G3@ece=*d^pm*IWb0xM5|W@bKQ3cIjY}c)@&#!BIk>@AKpy% zIJ!BV*0_bikX~Pjp?wS$bBIyj9aE@Yu!(b1xXI!z5^Hg{ld&F7qwnGeN6GAc@S$7W zle^y!A7Mr5lWaGd0`rell+xU|=S5DvIO3J1M4cINh8dhc~tG zazo*Qja^O)zkH$mdVx~kQ zepl>LwD9i|%Vu3Rx?u2K{QTgG`-4aC@qYrEBKWFjXKt>so0Ff~6xPMS$Veuz^!*M+ z=!S87LSuuYK)1H0Bxb;MA9j#{&?4f)NH976$6Hq+1lWzEBdre~&_8#;z9AyS2yg1f zllcPkUH(lnFC7wt&Ag}Q+Ki~MEcygWH|fes^T}duzPAjL0IAAItGnb|dT_Gb^S7E| zs#nobCUs1;Wo6L~BC)%>NXRPP_kWJ1Rxp*I-FwJ*m^Fci^S;UP{94K~HWUQ{W;5~e zPIBDCL>pUo^z^&i+kLNIamEdI^toL5y-A>aLi+1ZD}N=k6i=4_;e0?6egm|X(bv7C z6(rst1P^a~IM1J+s&!`4&6Vfe%t#n}&T;DK>c&8sc=#bb3FPvHC%aH_vRmMnYLVHo zafeS+^(nV16s7@ZdE#d}E$;UOA-41k!6fI=J6yVyup{2hZr@W(V(%zH$=gk;;0KtR zz1>i3`VWBo1yD>zDv%@^5@W_2)z|OjKIP}{ANm{UE*xE+AE!%&6Yc_yX?^`FIv&hbw~S=KExRkD zQ7c|+2L9jMZBsE{H?lz8K+d1ZtS*p~6XbybE2*v4pQ1FU1Dk3Q5x4UvCBr0%Lx!d< za&8f;rSqD?viLlrUdJLM4@yB+G732O`qw-laIi@VsktAA^%vVO)@+V=!<(b?HS(e& zUU-d?3nvXDS69T;fV}=xeDFD^FRJur<8OO(v^n0$`*3(=4G|G966$fJ7@(P(5JjO= zx5j9Cg`+3s#XH78@FU=UUsB?OU+j${9Lv-?mf_&A=pmxm)pFxopsG)aUWpZUqSWL} zsI3JPrz_go&2@cXM0NTp{u(b1PpCJwdi?9X<-5P*b-zWxOHQsbgNJ_r@b4KYASrB| z=0BbF<-@uELMz0`9y-mBz(&f+I(&v5b8=qaxlB7B^wyKvL5mCfRsHUiD&YC9I$ts< z=?29yb2LN}AgBd#@x;3|I{Nz3`R9sqhY%N`?+_fcJ5J;KV3Qwv@u#`DiqJRmZVChh zOxWZ;@NmrV_&i)|*iI%z`1{R->YxRU6Q3qY#;qnVKF=|oF7<8vKA^^NnQ?-&s zdpZc29@F1S+zp+dn`_eeqiqnNFi1S#5*5+#ROg@`cdX9N_VC}Kr0D7BXq#^IUN(Qz z_{pj(;diltoC8p65Up;!PrQJ+ypxGbDQu}gve&JTg++hx4h9$e=4mU)MoFgF;_tJj0zFtF zFDC%<8Vcj&J=4&xLma0NHVh&PZO2~?=@`YBV_y1QG^wj&xH87+0mtTZe|7!zkf9QL zG#eZ);pahdiz_(>C-kkIH_L$7z+|Ly8cuL}xp;y-ufoGfL;TY;V?TclSgBCPu zZ{+pTYvKO(?YHgKG3DtjZx<1SRPu|8qQ?H%!WoZ4jLp9uNlPp)RuDd?Gn?Vah|IqT z*#qC&!P=#GNO{4K^77H>yZ;JnJ~?PBXX;4i<)T(q&5m=^odC2~1icLw#Xac}T*NIW z9=8Y$ylra~d)<+BnW>iCgt{+e-%2PC~VsuFfj8&TqrajPSP?XIq{cjeYuHSk3DEK1U=t_Z%Z!3?C<_ zlp#$=72_r?H|yDkVUoUAJX(sNuXvO(K>Ira?cc`Lpa>?yLSvOBTdz~{ORO!n7H2GA z9CZu&TVL|_R1X22@VANgO;}!@V$Q@*vv1|)hr(;Z2>I%!-$POau+QE*JKxV&a*oXq z3uM1@^z%EK$c@dJ;-Y+uPn4mfGk-B!U#T)-)DjK~0=2S~3ovFiD3qf%Xkaz>yNDmyTV5!rsa%_r#aWV6(ZbEWrqU zM>=)q;f8a3Ld}2{#juwv6@b5*YW&%`vOOohlvE$f=*-Soq2fZk>I8Uz2%7d)4Zcm7 zLmA2@(n`LY7!ccqQr?EI!JU@E#>0&Aqs{Yh81n*z%=Yg7VNT~Y!>mMAv;`gAlejoG z^~EOd5v|;twm#TWoVu!(PqF0@PQ1Ll=eOso8WF>vNvoettQ~z9o^1Ma3P`JGp1`!UabHw8Hfcx;n!oSxM)27s*LqE)+wen=X?jt1wUa zPUytTuhweq@weT4g$ZsyPKt?$aEYysXB)ZFpZ4{2ib+U*gwGf)JY^=Ym_0ZUp`5^P zQsolbnDex$6>Hvw`crc)%y}jvxAcM9)&}V5(-Z{uRhez#-b{cQFd<4UogZwvfR=E> z>T;N>9@d+(PKlUE9S1*gXf*nLH+i>7j6z}hXcOm0v(NrHpF}Z4nYGiWPBZOmYwGIk zDRJN_oy|Tw`1$o3EL~eUZr@!#K$Mhj-0_n|(^y#MNmi%Q1cC+Fgk@8Cw>(6@78N~q zhiFECz&m7u5{6kxG(mO>ca}PvYDOuatJyTt=N?lhbziqR96b7^{sx*C{+4&5*mBwV z`E$ndiisMp->`ZjdZ$VHb<&IR`JRO+N6Mg+NzrUl%UR~kgMED)dtBte?d};IAI!Ae z_Vk>bX3B;$!8~0-f0^^EdxPz_!ot=j^Tds^l5pkalgF5X#_(2&z>wfGzfI8=w9IeP zbF>X&>4=U+wY5DmO{lIs;>`o)J!-=YhCK* z(@6o-MyosGdTNeznVr4frIfEKYtSsr39~*p0nuhQIb}yrge)8#Q60Wz1~bRK zQ3*Cr>J582@)(C8va4YIxQZZln8eM>uEZQQ^Kjw2o+GaOVF7DQ zB4|m4C1@7uB({J`rw#edR2oYJ>L$mfZKoVZ>D!Mof&SgnAUxVglW@qMx2Z+cu zBWuo_i9&4nXcxpG9mH{yJ3CP)2t*1LX9>23m+s|ZMh+r^{QMK5r&RF@q@)5zi|?86 z(UQW)$dDMp=~XJlE4hQiRE?pcyC^t`T<@^8pOp$efu}<|G#H3tJ-zF(y5Yz`tED}$ zQuw_z?C_UNDGW}i#(7AGc}0jV{pK|(m`v~N@ z$#WJL`{puJg78AQDA0MkulJ@WU!jNwi*SMb)Ljx<-+wanJ?+{ zxEQsA@ot~jCh&WuQ~Nn;Cbh^_0X9z}@NlWZ@`UzB=BWqgOUipmn3|B(dW`otXF8fMTz1 zd7`uldr;7qIn61yqF}@BVVSl~G6?M}fxv}AW4Q4OLWs1!-|G}zKt^4UApkPEz1Pcs zT78VeA_HU;33Ct_!8_S<+=TEh?eYCm*KQ3Ad9>UQ0d+C{sGrI-=()MnacKz{u^WLC zUo(oCZFnd4rJxuY9ZGI{&)Y+Ss_Q>~Y=)~$hdy$ra{ee~mz4oS^tEFV{M2?6S^rW= za3=HBg(kyVmt4XNBv@yAZ@m^)k+B69)2Y#OVe%>`pRRY7>B=y0UMPCGzGc2!0D8|h z!~zI%|MfeaPfjz|6gZoX)&+7+f>}8<#<3KHn4j%r_NEJ0M3}K=+ev+kjxjd#;@Og~ z;k?P9;wf@tbSu%vz0Nf8U(osbYmKVY__seeV>*uWWCQ7d-q>s;BE99RG!%{@7M4@E z_X>hgJjtGvG6%lT-4|H&@2jS}lgJJhW&b)lg={wdp4R4uP$&l`xMmvmHIHYf?B72m zv6;VJ;fROl%70l~S7hYSpk}hRF@P`Vf{cvZ3cjK2NW?b1m8#wzkI#>`7RXf-q#Cz{6f6AbP{kj(yCbno<-O;Lets^wIW?U= zloCq37?PJ{9i^lp{li-+teBOeUFoL0Hg?F)UI!r{a`&Z(`su61G)sXgPMPm?;TSCk zXA+sJF#X|kOz&1wDZ{I?+VauY!z57xw2;lOZ>YliF54=aA4jM(Aq9Rr%u{F556-&P zbd^l?QvM;MgC&Y)IohJ8}>sgm=%H|HOdoZWzA$7oj} zv!+9e`PUOk9B=Xy<1u4ch>_gaNwK!eC94+q3fRj16+b)W6MLz@CS+#wWwPW}G2Vo^ zP88n^)_I^~Px_$OpnAm0)J8?e9N!Gv?VE0NWEMdpn?+j5nYix-9Q@u$as(|wyw{HTEvis&P zUUEDKCSt5ZySK^(@#{psb9x;rMdb=AV-R7?Pk&#E$Z@L0w- zTkO1@^+j(qtYe`39s@MzpEBH-+BuECg{Ce+g9{A}&I4O=X#9HBst;d?K%JCTI**H4 zxq2#j!?1^o<0cu@?)QTbyn=-TV*5GTV40MKTv}F_y8H%|R_wKWoE~mz6jF?AaO?H3 zHMWlwhxcz4@-A*y^o@kiV7Z1v0n3oroOruhCf=798A6W9j1(X2D4Q~`R<&s|Jdoc` zG7b!`2l%6WKM00;+5*-(P)Q6BenfB*!Xwh`9RIHDfN+s<@AcFo_)_2@_4UPS92T7K%XKyv$sbRWtwZbnV2?% z7Q>I*6~VxOLMAu7H6Vof)i_K`D_&R`l&Wqf?MdbTu$=q9Sl==pqQZN)3m$LdZ=^F* z5y{AKMqJLvW6ZFzRsW4E>$eem=Jv+r8APphTtQS9hP5W9AEPUx zA}zziLMRaJ2$T%C8rHk(H5>dY!&uuY=@`Sv<5ob)BjNjEkZR}4k@>gRG{>GTzQ_}{ zfRUYBdnL7b;48S?l6$l1C6h&QvVW(oH=&5Hn95n3=;agm$md0J%y64lpbm)&53T-t z()aCP7;dQ8_TAmR)t2-bnn=ql(Oqg#g%Yevfu|dz<2>zZk`pPSHHSt+P|gf#yb)I|zB__KSVh+2>ytKYKmh)AVMYJI)WD z0C@6k7mRpxKv=wExFrW`7#EN+C8geTFyL#rvC*X7Sl5=>1phWadN|z+TrP4;m;G0;-DI_+wS1Fn=(rjX7%%aPQxUB}1q*GYP9EmAd}Z1V+R zAq~^^T)wL5DQY>j*RW0_hII-VZW-g1;RiXN|CxxcTxZl4UyOZK_nwAfCImsg1?6&2nWC+$k+fV>Q4S4LP#=Y+T7?XZr5`N@z|Dk& z*e-!pf_JUl6vPo|OPZ`aBDWk*|q1O`)!mXKyVnz*}ECwnN!`mCzagQr7t!5Y1n{_UAl zEGHtK=Icj=^?79>A(6zd#0U}0$w6z12Jxuy(SLE;+plM$pQtM$yTt1?HF@k;y!+_V zG5>&s9UB542u$xNQxBUL8OJe9Ghum-y>m7Ae?|b7F3|3Bv#u5(o2f z(ldtPHh^3X8|5S{{q1VObgbg<-0M5L5{Z9aXO4-%UA<-(q7FAK_I&r-i7a5q#&v<( z<#i=sZT&YQ8D$qdbYE^r39JbfP1KsSpXx&o)k7fB+<@eKW90n&3m(*}9jyM*)zYFI z6!bJeHycd;{aqh!MJelY!t66aId8f1@uS*qqPZd7quU+Vs>t|e0Wf>jEh<|?+S(1@ zTt>}mRjzD>-vqG6&CaBFei|9W zmEJjjmy_yiCpE!H3N2Ei4|FE@=1i!crBkgjo72YcS6{W~H>j1EKXnETHC1T{CHlPa zrQq_p27M}m$XlCXQ)bZc^kZRxcorQbCWj{R^Zh*+g9?i$2#-dvcmhzT*SFR@si(Gv z_1mH4UXZe`cRCl>r8FvrR+#HtU?0Y{CD@;+@6plI|8h1I!fB>$>NKGnEIt>|;<9&%P3_X=o%UyWZv6V{sk;j!#R(xfF(&iu;z#2uK$%8)E%sA@ zyemE6Byc}_JQ&Xn@8Al1kUB+B`GE~9yDpw!2ou_(N+s0-Xwe`-V+u-;$ok)1kCgGVmCXKkN{EwwDeEt>e@T zP!LD0J6I@6i~LeHlP7;g;V+ed!C~xHS-Ofx!%LWU@asv7KZbGcp-`KuIGen4r3-J( z2U!qfS*T1nQc5zetL`vR*OuIVoU~5HkN83#kbVdJYz9Brg%g@UejPccMiJR)_1G?- z7Q{fNo0q1mZSRGfyXyJ*@k+laHQBRkV!}WgT<+LP5e`WufBa|1JgBBEEOGMpDyBXe zo`W3&GHVW%ThL@W(W7lK3aJcwai(FLqd;nfYD$6h#0~P5F;4DwufWqTCrW%xn~Q}9H`_c`jJC8$m^T{rrZ$U%GsOsrQs?M*ecA^>q-C2+(@fz zQCPC}<@Q;bruJU4AL9P8h(QiS!yaotaOp9Wp-$E3^i6xhetus%#HafX{7@J-OiMum zPT|l5tgDmS+eowzK)dVbLP5bJIYqg*VLIvPQNcEACx-*T#~l#6&-XEBzS*SX52vuy zs7VYlCW&|qR3i>zy?p}&H~vT93x?6qyz(R@IAor zyy7nn@02K-Lqz%1sj4UAdatc!c*Ltvp+svd_c`=k@n_bx6~7|m5cn(ca9&*eOA+CZ z^qsFxa3Wg*v3?j)?ZZDCbtPA~a%XHgKNTA&-`if|`M3spvM=1Ig zALg`jI-{-O84``YII~{ZZ?`p#bDg~7Qqibv*Nx`!9IW+YMk}htP@xCA8w3yy1y@RJ zR=WX((K5Dp$HU>f69?U`y?pm_0G9z*p~d)BrsolD5X$0xxUVb2P@dqO$;Hhtde_$) zv=)4xKOejZdKs!%yrJv$!+Fud&%?zfmO#RNt%->uYmlw3L`B46Y_s5`5e-!b;d_5@ z;XOTwp7?d8O$Xw-=I4{c!bX~!!dqSY#{(1Gxmb`iM&7c%+(AJS)=H!a3=VnnizOi; z>-1vdaHxB8QDbTCU5*f{c0*1zncSysw(Pi>gU~2rr zq)B->;N#s~xk;(tV|Ae!D?8Vmb2wRyw5L`rvIi^Zt78MLnM6b$BMJ^XWtJr1grN}!&>wUeXi2p{z4L{5FxTV}Vh-HA0(-uH^@6HE;^f_e%f?V+z6cQZ>_X<5 zd7}_3?Z+nsaP8_@kdzM)Mr9Z$uwXF~(iQ~k-yX#o((jWP!=)3zI}wJ>=#|0Hq;+Y- zml@t*T^-d(L~gBM5}8&O&xO&D`DcA4UvK;%OFk*P(69byf~c8fkFH)^S=?vLi*QSV zT1LY9i7DMxj4r&xVb)em6muM}p_o*r;d>!5G>X{hCNWuzCf@k&+O7%px>A>*+%Ui{ z-J?xP8}k6qCW^Q|4!ud;OUE=`twEY`ZZB?wboxxs=7N(4njTx7c0_+v9%qKIkULdM z&JR>hT!4{WC}D7;eZ(9sSnyPXAFPe`d-%8RMR~s6y84BSPnzsdS?W&&2&jmm3Lvo8 zI8w0Q07d~CwunFo>27`$3YT>2j!r_b{Mxtt{6Yf|8jF*sr%|)T1lF*`^q`eH-A`Cx zCNpnCzH+#|%Z^VF>0<$*F(T@*IfKpegw_5OA{ZKc?8~(#`xE;P7?)cg_5F!H@*f;o zXkXzcd)w;m7vufnY}HswQ>ln)adARWv8<#uVApp0T^XULsNh5fStFqg_X{qD#$Ya( z4N9Y;=pm4Kc)rXwD@@x*togdZN{ko&aD0w0!U!n3+!Fbtr&SM;|?BY zOz=AttFSB@Ortz##!%I6%$lMsgpSDCO#mh6KBERs9;4x2BVnb6LsXb{v>_o4{uOW= z|I2RkR%k#@Mk6m99L}aPG(LHK4f=7g9I8VM_@-%$V>6;3i>`pK~xD3L3|x6B|+M z0#d)m!cUV1*Uq3)b@lB#Qw;eYgZENg_b$ktvg}iLGTQLwp`OUiP+nOqVP!+4bJr=; zKP^H!@??&Eli2NM@nm<*GUgrv6Kv~?26ykPZ-S1G)tkKXNt`i7G&W8`1k_7G^9mu{ zJ3@Wdp5RXNVrV4asY-^*%T6Oul9Y^#6wQ}69%YG7rOS1up@_$G>Nqp%`VGrJtN3SU z*8R#PfJ&rAW&B5GafE{U%H6etgN3E}iE0ZXW##s7_3+yb-kSZ|pI85n5OBQML}T=y zB+)D|<9%UA(#}&+ZPI0rpt4nQu3|{*_AVC#$1=p?Pc9YY>C9nz3LS08K zC=T}ayyud^=}@zV;|$trU_{~GHMv~nw<;edf50$FeMS!kL68xK;m=+RrZD}E-DFLz zfqDYoBYqXs(;EQ-jEoo_KyK}Pz7=`$-8a?7I-9GgXQ2N)qNFPEBMX;mTw#sVR_xxT zqRB-wG!7l1#rU=$WUV3G7i^QMuKOFe;|M){P1&;##DrD7(GM@K<8!xV5h}AJ9R*tGDcFWHA)i_sY$Hu<4b4ASB+D)zt@ zOF688X0jC+o%7gKC+5jvvFX`PC9{ras~7qjaZoMeJn(5*_&d^ShQ8}&6*DL&%-HJ! zm7~ozw&&ykClEPezQ-mL|1^e=s2)nfoJ9DVV?D8dVl1AEemu>!U#JoPV5HKASHZTZ zBA-nKht%Lpckgg>EB`_~AI!+de=u^CTQ7OFd-%k3si-;VTIxDM9DfdtLlP5<>EMyE z9hMPmm3qvoQd>42b>6oCG^E)F>1#F=@cHRSE}ZIULylJYAFMYxbF9Ny>*NMBmE>Tg zEm;=(U~od+1AdCcqvc|^l9bu^td#M}4iIEW7Z+KO zut51J*png;wpdtTOMxRHae4NcVQFYp>TyGoaF&goY%{`8-h6J}cyg|oA4+jor`VYn?2`-KLqwJkolI&SJVbxWvsYJ)wn{B zrkUt_0ON@-_0S;R-uA1v+r55Za>V`xQ$|EA9#l!AKju1A%qPHA#_avsJd;OQ7Ct2M z3(eBKj+UZi7ES4FEuc;@r9jX$FsoPTCB-k#!9p1EMMCut_q-jx@f)?T!eC#0qqr+$&>7;F? zDnBjorsdz5mStll*6!P!IDLu(K_Y5Dof~@0(;Es2Jqizp$yLS5$+s(Et&+K#H`aXq zqHx`L7b>vn%*cxfWoQSML@dTU(_VMq$z*Kq;iti9?(28f{X~p@8|+$mPwmFM{@FQk z-Bwo$Tur;*vUd-D6|UuQo_P%ne0xy>qz7kaNJeI%q47-fmjm?U{_nzl0ZkU2OWrV2 z4o-=q=exH+=)(eKQr&hoEi^cZ0EPQz$9#0q9Qz>q@^Mg}S}7k0^}sEEi&ciGoxcQy zaSeG79|l)&)Y8N|aWPpw<%tnW>#_#eNnD)SKs1?AbboBfi2YtKCaS0Bx2W0PlO~tt zv-O(mJawoZP>MjS&#Se1T28-Pw@udwM(II z_70Q$N2sFq@*ZMiSuV*Ye57x6o#&7wSqSdNqdAW=+`spplcll z=4y(PMj8R*cg`TEyAREIlF8d#pP2g&u1_2+kA5tvcsbBh%PlKsZ?Id%Z%jP%u-~uP zvkJqDsi`R|q?d8WO{GIRqlT$E3iTz8+<>@Hv6Znj5T+fAVPFhV%JW0m+v=M6#;0rj zO-kmuzNH!-$qDa~zb2AW3_rQO0VDd#uLPYdtIP}y!Ri6DLkMR@{PdK!wTb>)%_iOP zoP^v|YG^|1+Q8LPuQfln#BKj=(uU^+8u>Hq>`cYEF@?|{nHURS*r#k#0WaAqEb}nM zY1k;$!9=TitHtENv0IO}D$PZ1ry{6=cgR?7wm)Qa(Lzef5uyD%o>W`Tz}LG5;)H!c zEeu(P<_nO2QsE_Sc4s{P<{_^3TV2b*7nv0BkQMaA&NPS(j*Q9Btku6s6zQT~4SoE2 zC@4aN!d`Bn2@Ty987V`^W^HZ#6zt7hBeoRoog$sPz+g7{8~`^krD8AtB4R{xQhFavkKs!66)iJA;EA zflQwNPEhb(%A5uLy~)B1Qt0&LF7FEoN;kG8CU(A{b83o=)T1u6eZnhad2upA(sMNy z3=?=?>?T(QpdJzY^Ar4&L~E0a3u%13sX(euZ16zByc5$veyDh%aKL+qe|qZV600O% zmKNyn34#r0r5I2OhGKBzo0M2@tQ~frEnWz?lRsJo{Z?aAPTO0b&EUROxdJU-PXXRQ zmFeZ%23lU6FrSBLY)ie)eHL76Y3}57;o}bAB@`Y2r}^8uD=SSBAcvh2@P zvq;)PpzEiO=VJvSC&Z7d&;99vzbe0a>5@Tg|g9^Jt)fY2=;TWJn97j4f2+pLw#AxgsL3>nGM@Ls*lkS|9gk~qC3Ow{WnaT zbq%|{>Sn8h-t;e@8Vy1!a84~HU8N#Nxd$Zmzi1Cg5bu8s$aG_IHKGrbUwjLTSV&&C$ToagYo#?LX_$WckGMhGlcRgM9Dp z5k9Y=ovOC#iWD^a-ET$;!ZAgthhtD3lQh97xVc%oT@7u*I*G~(hQc6VNQIz;y7!1J z+KMp+C*(63_q=w|vLQ&sgNu~qyz%Kt%$MjRO(~YL#HO@xf=}P;Vie1d&n@rMYT(6M zS;G34X5t}*@)6~yGb#h`9b0yPz@eg`tkDM27M*(&kSgKKLzR@20FL<`J96%jWsYKs z?ZN2o++mkH9$wLFEcyllfVMSQmZo^=@lNkG1}Jz-byVvB?G=kl)4LEHiWPP}HY1AT z)r9+B`VVn7itU|p&w3oxSdPv}?*(!bgYRZ$7EFYoGV!*p3U&xmME-O688w?V_%&CAhQl?;@=}_h_&6fpuQ8s8oaCIozAb2 zX*h)JxynQPisi~0)j=eXNy)NvTHU#O>b&gJU5X#cQBITD;T6`DDM>)wLv$JuvjQvf z%H&YTYR5@Z>iCJZ!dN0@rz5olr2RdRq_GQ+_fcSts zfRX`{b$!$DAGog)CA6I0;3LAK;j?$CtqJ2+3GwY1+ico5_T5wu$MrL!bu;ymQ?oxw zgt>bDrnIqDR@qqySh6rjXoBnH+?EjEb`>DY^*I& zYapai=A``UZCn3K-iMO!s7{e|CRXA}kiSu?6YPSR9b84Y{g3SCD^mY#QV;L|&J zKH_JlJ9nrHo+8df*zq@pu_AyyT&Td>VOvJ1uQ8tAuQs)(XNb42ak_4LveJ_wMcQQW zHo!^CY+Vu?%bv2-9kN12xWD+({B+nCHB9Gk9nH)Sj@5-GM1B1t-oeKjeZ3z1x_z!5 zgYz~7oO?DcN!MQ;z81Zv-L?1kXBmHj7U?(OUAD6YW8a+mLF%%j8spx-!8q^RKMFHx zXCB@z(6GZ=a3WKN*sKdWJ=CB)fC6mmjNE1-13q2$Jhft!{KQz)D&3$0|f$4Gj2QlURJjY|f0{ zJnd2F+rGQ!CVpy@HRuR;;CCL)6B84Epib1ACHEIBg@UV zLt;P|sTv&>^@O{0e3-Xav(9~wv49ccZOSr6+-_if*RUZM@Ak-vh`w~7JjxZz8Ch?D z$*yi|0d(Om&wYvodz7!u2H{=E?+%@Ga-S00LV{PO96B;NS|8k(TbFJ?*X1 z_0!dO#WYF$2?pA*>PcH$n9T)8A)|Ni}=PtTt!a4ol*ev1p|?`QoKv z$=Q9>Fc%rF_7k@d8FmptHoeV~TK)#gz*Wex=e@pfg|LOPM1I=#zcKd|2L!UeL zSp9LvhVUVs4ILdNf7juQMW1cUWAA!m%qfJnu-z@GYaVQsg!q@I((<_pj(Tbzo0}px zNi+mxg&H|IAYaYz=!f2S=fKGK^f)u!$z?If)?Q6bsxrr}P1K)gOKXCW#ZbWoAQa*! zqKFuOm{;&Uok1fIfrqs;A(!eV16)nIqGtgDDMNmcTr+L*Um<{_m4 zxJl#c@Xt>Vc%vkGwze+Vy=R*J6Dz$~A3!|nK@6*PS~!A%_o1NC;lTVLJJ@=CPmWGQ zR<#Y;1qiDt81&`!yXC)P@8(+h;<{a^(cFFvr4Zx73Qy{>l&MAQKw;xQRA1d8Z$4$= zlOr6I<9iNW#2SoRqeZ{p2Jc?0(&Q(tyUxy%uR^C*G)v*q9vU+T+JPCmH(NWnxvZD7 za&pMj3Q~zggTv4(n_W0;Tr6y%Su1KwOFsjet~__%-qf^FN>B9r zK<~d?MY`ZwTW@g*DTpx;6R^HamYtRPiB?;}U&Az&E(JO*-8s(c&YjT}CyeHvVI|U` zkvw_T_j_=T%}q&(k+Q#7+BOPC9m?ZHXbAlHbdBt}4P>p+C7S*XlJ@BR71#qoDVbDf zG{OtnmC^;w)^q2%qGk?QepJ_@!|5<5V+ooNY9vXXY!Xo}KF2y*dbNRagh?X{IF~da z(6b-OOyg1meMT=+jcivNn_7|=<|%GUOR!vbTy(MVV8aWa8mnl)FfcH`3A<>H2cJE< zGG=aBik-g+Gvo`S08W%0%(kO2-YeQ)RpY5WmmEoHlqA+^e{4z`Hva~4Z4$kEU7oM*W|A9V@ z6R`Oh`auj;aJFLv7`2vv$82mu!9(WHx?IcNtK4&mw86+Sio*Ma8+S~$TU&EOL&>Pd z4wg4ztKYXpN7qVBTA^sDla+OM9!Et;RNt$`K_VPf35!g3cAj4{G%+izq8!0;;Z|Xw z38*M_HNvH?iI8aX^@flrQ71|#CMoIRPc@f-B@WKkeD zLzzl6Ei*Ya<<*X-WDd&vgG=t}gl%+*+SViv>VgEyjf>j^bldV70t36+n}NtS+x~+^ z)A{SgzTcr4y_eul5Bl+Jz0>+VcVHSFl@v-xI|DGiWsQN(%0rA1dn9tJfP53J7X!Nr zID2Zdvhg@P5lk&1Lj#sf*@w>L>)Sj{IJS5Y+*S|{xymP!PvG^aiTWj^26!6%;ui_~ z2H=Mel6B!y*FV_FEcs$ov^TDuel#X1!|p*emxgh;ReoN?#x2^ppnpTD)ah8g{vC#5 zI#AQd$MRhZTd=N*$>>OIjE$h)FbL{wvZs^na7z|rr%(}l@@Yc|g|(%r9)0AmQ+rjr zs?vJIgSL7V*L%erUQqWJEeN=%8Y|D8u=jvwSd==;ZsdcB_1CW!ycSAmCGKg}%IGnJ zgi9J`QrO})akW!s%v5GN6>b9ja5ZtYy`95~^2njcRLcvSd;4G*dFWHGiMMuADXy}E zA|Bf=U-Yms1(83uR)l$$K3dsF*vqX03IH!O^(?iT}xi-@ap9B>Z#fha!!Pq zcE>tMP~}$Inc$CHt{W(bF4|M{sIK*U78`+X?P=azo^6TVF7FyKI+vGja54-pF(2xt zpV~OO`%c@fw9m=tz?mC{g8y8+QBIkH_0EfK@T7p| zVY|$KRDcRSLdlmdM%>~{PxN|wxOX`?^-WBT{aWjF>0Zg6z`?+XaGFymTtkC%d3LU$ zw1$}spmBM3Fk)8(of`i+%ySzP<9ES$b>Ab8*AD0+v;|R6$f4*2+rjoD83uu>w6yK^ zKn-PVDX6Fnu+@8*T3=ya+f0zPwp&e88X zb)>30K!tfGK!D7%?lBs;6i{FdqbiE@sg|7(b$~eso&q$f%|FC)?@q$J59CyL17yYjw}X zPh(h(_v&cx4*gB>e^{nLb=H_PHm)~}DReO$ziMv8fJ7>oFwLJYGA;6dLE877NL3t5z?)7hH zR?Bb4D4a(;;I~r^<4r)eH5!d_YDa}mYgByDWhvj)Qsyk`s8<#+E-w#D0K>Bd64S$N zCKh&oYP`;CVnFT1$Hzj-UPQ$E+tuKGIv2cD7F#FuPOpTl)u%yps#Gyda^KZOCXdYg^h zIlWjSbC=lH2t6WXOutlWqN8uOuhL2)rB46AcTsWu=G#HKx$8gW+q^B*3SYM9<)U&B%)pOC>JR22YMnWt*3%8dodr8?)7!@4sH0G&D zuDr)rf5$+l-tLtOFP>|P;*AX!W{oLqzWi&tAG ziFnO=^EY;|xIjBQIbZZU-EqW85z$mxc#D5t&5O%g`U$Pv+Ng$!&Wu<*ecK3rm<`Dh zk(`7=50%^lnG=$kA^jN?o1EjpjsZ2?+K>SWgOF`_f~RrP?VhP#7aIay0)ZWwQs3bS z0*Nu?Xyd~kCX7aOc#klKg3&EjQ&DJ^M@%XFlZ(X@tR;%71z!YXu#zbV!xxjh1Y@d2(DyGzn~_q!3V% zpV{F*_qb1sS8D+2qSx7wQb~X~%{%qYUa{4fMI`AQRMdbI?sGUXYNtz3`IIB5I<_bw z%UY!Q<@Jnk$nv$KFtR_@;hGLb+FGdz7!C~T^W$5d8@b*)SGOuBCy-1$u7@HVXLtqH z4AD(&T}VUe!!gsGg(-gZ$8EMHa%ju7uJWH{`ChuGLg`j~SrBTBsJG)1jN+%8+yV!q zGzNODeu;TM3Ni(<#kiIRPzJvbilUcg5bnv!FWG(ErmsEFVQ&Qkq;8%@N3|~#TE=>n z>Dx&?8iv9&@;W-S;8TNqL%KUv;u&Vj)4j(tjM{K=Vo!31#@dYcXhO`#+s#2irxKlC z4^-@k5d?GimMEy?NLnt*SfMUt%N=DpS?Kpt8_UAa(KZ_dCDxH{ROeKWWqjv%P`U$% z@C7!=^<{&$80!^sQDN!QDzC3ASh)nscWD`-7nQ70U+1#`+dqY*`35I?04p62@tMLh z!3MtVn0yJZIus&#DB}Q?1U@{9Rbr>v+QLbBz)j(0s4S{@v}Qb12Wus6gZ7F6lW{WXg%Q&Rmdf`53(nRSZ+M+>Q#g)BB5?!llVZ5II z0D}A6Wj6eCb`^OVL@#j|_IdrQ4@rb1Gu4G?wLp;H3b1*3cNDP+bNVdr;cDv?-w71% zg0IbYh@RpQysSM8my^4jd?k^^49Vp1emxP7vhE|bsvZf(+MZ&;@Vt(ilvCR8ZZT|` zshXECIKA(v&a;r>t0tL@RV~9t0s-cgytD7>wPa?438suwW?f_yT)R8 zvaSu2FjTT`wY@f{Nl9MNT;!Rketntz(9`&ecs0{mP{awD(N zUxi?pUd&KcwHI>BcR|-rTFPaMwRb&wOyC&j2Lm@#A{JO=N_Rb*qLWU)lVYvNa5dy= z(OD6XIHBReJl2#bkk+)K_cLM!(UI`P#eMY_QA31$G2tu{{>B8qb^q3oo?WP{|N00A z`0(e}!SLj=ozz6_xgFss^%+)u9T8z&@blIi1=JRw03XR$ zCT;K6?_;Ricg9G~J_{T^+>&AdR^#KNuFy6Xc`-?7jnP|L(}}+kKeZ20Bz_B?KICul zkJ4FwdD-XwgXvsb9El~#-7HKcW@GyTW13|s^XhJ&;yS?==ew5xsl+st8It3a0{65>;mYC5m z)n;`G+`SARS!0V`U)P8&Kl)jwE2k-(wKUu@W#vitcb>4h6r$i6k~1f&5HBHRe%~15 z<={*ey+VTre!v={q0CLn_ctti`SP5`=)jyCK5tBli4Xd8a&YN)&d%{nz6qHwL5_1! zKu#XM#K;f4iYBD$R@{Yj(W4Rl0X9IzKZicJ1}^NMcUv+nP{N@%JM4{PvQupVm145X z-a=)tYMCz4v+Qhi79Zqr{9E=nPfI-}C4zXuH~&^$Er9kCv2tF!Ddp145@;m>jYX@h zfdt2Au*Il2l5m6JwXbVsqmEmSF5-G4>LYDHqUAxMk~8>|+a2yTybfk0Uq&MA*qFxD z@H(xPm+0juoMBaI2ZX*J#Gy=27;K>!Zd?%NgxAJkheQUbWep&Yt#m$Y*oCc3Vq1ZI zCmDcY6@^s*&PYwX%T2#aJ+^6chBKp^U%Y$O(Ya}9q-UHp=$J!Ib0J3BvN#CPtjzp8 zs<0|Xp4bA*t8|jDtY29(wou)1@rUgX``Znez%@4r``-vfymYB3>}$t`NW8|B%>`mv}XW*+>O;Slh5K1ybrC)YK>P^0qz#=z7mcf$w+%U-E zDUjF0F+@w*+7QW3PUfFdb6tr0K{yP3X|XV>_WL)cFE#JJVyf7NZtO~x~s0@lr5nT^P$)>R^(&WNc^Ow0=;POuY98li05~ic8JQG5ozt^~bkuIBj!khY51DTTFHeYCT|}h4R@H!Sz)) zjEak(0*&FF>v>m%8oZ(#%^1l;^~kurHy-_4Q^m$?qQRVz1uvz~l*+vmV%=LO-$Z7F zw2{&rBB+F-fzseE}Hif zL?GQ%9wYDmAgesKLTj4wWa0NLcotYB8+r7dY#>EuD$OJM8IK(09&{JXF66#{Ld;u+ z{TCPz0SMfp<@u&TC@IBH=djw8}K)_#-EIyz#qoV|x?^GAQ>CA=BK%{K|?kQ-Z zsI*cauAz<%-0pU4|TWleJl52RA3=Eofu~%nLa=U1pnmoADP)ud}=}?VveN5h58EwDNZ2ok+WrHk`co7S9TpEzaB}F3?c(psh z#z}fE3%|DjUZQnzgR$2$`-+x$Lh|?T^m)ECe`g343GKubT=kmLcpS{U@h4;FFhPbbY`{*FrSvs{g zYquC!=eg4*N?BQ_9J!E}x@$S!+*p+q#{aFudTX^ihH4*j*Ku)RWtTh!z^Mf~6%voo zk;eeZ%r6<>cMsGJGv&!G9il85tbIEC&Mum{bN%2dU(m1r`X2mU#ZQg>=uOzcr9iqJ zT!Ia1NgACY-5F!PP@BJnZNaPuKYGk08n}~nOLm>&YZJS&RGB#G?ecp8o_?F(n7qwx z#@pZ&K(Ed`BeizgeOy5z!NV_$msxwp?0RT8-i#GkA5p5u0*quz{3=$^MUjAgjGt)~ zfW?FHg5S+%^XM)e{ zW&>6!eCJr))h7IDamTBTDHGQ%T!f~MbS=_@fS9k|xgJHWfwxe^`K@B|wMCQf!&{^l zFVD8~s$oYnAjBgJ8nL@tr>fKlHXpdd z08&qF(Ty2hHq;p^3j0B~dricE=StGg0%(B6yv345(7w&MxHS``k6AeSs6ZvJDmD*_ zJ@99}Jo(fiIlAhN2z1K#rWmx@Ca2OLIDHzp*CQ8-*TJY(_32sE>NXFV>r6RYV0qAw z;jS(YeaDO(K*uQw2CTn#?`QDGES01|<{0>Wds#emRGdgiJ|HFh1^=JyX#{K*xvziB z=^{V?0Qi5clAW!Yl8Lp6(ck|~#x{x5u^OO93Az17C0x}gJ2ySeLl?3~?@X(*Wg|km z)PNmHOn|S0`TbPfjA)4Df5^J)3Uy^6I%2~UJZmWT??JHC-m`mv=wc@q4pwoE*Mb$X zNd^}Up^Negbe_tYyWzWbdl}n_+HeX!$JJmRDl%ccN?&^g_=P8!C+h34`^`jAbzjrvEeU3WW zU4Kn*IUcH#JfQV(+&8@p>9RV@r^tn2*#D`X(JAASy2FY=WrbaHX<8^_f(KGtU*HNo z^&)vo-Q-{CEPOiu0slV()!oNF8}Tnl;}8G3_#- zJ6Yhr;x&5f6EWum`)`&2{*N($+`^#YjDC-BsRcVCoPa`YwCi22I&a$sr-S@C%=n4 zg}%NPhULt&CE%R)J=+m>b3h*kIef;-PKS$Wq!h|Ab-qne`7`+|3(^1=>Og@SRXd5D zBZIBqK)wMgFxP$6(qxD0xT|Z^A*!`}v+O?xL{Y7A0sp11R0o=u*3}+R)#Gd9=v20% zB2Qqq3Ug2K1%La%XcN{yAPz4@Z2zB9Y$20>_GnUoKqvtJ|H%4(pYZ=W{Qs-@zXA6D zsrpZB{QuDa0QfijAJzW@k^fKWe^TB5TPpjn8~snl`+sWxb5#DfcEa=jHAeqa{GUDb gzr~OL0Q3Lf{Z?KI6zsq51O0c>{(HQ7pZ~i0UkaAA#Q*>R literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/Archives/modified-default-20220723.osk b/osu.Game.Tests/Resources/Archives/modified-default-20220723.osk new file mode 100644 index 0000000000000000000000000000000000000000..7547162165c84e5cd05b7c2cd259f17add5940a5 GIT binary patch literal 1383 zcmWIWW@Zs#U|`^2xXR2JdTQq0HlX?>Con{nEK zB&mxv{fasbEB*hd%(t;s0&#T`mGTx)X?bff(fQ z%)GRGy{zK=Jky@tT!$P4Tz}Ub-4V)^c<@@7vYouBy6Y*63#yWtT}c$q1W z$2a3+uk-r9M=~B2(VtWiz31D!f8`nX;`7~I+%s#kqpqP{Cc?1K8+viWzIr50Y*;9Atdw|EAd$%m6i=4uGKad~z7{8G`M zzvRLG1yL_dS4`Ae`sGh8=T5UjR$Sr7_Gz@gy`$vgB$alv^4a!`rx$*(^WM9*{_My5 zw>CYim|Mkv&T{gH#tppYArA#FFMXulTbgh~VY>!bps~4WMLFA(HzgPVzUMFZJYHx8#i|^NjzYSlO{8oLgY7|$h_4j6Z z)*p*^*Bd1bGQ)!tx9MH*e_ejz=gp08YVVjAukDg4ZA>_GQcHHZyp_${m50+0{d2ie z!Tc`Eu;k1K*`iHiEeAKUvOn3+TAzCG=5zbzC$}pmFzcD-&3H5+d*PawrRO|@rFN)$ z`d8eDZE>kX;^92~cjlj6(2hzd$dFjEaIjPAd;0TVLu-EUffr#68yVj{UBR1Zi&@`pd zrKz#8OKjSzW>5WDCP47{dG>}}rYw7TnQ&%{Z(o_<9=Qu=ev12jLJ zE9ks0&`T7UFj2k3C7r^>dQrbvgY{;6iEP54HerMkWyk+yx9UlpvrHM8S$1bY1AV8>$Bw y(mSEL;CUTgD|+5TXbl6#684;kZU%b1BFwO3#)#zrZ&o&t0u~_r1f=6xKs*59D<&=g literal 0 HcmV?d00001 From f9f9b65c86baf9d3a5f18dc422b720e925614d5f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 31 Jul 2022 23:42:18 +0900 Subject: [PATCH 0189/2686] Add test coverage of deserialisation skin layouts --- .../Skins/SkinDeserialisationTest.cs | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 osu.Game.Tests/Skins/SkinDeserialisationTest.cs diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs new file mode 100644 index 0000000000..699c1bcc2c --- /dev/null +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -0,0 +1,78 @@ +// 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.Linq; +using NUnit.Framework; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; +using osu.Game.Audio; +using osu.Game.IO; +using osu.Game.IO.Archives; +using osu.Game.Skinning; +using osu.Game.Tests.Resources; + +namespace osu.Game.Tests.Skins +{ + /// + /// Test that the main components (which are serialised based on namespace/class name) + /// remain compatible with any changes. + /// + /// + /// If this test breaks, check any naming or class structure changes. + /// Migration rules may need to be added to . + /// + [TestFixture] + public class SkinDeserialisationTest + { + [Test] + public void TestDeserialiseModifiedDefault() + { + using (var stream = TestResources.OpenResource("Archives/modified-default-20220723.osk")) + using (var storage = new ZipArchiveReader(stream)) + { + var skin = new TestSkin(new SkinInfo(), null, storage); + + Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2)); + Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents], Has.Length.EqualTo(9)); + } + } + + [Test] + public void TestDeserialiseModifiedClassic() + { + using (var stream = TestResources.OpenResource("Archives/modified-classic-20220723.osk")) + using (var storage = new ZipArchiveReader(stream)) + { + var skin = new TestSkin(new SkinInfo(), null, storage); + + Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2)); + Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents], Has.Length.EqualTo(6)); + Assert.That(skin.DrawableComponentInfo[SkinnableTarget.SongSelect], Has.Length.EqualTo(1)); + + var skinnableInfo = skin.DrawableComponentInfo[SkinnableTarget.SongSelect].First(); + + Assert.That(skinnableInfo.Type, Is.EqualTo(typeof(SkinnableSprite))); + Assert.That(skinnableInfo.Settings.First().Key, Is.EqualTo("sprite_name")); + Assert.That(skinnableInfo.Settings.First().Value, Is.EqualTo("ppy_logo-2.png")); + } + } + + private class TestSkin : Skin + { + public TestSkin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStore? storage = null, string configurationFilename = "skin.ini") + : base(skin, resources, storage, configurationFilename) + { + } + + public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); + + public override IBindable GetConfig(TLookup lookup) => throw new NotImplementedException(); + + public override ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); + } + } +} From 98214beb6cd92b272872e6c8645aad185b7ee640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gutyina=20Gerg=C5=91?= Date: Sun, 31 Jul 2022 21:24:41 +0200 Subject: [PATCH 0190/2686] Prevent overflow on beatmap info using scrollable container --- osu.Game/Overlays/BeatmapSet/Info.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 666ceff6cb..5517e51515 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; @@ -62,7 +63,7 @@ namespace osu.Game.Overlays.BeatmapSet Child = new MetadataSection(MetadataType.Description), }, }, - new Container + new OsuScrollContainer { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, From cbabc4886cc7b94abca634ca618525fb32eb5cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 17:25:11 +0200 Subject: [PATCH 0191/2686] Convert `ModPreset` to realm object --- osu.Game/Rulesets/Mods/ModPreset.cs | 46 +++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModPreset.cs b/osu.Game/Rulesets/Mods/ModPreset.cs index 367acc8a91..2c3f574d47 100644 --- a/osu.Game/Rulesets/Mods/ModPreset.cs +++ b/osu.Game/Rulesets/Mods/ModPreset.cs @@ -3,6 +3,12 @@ using System; using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Game.Database; +using osu.Game.Online.API; +using Realms; namespace osu.Game.Rulesets.Mods { @@ -10,12 +16,18 @@ namespace osu.Game.Rulesets.Mods /// A mod preset is a named collection of configured mods. /// Presets are presented to the user in the mod select overlay for convenience. /// - public class ModPreset + public class ModPreset : RealmObject, IHasGuidPrimaryKey, ISoftDelete { + /// + /// The internal database ID of the preset. + /// + [PrimaryKey] + public Guid ID { get; set; } = Guid.NewGuid(); + /// /// The ruleset that the preset is valid for. /// - public RulesetInfo RulesetInfo { get; set; } = null!; + public RulesetInfo Ruleset { get; set; } = null!; /// /// The name of the mod preset. @@ -30,6 +42,34 @@ namespace osu.Game.Rulesets.Mods /// /// The set of configured mods that are part of the preset. /// - public ICollection Mods { get; set; } = Array.Empty(); + [Ignored] + public ICollection Mods + { + get + { + if (string.IsNullOrEmpty(ModsJson)) + return Array.Empty(); + + var apiMods = JsonConvert.DeserializeObject>(ModsJson); + var ruleset = Ruleset.CreateInstance(); + return apiMods.AsNonNull().Select(mod => mod.ToMod(ruleset)).ToArray(); + } + set + { + var apiMods = value.Select(mod => new APIMod(mod)).ToArray(); + ModsJson = JsonConvert.SerializeObject(apiMods); + } + } + + /// + /// The set of configured mods that are part of the preset, serialised as a JSON blob. + /// + [MapTo("Mods")] + public string ModsJson { get; set; } = string.Empty; + + /// + /// Whether the preset has been soft-deleted by the user. + /// + public bool DeletePending { get; set; } } } From 345f10311935da5f49e7f230acb82e3348af8fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 18:01:11 +0200 Subject: [PATCH 0192/2686] Migrate mod preset column to use realm --- .../UserInterface/TestSceneModPresetColumn.cs | 61 ++++++++++++++++--- .../UserInterface/TestSceneModPresetPanel.cs | 3 +- osu.Game/Database/RealmAccess.cs | 3 +- osu.Game/Overlays/Mods/ModPresetColumn.cs | 55 +++++++++++------ osu.Game/Overlays/Mods/ModPresetPanel.cs | 11 ++-- 5 files changed, 99 insertions(+), 34 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index f6209e1b42..f86072dbc0 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -5,10 +5,14 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Game.Overlays; using osu.Game.Overlays.Mods; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; @@ -16,29 +20,54 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneModPresetColumn : OsuTestScene { + protected override bool UseFreshStoragePerRun => true; + + [Resolved] + private RulesetStore rulesets { get; set; } = null!; + [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + [BackgroundDependencyLoader] + private void load() + { + Dependencies.Cache(Realm); + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("reset storage", () => + { + Realm.Write(realm => + { + realm.RemoveAll(); + realm.Add(createTestPresets()); + }); + }); + } + [Test] public void TestBasicAppearance() { - ModPresetColumn modPresetColumn = null!; - + AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0)); AddStep("create content", () => Child = new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(30), - Child = modPresetColumn = new ModPresetColumn + Child = new ModPresetColumn { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Presets = createTestPresets().ToArray() } }); - AddStep("change presets", () => modPresetColumn.Presets = createTestPresets().Skip(1).ToArray()); + AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3); + + AddStep("change ruleset to mania", () => Ruleset.Value = rulesets.GetRuleset(3)); + AddUntilStep("1 panel visible", () => this.ChildrenOfType().Count() == 1); } - private static IEnumerable createTestPresets() => new[] + private IEnumerable createTestPresets() => new[] { new ModPreset { @@ -48,7 +77,8 @@ namespace osu.Game.Tests.Visual.UserInterface { new OsuModHardRock(), new OsuModDoubleTime() - } + }, + Ruleset = rulesets.GetRuleset(0).AsNonNull() }, new ModPreset { @@ -60,7 +90,8 @@ namespace osu.Game.Tests.Visual.UserInterface { ApproachRate = { Value = 0 } } - } + }, + Ruleset = rulesets.GetRuleset(0).AsNonNull() }, new ModPreset { @@ -70,7 +101,19 @@ namespace osu.Game.Tests.Visual.UserInterface { new OsuModFlashlight(), new OsuModSpinIn() - } + }, + Ruleset = rulesets.GetRuleset(0).AsNonNull() + }, + new ModPreset + { + Name = "Different ruleset", + Description = "Just to shake things up", + Mods = new Mod[] + { + new ManiaModKey4(), + new ManiaModFadeIn() + }, + Ruleset = rulesets.GetRuleset(3).AsNonNull() } }; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs index 62e63d47bc..dd3c7000a2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Database; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; @@ -31,7 +32,7 @@ namespace osu.Game.Tests.Visual.UserInterface Anchor = Anchor.Centre, Origin = Anchor.Centre, Spacing = new Vector2(0, 5), - ChildrenEnumerable = createTestPresets().Select(preset => new ModPresetPanel(preset)) + ChildrenEnumerable = createTestPresets().Select(preset => new ModPresetPanel(preset.ToLiveUnmanaged())) }); } diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 1a0c03af7d..5f0ec67c71 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -66,8 +66,9 @@ namespace osu.Game.Database /// 19 2022-07-19 Added DateSubmitted and DateRanked to BeatmapSetInfo. /// 20 2022-07-21 Added LastAppliedDifficultyVersion to RulesetInfo, changed default value of BeatmapInfo.StarRating to -1. /// 21 2022-07-27 Migrate collections to realm (BeatmapCollection). + /// 22 2022-07-31 Added ModPreset. /// - private const int schema_version = 21; + private const int schema_version = 22; /// /// Lock object which is held during sections, blocking realm retrieval during blocking periods. diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index 1eea8383f8..bed4cff0ea 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -7,31 +7,24 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Localisation; +using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osuTK; +using Realms; namespace osu.Game.Overlays.Mods { public class ModPresetColumn : ModSelectColumn { - private IReadOnlyList presets = Array.Empty(); + [Resolved] + private RealmAccess realm { get; set; } = null!; - /// - /// Sets the collection of available mod presets. - /// - public IReadOnlyList Presets - { - get => presets; - set - { - presets = value; - - if (IsLoaded) - asyncLoadPanels(); - } - } + [Resolved] + private IBindable ruleset { get; set; } = null!; [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -44,7 +37,20 @@ namespace osu.Game.Overlays.Mods { base.LoadComplete(); - asyncLoadPanels(); + ruleset.BindValueChanged(_ => rulesetChanged(), true); + } + + private IDisposable? presetSubscription; + + private void rulesetChanged() + { + presetSubscription?.Dispose(); + presetSubscription = realm.RegisterForNotifications(r => + r.All() + .Filter($"{nameof(ModPreset.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $0" + + $" && {nameof(ModPreset.DeletePending)} == false", ruleset.Value.ShortName) + .OrderBy(preset => preset.Name), + (presets, _, _) => asyncLoadPanels(presets)); } private CancellationTokenSource? cancellationTokenSource; @@ -52,11 +58,17 @@ namespace osu.Game.Overlays.Mods private Task? latestLoadTask; internal bool ItemsLoaded => latestLoadTask == null; - private void asyncLoadPanels() + private void asyncLoadPanels(IReadOnlyList presets) { cancellationTokenSource?.Cancel(); - var panels = presets.Select(preset => new ModPresetPanel(preset) + if (!presets.Any()) + { + ItemsFlow.Clear(); + return; + } + + var panels = presets.Select(preset => new ModPresetPanel(preset.ToLive(realm)) { Shear = Vector2.Zero }); @@ -73,5 +85,12 @@ namespace osu.Game.Overlays.Mods latestLoadTask = null; }); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + presetSubscription?.Dispose(); + } } } diff --git a/osu.Game/Overlays/Mods/ModPresetPanel.cs b/osu.Game/Overlays/Mods/ModPresetPanel.cs index 47e2f25538..a00729d9fd 100644 --- a/osu.Game/Overlays/Mods/ModPresetPanel.cs +++ b/osu.Game/Overlays/Mods/ModPresetPanel.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Cursor; +using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; @@ -11,16 +12,16 @@ namespace osu.Game.Overlays.Mods { public class ModPresetPanel : ModSelectPanel, IHasCustomTooltip { - public readonly ModPreset Preset; + public readonly Live Preset; public override BindableBool Active { get; } = new BindableBool(); - public ModPresetPanel(ModPreset preset) + public ModPresetPanel(Live preset) { Preset = preset; - Title = preset.Name; - Description = preset.Description; + Title = preset.Value.Name; + Description = preset.Value.Description; } [BackgroundDependencyLoader] @@ -29,7 +30,7 @@ namespace osu.Game.Overlays.Mods AccentColour = colours.Orange1; } - public ModPreset TooltipContent => Preset; + public ModPreset TooltipContent => Preset.Value; public ITooltip GetCustomTooltip() => new ModPresetTooltip(ColourProvider); } } From c837848238f3b75b9a567b412916f4117b656571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 18:09:27 +0200 Subject: [PATCH 0193/2686] Add extended test coverage of preset realm subscription --- .../UserInterface/TestSceneModPresetColumn.cs | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index f86072dbc0..f927d83722 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.UserInterface } [Test] - public void TestBasicAppearance() + public void TestBasicOperation() { AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0)); AddStep("create content", () => Child = new Container @@ -65,6 +65,41 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("change ruleset to mania", () => Ruleset.Value = rulesets.GetRuleset(3)); AddUntilStep("1 panel visible", () => this.ChildrenOfType().Count() == 1); + + AddStep("add another mania preset", () => Realm.Write(r => r.Add(new ModPreset + { + Name = "and another one", + Mods = new Mod[] + { + new ManiaModMirror(), + new ManiaModNightcore(), + new ManiaModHardRock() + }, + Ruleset = rulesets.GetRuleset(3).AsNonNull() + }))); + AddUntilStep("2 panels visible", () => this.ChildrenOfType().Count() == 2); + + AddStep("add another osu! preset", () => Realm.Write(r => r.Add(new ModPreset + { + Name = "hdhr", + Mods = new Mod[] + { + new OsuModHidden(), + new OsuModHardRock() + }, + Ruleset = rulesets.GetRuleset(0).AsNonNull() + }))); + AddUntilStep("2 panels visible", () => this.ChildrenOfType().Count() == 2); + + AddStep("remove mania preset", () => Realm.Write(r => + { + var toRemove = r.All().Single(preset => preset.Name == "Different ruleset"); + r.Remove(toRemove); + })); + AddUntilStep("1 panel visible", () => this.ChildrenOfType().Count() == 1); + + AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0)); + AddUntilStep("4 panels visible", () => this.ChildrenOfType().Count() == 4); } private IEnumerable createTestPresets() => new[] From 9dea8e3d12ef84ca23b4d36a2e114dc5e3501218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 18:12:55 +0200 Subject: [PATCH 0194/2686] Add test coverage of preset soft deletion --- .../UserInterface/TestSceneModPresetColumn.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index f927d83722..2ef6d2ab70 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -102,6 +102,44 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("4 panels visible", () => this.ChildrenOfType().Count() == 4); } + [Test] + public void TestSoftDeleteSupport() + { + AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0)); + AddStep("create content", () => Child = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(30), + Child = new ModPresetColumn + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }); + AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3); + + AddStep("soft delete preset", () => Realm.Write(r => + { + var toSoftDelete = r.All().Single(preset => preset.Name == "AR0"); + toSoftDelete.DeletePending = true; + })); + AddUntilStep("2 panels visible", () => this.ChildrenOfType().Count() == 2); + + AddStep("soft delete all presets", () => Realm.Write(r => + { + foreach (var preset in r.All()) + preset.DeletePending = true; + })); + AddUntilStep("no panels visible", () => this.ChildrenOfType().Count() == 0); + + AddStep("undelete preset", () => Realm.Write(r => + { + foreach (var preset in r.All()) + preset.DeletePending = false; + })); + AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3); + } + private IEnumerable createTestPresets() => new[] { new ModPreset From 9d3cdae4bba5cd15eaaecea1b9ad32107541103c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 21:56:10 +0200 Subject: [PATCH 0195/2686] Fix test scene to handle restarts properly --- .../UserInterface/TestSceneModPresetColumn.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index 2ef6d2ab70..593c8abac4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -22,8 +22,7 @@ namespace osu.Game.Tests.Visual.UserInterface { protected override bool UseFreshStoragePerRun => true; - [Resolved] - private RulesetStore rulesets { get; set; } = null!; + private RulesetStore rulesets = null!; [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); @@ -31,18 +30,25 @@ namespace osu.Game.Tests.Visual.UserInterface [BackgroundDependencyLoader] private void load() { + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(Realm); } [SetUpSteps] public void SetUpSteps() { + AddStep("clear contents", Clear); AddStep("reset storage", () => { Realm.Write(realm => { realm.RemoveAll(); - realm.Add(createTestPresets()); + + var testPresets = createTestPresets(); + foreach (var preset in testPresets) + preset.Ruleset = realm.Find(preset.Ruleset.ShortName); + + realm.Add(testPresets); }); }); } @@ -75,7 +81,7 @@ namespace osu.Game.Tests.Visual.UserInterface new ManiaModNightcore(), new ManiaModHardRock() }, - Ruleset = rulesets.GetRuleset(3).AsNonNull() + Ruleset = r.Find("mania") }))); AddUntilStep("2 panels visible", () => this.ChildrenOfType().Count() == 2); @@ -87,7 +93,7 @@ namespace osu.Game.Tests.Visual.UserInterface new OsuModHidden(), new OsuModHardRock() }, - Ruleset = rulesets.GetRuleset(0).AsNonNull() + Ruleset = r.Find("osu") }))); AddUntilStep("2 panels visible", () => this.ChildrenOfType().Count() == 2); @@ -140,7 +146,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3); } - private IEnumerable createTestPresets() => new[] + private ICollection createTestPresets() => new[] { new ModPreset { From 5a34122a85c746e5eb1d954c6df898519ef9ef2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 21:29:30 +0200 Subject: [PATCH 0196/2686] Fix test breakage after realm migration --- .../Visual/UserInterface/TestSceneModPresetPanel.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs index dd3c7000a2..92d1cba2c2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs @@ -11,6 +11,7 @@ using osu.Game.Database; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osuTK; @@ -46,7 +47,8 @@ namespace osu.Game.Tests.Visual.UserInterface { new OsuModHardRock(), new OsuModDoubleTime() - } + }, + Ruleset = new OsuRuleset().RulesetInfo }, new ModPreset { @@ -58,7 +60,8 @@ namespace osu.Game.Tests.Visual.UserInterface { ApproachRate = { Value = 0 } } - } + }, + Ruleset = new OsuRuleset().RulesetInfo }, new ModPreset { @@ -68,7 +71,8 @@ namespace osu.Game.Tests.Visual.UserInterface { new OsuModFlashlight(), new OsuModSpinIn() - } + }, + Ruleset = new OsuRuleset().RulesetInfo } }; } From 85f77abee113342d224c03353f9aa2a7e597e1a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 31 Jul 2022 22:59:33 +0200 Subject: [PATCH 0197/2686] Fix code quality inspection about ambiguous equality --- osu.Game/Overlays/Mods/ModPresetTooltip.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModPresetTooltip.cs b/osu.Game/Overlays/Mods/ModPresetTooltip.cs index 68da649e81..97d118fbfd 100644 --- a/osu.Game/Overlays/Mods/ModPresetTooltip.cs +++ b/osu.Game/Overlays/Mods/ModPresetTooltip.cs @@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Mods public void SetContent(ModPreset preset) { - if (preset == lastPreset) + if (ReferenceEquals(preset, lastPreset)) return; lastPreset = preset; From 415d6def2d345903a51634ec544c693c46bd3166 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 1 Aug 2022 13:22:58 +0900 Subject: [PATCH 0198/2686] Remove unnecessary AsNonNull() --- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index c273da2462..623157a427 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; @@ -274,7 +273,7 @@ namespace osu.Game.Rulesets.Osu.Mods { if (hitObjects.Count == 0) return; - float nextSingle(float max = 1f) => (float)(rng.AsNonNull().NextDouble() * max); + float nextSingle(float max = 1f) => (float)(rng.NextDouble() * max); const float two_pi = MathF.PI * 2; From 5b98a73edcb2dc061e0898251098a5de405d5325 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 14:03:57 +0900 Subject: [PATCH 0199/2686] Apply nullability to `SkinComponentToolbox` and split out reflection method to get all skinnable components --- osu.Game/Screens/Play/HUD/SkinnableInfo.cs | 9 +++++ .../Skinning/Editor/SkinComponentToolbox.cs | 35 ++++++++----------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs index ee29241321..6d63776dbb 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs @@ -98,5 +98,14 @@ namespace osu.Game.Screens.Play.HUD return Drawable.Empty(); } } + + public static Type[] GetAllAvailableDrawables() + { + return typeof(OsuGame).Assembly.GetTypes() + .Where(t => !t.IsInterface && !t.IsAbstract) + .Where(t => typeof(ISkinnableDrawable).IsAssignableFrom(t)) + .OrderBy(t => t.Name) + .ToArray(); + } } } diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs index 344a659627..980dee8601 100644 --- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs @@ -1,11 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Diagnostics; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -16,24 +13,25 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osu.Game.Screens.Edit.Components; +using osu.Game.Screens.Play.HUD; using osuTK; namespace osu.Game.Skinning.Editor { public class SkinComponentToolbox : EditorSidebarSection { - public Action RequestPlacement; + public Action? RequestPlacement; - private readonly CompositeDrawable target; + private readonly CompositeDrawable? target; - public SkinComponentToolbox(CompositeDrawable target = null) + private FillFlowContainer fill = null!; + + public SkinComponentToolbox(CompositeDrawable? target = null) : base("Components") { this.target = target; } - private FillFlowContainer fill; - [BackgroundDependencyLoader] private void load() { @@ -52,12 +50,7 @@ namespace osu.Game.Skinning.Editor { fill.Clear(); - var skinnableTypes = typeof(OsuGame).Assembly.GetTypes() - .Where(t => !t.IsInterface && !t.IsAbstract) - .Where(t => typeof(ISkinnableDrawable).IsAssignableFrom(t)) - .OrderBy(t => t.Name) - .ToArray(); - + var skinnableTypes = SkinnableInfo.GetAllAvailableDrawables(); foreach (var type in skinnableTypes) attemptAddComponent(type); } @@ -90,21 +83,21 @@ namespace osu.Game.Skinning.Editor public class ToolboxComponentButton : OsuButton { + public Action? RequestPlacement; + protected override bool ShouldBeConsideredForInput(Drawable child) => false; public override bool PropagateNonPositionalInputSubTree => false; private readonly Drawable component; - private readonly CompositeDrawable dependencySource; + private readonly CompositeDrawable? dependencySource; - public Action RequestPlacement; - - private Container innerContainer; + private Container innerContainer = null!; private const float contracted_size = 60; private const float expanded_size = 120; - public ToolboxComponentButton(Drawable component, CompositeDrawable dependencySource) + public ToolboxComponentButton(Drawable component, CompositeDrawable? dependencySource) { this.component = component; this.dependencySource = dependencySource; @@ -184,9 +177,9 @@ namespace osu.Game.Skinning.Editor public class DependencyBorrowingContainer : Container { - private readonly CompositeDrawable donor; + private readonly CompositeDrawable? donor; - public DependencyBorrowingContainer(CompositeDrawable donor) + public DependencyBorrowingContainer(CompositeDrawable? donor) { this.donor = donor; } From d112743cea7d959a1f1d8e22dc3b58f04aa356aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 14:04:06 +0900 Subject: [PATCH 0200/2686] Improve test coverage of skin serialisation to ensure full coverage Will fail when new skinnable components are added until they have coverage in resources. --- .../Skins/SkinDeserialisationTest.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 699c1bcc2c..2ef8de387b 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -2,6 +2,7 @@ // 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.Audio.Sample; @@ -12,6 +13,7 @@ using osu.Framework.IO.Stores; using osu.Game.Audio; using osu.Game.IO; using osu.Game.IO.Archives; +using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; using osu.Game.Tests.Resources; @@ -28,6 +30,39 @@ namespace osu.Game.Tests.Skins [TestFixture] public class SkinDeserialisationTest { + private static readonly string[] available_skins = + { + // Covers song progress before namespace changes, and most other components. + "Archives/modified-default-20220723.osk", + "Archives/modified-classic-20220723.osk" + }; + + /// + /// If this test fails, new test resources should be added to include new components. + /// + [Test] + public void TestSkinnableComponentsCoveredByDeserialisationTests() + { + HashSet instantiatedTypes = new HashSet(); + + foreach (string oskFile in available_skins) + { + using (var stream = TestResources.OpenResource(oskFile)) + using (var storage = new ZipArchiveReader(stream)) + { + var skin = new TestSkin(new SkinInfo(), null, storage); + + foreach (var target in skin.DrawableComponentInfo) + { + foreach (var info in target.Value) + instantiatedTypes.Add(info.Type); + } + } + } + + Assert.That(SkinnableInfo.GetAllAvailableDrawables(), Is.EquivalentTo(instantiatedTypes)); + } + [Test] public void TestDeserialiseModifiedDefault() { From 3b6349a14522c7bc7293ead59b47d508fdfa0061 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 14:16:26 +0900 Subject: [PATCH 0201/2686] Add test coverage of remaining components which weren't already included --- .../Archives/modified-classic-20220801.osk | Bin 0 -> 1182 bytes .../Skins/SkinDeserialisationTest.cs | 20 ++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Resources/Archives/modified-classic-20220801.osk diff --git a/osu.Game.Tests/Resources/Archives/modified-classic-20220801.osk b/osu.Game.Tests/Resources/Archives/modified-classic-20220801.osk new file mode 100644 index 0000000000000000000000000000000000000000..9236e1d77f181e680171e0ffb4374f4eb291944d GIT binary patch literal 1182 zcmWIWW@Zs#U|`^2cvrv}`s~Z3;}d|q)nE|@hT`nZJiW}kOxZJre1{Bp94^`}H;C3& z)Vh}EljCEc$Yx%qsI)Qg(TZ0$B`k!(7o`64|Nr}6iR>JCp2f#j1W&N85KT6mv4J7% za*LSFF$-oP!-EFR({?egs(h-r*W|Vsn~rx#qoIqK56@jI)pHYWOt?_+e4V@4If?vt zTRQ&Pe-iZOl$*6g~tTM0A1V##JoTZa&=~2 zTE1RZaekiZ8Aq-|4nU{Z`U`H(TFA4bbhQHOOE(*b8EIY_vmMl3UH0ted-d(}kMmp% z)lm}s4b!&A&e2To4A3|85R#Kx@tt?uQQ2^{?OQL*_RA{&`^|6jO9TeKD;bIXE6aWKM)7!=cNay=A{_}ow0%nVOW!QCnJX)!{_qdIf z`=zrdKL0aY|NQ6mugX8>+r;1Is(sAg@a(&j=0dM8%wBON?+M);XG|_ z?r*Crns(oPU>_58LyhgZRKT{gdrQxTJKdAah|SA$kKJazXrB131IL|Zm8S8niTGud z<TY55_N7#|D5n+C-Z!!>3OA^Zx%oK%C41XQ*elRxvY&D z%UQoemFq$+jdz(Oygg{xUnrw|=*EKonN1OgHmTT|d=_72Z71~g5Q9c{ny=~Nmyd*e zTYo3@nAtD9>8JDSjIY1t@-F$!-yg}hI{&k<5&Yk}sZU=urm%dAvPiq(p-7)abw8I& zsH%8oZc6{D-XSzAHSqs|8y#PIXY((6evy6Wv|Uz3+6i5oM2<)P|7Xr8sA$5)dHP$- z^s?32*BXx5-uFvge@B=9mg3^u{{y@knM4?H=SyIsfPh921T0?;e6D @@ -60,7 +64,9 @@ namespace osu.Game.Tests.Skins } } - Assert.That(SkinnableInfo.GetAllAvailableDrawables(), Is.EquivalentTo(instantiatedTypes)); + var editableTypes = SkinnableInfo.GetAllAvailableDrawables().Where(t => (Activator.CreateInstance(t) as ISkinnableDrawable)?.IsEditable == true); + + Assert.That(instantiatedTypes, Is.EquivalentTo(editableTypes)); } [Test] @@ -94,6 +100,16 @@ namespace osu.Game.Tests.Skins Assert.That(skinnableInfo.Settings.First().Key, Is.EqualTo("sprite_name")); Assert.That(skinnableInfo.Settings.First().Value, Is.EqualTo("ppy_logo-2.png")); } + + using (var stream = TestResources.OpenResource("Archives/modified-classic-20220801.osk")) + using (var storage = new ZipArchiveReader(stream)) + { + var skin = new TestSkin(new SkinInfo(), null, storage); + Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents], Has.Length.EqualTo(8)); + Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); + Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); + Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); + } } private class TestSkin : Skin From a5f48e336a2021efd96096ea3b9215b1da0ef004 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 14:38:02 +0900 Subject: [PATCH 0202/2686] Isolate development builds' storage from release builds --- osu.Desktop/Program.cs | 4 ++++ osu.Game/OsuGameBase.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs index 19cf7f5d46..c7505e624c 100644 --- a/osu.Desktop/Program.cs +++ b/osu.Desktop/Program.cs @@ -21,7 +21,11 @@ namespace osu.Desktop { public static class Program { +#if DEBUG + private const string base_game_name = @"osu-development"; +#else private const string base_game_name = @"osu"; +#endif private static LegacyTcpIpcProvider legacyIpc; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index c7820d395d..97d15ae6ad 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -212,6 +212,10 @@ namespace osu.Game { Name = @"osu!"; +#if DEBUG + Name += " (development)"; +#endif + allowableExceptions = UnhandledExceptionsBeforeCrash; } From fc8835d43a71b6c1f43eb434eeb60bb850f31913 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 14:58:09 +0900 Subject: [PATCH 0203/2686] Fix migration failing on single file copy failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No longer throw if copying of single files fails during data migration. Aiming to fix https://github.com/ppy/osu/runs/7601653833?check_suite_focus=true, which could also affect end users. I've left a limit before an exception is still thrown, to handle cases like the user running out of disk space (where we probably *do* want to bail, so they can continue to use their still-intact original storage location). If this isn't seen as a good direction, an alternative will be to make the migration code aware of the structure of the temporary files created by `Storage` (but doesn't guarantee this will cover all cases of such temporary files – there could for isntance be metadata files created by the host operating system). Another option would be to mark those temporary files as hidden and skip any hidden files during iteration. --- osu.Game/IO/MigratableStorage.cs | 34 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/osu.Game/IO/MigratableStorage.cs b/osu.Game/IO/MigratableStorage.cs index 30e74adca4..4bc729f429 100644 --- a/osu.Game/IO/MigratableStorage.cs +++ b/osu.Game/IO/MigratableStorage.cs @@ -7,6 +7,7 @@ using System; using System.IO; using System.Linq; using System.Threading; +using osu.Framework.Logging; using osu.Framework.Platform; namespace osu.Game.IO @@ -16,6 +17,12 @@ namespace osu.Game.IO /// public abstract class MigratableStorage : WrappedStorage { + /// + /// The number of file copy failures before actually bailing on migration. + /// This allows some lenience to cover things like temporary files which could not be copied but are also not too important. + /// + private const int allowed_failures = 10; + /// /// A relative list of directory paths which should not be migrated. /// @@ -73,7 +80,7 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreFiles.Contains(fi.Name)) continue; - allFilesDeleted &= AttemptOperation(() => fi.Delete(), throwOnFailure: false); + allFilesDeleted &= AttemptOperation(() => fi.Delete()); } foreach (DirectoryInfo dir in target.GetDirectories()) @@ -81,16 +88,16 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name)) continue; - allFilesDeleted &= AttemptOperation(() => dir.Delete(true), throwOnFailure: false); + allFilesDeleted &= AttemptOperation(() => dir.Delete(true)); } if (target.GetFiles().Length == 0 && target.GetDirectories().Length == 0) - allFilesDeleted &= AttemptOperation(target.Delete, throwOnFailure: false); + allFilesDeleted &= AttemptOperation(target.Delete); return allFilesDeleted; } - protected void CopyRecursive(DirectoryInfo source, DirectoryInfo destination, bool topLevelExcludes = true) + protected void CopyRecursive(DirectoryInfo source, DirectoryInfo destination, bool topLevelExcludes = true, int totalFailedOperations = 0) { // based off example code https://docs.microsoft.com/en-us/dotnet/api/system.io.directoryinfo if (!destination.Exists) @@ -101,7 +108,14 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreFiles.Contains(fi.Name)) continue; - AttemptOperation(() => fi.CopyTo(Path.Combine(destination.FullName, fi.Name), true)); + if (!AttemptOperation(() => fi.CopyTo(Path.Combine(destination.FullName, fi.Name), false))) + { + Logger.Log($"Failed to copy file {fi.Name} during folder migration"); + totalFailedOperations++; + + if (totalFailedOperations > allowed_failures) + throw new Exception("Aborting due to too many file copy failures during data migration"); + } } foreach (DirectoryInfo dir in source.GetDirectories()) @@ -109,7 +123,7 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name)) continue; - CopyRecursive(dir, destination.CreateSubdirectory(dir.Name), false); + CopyRecursive(dir, destination.CreateSubdirectory(dir.Name), false, totalFailedOperations); } } @@ -118,8 +132,7 @@ namespace osu.Game.IO /// /// The action to perform. /// The number of attempts (250ms wait between each). - /// Whether to throw an exception on failure. If false, will silently fail. - protected static bool AttemptOperation(Action action, int attempts = 10, bool throwOnFailure = true) + protected static bool AttemptOperation(Action action, int attempts = 10) { while (true) { @@ -131,12 +144,7 @@ namespace osu.Game.IO catch (Exception) { if (attempts-- == 0) - { - if (throwOnFailure) - throw; - return false; - } } Thread.Sleep(250); From 47860bb96606644cfadd5d80eaad7a2245647583 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 1 Aug 2022 16:33:59 +0900 Subject: [PATCH 0204/2686] Remove unused using --- osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 9181dc80f3..53639deac3 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -7,7 +7,6 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; -using osu.Framework.Graphics; using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; From 2519706ad612e0297be4b5c8f742150784cf018a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 16:53:47 +0900 Subject: [PATCH 0205/2686] Add test coverage of editor crash --- .../Editing/TestSceneEditorBeatmapCreation.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 6ad6f0b299..4baa4af8dd 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -136,6 +136,20 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("track is not virtual", () => Beatmap.Value.Track is not TrackVirtual); AddAssert("track length changed", () => Beatmap.Value.Track.Length > 60000); + + AddStep("test play", () => Editor.TestGameplay()); + + AddUntilStep("wait for dialog", () => DialogOverlay.CurrentDialog != null); + AddStep("confirm save", () => InputManager.Key(Key.Number1)); + + AddUntilStep("wait for return to editor", () => Editor.IsCurrentScreen()); + + AddAssert("track is still not virtual", () => Beatmap.Value.Track is not TrackVirtual); + AddAssert("track length correct", () => Beatmap.Value.Track.Length > 60000); + + AddUntilStep("track not playing", () => !EditorClock.IsRunning); + AddStep("play track", () => InputManager.Key(Key.Space)); + AddUntilStep("wait for track playing", () => EditorClock.IsRunning); } [Test] From 2f60f91a0ed2173282e1b97c68c76d76a476597d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 16:30:45 +0900 Subject: [PATCH 0206/2686] Fix editor potentially using a track post-disposal This changes the editor to track the current track as it is *loaded* by `MusicController`, rather than haphazardly following the current global `WorkingBeatmap` (with a potentially unloaded track) or relying on local immediate-load behaviour (as implemented in `ResourcesSection`). --- osu.Game/Overlays/MusicController.cs | 6 +++++- osu.Game/Screens/Edit/Editor.cs | 17 +++++++++++++---- osu.Game/Screens/Edit/Setup/ResourcesSection.cs | 2 -- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 8af295dfe8..da87336039 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -70,7 +70,11 @@ namespace osu.Game.Overlays /// /// Forcefully reload the current 's track from disk. /// - public void ReloadCurrentTrack() => changeTrack(); + public void ReloadCurrentTrack() + { + changeTrack(); + TrackChanged?.Invoke(current, TrackChangeDirection.None); + } /// /// Returns whether the beatmap track is playing. diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 3e3940c5ba..9e9cd8e3b7 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -329,6 +329,9 @@ namespace osu.Game.Screens.Edit changeHandler?.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true); } + [Resolved] + private MusicController musicController { get; set; } + protected override void LoadComplete() { base.LoadComplete(); @@ -336,12 +339,18 @@ namespace osu.Game.Screens.Edit Mode.Value = isNewBeatmap ? EditorScreenMode.SongSetup : EditorScreenMode.Compose; Mode.BindValueChanged(onModeChanged, true); + + musicController.TrackChanged += onTrackChanged; } - /// - /// If the beatmap's track has changed, this method must be called to keep the editor in a valid state. - /// - public void UpdateClockSource() => clock.ChangeSource(Beatmap.Value.Track); + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + musicController.TrackChanged -= onTrackChanged; + } + + private void onTrackChanged(WorkingBeatmap working, TrackChangeDirection direction) => clock.ChangeSource(working.Track); /// /// Creates an instance representing the current state of the editor. diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 1f8381e1ed..44bc2126fb 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -118,8 +118,6 @@ namespace osu.Game.Screens.Edit.Setup working.Value.Metadata.AudioFile = destination.Name; music.ReloadCurrentTrack(); - - editor?.UpdateClockSource(); return true; } From 6e7c298aaf6380032d344474863b73cabaf9342e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 16:36:12 +0900 Subject: [PATCH 0207/2686] Fix changes to audio / background not triggering an editor state change --- osu.Game/Screens/Edit/Setup/ResourcesSection.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 44bc2126fb..8c14feebbc 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -30,8 +30,8 @@ namespace osu.Game.Screens.Edit.Setup [Resolved] private IBindable working { get; set; } - [Resolved(canBeNull: true)] - private Editor editor { get; set; } + [Resolved] + private EditorBeatmap editorBeatmap { get; set; } [Resolved] private SetupScreenHeader header { get; set; } @@ -88,6 +88,8 @@ namespace osu.Game.Screens.Edit.Setup beatmaps.AddFile(set, stream, destination.Name); } + editorBeatmap.SaveState(); + working.Value.Metadata.BackgroundFile = destination.Name; header.Background.UpdateBackground(); @@ -117,7 +119,9 @@ namespace osu.Game.Screens.Edit.Setup working.Value.Metadata.AudioFile = destination.Name; + editorBeatmap.SaveState(); music.ReloadCurrentTrack(); + return true; } From 59210ecc9df96119f70004f68c06f96e9d734e8f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 16:57:50 +0900 Subject: [PATCH 0208/2686] Revert "Fix migration failing on single file copy failure" This reverts commit fc8835d43a71b6c1f43eb434eeb60bb850f31913. --- osu.Game/IO/MigratableStorage.cs | 34 ++++++++++++-------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/osu.Game/IO/MigratableStorage.cs b/osu.Game/IO/MigratableStorage.cs index 4bc729f429..30e74adca4 100644 --- a/osu.Game/IO/MigratableStorage.cs +++ b/osu.Game/IO/MigratableStorage.cs @@ -7,7 +7,6 @@ using System; using System.IO; using System.Linq; using System.Threading; -using osu.Framework.Logging; using osu.Framework.Platform; namespace osu.Game.IO @@ -17,12 +16,6 @@ namespace osu.Game.IO /// public abstract class MigratableStorage : WrappedStorage { - /// - /// The number of file copy failures before actually bailing on migration. - /// This allows some lenience to cover things like temporary files which could not be copied but are also not too important. - /// - private const int allowed_failures = 10; - /// /// A relative list of directory paths which should not be migrated. /// @@ -80,7 +73,7 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreFiles.Contains(fi.Name)) continue; - allFilesDeleted &= AttemptOperation(() => fi.Delete()); + allFilesDeleted &= AttemptOperation(() => fi.Delete(), throwOnFailure: false); } foreach (DirectoryInfo dir in target.GetDirectories()) @@ -88,16 +81,16 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name)) continue; - allFilesDeleted &= AttemptOperation(() => dir.Delete(true)); + allFilesDeleted &= AttemptOperation(() => dir.Delete(true), throwOnFailure: false); } if (target.GetFiles().Length == 0 && target.GetDirectories().Length == 0) - allFilesDeleted &= AttemptOperation(target.Delete); + allFilesDeleted &= AttemptOperation(target.Delete, throwOnFailure: false); return allFilesDeleted; } - protected void CopyRecursive(DirectoryInfo source, DirectoryInfo destination, bool topLevelExcludes = true, int totalFailedOperations = 0) + protected void CopyRecursive(DirectoryInfo source, DirectoryInfo destination, bool topLevelExcludes = true) { // based off example code https://docs.microsoft.com/en-us/dotnet/api/system.io.directoryinfo if (!destination.Exists) @@ -108,14 +101,7 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreFiles.Contains(fi.Name)) continue; - if (!AttemptOperation(() => fi.CopyTo(Path.Combine(destination.FullName, fi.Name), false))) - { - Logger.Log($"Failed to copy file {fi.Name} during folder migration"); - totalFailedOperations++; - - if (totalFailedOperations > allowed_failures) - throw new Exception("Aborting due to too many file copy failures during data migration"); - } + AttemptOperation(() => fi.CopyTo(Path.Combine(destination.FullName, fi.Name), true)); } foreach (DirectoryInfo dir in source.GetDirectories()) @@ -123,7 +109,7 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name)) continue; - CopyRecursive(dir, destination.CreateSubdirectory(dir.Name), false, totalFailedOperations); + CopyRecursive(dir, destination.CreateSubdirectory(dir.Name), false); } } @@ -132,7 +118,8 @@ namespace osu.Game.IO /// /// The action to perform. /// The number of attempts (250ms wait between each). - protected static bool AttemptOperation(Action action, int attempts = 10) + /// Whether to throw an exception on failure. If false, will silently fail. + protected static bool AttemptOperation(Action action, int attempts = 10, bool throwOnFailure = true) { while (true) { @@ -144,7 +131,12 @@ namespace osu.Game.IO catch (Exception) { if (attempts-- == 0) + { + if (throwOnFailure) + throw; + return false; + } } Thread.Sleep(250); From cc8a71b65d52d9fe849fc02434fce58c3be4326d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 17:01:19 +0900 Subject: [PATCH 0209/2686] Re-query file existence before failing a recursive copy operation during migration --- osu.Game/IO/MigratableStorage.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game/IO/MigratableStorage.cs b/osu.Game/IO/MigratableStorage.cs index 30e74adca4..7cd409c04c 100644 --- a/osu.Game/IO/MigratableStorage.cs +++ b/osu.Game/IO/MigratableStorage.cs @@ -96,12 +96,22 @@ namespace osu.Game.IO if (!destination.Exists) Directory.CreateDirectory(destination.FullName); - foreach (System.IO.FileInfo fi in source.GetFiles()) + foreach (System.IO.FileInfo fileInfo in source.GetFiles()) { - if (topLevelExcludes && IgnoreFiles.Contains(fi.Name)) + if (topLevelExcludes && IgnoreFiles.Contains(fileInfo.Name)) continue; - AttemptOperation(() => fi.CopyTo(Path.Combine(destination.FullName, fi.Name), true)); + AttemptOperation(() => + { + fileInfo.Refresh(); + + // A temporary file may have been deleted since the initial GetFiles operation. + // We don't want the whole migration process to fail in such a case. + if (!fileInfo.Exists) + return; + + fileInfo.CopyTo(Path.Combine(destination.FullName, fileInfo.Name), true); + }); } foreach (DirectoryInfo dir in source.GetDirectories()) From ee681139131b1690772e2801b243baeaa8ba8e87 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 17:06:45 +0900 Subject: [PATCH 0210/2686] Add more missing realm `Refresh()` calls to new beatmap import tests As noticed at https://github.com/ppy/osu/runs/7605101313?check_suite_focus=true --- osu.Game.Tests/Database/BeatmapImporterTests.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index 0546d3e912..56964aa8b2 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -702,6 +702,8 @@ namespace osu.Game.Tests.Database var firstImport = await importer.Import(new ImportTask(pathMissingOneBeatmap)); Assert.That(firstImport, Is.Not.Null); + realm.Run(r => r.Refresh()); + Assert.That(realm.Realm.All().Where(s => !s.DeletePending), Has.Count.EqualTo(1)); Assert.That(realm.Realm.All().First(s => !s.DeletePending).Beatmaps, Has.Count.EqualTo(11)); @@ -709,6 +711,8 @@ namespace osu.Game.Tests.Database var secondImport = await importer.Import(new ImportTask(pathOriginal)); Assert.That(secondImport, Is.Not.Null); + realm.Run(r => r.Refresh()); + Assert.That(realm.Realm.All(), Has.Count.EqualTo(23)); Assert.That(realm.Realm.All(), Has.Count.EqualTo(2)); From c65747d1b88ee677b6f04e3bb0d36b7cc798539c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gutyina=20Gerg=C5=91?= Date: Mon, 1 Aug 2022 10:36:06 +0200 Subject: [PATCH 0211/2686] Use masking instead of scrollable container to prevent tags overflow --- osu.Game/Overlays/BeatmapSet/Info.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 5517e51515..08423f2aa7 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.API.Requests.Responses; @@ -63,7 +62,7 @@ namespace osu.Game.Overlays.BeatmapSet Child = new MetadataSection(MetadataType.Description), }, }, - new OsuScrollContainer + new Container { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -71,6 +70,7 @@ namespace osu.Game.Overlays.BeatmapSet Width = metadata_width, Padding = new MarginPadding { Horizontal = 10 }, Margin = new MarginPadding { Right = BeatmapSetOverlay.RIGHT_WIDTH + spacing }, + Masking = true, Child = new FillFlowContainer { RelativeSizeAxes = Axes.X, From e0940c6c22e28f24d120d764e1c63eb024016f56 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 18:03:32 +0900 Subject: [PATCH 0212/2686] Update animations to final versions --- .../Skinning/Default/DefaultFollowCircle.cs | 8 +++----- .../Skinning/Legacy/LegacyFollowCircle.cs | 5 +---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs index 3b087245e9..aaace89cd5 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs @@ -59,11 +59,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default protected override void OnSliderTick() { - // TODO: Follow circle should bounce on each slider tick. - - // TEMP DUMMY ANIMS - this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.1f) - .ScaleTo(DrawableSliderBall.FOLLOW_AREA, 175f); + this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.08f, 40, Easing.OutQuint) + .Then() + .ScaleTo(DrawableSliderBall.FOLLOW_AREA, 200f, Easing.OutQuint); } protected override void OnSliderBreak() diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs index 6d16596ed2..0d12fb01f5 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs @@ -44,11 +44,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected override void OnSliderTick() { - // TODO: Follow circle should bounce on each slider tick. - - // TEMP DUMMY ANIMS this.ScaleTo(2.2f) - .ScaleTo(2f, 175f); + .ScaleTo(2f, 200); } protected override void OnSliderBreak() From 3ff0327d91b2217cefe58bd91a1c55ac42b06540 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 1 Aug 2022 14:22:54 +0300 Subject: [PATCH 0213/2686] Display readable message when reaching download limit --- osu.Game/Database/ModelDownloader.cs | 11 +++++++- .../Database/TooManyDownloadsNotification.cs | 26 +++++++++++++++++++ osu.Game/Localisation/CommonStrings.cs | 7 ++++- 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Database/TooManyDownloadsNotification.cs diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index edb8563c65..5c84e0c308 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Threading.Tasks; using Humanizer; using osu.Framework.Logging; @@ -107,7 +108,15 @@ namespace osu.Game.Database notification.State = ProgressNotificationState.Cancelled; if (!(error is OperationCanceledException)) - Logger.Error(error, $"{importer.HumanisedModelName.Titleize()} download failed!"); + { + if (error is WebException webException && webException.Message == @"TooManyRequests") + { + notification.Close(); + PostNotification?.Invoke(new TooManyDownloadsNotification(importer.HumanisedModelName)); + } + else + Logger.Error(error, $"{importer.HumanisedModelName.Titleize()} download failed!"); + } } } diff --git a/osu.Game/Database/TooManyDownloadsNotification.cs b/osu.Game/Database/TooManyDownloadsNotification.cs new file mode 100644 index 0000000000..8adb997999 --- /dev/null +++ b/osu.Game/Database/TooManyDownloadsNotification.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Localisation; +using osu.Game.Overlays.Notifications; + +namespace osu.Game.Database +{ + public class TooManyDownloadsNotification : SimpleNotification + { + public TooManyDownloadsNotification(string humanisedModelName) + { + Text = CommonStrings.TooManyDownloaded(humanisedModelName); + Icon = FontAwesome.Solid.ExclamationCircle; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + IconBackground.Colour = colours.RedDark; + } + } +} diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 1ee562e122..7c82ecf926 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using osu.Framework.Localisation; @@ -54,6 +54,11 @@ namespace osu.Game.Localisation /// public static LocalisableString Downloading => new TranslatableString(getKey(@"downloading"), @"Downloading..."); + /// + /// "You have downloaded too many {0}s! Please try again later." + /// + public static LocalisableString TooManyDownloaded(string humanisedModelName) => new TranslatableString(getKey(@"too_many_downloaded"), @"You have downloaded too many {0}s! Please try again later.", humanisedModelName); + /// /// "Importing..." /// From 6cccb6b84825dd4f58ddb5d5e8ea679f0a57f4bb Mon Sep 17 00:00:00 2001 From: andy840119 Date: Mon, 1 Aug 2022 19:45:15 +0800 Subject: [PATCH 0214/2686] Remove `canBeNull: true`. --- osu.Game/Audio/PreviewTrackManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index a0537d7a4e..b8662b6a4b 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -87,7 +87,7 @@ namespace osu.Game.Audio public class TrackManagerPreviewTrack : PreviewTrack { - [Resolved(canBeNull: true)] + [Resolved] public IPreviewTrackOwner? Owner { get; private set; } private readonly IBeatmapSetInfo beatmapSetInfo; From a5fac70c3b468b9788d5e783f65fb94ca80fce4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 23:30:00 +0900 Subject: [PATCH 0215/2686] Rename variable to not include mode name itself --- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index f3d944d55c..3f1c3aa812 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Mods private const int wiggle_duration = 100; // (ms) Higher = fewer wiggles [SettingSource("Strength", "Multiplier applied to the wiggling strength.")] - public BindableDouble WiggleStrength { get; } = new BindableDouble(1) + public BindableDouble Strength { get; } = new BindableDouble(1) { MinValue = 0.1f, MaxValue = 2f, @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Mods void wiggle() { float nextAngle = (float)(objRand.NextDouble() * 2 * Math.PI); - float nextDist = (float)(objRand.NextDouble() * WiggleStrength.Value * 7); + float nextDist = (float)(objRand.NextDouble() * Strength.Value * 7); drawable.MoveTo(new Vector2((float)(nextDist * Math.Cos(nextAngle) + origin.X), (float)(nextDist * Math.Sin(nextAngle) + origin.Y)), wiggle_duration); } From 682192dbd7fc53d8e642d84a3f2c9cf780ec83e4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 1 Aug 2022 18:43:01 +0300 Subject: [PATCH 0216/2686] Add failing test case --- .../SongSelect/TestSceneBeatmapCarousel.cs | 53 +++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 59932f8781..bb9e83a21c 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -486,9 +486,6 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Something is selected", () => carousel.SelectedBeatmapInfo != null); } - /// - /// Test sorting - /// [Test] public void TestSorting() { @@ -517,6 +514,9 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert($"Check {zzz_string} is at bottom", () => carousel.BeatmapSets.Last().Metadata.Artist == zzz_string); } + /// + /// Ensures stability is maintained on different sort modes for items with equal properties. + /// [Test] public void TestSortingStability() { @@ -549,6 +549,53 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Items reset to original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); } + /// + /// Ensures stability is maintained on different sort modes while a new item is added to the carousel. + /// + [Test] + public void TestSortingStabilityWithNewItems() + { + List sets = new List(); + + for (int i = 0; i < 3; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(3); + + // only need to set the first as they are a shared reference. + var beatmap = set.Beatmaps.First(); + + beatmap.Metadata.Artist = "same artist"; + beatmap.Metadata.Title = "same title"; + + sets.Add(set); + } + + int idOffset = sets.First().OnlineID; + + loadBeatmaps(sets); + + AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); + AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); + + AddStep("Add new item", () => + { + var set = TestResources.CreateTestBeatmapSetInfo(); + + // only need to set the first as they are a shared reference. + var beatmap = set.Beatmaps.First(); + + beatmap.Metadata.Artist = "same artist"; + beatmap.Metadata.Title = "same title"; + + carousel.UpdateBeatmapSet(set); + }); + + AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); + + AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false)); + AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); + } + [Test] public void TestSortingWithFiltered() { From 0fcae08d38b055187ccec1ce790f541c2a6411ce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 1 Aug 2022 23:57:46 +0900 Subject: [PATCH 0217/2686] Show "locally modified" pill when local modifications have been made --- osu.Game/Beatmaps/BeatmapInfo.cs | 3 ++- osu.Game/Beatmaps/BeatmapManager.cs | 4 ++++ osu.Game/Beatmaps/BeatmapOnlineStatus.cs | 4 ++++ .../Beatmaps/BeatmapUpdaterMetadataLookup.cs | 18 ++++++++++-------- osu.Game/Graphics/OsuColour.cs | 3 +++ 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index f368f369ae..c53c2f67dd 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -121,7 +121,8 @@ namespace osu.Game.Beatmaps OnlineID = -1; LastOnlineUpdate = null; OnlineMD5Hash = string.Empty; - Status = BeatmapOnlineStatus.None; + if (Status != BeatmapOnlineStatus.LocallyModified) + Status = BeatmapOnlineStatus.None; } #region Properties we may not want persisted (but also maybe no harm?) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index cf763c53a7..e3d2832108 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -312,6 +312,10 @@ namespace osu.Game.Beatmaps beatmapInfo.MD5Hash = stream.ComputeMD5Hash(); beatmapInfo.Hash = stream.ComputeSHA2Hash(); + beatmapInfo.Status = BeatmapOnlineStatus.LocallyModified; + + if (setInfo.Beatmaps.All(b => b.Status == BeatmapOnlineStatus.LocallyModified)) + setInfo.Status = BeatmapOnlineStatus.LocallyModified; AddFile(setInfo, stream, createBeatmapFilenameFromMetadata(beatmapInfo)); diff --git a/osu.Game/Beatmaps/BeatmapOnlineStatus.cs b/osu.Game/Beatmaps/BeatmapOnlineStatus.cs index ced85e0908..c91b46c92f 100644 --- a/osu.Game/Beatmaps/BeatmapOnlineStatus.cs +++ b/osu.Game/Beatmaps/BeatmapOnlineStatus.cs @@ -3,6 +3,7 @@ #nullable disable +using System.ComponentModel; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; @@ -10,6 +11,9 @@ namespace osu.Game.Beatmaps { public enum BeatmapOnlineStatus { + [Description("Local")] + LocallyModified = -4, + None = -3, [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusGraveyard))] diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index 02fb69b8f5..f51a8bf7bf 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -89,7 +89,16 @@ namespace osu.Game.Beatmaps if (res != null) { - beatmapInfo.Status = res.Status; + beatmapInfo.OnlineID = res.OnlineID; + beatmapInfo.OnlineMD5Hash = res.MD5Hash; + beatmapInfo.LastOnlineUpdate = res.LastUpdated; + beatmapInfo.Metadata.Author.OnlineID = res.AuthorID; + + // In the case local changes have been applied, don't reset the status. + if (beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified) + { + beatmapInfo.Status = res.Status; + } Debug.Assert(beatmapInfo.BeatmapSet != null); @@ -98,13 +107,6 @@ namespace osu.Game.Beatmaps beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked; beatmapInfo.BeatmapSet.DateSubmitted = res.BeatmapSet?.Submitted; - beatmapInfo.OnlineMD5Hash = res.MD5Hash; - beatmapInfo.LastOnlineUpdate = res.LastUpdated; - - beatmapInfo.OnlineID = res.OnlineID; - - beatmapInfo.Metadata.Author.OnlineID = res.AuthorID; - logForModel(set, $"Online retrieval mapped {beatmapInfo} to {res.OnlineBeatmapSetID} / {res.OnlineID}."); } } diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index 0e411876d3..6e2f460930 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -137,6 +137,9 @@ namespace osu.Game.Graphics { switch (status) { + case BeatmapOnlineStatus.LocallyModified: + return Color4.OrangeRed; + case BeatmapOnlineStatus.Ranked: case BeatmapOnlineStatus.Approved: return Color4Extensions.FromHex(@"b3ff66"); From 013cf7a80aaca9da466063fb969b328d21e32022 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 00:21:13 +0900 Subject: [PATCH 0218/2686] Fix `DateAdded` not being set to a sane value when creating a new beatmap in the editor --- osu.Game/Beatmaps/BeatmapManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e3d2832108..8ce4e4c2fb 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -94,6 +94,7 @@ namespace osu.Game.Beatmaps var beatmapSet = new BeatmapSetInfo { + DateAdded = DateTimeOffset.UtcNow, Beatmaps = { new BeatmapInfo(ruleset, new BeatmapDifficulty(), metadata) From d7a06abcab0f697057a4c9d2859faaa3aec95349 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 00:21:28 +0900 Subject: [PATCH 0219/2686] Add `BeatmapInfo.LastUpdate` to track the time of local changes --- osu.Game/Beatmaps/BeatmapInfo.cs | 8 ++++++++ osu.Game/Beatmaps/BeatmapManager.cs | 1 + osu.Game/Database/RealmAccess.cs | 3 ++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index c53c2f67dd..c0d72fdf8c 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -102,6 +102,14 @@ namespace osu.Game.Beatmaps public string OnlineMD5Hash { get; set; } = string.Empty; + /// + /// The last time of a local modification (via the editor). + /// + public DateTimeOffset? LastUpdated { get; set; } + + /// + /// The last time online metadata was applied to this beatmap. + /// public DateTimeOffset? LastOnlineUpdate { get; set; } /// diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 8ce4e4c2fb..b457fcb387 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -314,6 +314,7 @@ namespace osu.Game.Beatmaps beatmapInfo.MD5Hash = stream.ComputeMD5Hash(); beatmapInfo.Hash = stream.ComputeSHA2Hash(); beatmapInfo.Status = BeatmapOnlineStatus.LocallyModified; + beatmapInfo.LastUpdated = DateTimeOffset.Now; if (setInfo.Beatmaps.All(b => b.Status == BeatmapOnlineStatus.LocallyModified)) setInfo.Status = BeatmapOnlineStatus.LocallyModified; diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 5f0ec67c71..c073415547 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -67,8 +67,9 @@ namespace osu.Game.Database /// 20 2022-07-21 Added LastAppliedDifficultyVersion to RulesetInfo, changed default value of BeatmapInfo.StarRating to -1. /// 21 2022-07-27 Migrate collections to realm (BeatmapCollection). /// 22 2022-07-31 Added ModPreset. + /// 23 2022-08-01 Added LastUpdated to BeatmapInfo. /// - private const int schema_version = 22; + private const int schema_version = 23; /// /// Lock object which is held during sections, blocking realm retrieval during blocking periods. From fc7fc3d673cf0a843d4eeea0225bcde76b987c36 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 1 Aug 2022 19:13:57 +0300 Subject: [PATCH 0220/2686] Fix newly imported beatmaps not using correct comparer for sorting --- .../Screens/Select/Carousel/CarouselGroup.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs index 8d141b6f72..9302578038 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroup.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroup.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Linq; namespace osu.Game.Screens.Select.Carousel { @@ -15,7 +14,7 @@ namespace osu.Game.Screens.Select.Carousel public IReadOnlyList Items => items; - private List items = new List(); + private readonly List items = new List(); /// /// Used to assign a monotonically increasing ID to items as they are added. This member is @@ -24,9 +23,6 @@ namespace osu.Game.Screens.Select.Carousel private ulong currentItemID; private Comparer? criteriaComparer; - - private static readonly Comparer item_id_comparer = Comparer.Create((x, y) => x.ItemID.CompareTo(y.ItemID)); - private FilterCriteria? lastCriteria; protected int GetIndexOfItem(CarouselItem lastSelected) => items.IndexOf(lastSelected); @@ -90,9 +86,16 @@ namespace osu.Game.Screens.Select.Carousel items.ForEach(c => c.Filter(criteria)); - // IEnumerable.OrderBy() is used instead of List.Sort() to ensure sorting stability - criteriaComparer = Comparer.Create((x, y) => x.CompareTo(criteria, y)); - items = items.OrderBy(c => c, criteriaComparer).ThenBy(c => c, item_id_comparer).ToList(); + criteriaComparer = Comparer.Create((x, y) => + { + int comparison = x.CompareTo(criteria, y); + if (comparison != 0) + return comparison; + + return x.ItemID.CompareTo(y.ItemID); + }); + + items.Sort(criteriaComparer); lastCriteria = criteria; } From 1fe7e4d19a51c8cd8a15122ccb8d5b20c0bfb4bd Mon Sep 17 00:00:00 2001 From: andy840119 Date: Tue, 2 Aug 2022 00:45:47 +0800 Subject: [PATCH 0221/2686] Use non-nullable instead in the catch ruleset. --- osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs | 5 ++--- osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs | 5 +---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index 4824106c55..abe391ba4e 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Game.Configuration; using osu.Game.Rulesets.Catch.Objects; @@ -36,9 +35,9 @@ namespace osu.Game.Rulesets.Catch.Mods public override float DefaultFlashlightSize => 350; - protected override Flashlight CreateFlashlight() => new CatchFlashlight(this, playfield.AsNonNull()); + protected override Flashlight CreateFlashlight() => new CatchFlashlight(this, playfield); - private CatchPlayfield? playfield; + private CatchPlayfield playfield = null!; public override void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs index 0ab6da0363..60f1614d98 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs @@ -1,7 +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 System.Diagnostics; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Bindings; @@ -19,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Mods { public override string Description => @"Use the mouse to control the catcher."; - private DrawableRuleset? drawableRuleset; + private DrawableRuleset drawableRuleset = null!; public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { @@ -28,8 +27,6 @@ namespace osu.Game.Rulesets.Catch.Mods public void ApplyToPlayer(Player player) { - Debug.Assert(drawableRuleset != null); - if (!drawableRuleset.HasReplayLoaded.Value) drawableRuleset.Cursor.Add(new MouseInputHelper((CatchPlayfield)drawableRuleset.Playfield)); } From b1d320bf6700285957102206ade738b3a6b1d318 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Tue, 2 Aug 2022 00:48:23 +0800 Subject: [PATCH 0222/2686] Use non-nullable instead in the taiko ruleset. --- osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs | 5 ++--- osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs | 4 +--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 8872de4d7a..66616486df 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Layout; using osu.Game.Configuration; @@ -37,9 +36,9 @@ namespace osu.Game.Rulesets.Taiko.Mods public override float DefaultFlashlightSize => 250; - protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, playfield.AsNonNull()); + protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, playfield); - private TaikoPlayfield? playfield; + private TaikoPlayfield playfield = null!; public override void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index dab2279351..ec39a2b2e5 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Taiko.Mods /// private const float fade_out_duration = 0.375f; - private DrawableTaikoRuleset? drawableRuleset; + private DrawableTaikoRuleset drawableRuleset = null!; public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { @@ -45,8 +45,6 @@ namespace osu.Game.Rulesets.Taiko.Mods protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) { - Debug.Assert(drawableRuleset != null); - switch (hitObject) { case DrawableDrumRollTick: From 6686b095492abdd1eb0909eea6b57a6c33513b93 Mon Sep 17 00:00:00 2001 From: notmyname <50967056+naipofo@users.noreply.github.com> Date: Mon, 1 Aug 2022 18:54:00 +0200 Subject: [PATCH 0223/2686] Hide F rank from beatmap overlay --- osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs index 118ddfb060..09b44be6c9 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.BeatmapListing { protected override MultipleSelectionFilterTabItem CreateTabItem(ScoreRank value) => new RankItem(value); - protected override IEnumerable GetValues() => base.GetValues().Reverse(); + protected override IEnumerable GetValues() => base.GetValues().Where(r => r > ScoreRank.F).Reverse(); } private class RankItem : MultipleSelectionFilterTabItem From c851e3d8f3150dc965be7e0c5d20a25a1da44d8e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 1 Aug 2022 20:08:18 +0300 Subject: [PATCH 0224/2686] Fix playlist settings reference leak due to unsafe callback binding --- .../OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index 9c6a2a5e0b..a59d37dc8b 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -78,6 +78,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [Resolved] private IAPIProvider api { get; set; } + private IBindable localUser; + private readonly Room room; public MatchSettings(Room room) @@ -304,7 +306,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists MaxAttempts.BindValueChanged(count => MaxAttemptsField.Text = count.NewValue?.ToString(), true); Duration.BindValueChanged(duration => DurationField.Current.Value = duration.NewValue ?? TimeSpan.FromMinutes(30), true); - api.LocalUser.BindValueChanged(populateDurations, true); + localUser = api.LocalUser.GetBoundCopy(); + localUser.BindValueChanged(populateDurations, true); playlist.Items.BindTo(Playlist); Playlist.BindCollectionChanged(onPlaylistChanged, true); From 7e9d11ee2486e04b06f92d3edeb19088ffcf3e68 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 1 Aug 2022 20:15:08 +0300 Subject: [PATCH 0225/2686] Enable NRT on playlists settings overlay --- .../Playlists/PlaylistsRoomSettingsOverlay.cs | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index a59d37dc8b..cd52981528 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.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. -#nullable disable - using System; using System.Collections.Specialized; using System.Linq; @@ -29,9 +27,9 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsRoomSettingsOverlay : RoomSettingsOverlay { - public Action EditPlaylist; + public Action? EditPlaylist; - private MatchSettings settings; + private MatchSettings settings = null!; protected override OsuButton SubmitButton => settings.ApplyButton; @@ -55,30 +53,30 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { private const float disabled_alpha = 0.2f; - public Action EditPlaylist; + public Action? EditPlaylist; - public OsuTextBox NameField, MaxParticipantsField, MaxAttemptsField; - public OsuDropdown DurationField; - public RoomAvailabilityPicker AvailabilityPicker; - public TriangleButton ApplyButton; + public OsuTextBox NameField = null!, MaxParticipantsField = null!, MaxAttemptsField = null!; + public OsuDropdown DurationField = null!; + public RoomAvailabilityPicker AvailabilityPicker = null!; + public TriangleButton ApplyButton = null!; public bool IsLoading => loadingLayer.State.Value == Visibility.Visible; - public OsuSpriteText ErrorText; + public OsuSpriteText ErrorText = null!; - private LoadingLayer loadingLayer; - private DrawableRoomPlaylist playlist; - private OsuSpriteText playlistLength; + private LoadingLayer loadingLayer = null!; + private DrawableRoomPlaylist playlist = null!; + private OsuSpriteText playlistLength = null!; - private PurpleTriangleButton editPlaylistButton; - - [Resolved(CanBeNull = true)] - private IRoomManager manager { get; set; } + private PurpleTriangleButton editPlaylistButton = null!; [Resolved] - private IAPIProvider api { get; set; } + private IRoomManager? manager { get; set; } - private IBindable localUser; + [Resolved] + private IAPIProvider api { get; set; } = null!; + + private IBindable localUser = null!; private readonly Room room; From 7354f9e6ba3c28a27c646409c3a06213155e328e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 1 Aug 2022 22:05:52 +0300 Subject: [PATCH 0226/2686] Remove localisation for now --- osu.Game/Database/TooManyDownloadsNotification.cs | 3 +-- osu.Game/Localisation/CommonStrings.cs | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Database/TooManyDownloadsNotification.cs b/osu.Game/Database/TooManyDownloadsNotification.cs index 8adb997999..c07584c6ec 100644 --- a/osu.Game/Database/TooManyDownloadsNotification.cs +++ b/osu.Game/Database/TooManyDownloadsNotification.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; -using osu.Game.Localisation; using osu.Game.Overlays.Notifications; namespace osu.Game.Database @@ -13,7 +12,7 @@ namespace osu.Game.Database { public TooManyDownloadsNotification(string humanisedModelName) { - Text = CommonStrings.TooManyDownloaded(humanisedModelName); + Text = $"You have downloaded too many {humanisedModelName}s! Please try again later."; Icon = FontAwesome.Solid.ExclamationCircle; } diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 7c82ecf926..1ffcdc0db2 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -54,11 +54,6 @@ namespace osu.Game.Localisation /// public static LocalisableString Downloading => new TranslatableString(getKey(@"downloading"), @"Downloading..."); - /// - /// "You have downloaded too many {0}s! Please try again later." - /// - public static LocalisableString TooManyDownloaded(string humanisedModelName) => new TranslatableString(getKey(@"too_many_downloaded"), @"You have downloaded too many {0}s! Please try again later.", humanisedModelName); - /// /// "Importing..." /// From 923d9a4e5f19aa10273f99a058b51fcecf5b4757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 1 Aug 2022 22:04:14 +0200 Subject: [PATCH 0227/2686] Add failing assertions to demonstrate autosize failure --- .../UserInterface/TestSceneShearedButtons.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs index ba9e1c6366..6c485aff34 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs @@ -3,9 +3,13 @@ #nullable disable +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osuTK.Input; @@ -99,7 +103,10 @@ namespace osu.Game.Tests.Visual.UserInterface Origin = Anchor.Centre, Text = "Fixed width" }); + AddAssert("draw width is 200", () => toggleButton.DrawWidth, () => Is.EqualTo(200).Within(Precision.FLOAT_EPSILON)); + AddStep("change text", () => toggleButton.Text = "New text"); + AddAssert("draw width is 200", () => toggleButton.DrawWidth, () => Is.EqualTo(200).Within(Precision.FLOAT_EPSILON)); AddStep("create auto-sizing button", () => Child = toggleButton = new ShearedToggleButton { @@ -107,7 +114,14 @@ namespace osu.Game.Tests.Visual.UserInterface Origin = Anchor.Centre, Text = "This button autosizes to its text!" }); + AddAssert("button is wider than text", () => toggleButton.DrawWidth, () => Is.GreaterThan(toggleButton.ChildrenOfType().Single().DrawWidth)); + + float originalDrawWidth = 0; + AddStep("store button width", () => originalDrawWidth = toggleButton.DrawWidth); + AddStep("change text", () => toggleButton.Text = "New text"); + AddAssert("button is wider than text", () => toggleButton.DrawWidth, () => Is.GreaterThan(toggleButton.ChildrenOfType().Single().DrawWidth)); + AddAssert("button width decreased", () => toggleButton.DrawWidth, () => Is.LessThan(originalDrawWidth)); } [Test] From 298efa5391734206c8c8d896beb02a940b2b28d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 22 Jul 2022 21:40:24 +0200 Subject: [PATCH 0228/2686] Fix broken `ShearedButton` autosizing logic --- osu.Game/Graphics/UserInterface/ShearedButton.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/ShearedButton.cs b/osu.Game/Graphics/UserInterface/ShearedButton.cs index 259c0646f3..0c25d06cd4 100644 --- a/osu.Game/Graphics/UserInterface/ShearedButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedButton.cs @@ -97,7 +97,7 @@ namespace osu.Game.Graphics.UserInterface { backgroundLayer = new Container { - RelativeSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.Y, CornerRadius = corner_radius, Masking = true, BorderThickness = 2, @@ -128,10 +128,12 @@ namespace osu.Game.Graphics.UserInterface if (width != null) { Width = width.Value; + backgroundLayer.RelativeSizeAxes = Axes.Both; } else { AutoSizeAxes = Axes.X; + backgroundLayer.AutoSizeAxes = Axes.X; text.Margin = new MarginPadding { Horizontal = 15 }; } } From bc059cc1d22ef01c4ec10aa6b58a1249febb1fdf Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Mon, 1 Aug 2022 21:46:01 +0100 Subject: [PATCH 0229/2686] Implemented KeepUpright --- osu.Game/Extensions/DrawableExtensions.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index 35f2d61437..5b92600cd1 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -8,6 +8,7 @@ using osu.Game.Configuration; using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; using osuTK; +using System; namespace osu.Game.Extensions { @@ -79,5 +80,24 @@ namespace osu.Game.Extensions container.Add(child.CreateInstance()); } } + + /// + /// Keeps the drawable upright no matter the Rotation of its parents. + /// + /// The drawable. + public static void KeepUpright(this Drawable drawable) + { + var result = drawable.Parent.DrawInfo; + var scale = result.Matrix.ExtractScale(); + var rotation = new Matrix3( + result.Matrix.Row0 / scale.X, + result.Matrix.Row1 / scale.Y, + new Vector3(0.0f, 0.0f, 1.0f) + ); + float angle = MathF.Atan2(rotation.M12, rotation.M11); + angle *= (360 / (2 * MathF.PI)); + drawable.Rotation = -angle; + } + } } From df85bd74d7ab9eabd2c51b283ab0e15bafa25edc Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Mon, 1 Aug 2022 21:46:37 +0100 Subject: [PATCH 0230/2686] Keep TextSprites in SongProgressInfo upright --- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 69 ++++++++++++++----- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 8f10e84509..520d0c661d 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -48,38 +48,67 @@ namespace osu.Game.Screens.Play.HUD Children = new Drawable[] { - timeCurrent = new OsuSpriteText + new Container { - Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, - Colour = colours.BlueLighter, - Font = OsuFont.Numeric, - Margin = new MarginPadding + Origin = Anchor.BottomLeft, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] { - Left = margin, - }, + timeCurrent = new OsuSpriteText + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Colour = colours.BlueLighter, + Font = OsuFont.Numeric, + } + } }, - progress = new OsuSpriteText + new Container { Origin = Anchor.BottomCentre, Anchor = Anchor.BottomCentre, - Colour = colours.BlueLighter, - Font = OsuFont.Numeric, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + progress = new OsuSpriteText + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Colour = colours.BlueLighter, + Font = OsuFont.Numeric, + } + } }, - timeLeft = new OsuSpriteText + new Container { Origin = Anchor.BottomRight, Anchor = Anchor.BottomRight, - Colour = colours.BlueLighter, - Font = OsuFont.Numeric, - Margin = new MarginPadding + AutoSizeAxes = Axes.Both, + Children = new Drawable[] { - Right = margin, - }, + timeLeft = new OsuSpriteText + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Colour = colours.BlueLighter, + Font = OsuFont.Numeric, + Margin = new MarginPadding + { + Right = margin, + }, + } + } } }; } + protected override void LoadComplete() + { + base.LoadComplete(); + keepTextSpritesUpright(); + } + protected override void Update() { base.Update(); @@ -106,5 +135,13 @@ namespace osu.Game.Screens.Play.HUD } private string formatTime(TimeSpan timeSpan) => $"{(timeSpan < TimeSpan.Zero ? "-" : "")}{Math.Floor(timeSpan.Duration().TotalMinutes)}:{timeSpan.Duration().Seconds:D2}"; + + private void keepTextSpritesUpright() + { + timeCurrent.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUpright(timeCurrent); }; + progress.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUpright(timeCurrent); }; + timeLeft.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUpright(timeCurrent); }; + } + } } From eb73f9e88c2616bc42ff81a2b5f0e7729a798e9f Mon Sep 17 00:00:00 2001 From: andy840119 Date: Tue, 2 Aug 2022 10:23:52 +0800 Subject: [PATCH 0231/2686] Remove un-need using. --- osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index ec39a2b2e5..4c802978e3 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -1,7 +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 System.Diagnostics; using osu.Framework.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; From 4adc8375e927fe0258c64a174ef100fc992a5317 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 12:12:02 +0900 Subject: [PATCH 0232/2686] Add more xmldoc and avoid `BeatmapSet` status being set when it shouldn't be --- osu.Game/Beatmaps/BeatmapOnlineStatus.cs | 4 ++++ osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapOnlineStatus.cs b/osu.Game/Beatmaps/BeatmapOnlineStatus.cs index c91b46c92f..b78c42022a 100644 --- a/osu.Game/Beatmaps/BeatmapOnlineStatus.cs +++ b/osu.Game/Beatmaps/BeatmapOnlineStatus.cs @@ -11,6 +11,10 @@ namespace osu.Game.Beatmaps { public enum BeatmapOnlineStatus { + /// + /// This is a special status given when local changes are made via the editor. + /// Once in this state, online status changes should be ignored unless the beatmap is reverted or submitted. + /// [Description("Local")] LocallyModified = -4, diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index f51a8bf7bf..2228281ed3 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -51,6 +51,9 @@ namespace osu.Game.Beatmaps /// /// Queue an update for a beatmap set. /// + /// + /// This may happen during initial import, or at a later stage in response to a user action or server event. + /// /// The beatmap set to update. Updates will be applied directly (so a transaction should be started if this instance is managed). /// Whether metadata from an online source should be preferred. If true, the local cache will be skipped to ensure the freshest data state possible. public void Update(BeatmapSetInfo beatmapSet, bool preferOnlineFetch) @@ -94,15 +97,15 @@ namespace osu.Game.Beatmaps beatmapInfo.LastOnlineUpdate = res.LastUpdated; beatmapInfo.Metadata.Author.OnlineID = res.AuthorID; + Debug.Assert(beatmapInfo.BeatmapSet != null); + // In the case local changes have been applied, don't reset the status. if (beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified) { beatmapInfo.Status = res.Status; + beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None; } - Debug.Assert(beatmapInfo.BeatmapSet != null); - - beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None; beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID; beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked; beatmapInfo.BeatmapSet.DateSubmitted = res.BeatmapSet?.Submitted; From 34ffc51c5195196873aefda972549e20b5e1a1f5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 13:56:02 +0900 Subject: [PATCH 0233/2686] Avoid clearing chat overlay textbox when pressing "back" key binding Generally this is expected behaviour for usages of focused text boxes (ie. to clear search content), but not so much here. Addresses https://github.com/ppy/osu/discussions/19403#discussioncomment-3230395. --- osu.Game/Graphics/UserInterface/FocusedTextBox.cs | 7 ++++++- osu.Game/Overlays/Chat/ChatTextBox.cs | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index fce4221c87..230d921c68 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -21,6 +21,11 @@ namespace osu.Game.Graphics.UserInterface private bool allowImmediateFocus => host?.OnScreenKeyboardOverlapsGameWindow != true; + /// + /// Whether the content of the text box should be cleared on the first "back" key press. + /// + protected virtual bool ClearTextOnBackKey => true; + public void TakeFocus() { if (!allowImmediateFocus) @@ -78,7 +83,7 @@ namespace osu.Game.Graphics.UserInterface if (!HasFocus) return false; - if (e.Action == GlobalAction.Back) + if (ClearTextOnBackKey && e.Action == GlobalAction.Back) { if (Text.Length > 0) { diff --git a/osu.Game/Overlays/Chat/ChatTextBox.cs b/osu.Game/Overlays/Chat/ChatTextBox.cs index ae8816b009..887eb96c15 100644 --- a/osu.Game/Overlays/Chat/ChatTextBox.cs +++ b/osu.Game/Overlays/Chat/ChatTextBox.cs @@ -13,6 +13,8 @@ namespace osu.Game.Overlays.Chat public override bool HandleLeftRightArrows => !ShowSearch.Value; + protected override bool ClearTextOnBackKey => false; + protected override void LoadComplete() { base.LoadComplete(); From df76f9f4dae2c7cd5842801332bd50b772b3ec2e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 15:49:22 +0900 Subject: [PATCH 0234/2686] Fix some additional metadata being updated when it shouldn't (with local changes) --- .../Beatmaps/BeatmapUpdaterMetadataLookup.cs | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index 2228281ed3..9d17e36812 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -95,20 +95,21 @@ namespace osu.Game.Beatmaps beatmapInfo.OnlineID = res.OnlineID; beatmapInfo.OnlineMD5Hash = res.MD5Hash; beatmapInfo.LastOnlineUpdate = res.LastUpdated; - beatmapInfo.Metadata.Author.OnlineID = res.AuthorID; Debug.Assert(beatmapInfo.BeatmapSet != null); + beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID; - // In the case local changes have been applied, don't reset the status. + // Some metadata should only be applied if there's no local changes. if (beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified) { beatmapInfo.Status = res.Status; - beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None; - } - beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID; - beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked; - beatmapInfo.BeatmapSet.DateSubmitted = res.BeatmapSet?.Submitted; + beatmapInfo.Metadata.Author.OnlineID = res.AuthorID; + + beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None; + beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked; + beatmapInfo.BeatmapSet.DateSubmitted = res.BeatmapSet?.Submitted; + } logForModel(set, $"Online retrieval mapped {beatmapInfo} to {res.OnlineBeatmapSetID} / {res.OnlineID}."); } @@ -209,17 +210,21 @@ namespace osu.Game.Beatmaps beatmapInfo.Status = status; - Debug.Assert(beatmapInfo.BeatmapSet != null); - - beatmapInfo.BeatmapSet.Status = status; - beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0); // TODO: DateSubmitted and DateRanked are not provided by local cache. beatmapInfo.OnlineID = reader.GetInt32(1); - beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3); - beatmapInfo.OnlineMD5Hash = reader.GetString(4); beatmapInfo.LastOnlineUpdate = reader.GetDateTimeOffset(5); + Debug.Assert(beatmapInfo.BeatmapSet != null); + beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0); + + // Some metadata should only be applied if there's no local changes. + if (beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified) + { + beatmapInfo.BeatmapSet.Status = status; + beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3); + } + logForModel(set, $"Cached local retrieval for {beatmapInfo}."); return true; } From 8cb02f47eb6b8108c9f61de61f0187b80baebb64 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 15:50:16 +0900 Subject: [PATCH 0235/2686] Mark `BeatmapSet.Status` as modified when any beatmap is modified, rather than all --- osu.Game/Beatmaps/BeatmapManager.cs | 5 ++--- .../Beatmaps/BeatmapUpdaterMetadataLookup.cs | 16 +++++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e3d2832108..b6bfab32cd 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -312,14 +312,13 @@ namespace osu.Game.Beatmaps beatmapInfo.MD5Hash = stream.ComputeMD5Hash(); beatmapInfo.Hash = stream.ComputeSHA2Hash(); - beatmapInfo.Status = BeatmapOnlineStatus.LocallyModified; - if (setInfo.Beatmaps.All(b => b.Status == BeatmapOnlineStatus.LocallyModified)) - setInfo.Status = BeatmapOnlineStatus.LocallyModified; + beatmapInfo.Status = BeatmapOnlineStatus.LocallyModified; AddFile(setInfo, stream, createBeatmapFilenameFromMetadata(beatmapInfo)); setInfo.Hash = beatmapImporter.ComputeHash(setInfo); + setInfo.Status = BeatmapOnlineStatus.LocallyModified; Realm.Write(r => { diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index 9d17e36812..3238863700 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -6,6 +6,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Linq; using System.Threading.Tasks; using Microsoft.Data.Sqlite; using osu.Framework.Development; @@ -103,9 +104,11 @@ namespace osu.Game.Beatmaps if (beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified) { beatmapInfo.Status = res.Status; - beatmapInfo.Metadata.Author.OnlineID = res.AuthorID; + } + if (beatmapInfo.BeatmapSet.Beatmaps.All(b => b.MatchesOnlineVersion || b.Status != BeatmapOnlineStatus.LocallyModified)) + { beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None; beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked; beatmapInfo.BeatmapSet.DateSubmitted = res.BeatmapSet?.Submitted; @@ -208,7 +211,12 @@ namespace osu.Game.Beatmaps { var status = (BeatmapOnlineStatus)reader.GetByte(2); - beatmapInfo.Status = status; + // Some metadata should only be applied if there's no local changes. + if (beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified) + { + beatmapInfo.Status = status; + beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3); + } // TODO: DateSubmitted and DateRanked are not provided by local cache. beatmapInfo.OnlineID = reader.GetInt32(1); @@ -218,11 +226,9 @@ namespace osu.Game.Beatmaps Debug.Assert(beatmapInfo.BeatmapSet != null); beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0); - // Some metadata should only be applied if there's no local changes. - if (beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified) + if (beatmapInfo.BeatmapSet.Beatmaps.All(b => b.MatchesOnlineVersion || b.Status != BeatmapOnlineStatus.LocallyModified)) { beatmapInfo.BeatmapSet.Status = status; - beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3); } logForModel(set, $"Cached local retrieval for {beatmapInfo}."); From 7022c6382dfd200974d3ef871beb01dab0eeac94 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 16:30:14 +0900 Subject: [PATCH 0236/2686] Add localisation support for local modification strings --- osu.Game/Beatmaps/BeatmapOnlineStatus.cs | 2 ++ .../Drawables/BeatmapSetOnlineStatusPill.cs | 19 ++++++++++++++- osu.Game/Localisation/SongSelectStrings.cs | 24 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Localisation/SongSelectStrings.cs diff --git a/osu.Game/Beatmaps/BeatmapOnlineStatus.cs b/osu.Game/Beatmaps/BeatmapOnlineStatus.cs index b78c42022a..cdd99d4432 100644 --- a/osu.Game/Beatmaps/BeatmapOnlineStatus.cs +++ b/osu.Game/Beatmaps/BeatmapOnlineStatus.cs @@ -5,6 +5,7 @@ using System.ComponentModel; using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Beatmaps @@ -16,6 +17,7 @@ namespace osu.Game.Beatmaps /// Once in this state, online status changes should be ignored unless the beatmap is reverted or submitted. /// [Description("Local")] + [LocalisableDescription(typeof(SongSelectStrings), nameof(SongSelectStrings.LocallyModified))] LocallyModified = -4, None = -3, diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs index 88d4991c5d..23d90ab76e 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs @@ -6,15 +6,18 @@ using osu.Framework.Extensions; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Localisation; using osu.Game.Overlays; using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables { - public class BeatmapSetOnlineStatusPill : CircularContainer + public class BeatmapSetOnlineStatusPill : CircularContainer, IHasTooltip { private BeatmapOnlineStatus status; @@ -96,5 +99,19 @@ namespace osu.Game.Beatmaps.Drawables background.Colour = OsuColour.ForBeatmapSetOnlineStatus(Status) ?? colourProvider?.Light1 ?? colours.GreySeaFoamLighter; } + + public LocalisableString TooltipText + { + get + { + switch (Status) + { + case BeatmapOnlineStatus.LocallyModified: + return SongSelectStrings.LocallyModifiedTooltip; + } + + return string.Empty; + } + } } } diff --git a/osu.Game/Localisation/SongSelectStrings.cs b/osu.Game/Localisation/SongSelectStrings.cs new file mode 100644 index 0000000000..12f70cd967 --- /dev/null +++ b/osu.Game/Localisation/SongSelectStrings.cs @@ -0,0 +1,24 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class SongSelectStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.SongSelect"; + + /// + /// "Local" + /// + public static LocalisableString LocallyModified => new TranslatableString(getKey(@"locally_modified"), @"Local"); + + /// + /// "Has been locally modified" + /// + public static LocalisableString LocallyModifiedTooltip => new TranslatableString(getKey(@"locally_modified_tooltip"), @"Has been locally modified"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} From efa3c3b75716f3355e9187f23a497267d2680f55 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 16:35:15 +0900 Subject: [PATCH 0237/2686] Fix multiple cases of mutations at editor setup screen not triggering a state save --- osu.Game/Screens/Edit/EditorBeatmap.cs | 3 +++ osu.Game/Screens/Edit/Setup/DesignSection.cs | 2 ++ osu.Game/Screens/Edit/Setup/MetadataSection.cs | 2 ++ 3 files changed, 7 insertions(+) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 96425e8bc8..afbb5cc018 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -78,7 +78,10 @@ namespace osu.Game.Screens.Edit this.beatmapInfo = beatmapInfo ?? playableBeatmap.BeatmapInfo; if (beatmapSkin is Skin skin) + { BeatmapSkin = new EditorBeatmapSkin(skin); + BeatmapSkin.BeatmapSkinChanged += SaveState; + } beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap); diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index 40bbfeaf7d..5cec730440 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -126,6 +126,8 @@ namespace osu.Game.Screens.Edit.Setup Beatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning.Current.Value; Beatmap.BeatmapInfo.LetterboxInBreaks = letterboxDuringBreaks.Current.Value; Beatmap.BeatmapInfo.SamplesMatchPlaybackRate = samplesMatchPlaybackRate.Current.Value; + + Beatmap.SaveState(); } } } diff --git a/osu.Game/Screens/Edit/Setup/MetadataSection.cs b/osu.Game/Screens/Edit/Setup/MetadataSection.cs index 854dec2001..33cc88da0a 100644 --- a/osu.Game/Screens/Edit/Setup/MetadataSection.cs +++ b/osu.Game/Screens/Edit/Setup/MetadataSection.cs @@ -117,6 +117,8 @@ namespace osu.Game.Screens.Edit.Setup Beatmap.BeatmapInfo.DifficultyName = difficultyTextBox.Current.Value; Beatmap.Metadata.Source = sourceTextBox.Current.Value; Beatmap.Metadata.Tags = tagsTextBox.Current.Value; + + Beatmap.SaveState(); } } } From cc4cde2c7978a4e474eb1a606995cde6b7d28841 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 17:54:42 +0900 Subject: [PATCH 0238/2686] Improve `IBeatSyncProvider` interface and reduce beatmap track dependence --- osu.Game/Beatmaps/IBeatSyncProvider.cs | 17 ++- .../Containers/BeatSyncedContainer.cs | 23 ++-- osu.Game/OsuGameBase.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 3 +- osu.Game/Screens/Menu/LogoVisualisation.cs | 111 +++++++++--------- .../Play/MasterGameplayClockContainer.cs | 20 ++-- 6 files changed, 88 insertions(+), 88 deletions(-) diff --git a/osu.Game/Beatmaps/IBeatSyncProvider.cs b/osu.Game/Beatmaps/IBeatSyncProvider.cs index 362f02f2dd..b0b265c228 100644 --- a/osu.Game/Beatmaps/IBeatSyncProvider.cs +++ b/osu.Game/Beatmaps/IBeatSyncProvider.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Audio.Track; +using osu.Framework.Audio; using osu.Framework.Timing; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; @@ -14,12 +14,21 @@ namespace osu.Game.Beatmaps /// Primarily intended for use with . /// [Cached] - public interface IBeatSyncProvider + public interface IBeatSyncProvider : IHasAmplitudes { + /// + /// Check whether beat sync is currently available. + /// + public bool BeatSyncAvailable => Clock != null; + + /// + /// Access any available control points from a beatmap providing beat sync. If null, no current provider is available. + /// ControlPointInfo? ControlPoints { get; } + /// + /// Access a clock currently responsible for providing beat sync. If null, no current provider is available. + /// IClock? Clock { get; } - - ChannelAmplitudes? Amplitudes { get; } } } diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index e1998a1d7f..774468c344 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.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. -#nullable disable - using System; using System.Diagnostics; using osu.Framework.Allocation; @@ -10,13 +8,12 @@ using osu.Framework.Audio.Track; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Screens.Play; namespace osu.Game.Graphics.Containers { /// /// A container which fires a callback when a new beat is reached. - /// Consumes a parent or (whichever is first available). + /// Consumes a parent . /// /// /// This container does not set its own clock to the source used for beat matching. @@ -28,8 +25,9 @@ namespace osu.Game.Graphics.Containers public class BeatSyncedContainer : Container { private int lastBeat; - protected TimingControlPoint LastTimingPoint { get; private set; } - protected EffectControlPoint LastEffectPoint { get; private set; } + + protected TimingControlPoint? LastTimingPoint { get; private set; } + protected EffectControlPoint? LastEffectPoint { get; private set; } /// /// The amount of time before a beat we should fire . @@ -71,12 +69,12 @@ namespace osu.Game.Graphics.Containers public double MinimumBeatLength { get; set; } /// - /// Whether this container is currently tracking a beatmap's timing data. + /// Whether this container is currently tracking a beat sync provider. /// protected bool IsBeatSyncedWithTrack { get; private set; } [Resolved] - protected IBeatSyncProvider BeatSyncSource { get; private set; } + protected IBeatSyncProvider BeatSyncSource { get; private set; } = null!; protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { @@ -87,19 +85,18 @@ namespace osu.Game.Graphics.Containers TimingControlPoint timingPoint; EffectControlPoint effectPoint; - IsBeatSyncedWithTrack = BeatSyncSource.Clock?.IsRunning == true && BeatSyncSource.ControlPoints != null; + IsBeatSyncedWithTrack = BeatSyncSource.BeatSyncAvailable && BeatSyncSource.Clock?.IsRunning == true; double currentTrackTime; if (IsBeatSyncedWithTrack) { - Debug.Assert(BeatSyncSource.ControlPoints != null); Debug.Assert(BeatSyncSource.Clock != null); currentTrackTime = BeatSyncSource.Clock.CurrentTime + EarlyActivationMilliseconds; - timingPoint = BeatSyncSource.ControlPoints.TimingPointAt(currentTrackTime); - effectPoint = BeatSyncSource.ControlPoints.EffectPointAt(currentTrackTime); + timingPoint = BeatSyncSource.ControlPoints?.TimingPointAt(currentTrackTime) ?? TimingControlPoint.DEFAULT; + effectPoint = BeatSyncSource.ControlPoints?.EffectPointAt(currentTrackTime) ?? EffectControlPoint.DEFAULT; } else { @@ -136,7 +133,7 @@ namespace osu.Game.Graphics.Containers if (AllowMistimedEventFiring || Math.Abs(TimeSinceLastBeat) < MISTIMED_ALLOWANCE) { using (BeginDelayedSequence(-TimeSinceLastBeat)) - OnNewBeat(beatIndex, timingPoint, effectPoint, BeatSyncSource.Amplitudes ?? ChannelAmplitudes.Empty); + OnNewBeat(beatIndex, timingPoint, effectPoint, BeatSyncSource.CurrentAmplitudes); } lastBeat = beatIndex; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 97d15ae6ad..f62349c447 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -588,6 +588,6 @@ namespace osu.Game ControlPointInfo IBeatSyncProvider.ControlPoints => Beatmap.Value.BeatmapLoaded ? Beatmap.Value.Beatmap.ControlPointInfo : null; IClock IBeatSyncProvider.Clock => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track : (IClock)null; - ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : null; + ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 9e9cd8e3b7..89f9aec5ee 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -10,6 +10,7 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -949,7 +950,7 @@ namespace osu.Game.Screens.Edit ControlPointInfo IBeatSyncProvider.ControlPoints => editorBeatmap.ControlPointInfo; IClock IBeatSyncProvider.Clock => clock; - ChannelAmplitudes? IBeatSyncProvider.Amplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : null; + ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; private class BeatmapEditorToast : Toast { diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index c66bd3639a..c238bf8a21 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -1,10 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using osuTK; -using osuTK.Graphics; +using System; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Track; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Batches; using osu.Framework.Graphics.Colour; @@ -12,16 +14,10 @@ using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; -using osu.Game.Beatmaps; -using System; -using System.Collections.Generic; -using JetBrains.Annotations; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Track; -using osu.Framework.Bindables; using osu.Framework.Utils; -using osu.Framework.Extensions.Color4Extensions; +using osu.Game.Beatmaps; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Menu { @@ -30,8 +26,6 @@ namespace osu.Game.Screens.Menu /// public class LogoVisualisation : Drawable { - private readonly IBindable beatmap = new Bindable(); - /// /// The number of bars to jump each update iteration. /// @@ -76,7 +70,8 @@ namespace osu.Game.Screens.Menu private readonly float[] frequencyAmplitudes = new float[256]; - private IShader shader; + private IShader shader = null!; + private readonly Texture texture; public LogoVisualisation() @@ -93,32 +88,35 @@ namespace osu.Game.Screens.Menu } [BackgroundDependencyLoader] - private void load(ShaderManager shaders, IBindable beatmap) + private void load(ShaderManager shaders) { - this.beatmap.BindTo(beatmap); shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); } private readonly float[] temporalAmplitudes = new float[ChannelAmplitudes.AMPLITUDES_SIZE]; + [Resolved] + private IBeatSyncProvider beatSyncProvider { get; set; } = null!; + private void updateAmplitudes() { - var effect = beatmap.Value.BeatmapLoaded && beatmap.Value.TrackLoaded - ? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(beatmap.Value.Track.CurrentTime) - : null; + bool isKiaiTime = false; for (int i = 0; i < temporalAmplitudes.Length; i++) temporalAmplitudes[i] = 0; - if (beatmap.Value.TrackLoaded) - addAmplitudesFromSource(beatmap.Value.Track); + if (beatSyncProvider.Clock != null) + { + isKiaiTime = beatSyncProvider.ControlPoints?.EffectPointAt(beatSyncProvider.Clock.CurrentTime).KiaiMode ?? false; + addAmplitudesFromSource(beatSyncProvider); + } foreach (var source in amplitudeSources) addAmplitudesFromSource(source); for (int i = 0; i < bars_per_visualiser; i++) { - float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (effect?.KiaiMode == true ? 1 : 0.5f); + float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (isKiaiTime ? 1 : 0.5f); if (targetAmplitude > frequencyAmplitudes[i]) frequencyAmplitudes[i] = targetAmplitude; } @@ -153,7 +151,7 @@ namespace osu.Game.Screens.Menu protected override DrawNode CreateDrawNode() => new VisualisationDrawNode(this); - private void addAmplitudesFromSource([NotNull] IHasAmplitudes source) + private void addAmplitudesFromSource(IHasAmplitudes source) { if (source == null) throw new ArgumentNullException(nameof(source)); @@ -170,8 +168,8 @@ namespace osu.Game.Screens.Menu { protected new LogoVisualisation Source => (LogoVisualisation)base.Source; - private IShader shader; - private Texture texture; + private IShader shader = null!; + private Texture texture = null!; // Assuming the logo is a circle, we don't need a second dimension. private float size; @@ -209,43 +207,40 @@ namespace osu.Game.Screens.Menu ColourInfo colourInfo = DrawColourInfo.Colour; colourInfo.ApplyChild(transparent_white); - if (audioData != null) + for (int j = 0; j < visualiser_rounds; j++) { - for (int j = 0; j < visualiser_rounds; j++) + for (int i = 0; i < bars_per_visualiser; i++) { - for (int i = 0; i < bars_per_visualiser; i++) - { - if (audioData[i] < amplitude_dead_zone) - continue; + if (audioData[i] < amplitude_dead_zone) + continue; - float rotation = MathUtils.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds); - float rotationCos = MathF.Cos(rotation); - float rotationSin = MathF.Sin(rotation); - // taking the cos and sin to the 0..1 range - var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * size; + float rotation = MathUtils.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds); + float rotationCos = MathF.Cos(rotation); + float rotationSin = MathF.Sin(rotation); + // taking the cos and sin to the 0..1 range + var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * size; - var barSize = new Vector2(size * MathF.Sqrt(2 * (1 - MathF.Cos(MathUtils.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * audioData[i]); - // The distance between the position and the sides of the bar. - var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2); - // The distance between the bottom side of the bar and the top side. - var amplitudeOffset = new Vector2(rotationCos * barSize.Y, rotationSin * barSize.Y); + var barSize = new Vector2(size * MathF.Sqrt(2 * (1 - MathF.Cos(MathUtils.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * audioData[i]); + // The distance between the position and the sides of the bar. + var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2); + // The distance between the bottom side of the bar and the top side. + var amplitudeOffset = new Vector2(rotationCos * barSize.Y, rotationSin * barSize.Y); - var rectangle = new Quad( - Vector2Extensions.Transform(barPosition - bottomOffset, DrawInfo.Matrix), - Vector2Extensions.Transform(barPosition - bottomOffset + amplitudeOffset, DrawInfo.Matrix), - Vector2Extensions.Transform(barPosition + bottomOffset, DrawInfo.Matrix), - Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix) - ); + var rectangle = new Quad( + Vector2Extensions.Transform(barPosition - bottomOffset, DrawInfo.Matrix), + Vector2Extensions.Transform(barPosition - bottomOffset + amplitudeOffset, DrawInfo.Matrix), + Vector2Extensions.Transform(barPosition + bottomOffset, DrawInfo.Matrix), + Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix) + ); - DrawQuad( - texture, - rectangle, - colourInfo, - null, - vertexBatch.AddAction, - // barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that. - Vector2.Divide(inflation, barSize.Yx)); - } + DrawQuad( + texture, + rectangle, + colourInfo, + null, + vertexBatch.AddAction, + // barSize by itself will make it smooth more in the X axis than in the Y axis, this reverts that. + Vector2.Divide(inflation, barSize.Yx)); } } diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index cd37c541ec..d7f6992fee 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -53,21 +51,21 @@ namespace osu.Game.Screens.Play private readonly WorkingBeatmap beatmap; - private HardwareCorrectionOffsetClock userGlobalOffsetClock; - private HardwareCorrectionOffsetClock userBeatmapOffsetClock; - private HardwareCorrectionOffsetClock platformOffsetClock; - private MasterGameplayClock masterGameplayClock; - private Bindable userAudioOffset; + private HardwareCorrectionOffsetClock userGlobalOffsetClock = null!; + private HardwareCorrectionOffsetClock userBeatmapOffsetClock = null!; + private HardwareCorrectionOffsetClock platformOffsetClock = null!; + private MasterGameplayClock masterGameplayClock = null!; + private Bindable userAudioOffset = null!; - private IDisposable beatmapOffsetSubscription; + private IDisposable? beatmapOffsetSubscription; private readonly double skipTargetTime; [Resolved] - private RealmAccess realm { get; set; } + private RealmAccess realm { get; set; } = null!; [Resolved] - private OsuConfigManager config { get; set; } + private OsuConfigManager config { get; set; } = null!; /// /// Create a new master gameplay clock container. @@ -255,7 +253,7 @@ namespace osu.Game.Screens.Play ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo; IClock IBeatSyncProvider.Clock => GameplayClock; - ChannelAmplitudes? IBeatSyncProvider.Amplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : null; + ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; private class HardwareCorrectionOffsetClock : FramedOffsetClock { From 258ad7c6b90dbe06f8d4e6c6ae5e28ca2d6a5b40 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 18:18:40 +0900 Subject: [PATCH 0239/2686] Tidy up kiai time access --- osu.Game/Beatmaps/IBeatSyncProvider.cs | 5 +++++ .../Graphics/Containers/BeatSyncedContainer.cs | 14 +++++++++----- osu.Game/Screens/Menu/LogoVisualisation.cs | 7 +------ osu.Game/Screens/Menu/OsuLogo.cs | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/IBeatSyncProvider.cs b/osu.Game/Beatmaps/IBeatSyncProvider.cs index b0b265c228..485497a8f0 100644 --- a/osu.Game/Beatmaps/IBeatSyncProvider.cs +++ b/osu.Game/Beatmaps/IBeatSyncProvider.cs @@ -21,6 +21,11 @@ namespace osu.Game.Beatmaps /// public bool BeatSyncAvailable => Clock != null; + /// + /// Whether the beat sync provider is currently in a kiai section. Should make everything more epic. + /// + public bool IsKiaiTime => Clock != null && (ControlPoints?.EffectPointAt(Clock.CurrentTime).KiaiMode ?? false); + /// /// Access any available control points from a beatmap providing beat sync. If null, no current provider is available. /// diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 774468c344..c8ea21e139 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -26,8 +26,10 @@ namespace osu.Game.Graphics.Containers { private int lastBeat; - protected TimingControlPoint? LastTimingPoint { get; private set; } - protected EffectControlPoint? LastEffectPoint { get; private set; } + private TimingControlPoint? lastTimingPoint { get; set; } + private EffectControlPoint? lastEffectPoint { get; set; } + + public bool IsKiaiTime { get; private set; } /// /// The amount of time before a beat we should fire . @@ -125,7 +127,7 @@ namespace osu.Game.Graphics.Containers TimeSinceLastBeat = beatLength - TimeUntilNextBeat; - if (ReferenceEquals(timingPoint, LastTimingPoint) && beatIndex == lastBeat) + if (ReferenceEquals(timingPoint, lastTimingPoint) && beatIndex == lastBeat) return; // as this event is sometimes used for sound triggers where `BeginDelayedSequence` has no effect, avoid firing it if too far away from the beat. @@ -137,8 +139,10 @@ namespace osu.Game.Graphics.Containers } lastBeat = beatIndex; - LastTimingPoint = timingPoint; - LastEffectPoint = effectPoint; + lastTimingPoint = timingPoint; + lastEffectPoint = effectPoint; + + IsKiaiTime = lastEffectPoint?.KiaiMode ?? false; } } } diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index c238bf8a21..e9f52e0b9f 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -100,23 +100,18 @@ namespace osu.Game.Screens.Menu private void updateAmplitudes() { - bool isKiaiTime = false; - for (int i = 0; i < temporalAmplitudes.Length; i++) temporalAmplitudes[i] = 0; if (beatSyncProvider.Clock != null) - { - isKiaiTime = beatSyncProvider.ControlPoints?.EffectPointAt(beatSyncProvider.Clock.CurrentTime).KiaiMode ?? false; addAmplitudesFromSource(beatSyncProvider); - } foreach (var source in amplitudeSources) addAmplitudesFromSource(source); for (int i = 0; i < bars_per_visualiser; i++) { - float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (isKiaiTime ? 1 : 0.5f); + float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (beatSyncProvider.IsKiaiTime ? 1 : 0.5f); if (targetAmplitude > frequencyAmplitudes[i]) frequencyAmplitudes[i] = targetAmplitude; } diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 0909f615f2..e9b50f94f7 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -353,7 +353,7 @@ namespace osu.Game.Screens.Menu float maxAmplitude = lastBeatIndex >= 0 ? musicController.CurrentTrack.CurrentAmplitudes.Maximum : 0; logoAmplitudeContainer.Scale = new Vector2((float)Interpolation.Damp(logoAmplitudeContainer.Scale.X, 1 - Math.Max(0, maxAmplitude - scale_adjust_cutoff) * 0.04f, 0.9f, Time.Elapsed)); - triangles.Velocity = (float)Interpolation.Damp(triangles.Velocity, triangles_paused_velocity * (LastEffectPoint.KiaiMode ? 4 : 2), 0.995f, Time.Elapsed); + triangles.Velocity = (float)Interpolation.Damp(triangles.Velocity, triangles_paused_velocity * (IsKiaiTime ? 4 : 2), 0.995f, Time.Elapsed); } else { From b4e55f7309f1a121152023e066a83c1bfb0d3bdf Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 2 Aug 2022 19:50:57 +0900 Subject: [PATCH 0240/2686] Apply IRenderer changes --- .../PippidonRuleset.cs | 7 +---- .../PippidonRulesetIcon.cs | 26 +++++++++++++++++ .../PippidonRuleset.cs | 8 +---- .../PippidonRulesetIcon.cs | 29 +++++++++++++++++++ .../Skinning/Legacy/LegacyBodyPiece.cs | 2 +- .../Skinning/Legacy/LegacyNotePiece.cs | 1 - .../LegacyMainCirclePieceTest.cs | 15 ++++++++-- .../TestSceneCursorTrail.cs | 9 ++++-- .../TestSceneGameplayCursor.cs | 1 - .../TestSceneSkinFallbacks.cs | 1 - .../UI/Cursor/CursorTrail.cs | 7 +++-- .../Skinning/Legacy/LegacyDrumRoll.cs | 2 +- .../Checks/CheckBackgroundQualityTest.cs | 13 +++++---- .../TestSceneHitObjectAccentColour.cs | 1 - .../Gameplay/TestSceneStoryboardSamples.cs | 6 ++++ .../Skinning/LegacySkinAnimationTest.cs | 21 +++++++++++--- .../Skinning/LegacySkinTextureFallbackTest.cs | 3 ++ .../TestSceneDrawableRulesetDependencies.cs | 8 +++-- .../TestSceneRulesetSkinProvidingContainer.cs | 1 - .../Skins/SkinDeserialisationTest.cs | 1 - .../TestSceneBeatmapSkinLookupDisables.cs | 1 - .../Skins/TestSceneSkinConfigurationLookup.cs | 1 - .../Skins/TestSceneSkinProvidingContainer.cs | 17 +++++++++-- .../TestSceneBackgroundScreenDefault.cs | 13 +++++++-- .../TestSceneSeasonalBackgroundLoader.cs | 27 ++++++++++++----- .../Gameplay/TestSceneSkinnableDrawable.cs | 1 - .../Gameplay/TestSceneSkinnableSound.cs | 1 - osu.Game/Beatmaps/WorkingBeatmapCache.cs | 5 +++- osu.Game/Graphics/Backgrounds/Triangles.cs | 9 +++--- osu.Game/Graphics/ParticleExplosion.cs | 2 +- osu.Game/Graphics/ParticleSpewer.cs | 2 +- osu.Game/IO/IStorageResourceProvider.cs | 6 ++++ osu.Game/OsuGameBase.cs | 2 +- osu.Game/Rulesets/Mods/ModFlashlight.cs | 3 +- .../UI/DrawableRulesetDependencies.cs | 8 ++--- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 1 - osu.Game/Screens/Menu/LogoVisualisation.cs | 8 ++--- osu.Game/Skinning/DefaultSkin.cs | 1 - osu.Game/Skinning/IAnimationTimeReference.cs | 2 +- osu.Game/Skinning/ISkin.cs | 1 - osu.Game/Skinning/LegacySkin.cs | 1 - osu.Game/Skinning/LegacySkinExtensions.cs | 1 - osu.Game/Skinning/LegacySkinTransformer.cs | 1 - osu.Game/Skinning/ResourceStoreBackedSkin.cs | 3 +- osu.Game/Skinning/Skin.cs | 3 +- osu.Game/Skinning/SkinManager.cs | 3 +- osu.Game/Skinning/SkinProvidingContainer.cs | 1 - .../Drawables/DrawableStoryboard.cs | 2 +- .../Tests/Beatmaps/HitObjectSampleTest.cs | 7 +++++ osu.Game/Tests/Visual/SkinnableTestScene.cs | 3 +- 50 files changed, 204 insertions(+), 94 deletions(-) create mode 100644 Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs create mode 100644 Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs index 7dcdac7019..0522840e9e 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; @@ -50,9 +48,6 @@ namespace osu.Game.Rulesets.Pippidon new KeyBinding(InputKey.X, PippidonAction.Button2), }; - public override Drawable CreateIcon() => new Sprite - { - Texture = new TextureStore(new TextureLoaderStore(CreateResourceStore()), false).Get("Textures/coin"), - }; + public override Drawable CreateIcon() => new PippidonRulesetIcon(this); } } diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs new file mode 100644 index 0000000000..ff10233b50 --- /dev/null +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Rulesets.Pippidon +{ + public class PippidonRulesetIcon : Sprite + { + private readonly Ruleset ruleset; + + public PippidonRulesetIcon(Ruleset ruleset) + { + this.ruleset = ruleset; + } + + [BackgroundDependencyLoader] + private void load(IRenderer renderer) + { + Texture = new TextureStore(renderer, new TextureLoaderStore(ruleset.CreateResourceStore()), false).Get("Textures/coin"); + } + } +} diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs index d4566477db..89246373ee 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; @@ -47,10 +45,6 @@ namespace osu.Game.Rulesets.Pippidon new KeyBinding(InputKey.S, PippidonAction.MoveDown), }; - public override Drawable CreateIcon() => new Sprite - { - Margin = new MarginPadding { Top = 3 }, - Texture = new TextureStore(new TextureLoaderStore(CreateResourceStore()), false).Get("Textures/coin"), - }; + public override Drawable CreateIcon() => new PippidonRulesetIcon(this); } } diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs new file mode 100644 index 0000000000..6b87d93951 --- /dev/null +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; + +namespace osu.Game.Rulesets.Pippidon +{ + public class PippidonRulesetIcon : Sprite + { + private readonly Ruleset ruleset; + + public PippidonRulesetIcon(Ruleset ruleset) + { + this.ruleset = ruleset; + + Margin = new MarginPadding { Top = 3 }; + } + + [BackgroundDependencyLoader] + private void load(IRenderer renderer) + { + Texture = new TextureStore(renderer, new TextureLoaderStore(ruleset.CreateResourceStore()), false).Get("Textures/coin"); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index 4e6493ba18..4b6f364831 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -9,7 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; -using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Textures; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs index f185c8b99d..41e149ea2f 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs @@ -9,7 +9,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Rulesets.UI.Scrolling; diff --git a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs index 7c4ab2f5f4..6209be89ff 100644 --- a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs @@ -6,7 +6,8 @@ using System.Diagnostics; using System.Linq; using Moq; using NUnit.Framework; -using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; @@ -19,6 +20,9 @@ namespace osu.Game.Rulesets.Osu.Tests [HeadlessTest] public class LegacyMainCirclePieceTest : OsuTestScene { + [Resolved] + private IRenderer renderer { get; set; } = null!; + private static readonly object?[][] texture_priority_cases = { // default priority lookup @@ -76,7 +80,12 @@ namespace osu.Game.Rulesets.Osu.Tests skin.Setup(s => s.GetTexture(It.IsAny())).CallBase(); skin.Setup(s => s.GetTexture(It.IsIn(textureFilenames), It.IsAny(), It.IsAny())) - .Returns((string componentName, WrapMode _, WrapMode _) => new Texture(1, 1) { AssetName = componentName }); + .Returns((string componentName, WrapMode _, WrapMode _) => + { + var tex = renderer.CreateTexture(1, 1); + tex.AssetName = componentName; + return tex; + }); Child = new DependencyProvidingContainer { @@ -84,7 +93,7 @@ namespace osu.Game.Rulesets.Osu.Tests Child = piece = new TestLegacyMainCirclePiece(priorityLookup), }; - var sprites = this.ChildrenOfType().Where(s => s.Texture.AssetName != null).DistinctBy(s => s.Texture.AssetName).ToArray(); + var sprites = this.ChildrenOfType().DistinctBy(s => s.Texture.AssetName).ToArray(); Debug.Assert(sprites.Length <= 2); }); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs index c8d2d07be5..04ad0f7008 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs @@ -11,7 +11,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Textures; using osu.Framework.Testing.Input; using osu.Game.Audio; @@ -82,6 +82,9 @@ namespace osu.Game.Rulesets.Osu.Tests [Cached(typeof(ISkinSource))] private class LegacySkinContainer : Container, ISkinSource { + [Resolved] + private IRenderer renderer { get; set; } + private readonly bool disjoint; public LegacySkinContainer(bool disjoint) @@ -98,14 +101,14 @@ namespace osu.Game.Rulesets.Osu.Tests switch (componentName) { case "cursortrail": - var tex = new Texture(Texture.WhitePixel.TextureGL); + var tex = new Texture(renderer.WhitePixel); if (disjoint) tex.ScaleAdjust = 1 / 25f; return tex; case "cursormiddle": - return disjoint ? null : Texture.WhitePixel; + return disjoint ? null : renderer.WhitePixel; } return null; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs index 2edacee9ac..360815afbf 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs @@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; using osu.Framework.Input; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs index dd110662b2..036f90b962 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs @@ -12,7 +12,6 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Timing; diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 95db785840..6a25663542 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -68,8 +68,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor } [BackgroundDependencyLoader] - private void load(ShaderManager shaders) + private void load(IRenderer renderer, ShaderManager shaders) { + texture ??= renderer.WhitePixel; shader = shaders.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE); } @@ -79,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor resetTime(); } - private Texture texture = Texture.WhitePixel; + private Texture texture; public Texture Texture { @@ -264,7 +265,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor shader.GetUniform("g_FadeClock").UpdateValue(ref time); shader.GetUniform("g_FadeExponent").UpdateValue(ref fadeExponent); - texture.TextureGL.Bind(); + texture.Bind(); RectangleF textureRect = texture.GetTextureRect(); diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs index 80f139a66b..d3bf70e603 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs @@ -6,8 +6,8 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; using osu.Game.Graphics; using osu.Game.Skinning; using osuTK.Graphics; diff --git a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs index af5588f509..f91e83a556 100644 --- a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs @@ -9,6 +9,7 @@ using System.Linq; using JetBrains.Annotations; using Moq; using NUnit.Framework; +using osu.Framework.Graphics.Rendering.Dummy; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; @@ -55,7 +56,7 @@ namespace osu.Game.Tests.Editing.Checks [Test] public void TestAcceptable() { - var context = getContext(new Texture(1920, 1080)); + var context = getContext(new DummyRenderer().CreateTexture(1920, 1080)); Assert.That(check.Run(context), Is.Empty); } @@ -63,7 +64,7 @@ namespace osu.Game.Tests.Editing.Checks [Test] public void TestTooHighResolution() { - var context = getContext(new Texture(3840, 2160)); + var context = getContext(new DummyRenderer().CreateTexture(3840, 2160)); var issues = check.Run(context).ToList(); @@ -74,7 +75,7 @@ namespace osu.Game.Tests.Editing.Checks [Test] public void TestLowResolution() { - var context = getContext(new Texture(640, 480)); + var context = getContext(new DummyRenderer().CreateTexture(640, 480)); var issues = check.Run(context).ToList(); @@ -85,7 +86,7 @@ namespace osu.Game.Tests.Editing.Checks [Test] public void TestTooLowResolution() { - var context = getContext(new Texture(100, 100)); + var context = getContext(new DummyRenderer().CreateTexture(100, 100)); var issues = check.Run(context).ToList(); @@ -96,7 +97,7 @@ namespace osu.Game.Tests.Editing.Checks [Test] public void TestTooUncompressed() { - var context = getContext(new Texture(1920, 1080), new MemoryStream(new byte[1024 * 1024 * 3])); + var context = getContext(new DummyRenderer().CreateTexture(1920, 1080), new MemoryStream(new byte[1024 * 1024 * 3])); var issues = check.Run(context).ToList(); @@ -107,7 +108,7 @@ namespace osu.Game.Tests.Editing.Checks [Test] public void TestStreamClosed() { - var background = new Texture(1920, 1080); + var background = new DummyRenderer().CreateTexture(1920, 1080); var stream = new Mock(new byte[1024 * 1024]); var context = getContext(background, stream.Object); diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs index 1e10fbb2bc..9701a32951 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Game.Audio; diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index a432cc9648..f05244ab88 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -11,8 +11,10 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Configuration; @@ -36,6 +38,9 @@ namespace osu.Game.Tests.Gameplay [Resolved] private OsuConfigManager config { get; set; } + [Resolved] + private GameHost host { get; set; } + [Test] public void TestRetrieveTopLevelSample() { @@ -202,6 +207,7 @@ namespace osu.Game.Tests.Gameplay #region IResourceStorageProvider + public IRenderer Renderer => host.Renderer; public AudioManager AudioManager => Audio; public IResourceStore Files => null; public new IResourceStore Resources => base.Resources; diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs index e21a3e636f..6297d9cdc7 100644 --- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs @@ -11,7 +11,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; -using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Framework.Timing; @@ -27,6 +27,9 @@ namespace osu.Game.Tests.NonVisual.Skinning private const string animation_name = "animation"; private const int frame_count = 6; + [Resolved] + private IRenderer renderer { get; set; } + [Cached(typeof(IAnimationTimeReference))] private TestAnimationTimeReference animationTimeReference = new TestAnimationTimeReference(); @@ -35,9 +38,12 @@ namespace osu.Game.Tests.NonVisual.Skinning [Test] public void TestAnimationTimeReferenceChange() { - ISkin skin = new TestSkin(); + AddStep("get animation", () => + { + ISkin skin = new TestSkin(renderer); + Add(animation = (TextureAnimation)skin.GetAnimation(animation_name, true, false)); + }); - AddStep("get animation", () => Add(animation = (TextureAnimation)skin.GetAnimation(animation_name, true, false))); AddAssert("frame count correct", () => animation.FrameCount == frame_count); assertPlaybackPosition(0); @@ -55,9 +61,16 @@ namespace osu.Game.Tests.NonVisual.Skinning { private static readonly string[] lookup_names = Enumerable.Range(0, frame_count).Select(frame => $"{animation_name}-{frame}").ToArray(); + private readonly IRenderer renderer; + + public TestSkin(IRenderer renderer) + { + this.renderer = renderer; + } + public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) { - return lookup_names.Contains(componentName) ? Texture.WhitePixel : null; + return lookup_names.Contains(componentName) ? renderer.WhitePixel : null; } public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException(); diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs index 22aa78838a..ca0d4d3cf3 100644 --- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinTextureFallbackTest.cs @@ -11,6 +11,8 @@ using System.Threading; using System.Threading.Tasks; using NUnit.Framework; using osu.Framework.Audio; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Rendering.Dummy; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Game.Database; @@ -141,6 +143,7 @@ namespace osu.Game.Tests.NonVisual.Skinning this.textureStore = textureStore; } + public IRenderer Renderer => new DummyRenderer(); public AudioManager AudioManager => null; public IResourceStore Files => null; public IResourceStore Resources => null; diff --git a/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs b/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs index 42d65ead2b..29534348dc 100644 --- a/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs +++ b/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs @@ -15,7 +15,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Shapes; @@ -79,7 +78,7 @@ namespace osu.Game.Tests.Rulesets { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.CacheAs(ParentTextureStore = new TestTextureStore()); + dependencies.CacheAs(ParentTextureStore = new TestTextureStore(parent.Get().Renderer)); dependencies.CacheAs(ParentSampleStore = new TestSampleStore()); dependencies.CacheAs(ParentShaderManager = new TestShaderManager(parent.Get().Renderer)); @@ -97,6 +96,11 @@ namespace osu.Game.Tests.Rulesets private class TestTextureStore : TextureStore { + public TestTextureStore(IRenderer renderer) + : base(renderer) + { + } + public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT) => null; public bool IsDisposed { get; private set; } diff --git a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs index f1ecd3b526..320373699d 100644 --- a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs +++ b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs @@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Game.Audio; diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 53639deac3..c7eb334f25 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -7,7 +7,6 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Game.Audio; diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs index 1493c10969..004e253c1f 100644 --- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs +++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs @@ -10,7 +10,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Game.Audio; diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index 5452bfc939..b0c26f7280 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -13,7 +13,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Game.Audio; diff --git a/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs b/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs index 1229b63a90..f7c88643fe 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs @@ -6,10 +6,11 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Game.Audio; @@ -21,6 +22,9 @@ namespace osu.Game.Tests.Skins [HeadlessTest] public class TestSceneSkinProvidingContainer : OsuTestScene { + [Resolved] + private IRenderer renderer { get; set; } + /// /// Ensures that the first inserted skin after resetting (via source change) /// is always prioritised over others when providing the same resource. @@ -35,7 +39,7 @@ namespace osu.Game.Tests.Skins { var sources = new List(); for (int i = 0; i < 10; i++) - sources.Add(new TestSkin()); + sources.Add(new TestSkin(renderer)); mostPrioritisedSource = sources.First(); @@ -76,12 +80,19 @@ namespace osu.Game.Tests.Skins { public const string TEXTURE_NAME = "virtual-texture"; + private readonly IRenderer renderer; + + public TestSkin(IRenderer renderer) + { + this.renderer = renderer; + } + public Drawable GetDrawableComponent(ISkinComponent component) => throw new System.NotImplementedException(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) { if (componentName == TEXTURE_NAME) - return Texture.WhitePixel; + return renderer.WhitePixel; return null; } diff --git a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs b/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs index 5aaaca2b2c..d9dfa1d876 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Graphics; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Textures; using osu.Framework.Screens; using osu.Framework.Testing; @@ -43,6 +44,9 @@ namespace osu.Game.Tests.Visual.Background [Resolved] private OsuConfigManager config { get; set; } + [Resolved] + private IRenderer renderer { get; set; } + [SetUpSteps] public void SetUpSteps() { @@ -245,7 +249,7 @@ namespace osu.Game.Tests.Visual.Background Id = API.LocalUser.Value.Id + 1, }); - private WorkingBeatmap createTestWorkingBeatmapWithUniqueBackground() => new UniqueBackgroundTestWorkingBeatmap(Audio); + private WorkingBeatmap createTestWorkingBeatmapWithUniqueBackground() => new UniqueBackgroundTestWorkingBeatmap(renderer, Audio); private WorkingBeatmap createTestWorkingBeatmapWithStoryboard() => new TestWorkingBeatmapWithStoryboard(Audio); private class TestBackgroundScreenDefault : BackgroundScreenDefault @@ -274,12 +278,15 @@ namespace osu.Game.Tests.Visual.Background private class UniqueBackgroundTestWorkingBeatmap : TestWorkingBeatmap { - public UniqueBackgroundTestWorkingBeatmap(AudioManager audioManager) + private readonly IRenderer renderer; + + public UniqueBackgroundTestWorkingBeatmap(IRenderer renderer, AudioManager audioManager) : base(new Beatmap(), null, audioManager) { + this.renderer = renderer; } - protected override Texture GetBackground() => new Texture(1, 1); + protected override Texture GetBackground() => renderer.CreateTexture(1, 1); } private class TestWorkingBeatmapWithStoryboard : TestWorkingBeatmap diff --git a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs index a44ab41d03..72171ff506 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs @@ -10,7 +10,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Textures; using osu.Game.Configuration; using osu.Game.Graphics.Backgrounds; @@ -28,11 +28,9 @@ namespace osu.Game.Tests.Visual.Background [Resolved] private SessionStatics statics { get; set; } - [Cached(typeof(LargeTextureStore))] - private LookupLoggingTextureStore textureStore = new LookupLoggingTextureStore(); - private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; + private LookupLoggingTextureStore textureStore; private SeasonalBackgroundLoader backgroundLoader; private Container backgroundContainer; @@ -46,14 +44,22 @@ namespace osu.Game.Tests.Visual.Background }; [BackgroundDependencyLoader] - private void load(LargeTextureStore wrappedStore) + private void load(IRenderer renderer, LargeTextureStore wrappedStore) { + textureStore = new LookupLoggingTextureStore(renderer); textureStore.AddStore(wrappedStore); - Add(backgroundContainer = new Container + Child = new DependencyProvidingContainer { - RelativeSizeAxes = Axes.Both - }); + CachedDependencies = new (Type, object)[] + { + (typeof(LargeTextureStore), textureStore) + }, + Child = backgroundContainer = new Container + { + RelativeSizeAxes = Axes.Both + } + }; } [SetUp] @@ -193,6 +199,11 @@ namespace osu.Game.Tests.Visual.Background { public List PerformedLookups { get; } = new List(); + public LookupLoggingTextureStore(IRenderer renderer) + : base(renderer) + { + } + public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT) { PerformedLookups.Add(name); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs index 16593effd6..d4fba76c37 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs @@ -13,7 +13,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; using osu.Game.Audio; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs index 36b07043dc..0ba112ec40 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs @@ -13,7 +13,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Game.Audio; diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs index df44f01629..adb5f8c433 100644 --- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs +++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs @@ -9,6 +9,8 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Audio; using osu.Framework.Audio.Track; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Rendering.Dummy; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Framework.Lists; @@ -56,7 +58,7 @@ namespace osu.Game.Beatmaps this.resources = resources; this.host = host; this.files = files; - largeTextureStore = new LargeTextureStore(host?.CreateTextureLoaderStore(files)); + largeTextureStore = new LargeTextureStore(host?.Renderer ?? new DummyRenderer(), host?.CreateTextureLoaderStore(files)); this.trackStore = trackStore; } @@ -110,6 +112,7 @@ namespace osu.Game.Beatmaps TextureStore IBeatmapResourceProvider.LargeTextureStore => largeTextureStore; ITrackStore IBeatmapResourceProvider.Tracks => trackStore; + IRenderer IStorageResourceProvider.Renderer => host?.Renderer ?? new DummyRenderer(); AudioManager IStorageResourceProvider.AudioManager => audioManager; RealmAccess IStorageResourceProvider.RealmAccess => null; IResourceStore IStorageResourceProvider.Files => files; diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 0df90fd770..ad35c00d2b 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -87,7 +87,7 @@ namespace osu.Game.Graphics.Backgrounds private Random stableRandom; private IShader shader; - private readonly Texture texture; + private Texture texture; /// /// Construct a new triangle visualisation. @@ -97,13 +97,12 @@ namespace osu.Game.Graphics.Backgrounds { if (seed != null) stableRandom = new Random(seed.Value); - - texture = Texture.WhitePixel; } [BackgroundDependencyLoader] - private void load(ShaderManager shaders) + private void load(IRenderer renderer, ShaderManager shaders) { + texture = renderer.WhitePixel; shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); } @@ -296,7 +295,7 @@ namespace osu.Game.Graphics.Backgrounds ColourInfo colourInfo = DrawColourInfo.Colour; colourInfo.ApplyChild(particle.Colour); - DrawTriangle( + renderer.DrawTriangle( texture, triangle, colourInfo, diff --git a/osu.Game/Graphics/ParticleExplosion.cs b/osu.Game/Graphics/ParticleExplosion.cs index 5c59b4efb2..a902c8426f 100644 --- a/osu.Game/Graphics/ParticleExplosion.cs +++ b/osu.Game/Graphics/ParticleExplosion.cs @@ -112,7 +112,7 @@ namespace osu.Game.Graphics Vector2Extensions.Transform(rect.BottomRight, DrawInfo.Matrix) ); - DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), + renderer.DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), inflationPercentage: new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height), textureCoords: TextureCoords); } diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 5008f52a5a..41a7d82e74 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -136,7 +136,7 @@ namespace osu.Game.Graphics transformPosition(rect.BottomRight, rect.Centre, angle) ); - DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), + renderer.DrawQuad(Texture, quad, DrawColourInfo.Colour.MultiplyAlpha(alpha), inflationPercentage: new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height), textureCoords: TextureCoords); } diff --git a/osu.Game/IO/IStorageResourceProvider.cs b/osu.Game/IO/IStorageResourceProvider.cs index 1cb6509cac..ae0dbb963c 100644 --- a/osu.Game/IO/IStorageResourceProvider.cs +++ b/osu.Game/IO/IStorageResourceProvider.cs @@ -4,6 +4,7 @@ #nullable disable using osu.Framework.Audio; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Game.Database; @@ -12,6 +13,11 @@ namespace osu.Game.IO { public interface IStorageResourceProvider { + /// + /// The game renderer. + /// + IRenderer Renderer { get; } + /// /// Retrieve the game-wide audio manager. /// diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 97d15ae6ad..19db310668 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -248,7 +248,7 @@ namespace osu.Game dependencies.CacheAs(Storage); - var largeStore = new LargeTextureStore(Host.CreateTextureLoaderStore(new NamespacedResourceStore(Resources, @"Textures"))); + var largeStore = new LargeTextureStore(Host.Renderer, Host.CreateTextureLoaderStore(new NamespacedResourceStore(Resources, @"Textures"))); largeStore.AddTextureSource(Host.CreateTextureLoaderStore(new OnlineStore())); dependencies.Cache(largeStore); diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 8e433ccb97..39d0c5c3d1 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps.Timing; using osu.Game.Configuration; using osu.Game.Graphics; @@ -250,7 +249,7 @@ namespace osu.Game.Rulesets.Mods shader.GetUniform("flashlightSize").UpdateValue(ref flashlightSize); shader.GetUniform("flashlightDim").UpdateValue(ref flashlightDim); - DrawQuad(Texture.WhitePixel, screenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: addAction); + renderer.DrawQuad(renderer.WhitePixel, screenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: addAction); shader.Unbind(); } diff --git a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs index bd36255c02..cffbf2c9a1 100644 --- a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs +++ b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs @@ -12,7 +12,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; @@ -58,8 +57,8 @@ namespace osu.Game.Rulesets.UI { var host = parent.Get(); - TextureStore = new TextureStore(parent.Get().CreateTextureLoaderStore(new NamespacedResourceStore(resources, @"Textures"))); - CacheAs(TextureStore = new FallbackTextureStore(TextureStore, parent.Get())); + TextureStore = new TextureStore(host.Renderer, parent.Get().CreateTextureLoaderStore(new NamespacedResourceStore(resources, @"Textures"))); + CacheAs(TextureStore = new FallbackTextureStore(host.Renderer, TextureStore, parent.Get())); SampleStore = parent.Get().GetSampleStore(new NamespacedResourceStore(resources, @"Samples")); SampleStore.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY; @@ -173,7 +172,8 @@ namespace osu.Game.Rulesets.UI private readonly TextureStore primary; private readonly TextureStore fallback; - public FallbackTextureStore(TextureStore primary, TextureStore fallback) + public FallbackTextureStore(IRenderer renderer, TextureStore primary, TextureStore fallback) + : base(renderer) { this.primary = primary; this.fallback = fallback; diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 475c894b30..a106a60379 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -8,7 +8,6 @@ using System.Linq; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Game.Audio; using osu.Game.Skinning; diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 71f9799ed0..a216edc9b4 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -77,11 +77,10 @@ namespace osu.Game.Screens.Menu private readonly float[] frequencyAmplitudes = new float[256]; private IShader shader; - private readonly Texture texture; + private Texture texture; public LogoVisualisation() { - texture = Texture.WhitePixel; Blending = BlendingParameters.Additive; } @@ -93,9 +92,10 @@ namespace osu.Game.Screens.Menu } [BackgroundDependencyLoader] - private void load(ShaderManager shaders, IBindable beatmap) + private void load(IRenderer renderer, ShaderManager shaders, IBindable beatmap) { this.beatmap.BindTo(beatmap); + texture = renderer.WhitePixel; shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); } @@ -239,7 +239,7 @@ namespace osu.Game.Screens.Menu Vector2Extensions.Transform(barPosition + bottomOffset + amplitudeOffset, DrawInfo.Matrix) ); - DrawQuad( + renderer.DrawQuad( texture, rectangle, colourInfo, diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index 7d217dd956..32415e8212 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -9,7 +9,6 @@ using JetBrains.Annotations; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Audio; diff --git a/osu.Game/Skinning/IAnimationTimeReference.cs b/osu.Game/Skinning/IAnimationTimeReference.cs index dcb9e9bbb9..a65d15d24b 100644 --- a/osu.Game/Skinning/IAnimationTimeReference.cs +++ b/osu.Game/Skinning/IAnimationTimeReference.cs @@ -5,7 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Textures; using osu.Framework.Timing; namespace osu.Game.Skinning diff --git a/osu.Game/Skinning/ISkin.cs b/osu.Game/Skinning/ISkin.cs index 431fc1c0b8..c093dc2f32 100644 --- a/osu.Game/Skinning/ISkin.cs +++ b/osu.Game/Skinning/ISkin.cs @@ -4,7 +4,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Game.Audio; diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 15d4965a1d..1e096702b3 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -10,7 +10,6 @@ using JetBrains.Annotations; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Game.Audio; diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index 5a537dd57d..8765882af2 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -9,7 +9,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using static osu.Game.Skinning.SkinConfiguration; diff --git a/osu.Game/Skinning/LegacySkinTransformer.cs b/osu.Game/Skinning/LegacySkinTransformer.cs index da7da759fc..8f2526db37 100644 --- a/osu.Game/Skinning/LegacySkinTransformer.cs +++ b/osu.Game/Skinning/LegacySkinTransformer.cs @@ -8,7 +8,6 @@ using JetBrains.Annotations; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Game.Audio; using osu.Game.Rulesets.Objects.Legacy; diff --git a/osu.Game/Skinning/ResourceStoreBackedSkin.cs b/osu.Game/Skinning/ResourceStoreBackedSkin.cs index 597eef99d4..efdbb0a207 100644 --- a/osu.Game/Skinning/ResourceStoreBackedSkin.cs +++ b/osu.Game/Skinning/ResourceStoreBackedSkin.cs @@ -6,7 +6,6 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Framework.Platform; @@ -24,7 +23,7 @@ namespace osu.Game.Skinning public ResourceStoreBackedSkin(IResourceStore resources, GameHost host, AudioManager audio) { - textures = new TextureStore(host.CreateTextureLoaderStore(new NamespacedResourceStore(resources, @"Textures"))); + textures = new TextureStore(host.Renderer, host.CreateTextureLoaderStore(new NamespacedResourceStore(resources, @"Textures"))); samples = audio.GetSampleStore(new NamespacedResourceStore(resources, @"Samples")); } diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 7d93aeb897..7fe7040965 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -11,7 +11,6 @@ using Newtonsoft.Json; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Framework.Logging; @@ -76,7 +75,7 @@ namespace osu.Game.Skinning samples.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY; Samples = samples; - Textures = new TextureStore(resources.CreateTextureLoaderStore(storage)); + Textures = new TextureStore(resources.Renderer, resources.CreateTextureLoaderStore(storage)); } else { diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index dd35f83434..f677cebe51 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -14,7 +14,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Framework.Platform; @@ -249,6 +249,7 @@ namespace osu.Game.Skinning #region IResourceStorageProvider + IRenderer IStorageResourceProvider.Renderer => host.Renderer; AudioManager IStorageResourceProvider.AudioManager => audio; IResourceStore IStorageResourceProvider.Resources => resources; IResourceStore IStorageResourceProvider.Files => userFiles; diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index e447570931..42c39e581f 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -12,7 +12,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; using osu.Framework.Graphics.Textures; using osu.Game.Audio; diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index be98ca9a46..8343f14050 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -90,7 +90,7 @@ namespace osu.Game.Storyboards.Drawables if (clock != null) Clock = clock; - dependencies.Cache(new TextureStore(host.CreateTextureLoaderStore(new RealmFileStore(realm, host.Storage).Store), false, scaleAdjust: 1)); + dependencies.Cache(new TextureStore(host.Renderer, host.CreateTextureLoaderStore(new RealmFileStore(realm, host.Storage).Store), false, scaleAdjust: 1)); foreach (var layer in Storyboard.Layers) { diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index 3ed3bb65c9..c97eec116c 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -12,8 +12,10 @@ using System.Threading; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Framework.Platform; using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Beatmaps; @@ -39,6 +41,9 @@ namespace osu.Game.Tests.Beatmaps [Resolved] private RulesetStore rulesetStore { get; set; } + [Resolved] + private GameHost host { get; set; } + private readonly SkinInfo userSkinInfo = new SkinInfo(); private readonly BeatmapInfo beatmapInfo = new BeatmapInfo @@ -123,6 +128,7 @@ namespace osu.Game.Tests.Beatmaps #region IResourceStorageProvider + public IRenderer Renderer => host.Renderer; public AudioManager AudioManager => Audio; public IResourceStore Files => userSkinResourceStore; public new IResourceStore Resources => base.Resources; @@ -212,6 +218,7 @@ namespace osu.Game.Tests.Beatmaps protected internal override ISkin GetSkin() => new LegacyBeatmapSkin(skinBeatmapInfo, this); + public IRenderer Renderer => resources.Renderer; public AudioManager AudioManager => resources.AudioManager; public IResourceStore Files { get; } diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 2e5d0534f6..ffdde782a5 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -11,7 +11,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; @@ -159,6 +159,7 @@ namespace osu.Game.Tests.Visual #region IResourceStorageProvider + public IRenderer Renderer => host.Renderer; public AudioManager AudioManager => Audio; public IResourceStore Files => null; public new IResourceStore Resources => base.Resources; From 5a1c05918f08e24738ba8edb55eb90e59d97f0f6 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 2 Aug 2022 20:18:45 +0900 Subject: [PATCH 0241/2686] Fix test failures --- .../LegacyMainCirclePieceTest.cs | 2 +- .../TestSceneCursorTrail.cs | 14 ++++++++------ .../TestSceneSeasonalBackgroundLoader.cs | 15 ++++++++++++--- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs index 6209be89ff..b6c8103e3c 100644 --- a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Osu.Tests Child = piece = new TestLegacyMainCirclePiece(priorityLookup), }; - var sprites = this.ChildrenOfType().DistinctBy(s => s.Texture.AssetName).ToArray(); + var sprites = this.ChildrenOfType().Where(s => !string.IsNullOrEmpty(s.Texture.AssetName)).DistinctBy(s => s.Texture.AssetName).ToArray(); Debug.Assert(sprites.Length <= 2); }); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs index 04ad0f7008..d3e70a0a01 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs @@ -25,6 +25,9 @@ namespace osu.Game.Rulesets.Osu.Tests { public class TestSceneCursorTrail : OsuTestScene { + [Resolved] + private IRenderer renderer { get; set; } + [Test] public void TestSmoothCursorTrail() { @@ -44,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Tests { createTest(() => { - var skinContainer = new LegacySkinContainer(false); + var skinContainer = new LegacySkinContainer(renderer, false); var legacyCursorTrail = new LegacyCursorTrail(skinContainer); skinContainer.Child = legacyCursorTrail; @@ -58,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Tests { createTest(() => { - var skinContainer = new LegacySkinContainer(true); + var skinContainer = new LegacySkinContainer(renderer, true); var legacyCursorTrail = new LegacyCursorTrail(skinContainer); skinContainer.Child = legacyCursorTrail; @@ -82,13 +85,12 @@ namespace osu.Game.Rulesets.Osu.Tests [Cached(typeof(ISkinSource))] private class LegacySkinContainer : Container, ISkinSource { - [Resolved] - private IRenderer renderer { get; set; } - + private readonly IRenderer renderer; private readonly bool disjoint; - public LegacySkinContainer(bool disjoint) + public LegacySkinContainer(IRenderer renderer, bool disjoint) { + this.renderer = renderer; this.disjoint = disjoint; RelativeSizeAxes = Axes.Both; diff --git a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs index 72171ff506..cce7ae1922 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs @@ -43,10 +43,19 @@ namespace osu.Game.Tests.Visual.Background "Backgrounds/bg3" }; - [BackgroundDependencyLoader] - private void load(IRenderer renderer, LargeTextureStore wrappedStore) + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + textureStore = new LookupLoggingTextureStore(dependencies.Get()); + dependencies.CacheAs(typeof(LargeTextureStore), textureStore); + + return dependencies; + } + + [BackgroundDependencyLoader] + private void load(LargeTextureStore wrappedStore) { - textureStore = new LookupLoggingTextureStore(renderer); textureStore.AddStore(wrappedStore); Child = new DependencyProvidingContainer From de186f67e0880aabc8cfb29e2bf019a9e8bd14db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 22:02:30 +0900 Subject: [PATCH 0242/2686] Limit metadata updates to once per frame --- osu.Game/Screens/Edit/Setup/MetadataSection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/MetadataSection.cs b/osu.Game/Screens/Edit/Setup/MetadataSection.cs index 33cc88da0a..928e5bc3b6 100644 --- a/osu.Game/Screens/Edit/Setup/MetadataSection.cs +++ b/osu.Game/Screens/Edit/Setup/MetadataSection.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Edit.Setup target.Current.Value = value; updateReadOnlyState(); - updateMetadata(); + Scheduler.AddOnce(updateMetadata); } private void updateReadOnlyState() @@ -102,7 +102,7 @@ namespace osu.Game.Screens.Edit.Setup // for now, update on commit rather than making BeatmapMetadata bindables. // after switching database engines we can reconsider if switching to bindables is a good direction. - updateMetadata(); + Scheduler.AddOnce(updateMetadata); } private void updateMetadata() From 78cc28d75f49eb7f7b6007278169d39473e37272 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Tue, 2 Aug 2022 22:23:54 +0800 Subject: [PATCH 0243/2686] Remove nullable disable annotation and fix the api broken. --- osu.Desktop/DiscordRichPresence.cs | 14 ++++++-------- .../LegacyIpcDifficultyCalculationRequest.cs | 2 -- .../LegacyIpcDifficultyCalculationResponse.cs | 2 -- osu.Desktop/LegacyIpc/LegacyIpcMessage.cs | 2 -- osu.Desktop/Program.cs | 4 +--- osu.Desktop/Security/ElevatedPrivilegesChecker.cs | 4 +--- osu.Desktop/Updater/SquirrelUpdateManager.cs | 12 +++++------- osu.Desktop/Windows/GameplayWinKeyBlocker.cs | 10 ++++------ osu.Desktop/Windows/WindowsKey.cs | 4 +--- 9 files changed, 18 insertions(+), 36 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index d0b6953c30..13c6440599 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.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. -#nullable disable - using System; using System.Text; using DiscordRPC; @@ -26,15 +24,15 @@ namespace osu.Desktop { private const string client_id = "367827983903490050"; - private DiscordRpcClient client; + private DiscordRpcClient client = null!; [Resolved] - private IBindable ruleset { get; set; } + private IBindable ruleset { get; set; } = null!; - private IBindable user; + private IBindable user = null!; [Resolved] - private IAPIProvider api { get; set; } + private IAPIProvider api { get; set; } = null!; private readonly IBindable status = new Bindable(); private readonly IBindable activity = new Bindable(); @@ -130,7 +128,7 @@ namespace osu.Desktop presence.Assets.LargeImageText = string.Empty; else { - if (user.Value.RulesetsStatistics != null && user.Value.RulesetsStatistics.TryGetValue(ruleset.Value.ShortName, out UserStatistics statistics)) + if (user.Value.RulesetsStatistics != null && user.Value.RulesetsStatistics.TryGetValue(ruleset.Value.ShortName, out UserStatistics? statistics)) presence.Assets.LargeImageText = $"{user.Value.Username}" + (statistics.GlobalRank > 0 ? $" (rank #{statistics.GlobalRank:N0})" : string.Empty); else presence.Assets.LargeImageText = $"{user.Value.Username}" + (user.Value.Statistics?.GlobalRank > 0 ? $" (rank #{user.Value.Statistics.GlobalRank:N0})" : string.Empty); @@ -164,7 +162,7 @@ namespace osu.Desktop }); } - private IBeatmapInfo getBeatmap(UserActivity activity) + private IBeatmapInfo? getBeatmap(UserActivity activity) { switch (activity) { diff --git a/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs b/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs index 7b0bd69363..d6ef390a8f 100644 --- a/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs +++ b/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.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. -#nullable disable - namespace osu.Desktop.LegacyIpc { /// diff --git a/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationResponse.cs b/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationResponse.cs index 6d36cbc4b6..7b9fae5797 100644 --- a/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationResponse.cs +++ b/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationResponse.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. -#nullable disable - namespace osu.Desktop.LegacyIpc { /// diff --git a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs index 4df477191d..0fa60e2068 100644 --- a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs +++ b/osu.Desktop/LegacyIpc/LegacyIpcMessage.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. -#nullable disable - using osu.Framework.Platform; using Newtonsoft.Json.Linq; diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs index c7505e624c..5a1373e040 100644 --- a/osu.Desktop/Program.cs +++ b/osu.Desktop/Program.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. -#nullable disable - using System; using System.IO; using System.Runtime.Versioning; @@ -27,7 +25,7 @@ namespace osu.Desktop private const string base_game_name = @"osu"; #endif - private static LegacyTcpIpcProvider legacyIpc; + private static LegacyTcpIpcProvider? legacyIpc; [STAThread] public static void Main(string[] args) diff --git a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs index f0d95ba194..9959b24b35 100644 --- a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs +++ b/osu.Desktop/Security/ElevatedPrivilegesChecker.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. -#nullable disable - using System; using System.Security.Principal; using osu.Framework; @@ -21,7 +19,7 @@ namespace osu.Desktop.Security public class ElevatedPrivilegesChecker : Component { [Resolved] - private INotificationOverlay notifications { get; set; } + private INotificationOverlay notifications { get; set; } = null!; private bool elevated; diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index 4e5f8d37b1..64872de3f1 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.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. -#nullable disable - using System; using System.Runtime.Versioning; using System.Threading.Tasks; @@ -26,8 +24,8 @@ namespace osu.Desktop.Updater [SupportedOSPlatform("windows")] public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager { - private UpdateManager updateManager; - private INotificationOverlay notificationOverlay; + private UpdateManager? updateManager; + private INotificationOverlay notificationOverlay = null!; public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited(); @@ -50,12 +48,12 @@ namespace osu.Desktop.Updater protected override async Task PerformUpdateCheck() => await checkForUpdateAsync().ConfigureAwait(false); - private async Task checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null) + private async Task checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification? notification = null) { // should we schedule a retry on completion of this check? bool scheduleRecheck = true; - const string github_token = null; // TODO: populate. + const string? github_token = null; // TODO: populate. try { @@ -145,7 +143,7 @@ namespace osu.Desktop.Updater private class UpdateCompleteNotification : ProgressCompletionNotification { [Resolved] - private OsuGame game { get; set; } + private OsuGame game { get; set; } = null!; public UpdateCompleteNotification(SquirrelUpdateManager updateManager) { diff --git a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs index 0cb4ba9c04..284d25306d 100644 --- a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs +++ b/osu.Desktop/Windows/GameplayWinKeyBlocker.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -14,12 +12,12 @@ namespace osu.Desktop.Windows { public class GameplayWinKeyBlocker : Component { - private Bindable disableWinKey; - private IBindable localUserPlaying; - private IBindable isActive; + private Bindable disableWinKey = null!; + private IBindable localUserPlaying = null!; + private IBindable isActive = null!; [Resolved] - private GameHost host { get; set; } + private GameHost host { get; set; } = null!; [BackgroundDependencyLoader] private void load(ILocalUserPlayInfo localUserInfo, OsuConfigManager config) diff --git a/osu.Desktop/Windows/WindowsKey.cs b/osu.Desktop/Windows/WindowsKey.cs index c69cce6200..1051e61f2f 100644 --- a/osu.Desktop/Windows/WindowsKey.cs +++ b/osu.Desktop/Windows/WindowsKey.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. -#nullable disable - using System; using System.Runtime.InteropServices; @@ -21,7 +19,7 @@ namespace osu.Desktop.Windows private const int wm_syskeyup = 261; //Resharper disable once NotAccessedField.Local - private static LowLevelKeyboardProcDelegate keyboardHookDelegate; // keeping a reference alive for the GC + private static LowLevelKeyboardProcDelegate? keyboardHookDelegate; // keeping a reference alive for the GC private static IntPtr keyHook; [StructLayout(LayoutKind.Explicit)] From 11a4bb58335a15b236a3f12c6bd44982a9ef6d20 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Tue, 2 Aug 2022 22:24:22 +0800 Subject: [PATCH 0244/2686] Prevent return the null value. --- osu.Desktop/DiscordRichPresence.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 13c6440599..9cf68d88d9 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -181,10 +181,10 @@ namespace osu.Desktop switch (activity) { case UserActivity.InGame game: - return game.BeatmapInfo.ToString(); + return game.BeatmapInfo.ToString() ?? string.Empty; case UserActivity.Editing edit: - return edit.BeatmapInfo.ToString(); + return edit.BeatmapInfo.ToString() ?? string.Empty; case UserActivity.InLobby lobby: return privacyMode.Value == DiscordRichPresenceMode.Limited ? string.Empty : lobby.Room.Name.Value; From 13b2441c5145504b21c3e8038f0f7c38763b6670 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Tue, 2 Aug 2022 22:29:27 +0800 Subject: [PATCH 0245/2686] give the field a default value. --- osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs | 2 +- osu.Desktop/LegacyIpc/LegacyIpcMessage.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs b/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs index d6ef390a8f..0ad68919a2 100644 --- a/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs +++ b/osu.Desktop/LegacyIpc/LegacyIpcDifficultyCalculationRequest.cs @@ -11,7 +11,7 @@ namespace osu.Desktop.LegacyIpc /// public class LegacyIpcDifficultyCalculationRequest { - public string BeatmapFile { get; set; } + public string BeatmapFile { get; set; } = string.Empty; public int RulesetId { get; set; } public int Mods { get; set; } } diff --git a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs index 0fa60e2068..865d1aa60c 100644 --- a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs +++ b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs @@ -46,7 +46,7 @@ namespace osu.Desktop.LegacyIpc public class Data { - public string MessageType { get; set; } + public string MessageType { get; set; } = string.Empty; public object MessageData { get; set; } } } From c8c2758d63fc13e6eedfeab60798fa4e6feff7a9 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Tue, 2 Aug 2022 23:02:14 +0800 Subject: [PATCH 0246/2686] give the object a default value(null). --- osu.Desktop/LegacyIpc/LegacyIpcMessage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs index 865d1aa60c..76eb6cdbd1 100644 --- a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs +++ b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs @@ -47,7 +47,7 @@ namespace osu.Desktop.LegacyIpc public class Data { public string MessageType { get; set; } = string.Empty; - public object MessageData { get; set; } + public object MessageData { get; set; } = default!; } } } From 8d175bc40201efeb34b907f2d3e950c1bcce2a1a Mon Sep 17 00:00:00 2001 From: andy840119 Date: Tue, 2 Aug 2022 23:13:50 +0800 Subject: [PATCH 0247/2686] Remove the null check. --- osu.Desktop/Updater/SquirrelUpdateManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index 64872de3f1..d53db6c516 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -152,7 +152,7 @@ namespace osu.Desktop.Updater Activated = () => { updateManager.PrepareUpdateAsync() - .ContinueWith(_ => updateManager.Schedule(() => game?.AttemptExit())); + .ContinueWith(_ => updateManager.Schedule(() => game.AttemptExit())); return true; }; } From 78a98cdb9c23ef9b0827d77adfc8a07c571308bd Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Tue, 2 Aug 2022 17:03:02 +0100 Subject: [PATCH 0248/2686] Prevent TextSprites inside SongProgressInfo from being stretched or flipped --- osu.Game/Extensions/DrawableExtensions.cs | 30 ++++++++++++++++--- .../Screens/Play/HUD/DefaultSongProgress.cs | 5 ++-- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 7 +++-- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index 5b92600cd1..46105218c5 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -82,11 +82,12 @@ namespace osu.Game.Extensions } /// - /// Keeps the drawable upright no matter the Rotation of its parents. + /// Keeps the drawable upright and prevents it from being scaled or flipped with its Parent. /// /// The drawable. - public static void KeepUpright(this Drawable drawable) + public static void KeepUprightAndUnstretched(this Drawable drawable) { + // Fix the rotation var result = drawable.Parent.DrawInfo; var scale = result.Matrix.ExtractScale(); var rotation = new Matrix3( @@ -94,9 +95,30 @@ namespace osu.Game.Extensions result.Matrix.Row1 / scale.Y, new Vector3(0.0f, 0.0f, 1.0f) ); - float angle = MathF.Atan2(rotation.M12, rotation.M11); + rotation.Invert(); + float angle = MathF.Atan(rotation.M12 / rotation.M11); angle *= (360 / (2 * MathF.PI)); - drawable.Rotation = -angle; + drawable.Rotation = angle; + + // Fix the scale (includes flip) + var containerOriginToSpaceOrigin = new Matrix3( + new Vector3(1.0f, 0.0f, 0.0f), + new Vector3(0.0f, 1.0f, 0.0f), + new Vector3(drawable.DrawSize.X / 2, drawable.DrawSize.Y / 2, 1.0f) + ); + var containerOriginToSpaceOriginInverse = containerOriginToSpaceOrigin; + containerOriginToSpaceOriginInverse.Invert(); + Matrix3 rotatedBack = (containerOriginToSpaceOriginInverse * (rotation * (containerOriginToSpaceOrigin * result.Matrix))); + + bool xFliped = rotation.M11 < 0; + bool yFliped = rotation.M22 < 0; + + var rotatedBackScale = rotatedBack.ExtractScale(); + + drawable.Scale = new Vector2( + (xFliped ? -1 : 1) / rotatedBackScale.X, + (yFliped ? -1 : 1) / rotatedBackScale.Y + ); } } diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index 96a6c56860..9ed99ab5f6 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Objects; @@ -16,7 +17,6 @@ namespace osu.Game.Screens.Play.HUD { public class DefaultSongProgress : SongProgress { - private const float info_height = 20; private const float bottom_bar_height = 5; private const float graph_height = SquareGraph.Column.WIDTH * 6; private const float handle_height = 18; @@ -67,7 +67,6 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, RelativeSizeAxes = Axes.X, - Height = info_height, }, graph = new SongProgressGraph { @@ -180,7 +179,7 @@ namespace osu.Game.Screens.Play.HUD protected override void Update() { base.Update(); - Height = bottom_bar_height + graph_height + handle_size.Y + info_height - graph.Y; + Height = bottom_bar_height + graph_height + handle_size.Y + info.Height - graph.Y; } private void updateBarVisibility() diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 520d0c661d..656498fc43 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -46,6 +46,7 @@ namespace osu.Game.Screens.Play.HUD if (clock != null) gameplayClock = clock; + AutoSizeAxes = Axes.Y; Children = new Drawable[] { new Container @@ -138,9 +139,9 @@ namespace osu.Game.Screens.Play.HUD private void keepTextSpritesUpright() { - timeCurrent.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUpright(timeCurrent); }; - progress.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUpright(timeCurrent); }; - timeLeft.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUpright(timeCurrent); }; + timeCurrent.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUprightAndUnstretched(timeCurrent); }; + progress.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUprightAndUnstretched(timeCurrent); }; + timeLeft.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUprightAndUnstretched(timeCurrent); }; } } From bc21a2ed569a443bd03fb5e230aebc280fa1bcc1 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Tue, 2 Aug 2022 17:41:17 +0100 Subject: [PATCH 0249/2686] Remove unnecessary using directive --- osu.Game/Screens/Play/HUD/DefaultSongProgress.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index 9ed99ab5f6..361e35ed45 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Objects; From 085080576a2ce78b0f0547fc45fa52f2ece37a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 22 Jul 2022 21:17:27 +0200 Subject: [PATCH 0250/2686] Add button for creating new mod presets --- .../UserInterface/ShearedToggleButton.cs | 6 +-- osu.Game/Overlays/Mods/AddPresetButton.cs | 38 +++++++++++++++++++ osu.Game/Overlays/Mods/ModPresetColumn.cs | 9 ++++- osu.Game/Overlays/Mods/ModSelectPanel.cs | 3 +- 4 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 osu.Game/Overlays/Mods/AddPresetButton.cs diff --git a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs index 0bbcb2b976..9ef09d799e 100644 --- a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs @@ -49,15 +49,15 @@ namespace osu.Game.Graphics.UserInterface Active.BindDisabledChanged(disabled => Action = disabled ? null : Active.Toggle, true); Active.BindValueChanged(_ => { - updateActiveState(); + UpdateActiveState(); playSample(); }); - updateActiveState(); + UpdateActiveState(); base.LoadComplete(); } - private void updateActiveState() + protected virtual void UpdateActiveState() { DarkerColour = Active.Value ? ColourProvider.Highlight1 : ColourProvider.Background3; LighterColour = Active.Value ? ColourProvider.Colour0 : ColourProvider.Background1; diff --git a/osu.Game/Overlays/Mods/AddPresetButton.cs b/osu.Game/Overlays/Mods/AddPresetButton.cs new file mode 100644 index 0000000000..e73ee3956a --- /dev/null +++ b/osu.Game/Overlays/Mods/AddPresetButton.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.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osuTK; + +namespace osu.Game.Overlays.Mods +{ + public class AddPresetButton : ShearedToggleButton + { + [Resolved] + private OsuColour colours { get; set; } = null!; + + public AddPresetButton() + : base(1) + { + RelativeSizeAxes = Axes.X; + Height = ModSelectPanel.HEIGHT; + + // shear will be applied at a higher level in `ModPresetColumn`. + Content.Shear = Vector2.Zero; + Padding = new MarginPadding(); + + Text = "+"; + TextSize = 30; + } + + protected override void UpdateActiveState() + { + DarkerColour = Active.Value ? colours.Orange1 : ColourProvider.Background3; + LighterColour = Active.Value ? colours.Orange0 : ColourProvider.Background1; + TextColour = Active.Value ? ColourProvider.Background6 : ColourProvider.Content1; + } + } +} diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index bed4cff0ea..7f453637e7 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -31,6 +31,10 @@ namespace osu.Game.Overlays.Mods { AccentColour = colours.Orange1; HeaderText = ModSelectOverlayStrings.PersonalPresets; + + AddPresetButton addPresetButton; + ItemsFlow.Add(addPresetButton = new AddPresetButton()); + ItemsFlow.SetLayoutPosition(addPresetButton, float.PositiveInfinity); } protected override void LoadComplete() @@ -64,7 +68,7 @@ namespace osu.Game.Overlays.Mods if (!presets.Any()) { - ItemsFlow.Clear(); + ItemsFlow.RemoveAll(panel => panel is ModPresetPanel); return; } @@ -77,7 +81,8 @@ namespace osu.Game.Overlays.Mods latestLoadTask = loadTask = LoadComponentsAsync(panels, loaded => { - ItemsFlow.ChildrenEnumerable = loaded; + ItemsFlow.RemoveAll(panel => panel is ModPresetPanel); + ItemsFlow.AddRange(loaded); }, (cancellationTokenSource = new CancellationTokenSource()).Token); loadTask.ContinueWith(_ => { diff --git a/osu.Game/Overlays/Mods/ModSelectPanel.cs b/osu.Game/Overlays/Mods/ModSelectPanel.cs index abf327a388..b3df00f8f9 100644 --- a/osu.Game/Overlays/Mods/ModSelectPanel.cs +++ b/osu.Game/Overlays/Mods/ModSelectPanel.cs @@ -43,8 +43,7 @@ namespace osu.Game.Overlays.Mods } public const float CORNER_RADIUS = 7; - - protected const float HEIGHT = 42; + public const float HEIGHT = 42; protected virtual float IdleSwitchWidth => 14; protected virtual float ExpandedSwitchWidth => 30; From 1b3074d0981a38b87a10215c048faa5d4e1a4472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 22 Jul 2022 21:42:42 +0200 Subject: [PATCH 0251/2686] Implement popover for creating mod presets --- .../UserInterface/TestSceneModPresetColumn.cs | 32 ++++---- osu.Game/Overlays/Mods/AddPresetButton.cs | 75 ++++++++++++++++++- 2 files changed, 90 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index 593c8abac4..d76ff3f332 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -9,6 +9,7 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Framework.Graphics.Cursor; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets; @@ -22,6 +23,9 @@ namespace osu.Game.Tests.Visual.UserInterface { protected override bool UseFreshStoragePerRun => true; + private Container content = null!; + protected override Container Content => content; + private RulesetStore rulesets = null!; [Cached] @@ -32,6 +36,12 @@ namespace osu.Game.Tests.Visual.UserInterface { Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(Realm); + + base.Content.Add(content = new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(30), + }); } [SetUpSteps] @@ -57,15 +67,10 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestBasicOperation() { AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0)); - AddStep("create content", () => Child = new Container + AddStep("create content", () => Child = new ModPresetColumn { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(30), - Child = new ModPresetColumn - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre, }); AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3); @@ -112,15 +117,10 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestSoftDeleteSupport() { AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0)); - AddStep("create content", () => Child = new Container + AddStep("create content", () => Child = new ModPresetColumn { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(30), - Child = new ModPresetColumn - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre, }); AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3); diff --git a/osu.Game/Overlays/Mods/AddPresetButton.cs b/osu.Game/Overlays/Mods/AddPresetButton.cs index e73ee3956a..00343ac851 100644 --- a/osu.Game/Overlays/Mods/AddPresetButton.cs +++ b/osu.Game/Overlays/Mods/AddPresetButton.cs @@ -2,14 +2,20 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osuTK; namespace osu.Game.Overlays.Mods { - public class AddPresetButton : ShearedToggleButton + public class AddPresetButton : ShearedToggleButton, IHasPopover { [Resolved] private OsuColour colours { get; set; } = null!; @@ -33,6 +39,73 @@ namespace osu.Game.Overlays.Mods DarkerColour = Active.Value ? colours.Orange1 : ColourProvider.Background3; LighterColour = Active.Value ? colours.Orange0 : ColourProvider.Background1; TextColour = Active.Value ? ColourProvider.Background6 : ColourProvider.Content1; + + if (Active.Value) + this.ShowPopover(); + else + this.HidePopover(); + } + + public Popover GetPopover() => new AddPresetPopover(this); + + private class AddPresetPopover : OsuPopover + { + private readonly AddPresetButton button; + + private readonly LabelledTextBox nameTextBox; + private readonly LabelledTextBox descriptionTextBox; + private readonly ShearedButton createButton; + + public AddPresetPopover(AddPresetButton addPresetButton) + { + button = addPresetButton; + + Child = new FillFlowContainer + { + Width = 300, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(7), + Children = new Drawable[] + { + nameTextBox = new LabelledTextBox + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Label = "Name", + TabbableContentContainer = this + }, + descriptionTextBox = new LabelledTextBox + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Label = "Description", + TabbableContentContainer = this + }, + createButton = new ShearedButton + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = "Create preset", + Action = this.HidePopover + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider, OsuColour colours) + { + createButton.DarkerColour = colours.Orange1; + createButton.LighterColour = colours.Orange0; + createButton.TextColour = colourProvider.Background6; + } + + protected override void UpdateState(ValueChangedEvent state) + { + base.UpdateState(state); + if (state.NewValue == Visibility.Hidden) + button.Active.Value = false; + } } } } From 059a465fe82fb0b5fe85c0fd83bda741c381addd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 16:22:09 +0200 Subject: [PATCH 0252/2686] Add border to popover for better visual contrast --- osu.Game/Overlays/Mods/AddPresetButton.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Mods/AddPresetButton.cs b/osu.Game/Overlays/Mods/AddPresetButton.cs index 00343ac851..0141f3fa2b 100644 --- a/osu.Game/Overlays/Mods/AddPresetButton.cs +++ b/osu.Game/Overlays/Mods/AddPresetButton.cs @@ -95,6 +95,9 @@ namespace osu.Game.Overlays.Mods [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider, OsuColour colours) { + Body.BorderThickness = 3; + Body.BorderColour = colours.Orange1; + createButton.DarkerColour = colours.Orange1; createButton.LighterColour = colours.Orange0; createButton.TextColour = colourProvider.Background6; From 7251389e4302be835b14f064aa50c0677c5d9400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 22 Jul 2022 21:49:51 +0200 Subject: [PATCH 0253/2686] Add localisations for add preset button --- osu.Game/Localisation/CommonStrings.cs | 14 ++++++++++++-- osu.Game/Localisation/ModSelectOverlayStrings.cs | 5 +++++ osu.Game/Overlays/Mods/AddPresetButton.cs | 7 ++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 1ee562e122..f2dcd57742 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using osu.Framework.Localisation; @@ -89,6 +89,16 @@ namespace osu.Game.Localisation /// public static LocalisableString Collections => new TranslatableString(getKey(@"collections"), @"Collections"); + /// + /// "Name" + /// + public static LocalisableString Name => new TranslatableString(getKey(@"name"), @"Name"); + + /// + /// "Description" + /// + public static LocalisableString Description => new TranslatableString(getKey(@"description"), @"Description"); + private static string getKey(string key) => $@"{prefix}:{key}"; } -} +} \ No newline at end of file diff --git a/osu.Game/Localisation/ModSelectOverlayStrings.cs b/osu.Game/Localisation/ModSelectOverlayStrings.cs index 3696b1f2cd..d6a01c4794 100644 --- a/osu.Game/Localisation/ModSelectOverlayStrings.cs +++ b/osu.Game/Localisation/ModSelectOverlayStrings.cs @@ -29,6 +29,11 @@ namespace osu.Game.Localisation /// public static LocalisableString PersonalPresets => new TranslatableString(getKey(@"personal_presets"), @"Personal Presets"); + /// + /// "Add preset" + /// + public static LocalisableString AddPreset => new TranslatableString(getKey(@"add_preset"), @"Add preset"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/Mods/AddPresetButton.cs b/osu.Game/Overlays/Mods/AddPresetButton.cs index 0141f3fa2b..44bdaeb9ac 100644 --- a/osu.Game/Overlays/Mods/AddPresetButton.cs +++ b/osu.Game/Overlays/Mods/AddPresetButton.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osuTK; +using osu.Game.Localisation; namespace osu.Game.Overlays.Mods { @@ -71,21 +72,21 @@ namespace osu.Game.Overlays.Mods { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Label = "Name", + Label = CommonStrings.Name, TabbableContentContainer = this }, descriptionTextBox = new LabelledTextBox { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Label = "Description", + Label = CommonStrings.Description, TabbableContentContainer = this }, createButton = new ShearedButton { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = "Create preset", + Text = ModSelectOverlayStrings.AddPreset, Action = this.HidePopover } } From add2971eb4a055f8560fe538f854fda346a5e20b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 22 Jul 2022 22:11:45 +0200 Subject: [PATCH 0254/2686] Implement preset creation flow with test coverage --- .../UserInterface/TestSceneModPresetColumn.cs | 61 ++++++++++++++++++- osu.Game/Overlays/Mods/AddPresetButton.cs | 51 +++++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index d76ff3f332..05ed03f01d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.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 System.Linq; using NUnit.Framework; @@ -10,16 +11,19 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Graphics.Cursor; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneModPresetColumn : OsuTestScene + public class TestSceneModPresetColumn : OsuManualInputManagerTestScene { protected override bool UseFreshStoragePerRun => true; @@ -146,6 +150,61 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("3 panels visible", () => this.ChildrenOfType().Count() == 3); } + [Test] + public void TestAddingFlow() + { + ModPresetColumn modPresetColumn = null!; + + AddStep("clear mods", () => SelectedMods.Value = Array.Empty()); + AddStep("create content", () => Child = modPresetColumn = new ModPresetColumn + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + AddUntilStep("items loaded", () => modPresetColumn.IsLoaded && modPresetColumn.ItemsLoaded); + AddAssert("add preset button disabled", () => !this.ChildrenOfType().Single().Enabled.Value); + + AddStep("set mods", () => SelectedMods.Value = new Mod[] { new OsuModDaycore(), new OsuModClassic() }); + AddAssert("add preset button enabled", () => this.ChildrenOfType().Single().Enabled.Value); + + AddStep("click add preset button", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + OsuPopover? popover = null; + AddUntilStep("wait for popover", () => (popover = this.ChildrenOfType().FirstOrDefault()) != null); + AddStep("attempt preset creation", () => + { + InputManager.MoveMouseTo(popover.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + AddWaitStep("wait some", 3); + AddAssert("preset creation did not occur", () => this.ChildrenOfType().Count() == 3); + AddUntilStep("popover is unchanged", () => this.ChildrenOfType().FirstOrDefault() == popover); + + AddStep("fill preset name", () => popover.ChildrenOfType().First().Current.Value = "new preset"); + AddStep("attempt preset creation", () => + { + InputManager.MoveMouseTo(popover.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + AddUntilStep("popover closed", () => !this.ChildrenOfType().Any()); + AddUntilStep("preset creation occurred", () => this.ChildrenOfType().Count() == 4); + + AddStep("click add preset button", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("wait for popover", () => (popover = this.ChildrenOfType().FirstOrDefault()) != null); + AddStep("clear mods", () => SelectedMods.Value = Array.Empty()); + AddUntilStep("popover closed", () => !this.ChildrenOfType().Any()); + } + private ICollection createTestPresets() => new[] { new ModPreset diff --git a/osu.Game/Overlays/Mods/AddPresetButton.cs b/osu.Game/Overlays/Mods/AddPresetButton.cs index 44bdaeb9ac..e3aeb21f1d 100644 --- a/osu.Game/Overlays/Mods/AddPresetButton.cs +++ b/osu.Game/Overlays/Mods/AddPresetButton.cs @@ -1,6 +1,8 @@ // 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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -8,9 +10,13 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; +using osu.Game.Database; +using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osuTK; using osu.Game.Localisation; @@ -21,6 +27,9 @@ namespace osu.Game.Overlays.Mods [Resolved] private OsuColour colours { get; set; } = null!; + [Resolved] + private Bindable> selectedMods { get; set; } = null!; + public AddPresetButton() : base(1) { @@ -35,6 +44,18 @@ namespace osu.Game.Overlays.Mods TextSize = 30; } + protected override void LoadComplete() + { + base.LoadComplete(); + + selectedMods.BindValueChanged(val => Enabled.Value = val.NewValue.Any(), true); + Enabled.BindValueChanged(val => + { + if (!val.NewValue) + Active.Value = false; + }); + } + protected override void UpdateActiveState() { DarkerColour = Active.Value ? colours.Orange1 : ColourProvider.Background3; @@ -57,6 +78,15 @@ namespace osu.Game.Overlays.Mods private readonly LabelledTextBox descriptionTextBox; private readonly ShearedButton createButton; + [Resolved] + private Bindable ruleset { get; set; } = null!; + + [Resolved] + private Bindable> selectedMods { get; set; } = null!; + + [Resolved] + private RealmAccess realm { get; set; } = null!; + public AddPresetPopover(AddPresetButton addPresetButton) { button = addPresetButton; @@ -87,7 +117,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Text = ModSelectOverlayStrings.AddPreset, - Action = this.HidePopover + Action = tryCreatePreset } } }; @@ -104,6 +134,25 @@ namespace osu.Game.Overlays.Mods createButton.TextColour = colourProvider.Background6; } + private void tryCreatePreset() + { + if (string.IsNullOrWhiteSpace(nameTextBox.Current.Value)) + { + Body.Shake(); + return; + } + + realm.Write(r => r.Add(new ModPreset + { + Name = nameTextBox.Current.Value, + Description = descriptionTextBox.Current.Value, + Mods = selectedMods.Value.ToArray(), + Ruleset = r.Find(ruleset.Value.ShortName) + })); + + this.HidePopover(); + } + protected override void UpdateState(ValueChangedEvent state) { base.UpdateState(state); From 9306dd5e30f8c1671606ef161d7235ceec133455 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 3 Aug 2022 15:02:22 +0900 Subject: [PATCH 0255/2686] Apply changes from removal of GLWrapper --- osu.Game/Graphics/Sprites/LogoAnimation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Sprites/LogoAnimation.cs b/osu.Game/Graphics/Sprites/LogoAnimation.cs index 14d78b4dee..7debdc7a37 100644 --- a/osu.Game/Graphics/Sprites/LogoAnimation.cs +++ b/osu.Game/Graphics/Sprites/LogoAnimation.cs @@ -58,7 +58,7 @@ namespace osu.Game.Graphics.Sprites protected override void Blit(IRenderer renderer) { - Shader.GetUniform("progress").UpdateValue(ref progress); + GetAppropriateShader(renderer).GetUniform("progress").UpdateValue(ref progress); base.Blit(renderer); } From f743dc623f6337fd80259de8768776e9ba59db3d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 3 Aug 2022 17:37:30 +0900 Subject: [PATCH 0256/2686] Change migration logic to ignore realm pipe files regardless of database filename --- osu.Game/IO/MigratableStorage.cs | 17 +++++++++++++++++ osu.Game/IO/OsuStorage.cs | 11 ++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/osu.Game/IO/MigratableStorage.cs b/osu.Game/IO/MigratableStorage.cs index 7cd409c04c..14a3c5a43c 100644 --- a/osu.Game/IO/MigratableStorage.cs +++ b/osu.Game/IO/MigratableStorage.cs @@ -26,6 +26,11 @@ namespace osu.Game.IO /// public virtual string[] IgnoreFiles => Array.Empty(); + /// + /// A list of file/directory suffixes which should not be migrated. + /// + public virtual string[] IgnoreSuffixes => Array.Empty(); + protected MigratableStorage(Storage storage, string subPath = null) : base(storage, subPath) { @@ -73,6 +78,9 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreFiles.Contains(fi.Name)) continue; + if (IgnoreSuffixes.Any(suffix => fi.Name.EndsWith(suffix, StringComparison.Ordinal))) + continue; + allFilesDeleted &= AttemptOperation(() => fi.Delete(), throwOnFailure: false); } @@ -81,6 +89,9 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name)) continue; + if (IgnoreSuffixes.Any(suffix => dir.Name.EndsWith(suffix, StringComparison.Ordinal))) + continue; + allFilesDeleted &= AttemptOperation(() => dir.Delete(true), throwOnFailure: false); } @@ -101,6 +112,9 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreFiles.Contains(fileInfo.Name)) continue; + if (IgnoreSuffixes.Any(suffix => fileInfo.Name.EndsWith(suffix, StringComparison.Ordinal))) + continue; + AttemptOperation(() => { fileInfo.Refresh(); @@ -119,6 +133,9 @@ namespace osu.Game.IO if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name)) continue; + if (IgnoreSuffixes.Any(suffix => dir.Name.EndsWith(suffix, StringComparison.Ordinal))) + continue; + CopyRecursive(dir, destination.CreateSubdirectory(dir.Name), false); } } diff --git a/osu.Game/IO/OsuStorage.cs b/osu.Game/IO/OsuStorage.cs index 368ac56850..f4c55e4b0e 100644 --- a/osu.Game/IO/OsuStorage.cs +++ b/osu.Game/IO/OsuStorage.cs @@ -38,15 +38,20 @@ namespace osu.Game.IO public override string[] IgnoreDirectories => new[] { "cache", - $"{OsuGameBase.CLIENT_DATABASE_FILENAME}.management", }; public override string[] IgnoreFiles => new[] { "framework.ini", "storage.ini", - $"{OsuGameBase.CLIENT_DATABASE_FILENAME}.note", - $"{OsuGameBase.CLIENT_DATABASE_FILENAME}.lock", + }; + + public override string[] IgnoreSuffixes => new[] + { + // Realm pipe files don't play well with copy operations + ".note", + ".lock", + ".management", }; public OsuStorage(GameHost host, Storage defaultStorage) From 6ad6561e1cd8c73f9ad7237ce1c51ed389e24656 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 3 Aug 2022 17:42:27 +0900 Subject: [PATCH 0257/2686] Fix `LegacySongProgress` incorrectly blocking mouse input from gameplay Closes #19555. --- osu.Game/Screens/Play/HUD/DefaultSongProgress.cs | 2 -- osu.Game/Screens/Play/HUD/SongProgress.cs | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index 96a6c56860..659984682e 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -40,8 +40,6 @@ namespace osu.Game.Screens.Play.HUD public override bool HandleNonPositionalInput => AllowSeeking.Value; public override bool HandlePositionalInput => AllowSeeking.Value; - protected override bool BlockScrollInput => false; - [Resolved] private Player? player { get; set; } diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index 702d2f7c6f..09afd7a9d3 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -14,6 +14,12 @@ namespace osu.Game.Screens.Play.HUD { public abstract class SongProgress : OverlayContainer, ISkinnableDrawable { + // Some implementations of this element allow seeking during gameplay playback. + // Set a sane default of never handling input to override the behaviour provided by OverlayContainer. + public override bool HandleNonPositionalInput => false; + public override bool HandlePositionalInput => false; + protected override bool BlockScrollInput => false; + public bool UsesFixedAnchor { get; set; } [Resolved] From 16ff8d5c38354e914d30366f4a322dfda35acc2d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 3 Aug 2022 17:47:32 +0900 Subject: [PATCH 0258/2686] Use different variable source --- osu.Game/Graphics/Containers/BeatSyncedContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index c8ea21e139..6dd5d61cc9 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -29,7 +29,7 @@ namespace osu.Game.Graphics.Containers private TimingControlPoint? lastTimingPoint { get; set; } private EffectControlPoint? lastEffectPoint { get; set; } - public bool IsKiaiTime { get; private set; } + protected bool IsKiaiTime { get; private set; } /// /// The amount of time before a beat we should fire . @@ -142,7 +142,7 @@ namespace osu.Game.Graphics.Containers lastTimingPoint = timingPoint; lastEffectPoint = effectPoint; - IsKiaiTime = lastEffectPoint?.KiaiMode ?? false; + IsKiaiTime = effectPoint?.KiaiMode ?? false; } } } From 24d84890e4869ac12437291eaa82ccb3f11114a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 3 Aug 2022 20:03:05 +0900 Subject: [PATCH 0259/2686] Change all filter control button state test to until steps There's multiple schedules at play which could be adding multi-frame delays. let's play it safe and try and fix flaky tests. Example of `Schedule` which could cause an issue: https://github.com/ppy/osu/blob/392cb352cc71da8b0f82aa0877ea6a7febfc54b1/osu.Game/Collections/CollectionDropdown.cs#L77-L78 Example of test failure: https://github.com/ppy/osu/runs/7648118894?check_suite_focus=true --- .../Visual/SongSelect/TestSceneFilterControl.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs index d0523b58fa..99afe5a2f7 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs @@ -150,13 +150,14 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1")))); assertCollectionDropdownContains("1"); - AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare)); + + assertFirstButtonIs(FontAwesome.Solid.PlusSquare); AddStep("add beatmap to collection", () => writeAndRefresh(r => getFirstCollection().BeatmapMD5Hashes.Add(Beatmap.Value.BeatmapInfo.MD5Hash))); - AddAssert("button is minus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.MinusSquare)); + assertFirstButtonIs(FontAwesome.Solid.MinusSquare); AddStep("remove beatmap from collection", () => writeAndRefresh(r => getFirstCollection().BeatmapMD5Hashes.Clear())); - AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare)); + assertFirstButtonIs(FontAwesome.Solid.PlusSquare); } [Test] @@ -168,15 +169,15 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("add collection", () => writeAndRefresh(r => r.Add(new BeatmapCollection(name: "1")))); assertCollectionDropdownContains("1"); - AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare)); + assertFirstButtonIs(FontAwesome.Solid.PlusSquare); addClickAddOrRemoveButtonStep(1); AddAssert("collection contains beatmap", () => getFirstCollection().BeatmapMD5Hashes.Contains(Beatmap.Value.BeatmapInfo.MD5Hash)); - AddAssert("button is minus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.MinusSquare)); + assertFirstButtonIs(FontAwesome.Solid.MinusSquare); addClickAddOrRemoveButtonStep(1); AddAssert("collection does not contain beatmap", () => !getFirstCollection().BeatmapMD5Hashes.Contains(Beatmap.Value.BeatmapInfo.MD5Hash)); - AddAssert("button is plus", () => getAddOrRemoveButton(1).Icon.Equals(FontAwesome.Solid.PlusSquare)); + assertFirstButtonIs(FontAwesome.Solid.PlusSquare); } [Test] @@ -226,6 +227,8 @@ namespace osu.Game.Tests.Visual.SongSelect => AddUntilStep($"collection dropdown header displays '{collectionName}'", () => shouldDisplay == (control.ChildrenOfType().Single().ChildrenOfType().First().Text == collectionName)); + private void assertFirstButtonIs(IconUsage icon) => AddUntilStep($"button is {icon.ToString()}", () => getAddOrRemoveButton(1).Icon.Equals(icon)); + private void assertCollectionDropdownContains(string collectionName, bool shouldContain = true) => AddUntilStep($"collection dropdown {(shouldContain ? "contains" : "does not contain")} '{collectionName}'", // A bit of a roundabout way of going about this, see: https://github.com/ppy/osu-framework/issues/3871 + https://github.com/ppy/osu-framework/issues/3872 From a32149fda125c207575fc6dc1fc30450d5eee556 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 3 Aug 2022 20:07:54 +0900 Subject: [PATCH 0260/2686] Convert interface methods to extension methods --- .../Beatmaps/BeatSyncProviderExtensions.cs | 18 ++++++++++++++++++ osu.Game/Beatmaps/IBeatSyncProvider.cs | 10 ---------- .../Graphics/Containers/BeatSyncedContainer.cs | 6 ++---- osu.Game/Screens/Menu/LogoVisualisation.cs | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 osu.Game/Beatmaps/BeatSyncProviderExtensions.cs diff --git a/osu.Game/Beatmaps/BeatSyncProviderExtensions.cs b/osu.Game/Beatmaps/BeatSyncProviderExtensions.cs new file mode 100644 index 0000000000..117b4d23b0 --- /dev/null +++ b/osu.Game/Beatmaps/BeatSyncProviderExtensions.cs @@ -0,0 +1,18 @@ +// 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.Beatmaps +{ + public static class BeatSyncProviderExtensions + { + /// + /// Check whether beat sync is currently available. + /// + public static bool CheckBeatSyncAvailable(this IBeatSyncProvider provider) => provider.Clock != null; + + /// + /// Whether the beat sync provider is currently in a kiai section. Should make everything more epic. + /// + public static bool CheckIsKiaiTime(this IBeatSyncProvider provider) => provider.Clock != null && (provider.ControlPoints?.EffectPointAt(provider.Clock.CurrentTime).KiaiMode ?? false); + } +} diff --git a/osu.Game/Beatmaps/IBeatSyncProvider.cs b/osu.Game/Beatmaps/IBeatSyncProvider.cs index 485497a8f0..9ee19e720d 100644 --- a/osu.Game/Beatmaps/IBeatSyncProvider.cs +++ b/osu.Game/Beatmaps/IBeatSyncProvider.cs @@ -16,16 +16,6 @@ namespace osu.Game.Beatmaps [Cached] public interface IBeatSyncProvider : IHasAmplitudes { - /// - /// Check whether beat sync is currently available. - /// - public bool BeatSyncAvailable => Clock != null; - - /// - /// Whether the beat sync provider is currently in a kiai section. Should make everything more epic. - /// - public bool IsKiaiTime => Clock != null && (ControlPoints?.EffectPointAt(Clock.CurrentTime).KiaiMode ?? false); - /// /// Access any available control points from a beatmap providing beat sync. If null, no current provider is available. /// diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 6dd5d61cc9..00fea601c6 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -27,7 +27,6 @@ namespace osu.Game.Graphics.Containers private int lastBeat; private TimingControlPoint? lastTimingPoint { get; set; } - private EffectControlPoint? lastEffectPoint { get; set; } protected bool IsKiaiTime { get; private set; } @@ -87,7 +86,7 @@ namespace osu.Game.Graphics.Containers TimingControlPoint timingPoint; EffectControlPoint effectPoint; - IsBeatSyncedWithTrack = BeatSyncSource.BeatSyncAvailable && BeatSyncSource.Clock?.IsRunning == true; + IsBeatSyncedWithTrack = BeatSyncSource.CheckBeatSyncAvailable() && BeatSyncSource.Clock?.IsRunning == true; double currentTrackTime; @@ -140,9 +139,8 @@ namespace osu.Game.Graphics.Containers lastBeat = beatIndex; lastTimingPoint = timingPoint; - lastEffectPoint = effectPoint; - IsKiaiTime = effectPoint?.KiaiMode ?? false; + IsKiaiTime = effectPoint.KiaiMode; } } } diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index e9f52e0b9f..1c5fd341b0 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -111,7 +111,7 @@ namespace osu.Game.Screens.Menu for (int i = 0; i < bars_per_visualiser; i++) { - float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (beatSyncProvider.IsKiaiTime ? 1 : 0.5f); + float targetAmplitude = (temporalAmplitudes[(i + indexOffset) % bars_per_visualiser]) * (beatSyncProvider.CheckIsKiaiTime() ? 1 : 0.5f); if (targetAmplitude > frequencyAmplitudes[i]) frequencyAmplitudes[i] = targetAmplitude; } From d3954fc583ad5ec1de1a240261664d0112fa2a7a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 3 Aug 2022 20:15:42 +0900 Subject: [PATCH 0261/2686] Use existing localised error message --- osu.Game/Database/ModelDownloader.cs | 2 +- osu.Game/Database/TooManyDownloadsNotification.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index 5c84e0c308..a3678602d1 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -112,7 +112,7 @@ namespace osu.Game.Database if (error is WebException webException && webException.Message == @"TooManyRequests") { notification.Close(); - PostNotification?.Invoke(new TooManyDownloadsNotification(importer.HumanisedModelName)); + PostNotification?.Invoke(new TooManyDownloadsNotification()); } else Logger.Error(error, $"{importer.HumanisedModelName.Titleize()} download failed!"); diff --git a/osu.Game/Database/TooManyDownloadsNotification.cs b/osu.Game/Database/TooManyDownloadsNotification.cs index c07584c6ec..aa88fed43c 100644 --- a/osu.Game/Database/TooManyDownloadsNotification.cs +++ b/osu.Game/Database/TooManyDownloadsNotification.cs @@ -5,14 +5,15 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Overlays.Notifications; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Database { public class TooManyDownloadsNotification : SimpleNotification { - public TooManyDownloadsNotification(string humanisedModelName) + public TooManyDownloadsNotification() { - Text = $"You have downloaded too many {humanisedModelName}s! Please try again later."; + Text = BeatmapsetsStrings.DownloadLimitExceeded; Icon = FontAwesome.Solid.ExclamationCircle; } From bacbf5b7f0cb87e334d64c6f98af3afc6a298427 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 3 Aug 2022 20:20:06 +0900 Subject: [PATCH 0262/2686] Update existing test expectations --- osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 4baa4af8dd..a21f66a7cb 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -294,7 +294,7 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4); AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2); - AddAssert("status not copied", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.None); + AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified); AddAssert("online ID not copied", () => EditorBeatmap.BeatmapInfo.OnlineID == -1); AddStep("save beatmap", () => Editor.Save()); From 7022d9e5f81c23730b3db690dbfb288238508129 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 3 Aug 2022 21:13:49 +0900 Subject: [PATCH 0263/2686] Fix test step names being too long --- osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs index 99afe5a2f7..dadcd43db5 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs @@ -227,7 +227,7 @@ namespace osu.Game.Tests.Visual.SongSelect => AddUntilStep($"collection dropdown header displays '{collectionName}'", () => shouldDisplay == (control.ChildrenOfType().Single().ChildrenOfType().First().Text == collectionName)); - private void assertFirstButtonIs(IconUsage icon) => AddUntilStep($"button is {icon.ToString()}", () => getAddOrRemoveButton(1).Icon.Equals(icon)); + private void assertFirstButtonIs(IconUsage icon) => AddUntilStep($"button is {icon.Icon.ToString()}", () => getAddOrRemoveButton(1).Icon.Equals(icon)); private void assertCollectionDropdownContains(string collectionName, bool shouldContain = true) => AddUntilStep($"collection dropdown {(shouldContain ? "contains" : "does not contain")} '{collectionName}'", From 8b02c955d838541cb782596457f184b3f50d45fb Mon Sep 17 00:00:00 2001 From: andy840119 Date: Wed, 3 Aug 2022 23:17:09 +0800 Subject: [PATCH 0264/2686] Give this class a constructor to make sure that message data will always assigned. --- osu.Desktop/LegacyIpc/LegacyIpcMessage.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs index 76eb6cdbd1..54198ef605 100644 --- a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs +++ b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs @@ -37,17 +37,19 @@ namespace osu.Desktop.LegacyIpc public new object Value { get => base.Value; - set => base.Value = new Data - { - MessageType = value.GetType().Name, - MessageData = value - }; + set => base.Value = new Data(value.GetType().Name, value); } public class Data { - public string MessageType { get; set; } = string.Empty; - public object MessageData { get; set; } = default!; + public Data(string messageType, object messageData) + { + MessageType = messageType; + MessageData = messageData; + } + + public string MessageType { get; set; } + public object MessageData { get; set; } } } } From 844430502b548747b0ed4867e8a2bb230c031d7a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 3 Aug 2022 20:11:08 +0300 Subject: [PATCH 0265/2686] Replace parantheses with nullable-bool equality operation --- osu.Game/Beatmaps/BeatSyncProviderExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatSyncProviderExtensions.cs b/osu.Game/Beatmaps/BeatSyncProviderExtensions.cs index 117b4d23b0..767aa5df73 100644 --- a/osu.Game/Beatmaps/BeatSyncProviderExtensions.cs +++ b/osu.Game/Beatmaps/BeatSyncProviderExtensions.cs @@ -13,6 +13,6 @@ namespace osu.Game.Beatmaps /// /// Whether the beat sync provider is currently in a kiai section. Should make everything more epic. /// - public static bool CheckIsKiaiTime(this IBeatSyncProvider provider) => provider.Clock != null && (provider.ControlPoints?.EffectPointAt(provider.Clock.CurrentTime).KiaiMode ?? false); + public static bool CheckIsKiaiTime(this IBeatSyncProvider provider) => provider.Clock != null && provider.ControlPoints?.EffectPointAt(provider.Clock.CurrentTime).KiaiMode == true; } } From b00c3a4d6d9fd725b428f36155bb47c641697127 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 3 Aug 2022 20:31:51 +0300 Subject: [PATCH 0266/2686] Move properties and mark as get-only --- osu.Desktop/LegacyIpc/LegacyIpcMessage.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs index 54198ef605..8d0add32d1 100644 --- a/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs +++ b/osu.Desktop/LegacyIpc/LegacyIpcMessage.cs @@ -42,14 +42,15 @@ namespace osu.Desktop.LegacyIpc public class Data { + public string MessageType { get; } + + public object MessageData { get; } + public Data(string messageType, object messageData) { MessageType = messageType; MessageData = messageData; } - - public string MessageType { get; set; } - public object MessageData { get; set; } } } } From 82d3fbd51b0b49fa003b961aa06c2093f061b303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 3 Aug 2022 21:22:55 +0200 Subject: [PATCH 0267/2686] Split `AddPresetPopover` to separate file --- osu.Game/Overlays/Mods/AddPresetButton.cs | 97 ------------------ osu.Game/Overlays/Mods/AddPresetPopover.cs | 113 +++++++++++++++++++++ 2 files changed, 113 insertions(+), 97 deletions(-) create mode 100644 osu.Game/Overlays/Mods/AddPresetPopover.cs diff --git a/osu.Game/Overlays/Mods/AddPresetButton.cs b/osu.Game/Overlays/Mods/AddPresetButton.cs index e3aeb21f1d..375987e474 100644 --- a/osu.Game/Overlays/Mods/AddPresetButton.cs +++ b/osu.Game/Overlays/Mods/AddPresetButton.cs @@ -7,18 +7,12 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; -using osu.Game.Database; -using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osuTK; -using osu.Game.Localisation; namespace osu.Game.Overlays.Mods { @@ -69,96 +63,5 @@ namespace osu.Game.Overlays.Mods } public Popover GetPopover() => new AddPresetPopover(this); - - private class AddPresetPopover : OsuPopover - { - private readonly AddPresetButton button; - - private readonly LabelledTextBox nameTextBox; - private readonly LabelledTextBox descriptionTextBox; - private readonly ShearedButton createButton; - - [Resolved] - private Bindable ruleset { get; set; } = null!; - - [Resolved] - private Bindable> selectedMods { get; set; } = null!; - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - public AddPresetPopover(AddPresetButton addPresetButton) - { - button = addPresetButton; - - Child = new FillFlowContainer - { - Width = 300, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(7), - Children = new Drawable[] - { - nameTextBox = new LabelledTextBox - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Label = CommonStrings.Name, - TabbableContentContainer = this - }, - descriptionTextBox = new LabelledTextBox - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Label = CommonStrings.Description, - TabbableContentContainer = this - }, - createButton = new ShearedButton - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Text = ModSelectOverlayStrings.AddPreset, - Action = tryCreatePreset - } - } - }; - } - - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, OsuColour colours) - { - Body.BorderThickness = 3; - Body.BorderColour = colours.Orange1; - - createButton.DarkerColour = colours.Orange1; - createButton.LighterColour = colours.Orange0; - createButton.TextColour = colourProvider.Background6; - } - - private void tryCreatePreset() - { - if (string.IsNullOrWhiteSpace(nameTextBox.Current.Value)) - { - Body.Shake(); - return; - } - - realm.Write(r => r.Add(new ModPreset - { - Name = nameTextBox.Current.Value, - Description = descriptionTextBox.Current.Value, - Mods = selectedMods.Value.ToArray(), - Ruleset = r.Find(ruleset.Value.ShortName) - })); - - this.HidePopover(); - } - - protected override void UpdateState(ValueChangedEvent state) - { - base.UpdateState(state); - if (state.NewValue == Visibility.Hidden) - button.Active.Value = false; - } - } } } diff --git a/osu.Game/Overlays/Mods/AddPresetPopover.cs b/osu.Game/Overlays/Mods/AddPresetPopover.cs new file mode 100644 index 0000000000..a7c77b7d83 --- /dev/null +++ b/osu.Game/Overlays/Mods/AddPresetPopover.cs @@ -0,0 +1,113 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Database; +using osu.Game.Extensions; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Localisation; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osuTK; + +namespace osu.Game.Overlays.Mods +{ + internal class AddPresetPopover : OsuPopover + { + private readonly AddPresetButton button; + + private readonly LabelledTextBox nameTextBox; + private readonly LabelledTextBox descriptionTextBox; + private readonly ShearedButton createButton; + + [Resolved] + private Bindable ruleset { get; set; } = null!; + + [Resolved] + private Bindable> selectedMods { get; set; } = null!; + + [Resolved] + private RealmAccess realm { get; set; } = null!; + + public AddPresetPopover(AddPresetButton addPresetButton) + { + button = addPresetButton; + + Child = new FillFlowContainer + { + Width = 300, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(7), + Children = new Drawable[] + { + nameTextBox = new LabelledTextBox + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Label = CommonStrings.Name, + TabbableContentContainer = this + }, + descriptionTextBox = new LabelledTextBox + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Label = CommonStrings.Description, + TabbableContentContainer = this + }, + createButton = new ShearedButton + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = ModSelectOverlayStrings.AddPreset, + Action = tryCreatePreset + } + } + }; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider, OsuColour colours) + { + Body.BorderThickness = 3; + Body.BorderColour = colours.Orange1; + + createButton.DarkerColour = colours.Orange1; + createButton.LighterColour = colours.Orange0; + createButton.TextColour = colourProvider.Background6; + } + + private void tryCreatePreset() + { + if (string.IsNullOrWhiteSpace(nameTextBox.Current.Value)) + { + Body.Shake(); + return; + } + + realm.Write(r => r.Add(new ModPreset + { + Name = nameTextBox.Current.Value, + Description = descriptionTextBox.Current.Value, + Mods = selectedMods.Value.ToArray(), + Ruleset = r.Find(ruleset.Value.ShortName) + })); + + this.HidePopover(); + } + + protected override void UpdateState(ValueChangedEvent state) + { + base.UpdateState(state); + if (state.NewValue == Visibility.Hidden) + button.Active.Value = false; + } + } +} From 159d3b032c2243ce6581dc9f3322925e919dfbbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 3 Aug 2022 21:23:31 +0200 Subject: [PATCH 0268/2686] Rename locals for legibility --- osu.Game/Overlays/Mods/AddPresetButton.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Mods/AddPresetButton.cs b/osu.Game/Overlays/Mods/AddPresetButton.cs index 375987e474..1242088cf5 100644 --- a/osu.Game/Overlays/Mods/AddPresetButton.cs +++ b/osu.Game/Overlays/Mods/AddPresetButton.cs @@ -42,10 +42,10 @@ namespace osu.Game.Overlays.Mods { base.LoadComplete(); - selectedMods.BindValueChanged(val => Enabled.Value = val.NewValue.Any(), true); - Enabled.BindValueChanged(val => + selectedMods.BindValueChanged(mods => Enabled.Value = mods.NewValue.Any(), true); + Enabled.BindValueChanged(enabled => { - if (!val.NewValue) + if (!enabled.NewValue) Active.Value = false; }); } From ca1b4689cb7e6490c302efb19a8becb64c1fe524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 3 Aug 2022 21:26:35 +0200 Subject: [PATCH 0269/2686] Automatically focus name textbox upon add preset popover open --- osu.Game/Overlays/Mods/AddPresetPopover.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Overlays/Mods/AddPresetPopover.cs b/osu.Game/Overlays/Mods/AddPresetPopover.cs index a7c77b7d83..8188c98e46 100644 --- a/osu.Game/Overlays/Mods/AddPresetPopover.cs +++ b/osu.Game/Overlays/Mods/AddPresetPopover.cs @@ -84,6 +84,13 @@ namespace osu.Game.Overlays.Mods createButton.TextColour = colourProvider.Background6; } + protected override void LoadComplete() + { + base.LoadComplete(); + + ScheduleAfterChildren(() => GetContainingInputManager().ChangeFocus(nameTextBox)); + } + private void tryCreatePreset() { if (string.IsNullOrWhiteSpace(nameTextBox.Current.Value)) From 6632367c6db4cff221e35386a7447e771ca44c61 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 4 Aug 2022 14:48:12 +0900 Subject: [PATCH 0270/2686] Ensure skin samples are looked up in correct order --- .../Skins/TestSceneSkinResources.cs | 69 +++++++++++++++++-- osu.Game/Skinning/Skin.cs | 6 +- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinResources.cs b/osu.Game.Tests/Skins/TestSceneSkinResources.cs index 42c1eeb6d1..20f5c3d911 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinResources.cs @@ -1,14 +1,25 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using Moq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Textures; +using osu.Framework.IO.Stores; using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Database; +using osu.Game.IO; using osu.Game.Skinning; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual; @@ -19,9 +30,9 @@ namespace osu.Game.Tests.Skins public class TestSceneSkinResources : OsuTestScene { [Resolved] - private SkinManager skins { get; set; } + private SkinManager skins { get; set; } = null!; - private ISkin skin; + private ISkin skin = null!; [BackgroundDependencyLoader] private void load() @@ -32,5 +43,55 @@ namespace osu.Game.Tests.Skins [Test] public void TestRetrieveOggSample() => AddAssert("sample is non-null", () => skin.GetSample(new SampleInfo("sample")) != null); + + [Test] + public void TestSampleRetrievalOrder() + { + Mock mockResourceProvider = null!; + Mock> mockResourceStore = null!; + List lookedUpFileNames = null!; + + AddStep("setup mock providers provider", () => + { + lookedUpFileNames = new List(); + mockResourceProvider = new Mock(); + mockResourceProvider.Setup(m => m.AudioManager).Returns(Audio); + mockResourceStore = new Mock>(); + mockResourceStore.Setup(r => r.Get(It.IsAny())) + .Callback(n => lookedUpFileNames.Add(n)) + .Returns(null); + }); + + AddStep("query sample", () => + { + TestSkin testSkin = new TestSkin(new SkinInfo(), mockResourceProvider.Object, new ResourceStore(mockResourceStore.Object)); + testSkin.GetSample(new SampleInfo()); + }); + + AddAssert("sample lookups were in correct order", () => + { + string[] lookups = lookedUpFileNames.Where(f => f.StartsWith(TestSkin.SAMPLE_NAME, StringComparison.Ordinal)).ToArray(); + return Path.GetExtension(lookups[0]) == string.Empty + && Path.GetExtension(lookups[1]) == ".wav" + && Path.GetExtension(lookups[2]) == ".mp3" + && Path.GetExtension(lookups[3]) == ".ogg"; + }); + } + + private class TestSkin : Skin + { + public const string SAMPLE_NAME = "test-sample"; + + public TestSkin(SkinInfo skin, IStorageResourceProvider? resources, IResourceStore? storage = null, string configurationFilename = "skin.ini") + : base(skin, resources, storage, configurationFilename) + { + } + + public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); + + public override IBindable GetConfig(TLookup lookup) => throw new NotImplementedException(); + + public override ISample GetSample(ISampleInfo sampleInfo) => Samples.AsNonNull().Get(SAMPLE_NAME); + } } } diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 7d93aeb897..86347d9a3a 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -69,12 +69,14 @@ namespace osu.Game.Skinning storage ??= realmBackedStorage = new RealmBackedResourceStore(SkinInfo, resources.Files, resources.RealmAccess); - (storage as ResourceStore)?.AddExtension("ogg"); - var samples = resources.AudioManager?.GetSampleStore(storage); if (samples != null) samples.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY; + // osu-stable performs audio lookups in order of wav -> mp3 -> ogg. + // The GetSampleStore() call above internally adds wav and mp3, so ogg is added at the end to ensure expected ordering. + (storage as ResourceStore)?.AddExtension("ogg"); + Samples = samples; Textures = new TextureStore(resources.CreateTextureLoaderStore(storage)); } From c11a24b3ff541c85133e401f0f02c3057554b607 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 4 Aug 2022 15:05:52 +0900 Subject: [PATCH 0271/2686] Remove unused using --- osu.Game.Tests/Skins/TestSceneSkinResources.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinResources.cs b/osu.Game.Tests/Skins/TestSceneSkinResources.cs index 20f5c3d911..d1561c84bf 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinResources.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading; using Moq; using NUnit.Framework; using osu.Framework.Allocation; From 094eaafd43866c395755e86b9d240e938caf5eb2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 4 Aug 2022 17:26:54 +0900 Subject: [PATCH 0272/2686] Split out common conditional check into local `static` method --- osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index 3238863700..f96fcc2630 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -101,13 +101,13 @@ namespace osu.Game.Beatmaps beatmapInfo.BeatmapSet.OnlineID = res.OnlineBeatmapSetID; // Some metadata should only be applied if there's no local changes. - if (beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified) + if (shouldSaveOnlineMetadata(beatmapInfo)) { beatmapInfo.Status = res.Status; beatmapInfo.Metadata.Author.OnlineID = res.AuthorID; } - if (beatmapInfo.BeatmapSet.Beatmaps.All(b => b.MatchesOnlineVersion || b.Status != BeatmapOnlineStatus.LocallyModified)) + if (beatmapInfo.BeatmapSet.Beatmaps.All(shouldSaveOnlineMetadata)) { beatmapInfo.BeatmapSet.Status = res.BeatmapSet?.Status ?? BeatmapOnlineStatus.None; beatmapInfo.BeatmapSet.DateRanked = res.BeatmapSet?.Ranked; @@ -212,7 +212,7 @@ namespace osu.Game.Beatmaps var status = (BeatmapOnlineStatus)reader.GetByte(2); // Some metadata should only be applied if there's no local changes. - if (beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified) + if (shouldSaveOnlineMetadata(beatmapInfo)) { beatmapInfo.Status = status; beatmapInfo.Metadata.Author.OnlineID = reader.GetInt32(3); @@ -226,7 +226,7 @@ namespace osu.Game.Beatmaps Debug.Assert(beatmapInfo.BeatmapSet != null); beatmapInfo.BeatmapSet.OnlineID = reader.GetInt32(0); - if (beatmapInfo.BeatmapSet.Beatmaps.All(b => b.MatchesOnlineVersion || b.Status != BeatmapOnlineStatus.LocallyModified)) + if (beatmapInfo.BeatmapSet.Beatmaps.All(shouldSaveOnlineMetadata)) { beatmapInfo.BeatmapSet.Status = status; } @@ -249,6 +249,12 @@ namespace osu.Game.Beatmaps private void logForModel(BeatmapSetInfo set, string message) => RealmArchiveModelImporter.LogForModel(set, $"[{nameof(BeatmapUpdaterMetadataLookup)}] {message}"); + /// + /// Check whether the provided beatmap is in a state where online "ranked" status metadata should be saved against it. + /// Handles the case where a user may have locally modified a beatmap in the editor and expects the local status to stick. + /// + private static bool shouldSaveOnlineMetadata(BeatmapInfo beatmapInfo) => beatmapInfo.MatchesOnlineVersion || beatmapInfo.Status != BeatmapOnlineStatus.LocallyModified; + public void Dispose() { cacheDownloadRequest?.Dispose(); From 8ff7770a71591fc3d014c4033c7e090cd35b23e3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 4 Aug 2022 19:11:39 +0900 Subject: [PATCH 0273/2686] Omit irrelevant data from SoloScoreInfo serialisation --- osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 6558578023..51b9e601c8 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -102,6 +102,14 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("pp")] public double? PP { get; set; } + public bool ShouldSerializeID() => false; + public bool ShouldSerializeUser() => false; + public bool ShouldSerializeBeatmap() => false; + public bool ShouldSerializeBeatmapSet() => false; + public bool ShouldSerializePP() => false; + public bool ShouldSerializeOnlineID() => false; + public bool ShouldSerializeHasReplay() => false; + #endregion public override string ToString() => $"score_id: {ID} user_id: {UserID}"; From 2d9da07eb69bfbeb1e9ff65fb50920ee7c6ec0b7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 4 Aug 2022 19:27:50 +0900 Subject: [PATCH 0274/2686] Trim zero values from hit statistics --- osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 51b9e601c8..e2e5ea4239 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -173,7 +173,7 @@ namespace osu.Game.Online.API.Requests.Responses RulesetID = score.RulesetID, Passed = score.Passed, Mods = score.APIMods, - Statistics = score.Statistics, + Statistics = score.Statistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value), }; public long OnlineID => ID ?? -1; From 42d1bdfc95fe78555fd5ce0426bc79b6a4d6f736 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Fri, 5 Aug 2022 04:17:01 +0200 Subject: [PATCH 0275/2686] Move KPS calculation to a standalone class --- .../Gameplay/TestSceneKeyPerSecondCounter.cs | 91 +++++++++++++++++++ .../Gameplay/TestSceneKeysPerSecondCounter.cs | 4 +- .../HUD/KPSCounter/KeysPerSecondCalculator.cs | 91 +++++++++++++++++++ .../{ => KPSCounter}/KeysPerSecondCounter.cs | 63 ++----------- osu.Game/Screens/Play/KeyCounter.cs | 4 +- osu.Game/Screens/Play/KeyCounterDisplay.cs | 2 - osu.Game/Screens/Play/Player.cs | 4 +- 7 files changed, 195 insertions(+), 64 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneKeyPerSecondCounter.cs create mode 100644 osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs rename osu.Game/Screens/Play/HUD/{ => KPSCounter}/KeysPerSecondCounter.cs (63%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyPerSecondCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyPerSecondCounter.cs new file mode 100644 index 0000000000..a2eaea29eb --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyPerSecondCounter.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD.KPSCounter; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneKeyPerSecondCounter : PlayerTestScene + { + protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); + protected override bool HasCustomSteps => false; + protected override bool Autoplay => true; + + private GameplayClock gameplayClock; + private DrawableRuleset drawableRuleset; + + // private DependencyProvidingContainer dependencyContainer; + private KeysPerSecondCounter counter; + + [SetUpSteps] + public new void SetUpSteps() + { + /* + CreateTest(() => AddStep("Create components", () => + { + Logger.Log($"{(Player != null ? Player.ToString() : "null")}", level: LogLevel.Debug); + dependencyContainer = new DependencyProvidingContainer + { + RelativePositionAxes = Axes.Both, + }; + })); + */ + } + + private void createCounter() + { + AddStep("Create counter", () => + { + /* + if (!Contains(dependencyContainer)) + { + Add(dependencyContainer); + } + + if (dependencyContainer.CachedDependencies.Length == 0) + { + dependencyContainer.CachedDependencies = new (Type, object)[] + { + (typeof(GameplayClock), , + (typeof(DrawableRuleset),) + }; + } + Dependencies.Cache(gameplayClock = Player.GameplayClockContainer.GameplayClock)); + */ + + Dependencies.Cache(gameplayClock = Player.GameplayClockContainer.GameplayClock); + Dependencies.Cache(drawableRuleset = Player.DrawableRuleset); + + Add(counter = new KeysPerSecondCounter + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Scale = new Vector2(5), + Position = new Vector2(10, 100) + } + ); + }); + AddAssert("ensure counter added", () => Contains(counter)); + } + + [Test] + public void TestInGameTimeConsistency() + { + createCounter(); + + AddUntilStep("Wait until first note", () => counter.Current.Value != 0); + AddStep("Pause gameplay", () => gameplayClock.IsPaused.Value = true); + AddAssert("KPS = 1", () => counter.Current.Value == 1); + } + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs index e20a83b54a..c8c31d1366 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs @@ -7,7 +7,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.HUD.KPSCounter; using osuTK; using osuTK.Input; @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestManualTrigger() { AddAssert("Counter = 0", () => counter.Current.Value == 0); - AddRepeatStep("manual trigger", KeysPerSecondCounter.AddTimestamp, 20); + AddRepeatStep("manual trigger", KeysPerSecondCalculator.AddInput, 20); AddAssert("Counter is not 0", () => counter.Current.Value > 0); } diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs new file mode 100644 index 0000000000..f9839abde4 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Timing; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Screens.Play.HUD.KPSCounter +{ + public class KeysPerSecondCalculator : IDisposable + { + private static KeysPerSecondCalculator instance; + + public static void AddInput() + { + instance?.onNewInput.Invoke(); + } + + public static KeysPerSecondCalculator GetInstance(GameplayClock gameplayClock = null, DrawableRuleset drawableRuleset = null) + { + if (instance != null) return instance; + + try + { + return new KeysPerSecondCalculator(gameplayClock, drawableRuleset); + } + catch (ArgumentNullException) + { + return null; + } + } + + private readonly List timestamps; + private readonly GameplayClock gameplayClock; + private readonly DrawableRuleset drawableRuleset; + + private event Action onNewInput; + + private IClock workingClock => (IClock)drawableRuleset.FrameStableClock ?? gameplayClock; + + // Having the rate from mods is preffered to using GameplayClock.TrueGameplayRate() + // as it returns 0 when paused in replays, not useful for players who want to "analyze" a replay. + private double rate => (drawableRuleset.Mods.FirstOrDefault(m => m is ModRateAdjust) as ModRateAdjust)?.SpeedChange.Value + ?? 1; + + private double maxTime = double.NegativeInfinity; + + public bool Ready => workingClock != null && gameplayClock != null; + public int Value => timestamps.Count(isTimestampWithinSpan); + + private KeysPerSecondCalculator(GameplayClock gameplayClock, DrawableRuleset drawableRuleset) + { + instance = this; + timestamps = new List(); + this.gameplayClock = gameplayClock ?? throw new ArgumentNullException(nameof(gameplayClock)); + this.drawableRuleset = drawableRuleset; + onNewInput += addTimestamp; + } + + private void addTimestamp() + { + if (workingClock != null && workingClock.CurrentTime >= maxTime) + { + timestamps.Add(workingClock.CurrentTime); + maxTime = workingClock.CurrentTime; + } + } + + private bool isTimestampWithinSpan(double timestamp) + { + if (!Ready) + return false; + + double span = 1000 * rate; + double relativeTime = workingClock.CurrentTime - timestamp; + return relativeTime >= 0 && relativeTime <= span; + } + + public void Dispose() + { + instance = null; + } + + ~KeysPerSecondCalculator() => Dispose(); + } +} diff --git a/osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs similarity index 63% rename from osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs rename to osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs index d32ca1410a..2fcca2ffce 100644 --- a/osu.Game/Screens/Play/HUD/KeysPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs @@ -3,17 +3,12 @@ #nullable disable -using System; -using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Framework.Logging; -using osu.Framework.Timing; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -22,28 +17,20 @@ using osu.Game.Rulesets.UI; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Screens.Play.HUD +namespace osu.Game.Screens.Play.HUD.KPSCounter { public class KeysPerSecondCounter : RollingCounter, ISkinnableDrawable { - private static List timestamps; - private static double maxTime = double.NegativeInfinity; - - private static event Action onNewInput; - - private const int invalidation_timeout = 1000; private const float alpha_when_invalid = 0.3f; private readonly Bindable valid = new Bindable(); - - private static GameplayClock gameplayClock; - private static IClock referenceClock; - - private static IClock clock => referenceClock ?? gameplayClock; + private GameplayClock gameplayClock; [Resolved(canBeNull: true)] private DrawableRuleset drawableRuleset { get; set; } + private KeysPerSecondCalculator calculator => KeysPerSecondCalculator.GetInstance(gameplayClock, drawableRuleset); + [SettingSource("Smoothing time", "How smooth the counter should change\nThe more it is smooth, the less it's accurate.")] public BindableNumber SmoothingTime { get; } = new BindableNumber(350) { @@ -51,66 +38,30 @@ namespace osu.Game.Screens.Play.HUD MinValue = 0 }; - public static void AddTimestamp() - { - Logger.Log($"Input timestamp attempt C: {clock.CurrentTime}ms | GC: {gameplayClock.CurrentTime} | RC: {referenceClock?.CurrentTime ?? -1} | Max: {maxTime})", level: LogLevel.Debug); - - if (clock.CurrentTime >= maxTime) - { - Logger.Log("Input timestamp added.", level: LogLevel.Debug); - timestamps?.Add(clock.CurrentTime); - maxTime = timestamps?.Max() ?? clock.CurrentTime; - } - - onNewInput?.Invoke(); - } - - public static void Reset() - { - timestamps?.Clear(); - maxTime = int.MinValue; - } - protected override double RollingDuration => SmoothingTime.Value; public bool UsesFixedAnchor { get; set; } public KeysPerSecondCounter() { - timestamps ??= new List(); Current.Value = 0; - onNewInput += updateCounter; - Scheduler.AddOnce(updateCounter); } [BackgroundDependencyLoader] - private void load(OsuColour colours, GameplayClock clock) + private void load(OsuColour colours, GameplayClock clock, DrawableRuleset ruleset) { gameplayClock = clock; Colour = colours.BlueLighter; valid.BindValueChanged(e => DrawableCount.FadeTo(e.NewValue ? 1 : alpha_when_invalid, 1000, Easing.OutQuint)); - referenceClock = drawableRuleset?.FrameStableClock; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - updateCounter(); } protected override void Update() { base.Update(); - updateCounter(); - } - - private void updateCounter() - { - valid.Value = timestamps != null && MathHelper.ApproximatelyEquivalent(gameplayClock.CurrentTime, referenceClock.CurrentTime, 500); - Current.Value = timestamps?.Count(timestamp => clock.CurrentTime - timestamp is >= 0 and <= invalidation_timeout) ?? 0; + valid.Value = calculator.Ready; + Current.Value = calculator.Value; } protected override IHasText CreateText() => new TextComponent diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs index b8bbac9a7e..044c9ee24e 100644 --- a/osu.Game/Screens/Play/KeyCounter.cs +++ b/osu.Game/Screens/Play/KeyCounter.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.HUD.KPSCounter; using osuTK; using osuTK.Graphics; @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Play public void Increment() { - KeysPerSecondCounter.AddTimestamp(); + KeysPerSecondCalculator.AddInput(); if (!IsCounting) return; diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs index aaf2e997f2..b6094726c0 100644 --- a/osu.Game/Screens/Play/KeyCounterDisplay.cs +++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Configuration; -using osu.Game.Screens.Play.HUD; using osuTK; using osuTK.Graphics; @@ -66,7 +65,6 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - KeysPerSecondCounter.Reset(); config.BindWith(OsuSetting.KeyOverlay, configVisibility); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index fb2f556611..88cd197076 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -34,7 +34,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; -using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.HUD.KPSCounter; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Users; @@ -1046,7 +1046,7 @@ namespace osu.Game.Screens.Play fadeOut(); - KeysPerSecondCounter.Reset(); + KeysPerSecondCalculator.GetInstance().Dispose(); return base.OnExiting(e); } From 0de00e9b3fc4a6351e5c610422f70251dd2477bc Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 4 Aug 2022 19:15:28 +0900 Subject: [PATCH 0276/2686] Don't serialise empty mod settings --- osu.Game.Tests/Online/TestAPIModJsonSerialization.cs | 11 +++++++++++ osu.Game/Online/API/APIMod.cs | 9 ++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs index 67dbcf0ccf..7458508c7a 100644 --- a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs +++ b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using NUnit.Framework; using osu.Framework.Bindables; using osu.Game.Beatmaps; @@ -148,6 +149,16 @@ namespace osu.Game.Tests.Online Assert.That(apiMod.Settings["speed_change"], Is.EqualTo(1.01d)); } + [Test] + public void TestSerialisedModSettingPresence() + { + var mod = new TestMod(); + + mod.TestSetting.Value = mod.TestSetting.Default; + JObject serialised = JObject.Parse(JsonConvert.SerializeObject(new APIMod(mod))); + Assert.False(serialised.ContainsKey("settings")); + } + private class TestRuleset : Ruleset { public override IEnumerable GetModsFor(ModType type) => new Mod[] diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 900f59290c..dcbaaea012 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -1,11 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using MessagePack; using Newtonsoft.Json; @@ -23,7 +20,7 @@ namespace osu.Game.Online.API { [JsonProperty("acronym")] [Key(0)] - public string Acronym { get; set; } + public string Acronym { get; set; } = string.Empty; [JsonProperty("settings")] [Key(1)] @@ -49,7 +46,7 @@ namespace osu.Game.Online.API } } - public Mod ToMod([NotNull] Ruleset ruleset) + public Mod ToMod(Ruleset ruleset) { Mod resultMod = ruleset.CreateModFromAcronym(Acronym); @@ -80,6 +77,8 @@ namespace osu.Game.Online.API return resultMod; } + public bool ShouldSerializeSettings() => Settings.Count > 0; + public bool Equals(APIMod other) { if (ReferenceEquals(null, other)) return false; From 786af81274064ea3afa3f40dfd0b6b683db80075 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 14:15:01 +0900 Subject: [PATCH 0277/2686] Fix `PreviewTrack` not disposing its owned audio `Track` --- osu.Game/Audio/PreviewTrack.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 7fb92f9f9d..2409ca6eb6 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -105,5 +105,11 @@ namespace osu.Game.Audio /// Retrieves the audio track. /// protected abstract Track? GetTrack(); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + Track?.Dispose(); + } } } From 68232826045bb182f4098496ed497ffcfb2933f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 14:15:27 +0900 Subject: [PATCH 0278/2686] Fix `PlayButton` potentially not disposing an unused `PreviewTrack` during load --- osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs index e840d0e82c..0ce55ce549 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs @@ -147,7 +147,10 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { // beatmapset may have changed. if (Preview != preview) + { + preview?.Dispose(); return; + } AddInternal(preview); loading = false; From 7c952f806969d4b15d6507a54c4d8b55213c2fdf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 14:25:10 +0900 Subject: [PATCH 0279/2686] Add more test coverage of locally-modified state change --- .../Visual/Editing/TestSceneEditorBeatmapCreation.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index a21f66a7cb..80a5b4832b 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -56,8 +56,10 @@ namespace osu.Game.Tests.Visual.Editing [Test] public void TestCreateNewBeatmap() { + AddAssert("status is none", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.None); AddStep("save beatmap", () => Editor.Save()); AddAssert("new beatmap in database", () => beatmapManager.QueryBeatmapSet(s => s.ID == currentBeatmapSetID)?.Value.DeletePending == false); + AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified); } [Test] @@ -208,6 +210,8 @@ namespace osu.Game.Tests.Visual.Editing }); AddAssert("created difficulty has no objects", () => EditorBeatmap.HitObjects.Count == 0); + AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified); + AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = secondDifficultyName); AddStep("save beatmap", () => Editor.Save()); AddAssert("new beatmap persisted", () => @@ -218,7 +222,7 @@ namespace osu.Game.Tests.Visual.Editing return beatmap != null && beatmap.DifficultyName == secondDifficultyName && set != null - && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Beatmaps.Any(b => b.DifficultyName == secondDifficultyName)); + && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Beatmaps.Any(b => b.DifficultyName == secondDifficultyName) && s.Beatmaps.All(b => s.Status == BeatmapOnlineStatus.LocallyModified)); }); } From 94ec6534201c50a7574f1afeaa651af1d4b7dcc6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 14:26:01 +0900 Subject: [PATCH 0280/2686] Add same load-cancel safeties to ensure tracks are disposed in card `PlayButton` --- osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs index 18eab09465..8ab632a757 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs @@ -118,7 +118,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons // another async load might have completed before this one. // if so, do not make any changes. if (loadedPreview != previewTrack) + { + loadedPreview.Dispose(); return; + } AddInternal(loadedPreview); toggleLoading(false); From 84a3fbd25cb29bc41a976810200d4a30ec8a11e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 17:36:48 +0900 Subject: [PATCH 0281/2686] Version realm files for debug executions To make it easier for developers to test out pull requests which bump the realm schema version, realm files are now stored with the schema version in the filename. Note that this means any changes made to a newer version will not be applied to previous ones. --- osu.Game/Database/RealmAccess.cs | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 5f0ec67c71..9e964750a8 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -172,6 +172,10 @@ namespace osu.Game.Database if (!Filename.EndsWith(realm_extension, StringComparison.Ordinal)) Filename += realm_extension; +#if DEBUG + Filename = applyFilenameSchemaSuffix(Filename); +#endif + string newerVersionFilename = $"{Filename.Replace(realm_extension, string.Empty)}_newer_version{realm_extension}"; // Attempt to recover a newer database version if available. @@ -211,6 +215,50 @@ namespace osu.Game.Database } } + /// + /// Some developers may be annoyed if a newer version migration (ie. caused by testing a pull request) + /// cause their test database to be unusable with previous versions. + /// To get around this, store development databases against their realm version. + /// Note that this means changes made on newer realm versions will disappear. + /// + private string applyFilenameSchemaSuffix(string filename) + { + string proposedFilename = getVersionedFilename(schema_version); + + // First check if the current realm version already exists... + if (storage.Exists(proposedFilename)) + return proposedFilename; + + // If a non-versioned file exists (aka before this method was added), move it to the new versioned + // format. + if (storage.Exists(filename)) + { + Logger.Log(@$"Moving non-versioned realm file {filename} to {proposedFilename}"); + storage.Move(filename, proposedFilename); + return proposedFilename; + } + + // If it doesn't, check for a previous version we can use as a base database to migrate from... + for (int i = schema_version - 1; i >= 0; i--) + { + string iFilename = getVersionedFilename(i); + + if (storage.Exists(iFilename)) + { + using (var previous = storage.GetStream(iFilename)) + using (var current = storage.CreateFileSafely(proposedFilename)) + { + Logger.Log(@$"Using previous realm database {iFilename} to migrate new schema version {schema_version}"); + previous.CopyTo(current); + } + } + } + + return proposedFilename; + + string getVersionedFilename(int version) => filename.Replace(realm_extension, $"_{version}{realm_extension}"); + } + private void attemptRecoverFromFile(string recoveryFilename) { Logger.Log($@"Performing recovery from {recoveryFilename}", LoggingTarget.Database); From 3c84b1a389905ec61295afee2e284f27975b69ed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 17:48:51 +0900 Subject: [PATCH 0282/2686] Change order of application to use original `client.realm` last --- osu.Game/Database/RealmAccess.cs | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 9e964750a8..65cad5bdf0 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -173,7 +173,7 @@ namespace osu.Game.Database Filename += realm_extension; #if DEBUG - Filename = applyFilenameSchemaSuffix(Filename); + applyFilenameSchemaSuffix(ref Filename); #endif string newerVersionFilename = $"{Filename.Replace(realm_extension, string.Empty)}_newer_version{realm_extension}"; @@ -221,24 +221,17 @@ namespace osu.Game.Database /// To get around this, store development databases against their realm version. /// Note that this means changes made on newer realm versions will disappear. /// - private string applyFilenameSchemaSuffix(string filename) + private void applyFilenameSchemaSuffix(ref string filename) { - string proposedFilename = getVersionedFilename(schema_version); + string originalFilename = filename; + + filename = getVersionedFilename(schema_version); // First check if the current realm version already exists... - if (storage.Exists(proposedFilename)) - return proposedFilename; - - // If a non-versioned file exists (aka before this method was added), move it to the new versioned - // format. if (storage.Exists(filename)) - { - Logger.Log(@$"Moving non-versioned realm file {filename} to {proposedFilename}"); - storage.Move(filename, proposedFilename); - return proposedFilename; - } + return; - // If it doesn't, check for a previous version we can use as a base database to migrate from... + // Check for a previous version we can use as a base database to migrate from... for (int i = schema_version - 1; i >= 0; i--) { string iFilename = getVersionedFilename(i); @@ -246,7 +239,7 @@ namespace osu.Game.Database if (storage.Exists(iFilename)) { using (var previous = storage.GetStream(iFilename)) - using (var current = storage.CreateFileSafely(proposedFilename)) + using (var current = storage.CreateFileSafely(filename)) { Logger.Log(@$"Using previous realm database {iFilename} to migrate new schema version {schema_version}"); previous.CopyTo(current); @@ -254,9 +247,14 @@ namespace osu.Game.Database } } - return proposedFilename; + // Finally, check for a non-versioned file exists (aka before this method was added)... + if (storage.Exists(originalFilename)) + { + Logger.Log(@$"Moving non-versioned realm file {filename} to {filename}"); + storage.Move(filename, filename); + } - string getVersionedFilename(int version) => filename.Replace(realm_extension, $"_{version}{realm_extension}"); + string getVersionedFilename(int version) => originalFilename.Replace(realm_extension, $"_{version}{realm_extension}"); } private void attemptRecoverFromFile(string recoveryFilename) From 8ae54296026768958cf8df215dc2b5231dbe7898 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 18:08:02 +0900 Subject: [PATCH 0283/2686] Adjust slider pooling based on beatmap Handles edge cases like mentioned in https://github.com/ppy/osu/issues/19585. --- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 25 ++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 3179b37d5a..175c444f4e 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -11,9 +11,11 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -112,17 +114,28 @@ namespace osu.Game.Rulesets.Osu.UI } [BackgroundDependencyLoader(true)] - private void load(OsuRulesetConfigManager config) + private void load(OsuRulesetConfigManager config, IBeatmap beatmap) { config?.BindWith(OsuRulesetSetting.PlayfieldBorderStyle, playfieldBorder.PlayfieldBorderStyle); RegisterPool(10, 100); + var osuBeatmap = (OsuBeatmap)beatmap; - RegisterPool(10, 100); - RegisterPool(10, 100); - RegisterPool(10, 100); - RegisterPool(10, 100); - RegisterPool(5, 50); + + var sliders = osuBeatmap.HitObjects.OfType(); + + if (sliders.Any()) + { + // handle edge cases where a beatmap has a slider with many repeats. + int maxRepeatsOnOneSlider = osuBeatmap.HitObjects.OfType().Max(s => s.RepeatCount); + int maxTicksOnOneSlider = osuBeatmap.HitObjects.OfType().Max(s => s.NestedHitObjects.OfType().Count()); + + RegisterPool(20, 100); + RegisterPool(20, 100); + RegisterPool(20, 100); + RegisterPool(Math.Max(maxTicksOnOneSlider, 20), Math.Max(maxTicksOnOneSlider, 200)); + RegisterPool(Math.Max(maxRepeatsOnOneSlider, 20), Math.Max(maxRepeatsOnOneSlider, 200)); + } RegisterPool(2, 20); RegisterPool(10, 100); From 9a4d0494de1de4000a3b2c3f64db1568cb5fd254 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 18:09:07 +0900 Subject: [PATCH 0284/2686] Adjust various pooling defaults to better handle more intense beatmaps --- .../Objects/Drawables/Connections/FollowPointRenderer.cs | 2 +- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs index 4949abccab..306b034645 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections { InternalChildren = new Drawable[] { - connectionPool = new DrawablePool(1, 200), + connectionPool = new DrawablePool(10, 200), pointPool = new DrawablePool(50, 1000) }; } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 175c444f4e..edfa92e629 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -118,9 +118,9 @@ namespace osu.Game.Rulesets.Osu.UI { config?.BindWith(OsuRulesetSetting.PlayfieldBorderStyle, playfieldBorder.PlayfieldBorderStyle); - RegisterPool(10, 100); var osuBeatmap = (OsuBeatmap)beatmap; + RegisterPool(20, 100); var sliders = osuBeatmap.HitObjects.OfType(); @@ -138,8 +138,8 @@ namespace osu.Game.Rulesets.Osu.UI } RegisterPool(2, 20); - RegisterPool(10, 100); - RegisterPool(10, 100); + RegisterPool(10, 200); + RegisterPool(10, 200); } protected override HitObjectLifetimeEntry CreateLifetimeEntry(HitObject hitObject) => new OsuHitObjectLifetimeEntry(hitObject); @@ -186,7 +186,7 @@ namespace osu.Game.Rulesets.Osu.UI private readonly Action onLoaded; public DrawableJudgementPool(HitResult result, Action onLoaded) - : base(10) + : base(20) { this.result = result; this.onLoaded = onLoaded; From a682a823f43f58857ff7c2c9973be6c48f52b9c9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 18:14:30 +0900 Subject: [PATCH 0285/2686] Fix test failures where `Beatmap` is not provided --- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index edfa92e629..ff79c917cb 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -122,21 +122,24 @@ namespace osu.Game.Rulesets.Osu.UI RegisterPool(20, 100); - var sliders = osuBeatmap.HitObjects.OfType(); + int maxRepeatsOnOneSlider = 0; + int maxTicksOnOneSlider = 0; - if (sliders.Any()) + var sliders = osuBeatmap?.HitObjects.OfType(); + + if (sliders?.Any() == true) { // handle edge cases where a beatmap has a slider with many repeats. - int maxRepeatsOnOneSlider = osuBeatmap.HitObjects.OfType().Max(s => s.RepeatCount); - int maxTicksOnOneSlider = osuBeatmap.HitObjects.OfType().Max(s => s.NestedHitObjects.OfType().Count()); - - RegisterPool(20, 100); - RegisterPool(20, 100); - RegisterPool(20, 100); - RegisterPool(Math.Max(maxTicksOnOneSlider, 20), Math.Max(maxTicksOnOneSlider, 200)); - RegisterPool(Math.Max(maxRepeatsOnOneSlider, 20), Math.Max(maxRepeatsOnOneSlider, 200)); + maxRepeatsOnOneSlider = sliders?.Max(s => s.RepeatCount) ?? 0; + maxTicksOnOneSlider = sliders?.Max(s => s.NestedHitObjects.OfType().Count()) ?? 0; } + RegisterPool(20, 100); + RegisterPool(20, 100); + RegisterPool(20, 100); + RegisterPool(Math.Max(maxTicksOnOneSlider, 20), Math.Max(maxTicksOnOneSlider, 200)); + RegisterPool(Math.Max(maxRepeatsOnOneSlider, 20), Math.Max(maxRepeatsOnOneSlider, 200)); + RegisterPool(2, 20); RegisterPool(10, 200); RegisterPool(10, 200); From ad3d00b1dc5f28c095931cd40c506ddcc580a6df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 18:23:41 +0900 Subject: [PATCH 0286/2686] Don't add version suffixes when running unit tests --- osu.Game/Database/RealmAccess.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 65cad5bdf0..e31c121a9d 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -173,7 +173,8 @@ namespace osu.Game.Database Filename += realm_extension; #if DEBUG - applyFilenameSchemaSuffix(ref Filename); + if (!DebugUtils.IsNUnitRunning) + applyFilenameSchemaSuffix(ref Filename); #endif string newerVersionFilename = $"{Filename.Replace(realm_extension, string.Empty)}_newer_version{realm_extension}"; From 4544df59785e793286ee2a8e195ba7974c428704 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 5 Aug 2022 18:27:29 +0900 Subject: [PATCH 0287/2686] Leave `client.realm` around to handle pull requests without this change merged --- osu.Game/Database/RealmAccess.cs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index e31c121a9d..83a007e4ff 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -235,24 +235,27 @@ namespace osu.Game.Database // Check for a previous version we can use as a base database to migrate from... for (int i = schema_version - 1; i >= 0; i--) { - string iFilename = getVersionedFilename(i); + string previousFilename = getVersionedFilename(i); - if (storage.Exists(iFilename)) + if (storage.Exists(previousFilename)) { - using (var previous = storage.GetStream(iFilename)) - using (var current = storage.CreateFileSafely(filename)) - { - Logger.Log(@$"Using previous realm database {iFilename} to migrate new schema version {schema_version}"); - previous.CopyTo(current); - } + copyPreviousVersion(previousFilename, filename); + return; } } // Finally, check for a non-versioned file exists (aka before this method was added)... if (storage.Exists(originalFilename)) + copyPreviousVersion(originalFilename, filename); + + void copyPreviousVersion(string previousFilename, string newFilename) { - Logger.Log(@$"Moving non-versioned realm file {filename} to {filename}"); - storage.Move(filename, filename); + using (var previous = storage.GetStream(previousFilename)) + using (var current = storage.CreateFileSafely(newFilename)) + { + Logger.Log(@$"Copying previous realm database {previousFilename} to {newFilename} for migration to schema version {schema_version}"); + previous.CopyTo(current); + } } string getVersionedFilename(int version) => originalFilename.Replace(realm_extension, $"_{version}{realm_extension}"); From 802dc90cb147ff8b5ba22d425218e97fda7032ff Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 5 Aug 2022 20:36:28 +0900 Subject: [PATCH 0288/2686] Adjust using directives for vertices --- osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs | 2 +- osu.Game/Graphics/Backgrounds/Triangles.cs | 2 +- osu.Game/Graphics/OpenGL/Vertices/PositionAndColourVertex.cs | 2 +- osu.Game/Rulesets/Mods/ModFlashlight.cs | 2 +- osu.Game/Screens/Menu/LogoVisualisation.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 6a25663542..1b2ef23674 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -9,9 +9,9 @@ using System.Runtime.InteropServices; using osu.Framework.Allocation; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; using osu.Framework.Input; diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index ad35c00d2b..1166a86814 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -14,8 +14,8 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Primitives; using osu.Framework.Allocation; using System.Collections.Generic; -using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Lists; namespace osu.Game.Graphics.Backgrounds diff --git a/osu.Game/Graphics/OpenGL/Vertices/PositionAndColourVertex.cs b/osu.Game/Graphics/OpenGL/Vertices/PositionAndColourVertex.cs index a53b665857..78c8cbb79e 100644 --- a/osu.Game/Graphics/OpenGL/Vertices/PositionAndColourVertex.cs +++ b/osu.Game/Graphics/OpenGL/Vertices/PositionAndColourVertex.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.InteropServices; -using osu.Framework.Graphics.OpenGL.Vertices; +using osu.Framework.Graphics.Rendering.Vertices; using osuTK; using osuTK.Graphics; using osuTK.Graphics.ES30; diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 39d0c5c3d1..210dd56137 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -6,9 +6,9 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps.Timing; diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index dbd2fd6d95..c7bda4d8f8 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -9,9 +9,9 @@ using osu.Framework.Audio.Track; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.OpenGL.Vertices; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; From 15fb4d8dd5f3b8ba0b53e34882ef14164c387aa6 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Fri, 5 Aug 2022 12:53:14 +0100 Subject: [PATCH 0289/2686] Change Implementation and name of KeepUprightAndUnstretched --- osu.Game/Extensions/DrawableExtensions.cs | 56 +++++++++++------------ 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index 46105218c5..fd5bbab567 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -81,45 +81,43 @@ namespace osu.Game.Extensions } } + /// /// Keeps the drawable upright and prevents it from being scaled or flipped with its Parent. /// /// The drawable. - public static void KeepUprightAndUnstretched(this Drawable drawable) + public static void KeepUprightAndUnscaled(this Drawable drawable) { - // Fix the rotation - var result = drawable.Parent.DrawInfo; - var scale = result.Matrix.ExtractScale(); - var rotation = new Matrix3( - result.Matrix.Row0 / scale.X, - result.Matrix.Row1 / scale.Y, - new Vector3(0.0f, 0.0f, 1.0f) - ); - rotation.Invert(); - float angle = MathF.Atan(rotation.M12 / rotation.M11); + var parentMatrix = drawable.Parent.DrawInfo.Matrix; + float angle = MathF.Atan(parentMatrix.M12 / parentMatrix.M11); angle *= (360 / (2 * MathF.PI)); - drawable.Rotation = angle; - // Fix the scale (includes flip) - var containerOriginToSpaceOrigin = new Matrix3( - new Vector3(1.0f, 0.0f, 0.0f), - new Vector3(0.0f, 1.0f, 0.0f), - new Vector3(drawable.DrawSize.X / 2, drawable.DrawSize.Y / 2, 1.0f) - ); - var containerOriginToSpaceOriginInverse = containerOriginToSpaceOrigin; - containerOriginToSpaceOriginInverse.Invert(); - Matrix3 rotatedBack = (containerOriginToSpaceOriginInverse * (rotation * (containerOriginToSpaceOrigin * result.Matrix))); + parentMatrix.Transpose(); + parentMatrix.M13 = 0.0f; + parentMatrix.M23 = 0.0f; - bool xFliped = rotation.M11 < 0; - bool yFliped = rotation.M22 < 0; + if ((Math.Abs(Math.Abs(angle) - 90.0)) < 2.0f) + { + Matrix3 m = Matrix3.CreateRotationZ(MathHelper.DegreesToRadians(40.0f)); + m.Transpose(); + parentMatrix *= m; + drawable.Rotation = 40.0f; + } + else + drawable.Rotation = 0.0f; - var rotatedBackScale = rotatedBack.ExtractScale(); + Matrix3 C = parentMatrix.Inverted(); + + float alpha, beta, sx, sy; + sy = C.M22; + alpha = C.M12 / C.M22; + + beta = (C.M21 == 0.0f) ? 0.0f : 1 / ((C.M11 / C.M21) - alpha); + sx = (beta == 0.0f) ? C.M11 : C.M21 / beta; + + drawable.Scale = new Vector2(sx, sy); + drawable.Shear = new Vector2(-alpha, -beta); - drawable.Scale = new Vector2( - (xFliped ? -1 : 1) / rotatedBackScale.X, - (yFliped ? -1 : 1) / rotatedBackScale.Y - ); } - } } From 6afff72865b57099037a1aba4f67930e0cbd27b5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 5 Aug 2022 20:54:10 +0900 Subject: [PATCH 0290/2686] Fix CI inspections / refactor to single enumeration --- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index ff79c917cb..fc2ba8ea2f 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -122,16 +122,17 @@ namespace osu.Game.Rulesets.Osu.UI RegisterPool(20, 100); + // handle edge cases where a beatmap has a slider with many repeats. int maxRepeatsOnOneSlider = 0; int maxTicksOnOneSlider = 0; - var sliders = osuBeatmap?.HitObjects.OfType(); - - if (sliders?.Any() == true) + if (osuBeatmap != null) { - // handle edge cases where a beatmap has a slider with many repeats. - maxRepeatsOnOneSlider = sliders?.Max(s => s.RepeatCount) ?? 0; - maxTicksOnOneSlider = sliders?.Max(s => s.NestedHitObjects.OfType().Count()) ?? 0; + foreach (var slider in osuBeatmap.HitObjects.OfType()) + { + maxRepeatsOnOneSlider = Math.Max(maxRepeatsOnOneSlider, slider.RepeatCount); + maxTicksOnOneSlider = Math.Max(maxTicksOnOneSlider, slider.NestedHitObjects.OfType().Count()); + } } RegisterPool(20, 100); From 8618d9ea0d21ea9f67d9f2f3751c3b7cda08f614 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Fri, 5 Aug 2022 12:55:41 +0100 Subject: [PATCH 0291/2686] Implement GrowToFitContainer --- .../Graphics/Containers/GrowToFitContainer.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 osu.Game/Graphics/Containers/GrowToFitContainer.cs diff --git a/osu.Game/Graphics/Containers/GrowToFitContainer.cs b/osu.Game/Graphics/Containers/GrowToFitContainer.cs new file mode 100644 index 0000000000..6333718928 --- /dev/null +++ b/osu.Game/Graphics/Containers/GrowToFitContainer.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 System; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Graphics.Containers +{ + /// + /// A container that grows in size to fit its child and retains its size when its child shrinks + /// + public class GrowToFitContainer : Container + { + protected override void Update() + { + base.Update(); + Height = Math.Max(Child.Height, Height); + Width = Math.Max(Child.Width, Width); + } + } + +} From 12ef99a1a1534c255138eab4c336f385e145c144 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Fri, 5 Aug 2022 12:56:08 +0100 Subject: [PATCH 0292/2686] Fix text position --- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 49 +++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 656498fc43..8c9f3aaa8d 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -5,15 +5,22 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using System; + namespace osu.Game.Screens.Play.HUD { public class SongProgressInfo : Container { + private GrowToFitContainer timeCurrentContainer; + private GrowToFitContainer timeLeftContainer; + private GrowToFitContainer progressContainer; + private OsuSpriteText timeCurrent; private OsuSpriteText timeLeft; private OsuSpriteText progress; @@ -51,12 +58,14 @@ namespace osu.Game.Screens.Play.HUD { new Container { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, - Children = new Drawable[] + Child = timeCurrentContainer = new GrowToFitContainer { - timeCurrent = new OsuSpriteText + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Child = timeCurrent = new OsuSpriteText { Origin = Anchor.Centre, Anchor = Anchor.Centre, @@ -67,37 +76,37 @@ namespace osu.Game.Screens.Play.HUD }, new Container { - Origin = Anchor.BottomCentre, - Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, - Children = new Drawable[] + Child = timeLeftContainer = new GrowToFitContainer { - progress = new OsuSpriteText + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Child = progress = new OsuSpriteText { Origin = Anchor.Centre, Anchor = Anchor.Centre, Colour = colours.BlueLighter, Font = OsuFont.Numeric, - } + } } }, new Container { - Origin = Anchor.BottomRight, - Anchor = Anchor.BottomRight, + Origin = Anchor.CentreRight, + Anchor = Anchor.CentreRight, AutoSizeAxes = Axes.Both, - Children = new Drawable[] + Child = progressContainer = new GrowToFitContainer { - timeLeft = new OsuSpriteText + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Child = timeLeft = new OsuSpriteText { Origin = Anchor.Centre, Anchor = Anchor.Centre, Colour = colours.BlueLighter, Font = OsuFont.Numeric, - Margin = new MarginPadding - { - Right = margin, - }, } } } @@ -139,9 +148,9 @@ namespace osu.Game.Screens.Play.HUD private void keepTextSpritesUpright() { - timeCurrent.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUprightAndUnstretched(timeCurrent); }; - progress.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUprightAndUnstretched(timeCurrent); }; - timeLeft.OnUpdate += (timeCurrent) => { Extensions.DrawableExtensions.KeepUprightAndUnstretched(timeCurrent); }; + timeCurrentContainer.OnUpdate += (timeCurrentContainer) => { Extensions.DrawableExtensions.KeepUprightAndUnscaled(timeCurrentContainer); }; + progressContainer.OnUpdate += (progressContainer) => { Extensions.DrawableExtensions.KeepUprightAndUnscaled(progressContainer); }; + timeLeftContainer.OnUpdate += (timeLeftContainer) => { Extensions.DrawableExtensions.KeepUprightAndUnscaled(timeLeftContainer); }; } } From 0243f8d6ac0f97716f017468075c6a0ede2aa220 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Fri, 5 Aug 2022 14:28:15 +0100 Subject: [PATCH 0293/2686] Clean up --- osu.Game/Extensions/DrawableExtensions.cs | 4 +--- osu.Game/Graphics/Containers/GrowToFitContainer.cs | 1 - osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 8 +++----- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index fd5bbab567..f587b1c55b 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -81,7 +81,6 @@ namespace osu.Game.Extensions } } - /// /// Keeps the drawable upright and prevents it from being scaled or flipped with its Parent. /// @@ -90,7 +89,7 @@ namespace osu.Game.Extensions { var parentMatrix = drawable.Parent.DrawInfo.Matrix; float angle = MathF.Atan(parentMatrix.M12 / parentMatrix.M11); - angle *= (360 / (2 * MathF.PI)); + angle = MathHelper.RadiansToDegrees(angle); parentMatrix.Transpose(); parentMatrix.M13 = 0.0f; @@ -117,7 +116,6 @@ namespace osu.Game.Extensions drawable.Scale = new Vector2(sx, sy); drawable.Shear = new Vector2(-alpha, -beta); - } } } diff --git a/osu.Game/Graphics/Containers/GrowToFitContainer.cs b/osu.Game/Graphics/Containers/GrowToFitContainer.cs index 6333718928..9b4ad0dba9 100644 --- a/osu.Game/Graphics/Containers/GrowToFitContainer.cs +++ b/osu.Game/Graphics/Containers/GrowToFitContainer.cs @@ -18,5 +18,4 @@ namespace osu.Game.Graphics.Containers Width = Math.Max(Child.Width, Width); } } - } diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 8c9f3aaa8d..34f773509a 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -148,10 +147,9 @@ namespace osu.Game.Screens.Play.HUD private void keepTextSpritesUpright() { - timeCurrentContainer.OnUpdate += (timeCurrentContainer) => { Extensions.DrawableExtensions.KeepUprightAndUnscaled(timeCurrentContainer); }; - progressContainer.OnUpdate += (progressContainer) => { Extensions.DrawableExtensions.KeepUprightAndUnscaled(progressContainer); }; - timeLeftContainer.OnUpdate += (timeLeftContainer) => { Extensions.DrawableExtensions.KeepUprightAndUnscaled(timeLeftContainer); }; + timeCurrentContainer.OnUpdate += Extensions.DrawableExtensions.KeepUprightAndUnscaled; + progressContainer.OnUpdate += Extensions.DrawableExtensions.KeepUprightAndUnscaled; + timeLeftContainer.OnUpdate += Extensions.DrawableExtensions.KeepUprightAndUnscaled; } - } } From 24c29b7e2f5d6ec717a056db1149099c1632df46 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Fri, 5 Aug 2022 15:51:07 +0200 Subject: [PATCH 0294/2686] Do not add KPS calculation when gameplay rate is 0 --- osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs index f9839abde4..5ac3647e0e 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter private void addTimestamp() { - if (workingClock != null && workingClock.CurrentTime >= maxTime) + if (workingClock != null && workingClock.CurrentTime >= maxTime && gameplayClock.TrueGameplayRate > 0) { timestamps.Add(workingClock.CurrentTime); maxTime = workingClock.CurrentTime; From b4e0fa7c53cf3d1a8d580562c8301a6e70d4d2bc Mon Sep 17 00:00:00 2001 From: Ryuki Date: Fri, 5 Aug 2022 15:53:06 +0200 Subject: [PATCH 0295/2686] Rewrite tests for KPS --- .../Gameplay/TestSceneKeyPerSecondCounter.cs | 91 -------------- .../Gameplay/TestSceneKeysPerSecondCounter.cs | 114 ++++++++++-------- 2 files changed, 66 insertions(+), 139 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneKeyPerSecondCounter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyPerSecondCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyPerSecondCounter.cs deleted file mode 100644 index a2eaea29eb..0000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyPerSecondCounter.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Framework.Testing; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mania; -using osu.Game.Rulesets.UI; -using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD.KPSCounter; -using osuTK; - -namespace osu.Game.Tests.Visual.Gameplay -{ - public class TestSceneKeyPerSecondCounter : PlayerTestScene - { - protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); - protected override bool HasCustomSteps => false; - protected override bool Autoplay => true; - - private GameplayClock gameplayClock; - private DrawableRuleset drawableRuleset; - - // private DependencyProvidingContainer dependencyContainer; - private KeysPerSecondCounter counter; - - [SetUpSteps] - public new void SetUpSteps() - { - /* - CreateTest(() => AddStep("Create components", () => - { - Logger.Log($"{(Player != null ? Player.ToString() : "null")}", level: LogLevel.Debug); - dependencyContainer = new DependencyProvidingContainer - { - RelativePositionAxes = Axes.Both, - }; - })); - */ - } - - private void createCounter() - { - AddStep("Create counter", () => - { - /* - if (!Contains(dependencyContainer)) - { - Add(dependencyContainer); - } - - if (dependencyContainer.CachedDependencies.Length == 0) - { - dependencyContainer.CachedDependencies = new (Type, object)[] - { - (typeof(GameplayClock), , - (typeof(DrawableRuleset),) - }; - } - Dependencies.Cache(gameplayClock = Player.GameplayClockContainer.GameplayClock)); - */ - - Dependencies.Cache(gameplayClock = Player.GameplayClockContainer.GameplayClock); - Dependencies.Cache(drawableRuleset = Player.DrawableRuleset); - - Add(counter = new KeysPerSecondCounter - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Scale = new Vector2(5), - Position = new Vector2(10, 100) - } - ); - }); - AddAssert("ensure counter added", () => Contains(counter)); - } - - [Test] - public void TestInGameTimeConsistency() - { - createCounter(); - - AddUntilStep("Wait until first note", () => counter.Current.Value != 0); - AddStep("Pause gameplay", () => gameplayClock.IsPaused.Value = true); - AddAssert("KPS = 1", () => counter.Current.Value == 1); - } - } -} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs index c8c31d1366..0cc9b91d71 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs @@ -3,9 +3,15 @@ #nullable disable +using System.Linq; +using AutoMapper.Internal; using NUnit.Framework; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; -using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD.KPSCounter; using osuTK; @@ -13,63 +19,75 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneKeysPerSecondCounter : OsuManualInputManagerTestScene + public class TestSceneKeysPerSecondCounter : PlayerTestScene { + protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); + protected override bool HasCustomSteps => false; + protected override bool Autoplay => false; + protected override TestPlayer CreatePlayer(Ruleset ruleset) => new TestPlayer(true, false); + + private GameplayClock gameplayClock; + private DrawableRuleset drawableRuleset; + private KeysPerSecondCounter counter; - [SetUpSteps] - public void Setup() + private void createCounter() + { + AddStep("Create counter", () => + { + gameplayClock = Player.GameplayClockContainer.GameplayClock; + drawableRuleset = Player.DrawableRuleset; + + Player.HUDOverlay.Add(counter = new KeysPerSecondCounter + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(5), + }); + counter.SmoothingTime.Value = 0; + }); + AddUntilStep("Counter created", () => Player.HUDOverlay.Contains(counter)); + } + + [Test] + public void TestBasic() { createCounter(); - } - private void createCounter() => AddStep("Create counter", () => - { - Child = counter = new KeysPerSecondCounter + AddStep("press 1 key", () => InputManager.Key(Key.D)); + AddAssert("KPS = 1", () => counter.Current.Value == 1); + AddUntilStep("Wait for KPS cooldown", () => counter.Current.Value <= 0); + AddStep("press 4 keys", () => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(5) - }; - }); - - [Test] - public void TestManualTrigger() - { - AddAssert("Counter = 0", () => counter.Current.Value == 0); - AddRepeatStep("manual trigger", KeysPerSecondCalculator.AddInput, 20); - AddAssert("Counter is not 0", () => counter.Current.Value > 0); - } - - [Test] - public void TestKpsAsideKeyCounter() - { - AddStep("Create key counter display", () => - Add(new KeyCounterDisplay + InputManager.Key(Key.D); + InputManager.Key(Key.F); + InputManager.Key(Key.J); + InputManager.Key(Key.K); + }); + AddAssert("KPS = 4", () => counter.Current.Value == 4); + AddStep("Pause player", () => Player.Pause()); + AddAssert("KPS = 4", () => counter.Current.Value == 4); + AddStep("Resume player", () => Player.Resume()); + AddStep("press 4 keys", () => + { + InputManager.Key(Key.D); + InputManager.Key(Key.F); + InputManager.Key(Key.J); + InputManager.Key(Key.K); + }); + AddAssert("KPS = 8", () => counter.Current.Value == 8); + AddUntilStep("Wait for KPS cooldown", () => counter.Current.Value <= 0); + AddStep("Add DT", () => + { + var dt = new ManiaModDoubleTime { - Origin = Anchor.BottomCentre, - Anchor = Anchor.BottomCentre, - Y = 100, - Children = new KeyCounter[] + SpeedChange = { - new KeyCounterKeyboard(Key.W), - new KeyCounterKeyboard(Key.X), - new KeyCounterKeyboard(Key.C), - new KeyCounterKeyboard(Key.V) + Value = 2 } - }) - ); - AddAssert("Counter = 0", () => counter.Current.Value == 0); - addPressKeyStep(Key.W); - addPressKeyStep(Key.X); - addPressKeyStep(Key.C); - addPressKeyStep(Key.V); - AddAssert("Counter = 4", () => counter.Current.Value == 4); - } - - private void addPressKeyStep(Key key) - { - AddStep($"Press {key} key", () => InputManager.Key(key)); + }; + Player.Mods.Value.Concat((dt.Yield()).ToArray()); + }); } } } From b46bc5d65b9e4441bb3dc4509f4ff328317f22b6 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Fri, 5 Aug 2022 14:57:33 +0100 Subject: [PATCH 0296/2686] Remove empty line --- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 34f773509a..e9d0ffe4b9 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -11,7 +11,6 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using System; - namespace osu.Game.Screens.Play.HUD { public class SongProgressInfo : Container From e0426836c19391139a2976ea364ed0122c94aa77 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Fri, 5 Aug 2022 16:30:07 +0200 Subject: [PATCH 0297/2686] Make swells and drumrolls optional by default --- .../Mods/TestSceneTaikoModClassic.cs | 80 ---------- .../Mods/TestSceneTaikoModPerfect.cs | 4 +- .../TestSceneTaikoSuddenDeath.cs | 4 +- .../Judgements/TaikoDrumRollJudgement.cs | 13 +- .../Judgements/TaikoDrumRollTickJudgement.cs | 14 +- .../Judgements/TaikoSwellJudgement.cs | 7 +- .../Mods/TaikoModClassic.cs | 151 +----------------- .../Objects/Drawables/DrawableDrumRoll.cs | 13 +- .../Objects/Drawables/DrawableSwell.cs | 10 +- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 33 +--- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 3 - 11 files changed, 24 insertions(+), 308 deletions(-) delete mode 100644 osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModClassic.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModClassic.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModClassic.cs deleted file mode 100644 index 9028f411ce..0000000000 --- a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModClassic.cs +++ /dev/null @@ -1,80 +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.Collections.Generic; -using NUnit.Framework; -using osu.Game.Rulesets.Replays; -using osu.Game.Rulesets.Taiko.Beatmaps; -using osu.Game.Rulesets.Taiko.Mods; -using osu.Game.Rulesets.Taiko.Objects; -using osu.Game.Rulesets.Taiko.Replays; - -namespace osu.Game.Rulesets.Taiko.Tests.Mods -{ - public class TestSceneTaikoModClassic : TaikoModTestScene - { - [Test] - public void TestHittingDrumRollsIsOptional() => CreateModTest(new ModTestData - { - Mod = new TaikoModClassic(), - Autoplay = false, - Beatmap = new TaikoBeatmap - { - BeatmapInfo = { Ruleset = CreatePlayerRuleset().RulesetInfo }, - HitObjects = new List - { - new Hit - { - StartTime = 1000, - Type = HitType.Centre - }, - new DrumRoll - { - StartTime = 3000, - EndTime = 6000 - } - } - }, - ReplayFrames = new List - { - new TaikoReplayFrame(1000, TaikoAction.LeftCentre), - new TaikoReplayFrame(1001) - }, - PassCondition = () => Player.ScoreProcessor.HasCompleted.Value - && Player.ScoreProcessor.Combo.Value == 1 - && Player.ScoreProcessor.Accuracy.Value == 1 - }); - - [Test] - public void TestHittingSwellsIsOptional() => CreateModTest(new ModTestData - { - Mod = new TaikoModClassic(), - Autoplay = false, - Beatmap = new TaikoBeatmap - { - BeatmapInfo = { Ruleset = CreatePlayerRuleset().RulesetInfo }, - HitObjects = new List - { - new Hit - { - StartTime = 1000, - Type = HitType.Centre - }, - new Swell - { - StartTime = 3000, - EndTime = 6000 - } - } - }, - ReplayFrames = new List - { - new TaikoReplayFrame(1000, TaikoAction.LeftCentre), - new TaikoReplayFrame(1001) - }, - PassCondition = () => Player.ScoreProcessor.HasCompleted.Value - && Player.ScoreProcessor.Combo.Value == 1 - && Player.ScoreProcessor.Accuracy.Value == 1 - }); - } -} diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs index a83cc16413..92503a9f03 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs @@ -25,11 +25,11 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods [TestCase(false)] [TestCase(true)] - public void TestDrumRoll(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new DrumRoll { StartTime = 1000, EndTime = 3000 }), shouldMiss); + public void TestDrumRoll(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new DrumRoll { StartTime = 1000, EndTime = 3000 }, false), shouldMiss); [TestCase(false)] [TestCase(true)] - public void TestSwell(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Swell { StartTime = 1000, EndTime = 3000 }), shouldMiss); + public void TestSwell(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Swell { StartTime = 1000, EndTime = 3000 }, false), shouldMiss); private class TestTaikoRuleset : TaikoRuleset { diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs index cdfab4a215..2169ac5581 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Tests }; [Test] - public void TestSpinnerDoesFail() + public void TestSwellDoesNotFail() { bool judged = false; AddStep("Setup judgements", () => @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Tests Player.ScoreProcessor.NewJudgement += _ => judged = true; }); AddUntilStep("swell judged", () => judged); - AddAssert("failed", () => Player.GameplayState.HasFailed); + AddAssert("not failed", () => !Player.GameplayState.HasFailed); } } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs index be128d85b5..f7f923e76e 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs @@ -9,17 +9,8 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoDrumRollJudgement : TaikoJudgement { - protected override double HealthIncreaseFor(HitResult result) - { - // Drum rolls can be ignored with no health penalty - switch (result) - { - case HitResult.Miss: - return 0; + public override HitResult MaxResult => HitResult.IgnoreHit; - default: - return base.HealthIncreaseFor(result); - } - } + protected override double HealthIncreaseFor(HitResult result) => 0; } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs index 5f2587a5d5..de56c76f56 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollTickJudgement.cs @@ -9,18 +9,8 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoDrumRollTickJudgement : TaikoJudgement { - public override HitResult MaxResult => HitResult.SmallTickHit; + public override HitResult MaxResult => HitResult.SmallBonus; - protected override double HealthIncreaseFor(HitResult result) - { - switch (result) - { - case HitResult.SmallTickHit: - return 0.15; - - default: - return 0; - } - } + protected override double HealthIncreaseFor(HitResult result) => 0; } } diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs index 6d469bd1d7..146621997d 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs @@ -9,16 +9,13 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoSwellJudgement : TaikoJudgement { - /// - /// The to grant when the player has hit more than half of swell ticks. - /// - public virtual HitResult PartialCompletionResult => HitResult.Ok; + public override HitResult MaxResult => HitResult.LargeBonus; protected override double HealthIncreaseFor(HitResult result) { switch (result) { - case HitResult.Miss: + case HitResult.IgnoreMiss: return -0.65; default: diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs index 28124d16e1..f7fdd447d6 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModClassic.cs @@ -1,170 +1,27 @@ // 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.Collections.Generic; using System.Diagnostics; -using System.Threading; -using osu.Game.Beatmaps; -using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Beatmaps; -using osu.Game.Rulesets.Taiko.Judgements; using osu.Game.Rulesets.Taiko.Objects; -using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset, IUpdatableByPlayfield, IApplicableAfterBeatmapConversion + public class TaikoModClassic : ModClassic, IApplicableToDrawableRuleset, IUpdatableByPlayfield { private DrawableTaikoRuleset? drawableTaikoRuleset; public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - var playfield = (TaikoPlayfield)drawableRuleset.Playfield; - playfield.ClassicHitTargetPosition.Value = true; - drawableTaikoRuleset = (DrawableTaikoRuleset)drawableRuleset; drawableTaikoRuleset.LockPlayfieldAspect.Value = false; - drawableTaikoRuleset.Playfield.RegisterPool(5); - drawableTaikoRuleset.Playfield.RegisterPool(100); - drawableTaikoRuleset.Playfield.RegisterPool(5); + var playfield = (TaikoPlayfield)drawableRuleset.Playfield; + playfield.ClassicHitTargetPosition.Value = true; } - public void ApplyToBeatmap(IBeatmap beatmap) - { - var taikoBeatmap = (TaikoBeatmap)beatmap; - - if (taikoBeatmap.HitObjects.Count == 0) return; - - var hitObjects = taikoBeatmap.HitObjects.Select(ho => - { - switch (ho) - { - case DrumRoll drumRoll: - return new ClassicDrumRoll(drumRoll); - - case Swell swell: - return new ClassicSwell(swell); - - default: - return ho; - } - }).ToList(); - - taikoBeatmap.HitObjects = hitObjects; - } - - #region Classic drum roll - - private class TaikoClassicDrumRollJudgement : TaikoDrumRollJudgement - { - public override HitResult MaxResult => HitResult.IgnoreHit; - } - - private class ClassicDrumRoll : DrumRoll - { - public ClassicDrumRoll(DrumRoll original) - { - StartTime = original.StartTime; - Samples = original.Samples; - EndTime = original.EndTime; - Duration = original.Duration; - TickRate = original.TickRate; - RequiredGoodHits = original.RequiredGoodHits; - RequiredGreatHits = original.RequiredGreatHits; - } - - public override Judgement CreateJudgement() => new TaikoClassicDrumRollJudgement(); - - protected override List CreateTicks(CancellationToken cancellationToken) - { - List oldTicks = base.CreateTicks(cancellationToken); - - List newTicks = oldTicks.Select(oldTick => - { - if (oldTick is DrumRollTick drumRollTick) - { - return new ClassicDrumRollTick(drumRollTick); - } - - return oldTick; - }).ToList(); - - return newTicks; - } - } - - private class TaikoClassicDrumRollTickJudgement : TaikoDrumRollTickJudgement - { - public override HitResult MaxResult => HitResult.SmallBonus; - } - - private class ClassicDrumRollTick : DrumRollTick - { - public override Judgement CreateJudgement() => new TaikoClassicDrumRollTickJudgement(); - - public ClassicDrumRollTick(DrumRollTick original) - { - StartTime = original.StartTime; - Samples = original.Samples; - FirstTick = original.FirstTick; - TickSpacing = original.TickSpacing; - } - } - - private class ClassicDrawableDrumRoll : DrawableDrumRoll - { - public override bool DisplayResult => false; - - protected override void CheckForResult(bool userTriggered, double timeOffset) - { - if (userTriggered) - return; - - if (timeOffset < 0) - return; - - ApplyResult(r => r.Type = HitResult.IgnoreHit); - } - } - - #endregion - - #region Classic swell - - private class TaikoClassicSwellJudgement : TaikoSwellJudgement - { - public override HitResult MaxResult => HitResult.LargeBonus; - - public override HitResult PartialCompletionResult => HitResult.SmallBonus; - } - - private class ClassicSwell : Swell - { - public ClassicSwell(Swell original) - { - StartTime = original.StartTime; - Samples = original.Samples; - EndTime = original.EndTime; - Duration = original.Duration; - RequiredHits = original.RequiredHits; - } - - public override Judgement CreateJudgement() => new TaikoClassicSwellJudgement(); - } - - private class ClassicDrawableSwell : DrawableSwell - { - public override bool DisplayResult => false; - } - - #endregion - public void Update(Playfield playfield) { Debug.Assert(drawableTaikoRuleset != null); @@ -172,8 +29,6 @@ namespace osu.Game.Rulesets.Taiko.Mods // Classic taiko scrolls at a constant 100px per 1000ms. More notes become visible as the playfield is lengthened. const float scroll_rate = 10; - Debug.Assert(drawableTaikoRuleset != null); - // Since the time range will depend on a positional value, it is referenced to the x480 pixel space. float ratio = drawableTaikoRuleset.DrawHeight / 480; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 04ed6d0b87..418c4673e2 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -4,7 +4,6 @@ #nullable disable using System; -using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Utils; @@ -16,7 +15,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; using osuTK; @@ -40,6 +38,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private Color4 colourIdle; private Color4 colourEngaged; + public override bool DisplayResult => false; + public DrawableDrumRoll() : this(null) { @@ -140,14 +140,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables if (timeOffset < 0) return; - int countHit = NestedHitObjects.Count(o => o.IsHit); - - if (countHit >= HitObject.RequiredGoodHits) - { - ApplyResult(r => r.Type = countHit >= HitObject.RequiredGreatHits ? HitResult.Great : HitResult.Ok); - } - else - ApplyResult(r => r.Type = r.Judgement.MinResult); + ApplyResult(r => r.Type = r.Judgement.MinResult); } protected override void UpdateHitStateTransforms(ArmedState state) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index a90e9ce676..84edb30890 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Taiko.Judgements; +using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; @@ -39,6 +39,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables private readonly CircularContainer targetRing; private readonly CircularContainer expandingRing; + public override bool DisplayResult => false; + public DrawableSwell() : this(null) { @@ -222,11 +224,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables tick.TriggerResult(false); } - ApplyResult(r => - { - var swellJudgement = (TaikoSwellJudgement)r.Judgement; - r.Type = numHits > HitObject.RequiredHits / 2 ? swellJudgement.PartialCompletionResult : swellJudgement.MinResult; - }); + ApplyResult(r => r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.SmallBonus : r.Judgement.MinResult); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 21c7f13fec..db752c6691 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -4,8 +4,6 @@ #nullable disable using osu.Game.Rulesets.Objects.Types; -using System; -using System.Collections.Generic; using System.Threading; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -43,24 +41,12 @@ namespace osu.Game.Rulesets.Taiko.Objects /// public int TickRate = 1; - /// - /// Number of drum roll ticks required for a "Good" hit. - /// - public double RequiredGoodHits { get; protected set; } - - /// - /// Number of drum roll ticks required for a "Great" hit. - /// - public double RequiredGreatHits { get; protected set; } - /// /// The length (in milliseconds) between ticks of this drumroll. /// Half of this value is the hit window of the ticks. /// private double tickSpacing = 100; - private float overallDifficulty = BeatmapDifficulty.DEFAULT_DIFFICULTY; - protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty) { base.ApplyDefaultsToSelf(controlPointInfo, difficulty); @@ -71,28 +57,19 @@ namespace osu.Game.Rulesets.Taiko.Objects Velocity = scoringDistance / timingPoint.BeatLength; tickSpacing = timingPoint.BeatLength / TickRate; - overallDifficulty = difficulty.OverallDifficulty; } protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { - foreach (TaikoHitObject tick in CreateTicks(cancellationToken)) - { - AddNested(tick); - } - - RequiredGoodHits = NestedHitObjects.Count * Math.Min(0.15, 0.05 + 0.10 / 6 * overallDifficulty); - RequiredGreatHits = NestedHitObjects.Count * Math.Min(0.30, 0.10 + 0.20 / 6 * overallDifficulty); + createTicks(cancellationToken); base.CreateNestedHitObjects(cancellationToken); } - protected virtual List CreateTicks(CancellationToken cancellationToken) + private void createTicks(CancellationToken cancellationToken) { - List ticks = new List(); - if (tickSpacing == 0) - return ticks; + return; bool first = true; @@ -100,7 +77,7 @@ namespace osu.Game.Rulesets.Taiko.Objects { cancellationToken.ThrowIfCancellationRequested(); - ticks.Add(new DrumRollTick + AddNested(new DrumRollTick { FirstTick = first, TickSpacing = tickSpacing, @@ -110,8 +87,6 @@ namespace osu.Game.Rulesets.Taiko.Objects first = false; } - - return ticks; } public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index eb0706f131..499bb8cf1d 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -196,9 +196,6 @@ namespace osu.Game.Rulesets.Taiko { switch (result) { - case HitResult.SmallTickHit: - return "drum tick"; - case HitResult.SmallBonus: return "bonus"; } From 0c07df2c267c36fb1c5ac5cf4dae095b94d01521 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Fri, 5 Aug 2022 17:04:33 +0200 Subject: [PATCH 0298/2686] Remove DT from KPS test --- .../Gameplay/TestSceneKeysPerSecondCounter.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs index 0cc9b91d71..6e59c53a1f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs @@ -3,14 +3,10 @@ #nullable disable -using System.Linq; -using AutoMapper.Internal; using NUnit.Framework; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Game.Rulesets; using osu.Game.Rulesets.Mania; -using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD.KPSCounter; @@ -76,18 +72,6 @@ namespace osu.Game.Tests.Visual.Gameplay InputManager.Key(Key.K); }); AddAssert("KPS = 8", () => counter.Current.Value == 8); - AddUntilStep("Wait for KPS cooldown", () => counter.Current.Value <= 0); - AddStep("Add DT", () => - { - var dt = new ManiaModDoubleTime - { - SpeedChange = - { - Value = 2 - } - }; - Player.Mods.Value.Concat((dt.Yield()).ToArray()); - }); } } } From 0886137e39b965571143387cd44b516b185fd189 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Fri, 5 Aug 2022 16:31:20 +0200 Subject: [PATCH 0299/2686] Prevent KeysPerSecondCounter from NRE when no instance is initialized --- .../Play/HUD/KPSCounter/KeysPerSecondCalculator.cs | 8 ++++---- osu.Game/Screens/Play/Player.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs index 5ac3647e0e..a29f4c9706 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter public static void AddInput() { - instance?.onNewInput.Invoke(); + instance?.onNewInput?.Invoke(); } public static KeysPerSecondCalculator GetInstance(GameplayClock gameplayClock = null, DrawableRuleset drawableRuleset = null) @@ -41,9 +41,9 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter private event Action onNewInput; - private IClock workingClock => (IClock)drawableRuleset.FrameStableClock ?? gameplayClock; + private IClock workingClock => (IClock)drawableRuleset?.FrameStableClock ?? gameplayClock; - // Having the rate from mods is preffered to using GameplayClock.TrueGameplayRate() + // Having the rate from mods is preferred to using GameplayClock.TrueGameplayRate() // as it returns 0 when paused in replays, not useful for players who want to "analyze" a replay. private double rate => (drawableRuleset.Mods.FirstOrDefault(m => m is ModRateAdjust) as ModRateAdjust)?.SpeedChange.Value ?? 1; @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter private void addTimestamp() { - if (workingClock != null && workingClock.CurrentTime >= maxTime && gameplayClock.TrueGameplayRate > 0) + if (Ready && workingClock.CurrentTime >= maxTime && gameplayClock.TrueGameplayRate > 0) { timestamps.Add(workingClock.CurrentTime); maxTime = workingClock.CurrentTime; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 88cd197076..70b1dc9a41 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -1046,7 +1046,7 @@ namespace osu.Game.Screens.Play fadeOut(); - KeysPerSecondCalculator.GetInstance().Dispose(); + KeysPerSecondCalculator.GetInstance()?.Dispose(); return base.OnExiting(e); } From 6717f0606cf904e28ebce9156937439fa7e226a5 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Fri, 5 Aug 2022 23:00:37 +0200 Subject: [PATCH 0300/2686] Add property to SkipOverlay --- osu.Game/Screens/Play/SkipOverlay.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 3e2cf9a756..646d2c1762 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -8,6 +8,7 @@ using osu.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.Shapes; @@ -40,6 +41,8 @@ namespace osu.Game.Screens.Play private bool isClickable; + public BindableBool IsSkippable = new()!; + [Resolved] private GameplayClock gameplayClock { get; set; } @@ -134,6 +137,7 @@ namespace osu.Game.Screens.Play remainingTimeBox.Width = (float)Interpolation.Lerp(remainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1)); isClickable = progress > 0; + IsSkippable.Value = isClickable; button.Enabled.Value = isClickable; buttonContainer.State.Value = isClickable ? Visibility.Visible : Visibility.Hidden; } From 99e07aa09a0a0f5176fd9fad7c233405d02cf901 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Fri, 5 Aug 2022 23:01:52 +0200 Subject: [PATCH 0301/2686] Skip intro if the map gets restarted --- osu.Game/Screens/Play/Player.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9c08c77d91..91c13d95de 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -441,6 +441,12 @@ namespace osu.Game.Screens.Play }, }; + skipIntroOverlay.IsSkippable.ValueChanged += (e) => + { + if (RestartCount > 0 && e.NewValue) + skipIntroOverlay.RequestSkip.Invoke(); + }; + if (!Configuration.AllowSkipping || !DrawableRuleset.AllowGameplayOverlays) { skipIntroOverlay.Expire(); From d8d7423698c457258797eb63fa8c16a78b101375 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Fri, 5 Aug 2022 23:04:43 +0200 Subject: [PATCH 0302/2686] Reduce "wait time" in case restarting the map --- osu.Game/Screens/Play/PlayerLoader.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 674490d595..96aefd56ea 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -384,9 +384,10 @@ namespace osu.Game.Screens.Play private void contentIn() { MetadataInfo.Loading = true; + int scaleContentTime = restartCount > 0 ? 65 : 650; content.FadeInFromZero(400); - content.ScaleTo(1, 650, Easing.OutQuint).Then().Schedule(prepareNewPlayer); + content.ScaleTo(1, scaleContentTime, Easing.OutQuint).Then().Schedule(prepareNewPlayer); lowPassFilter.CutoffTo(1000, 650, Easing.OutQuint); highPassFilter.CutoffTo(300).Then().CutoffTo(0, 1250); // 1250 is to line up with the appearance of MetadataInfo (750 delay + 500 fade-in) @@ -468,7 +469,7 @@ namespace osu.Game.Screens.Play else this.Exit(); }); - }, 500); + }, CurrentPlayer?.RestartCount > 0 ? 50 : 500); } private void cancelLoad() From 445f9217568581fa2ed54f6f1f1727ed7f6f0a0b Mon Sep 17 00:00:00 2001 From: BlauFx Date: Fri, 5 Aug 2022 23:21:03 +0200 Subject: [PATCH 0303/2686] Move IsSkippable event into load method --- osu.Game/Screens/Play/Player.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 91c13d95de..e7f9e7b0d2 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -365,6 +365,12 @@ namespace osu.Game.Screens.Play IsBreakTime.BindTo(breakTracker.IsBreakTime); IsBreakTime.BindValueChanged(onBreakTimeChanged, true); + + skipIntroOverlay.IsSkippable.ValueChanged += (e) => + { + if (RestartCount > 0 && e.NewValue) + skipIntroOverlay.RequestSkip.Invoke(); + }; } protected virtual GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) => new MasterGameplayClockContainer(beatmap, gameplayStart); @@ -441,12 +447,6 @@ namespace osu.Game.Screens.Play }, }; - skipIntroOverlay.IsSkippable.ValueChanged += (e) => - { - if (RestartCount > 0 && e.NewValue) - skipIntroOverlay.RequestSkip.Invoke(); - }; - if (!Configuration.AllowSkipping || !DrawableRuleset.AllowGameplayOverlays) { skipIntroOverlay.Expire(); From 84ef24c34108a2021a1da2e4444bce0453211996 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 6 Aug 2022 05:12:18 +0300 Subject: [PATCH 0304/2686] Fix multi-spectator potentially getting stuck for passed players --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 8270bb3b6f..5cd9e0ddf9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -231,6 +231,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate if (state.State == SpectatedUserState.Passed || state.State == SpectatedUserState.Failed) return; + // we could also potentially receive EndGameplay with "Playing" state, at which point we can only early-return and hope it's a passing player. + // todo: this shouldn't exist, but it's here as a hotfix for an issue with multi-spectator screen not proceeding to results screen. + // see: https://github.com/ppy/osu/issues/19593 + if (state.State == SpectatedUserState.Playing) + return; + RemoveUser(userId); var instance = instances.Single(i => i.UserId == userId); From 789e8b4d8d54f1ac3095b446e8068d7245eed90c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 6 Aug 2022 05:20:46 +0300 Subject: [PATCH 0305/2686] Fix multi-spectator test updating state after removing user Removing user triggers `playingUsers.Remove`, but doing so before updating the state leads to `EndGameplay` being called with `State == Playing` rather than `Quit`. --- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index d626426e6d..706d493fd6 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -432,8 +432,8 @@ namespace osu.Game.Tests.Visual.Multiplayer { var user = playingUsers.Single(u => u.UserID == userId); - OnlinePlayDependencies.MultiplayerClient.RemoveUser(user.User.AsNonNull()); SpectatorClient.SendEndPlay(userId); + OnlinePlayDependencies.MultiplayerClient.RemoveUser(user.User.AsNonNull()); playingUsers.Remove(user); }); From 3000d9b9c6b816f7e29e28e39d7e985624e6f49d Mon Sep 17 00:00:00 2001 From: LukynkaCZE <48604271+LukynkaCZE@users.noreply.github.com> Date: Sat, 6 Aug 2022 07:16:34 +0200 Subject: [PATCH 0306/2686] Inline everything in RecentActivityIcon --- .../Profile/Sections/Recent/BeatmapIcon.cs | 93 --------------- .../Sections/Recent/DrawableRecentActivity.cs | 109 ++---------------- .../Profile/Sections/Recent/OtherIcon.cs | 25 ---- .../Sections/Recent/RecentActivityIcon.cs | 92 +++++++++++++++ .../Profile/Sections/Recent/SupporterIcon.cs | 59 ---------- 5 files changed, 99 insertions(+), 279 deletions(-) delete mode 100644 osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs delete mode 100644 osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs create mode 100644 osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs delete mode 100644 osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs diff --git a/osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs deleted file mode 100644 index 9fac1caff4..0000000000 --- a/osu.Game/Overlays/Profile/Sections/Recent/BeatmapIcon.cs +++ /dev/null @@ -1,93 +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.Graphics.Containers; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Allocation; -using osu.Game.Graphics; -using osuTK.Graphics; - -namespace osu.Game.Overlays.Profile.Sections.Recent -{ - public class BeatmapIcon : Container - { - private readonly SpriteIcon icon; - private readonly BeatmapActionType type; - - public enum BeatmapActionType - { - PlayedTimes, - Qualified, - Deleted, - Revived, - Updated, - Submitted - } - - public BeatmapIcon(BeatmapActionType type) - { - this.type = type; - Child = icon = new SpriteIcon - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - icon.Icon = getIcon(type); - icon.Colour = getColor(type, colours); - } - - private IconUsage getIcon(BeatmapActionType type) - { - switch (type) - { - case BeatmapActionType.Qualified: - - case BeatmapActionType.Submitted: - return FontAwesome.Solid.ArrowUp; - - case BeatmapActionType.Updated: - return FontAwesome.Solid.SyncAlt; - - case BeatmapActionType.Revived: - return FontAwesome.Solid.TrashRestore; - - case BeatmapActionType.Deleted: - return FontAwesome.Solid.TrashAlt; - - case BeatmapActionType.PlayedTimes: - return FontAwesome.Solid.Play; - - default: - return FontAwesome.Solid.Map; - } - } - - private Color4 getColor(BeatmapActionType type, OsuColour colours) - { - switch (type) - { - case BeatmapActionType.Qualified: - return colours.Blue1; - - case BeatmapActionType.Submitted: - return colours.Yellow; - - case BeatmapActionType.Updated: - return colours.Lime1; - - case BeatmapActionType.Deleted: - return colours.Red1; - - default: - return Color4.White; - } - } - } -} diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 5acbb58049..bb867a075a 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -16,8 +16,6 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Online.Leaderboards; using osu.Game.Rulesets; -using static osu.Game.Overlays.Profile.Sections.Recent.BeatmapIcon; -using static osu.Game.Overlays.Profile.Sections.Recent.SupporterIcon; namespace osu.Game.Overlays.Profile.Sections.Recent { @@ -121,107 +119,14 @@ namespace osu.Game.Overlays.Profile.Sections.Recent Height = 18 }; - case RecentActivityType.UserSupportAgain: - return new SupporterIcon(SupporterType.SupportAgain) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - - case RecentActivityType.UserSupportFirst: - return new SupporterIcon(SupporterType.SupportFirst) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - - case RecentActivityType.UserSupportGift: - return new SupporterIcon(SupporterType.SupportGift) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - - case RecentActivityType.BeatmapsetUpload: - return new BeatmapIcon(BeatmapActionType.Submitted) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - - case RecentActivityType.BeatmapsetUpdate: - return new BeatmapIcon(BeatmapActionType.Updated) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - - case RecentActivityType.BeatmapsetRevive: - return new BeatmapIcon(BeatmapActionType.Revived) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - - case RecentActivityType.BeatmapsetDelete: - return new BeatmapIcon(BeatmapActionType.Deleted) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - - case RecentActivityType.BeatmapsetApprove: - return new BeatmapIcon(BeatmapActionType.Qualified) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - - case RecentActivityType.BeatmapPlaycount: - return new BeatmapIcon(BeatmapActionType.PlayedTimes) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - - case RecentActivityType.RankLost: - return new OtherIcon(FontAwesome.Solid.AngleDoubleDown) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - - case RecentActivityType.UsernameChange: - return new OtherIcon(FontAwesome.Solid.Tag) - { - RelativeSizeAxes = Axes.X, - Height = 11, - FillMode = FillMode.Fit, - Margin = new MarginPadding { Top = 2, Vertical = 2 } - }; - default: - return Empty(); + return new RecentActivityIcon(activity.Type) + { + RelativeSizeAxes = Axes.X, + Height = 11, + FillMode = FillMode.Fit, + Margin = new MarginPadding { Top = 2, Vertical = 2 } + }; } } diff --git a/osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs deleted file mode 100644 index 57513b3132..0000000000 --- a/osu.Game/Overlays/Profile/Sections/Recent/OtherIcon.cs +++ /dev/null @@ -1,25 +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.Graphics.Containers; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; - -namespace osu.Game.Overlays.Profile.Sections.Recent -{ - public class OtherIcon : Container - { - public OtherIcon(IconUsage inputIcon) - { - { - Child = new SpriteIcon - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Icon = inputIcon, - }; - } - } - } -} diff --git a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs new file mode 100644 index 0000000000..a85104c89b --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs @@ -0,0 +1,92 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics; +using osu.Game.Online.API.Requests; +using osu.Framework.Allocation; +using osu.Game.Graphics; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Profile.Sections.Recent +{ + public class RecentActivityIcon : Container + { + private readonly SpriteIcon icon; + private readonly RecentActivityType type; + + public RecentActivityIcon(RecentActivityType type) + { + this.type = type; + Child = icon = new SpriteIcon + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + switch (type) + { + case RecentActivityType.BeatmapPlaycount: + icon.Icon = FontAwesome.Solid.Play; + icon.Colour = Color4.White; + break; + + case RecentActivityType.BeatmapsetApprove: + icon.Icon = FontAwesome.Solid.ArrowUp; + icon.Colour = colours.Blue1; + break; + + case RecentActivityType.BeatmapsetDelete: + icon.Icon = FontAwesome.Solid.TrashAlt; + icon.Colour = colours.Red1; + break; + + case RecentActivityType.BeatmapsetRevive: + icon.Icon = FontAwesome.Solid.TrashRestore; + icon.Colour = Color4.White; + break; + + case RecentActivityType.BeatmapsetUpdate: + icon.Icon = FontAwesome.Solid.SyncAlt; + icon.Colour = colours.Lime1; + break; + + case RecentActivityType.BeatmapsetUpload: + icon.Icon = FontAwesome.Solid.ArrowUp; + icon.Colour = colours.Yellow; + break; + + case RecentActivityType.RankLost: + icon.Icon = FontAwesome.Solid.AngleDoubleDown; + icon.Colour = Color4.White; + break; + + case RecentActivityType.UsernameChange: + icon.Icon = FontAwesome.Solid.Tag; + icon.Colour = Color4.White; + break; + + case RecentActivityType.UserSupportAgain: + icon.Icon = FontAwesome.Solid.Heart; + icon.Colour = colours.Pink; + break; + + case RecentActivityType.UserSupportFirst: + icon.Icon = FontAwesome.Solid.Heart; + icon.Colour = colours.Pink; + break; + + case RecentActivityType.UserSupportGift: + icon.Icon = FontAwesome.Solid.Gift; + icon.Colour = colours.Pink; + break; + } + } + } +} diff --git a/osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs deleted file mode 100644 index fa9b5641f0..0000000000 --- a/osu.Game/Overlays/Profile/Sections/Recent/SupporterIcon.cs +++ /dev/null @@ -1,59 +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.Graphics.Containers; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Allocation; -using osu.Game.Graphics; - -namespace osu.Game.Overlays.Profile.Sections.Recent -{ - public class SupporterIcon : Container - { - private readonly SpriteIcon icon; - private readonly SupporterType type; - - public enum SupporterType - { - SupportFirst, - SupportAgain, - SupportGift - } - - public SupporterIcon(SupporterType type) - { - this.type = type; - Child = icon = new SpriteIcon - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - icon.Icon = getIcon(type); - icon.Colour = colours.Pink; - } - - private IconUsage getIcon(SupporterType type) - { - switch (type) - { - case SupporterType.SupportFirst: - - case SupporterType.SupportAgain: - return FontAwesome.Solid.Heart; - - case SupporterType.SupportGift: - return FontAwesome.Solid.Gift; - - default: - return FontAwesome.Solid.Heart; - } - } - } -} From e411a2d18739f958d90dcbedfa38256489a570d7 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Sat, 6 Aug 2022 15:12:36 +0200 Subject: [PATCH 0307/2686] Revert reduced wait time commit --- osu.Game/Screens/Play/PlayerLoader.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 96aefd56ea..674490d595 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -384,10 +384,9 @@ namespace osu.Game.Screens.Play private void contentIn() { MetadataInfo.Loading = true; - int scaleContentTime = restartCount > 0 ? 65 : 650; content.FadeInFromZero(400); - content.ScaleTo(1, scaleContentTime, Easing.OutQuint).Then().Schedule(prepareNewPlayer); + content.ScaleTo(1, 650, Easing.OutQuint).Then().Schedule(prepareNewPlayer); lowPassFilter.CutoffTo(1000, 650, Easing.OutQuint); highPassFilter.CutoffTo(300).Then().CutoffTo(0, 1250); // 1250 is to line up with the appearance of MetadataInfo (750 delay + 500 fade-in) @@ -469,7 +468,7 @@ namespace osu.Game.Screens.Play else this.Exit(); }); - }, CurrentPlayer?.RestartCount > 0 ? 50 : 500); + }, 500); } private void cancelLoad() From 0d418559bc15b958dac1c75604a6596732f537dd Mon Sep 17 00:00:00 2001 From: BlauFx Date: Sat, 6 Aug 2022 17:02:45 +0200 Subject: [PATCH 0308/2686] Skip song intro only in case of a quick restart --- osu.Game/Screens/Play/Player.cs | 7 ++++++- osu.Game/Screens/Play/PlayerLoader.cs | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e7f9e7b0d2..a0e513648a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -81,6 +81,10 @@ namespace osu.Game.Screens.Play private bool isRestarting; + public bool RestartedViaHotkey; + + public Bindable IsRestartingFromHotkey = new Bindable(); + private Bindable mouseWheelDisabled; private readonly Bindable storyboardReplacesBackground = new Bindable(); @@ -287,6 +291,7 @@ namespace osu.Game.Screens.Play { if (!this.IsCurrentScreen()) return; + IsRestartingFromHotkey.Value = true; fadeOut(true); Restart(); }, @@ -368,7 +373,7 @@ namespace osu.Game.Screens.Play skipIntroOverlay.IsSkippable.ValueChanged += (e) => { - if (RestartCount > 0 && e.NewValue) + if (RestartedViaHotkey && e.NewValue && RestartCount > 0) skipIntroOverlay.RequestSkip.Invoke(); }; } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 674490d595..388d7d6ec5 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -123,6 +123,8 @@ namespace osu.Game.Screens.Play private EpilepsyWarning? epilepsyWarning; + private bool isHotKeyRestart; + [Resolved(CanBeNull = true)] private INotificationOverlay? notificationOverlay { get; set; } @@ -363,9 +365,20 @@ namespace osu.Game.Screens.Play CurrentPlayer = createPlayer(); CurrentPlayer.RestartCount = restartCount++; CurrentPlayer.RestartRequested = restartRequested; + CurrentPlayer.IsRestartingFromHotkey.ValueChanged += e => + { + if (e.NewValue) + isHotKeyRestart = true; + }; LoadTask = LoadComponentAsync(CurrentPlayer, _ => { + if (isHotKeyRestart) + { + CurrentPlayer.RestartedViaHotkey = true; + isHotKeyRestart = false; + } + MetadataInfo.Loading = false; OnPlayerLoaded(); }); From cc353b872ca1e33cdb6679ca2397e8ee5c12ae33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 6 Aug 2022 18:21:57 +0200 Subject: [PATCH 0309/2686] Add test coverage for other approval events --- .../TestSceneUserProfileRecentSection.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs index 163f0e62df..7875a9dfbc 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs @@ -83,6 +83,20 @@ namespace osu.Game.Tests.Visual.Online Beatmap = dummyBeatmap, }, new APIRecentActivity + { + User = dummyUser, + Type = RecentActivityType.BeatmapsetApprove, + Approval = BeatmapApproval.Approved, + Beatmapset = dummyBeatmap, + }, + new APIRecentActivity + { + User = dummyUser, + Type = RecentActivityType.BeatmapsetApprove, + Approval = BeatmapApproval.Loved, + Beatmapset = dummyBeatmap, + }, + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.BeatmapsetApprove, @@ -90,6 +104,13 @@ namespace osu.Game.Tests.Visual.Online Beatmapset = dummyBeatmap, }, new APIRecentActivity + { + User = dummyUser, + Type = RecentActivityType.BeatmapsetApprove, + Approval = BeatmapApproval.Ranked, + Beatmapset = dummyBeatmap, + }, + new APIRecentActivity { User = dummyUser, Type = RecentActivityType.BeatmapsetDelete, From f3ecd73e0b6a72c94a61dbebee7d96c977b4a43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 6 Aug 2022 18:23:15 +0200 Subject: [PATCH 0310/2686] Add references to web source in recent activity icon --- .../Overlays/Profile/Sections/Recent/RecentActivityIcon.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs index a85104c89b..bb3c5bc12e 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs @@ -30,6 +30,9 @@ namespace osu.Game.Overlays.Profile.Sections.Recent [BackgroundDependencyLoader] private void load(OsuColour colours) { + // references: + // https://github.com/ppy/osu-web/blob/659b371dcadf25b4f601a4c9895a813078301084/resources/assets/lib/profile-page/parse-event.tsx + // https://github.com/ppy/osu-web/blob/master/resources/assets/less/bem/profile-extra-entries.less#L98-L128 switch (type) { case RecentActivityType.BeatmapPlaycount: From f1e0dd2da3232ded7288323a4ce5b6fb548a08f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 6 Aug 2022 18:29:24 +0200 Subject: [PATCH 0311/2686] Match approval type-dependent icon appearance with web --- .../Sections/Recent/DrawableRecentActivity.cs | 2 +- .../Sections/Recent/RecentActivityIcon.cs | 36 +++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index bb867a075a..6b71ae73e3 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -120,7 +120,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent }; default: - return new RecentActivityIcon(activity.Type) + return new RecentActivityIcon(activity) { RelativeSizeAxes = Axes.X, Height = 11, diff --git a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs index bb3c5bc12e..53e2bb8bbb 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs @@ -1,12 +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 osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics; using osu.Game.Online.API.Requests; using osu.Framework.Allocation; using osu.Game.Graphics; +using osu.Game.Online.API.Requests.Responses; using osuTK.Graphics; namespace osu.Game.Overlays.Profile.Sections.Recent @@ -14,11 +16,11 @@ namespace osu.Game.Overlays.Profile.Sections.Recent public class RecentActivityIcon : Container { private readonly SpriteIcon icon; - private readonly RecentActivityType type; + private readonly APIRecentActivity activity; - public RecentActivityIcon(RecentActivityType type) + public RecentActivityIcon(APIRecentActivity activity) { - this.type = type; + this.activity = activity; Child = icon = new SpriteIcon { RelativeSizeAxes = Axes.Both, @@ -27,13 +29,16 @@ namespace osu.Game.Overlays.Profile.Sections.Recent }; } + [Resolved] + private OsuColour colours { get; set; } = null!; + [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { // references: // https://github.com/ppy/osu-web/blob/659b371dcadf25b4f601a4c9895a813078301084/resources/assets/lib/profile-page/parse-event.tsx // https://github.com/ppy/osu-web/blob/master/resources/assets/less/bem/profile-extra-entries.less#L98-L128 - switch (type) + switch (activity.Type) { case RecentActivityType.BeatmapPlaycount: icon.Icon = FontAwesome.Solid.Play; @@ -42,7 +47,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent case RecentActivityType.BeatmapsetApprove: icon.Icon = FontAwesome.Solid.ArrowUp; - icon.Colour = colours.Blue1; + icon.Colour = getColorForApprovalType(activity.Approval); break; case RecentActivityType.BeatmapsetDelete: @@ -91,5 +96,24 @@ namespace osu.Game.Overlays.Profile.Sections.Recent break; } } + + private Color4 getColorForApprovalType(BeatmapApproval approvalType) + { + switch (approvalType) + { + case BeatmapApproval.Approved: + case BeatmapApproval.Ranked: + return colours.Lime1; + + case BeatmapApproval.Loved: + return colours.Pink1; + + case BeatmapApproval.Qualified: + return colours.Blue1; + + default: + throw new ArgumentOutOfRangeException($"Unsupported {nameof(BeatmapApproval)} type", approvalType, nameof(approvalType)); + } + } } } From 2ba127b6fc089eef7e13d06e9431fd14faeef6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 6 Aug 2022 18:30:49 +0200 Subject: [PATCH 0312/2686] Fix wrong icon for approval event --- osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs index 53e2bb8bbb..3b550921a7 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent break; case RecentActivityType.BeatmapsetApprove: - icon.Icon = FontAwesome.Solid.ArrowUp; + icon.Icon = FontAwesome.Solid.Check; icon.Colour = getColorForApprovalType(activity.Approval); break; From 6a9c30c47a3c9d001055cee42d932283ef1debe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 6 Aug 2022 18:34:00 +0200 Subject: [PATCH 0313/2686] Fix some more wrong icon colours --- .../Overlays/Profile/Sections/Recent/RecentActivityIcon.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs index 3b550921a7..cbd334d707 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs @@ -62,12 +62,12 @@ namespace osu.Game.Overlays.Profile.Sections.Recent case RecentActivityType.BeatmapsetUpdate: icon.Icon = FontAwesome.Solid.SyncAlt; - icon.Colour = colours.Lime1; + icon.Colour = colours.Green1; break; case RecentActivityType.BeatmapsetUpload: icon.Icon = FontAwesome.Solid.ArrowUp; - icon.Colour = colours.Yellow; + icon.Colour = colours.Orange1; break; case RecentActivityType.RankLost: From ab1b38242f765f0a0f119dbe9646c87e7d681815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 6 Aug 2022 18:34:30 +0200 Subject: [PATCH 0314/2686] Reorder enum cases to match web order --- .../Profile/Sections/Recent/RecentActivityIcon.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs index cbd334d707..c55eedd1ed 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs @@ -75,11 +75,6 @@ namespace osu.Game.Overlays.Profile.Sections.Recent icon.Colour = Color4.White; break; - case RecentActivityType.UsernameChange: - icon.Icon = FontAwesome.Solid.Tag; - icon.Colour = Color4.White; - break; - case RecentActivityType.UserSupportAgain: icon.Icon = FontAwesome.Solid.Heart; icon.Colour = colours.Pink; @@ -94,6 +89,11 @@ namespace osu.Game.Overlays.Profile.Sections.Recent icon.Icon = FontAwesome.Solid.Gift; icon.Colour = colours.Pink; break; + + case RecentActivityType.UsernameChange: + icon.Icon = FontAwesome.Solid.Tag; + icon.Colour = Color4.White; + break; } } From fa6d55b5b5e69d4c61c965b02d42e84eec86c911 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Sat, 6 Aug 2022 18:47:11 +0200 Subject: [PATCH 0315/2686] Remove redundant lambda signature parentheses --- 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 a0e513648a..3087b56833 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -371,7 +371,7 @@ namespace osu.Game.Screens.Play IsBreakTime.BindTo(breakTracker.IsBreakTime); IsBreakTime.BindValueChanged(onBreakTimeChanged, true); - skipIntroOverlay.IsSkippable.ValueChanged += (e) => + skipIntroOverlay.IsSkippable.ValueChanged += e => { if (RestartedViaHotkey && e.NewValue && RestartCount > 0) skipIntroOverlay.RequestSkip.Invoke(); From bd43a9e96e377f4c57ef639cb180f1a62576880e Mon Sep 17 00:00:00 2001 From: BlauFx Date: Sat, 6 Aug 2022 18:49:07 +0200 Subject: [PATCH 0316/2686] Add missing type specification --- osu.Game/Screens/Play/SkipOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 646d2c1762..a5f6bf3fee 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Play private bool isClickable; - public BindableBool IsSkippable = new()!; + public BindableBool IsSkippable = new BindableBool()!; [Resolved] private GameplayClock gameplayClock { get; set; } From a0d093be5c087deff6e589e9a189798c83025c2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 21:20:27 +0200 Subject: [PATCH 0317/2686] Extract common implementation of delete dialog --- .../Collections/DeleteCollectionDialog.cs | 20 +-------- .../DeleteConfirmationDialogStrings.cs | 29 +++++++++++++ .../Dialog/DeleteConfirmationDialog.cs | 42 +++++++++++++++++++ .../MassDeleteConfirmationDialog.cs | 21 +--------- .../MassVideoDeleteConfirmationDialog.cs | 2 - .../Select/BeatmapClearScoresDialog.cs | 28 +++---------- .../Screens/Select/BeatmapDeleteDialog.cs | 35 ++++------------ .../Screens/Select/LocalScoreDeleteDialog.cs | 29 ++----------- osu.Game/Screens/Select/SkinDeleteDialog.cs | 36 +++++----------- 9 files changed, 105 insertions(+), 137 deletions(-) create mode 100644 osu.Game/Localisation/DeleteConfirmationDialogStrings.cs create mode 100644 osu.Game/Overlays/Dialog/DeleteConfirmationDialog.cs diff --git a/osu.Game/Collections/DeleteCollectionDialog.cs b/osu.Game/Collections/DeleteCollectionDialog.cs index f3f038a7f0..bf187265c1 100644 --- a/osu.Game/Collections/DeleteCollectionDialog.cs +++ b/osu.Game/Collections/DeleteCollectionDialog.cs @@ -3,33 +3,17 @@ using System; using Humanizer; -using osu.Framework.Graphics.Sprites; using osu.Game.Database; using osu.Game.Overlays.Dialog; namespace osu.Game.Collections { - public class DeleteCollectionDialog : PopupDialog + public class DeleteCollectionDialog : DeleteConfirmationDialog { public DeleteCollectionDialog(Live collection, Action deleteAction) { - HeaderText = "Confirm deletion of"; BodyText = collection.PerformRead(c => $"{c.Name} ({"beatmap".ToQuantity(c.BeatmapMD5Hashes.Count)})"); - - Icon = FontAwesome.Regular.TrashAlt; - - Buttons = new PopupDialogButton[] - { - new PopupDialogOkButton - { - Text = @"Yes. Go for it.", - Action = deleteAction - }, - new PopupDialogCancelButton - { - Text = @"No! Abort mission!", - }, - }; + DeleteAction = deleteAction; } } } diff --git a/osu.Game/Localisation/DeleteConfirmationDialogStrings.cs b/osu.Game/Localisation/DeleteConfirmationDialogStrings.cs new file mode 100644 index 0000000000..33738fe95e --- /dev/null +++ b/osu.Game/Localisation/DeleteConfirmationDialogStrings.cs @@ -0,0 +1,29 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class DeleteConfirmationDialogStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.DeleteConfirmationDialog"; + + /// + /// "Confirm deletion of" + /// + public static LocalisableString HeaderText => new TranslatableString(getKey(@"header_text"), @"Confirm deletion of"); + + /// + /// "Yes. Go for it." + /// + public static LocalisableString Confirm => new TranslatableString(getKey(@"confirm"), @"Yes. Go for it."); + + /// + /// "No! Abort mission" + /// + public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"No! Abort mission"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Dialog/DeleteConfirmationDialog.cs b/osu.Game/Overlays/Dialog/DeleteConfirmationDialog.cs new file mode 100644 index 0000000000..fd26dd7e8e --- /dev/null +++ b/osu.Game/Overlays/Dialog/DeleteConfirmationDialog.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 System; +using osu.Framework.Graphics.Sprites; +using osu.Game.Localisation; + +namespace osu.Game.Overlays.Dialog +{ + /// + /// Base class for various confirmation dialogs that concern deletion actions. + /// Differs from in that the confirmation button is a "dangerous" one + /// (requires the confirm button to be held). + /// + public abstract class DeleteConfirmationDialog : PopupDialog + { + /// + /// The action which performs the deletion. + /// + protected Action? DeleteAction { get; set; } + + protected DeleteConfirmationDialog() + { + HeaderText = DeleteConfirmationDialogStrings.HeaderText; + + Icon = FontAwesome.Regular.TrashAlt; + + Buttons = new PopupDialogButton[] + { + new PopupDialogDangerousButton + { + Text = DeleteConfirmationDialogStrings.Confirm, + Action = () => DeleteAction?.Invoke() + }, + new PopupDialogCancelButton + { + Text = DeleteConfirmationDialogStrings.Cancel + } + }; + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs index 526c096493..19e6f83dac 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs @@ -1,34 +1,17 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; -using osu.Framework.Graphics.Sprites; using osu.Game.Overlays.Dialog; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class MassDeleteConfirmationDialog : PopupDialog + public class MassDeleteConfirmationDialog : DeleteConfirmationDialog { public MassDeleteConfirmationDialog(Action deleteAction) { BodyText = "Everything?"; - - Icon = FontAwesome.Regular.TrashAlt; - HeaderText = @"Confirm deletion of"; - Buttons = new PopupDialogButton[] - { - new PopupDialogDangerousButton - { - Text = @"Yes. Go for it.", - Action = deleteAction - }, - new PopupDialogCancelButton - { - Text = @"No! Abort mission!", - }, - }; + DeleteAction = deleteAction; } } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs index e3870bc76a..fc8c9d497b 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.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. -#nullable disable - using System; namespace osu.Game.Overlays.Settings.Sections.Maintenance diff --git a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs index 84426d230b..0996e3e202 100644 --- a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs +++ b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs @@ -1,43 +1,27 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Threading.Tasks; using osu.Framework.Allocation; -using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; using osu.Game.Overlays.Dialog; using osu.Game.Scoring; namespace osu.Game.Screens.Select { - public class BeatmapClearScoresDialog : PopupDialog + public class BeatmapClearScoresDialog : DeleteConfirmationDialog { [Resolved] - private ScoreManager scoreManager { get; set; } + private ScoreManager scoreManager { get; set; } = null!; public BeatmapClearScoresDialog(BeatmapInfo beatmapInfo, Action onCompletion) { - BodyText = beatmapInfo.GetDisplayTitle(); - Icon = FontAwesome.Solid.Eraser; - HeaderText = @"Clearing all local scores. Are you sure?"; - Buttons = new PopupDialogButton[] + BodyText = $"All local scores on {beatmapInfo.GetDisplayTitle()}"; + DeleteAction = () => { - new PopupDialogOkButton - { - Text = @"Yes. Please.", - Action = () => - { - Task.Run(() => scoreManager.Delete(beatmapInfo)) - .ContinueWith(_ => onCompletion); - } - }, - new PopupDialogCancelButton - { - Text = @"No, I'm still attached.", - }, + Task.Run(() => scoreManager.Delete(beatmapInfo)) + .ContinueWith(_ => onCompletion); }; } } diff --git a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs index e3b83d5780..3d3e8b6d73 100644 --- a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs +++ b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs @@ -1,43 +1,26 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; -using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Select { - public class BeatmapDeleteDialog : PopupDialog + public class BeatmapDeleteDialog : DeleteConfirmationDialog { - private BeatmapManager manager; + private readonly BeatmapSetInfo beatmapSet; + + public BeatmapDeleteDialog(BeatmapSetInfo beatmapSet) + { + this.beatmapSet = beatmapSet; + BodyText = $@"{beatmapSet.Metadata.Artist} - {beatmapSet.Metadata.Title}"; + } [BackgroundDependencyLoader] private void load(BeatmapManager beatmapManager) { - manager = beatmapManager; - } - - public BeatmapDeleteDialog(BeatmapSetInfo beatmap) - { - BodyText = $@"{beatmap.Metadata.Artist} - {beatmap.Metadata.Title}"; - - Icon = FontAwesome.Regular.TrashAlt; - HeaderText = @"Confirm deletion of"; - Buttons = new PopupDialogButton[] - { - new PopupDialogDangerousButton - { - Text = @"Yes. Totally. Delete it.", - Action = () => manager?.Delete(beatmap), - }, - new PopupDialogCancelButton - { - Text = @"Firetruck, I didn't mean to!", - }, - }; + DeleteAction = () => beatmapManager.Delete(beatmapSet); } } } diff --git a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs index 3c05a1fa5a..d9312679bc 100644 --- a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs +++ b/osu.Game/Screens/Select/LocalScoreDeleteDialog.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. -#nullable disable - using osu.Framework.Allocation; using osu.Game.Overlays.Dialog; using osu.Game.Scoring; @@ -12,44 +10,25 @@ using osu.Game.Beatmaps; namespace osu.Game.Screens.Select { - public class LocalScoreDeleteDialog : PopupDialog + public class LocalScoreDeleteDialog : DeleteConfirmationDialog { private readonly ScoreInfo score; - [Resolved] - private ScoreManager scoreManager { get; set; } - - [Resolved] - private BeatmapManager beatmapManager { get; set; } - public LocalScoreDeleteDialog(ScoreInfo score) { this.score = score; - Debug.Assert(score != null); } [BackgroundDependencyLoader] - private void load() + private void load(BeatmapManager beatmapManager, ScoreManager scoreManager) { - BeatmapInfo beatmapInfo = beatmapManager.QueryBeatmap(b => b.ID == score.BeatmapInfoID); + BeatmapInfo? beatmapInfo = beatmapManager.QueryBeatmap(b => b.ID == score.BeatmapInfoID); Debug.Assert(beatmapInfo != null); BodyText = $"{score.User} ({score.DisplayAccuracy}, {score.Rank})"; Icon = FontAwesome.Regular.TrashAlt; - HeaderText = "Confirm deletion of local score"; - Buttons = new PopupDialogButton[] - { - new PopupDialogDangerousButton - { - Text = "Yes. Please.", - Action = () => scoreManager?.Delete(score) - }, - new PopupDialogCancelButton - { - Text = "No, I'm still attached.", - }, - }; + DeleteAction = () => scoreManager.Delete(score); } } } diff --git a/osu.Game/Screens/Select/SkinDeleteDialog.cs b/osu.Game/Screens/Select/SkinDeleteDialog.cs index 8defd6347a..c701d9049f 100644 --- a/osu.Game/Screens/Select/SkinDeleteDialog.cs +++ b/osu.Game/Screens/Select/SkinDeleteDialog.cs @@ -1,43 +1,29 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; -using osu.Framework.Graphics.Sprites; using osu.Game.Skinning; using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Select { - public class SkinDeleteDialog : PopupDialog + public class SkinDeleteDialog : DeleteConfirmationDialog { - [Resolved] - private SkinManager manager { get; set; } + private readonly Skin skin; public SkinDeleteDialog(Skin skin) { + this.skin = skin; BodyText = skin.SkinInfo.Value.Name; - Icon = FontAwesome.Regular.TrashAlt; - HeaderText = @"Confirm deletion of"; - Buttons = new PopupDialogButton[] - { - new PopupDialogDangerousButton - { - Text = @"Yes. Totally. Delete it.", - Action = () => - { - if (manager == null) - return; + } - manager.Delete(skin.SkinInfo.Value); - manager.CurrentSkinInfo.SetDefault(); - }, - }, - new PopupDialogCancelButton - { - Text = @"Firetruck, I didn't mean to!", - }, + [BackgroundDependencyLoader] + private void load(SkinManager manager) + { + DeleteAction = () => + { + manager.Delete(skin.SkinInfo.Value); + manager.CurrentSkinInfo.SetDefault(); }; } } From 26b9adbe0cb0a6496f28ea480490a36fb6a6393c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 6 Aug 2022 21:07:21 +0200 Subject: [PATCH 0318/2686] Adjust collection deletion test to match new expectations --- .../Visual/Collections/TestSceneManageCollectionsDialog.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs index 4f7d3a4403..77e781bfe4 100644 --- a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs +++ b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs @@ -200,10 +200,12 @@ namespace osu.Game.Tests.Visual.Collections AddStep("click confirmation", () => { InputManager.MoveMouseTo(dialogOverlay.CurrentDialog.ChildrenOfType().First()); - InputManager.Click(MouseButton.Left); + InputManager.PressButton(MouseButton.Left); }); assertCollectionCount(0); + + AddStep("release mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); } [Test] From 9b3183b2b4aad7cabb9fe8cf2931beed6ac815fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 22:03:31 +0200 Subject: [PATCH 0319/2686] Implement mod preset deletion flow --- .../UserInterface/TestSceneModPresetColumn.cs | 18 +++++++++++++--- .../Overlays/Mods/DeleteModPresetDialog.cs | 18 ++++++++++++++++ osu.Game/Overlays/Mods/ModPresetPanel.cs | 21 ++++++++++++++++++- 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Overlays/Mods/DeleteModPresetDialog.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index 05ed03f01d..f960ade77e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Graphics.Cursor; +using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; @@ -35,16 +36,27 @@ namespace osu.Game.Tests.Visual.UserInterface [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + [Cached(typeof(IDialogOverlay))] + private readonly DialogOverlay dialogOverlay = new DialogOverlay(); + [BackgroundDependencyLoader] private void load() { Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(Realm); - base.Content.Add(content = new PopoverContainer + base.Content.AddRange(new Drawable[] { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(30), + new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Both, + Child = content = new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(30), + } + }, + dialogOverlay }); } diff --git a/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs b/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs new file mode 100644 index 0000000000..b3a19e35ce --- /dev/null +++ b/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs @@ -0,0 +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 osu.Game.Database; +using osu.Game.Overlays.Dialog; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Overlays.Mods +{ + public class DeleteModPresetDialog : DeleteConfirmationDialog + { + public DeleteModPresetDialog(Live modPreset) + { + BodyText = modPreset.PerformRead(preset => preset.Name); + DeleteAction = () => modPreset.PerformWrite(preset => preset.DeletePending = true); + } + } +} diff --git a/osu.Game/Overlays/Mods/ModPresetPanel.cs b/osu.Game/Overlays/Mods/ModPresetPanel.cs index a00729d9fd..49e7d55bca 100644 --- a/osu.Game/Overlays/Mods/ModPresetPanel.cs +++ b/osu.Game/Overlays/Mods/ModPresetPanel.cs @@ -4,18 +4,24 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; using osu.Game.Database; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; namespace osu.Game.Overlays.Mods { - public class ModPresetPanel : ModSelectPanel, IHasCustomTooltip + public class ModPresetPanel : ModSelectPanel, IHasCustomTooltip, IHasContextMenu { public readonly Live Preset; public override BindableBool Active { get; } = new BindableBool(); + [Resolved] + private IDialogOverlay? dialogOverlay { get; set; } + public ModPresetPanel(Live preset) { Preset = preset; @@ -30,7 +36,20 @@ namespace osu.Game.Overlays.Mods AccentColour = colours.Orange1; } + #region IHasCustomTooltip + public ModPreset TooltipContent => Preset.Value; public ITooltip GetCustomTooltip() => new ModPresetTooltip(ColourProvider); + + #endregion + + #region IHasContextMenu + + public MenuItem[] ContextMenuItems => new MenuItem[] + { + new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new DeleteModPresetDialog(Preset))) + }; + + #endregion } } From 6f6beddab5de5b36ffc6c72dd6ab19303fc2e8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 23:00:57 +0200 Subject: [PATCH 0320/2686] Add test coverage for mod preset deletion flow --- .../UserInterface/TestSceneModPresetColumn.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index f960ade77e..13f83eac96 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -15,6 +15,7 @@ using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; +using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mania.Mods; @@ -217,6 +218,46 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("popover closed", () => !this.ChildrenOfType().Any()); } + [Test] + public void TestDeleteFlow() + { + ModPresetColumn modPresetColumn = null!; + + AddStep("create content", () => Child = modPresetColumn = new ModPresetColumn + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + AddUntilStep("items loaded", () => modPresetColumn.IsLoaded && modPresetColumn.ItemsLoaded); + AddStep("right click first panel", () => + { + var panel = this.ChildrenOfType().First(); + InputManager.MoveMouseTo(panel); + InputManager.Click(MouseButton.Right); + }); + + AddUntilStep("wait for context menu", () => this.ChildrenOfType().Any()); + AddStep("click delete", () => + { + var deleteItem = this.ChildrenOfType().Single(); + InputManager.MoveMouseTo(deleteItem); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("wait for dialog", () => dialogOverlay.CurrentDialog is DeleteModPresetDialog); + AddStep("hold confirm", () => + { + var confirmButton = this.ChildrenOfType().Single(); + InputManager.MoveMouseTo(confirmButton); + InputManager.PressButton(MouseButton.Left); + }); + AddUntilStep("wait for dialog to close", () => dialogOverlay.CurrentDialog == null); + AddStep("release mouse", () => InputManager.ReleaseButton(MouseButton.Left)); + AddUntilStep("preset deletion occurred", () => this.ChildrenOfType().Count() == 2); + AddAssert("preset soft-deleted", () => Realm.Run(r => r.All().Count(preset => preset.DeletePending) == 1)); + } + private ICollection createTestPresets() => new[] { new ModPreset From b2557a8d2d4ca1ecde0cc6b709085df912316ede Mon Sep 17 00:00:00 2001 From: Ryuki Date: Sun, 7 Aug 2022 00:53:00 +0200 Subject: [PATCH 0321/2686] Refactor KPS - Remove '#nullable disable' in KeysPerSecondCalculator and KeysPerSecondCounter - Remove KeysPerSecondCalculator IDisposable implementation - Make KeysPerSecondCalculator static instance initialized once by KeysPerSecondCounters - Auto transfer dependencies from KeysPerSecondCounter to KeysPerSecondCalculator using Resolved properties - Add internal reset logic to KeysPerSecondCalculator and make it independent from Player - Use GameplayClock.TrueGameplayRate to get real-time rate. If 0 then it defaults to the last non 0 rate if no such mod is enabled --- .../HUD/KPSCounter/KeysPerSecondCalculator.cs | 106 +++++++++++------- .../HUD/KPSCounter/KeysPerSecondCounter.cs | 33 +++--- osu.Game/Screens/Play/Player.cs | 3 - 3 files changed, 81 insertions(+), 61 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs index a29f4c9706..3c0d585984 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -12,59 +10,93 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Play.HUD.KPSCounter { - public class KeysPerSecondCalculator : IDisposable + public class KeysPerSecondCalculator { - private static KeysPerSecondCalculator instance; - public static void AddInput() { - instance?.onNewInput?.Invoke(); - } - - public static KeysPerSecondCalculator GetInstance(GameplayClock gameplayClock = null, DrawableRuleset drawableRuleset = null) - { - if (instance != null) return instance; - - try - { - return new KeysPerSecondCalculator(gameplayClock, drawableRuleset); - } - catch (ArgumentNullException) - { - return null; - } + onNewInput?.Invoke(); } private readonly List timestamps; - private readonly GameplayClock gameplayClock; - private readonly DrawableRuleset drawableRuleset; + private GameplayClock? gameplayClock; + private DrawableRuleset? drawableRuleset; - private event Action onNewInput; + public GameplayClock? GameplayClock + { + get => gameplayClock; + set + { + onResetRequested?.Invoke(); - private IClock workingClock => (IClock)drawableRuleset?.FrameStableClock ?? gameplayClock; + if (value != null) + { + gameplayClock = value; + } + } + } - // Having the rate from mods is preferred to using GameplayClock.TrueGameplayRate() - // as it returns 0 when paused in replays, not useful for players who want to "analyze" a replay. - private double rate => (drawableRuleset.Mods.FirstOrDefault(m => m is ModRateAdjust) as ModRateAdjust)?.SpeedChange.Value + public DrawableRuleset? DrawableRuleset + { + get => drawableRuleset; + set + { + onResetRequested?.Invoke(); + + if (value != null) + { + drawableRuleset = value; + baseRate = (drawableRuleset.Mods.FirstOrDefault(m => m is ModRateAdjust) as ModRateAdjust)?.SpeedChange.Value ?? 1; + } + } + } + + private static event Action? onNewInput; + private static event Action? onResetRequested; + + private IClock? workingClock => drawableRuleset?.FrameStableClock; + + private double baseRate; + + private double rate + { + get + { + if (gameplayClock != null) + { + if (gameplayClock.TrueGameplayRate > 0) + { + baseRate = gameplayClock.TrueGameplayRate; + } + } + + return baseRate; + } + } private double maxTime = double.NegativeInfinity; public bool Ready => workingClock != null && gameplayClock != null; public int Value => timestamps.Count(isTimestampWithinSpan); - private KeysPerSecondCalculator(GameplayClock gameplayClock, DrawableRuleset drawableRuleset) + public KeysPerSecondCalculator() { - instance = this; timestamps = new List(); - this.gameplayClock = gameplayClock ?? throw new ArgumentNullException(nameof(gameplayClock)); - this.drawableRuleset = drawableRuleset; onNewInput += addTimestamp; + onResetRequested += cleanUp; + } + + private void cleanUp() + { + timestamps.Clear(); + maxTime = double.NegativeInfinity; } private void addTimestamp() { - if (Ready && workingClock.CurrentTime >= maxTime && gameplayClock.TrueGameplayRate > 0) + if (workingClock == null) return; + + if (workingClock.CurrentTime >= maxTime) { timestamps.Add(workingClock.CurrentTime); maxTime = workingClock.CurrentTime; @@ -73,19 +105,11 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter private bool isTimestampWithinSpan(double timestamp) { - if (!Ready) - return false; + if (workingClock == null) return false; double span = 1000 * rate; double relativeTime = workingClock.CurrentTime - timestamp; return relativeTime >= 0 && relativeTime <= span; } - - public void Dispose() - { - instance = null; - } - - ~KeysPerSecondCalculator() => Dispose(); } } diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs index 2fcca2ffce..ad7b6c8f5c 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs @@ -1,15 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -24,21 +21,24 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter private const float alpha_when_invalid = 0.3f; private readonly Bindable valid = new Bindable(); - private GameplayClock gameplayClock; + + private static readonly KeysPerSecondCalculator calculator = new KeysPerSecondCalculator(); + + [Resolved] + private GameplayClock? gameplayClock + { + get => calculator.GameplayClock; + set => calculator.GameplayClock = value; + } [Resolved(canBeNull: true)] - private DrawableRuleset drawableRuleset { get; set; } - - private KeysPerSecondCalculator calculator => KeysPerSecondCalculator.GetInstance(gameplayClock, drawableRuleset); - - [SettingSource("Smoothing time", "How smooth the counter should change\nThe more it is smooth, the less it's accurate.")] - public BindableNumber SmoothingTime { get; } = new BindableNumber(350) + private DrawableRuleset? drawableRuleset { - MaxValue = 1000, - MinValue = 0 - }; + get => calculator.DrawableRuleset; + set => calculator.DrawableRuleset = value; + } - protected override double RollingDuration => SmoothingTime.Value; + protected override double RollingDuration => 350; public bool UsesFixedAnchor { get; set; } @@ -48,9 +48,8 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter } [BackgroundDependencyLoader] - private void load(OsuColour colours, GameplayClock clock, DrawableRuleset ruleset) + private void load(OsuColour colours) { - gameplayClock = clock; Colour = colours.BlueLighter; valid.BindValueChanged(e => DrawableCount.FadeTo(e.NewValue ? 1 : alpha_when_invalid, 1000, Easing.OutQuint)); @@ -61,7 +60,7 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter base.Update(); valid.Value = calculator.Ready; - Current.Value = calculator.Value; + Current.Value = calculator.Ready ? calculator.Value : 0; } protected override IHasText CreateText() => new TextComponent diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 70b1dc9a41..e3844088e2 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -34,7 +34,6 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; -using osu.Game.Screens.Play.HUD.KPSCounter; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Users; @@ -1046,8 +1045,6 @@ namespace osu.Game.Screens.Play fadeOut(); - KeysPerSecondCalculator.GetInstance()?.Dispose(); - return base.OnExiting(e); } From c31e257a1f217db48638b8b9f75824a2d590c98f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 7 Aug 2022 15:16:33 +0900 Subject: [PATCH 0322/2686] Clean up pending deletion presets on startup --- osu.Game/Database/RealmAccess.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 5f0ec67c71..1fb1c1da5c 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -25,6 +25,7 @@ using osu.Game.Configuration; using osu.Game.Input.Bindings; using osu.Game.Models; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Skinning; using Realms; @@ -292,6 +293,11 @@ namespace osu.Game.Database foreach (var s in pendingDeleteSkins) realm.Remove(s); + var pendingDeletePresets = realm.All().Where(s => s.DeletePending); + + foreach (var s in pendingDeletePresets) + realm.Remove(s); + transaction.Commit(); } From 09230304a4f49df8622391b49bab292fd54123f5 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Sun, 7 Aug 2022 13:20:29 +0200 Subject: [PATCH 0323/2686] Improve implementation --- osu.Game/Screens/Play/Player.cs | 11 +++++------ osu.Game/Screens/Play/PlayerConfiguration.cs | 2 ++ osu.Game/Screens/Play/PlayerLoader.cs | 12 ++++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 3087b56833..63e7bcb115 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -81,10 +81,6 @@ namespace osu.Game.Screens.Play private bool isRestarting; - public bool RestartedViaHotkey; - - public Bindable IsRestartingFromHotkey = new Bindable(); - private Bindable mouseWheelDisabled; private readonly Bindable storyboardReplacesBackground = new Bindable(); @@ -291,7 +287,7 @@ namespace osu.Game.Screens.Play { if (!this.IsCurrentScreen()) return; - IsRestartingFromHotkey.Value = true; + Configuration.AutomaticallySkipIntro = true; fadeOut(true); Restart(); }, @@ -373,8 +369,11 @@ namespace osu.Game.Screens.Play skipIntroOverlay.IsSkippable.ValueChanged += e => { - if (RestartedViaHotkey && e.NewValue && RestartCount > 0) + if (Configuration.AutomaticallySkipIntro && e.NewValue && RestartCount > 0) + { + Configuration.AutomaticallySkipIntro = false; skipIntroOverlay.RequestSkip.Invoke(); + } }; } diff --git a/osu.Game/Screens/Play/PlayerConfiguration.cs b/osu.Game/Screens/Play/PlayerConfiguration.cs index d11825baee..0624508584 100644 --- a/osu.Game/Screens/Play/PlayerConfiguration.cs +++ b/osu.Game/Screens/Play/PlayerConfiguration.cs @@ -31,5 +31,7 @@ namespace osu.Game.Screens.Play /// Whether the player should be allowed to skip intros/outros, advancing to the start of gameplay or the end of a storyboard. /// public bool AllowSkipping { get; set; } = true; + + public bool AutomaticallySkipIntro { get; set; } } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 388d7d6ec5..477811a979 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -365,17 +365,12 @@ namespace osu.Game.Screens.Play CurrentPlayer = createPlayer(); CurrentPlayer.RestartCount = restartCount++; CurrentPlayer.RestartRequested = restartRequested; - CurrentPlayer.IsRestartingFromHotkey.ValueChanged += e => - { - if (e.NewValue) - isHotKeyRestart = true; - }; LoadTask = LoadComponentAsync(CurrentPlayer, _ => { if (isHotKeyRestart) { - CurrentPlayer.RestartedViaHotkey = true; + CurrentPlayer.Configuration.AutomaticallySkipIntro = true; isHotKeyRestart = false; } @@ -390,6 +385,11 @@ namespace osu.Game.Screens.Play private void restartRequested() { + if (CurrentPlayer != null) + { + isHotKeyRestart = CurrentPlayer.Configuration.AutomaticallySkipIntro; + } + hideOverlays = true; ValidForResume = true; } From bb344e064fafb25878e006e30c5e77afd9df432b Mon Sep 17 00:00:00 2001 From: BlauFx Date: Sun, 7 Aug 2022 13:31:26 +0200 Subject: [PATCH 0324/2686] Add xml docs --- osu.Game/Screens/Play/PlayerConfiguration.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Play/PlayerConfiguration.cs b/osu.Game/Screens/Play/PlayerConfiguration.cs index 0624508584..b1b0e01d80 100644 --- a/osu.Game/Screens/Play/PlayerConfiguration.cs +++ b/osu.Game/Screens/Play/PlayerConfiguration.cs @@ -32,6 +32,9 @@ namespace osu.Game.Screens.Play /// public bool AllowSkipping { get; set; } = true; + /// + /// Whether the intro should be skipped by default. + /// public bool AutomaticallySkipIntro { get; set; } } } From 0bfa6fa975e5bb3e0510b2c71d9e62416f17bbf2 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Sun, 7 Aug 2022 13:18:29 +0100 Subject: [PATCH 0325/2686] Implement UprightUnscaledContainer --- .../Graphics/Containers/UprightContainer.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 osu.Game/Graphics/Containers/UprightContainer.cs diff --git a/osu.Game/Graphics/Containers/UprightContainer.cs b/osu.Game/Graphics/Containers/UprightContainer.cs new file mode 100644 index 0000000000..21035e82b9 --- /dev/null +++ b/osu.Game/Graphics/Containers/UprightContainer.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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Layout; + +namespace osu.Game.Graphics.Containers +{ + /// + /// A container that prevents itself and its children from getting rotated, scaled or flipped with its Parent. + /// + public class UprightUnscaledContainer : Container + { + public UprightUnscaledContainer() + { + AddLayout(layout); + } + + private LayoutValue layout = new LayoutValue(Invalidation.DrawInfo); + + protected override void Update() + { + base.Update(); + if (!layout.IsValid) + { + Extensions.DrawableExtensions.KeepUprightAndUnscaled(this); + layout.Validate(); + } + } + } +} From ed86255e2b45f7e658b9a47975044652902df107 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Sun, 7 Aug 2022 13:20:22 +0100 Subject: [PATCH 0326/2686] Use UprightUnscaledContainer instead of KeepUprightAndUnscaled --- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 61 ++++++++++--------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index e9d0ffe4b9..069492fd80 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -15,10 +15,6 @@ namespace osu.Game.Screens.Play.HUD { public class SongProgressInfo : Container { - private GrowToFitContainer timeCurrentContainer; - private GrowToFitContainer timeLeftContainer; - private GrowToFitContainer progressContainer; - private OsuSpriteText timeCurrent; private OsuSpriteText timeLeft; private OsuSpriteText progress; @@ -59,16 +55,22 @@ namespace osu.Game.Screens.Play.HUD Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, - Child = timeCurrentContainer = new GrowToFitContainer + Child = new UprightUnscaledContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = timeCurrent = new OsuSpriteText + AutoSizeAxes = Axes.Both, + Child = new GrowToFitContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Colour = colours.BlueLighter, - Font = OsuFont.Numeric, + Child = timeCurrent = new OsuSpriteText + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Colour = colours.BlueLighter, + Font = OsuFont.Numeric, + } } } }, @@ -77,17 +79,23 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, - Child = timeLeftContainer = new GrowToFitContainer + Child = new UprightUnscaledContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = progress = new OsuSpriteText + AutoSizeAxes = Axes.Both, + Child = new GrowToFitContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Colour = colours.BlueLighter, - Font = OsuFont.Numeric, - } + Child = progress = new OsuSpriteText + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Colour = colours.BlueLighter, + Font = OsuFont.Numeric, + } + } } }, new Container @@ -95,28 +103,28 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.CentreRight, Anchor = Anchor.CentreRight, AutoSizeAxes = Axes.Both, - Child = progressContainer = new GrowToFitContainer + Child = new UprightUnscaledContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = timeLeft = new OsuSpriteText + AutoSizeAxes = Axes.Both, + Child = new GrowToFitContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Colour = colours.BlueLighter, - Font = OsuFont.Numeric, + Child = timeLeft = new OsuSpriteText + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Colour = colours.BlueLighter, + Font = OsuFont.Numeric, + } } } } }; } - protected override void LoadComplete() - { - base.LoadComplete(); - keepTextSpritesUpright(); - } - protected override void Update() { base.Update(); @@ -143,12 +151,5 @@ namespace osu.Game.Screens.Play.HUD } private string formatTime(TimeSpan timeSpan) => $"{(timeSpan < TimeSpan.Zero ? "-" : "")}{Math.Floor(timeSpan.Duration().TotalMinutes)}:{timeSpan.Duration().Seconds:D2}"; - - private void keepTextSpritesUpright() - { - timeCurrentContainer.OnUpdate += Extensions.DrawableExtensions.KeepUprightAndUnscaled; - progressContainer.OnUpdate += Extensions.DrawableExtensions.KeepUprightAndUnscaled; - timeLeftContainer.OnUpdate += Extensions.DrawableExtensions.KeepUprightAndUnscaled; - } } } From 25daaa56e2147c3339ed0ea9a95e938a95d21c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 23:08:05 +0200 Subject: [PATCH 0327/2686] Add test coverage for desired external selection behaviour --- .../UserInterface/TestSceneModPresetPanel.cs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs index 92d1cba2c2..b8717c2838 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Database; @@ -37,6 +38,48 @@ namespace osu.Game.Tests.Visual.UserInterface }); } + [Test] + public void TestPresetSelectionStateAfterExternalModChanges() + { + ModPresetPanel? panel = null; + + AddStep("create panel", () => Child = panel = new ModPresetPanel(createTestPresets().First().ToLiveUnmanaged()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f + }); + AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value); + + AddStep("set mods to HR", () => SelectedMods.Value = new[] { new OsuModHardRock() }); + AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value); + + AddStep("set mods to DT", () => SelectedMods.Value = new[] { new OsuModDoubleTime() }); + AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value); + + AddStep("set mods to HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() }); + AddAssert("panel is active", () => panel.AsNonNull().Active.Value); + + AddStep("set mods to HR+customised DT", () => SelectedMods.Value = new Mod[] + { + new OsuModHardRock(), + new OsuModDoubleTime + { + SpeedChange = { Value = 1.25 } + } + }); + AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value); + + AddStep("set mods to HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() }); + AddAssert("panel is active", () => panel.AsNonNull().Active.Value); + + AddStep("customise mod in place", () => SelectedMods.Value.OfType().Single().SpeedChange.Value = 1.33); + AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value); + + AddStep("set mods to HD+HR+DT", () => SelectedMods.Value = new Mod[] { new OsuModHidden(), new OsuModHardRock(), new OsuModDoubleTime() }); + AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value); + } + private static IEnumerable createTestPresets() => new[] { new ModPreset From b1dcd7821c39cd1d8ce65edb91acc8982eb2f225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 23:15:28 +0200 Subject: [PATCH 0328/2686] Automatically toggle preset panels if selected mods match --- osu.Game/Overlays/Mods/ModPresetPanel.cs | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/osu.Game/Overlays/Mods/ModPresetPanel.cs b/osu.Game/Overlays/Mods/ModPresetPanel.cs index 49e7d55bca..c3c4fdff94 100644 --- a/osu.Game/Overlays/Mods/ModPresetPanel.cs +++ b/osu.Game/Overlays/Mods/ModPresetPanel.cs @@ -1,10 +1,12 @@ // 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 osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; +using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; @@ -22,6 +24,11 @@ namespace osu.Game.Overlays.Mods [Resolved] private IDialogOverlay? dialogOverlay { get; set; } + [Resolved] + private IBindable> selectedMods { get; set; } = null!; + + private ModSettingChangeTracker? settingChangeTracker; + public ModPresetPanel(Live preset) { Preset = preset; @@ -36,6 +43,26 @@ namespace osu.Game.Overlays.Mods AccentColour = colours.Orange1; } + protected override void LoadComplete() + { + base.LoadComplete(); + + selectedMods.BindValueChanged(_ => selectedModsChanged(), true); + } + + private void selectedModsChanged() + { + settingChangeTracker?.Dispose(); + settingChangeTracker = new ModSettingChangeTracker(selectedMods.Value); + settingChangeTracker.SettingChanged = _ => updateActiveState(); + updateActiveState(); + } + + private void updateActiveState() + { + Active.Value = new HashSet(Preset.Value.Mods).SetEquals(selectedMods.Value); + } + #region IHasCustomTooltip public ModPreset TooltipContent => Preset.Value; @@ -51,5 +78,12 @@ namespace osu.Game.Overlays.Mods }; #endregion + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + settingChangeTracker?.Dispose(); + } } } From cfd07cb366bb007b3936bc387eebd37857de1f9f Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Sun, 7 Aug 2022 15:04:11 +0100 Subject: [PATCH 0329/2686] Set InvalidationSource to parent and clean up --- .../{UprightContainer.cs => UprightUnscaledContainer.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename osu.Game/Graphics/Containers/{UprightContainer.cs => UprightUnscaledContainer.cs} (95%) diff --git a/osu.Game/Graphics/Containers/UprightContainer.cs b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs similarity index 95% rename from osu.Game/Graphics/Containers/UprightContainer.cs rename to osu.Game/Graphics/Containers/UprightUnscaledContainer.cs index 21035e82b9..cdb839fdec 100644 --- a/osu.Game/Graphics/Containers/UprightContainer.cs +++ b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Graphics.Containers AddLayout(layout); } - private LayoutValue layout = new LayoutValue(Invalidation.DrawInfo); + private LayoutValue layout = new LayoutValue(Invalidation.DrawInfo, InvalidationSource.Parent); protected override void Update() { From de64b835329eaa0a57e09f26b3c1b59bfb4901b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 23:24:30 +0200 Subject: [PATCH 0330/2686] Add test coverage for desired user selection behaviour --- .../UserInterface/TestSceneModPresetPanel.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs index b8717c2838..bcd5579f03 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.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 System.Linq; using NUnit.Framework; @@ -8,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Game.Database; using osu.Game.Overlays; using osu.Game.Overlays.Mods; @@ -24,6 +26,12 @@ namespace osu.Game.Tests.Visual.UserInterface [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + [SetUpSteps] + public void SetUpSteps() + { + AddStep("reset selected mods", () => SelectedMods.SetDefault()); + } + [Test] public void TestVariousModPresets() { @@ -80,6 +88,36 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("panel is not active", () => !panel.AsNonNull().Active.Value); } + [Test] + public void TestActivatingPresetTogglesIncludedMods() + { + ModPresetPanel? panel = null; + + AddStep("create panel", () => Child = panel = new ModPresetPanel(createTestPresets().First().ToLiveUnmanaged()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f + }); + + AddStep("activate panel", () => panel.AsNonNull().TriggerClick()); + assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() }); + + AddStep("deactivate panel", () => panel.AsNonNull().TriggerClick()); + assertSelectedModsEquivalentTo(Array.Empty()); + + AddStep("set different mod", () => SelectedMods.Value = new[] { new OsuModHidden() }); + AddStep("activate panel", () => panel.AsNonNull().TriggerClick()); + assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime() }); + + AddStep("set customised mod", () => SelectedMods.Value = new[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } }); + AddStep("activate panel", () => panel.AsNonNull().TriggerClick()); + assertSelectedModsEquivalentTo(new Mod[] { new OsuModHardRock(), new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } }); + } + + private void assertSelectedModsEquivalentTo(IEnumerable mods) + => AddAssert("selected mods changed correctly", () => new HashSet(SelectedMods.Value).SetEquals(mods)); + private static IEnumerable createTestPresets() => new[] { new ModPreset From 0287c49ca8a9971ccb747d397e64b10c288d98ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 23:35:56 +0200 Subject: [PATCH 0331/2686] Implement user selection logic for mod presets --- osu.Game/Overlays/Mods/ModPresetPanel.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModPresetPanel.cs b/osu.Game/Overlays/Mods/ModPresetPanel.cs index c3c4fdff94..a259645479 100644 --- a/osu.Game/Overlays/Mods/ModPresetPanel.cs +++ b/osu.Game/Overlays/Mods/ModPresetPanel.cs @@ -1,7 +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; using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Cursor; @@ -25,7 +27,7 @@ namespace osu.Game.Overlays.Mods private IDialogOverlay? dialogOverlay { get; set; } [Resolved] - private IBindable> selectedMods { get; set; } = null!; + private Bindable> selectedMods { get; set; } = null!; private ModSettingChangeTracker? settingChangeTracker; @@ -35,6 +37,8 @@ namespace osu.Game.Overlays.Mods Title = preset.Value.Name; Description = preset.Value.Description; + + Action = toggleRequestedByUser; } [BackgroundDependencyLoader] @@ -50,6 +54,17 @@ namespace osu.Game.Overlays.Mods selectedMods.BindValueChanged(_ => selectedModsChanged(), true); } + private void toggleRequestedByUser() + { + // if the preset is not active at the point of the user click, then set the mods using the preset directly, discarding any previous selections. + // if the preset is active when the user has clicked it, then it means that the set of active mods is exactly equal to the set of mods in the preset + // (there are no other active mods than what the preset specifies, and the mod settings match exactly). + // therefore it's safe to just clear selected mods, since it will have the effect of toggling the preset off. + selectedMods.Value = !Active.Value + ? Preset.Value.Mods.ToArray() + : Array.Empty(); + } + private void selectedModsChanged() { settingChangeTracker?.Dispose(); From b318bbd5e64b37d878dd2a1fb1c991f7bdeaf960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 23:43:40 +0200 Subject: [PATCH 0332/2686] Allow non-homogenous column types in mod select overlay --- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 23 +++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index afc6775e83..689c2b4c1e 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -269,7 +269,7 @@ namespace osu.Game.Overlays.Mods /// public void SelectAll() { - foreach (var column in columnFlow.Columns) + foreach (var column in columnFlow.Columns.OfType()) column.SelectAll(); } @@ -278,7 +278,7 @@ namespace osu.Game.Overlays.Mods /// public void DeselectAll() { - foreach (var column in columnFlow.Columns) + foreach (var column in columnFlow.Columns.OfType()) column.DeselectAll(); } @@ -317,7 +317,7 @@ namespace osu.Game.Overlays.Mods AvailableMods.Value = newLocalAvailableMods; filterMods(); - foreach (var column in columnFlow.Columns) + foreach (var column in columnFlow.Columns.OfType()) column.AvailableMods = AvailableMods.Value.GetValueOrDefault(column.ModType, Array.Empty()); } @@ -458,7 +458,7 @@ namespace osu.Game.Overlays.Mods { var column = columnFlow[i].Column; - bool allFiltered = column.AvailableMods.All(modState => modState.Filtered.Value); + bool allFiltered = column is ModColumn modColumn && modColumn.AvailableMods.All(modState => modState.Filtered.Value); double delay = allFiltered ? 0 : nonFilteredColumnCount * 30; double duration = allFiltered ? 0 : fade_in_duration; @@ -516,14 +516,19 @@ namespace osu.Game.Overlays.Mods { var column = columnFlow[i].Column; - bool allFiltered = column.AvailableMods.All(modState => modState.Filtered.Value); + bool allFiltered = false; + + if (column is ModColumn modColumn) + { + allFiltered = modColumn.AvailableMods.All(modState => modState.Filtered.Value); + modColumn.FlushPendingSelections(); + } double duration = allFiltered ? 0 : fade_out_duration; float newYPosition = 0; if (!allFiltered) newYPosition = nonFilteredColumnCount % 2 == 0 ? -distance : distance; - column.FlushPendingSelections(); column.TopLevelContent .MoveToY(newYPosition, duration, Easing.OutQuint) .FadeOut(duration, Easing.OutQuint); @@ -632,7 +637,7 @@ namespace osu.Game.Overlays.Mods /// internal class ColumnFlowContainer : FillFlowContainer { - public IEnumerable Columns => Children.Select(dimWrapper => dimWrapper.Column); + public IEnumerable Columns => Children.Select(dimWrapper => dimWrapper.Column); public override void Add(ColumnDimContainer dimContainer) { @@ -648,7 +653,7 @@ namespace osu.Game.Overlays.Mods /// internal class ColumnDimContainer : Container { - public ModColumn Column { get; } + public ModSelectColumn Column { get; } /// /// Tracks whether this column is in an interactive state. Generally only the case when the column is on-screen. @@ -677,7 +682,7 @@ namespace osu.Game.Overlays.Mods FinishTransforms(); } - protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate || Column.SelectionAnimationRunning; + protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate || (Column as ModColumn)?.SelectionAnimationRunning == true; private void updateState() { From 839409d7accae76f187fb74bf0c9d247f490595d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 23 Jul 2022 23:51:29 +0200 Subject: [PATCH 0333/2686] Add preset column to solo mod select overlay --- .../TestSceneModSelectOverlay.cs | 2 +- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 96 ++++++++++++------- osu.Game/Screens/Select/SongSelect.cs | 7 +- 3 files changed, 68 insertions(+), 37 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 4de70f6f9e..07473aa55b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("any column dimmed", () => this.ChildrenOfType().Any(column => !column.Active.Value)); - ModColumn lastColumn = null; + ModSelectColumn lastColumn = null; AddAssert("last column dimmed", () => !this.ChildrenOfType().Last().Active.Value); AddStep("request scroll to last column", () => diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 689c2b4c1e..adc008e1f7 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -11,12 +11,14 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Localisation; @@ -72,6 +74,11 @@ namespace osu.Game.Overlays.Mods /// protected virtual bool AllowCustomisation => true; + /// + /// Whether the column with available mod presets should be shown. + /// + protected virtual bool ShowPresets => false; + protected virtual ModColumn CreateModColumn(ModType modType) => new ModColumn(modType, false); protected virtual IReadOnlyList ComputeNewModsFromSelection(IReadOnlyList oldSelection, IReadOnlyList newSelection) => newSelection; @@ -139,40 +146,37 @@ namespace osu.Game.Overlays.Mods MainAreaContent.AddRange(new Drawable[] { - new Container + new OsuContextMenuContainer { - Padding = new MarginPadding - { - Top = (ShowTotalMultiplier ? DifficultyMultiplierDisplay.HEIGHT : 0) + PADDING, - Bottom = PADDING - }, RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, - Children = new Drawable[] + Child = new PopoverContainer { - columnScroll = new ColumnScrollContainer + Padding = new MarginPadding { - RelativeSizeAxes = Axes.Both, - Masking = false, - ClampExtension = 100, - ScrollbarOverlapsContent = false, - Child = columnFlow = new ColumnFlowContainer + Top = (ShowTotalMultiplier ? DifficultyMultiplierDisplay.HEIGHT : 0) + PADDING, + Bottom = PADDING + }, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Children = new Drawable[] + { + columnScroll = new ColumnScrollContainer { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Direction = FillDirection.Horizontal, - Shear = new Vector2(SHEAR, 0), - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Margin = new MarginPadding { Horizontal = 70 }, - Padding = new MarginPadding { Bottom = 10 }, - Children = new[] + RelativeSizeAxes = Axes.Both, + Masking = false, + ClampExtension = 100, + ScrollbarOverlapsContent = false, + Child = columnFlow = new ColumnFlowContainer { - createModColumnContent(ModType.DifficultyReduction), - createModColumnContent(ModType.DifficultyIncrease), - createModColumnContent(ModType.Automation), - createModColumnContent(ModType.Conversion), - createModColumnContent(ModType.Fun) + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Direction = FillDirection.Horizontal, + Shear = new Vector2(SHEAR, 0), + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Margin = new MarginPadding { Horizontal = 70 }, + Padding = new MarginPadding { Bottom = 10 }, + ChildrenEnumerable = createColumns() } } } @@ -282,6 +286,23 @@ namespace osu.Game.Overlays.Mods column.DeselectAll(); } + private IEnumerable createColumns() + { + if (ShowPresets) + { + yield return new ColumnDimContainer(new ModPresetColumn + { + Margin = new MarginPadding { Right = 10 } + }); + } + + yield return createModColumnContent(ModType.DifficultyReduction); + yield return createModColumnContent(ModType.DifficultyIncrease); + yield return createModColumnContent(ModType.Automation); + yield return createModColumnContent(ModType.Conversion); + yield return createModColumnContent(ModType.Fun); + } + private ColumnDimContainer createModColumnContent(ModType modType) { var column = CreateModColumn(modType).With(column => @@ -290,12 +311,7 @@ namespace osu.Game.Overlays.Mods column.Margin = new MarginPadding { Right = 10 }; }); - return new ColumnDimContainer(column) - { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - RequestScroll = col => columnScroll.ScrollIntoView(col, extraScroll: 140), - }; + return new ColumnDimContainer(column); } private void createLocalMods() @@ -594,6 +610,7 @@ namespace osu.Game.Overlays.Mods /// /// Manages horizontal scrolling of mod columns, along with the "active" states of each column based on visibility. /// + [Cached] internal class ColumnScrollContainer : OsuScrollContainer { public ColumnScrollContainer() @@ -668,12 +685,21 @@ namespace osu.Game.Overlays.Mods [Resolved] private OsuColour colours { get; set; } = null!; - public ColumnDimContainer(ModColumn column) + public ColumnDimContainer(ModSelectColumn column) { + AutoSizeAxes = Axes.X; + RelativeSizeAxes = Axes.Y; + Child = Column = column; column.Active.BindTo(Active); } + [BackgroundDependencyLoader] + private void load(ColumnScrollContainer columnScroll) + { + RequestScroll = col => columnScroll.ScrollIntoView(col, extraScroll: 140); + } + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 596a8eb896..33ff31857f 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -313,7 +313,7 @@ namespace osu.Game.Screens.Select (new FooterButtonOptions(), BeatmapOptions) }; - protected virtual ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay(); + protected virtual ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay(); protected virtual void ApplyFilterToCarousel(FilterCriteria criteria) { @@ -927,5 +927,10 @@ namespace osu.Game.Screens.Select return base.OnHover(e); } } + + private class SoloModSelectOverlay : UserModSelectOverlay + { + protected override bool ShowPresets => true; + } } } From 7d6efaebbe87743075b11b93d8e8673869c1aff8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 7 Aug 2022 16:05:43 +0200 Subject: [PATCH 0334/2686] Add maintenance settings section for mod presets --- .../MaintenanceSettingsStrings.cs | 10 +++ .../Sections/Maintenance/ModPresetSettings.cs | 89 +++++++++++++++++++ .../Settings/Sections/MaintenanceSection.cs | 3 +- 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs diff --git a/osu.Game/Localisation/MaintenanceSettingsStrings.cs b/osu.Game/Localisation/MaintenanceSettingsStrings.cs index 7a04bcd1ca..a398eced07 100644 --- a/osu.Game/Localisation/MaintenanceSettingsStrings.cs +++ b/osu.Game/Localisation/MaintenanceSettingsStrings.cs @@ -74,6 +74,16 @@ namespace osu.Game.Localisation /// public static LocalisableString RestoreAllRecentlyDeletedBeatmaps => new TranslatableString(getKey(@"restore_all_recently_deleted_beatmaps"), @"Restore all recently deleted beatmaps"); + /// + /// "Delete ALL mod presets" + /// + public static LocalisableString DeleteAllModPresets => new TranslatableString(getKey(@"delete_all_mod_presets"), @"Delete ALL mod presets"); + + /// + /// "Restore all recently deleted mod presets" + /// + public static LocalisableString RestoreAllRecentlyDeletedModPresets => new TranslatableString(getKey(@"restore_all_recently_deleted_mod_presets"), @"Restore all recently deleted mod presets"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs new file mode 100644 index 0000000000..d35d3ff468 --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs @@ -0,0 +1,89 @@ +// 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.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Framework.Logging; +using osu.Game.Database; +using osu.Game.Overlays.Notifications; +using osu.Game.Rulesets.Mods; +using osu.Game.Localisation; + +namespace osu.Game.Overlays.Settings.Sections.Maintenance +{ + public class ModPresetSettings : SettingsSubsection + { + protected override LocalisableString Header => "Mod presets"; + + [Resolved] + private RealmAccess realm { get; set; } = null!; + + [Resolved] + private INotificationOverlay? notificationOverlay { get; set; } + + private SettingsButton undeleteButton = null!; + private SettingsButton deleteAllButton = null!; + + [BackgroundDependencyLoader] + private void load(IDialogOverlay? dialogOverlay) + { + AddRange(new Drawable[] + { + deleteAllButton = new DangerousSettingsButton + { + Text = MaintenanceSettingsStrings.DeleteAllModPresets, + Action = () => + { + dialogOverlay?.Push(new MassDeleteConfirmationDialog(() => + { + deleteAllButton.Enabled.Value = false; + Task.Run(deleteAllModPresets).ContinueWith(t => Schedule(onAllModPresetsDeleted, t)); + })); + } + }, + undeleteButton = new SettingsButton + { + Text = MaintenanceSettingsStrings.RestoreAllRecentlyDeletedModPresets, + Action = () => Task.Run(undeleteModPresets).ContinueWith(t => Schedule(onModPresetsUndeleted, t)) + } + }); + } + + private void deleteAllModPresets() => + realm.Write(r => + { + foreach (var preset in r.All()) + preset.DeletePending = true; + }); + + private void onAllModPresetsDeleted(Task deletionTask) + { + deleteAllButton.Enabled.Value = true; + + if (deletionTask.IsCompletedSuccessfully) + notificationOverlay?.Post(new ProgressCompletionNotification { Text = "Deleted all mod presets!" }); + else if (deletionTask.IsFaulted) + Logger.Error(deletionTask.Exception, "Failed to delete all mod presets"); + } + + private void undeleteModPresets() => + realm.Write(r => + { + foreach (var preset in r.All().Where(preset => preset.DeletePending)) + preset.DeletePending = false; + }); + + private void onModPresetsUndeleted(Task undeletionTask) + { + undeleteButton.Enabled.Value = true; + + if (undeletionTask.IsCompletedSuccessfully) + notificationOverlay?.Post(new ProgressCompletionNotification { Text = "Restored all deleted mod presets!" }); + else if (undeletionTask.IsFaulted) + Logger.Error(undeletionTask.Exception, "Failed to restore mod presets"); + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs index 841a7d0abe..4be6d1653b 100644 --- a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs +++ b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs @@ -25,7 +25,8 @@ namespace osu.Game.Overlays.Settings.Sections new BeatmapSettings(), new SkinSettings(), new CollectionsSettings(), - new ScoreSettings() + new ScoreSettings(), + new ModPresetSettings() }; } } From f75dced30522e562633b706db196bceeceadcefb Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 8 Aug 2022 02:00:24 +0300 Subject: [PATCH 0335/2686] Fix possible null assignment inspection in `TestScenePreviewTrackManager` --- .../Visual/Components/TestScenePreviewTrackManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs index cb29475ba5..94a71ed50c 100644 --- a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs +++ b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs @@ -190,7 +190,7 @@ namespace osu.Game.Tests.Visual.Components AddAssert("track stopped", () => !track.IsRunning); } - private TestPreviewTrackManager.TestPreviewTrack getTrack() => (TestPreviewTrackManager.TestPreviewTrack)trackManager.Get(null); + private TestPreviewTrackManager.TestPreviewTrack getTrack() => (TestPreviewTrackManager.TestPreviewTrack)trackManager.Get(CreateAPIBeatmapSet()); private TestPreviewTrackManager.TestPreviewTrack getOwnedTrack() { From 8b990ef3c90fa83e1530d57aa85f11597074d517 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Aug 2022 12:31:55 +0900 Subject: [PATCH 0336/2686] 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 9aba8e236c..4614c2b9b7 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ecf5972797..b371aa3618 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 74d8f0d471..bab652bbee 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From f1691882e2a3ea789e15c16984128406234fb03e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Aug 2022 12:56:18 +0900 Subject: [PATCH 0337/2686] Fix incorrect argument passing to `ToMod` --- osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index 8dccc3d82f..beecd56b52 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -78,7 +78,7 @@ namespace osu.Game.Screens.OnlinePlay private IBeatmapInfo beatmap; private IRulesetInfo ruleset; - private Mod[] requiredMods; + private Mod[] requiredMods = Array.Empty(); private Container maskingContainer; private Container difficultyIconContainer; @@ -139,7 +139,8 @@ namespace osu.Game.Screens.OnlinePlay ruleset = rulesets.GetRuleset(Item.RulesetID); var rulesetInstance = ruleset?.CreateInstance(); - requiredMods = Item.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); + if (rulesetInstance != null) + requiredMods = Item.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); } protected override void LoadComplete() From a8dee1751317affc949ab384a5f76670a288e16e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Aug 2022 13:05:59 +0900 Subject: [PATCH 0338/2686] Fix missing `DummyRenderer` in skin resources tests --- osu.Game.Tests/Skins/TestSceneSkinResources.cs | 2 ++ osu.Game/IO/IStorageResourceProvider.cs | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinResources.cs b/osu.Game.Tests/Skins/TestSceneSkinResources.cs index 59a436fdb0..22d6d08355 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinResources.cs @@ -12,6 +12,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics.Rendering.Dummy; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; using osu.Framework.Testing; @@ -54,6 +55,7 @@ namespace osu.Game.Tests.Skins lookedUpFileNames = new List(); mockResourceProvider = new Mock(); mockResourceProvider.Setup(m => m.AudioManager).Returns(Audio); + mockResourceProvider.Setup(m => m.Renderer).Returns(new DummyRenderer()); mockResourceStore = new Mock>(); mockResourceStore.Setup(r => r.Get(It.IsAny())) .Callback(n => lookedUpFileNames.Add(n)) diff --git a/osu.Game/IO/IStorageResourceProvider.cs b/osu.Game/IO/IStorageResourceProvider.cs index ae0dbb963c..08982a8b5f 100644 --- a/osu.Game/IO/IStorageResourceProvider.cs +++ b/osu.Game/IO/IStorageResourceProvider.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. -#nullable disable - using osu.Framework.Audio; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Textures; @@ -21,7 +19,7 @@ namespace osu.Game.IO /// /// Retrieve the game-wide audio manager. /// - AudioManager AudioManager { get; } + AudioManager? AudioManager { get; } /// /// Access game-wide user files. From 237f72efbcddf2192eb7be7acec1a5824d2358d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Aug 2022 13:31:57 +0900 Subject: [PATCH 0339/2686] Add missing null check on `AudioManager` --- osu.Game/Skinning/DefaultSkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs index 32415e8212..f10e8412b1 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkin.cs @@ -53,7 +53,7 @@ namespace osu.Game.Skinning { foreach (string lookup in sampleInfo.LookupNames) { - var sample = Samples?.Get(lookup) ?? resources.AudioManager.Samples.Get(lookup); + var sample = Samples?.Get(lookup) ?? resources.AudioManager?.Samples.Get(lookup); if (sample != null) return sample; } From 68e70006202df1830292388936881e245c83f1da Mon Sep 17 00:00:00 2001 From: its5Q Date: Mon, 8 Aug 2022 15:52:47 +1000 Subject: [PATCH 0340/2686] Fix FPS counter disappearing when hovered over --- osu.Game/Graphics/UserInterface/FPSCounter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/FPSCounter.cs b/osu.Game/Graphics/UserInterface/FPSCounter.cs index 539ac7ed1f..fc5fac5cef 100644 --- a/osu.Game/Graphics/UserInterface/FPSCounter.cs +++ b/osu.Game/Graphics/UserInterface/FPSCounter.cs @@ -203,7 +203,7 @@ namespace osu.Game.Graphics.UserInterface if (hasSignificantChanges) requestDisplay(); - else if (isDisplayed && Time.Current - lastDisplayRequiredTime > 2000) + else if (isDisplayed && Time.Current - lastDisplayRequiredTime > 2000 && !IsHovered) { mainContent.FadeTo(0, 300, Easing.OutQuint); isDisplayed = false; From 6459dbd9e5e31dbba63309ab1961780ac49879ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Aug 2022 14:56:16 +0900 Subject: [PATCH 0341/2686] Fix collection import not showing progress notification --- osu.Game/Database/LegacyImportManager.cs | 41 +++++++++++++++--------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/osu.Game/Database/LegacyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs index 96f4aaf67c..797df49264 100644 --- a/osu.Game/Database/LegacyImportManager.cs +++ b/osu.Game/Database/LegacyImportManager.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. -#nullable disable - using System; using System.Collections.Generic; using System.Threading; @@ -27,27 +25,30 @@ namespace osu.Game.Database public class LegacyImportManager : Component { [Resolved] - private SkinManager skins { get; set; } + private SkinManager skins { get; set; } = null!; [Resolved] - private BeatmapManager beatmaps { get; set; } + private BeatmapManager beatmaps { get; set; } = null!; [Resolved] - private ScoreManager scores { get; set; } - - [Resolved(canBeNull: true)] - private OsuGame game { get; set; } + private ScoreManager scores { get; set; } = null!; [Resolved] - private IDialogOverlay dialogOverlay { get; set; } + private OsuGame? game { get; set; } [Resolved] - private RealmAccess realmAccess { get; set; } + private IDialogOverlay dialogOverlay { get; set; } = null!; - [Resolved(canBeNull: true)] - private DesktopGameHost desktopGameHost { get; set; } + [Resolved] + private RealmAccess realmAccess { get; set; } = null!; - private StableStorage cachedStorage; + [Resolved] + private DesktopGameHost? desktopGameHost { get; set; } + + [Resolved] + private INotificationOverlay? notifications { get; set; } + + private StableStorage? cachedStorage; public bool SupportsImportFromStable => RuntimeInfo.IsDesktop; @@ -98,6 +99,9 @@ namespace osu.Game.Database stableStorage = GetCurrentStableStorage(); } + if (stableStorage == null) + return; + var importTasks = new List(); Task beatmapImportTask = Task.CompletedTask; @@ -108,7 +112,14 @@ namespace osu.Game.Database importTasks.Add(new LegacySkinImporter(skins).ImportFromStableAsync(stableStorage)); if (content.HasFlagFast(StableContent.Collections)) - importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyCollectionImporter(realmAccess).ImportFromStorage(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion)); + { + importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyCollectionImporter(realmAccess) + { + // Other legacy importers import via model managers which handle the posting of notifications. + // Collections are an exception. + PostNotification = n => notifications?.Post(n) + }.ImportFromStorage(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion)); + } if (content.HasFlagFast(StableContent.Scores)) importTasks.Add(beatmapImportTask.ContinueWith(_ => new LegacyScoreImporter(scores).ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion)); @@ -116,7 +127,7 @@ namespace osu.Game.Database await Task.WhenAll(importTasks.ToArray()).ConfigureAwait(false); } - public StableStorage GetCurrentStableStorage() + public StableStorage? GetCurrentStableStorage() { if (cachedStorage != null) return cachedStorage; From 81c079c93708c91f7a350dbc804940f91b4ed86c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Aug 2022 15:17:42 +0900 Subject: [PATCH 0342/2686] Fix incorrect damping implementation I'm not sure what I was thinking with the weighting stuff. It wasn't correct. Can most easily be noticed if suspending the app on iOS for a considerable period, or pausing debugger. --- osu.Game/Graphics/UserInterface/FPSCounter.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/FPSCounter.cs b/osu.Game/Graphics/UserInterface/FPSCounter.cs index 539ac7ed1f..703dcbef53 100644 --- a/osu.Game/Graphics/UserInterface/FPSCounter.cs +++ b/osu.Game/Graphics/UserInterface/FPSCounter.cs @@ -177,15 +177,15 @@ namespace osu.Game.Graphics.UserInterface // use elapsed frame time rather then FramesPerSecond to better catch stutter frames. bool hasDrawSpike = displayedFpsCount > (1000 / spike_time_ms) && drawClock.ElapsedFrameTime > spike_time_ms; - // note that we use an elapsed time here of 1 intentionally. - // this weights all updates equally. if we passed in the elapsed time, longer frames would be weighted incorrectly lower. - displayedFrameTime = Interpolation.DampContinuously(displayedFrameTime, updateClock.ElapsedFrameTime, hasUpdateSpike ? 0 : 100, 1); + const float damp_time = 100; + + displayedFrameTime = Interpolation.DampContinuously(displayedFrameTime, updateClock.ElapsedFrameTime, hasUpdateSpike ? 0 : damp_time, updateClock.ElapsedFrameTime); if (hasDrawSpike) // show spike time using raw elapsed value, to account for `FramesPerSecond` being so averaged spike frames don't show. displayedFpsCount = 1000 / drawClock.ElapsedFrameTime; else - displayedFpsCount = Interpolation.DampContinuously(displayedFpsCount, drawClock.FramesPerSecond, 100, Time.Elapsed); + displayedFpsCount = Interpolation.DampContinuously(displayedFpsCount, drawClock.FramesPerSecond, damp_time, Time.Elapsed); if (Time.Current - lastUpdate > min_time_between_updates) { From 4f7d63be29b02f9644a04f5c4a4082ded256a963 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Aug 2022 15:17:33 +0900 Subject: [PATCH 0343/2686] Ignore very long periods of no frame drawing when showing FPS counter ms value --- osu.Game/Graphics/UserInterface/FPSCounter.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/FPSCounter.cs b/osu.Game/Graphics/UserInterface/FPSCounter.cs index 703dcbef53..531348b921 100644 --- a/osu.Game/Graphics/UserInterface/FPSCounter.cs +++ b/osu.Game/Graphics/UserInterface/FPSCounter.cs @@ -167,6 +167,11 @@ namespace osu.Game.Graphics.UserInterface { base.Update(); + // If the game goes into a suspended state (ie. debugger attached or backgrounded on a mobile device) + // we want to ignore really long periods of no processing. + if (updateClock.ElapsedFrameTime > 10000) + return; + mainContent.Width = Math.Max(mainContent.Width, counters.DrawWidth); // Handle the case where the window has become inactive or the user changed the From 070d156e89d55fe51566f14c8fbfbe3de0765611 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Aug 2022 16:12:07 +0900 Subject: [PATCH 0344/2686] Simplify task logic in `ModPresetColumn` --- osu.Game/Overlays/Mods/ModPresetColumn.cs | 27 +++++++---------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index 7f453637e7..bc0e97d77d 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -50,19 +49,18 @@ namespace osu.Game.Overlays.Mods { presetSubscription?.Dispose(); presetSubscription = realm.RegisterForNotifications(r => - r.All() - .Filter($"{nameof(ModPreset.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $0" - + $" && {nameof(ModPreset.DeletePending)} == false", ruleset.Value.ShortName) - .OrderBy(preset => preset.Name), - (presets, _, _) => asyncLoadPanels(presets)); + r.All() + .Filter($"{nameof(ModPreset.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $0" + + $" && {nameof(ModPreset.DeletePending)} == false", ruleset.Value.ShortName) + .OrderBy(preset => preset.Name), asyncLoadPanels); } private CancellationTokenSource? cancellationTokenSource; private Task? latestLoadTask; - internal bool ItemsLoaded => latestLoadTask == null; + internal bool ItemsLoaded => latestLoadTask?.IsCompleted ?? false; - private void asyncLoadPanels(IReadOnlyList presets) + private void asyncLoadPanels(IRealmCollection presets, ChangeSet changes, Exception error) { cancellationTokenSource?.Cancel(); @@ -72,23 +70,14 @@ namespace osu.Game.Overlays.Mods return; } - var panels = presets.Select(preset => new ModPresetPanel(preset.ToLive(realm)) + latestLoadTask = LoadComponentsAsync(presets.Select(p => new ModPresetPanel(p.ToLive(realm)) { Shear = Vector2.Zero - }); - - Task? loadTask; - - latestLoadTask = loadTask = LoadComponentsAsync(panels, loaded => + }), loaded => { ItemsFlow.RemoveAll(panel => panel is ModPresetPanel); ItemsFlow.AddRange(loaded); }, (cancellationTokenSource = new CancellationTokenSource()).Token); - loadTask.ContinueWith(_ => - { - if (loadTask == latestLoadTask) - latestLoadTask = null; - }); } protected override void Dispose(bool isDisposing) From d3ee2a0b8ec8286d080b5ecc08b23061a82d2c72 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Aug 2022 17:38:46 +0900 Subject: [PATCH 0345/2686] Add test scene for visually adjusting mania `BarLine`s --- .../Skinning/TestSceneBarLine.cs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs new file mode 100644 index 0000000000..ff557638a9 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.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 System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.UI; + +namespace osu.Game.Rulesets.Mania.Tests.Skinning +{ + public class TestSceneBarLine : ManiaSkinnableTestScene + { + [Test] + public void TestMinor() + { + AddStep("Create barlines", () => recreate()); + } + + private void recreate(Func>? createBarLines = null) + { + var stageDefinitions = new List + { + new StageDefinition { Columns = 4 }, + }; + + SetContents(_ => new ManiaPlayfield(stageDefinitions).With(s => + { + if (createBarLines != null) + { + var barLines = createBarLines(); + + foreach (var b in barLines) + s.Add(b); + + return; + } + + for (int i = 0; i < 64; i++) + { + s.Add(new BarLine + { + StartTime = Time.Current + i * 500, + Major = i % 4 == 0, + }); + } + })); + } + } +} From 1f4b87d233e6664080cc99e31667cbba5a5082e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 8 Aug 2022 17:38:56 +0900 Subject: [PATCH 0346/2686] Adjust visuals of osu!mania barlines to be less present Roughly matches the new design. Metrics adjusted to fit with the existing design. Closes #19611 maybe? --- .../Objects/Drawables/DrawableBarLine.cs | 46 +++++++------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs index 0e2d6bce21..bf0bc84f9b 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs @@ -1,12 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Objects.Drawables { @@ -16,21 +13,11 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// public class DrawableBarLine : DrawableManiaHitObject { - /// - /// Height of major bar line triangles. - /// - private const float triangle_height = 12; - - /// - /// Offset of the major bar line triangles from the sides of the bar line. - /// - private const float triangle_offset = 9; - public DrawableBarLine(BarLine barLine) : base(barLine) { RelativeSizeAxes = Axes.X; - Height = 2f; + Height = barLine.Major ? 1.7f : 1.2f; AddInternal(new Box { @@ -38,34 +25,33 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.Both, - Colour = new Color4(255, 204, 33, 255), + Alpha = barLine.Major ? 0.5f : 0.2f }); if (barLine.Major) { - AddInternal(new EquilateralTriangle + Vector2 size = new Vector2(22, 6); + const float triangle_offset = 4; + + AddInternal(new Circle { - Name = "Left triangle", - Anchor = Anchor.BottomLeft, - Origin = Anchor.TopCentre, - Size = new Vector2(triangle_height), + Name = "Left line", + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + + Size = size, X = -triangle_offset, - Rotation = 90 }); - AddInternal(new EquilateralTriangle + AddInternal(new Circle { - Name = "Right triangle", - Anchor = Anchor.BottomRight, - Origin = Anchor.TopCentre, - Size = new Vector2(triangle_height), + Name = "Right line", + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreLeft, + Size = size, X = triangle_offset, - Rotation = -90 }); } - - if (!barLine.Major) - Alpha = 0.2f; } protected override void UpdateInitialTransforms() From cd68134565d6a02d014b8d80ae37738cf737741a Mon Sep 17 00:00:00 2001 From: BlauFx Date: Mon, 8 Aug 2022 13:10:28 +0200 Subject: [PATCH 0347/2686] Call skip method directly --- 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 63e7bcb115..b648c918e1 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -372,7 +372,7 @@ namespace osu.Game.Screens.Play if (Configuration.AutomaticallySkipIntro && e.NewValue && RestartCount > 0) { Configuration.AutomaticallySkipIntro = false; - skipIntroOverlay.RequestSkip.Invoke(); + performUserRequestedSkip(); } }; } From fac2596eee86b21e49fc9e065258208009aa16d2 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Mon, 8 Aug 2022 13:38:52 +0200 Subject: [PATCH 0348/2686] Change type from BindableBool to IBindable --- osu.Game/Screens/Play/SkipOverlay.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index a5f6bf3fee..227038253d 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Play private bool isClickable; - public BindableBool IsSkippable = new BindableBool()!; + public IBindable IsSkippable = new Bindable(); [Resolved] private GameplayClock gameplayClock { get; set; } @@ -92,6 +92,8 @@ namespace osu.Game.Screens.Play } } }; + + IsSkippable.BindTo(button.Enabled); } private const double fade_time = 300; @@ -137,7 +139,6 @@ namespace osu.Game.Screens.Play remainingTimeBox.Width = (float)Interpolation.Lerp(remainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1)); isClickable = progress > 0; - IsSkippable.Value = isClickable; button.Enabled.Value = isClickable; buttonContainer.State.Value = isClickable ? Visibility.Visible : Visibility.Hidden; } From 5080d62e77282bbb3e29d2e3ef8821063d303aa4 Mon Sep 17 00:00:00 2001 From: its5Q Date: Mon, 8 Aug 2022 01:11:15 +1000 Subject: [PATCH 0349/2686] Add missing localisation for settings enums --- osu.Game/Configuration/BackgroundSource.cs | 8 +++- .../Configuration/DiscordRichPresenceMode.cs | 7 +++- osu.Game/Configuration/HUDVisibilityMode.cs | 7 +++- .../Configuration/RandomSelectAlgorithm.cs | 7 ++-- osu.Game/Configuration/ScalingMode.cs | 10 ++++- osu.Game/Configuration/ScreenshotFormat.cs | 7 ++-- .../Configuration/SeasonalBackgroundMode.cs | 6 +++ osu.Game/Input/OsuConfineMouseMode.cs | 7 +++- osu.Game/Localisation/CommonStrings.cs | 2 +- .../Localisation/GameplaySettingsStrings.cs | 25 ++++++++++++ .../Localisation/GraphicsSettingsStrings.cs | 10 +++++ .../Localisation/LayoutSettingsStrings.cs | 20 ++++++++++ osu.Game/Localisation/MouseSettingsStrings.cs | 15 +++++++ .../Localisation/OnlineSettingsStrings.cs | 15 +++++++ .../Localisation/RulesetSettingsStrings.cs | 15 +++++++ osu.Game/Localisation/UserInterfaceStrings.cs | 40 +++++++++++++++++++ .../Mods/Input/ModSelectHotkeyStyle.cs | 4 ++ osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 5 +++ osu.Game/Rulesets/UI/PlayfieldBorderStyle.cs | 8 ++++ 19 files changed, 201 insertions(+), 17 deletions(-) diff --git a/osu.Game/Configuration/BackgroundSource.cs b/osu.Game/Configuration/BackgroundSource.cs index b4a1fd78c3..f08b29cffe 100644 --- a/osu.Game/Configuration/BackgroundSource.cs +++ b/osu.Game/Configuration/BackgroundSource.cs @@ -3,16 +3,20 @@ #nullable disable -using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Configuration { public enum BackgroundSource { + [LocalisableDescription(typeof(SkinSettingsStrings), nameof(SkinSettingsStrings.SkinSectionHeader))] Skin, + + [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.BeatmapHeader))] Beatmap, - [Description("Beatmap (with storyboard / video)")] + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.BeatmapWithStoryboard))] BeatmapWithStoryboard, } } diff --git a/osu.Game/Configuration/DiscordRichPresenceMode.cs b/osu.Game/Configuration/DiscordRichPresenceMode.cs index 935619920a..604c151224 100644 --- a/osu.Game/Configuration/DiscordRichPresenceMode.cs +++ b/osu.Game/Configuration/DiscordRichPresenceMode.cs @@ -3,17 +3,20 @@ #nullable disable -using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Configuration { public enum DiscordRichPresenceMode { + [LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.Off))] Off, - [Description("Hide identifiable information")] + [LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.HideIdentifiableInformation))] Limited, + [LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.Full))] Full } } diff --git a/osu.Game/Configuration/HUDVisibilityMode.cs b/osu.Game/Configuration/HUDVisibilityMode.cs index ec54bfcb71..ac85081edf 100644 --- a/osu.Game/Configuration/HUDVisibilityMode.cs +++ b/osu.Game/Configuration/HUDVisibilityMode.cs @@ -3,17 +3,20 @@ #nullable disable -using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Configuration { public enum HUDVisibilityMode { + [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.Never))] Never, - [Description("Hide during gameplay")] + [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.HideDuringGameplay))] HideDuringGameplay, + [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.Always))] Always } } diff --git a/osu.Game/Configuration/RandomSelectAlgorithm.cs b/osu.Game/Configuration/RandomSelectAlgorithm.cs index 9a02aaee60..052c6b4c55 100644 --- a/osu.Game/Configuration/RandomSelectAlgorithm.cs +++ b/osu.Game/Configuration/RandomSelectAlgorithm.cs @@ -3,16 +3,17 @@ #nullable disable -using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Configuration { public enum RandomSelectAlgorithm { - [Description("Never repeat")] + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.NeverRepeat))] RandomPermutation, - [Description("True Random")] + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.TrueRandom))] Random } } diff --git a/osu.Game/Configuration/ScalingMode.cs b/osu.Game/Configuration/ScalingMode.cs index 25c3692a1a..c655fe1000 100644 --- a/osu.Game/Configuration/ScalingMode.cs +++ b/osu.Game/Configuration/ScalingMode.cs @@ -3,17 +3,23 @@ #nullable disable -using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Configuration { public enum ScalingMode { + [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.Off))] Off, + + [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.Everything))] Everything, - [Description("Excluding overlays")] + [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ExcludingOverlays))] ExcludeOverlays, + + [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.Gameplay))] Gameplay, } } diff --git a/osu.Game/Configuration/ScreenshotFormat.cs b/osu.Game/Configuration/ScreenshotFormat.cs index 57c08538b8..d29c5e3d80 100644 --- a/osu.Game/Configuration/ScreenshotFormat.cs +++ b/osu.Game/Configuration/ScreenshotFormat.cs @@ -3,16 +3,17 @@ #nullable disable -using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Configuration { public enum ScreenshotFormat { - [Description("JPG (web-friendly)")] + [LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.JPG))] Jpg = 1, - [Description("PNG (lossless)")] + [LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.PNG))] Png = 2 } } diff --git a/osu.Game/Configuration/SeasonalBackgroundMode.cs b/osu.Game/Configuration/SeasonalBackgroundMode.cs index 909798fe97..cf01dca0c2 100644 --- a/osu.Game/Configuration/SeasonalBackgroundMode.cs +++ b/osu.Game/Configuration/SeasonalBackgroundMode.cs @@ -3,6 +3,9 @@ #nullable disable +using osu.Framework.Localisation; +using osu.Game.Localisation; + namespace osu.Game.Configuration { public enum SeasonalBackgroundMode @@ -10,16 +13,19 @@ namespace osu.Game.Configuration /// /// Seasonal backgrounds are shown regardless of season, if at all available. /// + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.Always))] Always, /// /// Seasonal backgrounds are shown only during their corresponding season. /// + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.Sometimes))] Sometimes, /// /// Seasonal backgrounds are never shown. /// + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.Never))] Never } } diff --git a/osu.Game/Input/OsuConfineMouseMode.cs b/osu.Game/Input/OsuConfineMouseMode.cs index 2a93ac1cd6..97c9df5072 100644 --- a/osu.Game/Input/OsuConfineMouseMode.cs +++ b/osu.Game/Input/OsuConfineMouseMode.cs @@ -3,8 +3,9 @@ #nullable disable -using System.ComponentModel; using osu.Framework.Input; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Input { @@ -17,18 +18,20 @@ namespace osu.Game.Input /// /// The mouse cursor will be free to move outside the game window. /// + [LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.Never))] Never, /// /// The mouse cursor will be locked to the window bounds during gameplay, /// but may otherwise move freely. /// - [Description("During Gameplay")] + [LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.DuringGameplay))] DuringGameplay, /// /// The mouse cursor will always be locked to the window bounds while the game has focus. /// + [LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.Always))] Always } } diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index f2dcd57742..93e3276f59 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -101,4 +101,4 @@ namespace osu.Game.Localisation private static string getKey(string key) => $@"{prefix}:{key}"; } -} \ No newline at end of file +} diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs index 8a0f773551..51450d975d 100644 --- a/osu.Game/Localisation/GameplaySettingsStrings.cs +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -104,6 +104,31 @@ namespace osu.Game.Localisation /// public static LocalisableString IncreaseFirstObjectVisibility => new TranslatableString(getKey(@"increase_first_object_visibility"), @"Increase visibility of first object when visual impairment mods are enabled"); + /// + /// "Hide during gameplay" + /// + public static LocalisableString HideDuringGameplay => new TranslatableString(getKey(@"hide_during_gameplay"), @"Hide during gameplay"); + + /// + /// "Always" + /// + public static LocalisableString Always => new TranslatableString(getKey(@"always"), @"Always"); + + /// + /// "Never" + /// + public static LocalisableString Never => new TranslatableString(getKey(@"never"), @"Never"); + + /// + /// "Standardised" + /// + public static LocalisableString Standardised => new TranslatableString(getKey(@"standardised"), @"Standardised"); + + /// + /// "Classic" + /// + public static LocalisableString Classic => new TranslatableString(getKey(@"classic"), @"Classic"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/GraphicsSettingsStrings.cs b/osu.Game/Localisation/GraphicsSettingsStrings.cs index 38355d9041..42632b9a38 100644 --- a/osu.Game/Localisation/GraphicsSettingsStrings.cs +++ b/osu.Game/Localisation/GraphicsSettingsStrings.cs @@ -129,6 +129,16 @@ namespace osu.Game.Localisation /// public static LocalisableString UseHardwareAcceleration => new TranslatableString(getKey(@"use_hardware_acceleration"), @"Use hardware acceleration"); + /// + /// "JPG (web-friendly)" + /// + public static LocalisableString JPG => new TranslatableString(getKey(@"jpg_web_friendly"), @"JPG (web-friendly)"); + + /// + /// "PNG (lossless)" + /// + public static LocalisableString PNG => new TranslatableString(getKey(@"png_lossless"), @"PNG (lossless)"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs index b4326b8e39..729b4bce6a 100644 --- a/osu.Game/Localisation/LayoutSettingsStrings.cs +++ b/osu.Game/Localisation/LayoutSettingsStrings.cs @@ -29,6 +29,26 @@ namespace osu.Game.Localisation /// public static LocalisableString FullscreenMacOSNote => new TranslatableString(getKey(@"fullscreen_macos_note"), @"Using fullscreen on macOS makes interacting with the menu bar and spaces no longer work, and may lead to freezes if a system dialog is presented. Using borderless is recommended."); + /// + /// "Excluding overlays" + /// + public static LocalisableString ExcludingOverlays => new TranslatableString(getKey(@"excluding_overlays"), @"Excluding overlays"); + + /// + /// "Everything" + /// + public static LocalisableString Everything => new TranslatableString(getKey(@"everything"), @"Everything"); + + /// + /// "Gameplay" + /// + public static LocalisableString Gameplay => new TranslatableString(getKey(@"gameplay"), @"Gameplay"); + + /// + /// "Off" + /// + public static LocalisableString Off => new TranslatableString(getKey(@"scaling_mode.off"), @"Off"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/MouseSettingsStrings.cs b/osu.Game/Localisation/MouseSettingsStrings.cs index fd7225ad2e..b9ae3de378 100644 --- a/osu.Game/Localisation/MouseSettingsStrings.cs +++ b/osu.Game/Localisation/MouseSettingsStrings.cs @@ -64,6 +64,21 @@ namespace osu.Game.Localisation /// public static LocalisableString HighPrecisionPlatformWarning => new TranslatableString(getKey(@"high_precision_platform_warning"), @"This setting has known issues on your platform. If you encounter problems, it is recommended to adjust sensitivity externally and keep this disabled for now."); + /// + /// "Always" + /// + public static LocalisableString Always => new TranslatableString(getKey(@"always"), @"Always"); + + /// + /// "During Gameplay" + /// + public static LocalisableString DuringGameplay => new TranslatableString(getKey(@"during_gameplay"), @"During Gameplay"); + + /// + /// "Never" + /// + public static LocalisableString Never => new TranslatableString(getKey(@"never"), @"Never"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/OnlineSettingsStrings.cs b/osu.Game/Localisation/OnlineSettingsStrings.cs index 6862f4ac2c..ad47284709 100644 --- a/osu.Game/Localisation/OnlineSettingsStrings.cs +++ b/osu.Game/Localisation/OnlineSettingsStrings.cs @@ -64,6 +64,21 @@ namespace osu.Game.Localisation /// public static LocalisableString ShowExplicitContent => new TranslatableString(getKey(@"show_explicit_content"), @"Show explicit content in search results"); + /// + /// "Hide identifiable information" + /// + public static LocalisableString HideIdentifiableInformation => new TranslatableString(getKey(@"hide_identifiable_information"), @"Hide identifiable information"); + + /// + /// "Full" + /// + public static LocalisableString Full => new TranslatableString(getKey(@"full"), @"Full"); + + /// + /// "Off" + /// + public static LocalisableString Off => new TranslatableString(getKey(@"off"), @"Off"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/RulesetSettingsStrings.cs b/osu.Game/Localisation/RulesetSettingsStrings.cs index a356c9e20b..bfd76148ea 100644 --- a/osu.Game/Localisation/RulesetSettingsStrings.cs +++ b/osu.Game/Localisation/RulesetSettingsStrings.cs @@ -14,6 +14,21 @@ namespace osu.Game.Localisation /// public static LocalisableString Rulesets => new TranslatableString(getKey(@"rulesets"), @"Rulesets"); + /// + /// "None" + /// + public static LocalisableString None => new TranslatableString(getKey(@"none"), @"None"); + + /// + /// "Corners" + /// + public static LocalisableString Corners => new TranslatableString(getKey(@"corners"), @"Corners"); + + /// + /// "Full" + /// + public static LocalisableString Full => new TranslatableString(getKey(@"full"), @"Full"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index a090b8c14c..b1f16c05f0 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -114,6 +114,46 @@ namespace osu.Game.Localisation /// public static LocalisableString NoLimit => new TranslatableString(getKey(@"no_limit"), @"no limit"); + /// + /// "Beatmap (with storyboard / video)" + /// + public static LocalisableString BeatmapWithStoryboard => new TranslatableString(getKey(@"beatmap_with_storyboard"), @"Beatmap (with storyboard / video)"); + + /// + /// "Always" + /// + public static LocalisableString Always => new TranslatableString(getKey(@"always"), @"Always"); + + /// + /// "Never" + /// + public static LocalisableString Never => new TranslatableString(getKey(@"never"), @"Never"); + + /// + /// "Sometimes" + /// + public static LocalisableString Sometimes => new TranslatableString(getKey(@"sometimes"), @"Sometimes"); + + /// + /// "Sequential" + /// + public static LocalisableString Sequential => new TranslatableString(getKey(@"sequential"), @"Sequential"); + + /// + /// "Classic" + /// + public static LocalisableString Classic => new TranslatableString(getKey(@"classic"), @"Classic"); + + /// + /// "Never repeat" + /// + public static LocalisableString NeverRepeat => new TranslatableString(getKey(@"never_repeat"), @"Never repeat"); + + /// + /// "True Random" + /// + public static LocalisableString TrueRandom => new TranslatableString(getKey(@"true_random"), @"True Random"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs b/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs index 6375b37f8b..17f005c313 100644 --- a/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs +++ b/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs @@ -1,7 +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 osu.Framework.Localisation; using osu.Game.Rulesets.Mods; +using osu.Game.Localisation; namespace osu.Game.Overlays.Mods.Input { @@ -15,6 +17,7 @@ namespace osu.Game.Overlays.Mods.Input /// Individual letters in a row trigger the mods in a sequential fashion. /// Uses . /// + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.Sequential))] Sequential, /// @@ -22,6 +25,7 @@ namespace osu.Game.Overlays.Mods.Input /// One keybinding can toggle between what used to be s on stable, /// and some mods in a column may not have any hotkeys at all. /// + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.Classic))] Classic } } diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 59fee0f97b..8b98a799ac 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -16,6 +16,8 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Replays; using osu.Game.Scoring; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Rulesets.Scoring { @@ -636,7 +638,10 @@ namespace osu.Game.Rulesets.Scoring public enum ScoringMode { + [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.Standardised))] Standardised, + + [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.Classic))] Classic } } diff --git a/osu.Game/Rulesets/UI/PlayfieldBorderStyle.cs b/osu.Game/Rulesets/UI/PlayfieldBorderStyle.cs index a4a483e930..9d6c7794a5 100644 --- a/osu.Game/Rulesets/UI/PlayfieldBorderStyle.cs +++ b/osu.Game/Rulesets/UI/PlayfieldBorderStyle.cs @@ -3,12 +3,20 @@ #nullable disable +using osu.Framework.Localisation; +using osu.Game.Localisation; + namespace osu.Game.Rulesets.UI { public enum PlayfieldBorderStyle { + [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.None))] None, + + [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.Corners))] Corners, + + [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.Full))] Full } } From 9f043e725f90093b9957150c75a56ebf9b08da6d Mon Sep 17 00:00:00 2001 From: its5Q Date: Mon, 8 Aug 2022 22:06:23 +1000 Subject: [PATCH 0350/2686] Fix CI code quality --- osu.Game/Configuration/ScreenshotFormat.cs | 4 ++-- osu.Game/Localisation/GraphicsSettingsStrings.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Configuration/ScreenshotFormat.cs b/osu.Game/Configuration/ScreenshotFormat.cs index d29c5e3d80..13d0b64fd2 100644 --- a/osu.Game/Configuration/ScreenshotFormat.cs +++ b/osu.Game/Configuration/ScreenshotFormat.cs @@ -10,10 +10,10 @@ namespace osu.Game.Configuration { public enum ScreenshotFormat { - [LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.JPG))] + [LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.Jpg))] Jpg = 1, - [LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.PNG))] + [LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.Png))] Png = 2 } } diff --git a/osu.Game/Localisation/GraphicsSettingsStrings.cs b/osu.Game/Localisation/GraphicsSettingsStrings.cs index 42632b9a38..2ab9d9de87 100644 --- a/osu.Game/Localisation/GraphicsSettingsStrings.cs +++ b/osu.Game/Localisation/GraphicsSettingsStrings.cs @@ -132,12 +132,12 @@ namespace osu.Game.Localisation /// /// "JPG (web-friendly)" /// - public static LocalisableString JPG => new TranslatableString(getKey(@"jpg_web_friendly"), @"JPG (web-friendly)"); + public static LocalisableString Jpg => new TranslatableString(getKey(@"jpg_web_friendly"), @"JPG (web-friendly)"); /// /// "PNG (lossless)" /// - public static LocalisableString PNG => new TranslatableString(getKey(@"png_lossless"), @"PNG (lossless)"); + public static LocalisableString Png => new TranslatableString(getKey(@"png_lossless"), @"PNG (lossless)"); private static string getKey(string key) => $"{prefix}:{key}"; } From 00333fb0d21af61edb94812df8f9c5bd9a6de56d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 8 Aug 2022 19:19:13 +0200 Subject: [PATCH 0351/2686] Change `?? false` test to `== true` for legibility --- osu.Game/Overlays/Mods/ModPresetColumn.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index bc0e97d77d..2b234b4319 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Mods private CancellationTokenSource? cancellationTokenSource; private Task? latestLoadTask; - internal bool ItemsLoaded => latestLoadTask?.IsCompleted ?? false; + internal bool ItemsLoaded => latestLoadTask?.IsCompleted == true; private void asyncLoadPanels(IRealmCollection presets, ChangeSet changes, Exception error) { From f21a51aa247e9420c6c07d8c2bee7f2b3d626fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 8 Aug 2022 19:20:50 +0200 Subject: [PATCH 0352/2686] Simplify mirror copy of task logic in `ModColumn` --- osu.Game/Overlays/Mods/ModColumn.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index 1c40c8c6e5..7a2c727a00 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -66,7 +66,7 @@ namespace osu.Game.Overlays.Mods private IModHotkeyHandler hotkeyHandler = null!; private Task? latestLoadTask; - internal bool ItemsLoaded => latestLoadTask == null; + internal bool ItemsLoaded => latestLoadTask?.IsCompleted == true; public ModColumn(ModType modType, bool allowIncompatibleSelection) { @@ -132,18 +132,11 @@ namespace osu.Game.Overlays.Mods var panels = availableMods.Select(mod => CreateModPanel(mod).With(panel => panel.Shear = Vector2.Zero)); - Task? loadTask; - - latestLoadTask = loadTask = LoadComponentsAsync(panels, loaded => + latestLoadTask = LoadComponentsAsync(panels, loaded => { ItemsFlow.ChildrenEnumerable = loaded; updateState(); }, (cancellationTokenSource = new CancellationTokenSource()).Token); - loadTask.ContinueWith(_ => - { - if (loadTask == latestLoadTask) - latestLoadTask = null; - }); } private void updateState() From eba070a0f800176c6ea75ea6a83f81d0b19071f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 8 Aug 2022 19:57:12 +0200 Subject: [PATCH 0353/2686] Add weak test coverage of broken audio playback after soft-delete --- .../Visual/UserInterface/TestSceneModPresetColumn.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index 13f83eac96..901f234db6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -134,6 +134,7 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestSoftDeleteSupport() { AddStep("set osu! ruleset", () => Ruleset.Value = rulesets.GetRuleset(0)); + AddStep("clear mods", () => SelectedMods.Value = Array.Empty()); AddStep("create content", () => Child = new ModPresetColumn { Anchor = Anchor.Centre, @@ -153,9 +154,11 @@ namespace osu.Game.Tests.Visual.UserInterface foreach (var preset in r.All()) preset.DeletePending = true; })); - AddUntilStep("no panels visible", () => this.ChildrenOfType().Count() == 0); + AddUntilStep("no panels visible", () => !this.ChildrenOfType().Any()); - AddStep("undelete preset", () => Realm.Write(r => + AddStep("select mods from first preset", () => SelectedMods.Value = new Mod[] { new OsuModDoubleTime(), new OsuModHardRock() }); + + AddStep("undelete presets", () => Realm.Write(r => { foreach (var preset in r.All()) preset.DeletePending = false; From a0a6e1faeeab7a2362e3850ed94f26d05556ae33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 8 Aug 2022 20:30:21 +0200 Subject: [PATCH 0354/2686] Fix spurious sample playbacks from already-removed panels --- osu.Game/Overlays/Mods/ModPresetColumn.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index 2b234b4319..6266e360dd 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Localisation; @@ -66,7 +67,7 @@ namespace osu.Game.Overlays.Mods if (!presets.Any()) { - ItemsFlow.RemoveAll(panel => panel is ModPresetPanel); + removeAndDisposePresetPanels(); return; } @@ -75,9 +76,23 @@ namespace osu.Game.Overlays.Mods Shear = Vector2.Zero }), loaded => { - ItemsFlow.RemoveAll(panel => panel is ModPresetPanel); + removeAndDisposePresetPanels(); ItemsFlow.AddRange(loaded); }, (cancellationTokenSource = new CancellationTokenSource()).Token); + + void removeAndDisposePresetPanels() + { + int i = 0; + + while (i < ItemsFlow.Count) + { + var item = ItemsFlow[i]; + if (item is ModPresetPanel) + item.RemoveAndDisposeImmediately(); + else + i++; + } + } } protected override void Dispose(bool isDisposing) From f6e65cf1af289afdb6a3706321c16435057bcdda Mon Sep 17 00:00:00 2001 From: BlauFx Date: Mon, 8 Aug 2022 20:53:05 +0200 Subject: [PATCH 0355/2686] Improve implementation --- osu.Game/Screens/Play/Player.cs | 10 ++++++---- osu.Game/Screens/Play/PlayerLoader.cs | 4 +--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index b648c918e1..f2b3bfc090 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -81,6 +81,11 @@ namespace osu.Game.Screens.Play private bool isRestarting; + /// + /// Is set to true when pressed the via the quick retry hotkey. + /// + public Bindable IsQuickRestart = new Bindable(); + private Bindable mouseWheelDisabled; private readonly Bindable storyboardReplacesBackground = new Bindable(); @@ -287,7 +292,7 @@ namespace osu.Game.Screens.Play { if (!this.IsCurrentScreen()) return; - Configuration.AutomaticallySkipIntro = true; + IsQuickRestart.Value = true; fadeOut(true); Restart(); }, @@ -370,10 +375,7 @@ namespace osu.Game.Screens.Play skipIntroOverlay.IsSkippable.ValueChanged += e => { if (Configuration.AutomaticallySkipIntro && e.NewValue && RestartCount > 0) - { - Configuration.AutomaticallySkipIntro = false; performUserRequestedSkip(); - } }; } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 477811a979..76092fbaa3 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -386,9 +386,7 @@ namespace osu.Game.Screens.Play private void restartRequested() { if (CurrentPlayer != null) - { - isHotKeyRestart = CurrentPlayer.Configuration.AutomaticallySkipIntro; - } + isHotKeyRestart = CurrentPlayer.IsQuickRestart.Value; hideOverlays = true; ValidForResume = true; From f74fb3491ed2394886551451a9b22f32661b1b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 8 Aug 2022 21:08:54 +0200 Subject: [PATCH 0356/2686] Use alternative implementation of preset panel cleanup --- osu.Game/Overlays/Mods/ModPresetColumn.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index 6266e360dd..176c527a10 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -82,16 +82,8 @@ namespace osu.Game.Overlays.Mods void removeAndDisposePresetPanels() { - int i = 0; - - while (i < ItemsFlow.Count) - { - var item = ItemsFlow[i]; - if (item is ModPresetPanel) - item.RemoveAndDisposeImmediately(); - else - i++; - } + foreach (var panel in ItemsFlow.OfType().ToArray()) + panel.RemoveAndDisposeImmediately(); } } From e4879aa4509dfae0942989d2ca67cddfb7338743 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Mon, 8 Aug 2022 21:12:38 +0200 Subject: [PATCH 0357/2686] Add test --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 05474e3d39..b0308dcd22 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -353,6 +353,22 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("sound volume restored", () => Beatmap.Value.Track.AggregateVolume.Value == 1); } + [Test] + public void TestQuickRetry() + { + AddStep("load dummy beatmap", () => resetPlayer(false)); + AddUntilStep("wait for current", () => player.IsCurrentScreen()); + + AddStep("Restart map normally", () => player.Restart()); + AddUntilStep("wait for current", () => player.IsCurrentScreen()); + + AddStep("Restart map with quick retry hotkey", () => + { + InputManager.UseParentInput = true; + InputManager.PressKey(Key.Tilde); + }); + } + private EpilepsyWarning getWarning() => loader.ChildrenOfType().SingleOrDefault(); private class TestPlayerLoader : PlayerLoader From 0afa3a5ec8eb62e4bda6c8476fa03808af736259 Mon Sep 17 00:00:00 2001 From: BlauFx Date: Mon, 8 Aug 2022 21:20:09 +0200 Subject: [PATCH 0358/2686] Fix xml doc --- 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 f2b3bfc090..1dd4006450 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -82,7 +82,7 @@ namespace osu.Game.Screens.Play private bool isRestarting; /// - /// Is set to true when pressed the via the quick retry hotkey. + /// Is set to true when the quick retry hotkey has been pressed. /// public Bindable IsQuickRestart = new Bindable(); From b52a07c16a6559b3661453f533783ae9abeb7a69 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Mon, 8 Aug 2022 21:27:46 +0200 Subject: [PATCH 0359/2686] Use DI to provide dependencies for KPS Calculator and improve input gathering KPS Calculator now uses DI to retrieve the clocks. Using `HUDOverlay` it is now cached for `KeysPerSecondCounter`s to resolve it. This also allows to make an "Attach" flow like `KeyCounter`. --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 5 +- osu.Game/Rulesets/UI/RulesetInputManager.cs | 37 +++++++++- .../HUD/KPSCounter/KeysPerSecondCalculator.cs | 70 +++++++++---------- .../HUD/KPSCounter/KeysPerSecondCounter.cs | 22 +++--- osu.Game/Screens/Play/HUDOverlay.cs | 8 ++- osu.Game/Screens/Play/KeyCounter.cs | 2 - 6 files changed, 90 insertions(+), 54 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index f7f62d2af0..b28e3355a4 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -30,6 +30,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD.KPSCounter; using osuTK; namespace osu.Game.Rulesets.UI @@ -38,7 +39,7 @@ namespace osu.Game.Rulesets.UI /// Displays an interactive ruleset gameplay instance. /// /// The type of HitObject contained by this DrawableRuleset. - public abstract class DrawableRuleset : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter + public abstract class DrawableRuleset : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter, ICanAttachKpsCalculator where TObject : HitObject { public override event Action NewResult; @@ -340,6 +341,8 @@ namespace osu.Game.Rulesets.UI public void Attach(KeyCounterDisplay keyCounter) => (KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(keyCounter); + public void Attach(KeysPerSecondCalculator kps) => (KeyBindingInputManager as ICanAttachKpsCalculator)?.Attach(kps); + /// /// Creates a key conversion input manager. An exception will be thrown if a valid is not returned. /// diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 7c37913576..23e64153eb 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -20,11 +20,12 @@ using osu.Game.Input.Bindings; using osu.Game.Input.Handlers; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD.KPSCounter; using static osu.Game.Input.Handlers.ReplayInputHandler; namespace osu.Game.Rulesets.UI { - public abstract class RulesetInputManager : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler, IHasRecordingHandler + public abstract class RulesetInputManager : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler, IHasRecordingHandler, ICanAttachKpsCalculator where T : struct { public readonly KeyBindingContainer KeyBindingContainer; @@ -186,6 +187,35 @@ namespace osu.Game.Rulesets.UI #endregion + #region KPS Counter Attachment + + public void Attach(KeysPerSecondCalculator kps) + { + var listener = new ActionListener(); + + KeyBindingContainer.Add(listener); + + kps.Listener = listener; + } + + public class ActionListener : KeysPerSecondCalculator.InputListener, IKeyBindingHandler + { + public override event Action OnNewInput; + + public bool OnPressed(KeyBindingPressEvent e) + { + OnNewInput?.Invoke(); + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + } + + #endregion + protected virtual KeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) => new RulesetKeyBindingContainer(ruleset, variant, unique); @@ -229,6 +259,11 @@ namespace osu.Game.Rulesets.UI void Attach(KeyCounterDisplay keyCounter); } + public interface ICanAttachKpsCalculator + { + void Attach(KeysPerSecondCalculator keysPerSecondCalculator); + } + public class RulesetInputManagerInputState : InputState where T : struct { diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs index 3c0d585984..96a6d5b8eb 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs @@ -4,55 +4,36 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Timing; -using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Play.HUD.KPSCounter { - public class KeysPerSecondCalculator + public class KeysPerSecondCalculator : Component { - public static void AddInput() - { - onNewInput?.Invoke(); - } - private readonly List timestamps; - private GameplayClock? gameplayClock; - private DrawableRuleset? drawableRuleset; - public GameplayClock? GameplayClock + private InputListener? listener; + + [Resolved] + private GameplayClock? gameplayClock { get; set; } + + [Resolved(canBeNull: true)] + private DrawableRuleset? drawableRuleset { get; set; } + + public InputListener Listener { - get => gameplayClock; set { onResetRequested?.Invoke(); - - if (value != null) - { - gameplayClock = value; - } + listener = value; + listener.OnNewInput += addTimestamp; } } - public DrawableRuleset? DrawableRuleset - { - get => drawableRuleset; - set - { - onResetRequested?.Invoke(); - - if (value != null) - { - drawableRuleset = value; - baseRate = (drawableRuleset.Mods.FirstOrDefault(m => m is ModRateAdjust) as ModRateAdjust)?.SpeedChange.Value - ?? 1; - } - } - } - - private static event Action? onNewInput; - private static event Action? onResetRequested; + private event Action? onResetRequested; private IClock? workingClock => drawableRuleset?.FrameStableClock; @@ -81,8 +62,8 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter public KeysPerSecondCalculator() { + RelativeSizeAxes = Axes.Both; timestamps = new List(); - onNewInput += addTimestamp; onResetRequested += cleanUp; } @@ -90,6 +71,9 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter { timestamps.Clear(); maxTime = double.NegativeInfinity; + + if (listener != null) + listener.OnNewInput -= addTimestamp; } private void addTimestamp() @@ -111,5 +95,21 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter double relativeTime = workingClock.CurrentTime - timestamp; return relativeTime >= 0 && relativeTime <= span; } + + ~KeysPerSecondCalculator() + { + cleanUp(); + } + + public abstract class InputListener : Component + { + protected InputListener() + { + RelativeSizeAxes = Axes.Both; + Depth = float.MinValue; + } + + public abstract event Action? OnNewInput; + } } } diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs index ad7b6c8f5c..d6f1d19770 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs @@ -22,21 +22,15 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter private readonly Bindable valid = new Bindable(); - private static readonly KeysPerSecondCalculator calculator = new KeysPerSecondCalculator(); - [Resolved] - private GameplayClock? gameplayClock - { - get => calculator.GameplayClock; - set => calculator.GameplayClock = value; - } + private KeysPerSecondCalculator? calculator { get; set; } + + // This is to force the skin editor to show the component only in a Gameplay context + [Resolved] + private GameplayClock? gameplayClock { get; set; } [Resolved(canBeNull: true)] - private DrawableRuleset? drawableRuleset - { - get => calculator.DrawableRuleset; - set => calculator.DrawableRuleset = value; - } + private DrawableRuleset? drawableRuleset { get; set; } protected override double RollingDuration => 350; @@ -59,8 +53,8 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter { base.Update(); - valid.Value = calculator.Ready; - Current.Value = calculator.Ready ? calculator.Value : 0; + valid.Value = calculator != null && calculator.Ready; + Current.Value = calculator != null ? calculator.Ready ? calculator.Value : 0 : 0; } protected override IHasText CreateText() => new TextComponent diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 8f80644d52..1c28e04950 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -22,6 +22,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.HUD.KPSCounter; using osu.Game.Skinning; using osuTK; @@ -49,6 +50,9 @@ namespace osu.Game.Screens.Play public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; + [Cached] + private readonly KeysPerSecondCalculator keysPerSecondCalculator; + public Bindable ShowHealthBar = new Bindable(true); private readonly DrawableRuleset drawableRuleset; @@ -122,7 +126,8 @@ namespace osu.Game.Screens.Play KeyCounter = CreateKeyCounter(), HoldToQuit = CreateHoldForMenuButton(), } - } + }, + keysPerSecondCalculator = new KeysPerSecondCalculator() }; } @@ -260,6 +265,7 @@ namespace osu.Game.Screens.Play protected virtual void BindDrawableRuleset(DrawableRuleset drawableRuleset) { (drawableRuleset as ICanAttachKeyCounter)?.Attach(KeyCounter); + (drawableRuleset as ICanAttachKpsCalculator)?.Attach(keysPerSecondCalculator); replayLoaded.BindTo(drawableRuleset.HasReplayLoaded); } diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs index 044c9ee24e..1e5ada5295 100644 --- a/osu.Game/Screens/Play/KeyCounter.cs +++ b/osu.Game/Screens/Play/KeyCounter.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Screens.Play.HUD.KPSCounter; using osuTK; using osuTK.Graphics; @@ -56,7 +55,6 @@ namespace osu.Game.Screens.Play public void Increment() { - KeysPerSecondCalculator.AddInput(); if (!IsCounting) return; From edb8e5e33e3649f0be60e8b4a53498ab200076a4 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Tue, 9 Aug 2022 02:43:41 +0200 Subject: [PATCH 0360/2686] Temporarily emptying `TestSceneKeysPerSecondCounter` until a good test can be found --- .../Gameplay/TestSceneKeysPerSecondCounter.cs | 70 +------------------ 1 file changed, 1 insertion(+), 69 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs index 6e59c53a1f..8bc2eae1d4 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs @@ -1,77 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mania; -using osu.Game.Rulesets.UI; -using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD.KPSCounter; -using osuTK; -using osuTK.Input; - namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneKeysPerSecondCounter : PlayerTestScene + public class TestSceneKeysPerSecondCounter : OsuManualInputManagerTestScene { - protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); - protected override bool HasCustomSteps => false; - protected override bool Autoplay => false; - protected override TestPlayer CreatePlayer(Ruleset ruleset) => new TestPlayer(true, false); - - private GameplayClock gameplayClock; - private DrawableRuleset drawableRuleset; - - private KeysPerSecondCounter counter; - - private void createCounter() - { - AddStep("Create counter", () => - { - gameplayClock = Player.GameplayClockContainer.GameplayClock; - drawableRuleset = Player.DrawableRuleset; - - Player.HUDOverlay.Add(counter = new KeysPerSecondCounter - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(5), - }); - counter.SmoothingTime.Value = 0; - }); - AddUntilStep("Counter created", () => Player.HUDOverlay.Contains(counter)); - } - - [Test] - public void TestBasic() - { - createCounter(); - - AddStep("press 1 key", () => InputManager.Key(Key.D)); - AddAssert("KPS = 1", () => counter.Current.Value == 1); - AddUntilStep("Wait for KPS cooldown", () => counter.Current.Value <= 0); - AddStep("press 4 keys", () => - { - InputManager.Key(Key.D); - InputManager.Key(Key.F); - InputManager.Key(Key.J); - InputManager.Key(Key.K); - }); - AddAssert("KPS = 4", () => counter.Current.Value == 4); - AddStep("Pause player", () => Player.Pause()); - AddAssert("KPS = 4", () => counter.Current.Value == 4); - AddStep("Resume player", () => Player.Resume()); - AddStep("press 4 keys", () => - { - InputManager.Key(Key.D); - InputManager.Key(Key.F); - InputManager.Key(Key.J); - InputManager.Key(Key.K); - }); - AddAssert("KPS = 8", () => counter.Current.Value == 8); - } } } From a52fa8eb8b9a769b1fc481cc33052f881c76e367 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 9 Aug 2022 13:20:20 +0900 Subject: [PATCH 0361/2686] Rename const --- .../Objects/Drawables/DrawableBarLine.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs index bf0bc84f9b..6020348938 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables if (barLine.Major) { Vector2 size = new Vector2(22, 6); - const float triangle_offset = 4; + const float line_offset = 4; AddInternal(new Circle { @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Origin = Anchor.CentreRight, Size = size, - X = -triangle_offset, + X = -line_offset, }); AddInternal(new Circle @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Anchor = Anchor.CentreRight, Origin = Anchor.CentreLeft, Size = size, - X = triangle_offset, + X = line_offset, }); } } From 6c671434ec9670443fbd1a118ec95a218da955b5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 9 Aug 2022 14:41:36 +0900 Subject: [PATCH 0362/2686] Fix gameplay tests crashing when run multiple times --- osu.Game/Screens/Play/SubmittingPlayer.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index 02a95ae9eb..2e9e01ab8d 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -203,5 +203,15 @@ namespace osu.Game.Screens.Play api.Queue(request); return scoreSubmissionSource.Task; } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + // Specific to tests, the player can be disposed without OnExiting() ever being called. + // We should make sure that the gameplay session has finished even in this case. + if (LoadedBeatmapSuccessfully) + spectatorClient.EndPlaying(GameplayState); + } } } From 00bdd52cffa923616b480830464daee1f84c0e0d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 9 Aug 2022 15:05:05 +0900 Subject: [PATCH 0363/2686] Move to TestPlayer and add null check --- osu.Game/Screens/Play/SubmittingPlayer.cs | 10 ---------- osu.Game/Tests/Visual/TestPlayer.cs | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index 2e9e01ab8d..02a95ae9eb 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -203,15 +203,5 @@ namespace osu.Game.Screens.Play api.Queue(request); return scoreSubmissionSource.Task; } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - // Specific to tests, the player can be disposed without OnExiting() ever being called. - // We should make sure that the gameplay session has finished even in this case. - if (LoadedBeatmapSuccessfully) - spectatorClient.EndPlaying(GameplayState); - } } } diff --git a/osu.Game/Tests/Visual/TestPlayer.cs b/osu.Game/Tests/Visual/TestPlayer.cs index e2ddd1734d..5cc01a8918 100644 --- a/osu.Game/Tests/Visual/TestPlayer.cs +++ b/osu.Game/Tests/Visual/TestPlayer.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.API; using osu.Game.Online.Rooms; +using osu.Game.Online.Spectator; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; @@ -46,6 +47,9 @@ namespace osu.Game.Tests.Visual public readonly List Results = new List(); + [Resolved] + private SpectatorClient spectatorClient { get; set; } + public TestPlayer(bool allowPause = true, bool showResults = true, bool pauseOnFocusLost = false) : base(new PlayerConfiguration { @@ -98,5 +102,15 @@ namespace osu.Game.Tests.Visual ScoreProcessor.NewJudgement += r => Results.Add(r); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + // Specific to tests, the player can be disposed without OnExiting() ever being called. + // We should make sure that the gameplay session has finished even in this case. + if (LoadedBeatmapSuccessfully) + spectatorClient.EndPlaying(GameplayState); + } } } From c7313ac3712436e81b7931204e19500dedfe4ba8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 15:34:11 +0900 Subject: [PATCH 0364/2686] Allow `LoadingLayer`'s spinning circle to scale smaller than before --- osu.Game/Graphics/UserInterface/LoadingLayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index b3655eaab4..29b0201225 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -83,7 +83,7 @@ namespace osu.Game.Graphics.UserInterface { base.Update(); - MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100)); + MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 20, 100)); } } } From f65b7ef058b4ad3a20f9df593fcd4fb428ac4660 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Tue, 9 Aug 2022 02:49:53 -0400 Subject: [PATCH 0365/2686] Add keybind for showing profile --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 4 ++++ osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 5 +++++ osu.Game/OsuGame.cs | 4 ++++ osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 1 + 4 files changed, 14 insertions(+) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 1ee03a6964..d7a3bbba55 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -52,6 +52,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings), new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing), new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications), + new KeyBinding(new[] { InputKey.Control, InputKey.P }, GlobalAction.ShowProfile), new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.S }, GlobalAction.ToggleSkinEditor), new KeyBinding(InputKey.Escape, GlobalAction.Back), @@ -232,6 +233,9 @@ namespace osu.Game.Input.Bindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleNotifications))] ToggleNotifications, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ShowProfile))] + ShowProfile, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.PauseGameplay))] PauseGameplay, diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index de1a5b189c..9089834c30 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -149,6 +149,11 @@ namespace osu.Game.Localisation /// public static LocalisableString ToggleNotifications => new TranslatableString(getKey(@"toggle_notifications"), @"Toggle notifications"); + /// + /// "Show Profile" + /// + public static LocalisableString ShowProfile => new TranslatableString(getKey(@"toggle_notifications"), @"Show Profile"); + /// /// "Pause gameplay" /// diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 78cc4d7f70..9c160d39fa 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1138,6 +1138,10 @@ namespace osu.Game mouseDisableButtons.Value = !mouseDisableButtons.Value; return true; + case GlobalAction.ShowProfile: + ShowUser(new APIUser { Id = API.LocalUser.Value.Id }); + return true; + case GlobalAction.RandomSkin: // Don't allow random skin selection while in the skin editor. // This is mainly to stop many "osu! default (modified)" skins being created via the SkinManager.EnsureMutableSkin() path. diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index a93ba17c5b..ef8157394b 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -15,6 +15,7 @@ using osu.Game.Resources.Localisation.Web; using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; +using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { From aa9ced7f0409f9ace45a7ba6ee4e28e2424524d1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 15:34:33 +0900 Subject: [PATCH 0366/2686] Add test coverage of `ToolbarUserButton` --- .../Menus/TestSceneToolbarUserButton.cs | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs new file mode 100644 index 0000000000..2901501b30 --- /dev/null +++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs @@ -0,0 +1,87 @@ +// 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 NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Online.API; +using osu.Game.Overlays.Toolbar; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual.Menus +{ + [TestFixture] + public class TestSceneToolbarUserButton : OsuManualInputManagerTestScene + { + public TestSceneToolbarUserButton() + { + Container mainContainer; + + Children = new Drawable[] + { + mainContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Height = Toolbar.HEIGHT, + Children = new Drawable[] + { + new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new Box + { + Colour = Color4.DarkRed, + RelativeSizeAxes = Axes.Y, + Width = 2, + }, + new ToolbarUserButton(), + new Box + { + Colour = Color4.DarkRed, + RelativeSizeAxes = Axes.Y, + Width = 2, + }, + } + }, + } + }, + }; + + AddSliderStep("scale", 0.5, 4, 1, scale => mainContainer.Scale = new Vector2((float)scale)); + } + + [Test] + public void TestLoginLogout() + { + AddStep("Log out", () => ((DummyAPIAccess)API).Logout()); + AddStep("Log in", () => ((DummyAPIAccess)API).Login("wang", "jang")); + } + + [Test] + public void TestStates() + { + AddStep("Log in", () => ((DummyAPIAccess)API).Login("wang", "jang")); + + foreach (var state in Enum.GetValues()) + { + AddStep($"Change state to {state}", () => ((DummyAPIAccess)API).SetState(state)); + } + } + } +} From c35b4ef914393e404273ca9a0d08227b062d065d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 15:34:45 +0900 Subject: [PATCH 0367/2686] Display connecting / failing states on toolbar user display --- .../Overlays/Toolbar/ToolbarUserButton.cs | 82 ++++++++++++++----- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index a93ba17c5b..b9220a2520 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -1,17 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Resources.Localisation.Web; using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; @@ -20,59 +22,97 @@ namespace osu.Game.Overlays.Toolbar { public class ToolbarUserButton : ToolbarOverlayToggleButton { - private readonly UpdateableAvatar avatar; + private UpdateableAvatar avatar = null!; - [Resolved] - private IAPIProvider api { get; set; } + private IBindable localUser = null!; - private readonly IBindable apiState = new Bindable(); + private LoadingSpinner spinner = null!; + + private SpriteIcon failingIcon = null!; + + private IBindable apiState = null!; public ToolbarUserButton() { AutoSizeAxes = Axes.X; + } - DrawableText.Font = OsuFont.GetFont(italics: true); - + [BackgroundDependencyLoader] + private void load(OsuColour colours, IAPIProvider api, LoginOverlay? login) + { Add(new OpaqueBackground { Depth = 1 }); - Flow.Add(avatar = new UpdateableAvatar(isInteractive: false) + Flow.Add(new Container { Masking = true, + CornerRadius = 4, Size = new Vector2(32), Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - CornerRadius = 4, EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, Radius = 4, Colour = Color4.Black.Opacity(0.1f), + }, + Children = new Drawable[] + { + avatar = new UpdateableAvatar(isInteractive: false) + { + RelativeSizeAxes = Axes.Both, + }, + spinner = new LoadingLayer(dimBackground: true, withBox: false, blockInput: false) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + }, + failingIcon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + Size = new Vector2(0.3f), + Icon = FontAwesome.Solid.ExclamationTriangle, + RelativeSizeAxes = Axes.Both, + Colour = colours.YellowLight, + }, } }); - } - [BackgroundDependencyLoader(true)] - private void load(LoginOverlay login) - { - apiState.BindTo(api.State); + apiState = api.State.GetBoundCopy(); apiState.BindValueChanged(onlineStateChanged, true); + localUser = api.LocalUser.GetBoundCopy(); + localUser.BindValueChanged(userChanged, true); + StateContainer = login; } + private void userChanged(ValueChangedEvent user) + { + Text = user.NewValue.Username; + avatar.User = user.NewValue; + } + private void onlineStateChanged(ValueChangedEvent state) => Schedule(() => { + failingIcon.FadeTo(state.NewValue == APIState.Failing ? 1 : 0, 200, Easing.OutQuint); + switch (state.NewValue) { - default: - Text = UsersStrings.AnonymousUsername; - avatar.User = new APIUser(); + case APIState.Connecting: + case APIState.Failing: + spinner.Show(); break; + case APIState.Offline: case APIState.Online: - Text = api.LocalUser.Value.Username; - avatar.User = api.LocalUser.Value; + spinner.Hide(); break; + + default: + throw new ArgumentOutOfRangeException(); } }); } From 4da9482a3ef765659bdb1ec3edc46a8840e09ea7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 15:43:13 +0900 Subject: [PATCH 0368/2686] Add ability for loading layer to not block input --- osu.Game/Graphics/UserInterface/LoadingLayer.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 29b0201225..9f6177c226 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -20,6 +20,8 @@ namespace osu.Game.Graphics.UserInterface /// public class LoadingLayer : LoadingSpinner { + private readonly bool blockInput; + [CanBeNull] protected Box BackgroundDimLayer { get; } @@ -28,9 +30,11 @@ namespace osu.Game.Graphics.UserInterface /// /// Whether the full background area should be dimmed while loading. /// Whether the spinner should have a surrounding black box for visibility. - public LoadingLayer(bool dimBackground = false, bool withBox = true) + /// Whether to block input of components behind the loading layer. + public LoadingLayer(bool dimBackground = false, bool withBox = true, bool blockInput = true) : base(withBox) { + this.blockInput = blockInput; RelativeSizeAxes = Axes.Both; Size = new Vector2(1); @@ -52,6 +56,9 @@ namespace osu.Game.Graphics.UserInterface protected override bool Handle(UIEvent e) { + if (!blockInput) + return false; + switch (e) { // blocking scroll can cause weird behaviour when this layer is used within a ScrollContainer. From 3f8cedff3aca07de087ad209fbee87e3f56efdbd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 15:43:26 +0900 Subject: [PATCH 0369/2686] Add tooltips showing current connecting status --- osu.Game/Localisation/ToolbarStrings.cs | 24 +++++++++++++++++++ .../Overlays/Toolbar/ToolbarUserButton.cs | 6 +++++ 2 files changed, 30 insertions(+) create mode 100644 osu.Game/Localisation/ToolbarStrings.cs diff --git a/osu.Game/Localisation/ToolbarStrings.cs b/osu.Game/Localisation/ToolbarStrings.cs new file mode 100644 index 0000000000..21476f6d6f --- /dev/null +++ b/osu.Game/Localisation/ToolbarStrings.cs @@ -0,0 +1,24 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class ToolbarStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.Toolbar"; + + /// + /// "Connection interrupted, will try to reconnect..." + /// + public static LocalisableString ConnectionInterruptedWillTryTo => new TranslatableString(getKey(@"connection_interrupted_will_try_to"), @"Connection interrupted, will try to reconnect..."); + + /// + /// "Connecting..." + /// + public static LocalisableString Connecting => new TranslatableString(getKey(@"connecting"), @"Connecting..."); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index b9220a2520..a787bde508 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -102,12 +102,18 @@ namespace osu.Game.Overlays.Toolbar switch (state.NewValue) { case APIState.Connecting: + TooltipText = ToolbarStrings.Connecting; + spinner.Show(); + break; + case APIState.Failing: + TooltipText = ToolbarStrings.ConnectionInterruptedWillTryTo; spinner.Show(); break; case APIState.Offline: case APIState.Online: + TooltipText = string.Empty; spinner.Hide(); break; From 3473347f35335877eb8c7ecbb4c134505d885302 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Tue, 9 Aug 2022 02:56:12 -0400 Subject: [PATCH 0370/2686] Lowercase "p" --- osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 9089834c30..e28ec4eb09 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -150,9 +150,9 @@ namespace osu.Game.Localisation public static LocalisableString ToggleNotifications => new TranslatableString(getKey(@"toggle_notifications"), @"Toggle notifications"); /// - /// "Show Profile" + /// "Show profile" /// - public static LocalisableString ShowProfile => new TranslatableString(getKey(@"toggle_notifications"), @"Show Profile"); + public static LocalisableString ShowProfile => new TranslatableString(getKey(@"toggle_notifications"), @"Show profile"); /// /// "Pause gameplay" From 5d8bd1de288efacf2481aa5f30f2bb2abdddedc4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 15:57:16 +0900 Subject: [PATCH 0371/2686] Share localised strings with expanded display message --- osu.Game/Localisation/ToolbarStrings.cs | 2 +- osu.Game/Overlays/Login/LoginPanel.cs | 3 ++- osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/ToolbarStrings.cs b/osu.Game/Localisation/ToolbarStrings.cs index 21476f6d6f..6dc8a1e50c 100644 --- a/osu.Game/Localisation/ToolbarStrings.cs +++ b/osu.Game/Localisation/ToolbarStrings.cs @@ -12,7 +12,7 @@ namespace osu.Game.Localisation /// /// "Connection interrupted, will try to reconnect..." /// - public static LocalisableString ConnectionInterruptedWillTryTo => new TranslatableString(getKey(@"connection_interrupted_will_try_to"), @"Connection interrupted, will try to reconnect..."); + public static LocalisableString AttemptingToReconnect => new TranslatableString(getKey(@"attempting_to_reconnect"), @"Connection interrupted, will try to reconnect..."); /// /// "Connecting..." diff --git a/osu.Game/Overlays/Login/LoginPanel.cs b/osu.Game/Overlays/Login/LoginPanel.cs index 1d8926b991..32a7fca1a6 100644 --- a/osu.Game/Overlays/Login/LoginPanel.cs +++ b/osu.Game/Overlays/Login/LoginPanel.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Users; using osuTK; @@ -109,7 +110,7 @@ namespace osu.Game.Overlays.Login Origin = Anchor.TopCentre, TextAnchor = Anchor.TopCentre, AutoSizeAxes = Axes.Both, - Text = state.NewValue == APIState.Failing ? "Connection is failing, will attempt to reconnect... " : "Attempting to connect... ", + Text = state.NewValue == APIState.Failing ? ToolbarStrings.AttemptingToReconnect : ToolbarStrings.Connecting, Margin = new MarginPadding { Top = 10, Bottom = 10 }, }, }; diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index a787bde508..02d3059ba4 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.Toolbar break; case APIState.Failing: - TooltipText = ToolbarStrings.ConnectionInterruptedWillTryTo; + TooltipText = ToolbarStrings.AttemptingToReconnect; spinner.Show(); break; From ededaed5ef3dad1798063ed698efda25cf4b35b1 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Tue, 9 Aug 2022 02:58:28 -0400 Subject: [PATCH 0372/2686] Remove unused import --- osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index ef8157394b..a93ba17c5b 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -15,7 +15,6 @@ using osu.Game.Resources.Localisation.Web; using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; -using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { From 32852e5b213dd65bd596ab52a3ab840f956a5da8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 16:01:04 +0900 Subject: [PATCH 0373/2686] Fix potentially thread-unsafe `LocalUser` usage --- osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 02d3059ba4..4ebd19a1f7 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -89,11 +89,11 @@ namespace osu.Game.Overlays.Toolbar StateContainer = login; } - private void userChanged(ValueChangedEvent user) + private void userChanged(ValueChangedEvent user) => Schedule(() => { Text = user.NewValue.Username; avatar.User = user.NewValue; - } + }); private void onlineStateChanged(ValueChangedEvent state) => Schedule(() => { From 04108a749e9703be3349fb3c278513854be390f2 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Tue, 9 Aug 2022 03:03:14 -0400 Subject: [PATCH 0374/2686] Rename translation key --- osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index e28ec4eb09..0624a5b34b 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -152,7 +152,7 @@ namespace osu.Game.Localisation /// /// "Show profile" /// - public static LocalisableString ShowProfile => new TranslatableString(getKey(@"toggle_notifications"), @"Show profile"); + public static LocalisableString ShowProfile => new TranslatableString(getKey(@"show_profile"), @"Show profile"); /// /// "Pause gameplay" From a705c4f5d2ebfdf4d2f79758500b1ddc13e40d7e Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Tue, 9 Aug 2022 03:17:55 -0400 Subject: [PATCH 0375/2686] Moved ShowProfile to the bottom of the enum --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index d7a3bbba55..4fc85b135f 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -233,9 +233,6 @@ namespace osu.Game.Input.Bindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleNotifications))] ToggleNotifications, - [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ShowProfile))] - ShowProfile, - [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.PauseGameplay))] PauseGameplay, @@ -336,5 +333,8 @@ namespace osu.Game.Input.Bindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleFPSCounter))] ToggleFPSDisplay, + + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ShowProfile))] + ShowProfile, } } From a71c2bbe28a490b765be2179780d85c12e71eba3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 17:01:36 +0900 Subject: [PATCH 0376/2686] Split overlay toggles into own section in key bindings Things were getting hard to find.. --- .../Input/Bindings/GlobalActionContainer.cs | 25 +++++++++++-------- osu.Game/Localisation/InputSettingsStrings.cs | 5 ++++ .../Input/GlobalKeyBindingsSection.cs | 14 +++++++++-- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 1ee03a6964..f1ab342f5e 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics; @@ -15,8 +13,9 @@ namespace osu.Game.Input.Bindings { public class GlobalActionContainer : DatabasedKeyBindingContainer, IHandleGlobalKeyboardInput { - private readonly Drawable handler; - private InputManager parentInputManager; + private readonly Drawable? handler; + + private InputManager? parentInputManager; public GlobalActionContainer(OsuGameBase game) : base(matchingMode: KeyCombinationMatchingMode.Modifiers) @@ -33,6 +32,7 @@ namespace osu.Game.Input.Bindings } public override IEnumerable DefaultKeyBindings => GlobalKeyBindings + .Concat(OverlayKeyBindings) .Concat(EditorKeyBindings) .Concat(InGameKeyBindings) .Concat(SongSelectKeyBindings) @@ -40,18 +40,11 @@ namespace osu.Game.Input.Bindings public IEnumerable GlobalKeyBindings => new[] { - new KeyBinding(InputKey.F6, GlobalAction.ToggleNowPlaying), - new KeyBinding(InputKey.F8, GlobalAction.ToggleChat), - new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial), new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons), new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot), new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.F }, GlobalAction.ToggleFPSDisplay), - new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings), new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar), - new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings), - new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing), - new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications), new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.S }, GlobalAction.ToggleSkinEditor), new KeyBinding(InputKey.Escape, GlobalAction.Back), @@ -72,6 +65,16 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.R }, GlobalAction.RandomSkin), }; + public IEnumerable OverlayKeyBindings => new[] + { + new KeyBinding(InputKey.F8, GlobalAction.ToggleChat), + new KeyBinding(InputKey.F6, GlobalAction.ToggleNowPlaying), + new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial), + new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing), + new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings), + new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications), + }; + public IEnumerable EditorKeyBindings => new[] { new KeyBinding(new[] { InputKey.F1 }, GlobalAction.EditorComposeMode), diff --git a/osu.Game/Localisation/InputSettingsStrings.cs b/osu.Game/Localisation/InputSettingsStrings.cs index e46b4cecf3..a0da6cc2f7 100644 --- a/osu.Game/Localisation/InputSettingsStrings.cs +++ b/osu.Game/Localisation/InputSettingsStrings.cs @@ -19,6 +19,11 @@ namespace osu.Game.Localisation /// public static LocalisableString GlobalKeyBindingHeader => new TranslatableString(getKey(@"global_key_binding_header"), @"Global"); + /// + /// "Overlays" + /// + public static LocalisableString OverlaysSection => new TranslatableString(getKey(@"overlays_section"), @"Overlays"); + /// /// "Song Select" /// diff --git a/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs b/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs index a2e07065f1..7ab10a3c3a 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.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. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; @@ -23,6 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input public GlobalKeyBindingsSection(GlobalActionContainer manager) { Add(new DefaultBindingsSubsection(manager)); + Add(new OverlayBindingsSubsection(manager)); Add(new AudioControlKeyBindingsSubsection(manager)); Add(new SongSelectKeyBindingSubsection(manager)); Add(new InGameKeyBindingsSubsection(manager)); @@ -40,6 +39,17 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } + private class OverlayBindingsSubsection : KeyBindingsSubsection + { + protected override LocalisableString Header => InputSettingsStrings.OverlaysSection; + + public OverlayBindingsSubsection(GlobalActionContainer manager) + : base(null) + { + Defaults = manager.OverlayKeyBindings; + } + } + private class SongSelectKeyBindingSubsection : KeyBindingsSubsection { protected override LocalisableString Header => InputSettingsStrings.SongSelectSection; From 961f5d4accf594776895fa1503907a515762ebee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 17:08:31 +0900 Subject: [PATCH 0377/2686] Reorganise global bindings section to be easier to find things --- .../Input/Bindings/GlobalActionContainer.cs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index f1ab342f5e..ef31192079 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -40,18 +40,6 @@ namespace osu.Game.Input.Bindings public IEnumerable GlobalKeyBindings => new[] { - new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons), - new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot), - new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.F }, GlobalAction.ToggleFPSDisplay), - new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings), - new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar), - new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.S }, GlobalAction.ToggleSkinEditor), - - new KeyBinding(InputKey.Escape, GlobalAction.Back), - new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back), - - new KeyBinding(new[] { InputKey.Alt, InputKey.Home }, GlobalAction.Home), - new KeyBinding(InputKey.Up, GlobalAction.SelectPrevious), new KeyBinding(InputKey.Down, GlobalAction.SelectNext), @@ -62,7 +50,21 @@ namespace osu.Game.Input.Bindings new KeyBinding(InputKey.Enter, GlobalAction.Select), new KeyBinding(InputKey.KeypadEnter, GlobalAction.Select), + new KeyBinding(InputKey.Escape, GlobalAction.Back), + new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back), + + new KeyBinding(new[] { InputKey.Alt, InputKey.Home }, GlobalAction.Home), + + new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.F }, GlobalAction.ToggleFPSDisplay), + new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar), + new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.S }, GlobalAction.ToggleSkinEditor), + + new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings), + new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.R }, GlobalAction.RandomSkin), + + new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons), + new KeyBinding(InputKey.F12, GlobalAction.TakeScreenshot), }; public IEnumerable OverlayKeyBindings => new[] From aee18135a98be2610af30321d238328d04c1b59f Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Tue, 9 Aug 2022 04:09:22 -0400 Subject: [PATCH 0378/2686] Switch to toggle --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 6 +++--- osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 4 ++-- osu.Game/OsuGame.cs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 4fc85b135f..8b69e22324 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -52,7 +52,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings), new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing), new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications), - new KeyBinding(new[] { InputKey.Control, InputKey.P }, GlobalAction.ShowProfile), + new KeyBinding(new[] { InputKey.Control, InputKey.P }, GlobalAction.ToggleProfile), new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.S }, GlobalAction.ToggleSkinEditor), new KeyBinding(InputKey.Escape, GlobalAction.Back), @@ -334,7 +334,7 @@ namespace osu.Game.Input.Bindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleFPSCounter))] ToggleFPSDisplay, - [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ShowProfile))] - ShowProfile, + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleProfile))] + ToggleProfile, } } diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 0624a5b34b..172818c1c0 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -150,9 +150,9 @@ namespace osu.Game.Localisation public static LocalisableString ToggleNotifications => new TranslatableString(getKey(@"toggle_notifications"), @"Toggle notifications"); /// - /// "Show profile" + /// "Toggle profile" /// - public static LocalisableString ShowProfile => new TranslatableString(getKey(@"show_profile"), @"Show profile"); + public static LocalisableString ToggleProfile => new TranslatableString(getKey(@"toggle_profile"), @"Toggle profile"); /// /// "Pause gameplay" diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 9c160d39fa..f0d61ed07a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1138,7 +1138,7 @@ namespace osu.Game mouseDisableButtons.Value = !mouseDisableButtons.Value; return true; - case GlobalAction.ShowProfile: + case GlobalAction.ToggleProfile: ShowUser(new APIUser { Id = API.LocalUser.Value.Id }); return true; From beb3d41f0c945a77a24307de5a4940616a1b10df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 16:38:12 +0900 Subject: [PATCH 0379/2686] Fix unsafe usage of `APIAccess.LocalUser` in `BeatmapListingOverlay` --- osu.Game/Overlays/BeatmapListingOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index cfa53009ef..3136492af0 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -104,11 +104,11 @@ namespace osu.Game.Overlays filterControl.CardSize.BindValueChanged(_ => onCardSizeChanged()); apiUser = api.LocalUser.GetBoundCopy(); - apiUser.BindValueChanged(_ => + apiUser.BindValueChanged(_ => Schedule(() => { if (api.IsLoggedIn) addContentToResultsArea(Drawable.Empty()); - }); + })); } public void ShowWithSearch(string query) From f9d0cc3c4e5a8c39034fab117ba3c622eb5a36e9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 16:38:59 +0900 Subject: [PATCH 0380/2686] Change `APIAccess.IsLoggedIn` to also return `true` when connecting All usages of this are made with the intention of showing data when an api is going to eventually become available. In the case of a login failure, components are also able to display a correct state. With this change, it makes online components display in a more correct state during startup or initial logging in phase. --- osu.Game/Online/API/APIAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 7af19f6dd1..e198632ea6 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -402,7 +402,7 @@ namespace osu.Game.Online.API } } - public bool IsLoggedIn => localUser.Value.Id > 1; // TODO: should this also be true if attempting to connect? + public bool IsLoggedIn => State.Value > APIState.Offline; public void Queue(APIRequest request) { From 4a312d5658d5ce2ff22fd0a79d36006508400e9b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 16:40:20 +0900 Subject: [PATCH 0381/2686] Use a placeholder user with the correct username during connecting process This allows for various components (like gameplay) to obtain a correct username even if the API is not yet in a connected state. The most common case is during startup, where a connection may not have been established yet, but the user's username was restored from their config file. By making the change, local scores will now have the correct username (although avatar etc. will be missing, which I think it fine) even if the API is not yet connected. Previously, they would show up as "Guest". --- osu.Game/Online/API/APIAccess.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index e198632ea6..42133160ca 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -137,6 +137,17 @@ namespace osu.Game.Online.API state.Value = APIState.Connecting; + if (localUser.IsDefault) + { + // Show a placeholder user if saved credentials are available. + // This is useful for storing local scores and showing a placeholder username after starting the game, + // until a valid connection has been established. + localUser.Value = new APIUser + { + Username = ProvidedUsername, + }; + } + // save the username at this point, if the user requested for it to be. config.SetValue(OsuSetting.Username, config.Get(OsuSetting.SaveUsername) ? ProvidedUsername : string.Empty); From 106932b906d4c53a5b44c16195357fd8952054c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 18:15:50 +0900 Subject: [PATCH 0382/2686] Add null check in `TestPlayer`'s disposal code to avoid cascading test failure --- osu.Game/Tests/Visual/TestPlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/TestPlayer.cs b/osu.Game/Tests/Visual/TestPlayer.cs index 5cc01a8918..93a155e083 100644 --- a/osu.Game/Tests/Visual/TestPlayer.cs +++ b/osu.Game/Tests/Visual/TestPlayer.cs @@ -110,7 +110,7 @@ namespace osu.Game.Tests.Visual // Specific to tests, the player can be disposed without OnExiting() ever being called. // We should make sure that the gameplay session has finished even in this case. if (LoadedBeatmapSuccessfully) - spectatorClient.EndPlaying(GameplayState); + spectatorClient?.EndPlaying(GameplayState); } } } From 940629f2f1c04dd3e8afdae59a52d9e54fe335b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 18:17:05 +0900 Subject: [PATCH 0383/2686] Fix database storing order being changed by previous changes --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index ef31192079..8c9f74e657 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -31,12 +31,14 @@ namespace osu.Game.Input.Bindings parentInputManager = GetContainingInputManager(); } + // IMPORTANT: Do not change the order of key bindings in this list. + // It is used to decide the int values when storing settings in DatabasedKeyBindingContainer. public override IEnumerable DefaultKeyBindings => GlobalKeyBindings - .Concat(OverlayKeyBindings) .Concat(EditorKeyBindings) .Concat(InGameKeyBindings) .Concat(SongSelectKeyBindings) - .Concat(AudioControlKeyBindings); + .Concat(AudioControlKeyBindings) + .Concat(OverlayKeyBindings); public IEnumerable GlobalKeyBindings => new[] { From 1270ee962406a134e3f29a816891a46d3012cfcb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 19:15:32 +0900 Subject: [PATCH 0384/2686] Update multiple tests to use new assert output for easier to understand failures --- ...tSceneHitObjectComposerDistanceSnapping.cs | 2 +- .../Visual/Editing/TestSceneEditorClock.cs | 10 +- .../Editing/TestSceneEditorSeekSnapping.cs | 108 +++++++++--------- .../Visual/Editing/TestSceneEditorSeeking.cs | 3 +- 4 files changed, 62 insertions(+), 61 deletions(-) diff --git a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs index c2df9e5e09..0e80f8f699 100644 --- a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs +++ b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs @@ -206,7 +206,7 @@ namespace osu.Game.Tests.Editing } private void assertSnapDistance(float expectedDistance, HitObject hitObject = null) - => AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(hitObject ?? new HitObject()) == expectedDistance); + => AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(hitObject ?? new HitObject()), () => Is.EqualTo(expectedDistance)); private void assertDurationToDistance(double duration, float expectedDistance) => AddAssert($"duration = {duration} -> distance = {expectedDistance}", () => composer.DurationToDistance(new HitObject(), duration) == expectedDistance); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs index 3be6371f28..96ba802a5f 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Editing { AddStep("reset clock", () => Clock.Seek(0)); - AddStep("start clock", Clock.Start); + AddStep("start clock", () => Clock.Start()); AddAssert("clock running", () => Clock.IsRunning); AddStep("seek near end", () => Clock.Seek(Clock.TrackLength - 250)); @@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength); - AddStep("start clock again", Clock.Start); + AddStep("start clock again", () => Clock.Start()); AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500); } @@ -76,20 +76,20 @@ namespace osu.Game.Tests.Visual.Editing { AddStep("reset clock", () => Clock.Seek(0)); - AddStep("stop clock", Clock.Stop); + AddStep("stop clock", () => Clock.Stop()); AddAssert("clock stopped", () => !Clock.IsRunning); AddStep("seek exactly to end", () => Clock.Seek(Clock.TrackLength)); AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength); - AddStep("start clock again", Clock.Start); + AddStep("start clock again", () => Clock.Start()); AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500); } [Test] public void TestClampWhenSeekOutsideBeatmapBounds() { - AddStep("stop clock", Clock.Stop); + AddStep("stop clock", () => Clock.Stop()); AddStep("seek before start time", () => Clock.Seek(-1000)); AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs index c8ca273db5..185b6a4c6c 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs @@ -60,17 +60,17 @@ namespace osu.Game.Tests.Visual.Editing // Forwards AddStep("Seek(0)", () => Clock.Seek(0)); - AddAssert("Time = 0", () => Clock.CurrentTime == 0); + checkTime(0); AddStep("Seek(33)", () => Clock.Seek(33)); - AddAssert("Time = 33", () => Clock.CurrentTime == 33); + checkTime(33); AddStep("Seek(89)", () => Clock.Seek(89)); - AddAssert("Time = 89", () => Clock.CurrentTime == 89); + checkTime(89); // Backwards AddStep("Seek(25)", () => Clock.Seek(25)); - AddAssert("Time = 25", () => Clock.CurrentTime == 25); + checkTime(25); AddStep("Seek(0)", () => Clock.Seek(0)); - AddAssert("Time = 0", () => Clock.CurrentTime == 0); + checkTime(0); } /// @@ -83,19 +83,19 @@ namespace osu.Game.Tests.Visual.Editing reset(); AddStep("Seek(0), Snap", () => Clock.SeekSnapped(0)); - AddAssert("Time = 0", () => Clock.CurrentTime == 0); + checkTime(0); AddStep("Seek(50), Snap", () => Clock.SeekSnapped(50)); - AddAssert("Time = 50", () => Clock.CurrentTime == 50); + checkTime(50); AddStep("Seek(100), Snap", () => Clock.SeekSnapped(100)); - AddAssert("Time = 100", () => Clock.CurrentTime == 100); + checkTime(100); AddStep("Seek(175), Snap", () => Clock.SeekSnapped(175)); - AddAssert("Time = 175", () => Clock.CurrentTime == 175); + checkTime(175); AddStep("Seek(350), Snap", () => Clock.SeekSnapped(350)); - AddAssert("Time = 350", () => Clock.CurrentTime == 350); + checkTime(350); AddStep("Seek(400), Snap", () => Clock.SeekSnapped(400)); - AddAssert("Time = 400", () => Clock.CurrentTime == 400); + checkTime(400); AddStep("Seek(450), Snap", () => Clock.SeekSnapped(450)); - AddAssert("Time = 450", () => Clock.CurrentTime == 450); + checkTime(450); } /// @@ -108,17 +108,17 @@ namespace osu.Game.Tests.Visual.Editing reset(); AddStep("Seek(24), Snap", () => Clock.SeekSnapped(24)); - AddAssert("Time = 0", () => Clock.CurrentTime == 0); + checkTime(0); AddStep("Seek(26), Snap", () => Clock.SeekSnapped(26)); - AddAssert("Time = 50", () => Clock.CurrentTime == 50); + checkTime(50); AddStep("Seek(150), Snap", () => Clock.SeekSnapped(150)); - AddAssert("Time = 100", () => Clock.CurrentTime == 100); + checkTime(100); AddStep("Seek(170), Snap", () => Clock.SeekSnapped(170)); - AddAssert("Time = 175", () => Clock.CurrentTime == 175); + checkTime(175); AddStep("Seek(274), Snap", () => Clock.SeekSnapped(274)); - AddAssert("Time = 175", () => Clock.CurrentTime == 175); + checkTime(175); AddStep("Seek(276), Snap", () => Clock.SeekSnapped(276)); - AddAssert("Time = 350", () => Clock.CurrentTime == 350); + checkTime(350); } /// @@ -130,15 +130,15 @@ namespace osu.Game.Tests.Visual.Editing reset(); AddStep("SeekForward", () => Clock.SeekForward()); - AddAssert("Time = 50", () => Clock.CurrentTime == 50); + checkTime(50); AddStep("SeekForward", () => Clock.SeekForward()); - AddAssert("Time = 100", () => Clock.CurrentTime == 100); + checkTime(100); AddStep("SeekForward", () => Clock.SeekForward()); - AddAssert("Time = 200", () => Clock.CurrentTime == 200); + checkTime(200); AddStep("SeekForward", () => Clock.SeekForward()); - AddAssert("Time = 400", () => Clock.CurrentTime == 400); + checkTime(400); AddStep("SeekForward", () => Clock.SeekForward()); - AddAssert("Time = 450", () => Clock.CurrentTime == 450); + checkTime(450); } /// @@ -150,17 +150,17 @@ namespace osu.Game.Tests.Visual.Editing reset(); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 50", () => Clock.CurrentTime == 50); + checkTime(50); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 100", () => Clock.CurrentTime == 100); + checkTime(100); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 175", () => Clock.CurrentTime == 175); + checkTime(175); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 350", () => Clock.CurrentTime == 350); + checkTime(350); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 400", () => Clock.CurrentTime == 400); + checkTime(400); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 450", () => Clock.CurrentTime == 450); + checkTime(450); } /// @@ -174,28 +174,28 @@ namespace osu.Game.Tests.Visual.Editing AddStep("Seek(49)", () => Clock.Seek(49)); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 50", () => Clock.CurrentTime == 50); + checkTime(50); AddStep("Seek(49.999)", () => Clock.Seek(49.999)); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 100", () => Clock.CurrentTime == 100); + checkTime(100); AddStep("Seek(99)", () => Clock.Seek(99)); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 100", () => Clock.CurrentTime == 100); + checkTime(100); AddStep("Seek(99.999)", () => Clock.Seek(99.999)); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 100", () => Clock.CurrentTime == 150); + checkTime(100); AddStep("Seek(174)", () => Clock.Seek(174)); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 175", () => Clock.CurrentTime == 175); + checkTime(175); AddStep("Seek(349)", () => Clock.Seek(349)); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 350", () => Clock.CurrentTime == 350); + checkTime(350); AddStep("Seek(399)", () => Clock.Seek(399)); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 400", () => Clock.CurrentTime == 400); + checkTime(400); AddStep("Seek(449)", () => Clock.Seek(449)); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - AddAssert("Time = 450", () => Clock.CurrentTime == 450); + checkTime(450); } /// @@ -208,15 +208,15 @@ namespace osu.Game.Tests.Visual.Editing AddStep("Seek(450)", () => Clock.Seek(450)); AddStep("SeekBackward", () => Clock.SeekBackward()); - AddAssert("Time = 400", () => Clock.CurrentTime == 400); + checkTime(400); AddStep("SeekBackward", () => Clock.SeekBackward()); - AddAssert("Time = 350", () => Clock.CurrentTime == 350); + checkTime(350); AddStep("SeekBackward", () => Clock.SeekBackward()); - AddAssert("Time = 150", () => Clock.CurrentTime == 150); + checkTime(150); AddStep("SeekBackward", () => Clock.SeekBackward()); - AddAssert("Time = 50", () => Clock.CurrentTime == 50); + checkTime(50); AddStep("SeekBackward", () => Clock.SeekBackward()); - AddAssert("Time = 0", () => Clock.CurrentTime == 0); + checkTime(0); } /// @@ -229,17 +229,17 @@ namespace osu.Game.Tests.Visual.Editing AddStep("Seek(450)", () => Clock.Seek(450)); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); - AddAssert("Time = 400", () => Clock.CurrentTime == 400); + checkTime(400); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); - AddAssert("Time = 350", () => Clock.CurrentTime == 350); + checkTime(350); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); - AddAssert("Time = 175", () => Clock.CurrentTime == 175); + checkTime(175); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); - AddAssert("Time = 100", () => Clock.CurrentTime == 100); + checkTime(100); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); - AddAssert("Time = 50", () => Clock.CurrentTime == 50); + checkTime(50); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); - AddAssert("Time = 0", () => Clock.CurrentTime == 0); + checkTime(0); } /// @@ -253,16 +253,16 @@ namespace osu.Game.Tests.Visual.Editing AddStep("Seek(451)", () => Clock.Seek(451)); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); - AddAssert("Time = 450", () => Clock.CurrentTime == 450); + checkTime(450); AddStep("Seek(450.999)", () => Clock.Seek(450.999)); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); - AddAssert("Time = 450", () => Clock.CurrentTime == 450); + checkTime(450); AddStep("Seek(401)", () => Clock.Seek(401)); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); - AddAssert("Time = 400", () => Clock.CurrentTime == 400); + checkTime(400); AddStep("Seek(401.999)", () => Clock.Seek(401.999)); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); - AddAssert("Time = 400", () => Clock.CurrentTime == 400); + checkTime(400); } /// @@ -297,9 +297,11 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("Time < lastTime", () => Clock.CurrentTime < lastTime); } - AddAssert("Time = 0", () => Clock.CurrentTime == 0); + checkTime(0); } + private void checkTime(double expectedTime) => AddAssert($"Current time is {expectedTime}", () => Clock.CurrentTime, () => Is.EqualTo(expectedTime)); + private void reset() { AddStep("Reset", () => Clock.Seek(0)); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs index 6f248f1247..924396ce03 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs @@ -4,7 +4,6 @@ #nullable disable using NUnit.Framework; -using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets; @@ -120,7 +119,7 @@ namespace osu.Game.Tests.Visual.Editing private void pressAndCheckTime(Key key, double expectedTime) { AddStep($"press {key}", () => InputManager.Key(key)); - AddUntilStep($"time is {expectedTime}", () => Precision.AlmostEquals(expectedTime, EditorClock.CurrentTime, 1)); + AddUntilStep($"time is {expectedTime}", () => EditorClock.CurrentTime, () => Is.EqualTo(expectedTime).Within(1)); } } } From 551e1cf7ff28e228a015e74be7492cb2b03f8b2a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 19:26:24 +0900 Subject: [PATCH 0385/2686] Revert ordering and reword comment --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 8c9f74e657..8a358e24d0 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -32,13 +32,13 @@ namespace osu.Game.Input.Bindings } // IMPORTANT: Do not change the order of key bindings in this list. - // It is used to decide the int values when storing settings in DatabasedKeyBindingContainer. + // It is used to decide the order of precedence (see note in DatabasedKeyBindingContainer). public override IEnumerable DefaultKeyBindings => GlobalKeyBindings + .Concat(OverlayKeyBindings) .Concat(EditorKeyBindings) .Concat(InGameKeyBindings) .Concat(SongSelectKeyBindings) - .Concat(AudioControlKeyBindings) - .Concat(OverlayKeyBindings); + .Concat(AudioControlKeyBindings); public IEnumerable GlobalKeyBindings => new[] { From 2de9e5f40f22ed27c6d5fc2bd9396564ee6d1d4e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 9 Aug 2022 20:23:45 +0900 Subject: [PATCH 0386/2686] Fix test failure --- osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs index 185b6a4c6c..d24baa6f63 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs @@ -183,7 +183,7 @@ namespace osu.Game.Tests.Visual.Editing checkTime(100); AddStep("Seek(99.999)", () => Clock.Seek(99.999)); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); - checkTime(100); + checkTime(150); AddStep("Seek(174)", () => Clock.Seek(174)); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); checkTime(175); From 2367dc96107091207c468738a93f6ece62310f05 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Tue, 9 Aug 2022 13:06:11 +0100 Subject: [PATCH 0387/2686] Improved KeepUprightAndUnscaled --- osu.Game/Extensions/DrawableExtensions.cs | 36 +++++++++++------------ 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index f587b1c55b..320b9d7996 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -82,40 +82,38 @@ namespace osu.Game.Extensions } /// - /// Keeps the drawable upright and prevents it from being scaled or flipped with its Parent. + /// Keeps the drawable upright and unstretched preventing it from being rotated, sheared, scaled or flipped with its Parent. /// /// The drawable. public static void KeepUprightAndUnscaled(this Drawable drawable) { + // Decomposes the inverse of the parent FrawInfo.Matrix into rotation, shear and scale. var parentMatrix = drawable.Parent.DrawInfo.Matrix; - float angle = MathF.Atan(parentMatrix.M12 / parentMatrix.M11); - angle = MathHelper.RadiansToDegrees(angle); - parentMatrix.Transpose(); + + // Remove Translation. parentMatrix.M13 = 0.0f; parentMatrix.M23 = 0.0f; - if ((Math.Abs(Math.Abs(angle) - 90.0)) < 2.0f) - { - Matrix3 m = Matrix3.CreateRotationZ(MathHelper.DegreesToRadians(40.0f)); - m.Transpose(); - parentMatrix *= m; - drawable.Rotation = 40.0f; - } - else - drawable.Rotation = 0.0f; - Matrix3 C = parentMatrix.Inverted(); - float alpha, beta, sx, sy; + // Extract the rotation. + float angle = MathF.Atan2(C.M21, C.M11); + drawable.Rotation = MathHelper.RadiansToDegrees(angle); + + // Remove rotation from the C matrix so that it only contains shear and scale. + Matrix3 m = Matrix3.CreateRotationZ(-angle); + m.Transpose(); + C = m * C; + + // Extract shear and scale. + float alpha, sx, sy; + sx = C.M11; sy = C.M22; alpha = C.M12 / C.M22; - beta = (C.M21 == 0.0f) ? 0.0f : 1 / ((C.M11 / C.M21) - alpha); - sx = (beta == 0.0f) ? C.M11 : C.M21 / beta; - drawable.Scale = new Vector2(sx, sy); - drawable.Shear = new Vector2(-alpha, -beta); + drawable.Shear = new Vector2(-alpha, 0); } } } From 4107049b089eb5a38e053fa84995f3c2228121e4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 9 Aug 2022 21:43:09 +0900 Subject: [PATCH 0388/2686] Fix host room status showing ended after playing --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 603bd10c38..04b87c19da 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -196,6 +196,9 @@ namespace osu.Game.Online.Multiplayer APIRoom.Playlist.AddRange(joinedRoom.Playlist.Select(createPlaylistItem)); APIRoom.CurrentPlaylistItem.Value = APIRoom.Playlist.Single(item => item.ID == joinedRoom.Settings.PlaylistItemId); + // The server will null out the end date upon the host joining the room, but the null value is never communicated to the client. + APIRoom.EndDate.Value = null; + Debug.Assert(LocalUser != null); addUserToAPIRoom(LocalUser); From a5081826b78b484d6efa9f8dce7e2377c07448b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 9 Aug 2022 23:25:19 +0900 Subject: [PATCH 0389/2686] Handle cancellation at more points during `Player` initialisation As discussed in discord, this will help avoid null references during cancellation which can otherwise be quite confusing to debug. --- osu.Game/Screens/Play/Player.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9c08c77d91..08b6da1921 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -249,6 +249,9 @@ namespace osu.Game.Screens.Play // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. GameplayClockContainer.Add(rulesetSkinProvider); + if (cancellationToken.IsCancellationRequested) + return; + rulesetSkinProvider.AddRange(new Drawable[] { failAnimationLayer = new FailAnimation(DrawableRuleset) @@ -279,6 +282,9 @@ namespace osu.Game.Screens.Play }, }); + if (cancellationToken.IsCancellationRequested) + return; + if (Configuration.AllowRestart) { rulesetSkinProvider.Add(new HotkeyRetryOverlay From abca3d1b2a1c2597cd5537319db53ab3561aeb69 Mon Sep 17 00:00:00 2001 From: its5Q Date: Wed, 10 Aug 2022 00:35:19 +1000 Subject: [PATCH 0390/2686] Prefix common strings for context --- osu.Game/Configuration/DiscordRichPresenceMode.cs | 4 ++-- osu.Game/Configuration/HUDVisibilityMode.cs | 4 ++-- osu.Game/Configuration/ScalingMode.cs | 6 +++--- osu.Game/Configuration/SeasonalBackgroundMode.cs | 6 +++--- osu.Game/Input/OsuConfineMouseMode.cs | 6 +++--- osu.Game/Localisation/GameplaySettingsStrings.cs | 8 ++++---- osu.Game/Localisation/LayoutSettingsStrings.cs | 6 +++--- osu.Game/Localisation/MouseSettingsStrings.cs | 6 +++--- osu.Game/Localisation/OnlineSettingsStrings.cs | 4 ++-- osu.Game/Localisation/RulesetSettingsStrings.cs | 6 +++--- osu.Game/Localisation/UserInterfaceStrings.cs | 10 +++++----- osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs | 4 ++-- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 4 ++-- osu.Game/Rulesets/UI/PlayfieldBorderStyle.cs | 6 +++--- 14 files changed, 40 insertions(+), 40 deletions(-) diff --git a/osu.Game/Configuration/DiscordRichPresenceMode.cs b/osu.Game/Configuration/DiscordRichPresenceMode.cs index 604c151224..150d23447e 100644 --- a/osu.Game/Configuration/DiscordRichPresenceMode.cs +++ b/osu.Game/Configuration/DiscordRichPresenceMode.cs @@ -10,13 +10,13 @@ namespace osu.Game.Configuration { public enum DiscordRichPresenceMode { - [LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.Off))] + [LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.DiscordPresenceOff))] Off, [LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.HideIdentifiableInformation))] Limited, - [LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.Full))] + [LocalisableDescription(typeof(OnlineSettingsStrings), nameof(OnlineSettingsStrings.DiscordPresenceFull))] Full } } diff --git a/osu.Game/Configuration/HUDVisibilityMode.cs b/osu.Game/Configuration/HUDVisibilityMode.cs index ac85081edf..9c69f33220 100644 --- a/osu.Game/Configuration/HUDVisibilityMode.cs +++ b/osu.Game/Configuration/HUDVisibilityMode.cs @@ -10,13 +10,13 @@ namespace osu.Game.Configuration { public enum HUDVisibilityMode { - [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.Never))] + [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.NeverShowHUD))] Never, [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.HideDuringGameplay))] HideDuringGameplay, - [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.Always))] + [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.AlwaysShowHUD))] Always } } diff --git a/osu.Game/Configuration/ScalingMode.cs b/osu.Game/Configuration/ScalingMode.cs index c655fe1000..c9eaf71183 100644 --- a/osu.Game/Configuration/ScalingMode.cs +++ b/osu.Game/Configuration/ScalingMode.cs @@ -10,16 +10,16 @@ namespace osu.Game.Configuration { public enum ScalingMode { - [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.Off))] + [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScalingOff))] Off, - [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.Everything))] + [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleEverything))] Everything, [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ExcludingOverlays))] ExcludeOverlays, - [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.Gameplay))] + [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleGameplay))] Gameplay, } } diff --git a/osu.Game/Configuration/SeasonalBackgroundMode.cs b/osu.Game/Configuration/SeasonalBackgroundMode.cs index cf01dca0c2..3e6d9e42aa 100644 --- a/osu.Game/Configuration/SeasonalBackgroundMode.cs +++ b/osu.Game/Configuration/SeasonalBackgroundMode.cs @@ -13,19 +13,19 @@ namespace osu.Game.Configuration /// /// Seasonal backgrounds are shown regardless of season, if at all available. /// - [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.Always))] + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.AlwaysSeasonalBackground))] Always, /// /// Seasonal backgrounds are shown only during their corresponding season. /// - [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.Sometimes))] + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.SometimesSeasonalBackground))] Sometimes, /// /// Seasonal backgrounds are never shown. /// - [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.Never))] + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.NeverSeasonalBackground))] Never } } diff --git a/osu.Game/Input/OsuConfineMouseMode.cs b/osu.Game/Input/OsuConfineMouseMode.cs index 97c9df5072..2d914ac6e0 100644 --- a/osu.Game/Input/OsuConfineMouseMode.cs +++ b/osu.Game/Input/OsuConfineMouseMode.cs @@ -18,20 +18,20 @@ namespace osu.Game.Input /// /// The mouse cursor will be free to move outside the game window. /// - [LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.Never))] + [LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.NeverConfine))] Never, /// /// The mouse cursor will be locked to the window bounds during gameplay, /// but may otherwise move freely. /// - [LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.DuringGameplay))] + [LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.ConfineDuringGameplay))] DuringGameplay, /// /// The mouse cursor will always be locked to the window bounds while the game has focus. /// - [LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.Always))] + [LocalisableDescription(typeof(MouseSettingsStrings), nameof(MouseSettingsStrings.AlwaysConfine))] Always } } diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs index 51450d975d..7300af95a5 100644 --- a/osu.Game/Localisation/GameplaySettingsStrings.cs +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -112,22 +112,22 @@ namespace osu.Game.Localisation /// /// "Always" /// - public static LocalisableString Always => new TranslatableString(getKey(@"always"), @"Always"); + public static LocalisableString AlwaysShowHUD => new TranslatableString(getKey(@"always_show_hud"), @"Always"); /// /// "Never" /// - public static LocalisableString Never => new TranslatableString(getKey(@"never"), @"Never"); + public static LocalisableString NeverShowHUD => new TranslatableString(getKey(@"never"), @"Never"); /// /// "Standardised" /// - public static LocalisableString Standardised => new TranslatableString(getKey(@"standardised"), @"Standardised"); + public static LocalisableString StandardisedScoreDisplay => new TranslatableString(getKey(@"standardised_score_display"), @"Standardised"); /// /// "Classic" /// - public static LocalisableString Classic => new TranslatableString(getKey(@"classic"), @"Classic"); + public static LocalisableString ClassicScoreDisplay => new TranslatableString(getKey(@"classic_score_display"), @"Classic"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs index 729b4bce6a..5b409f728d 100644 --- a/osu.Game/Localisation/LayoutSettingsStrings.cs +++ b/osu.Game/Localisation/LayoutSettingsStrings.cs @@ -37,17 +37,17 @@ namespace osu.Game.Localisation /// /// "Everything" /// - public static LocalisableString Everything => new TranslatableString(getKey(@"everything"), @"Everything"); + public static LocalisableString ScaleEverything => new TranslatableString(getKey(@"everything"), @"Everything"); /// /// "Gameplay" /// - public static LocalisableString Gameplay => new TranslatableString(getKey(@"gameplay"), @"Gameplay"); + public static LocalisableString ScaleGameplay => new TranslatableString(getKey(@"gameplay"), @"Gameplay"); /// /// "Off" /// - public static LocalisableString Off => new TranslatableString(getKey(@"scaling_mode.off"), @"Off"); + public static LocalisableString ScalingOff => new TranslatableString(getKey(@"off"), @"Off"); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/MouseSettingsStrings.cs b/osu.Game/Localisation/MouseSettingsStrings.cs index b9ae3de378..c485036486 100644 --- a/osu.Game/Localisation/MouseSettingsStrings.cs +++ b/osu.Game/Localisation/MouseSettingsStrings.cs @@ -67,17 +67,17 @@ namespace osu.Game.Localisation /// /// "Always" /// - public static LocalisableString Always => new TranslatableString(getKey(@"always"), @"Always"); + public static LocalisableString AlwaysConfine => new TranslatableString(getKey(@"always"), @"Always"); /// /// "During Gameplay" /// - public static LocalisableString DuringGameplay => new TranslatableString(getKey(@"during_gameplay"), @"During Gameplay"); + public static LocalisableString ConfineDuringGameplay => new TranslatableString(getKey(@"during_gameplay"), @"During Gameplay"); /// /// "Never" /// - public static LocalisableString Never => new TranslatableString(getKey(@"never"), @"Never"); + public static LocalisableString NeverConfine => new TranslatableString(getKey(@"never"), @"Never"); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/OnlineSettingsStrings.cs b/osu.Game/Localisation/OnlineSettingsStrings.cs index ad47284709..f7ab57f303 100644 --- a/osu.Game/Localisation/OnlineSettingsStrings.cs +++ b/osu.Game/Localisation/OnlineSettingsStrings.cs @@ -72,12 +72,12 @@ namespace osu.Game.Localisation /// /// "Full" /// - public static LocalisableString Full => new TranslatableString(getKey(@"full"), @"Full"); + public static LocalisableString DiscordPresenceFull => new TranslatableString(getKey(@"full"), @"Full"); /// /// "Off" /// - public static LocalisableString Off => new TranslatableString(getKey(@"off"), @"Off"); + public static LocalisableString DiscordPresenceOff => new TranslatableString(getKey(@"off"), @"Off"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/RulesetSettingsStrings.cs b/osu.Game/Localisation/RulesetSettingsStrings.cs index bfd76148ea..92e17cd625 100644 --- a/osu.Game/Localisation/RulesetSettingsStrings.cs +++ b/osu.Game/Localisation/RulesetSettingsStrings.cs @@ -17,17 +17,17 @@ namespace osu.Game.Localisation /// /// "None" /// - public static LocalisableString None => new TranslatableString(getKey(@"none"), @"None"); + public static LocalisableString BorderNone => new TranslatableString(getKey(@"none"), @"None"); /// /// "Corners" /// - public static LocalisableString Corners => new TranslatableString(getKey(@"corners"), @"Corners"); + public static LocalisableString BorderCorners => new TranslatableString(getKey(@"corners"), @"Corners"); /// /// "Full" /// - public static LocalisableString Full => new TranslatableString(getKey(@"full"), @"Full"); + public static LocalisableString BorderFull => new TranslatableString(getKey(@"full"), @"Full"); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index b1f16c05f0..a2752602ad 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -122,27 +122,27 @@ namespace osu.Game.Localisation /// /// "Always" /// - public static LocalisableString Always => new TranslatableString(getKey(@"always"), @"Always"); + public static LocalisableString AlwaysSeasonalBackground => new TranslatableString(getKey(@"always"), @"Always"); /// /// "Never" /// - public static LocalisableString Never => new TranslatableString(getKey(@"never"), @"Never"); + public static LocalisableString NeverSeasonalBackground => new TranslatableString(getKey(@"never"), @"Never"); /// /// "Sometimes" /// - public static LocalisableString Sometimes => new TranslatableString(getKey(@"sometimes"), @"Sometimes"); + public static LocalisableString SometimesSeasonalBackground => new TranslatableString(getKey(@"sometimes"), @"Sometimes"); /// /// "Sequential" /// - public static LocalisableString Sequential => new TranslatableString(getKey(@"sequential"), @"Sequential"); + public static LocalisableString SequentialHotkeyStyle => new TranslatableString(getKey(@"sequential"), @"Sequential"); /// /// "Classic" /// - public static LocalisableString Classic => new TranslatableString(getKey(@"classic"), @"Classic"); + public static LocalisableString ClassicHotkeyStyle => new TranslatableString(getKey(@"classic"), @"Classic"); /// /// "Never repeat" diff --git a/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs b/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs index 17f005c313..abb7a804da 100644 --- a/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs +++ b/osu.Game/Overlays/Mods/Input/ModSelectHotkeyStyle.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Mods.Input /// Individual letters in a row trigger the mods in a sequential fashion. /// Uses . /// - [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.Sequential))] + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.SequentialHotkeyStyle))] Sequential, /// @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Mods.Input /// One keybinding can toggle between what used to be s on stable, /// and some mods in a column may not have any hotkeys at all. /// - [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.Classic))] + [LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.ClassicHotkeyStyle))] Classic } } diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 8b98a799ac..1deac9f08a 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -638,10 +638,10 @@ namespace osu.Game.Rulesets.Scoring public enum ScoringMode { - [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.Standardised))] + [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.StandardisedScoreDisplay))] Standardised, - [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.Classic))] + [LocalisableDescription(typeof(GameplaySettingsStrings), nameof(GameplaySettingsStrings.ClassicScoreDisplay))] Classic } } diff --git a/osu.Game/Rulesets/UI/PlayfieldBorderStyle.cs b/osu.Game/Rulesets/UI/PlayfieldBorderStyle.cs index 9d6c7794a5..79f3a2ca84 100644 --- a/osu.Game/Rulesets/UI/PlayfieldBorderStyle.cs +++ b/osu.Game/Rulesets/UI/PlayfieldBorderStyle.cs @@ -10,13 +10,13 @@ namespace osu.Game.Rulesets.UI { public enum PlayfieldBorderStyle { - [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.None))] + [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.BorderNone))] None, - [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.Corners))] + [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.BorderCorners))] Corners, - [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.Full))] + [LocalisableDescription(typeof(RulesetSettingsStrings), nameof(RulesetSettingsStrings.BorderFull))] Full } } From e8fef6e05c347905f1dbd6d8f6c80febcb7551bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 10 Aug 2022 01:36:39 +0900 Subject: [PATCH 0391/2686] 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 4614c2b9b7..2e3e9f8b66 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b371aa3618..1fdbcfe042 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index bab652bbee..ff9c310b64 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From ad410fc88bb009ee5bba5c41939371d46ea43c4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 10 Aug 2022 01:50:23 +0900 Subject: [PATCH 0392/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 2e3e9f8b66..5a0e48c19e 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 1fdbcfe042..ada0cce8f7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index ff9c310b64..f789d97976 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + From 7ed489b56d47c7e96758f9a17fdb02e300443724 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Tue, 9 Aug 2022 14:10:38 -0400 Subject: [PATCH 0393/2686] Add hotkey to Toolbar --- osu.Game/OsuGame.cs | 4 ---- osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f0d61ed07a..78cc4d7f70 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1138,10 +1138,6 @@ namespace osu.Game mouseDisableButtons.Value = !mouseDisableButtons.Value; return true; - case GlobalAction.ToggleProfile: - ShowUser(new APIUser { Id = API.LocalUser.Value.Id }); - return true; - case GlobalAction.RandomSkin: // Don't allow random skin selection while in the skin editor. // This is mainly to stop many "osu! default (modified)" skins being created via the SkinManager.EnsureMutableSkin() path. diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 4ebd19a1f7..35f72f0ff8 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -15,6 +15,7 @@ using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; +using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; @@ -34,6 +35,8 @@ namespace osu.Game.Overlays.Toolbar public ToolbarUserButton() { + Hotkey = GlobalAction.ToggleProfile; + AutoSizeAxes = Axes.X; } From 8c7ede611162bfb64faf86927e7390812bfacf8c Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Tue, 9 Aug 2022 14:43:37 -0400 Subject: [PATCH 0394/2686] Add proper toggling --- osu.Game/OsuGame.cs | 7 +++++++ osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 3 --- osu.Game/Overlays/UserProfileOverlay.cs | 13 +++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 78cc4d7f70..b89a0dc843 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1138,6 +1138,13 @@ namespace osu.Game mouseDisableButtons.Value = !mouseDisableButtons.Value; return true; + case GlobalAction.ToggleProfile: + if (userProfile.State.Value == Visibility.Visible) + return false; + + ShowUser(new APIUser { Id = API.LocalUser.Value.Id }); + return true; + case GlobalAction.RandomSkin: // Don't allow random skin selection while in the skin editor. // This is mainly to stop many "osu! default (modified)" skins being created via the SkinManager.EnsureMutableSkin() path. diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 35f72f0ff8..4ebd19a1f7 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -15,7 +15,6 @@ using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; -using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; @@ -35,8 +34,6 @@ namespace osu.Game.Overlays.Toolbar public ToolbarUserButton() { - Hotkey = GlobalAction.ToggleProfile; - AutoSizeAxes = Axes.X; } diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index c0ca63bbd9..fb119b92f2 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -19,6 +19,7 @@ using osu.Game.Overlays.Profile.Sections; using osu.Game.Users; using osuTK; using osuTK.Graphics; +using osu.Game.Input.Bindings; namespace osu.Game.Overlays { @@ -41,6 +42,18 @@ namespace osu.Game.Overlays protected override Color4 BackgroundColour => ColourProvider.Background6; + public override bool OnPressed(KeyBindingPressEvent e) + { + switch (e.Action) + { + case GlobalAction.ToggleProfile: + Hide(); + return true; + } + + return base.OnPressed(e); + } + public void ShowUser(IUser user) { if (user.OnlineID == APIUser.SYSTEM_USER_ID) From ddffa9b1bddb312cd8c586cd1dca8797ed404ef6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 10 Aug 2022 15:32:42 +0900 Subject: [PATCH 0395/2686] Fix crash when attempting to import on mobile platforms Regressed with NRT application to this file. It's probably the first time we've actually hit this due to an optional DI that is actually not available outside of tests. --- osu.Game/Database/LegacyImportManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/LegacyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs index 797df49264..78ebd8750e 100644 --- a/osu.Game/Database/LegacyImportManager.cs +++ b/osu.Game/Database/LegacyImportManager.cs @@ -42,7 +42,7 @@ namespace osu.Game.Database [Resolved] private RealmAccess realmAccess { get; set; } = null!; - [Resolved] + [Resolved(canBeNull: true)] // canBeNull required while we remain on mono for mobile platforms. private DesktopGameHost? desktopGameHost { get; set; } [Resolved] From 5f10ec19550af3c334606a0ffcb497846849feed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 10 Aug 2022 15:48:25 +0900 Subject: [PATCH 0396/2686] Add extension methods for case insensitive file lookups --- osu.Game/Beatmaps/BeatmapInfoExtensions.cs | 2 -- osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs | 33 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs diff --git a/osu.Game/Beatmaps/BeatmapInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapInfoExtensions.cs index e7ff07fa5d..eab66b9857 100644 --- a/osu.Game/Beatmaps/BeatmapInfoExtensions.cs +++ b/osu.Game/Beatmaps/BeatmapInfoExtensions.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. -#nullable disable - using System.Linq; using osu.Framework.Localisation; diff --git a/osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs new file mode 100644 index 0000000000..d833637d64 --- /dev/null +++ b/osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs @@ -0,0 +1,33 @@ +// 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.Linq; +using osu.Game.Database; +using osu.Game.Extensions; +using osu.Game.Models; + +namespace osu.Game.Beatmaps +{ + public static class HasRealmFilesExtensions + { + /// + /// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null. + /// The path returned is relative to the user file storage. + /// The lookup is case insensitive. + /// + /// The model to operate on. + /// The name of the file to get the storage path of. + public static string? GetPathForFile(this IHasRealmFiles model, string filename) => model.GetFile(filename)?.File.GetStoragePath(); + + /// + /// Returns the file usage for the file in this beatmapset with the given filename, if any exists, otherwise null. + /// The path returned is relative to the user file storage. + /// The lookup is case insensitive. + /// + /// The model to operate on. + /// The name of the file to get the storage path of. + public static RealmNamedFileUsage? GetFile(this IHasRealmFiles model, string filename) => + model.Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase)); + } +} From ac99c1ad6969027083c073b48c78bd10b3e0f425 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 10 Aug 2022 15:48:38 +0900 Subject: [PATCH 0397/2686] Migrate the majority of existing file lookups to use new extension methods --- osu.Game/Beatmaps/BeatmapInfo.cs | 4 ++-- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- osu.Game/Beatmaps/BeatmapSetInfo.cs | 7 ------- osu.Game/Database/IHasRealmFiles.cs | 9 +++++++++ osu.Game/Database/ModelManager.cs | 3 ++- .../Rulesets/Edit/Checks/CheckAudioInVideo.cs | 1 + .../Edit/Checks/CheckBackgroundQuality.cs | 1 + .../Screens/Edit/Setup/ResourcesSection.cs | 5 ++--- osu.Game/Skinning/SkinImporter.cs | 9 +++++---- .../Drawables/DrawableStoryboardVideo.cs | 20 ++++++++----------- osu.Game/Storyboards/Storyboard.cs | 10 +++------- 11 files changed, 34 insertions(+), 37 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index c53c2f67dd..9196dde73c 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -199,8 +199,8 @@ namespace osu.Game.Beatmaps Debug.Assert(x.BeatmapSet != null); Debug.Assert(y.BeatmapSet != null); - string? fileHashX = x.BeatmapSet.Files.FirstOrDefault(f => f.Filename == getFilename(x.Metadata))?.File.Hash; - string? fileHashY = y.BeatmapSet.Files.FirstOrDefault(f => f.Filename == getFilename(y.Metadata))?.File.Hash; + string? fileHashX = x.BeatmapSet.GetFile(getFilename(x.Metadata))?.File.Hash; + string? fileHashY = y.BeatmapSet.GetFile(getFilename(y.Metadata))?.File.Hash; return fileHashX == fileHashY; } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index b6bfab32cd..e148016487 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -300,7 +300,7 @@ namespace osu.Game.Beatmaps stream.Seek(0, SeekOrigin.Begin); // AddFile generally handles updating/replacing files, but this is a case where the filename may have also changed so let's delete for simplicity. - var existingFileInfo = setInfo.Files.SingleOrDefault(f => string.Equals(f.Filename, beatmapInfo.Path, StringComparison.OrdinalIgnoreCase)); + var existingFileInfo = beatmapInfo.Path != null ? setInfo.GetFile(beatmapInfo.Path) : null; string targetFilename = createBeatmapFilenameFromMetadata(beatmapInfo); // ensure that two difficulties from the set don't point at the same beatmap file. diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index d27d9d9192..b90dfdba05 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -84,13 +84,6 @@ namespace osu.Game.Beatmaps { } - /// - /// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null. - /// The path returned is relative to the user file storage. - /// - /// The name of the file to get the storage path of. - public string? GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.File.GetStoragePath(); - public bool Equals(BeatmapSetInfo? other) { if (ReferenceEquals(this, other)) return true; diff --git a/osu.Game/Database/IHasRealmFiles.cs b/osu.Game/Database/IHasRealmFiles.cs index 2adfe73d1e..dcf130eee8 100644 --- a/osu.Game/Database/IHasRealmFiles.cs +++ b/osu.Game/Database/IHasRealmFiles.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Game.Beatmaps; using osu.Game.Models; namespace osu.Game.Database @@ -11,8 +12,16 @@ namespace osu.Game.Database /// public interface IHasRealmFiles { + /// + /// Available files in this model, with locally filenames. + /// When performing lookups, consider using or to do case-insensitive lookups. + /// IList Files { get; } + /// + /// A combined hash representing the model, based on the files it contains. + /// Implementation specific. + /// string Hash { get; set; } } } diff --git a/osu.Game/Database/ModelManager.cs b/osu.Game/Database/ModelManager.cs index 4224c92f2c..5c106aa493 100644 --- a/osu.Game/Database/ModelManager.cs +++ b/osu.Game/Database/ModelManager.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using osu.Framework.Platform; +using osu.Game.Beatmaps; using osu.Game.Extensions; using osu.Game.Models; using osu.Game.Overlays.Notifications; @@ -79,7 +80,7 @@ namespace osu.Game.Database /// public void AddFile(TModel item, Stream contents, string filename, Realm realm) { - var existing = item.Files.FirstOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase)); + var existing = item.GetFile(filename); if (existing != null) { diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs index 93fb7b9ab8..a66c00d78b 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; +using osu.Game.Beatmaps; using osu.Game.IO.FileAbstraction; using osu.Game.Rulesets.Edit.Checks.Components; using osu.Game.Storyboards; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs index b15a9f5331..be0c4501e7 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit.Checks.Components; namespace osu.Game.Rulesets.Edit.Checks diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 8c14feebbc..69953bf659 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -4,7 +4,6 @@ #nullable disable using System.IO; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -78,7 +77,7 @@ namespace osu.Game.Screens.Edit.Setup // remove the previous background for now. // in the future we probably want to check if this is being used elsewhere (other difficulties?) - var oldFile = set.Files.FirstOrDefault(f => f.Filename == working.Value.Metadata.BackgroundFile); + var oldFile = set.GetFile(working.Value.Metadata.BackgroundFile); using (var stream = source.OpenRead()) { @@ -107,7 +106,7 @@ namespace osu.Game.Screens.Edit.Setup // remove the previous audio track for now. // in the future we probably want to check if this is being used elsewhere (other difficulties?) - var oldFile = set.Files.FirstOrDefault(f => f.Filename == working.Value.Metadata.AudioFile); + var oldFile = set.GetFile(working.Value.Metadata.AudioFile); using (var stream = source.OpenRead()) { diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index ed31a8c3f5..f270abd163 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -10,6 +10,7 @@ using System.Threading; using Newtonsoft.Json; using osu.Framework.Logging; using osu.Framework.Platform; +using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Extensions; using osu.Game.IO; @@ -49,7 +50,7 @@ namespace osu.Game.Skinning protected override void Populate(SkinInfo model, ArchiveReader? archive, Realm realm, CancellationToken cancellationToken = default) { - var skinInfoFile = model.Files.SingleOrDefault(f => f.Filename == skin_info_file); + var skinInfoFile = model.GetFile(skin_info_file); if (skinInfoFile != null) { @@ -129,7 +130,7 @@ namespace osu.Game.Skinning authorLine, }; - var existingFile = item.Files.SingleOrDefault(f => f.Filename.Equals(@"skin.ini", StringComparison.OrdinalIgnoreCase)); + var existingFile = item.GetFile(@"skin.ini"); if (existingFile == null) { @@ -163,7 +164,7 @@ namespace osu.Game.Skinning { Logger.Log($"Skin {item}'s skin.ini had issues and has been removed. Please report this and provide the problematic skin.", LoggingTarget.Database, LogLevel.Important); - var existingIni = item.Files.SingleOrDefault(f => f.Filename.Equals(@"skin.ini", StringComparison.OrdinalIgnoreCase)); + var existingIni = item.GetFile(@"skin.ini"); if (existingIni != null) item.Files.Remove(existingIni); @@ -248,7 +249,7 @@ namespace osu.Game.Skinning { string filename = @$"{drawableInfo.Key}.json"; - var oldFile = s.Files.FirstOrDefault(f => f.Filename == filename); + var oldFile = s.GetFile(filename); if (oldFile != null) modelManager.ReplaceFile(oldFile, streamContent, s.Realm); diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs index 23b1004e74..ebd056ba50 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs @@ -1,10 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using System; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -12,14 +8,14 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Video; using osu.Game.Beatmaps; -using osu.Game.Extensions; namespace osu.Game.Storyboards.Drawables { public class DrawableStoryboardVideo : CompositeDrawable { public readonly StoryboardVideo Video; - private Video video; + + private Video? drawableVideo; public override bool RemoveWhenNotAlive => false; @@ -33,7 +29,7 @@ namespace osu.Game.Storyboards.Drawables [BackgroundDependencyLoader(true)] private void load(IBindable beatmap, TextureStore textureStore) { - string path = beatmap.Value.BeatmapSetInfo?.Files.FirstOrDefault(f => f.Filename.Equals(Video.Path, StringComparison.OrdinalIgnoreCase))?.File.GetStoragePath(); + string? path = beatmap.Value.BeatmapSetInfo?.GetPathForFile(Video.Path); if (path == null) return; @@ -43,7 +39,7 @@ namespace osu.Game.Storyboards.Drawables if (stream == null) return; - InternalChild = video = new Video(stream, false) + InternalChild = drawableVideo = new Video(stream, false) { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fill, @@ -57,12 +53,12 @@ namespace osu.Game.Storyboards.Drawables { base.LoadComplete(); - if (video == null) return; + if (drawableVideo == null) return; - using (video.BeginAbsoluteSequence(Video.StartTime)) + using (drawableVideo.BeginAbsoluteSequence(Video.StartTime)) { - Schedule(() => video.PlaybackPosition = Time.Current - Video.StartTime); - video.FadeIn(500); + Schedule(() => drawableVideo.PlaybackPosition = Time.Current - Video.StartTime); + drawableVideo.FadeIn(500); } } } diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index f30c3f7f94..473f1ce97f 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -1,14 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; -using osu.Game.Extensions; using osu.Game.Rulesets.Mods; using osu.Game.Storyboards.Drawables; @@ -90,12 +86,12 @@ namespace osu.Game.Storyboards } } - public DrawableStoryboard CreateDrawable(IReadOnlyList mods = null) => + public DrawableStoryboard CreateDrawable(IReadOnlyList? mods = null) => new DrawableStoryboard(this, mods); - public Texture GetTextureFromPath(string path, TextureStore textureStore) + public Texture? GetTextureFromPath(string path, TextureStore textureStore) { - string storyboardPath = BeatmapInfo.BeatmapSet?.Files.FirstOrDefault(f => f.Filename.Equals(path, StringComparison.OrdinalIgnoreCase))?.File.GetStoragePath(); + string? storyboardPath = BeatmapInfo.BeatmapSet?.GetPathForFile(path); if (!string.IsNullOrEmpty(storyboardPath)) return textureStore.Get(storyboardPath); From 7c6e5a108585ca76edade57b6915e1940cdcfda8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 10 Aug 2022 16:03:40 +0900 Subject: [PATCH 0398/2686] Add test coverage of case insensitive audio equality --- .../NonVisual/BeatmapSetInfoEqualityTest.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs index 461102124a..a229331ef0 100644 --- a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs +++ b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs @@ -36,6 +36,23 @@ namespace osu.Game.Tests.NonVisual Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single())); } + [Test] + public void TestAudioEqualityCaseSensitivity() + { + var beatmapSetA = TestResources.CreateTestBeatmapSetInfo(1); + var beatmapSetB = TestResources.CreateTestBeatmapSetInfo(1); + + // empty by default so let's set it.. + beatmapSetA.Beatmaps.First().Metadata.AudioFile = "audio.mp3"; + beatmapSetB.Beatmaps.First().Metadata.AudioFile = "audio.mp3"; + + addAudioFile(beatmapSetA, "abc", "AuDiO.mP3"); + addAudioFile(beatmapSetB, "abc", "audio.mp3"); + + Assert.AreNotEqual(beatmapSetA, beatmapSetB); + Assert.IsTrue(beatmapSetA.Beatmaps.Single().AudioEquals(beatmapSetB.Beatmaps.Single())); + } + [Test] public void TestAudioEqualitySameHash() { From ef10d074e8c86e01af53244bbe175be8cdc68626 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 10 Aug 2022 16:07:47 +0900 Subject: [PATCH 0399/2686] 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 5a0e48c19e..a169ce5006 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ada0cce8f7..a351502dcf 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index f789d97976..4e2b8b33ad 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 231c33169026fb4cd5c82480fa632d50792700cd Mon Sep 17 00:00:00 2001 From: its5Q Date: Wed, 10 Aug 2022 18:31:57 +1000 Subject: [PATCH 0400/2686] Rename keys to match enum members Co-authored-by: Dan Balasescu --- osu.Game/Localisation/LayoutSettingsStrings.cs | 6 +++--- osu.Game/Localisation/MouseSettingsStrings.cs | 6 +++--- osu.Game/Localisation/OnlineSettingsStrings.cs | 4 ++-- osu.Game/Localisation/RulesetSettingsStrings.cs | 6 +++--- osu.Game/Localisation/UserInterfaceStrings.cs | 12 ++++++------ 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs index 5b409f728d..306b60897a 100644 --- a/osu.Game/Localisation/LayoutSettingsStrings.cs +++ b/osu.Game/Localisation/LayoutSettingsStrings.cs @@ -37,17 +37,17 @@ namespace osu.Game.Localisation /// /// "Everything" /// - public static LocalisableString ScaleEverything => new TranslatableString(getKey(@"everything"), @"Everything"); + public static LocalisableString ScaleEverything => new TranslatableString(getKey(@"scale_everything"), @"Everything"); /// /// "Gameplay" /// - public static LocalisableString ScaleGameplay => new TranslatableString(getKey(@"gameplay"), @"Gameplay"); + public static LocalisableString ScaleGameplay => new TranslatableString(getKey(@"scale_gameplay"), @"Gameplay"); /// /// "Off" /// - public static LocalisableString ScalingOff => new TranslatableString(getKey(@"off"), @"Off"); + public static LocalisableString ScalingOff => new TranslatableString(getKey(@"scaling_off"), @"Off"); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/MouseSettingsStrings.cs b/osu.Game/Localisation/MouseSettingsStrings.cs index c485036486..1772f03b29 100644 --- a/osu.Game/Localisation/MouseSettingsStrings.cs +++ b/osu.Game/Localisation/MouseSettingsStrings.cs @@ -67,17 +67,17 @@ namespace osu.Game.Localisation /// /// "Always" /// - public static LocalisableString AlwaysConfine => new TranslatableString(getKey(@"always"), @"Always"); + public static LocalisableString AlwaysConfine => new TranslatableString(getKey(@"always_confine"), @"Always"); /// /// "During Gameplay" /// - public static LocalisableString ConfineDuringGameplay => new TranslatableString(getKey(@"during_gameplay"), @"During Gameplay"); + public static LocalisableString ConfineDuringGameplay => new TranslatableString(getKey(@"confine_during_gameplay"), @"During Gameplay"); /// /// "Never" /// - public static LocalisableString NeverConfine => new TranslatableString(getKey(@"never"), @"Never"); + public static LocalisableString NeverConfine => new TranslatableString(getKey(@"never_confine"), @"Never"); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/OnlineSettingsStrings.cs b/osu.Game/Localisation/OnlineSettingsStrings.cs index f7ab57f303..3200b1c75c 100644 --- a/osu.Game/Localisation/OnlineSettingsStrings.cs +++ b/osu.Game/Localisation/OnlineSettingsStrings.cs @@ -72,12 +72,12 @@ namespace osu.Game.Localisation /// /// "Full" /// - public static LocalisableString DiscordPresenceFull => new TranslatableString(getKey(@"full"), @"Full"); + public static LocalisableString DiscordPresenceFull => new TranslatableString(getKey(@"discord_presence_full"), @"Full"); /// /// "Off" /// - public static LocalisableString DiscordPresenceOff => new TranslatableString(getKey(@"off"), @"Off"); + public static LocalisableString DiscordPresenceOff => new TranslatableString(getKey(@"discord_presence_off"), @"Off"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/RulesetSettingsStrings.cs b/osu.Game/Localisation/RulesetSettingsStrings.cs index 92e17cd625..bc4be56c80 100644 --- a/osu.Game/Localisation/RulesetSettingsStrings.cs +++ b/osu.Game/Localisation/RulesetSettingsStrings.cs @@ -17,17 +17,17 @@ namespace osu.Game.Localisation /// /// "None" /// - public static LocalisableString BorderNone => new TranslatableString(getKey(@"none"), @"None"); + public static LocalisableString BorderNone => new TranslatableString(getKey(@"no_borders"), @"None"); /// /// "Corners" /// - public static LocalisableString BorderCorners => new TranslatableString(getKey(@"corners"), @"Corners"); + public static LocalisableString BorderCorners => new TranslatableString(getKey(@"corner_borders"), @"Corners"); /// /// "Full" /// - public static LocalisableString BorderFull => new TranslatableString(getKey(@"full"), @"Full"); + public static LocalisableString BorderFull => new TranslatableString(getKey(@"full_borders"), @"Full"); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index a2752602ad..ea664d7b50 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -122,32 +122,32 @@ namespace osu.Game.Localisation /// /// "Always" /// - public static LocalisableString AlwaysSeasonalBackground => new TranslatableString(getKey(@"always"), @"Always"); + public static LocalisableString AlwaysSeasonalBackground => new TranslatableString(getKey(@"always_seasonal_backgrounds"), @"Always"); /// /// "Never" /// - public static LocalisableString NeverSeasonalBackground => new TranslatableString(getKey(@"never"), @"Never"); + public static LocalisableString NeverSeasonalBackground => new TranslatableString(getKey(@"never_seasonal_backgrounds"), @"Never"); /// /// "Sometimes" /// - public static LocalisableString SometimesSeasonalBackground => new TranslatableString(getKey(@"sometimes"), @"Sometimes"); + public static LocalisableString SometimesSeasonalBackground => new TranslatableString(getKey(@"sometimes_seasonal_backgrounds"), @"Sometimes"); /// /// "Sequential" /// - public static LocalisableString SequentialHotkeyStyle => new TranslatableString(getKey(@"sequential"), @"Sequential"); + public static LocalisableString SequentialHotkeyStyle => new TranslatableString(getKey(@"mods_sequential_hotkeys"), @"Sequential"); /// /// "Classic" /// - public static LocalisableString ClassicHotkeyStyle => new TranslatableString(getKey(@"classic"), @"Classic"); + public static LocalisableString ClassicHotkeyStyle => new TranslatableString(getKey(@"mods_classic_hotkeys"), @"Classic"); /// /// "Never repeat" /// - public static LocalisableString NeverRepeat => new TranslatableString(getKey(@"never_repeat"), @"Never repeat"); + public static LocalisableString NeverRepeat => new TranslatableString(getKey(@"never_repeat_random"), @"Never repeat"); /// /// "True Random" From 8f5bd437f6df5a19f40dfb9114dc290196a8d2f9 Mon Sep 17 00:00:00 2001 From: its5Q Date: Wed, 10 Aug 2022 18:41:53 +1000 Subject: [PATCH 0401/2686] Rename enum member to be more like the other --- osu.Game/Configuration/ScalingMode.cs | 2 +- osu.Game/Localisation/GameplaySettingsStrings.cs | 2 +- osu.Game/Localisation/LayoutSettingsStrings.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Configuration/ScalingMode.cs b/osu.Game/Configuration/ScalingMode.cs index c9eaf71183..e0ad59746b 100644 --- a/osu.Game/Configuration/ScalingMode.cs +++ b/osu.Game/Configuration/ScalingMode.cs @@ -16,7 +16,7 @@ namespace osu.Game.Configuration [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleEverything))] Everything, - [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ExcludingOverlays))] + [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleEverythingExcludingOverlays))] ExcludeOverlays, [LocalisableDescription(typeof(LayoutSettingsStrings), nameof(LayoutSettingsStrings.ScaleGameplay))] diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs index 7300af95a5..13cfcc3a19 100644 --- a/osu.Game/Localisation/GameplaySettingsStrings.cs +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -117,7 +117,7 @@ namespace osu.Game.Localisation /// /// "Never" /// - public static LocalisableString NeverShowHUD => new TranslatableString(getKey(@"never"), @"Never"); + public static LocalisableString NeverShowHUD => new TranslatableString(getKey(@"never_show_hud"), @"Never"); /// /// "Standardised" diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs index 306b60897a..9b8b207c47 100644 --- a/osu.Game/Localisation/LayoutSettingsStrings.cs +++ b/osu.Game/Localisation/LayoutSettingsStrings.cs @@ -32,7 +32,7 @@ namespace osu.Game.Localisation /// /// "Excluding overlays" /// - public static LocalisableString ExcludingOverlays => new TranslatableString(getKey(@"excluding_overlays"), @"Excluding overlays"); + public static LocalisableString ScaleEverythingExcludingOverlays => new TranslatableString(getKey(@"scale_everything_excluding_overlays"), @"Excluding overlays"); /// /// "Everything" From 6e9031b03ee5802abd005298a92049592ea1f4f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 10 Aug 2022 17:49:39 +0900 Subject: [PATCH 0402/2686] 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 a169ce5006..247140ceef 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a351502dcf..c17d45e84a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 4e2b8b33ad..5bfb53bc9d 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 69cbf4185bc955b1affae1c2d04be94bb059731e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 10 Aug 2022 19:53:40 +0900 Subject: [PATCH 0403/2686] Match class name to file --- osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs | 2 +- osu.Game/Database/IHasRealmFiles.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs b/osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs index d833637d64..965544da40 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfoExtensions.cs @@ -9,7 +9,7 @@ using osu.Game.Models; namespace osu.Game.Beatmaps { - public static class HasRealmFilesExtensions + public static class BeatmapSetInfoExtensions { /// /// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null. diff --git a/osu.Game/Database/IHasRealmFiles.cs b/osu.Game/Database/IHasRealmFiles.cs index dcf130eee8..79ea719583 100644 --- a/osu.Game/Database/IHasRealmFiles.cs +++ b/osu.Game/Database/IHasRealmFiles.cs @@ -14,7 +14,7 @@ namespace osu.Game.Database { /// /// Available files in this model, with locally filenames. - /// When performing lookups, consider using or to do case-insensitive lookups. + /// When performing lookups, consider using or to do case-insensitive lookups. /// IList Files { get; } From 396860d9e8f4a804fd7a72304f88dbf5de153e8d Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Wed, 10 Aug 2022 13:31:58 -0400 Subject: [PATCH 0404/2686] Move Hide() to OsuGame --- osu.Game/OsuGame.cs | 12 +++++++++--- osu.Game/Overlays/UserProfileOverlay.cs | 13 ------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b89a0dc843..ca0ce916a2 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1140,10 +1140,16 @@ namespace osu.Game case GlobalAction.ToggleProfile: if (userProfile.State.Value == Visibility.Visible) - return false; + { + userProfile.Hide(); + return true; + } - ShowUser(new APIUser { Id = API.LocalUser.Value.Id }); - return true; + else + { + ShowUser(new APIUser { Id = API.LocalUser.Value.Id }); + return true; + } case GlobalAction.RandomSkin: // Don't allow random skin selection while in the skin editor. diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index fb119b92f2..c0ca63bbd9 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -19,7 +19,6 @@ using osu.Game.Overlays.Profile.Sections; using osu.Game.Users; using osuTK; using osuTK.Graphics; -using osu.Game.Input.Bindings; namespace osu.Game.Overlays { @@ -42,18 +41,6 @@ namespace osu.Game.Overlays protected override Color4 BackgroundColour => ColourProvider.Background6; - public override bool OnPressed(KeyBindingPressEvent e) - { - switch (e.Action) - { - case GlobalAction.ToggleProfile: - Hide(); - return true; - } - - return base.OnPressed(e); - } - public void ShowUser(IUser user) { if (user.OnlineID == APIUser.SYSTEM_USER_ID) From 2499b7f0cd70cb23a2b298fb4e885a05924ef283 Mon Sep 17 00:00:00 2001 From: its5Q Date: Thu, 11 Aug 2022 03:53:20 +1000 Subject: [PATCH 0405/2686] Add localisation support for beatmap editor setup --- .../Graphics/UserInterfaceV2/ColourPalette.cs | 5 +- .../UserInterfaceV2/LabelledColourPalette.cs | 3 +- .../Localisation/EditorSetupColoursStrings.cs | 24 ++++++ .../Localisation/EditorSetupDesignStrings.cs | 84 +++++++++++++++++++ .../EditorSetupDifficultyStrings.cs | 34 ++++++++ .../EditorSetupMetadataStrings.cs | 39 +++++++++ .../EditorSetupResourcesStrings.cs | 44 ++++++++++ .../Localisation/EditorSetupRulesetStrings.cs | 19 +++++ osu.Game/Localisation/EditorSetupStrings.cs | 24 ++++++ osu.Game/Screens/Edit/Setup/ColoursSection.cs | 8 +- osu.Game/Screens/Edit/Setup/DesignSection.cs | 29 +++---- .../Screens/Edit/Setup/DifficultySection.cs | 11 +-- .../Screens/Edit/Setup/MetadataSection.cs | 15 ++-- .../Screens/Edit/Setup/ResourcesSection.cs | 15 ++-- .../Screens/Edit/Setup/RulesetSetupSection.cs | 3 +- .../Screens/Edit/Setup/SetupScreenHeader.cs | 5 +- 16 files changed, 320 insertions(+), 42 deletions(-) create mode 100644 osu.Game/Localisation/EditorSetupColoursStrings.cs create mode 100644 osu.Game/Localisation/EditorSetupDesignStrings.cs create mode 100644 osu.Game/Localisation/EditorSetupDifficultyStrings.cs create mode 100644 osu.Game/Localisation/EditorSetupMetadataStrings.cs create mode 100644 osu.Game/Localisation/EditorSetupResourcesStrings.cs create mode 100644 osu.Game/Localisation/EditorSetupRulesetStrings.cs create mode 100644 osu.Game/Localisation/EditorSetupStrings.cs diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs index 001ccc7f87..f61d6db8b1 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osuTK; @@ -26,9 +27,9 @@ namespace osu.Game.Graphics.UserInterfaceV2 { public BindableList Colours { get; } = new BindableList(); - private string colourNamePrefix = "Colour"; + private LocalisableString colourNamePrefix = "Colour"; - public string ColourNamePrefix + public LocalisableString ColourNamePrefix { get => colourNamePrefix; set diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs index 7b9684e3ef..b144f8f696 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs @@ -5,6 +5,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Localisation; namespace osu.Game.Graphics.UserInterfaceV2 { @@ -17,7 +18,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 public BindableList Colours => Component.Colours; - public string ColourNamePrefix + public LocalisableString ColourNamePrefix { get => Component.ColourNamePrefix; set => Component.ColourNamePrefix = value; diff --git a/osu.Game/Localisation/EditorSetupColoursStrings.cs b/osu.Game/Localisation/EditorSetupColoursStrings.cs new file mode 100644 index 0000000000..e08240a7d2 --- /dev/null +++ b/osu.Game/Localisation/EditorSetupColoursStrings.cs @@ -0,0 +1,24 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorSetupColoursStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupColours"; + + /// + /// "Colours" + /// + public static LocalisableString Colours => new TranslatableString(getKey(@"colours"), @"Colours"); + + /// + /// "Hitcircle / Slider Combos" + /// + public static LocalisableString HitcircleSliderCombos => new TranslatableString(getKey(@"hitcircle_slider_combos"), @"Hitcircle / Slider Combos"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/EditorSetupDesignStrings.cs b/osu.Game/Localisation/EditorSetupDesignStrings.cs new file mode 100644 index 0000000000..0a5e383b76 --- /dev/null +++ b/osu.Game/Localisation/EditorSetupDesignStrings.cs @@ -0,0 +1,84 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorSetupDesignStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupDesign"; + + /// + /// "Design" + /// + public static LocalisableString Design => new TranslatableString(getKey(@"design"), @"Design"); + + /// + /// "Enable countdown" + /// + public static LocalisableString EnableCountdown => new TranslatableString(getKey(@"enable_countdown"), @"Enable countdown"); + + /// + /// "If enabled, an "Are you ready? 3, 2, 1, GO!" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so." + /// + public static LocalisableString CountdownDescription => new TranslatableString(getKey(@"countdown_description"), @"If enabled, an ""Are you ready? 3, 2, 1, GO!"" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so."); + + /// + /// "Countdown speed" + /// + public static LocalisableString CountdownSpeed => new TranslatableString(getKey(@"countdown_speed"), @"Countdown speed"); + + /// + /// "If the countdown sounds off-time, use this to make it appear one or more beats early." + /// + public static LocalisableString CountdownOffsetDescription => new TranslatableString(getKey(@"countdown_offset_description"), @"If the countdown sounds off-time, use this to make it appear one or more beats early."); + + /// + /// "Countdown offset" + /// + public static LocalisableString CountdownOffset => new TranslatableString(getKey(@"countdown_offset"), @"Countdown offset"); + + /// + /// "Widescreen support" + /// + public static LocalisableString WidescreenSupport => new TranslatableString(getKey(@"widescreen_support"), @"Widescreen support"); + + /// + /// "Allows storyboards to use the full screen space, rather than be confined to a 4:3 area." + /// + public static LocalisableString WidescreenSupportDescription => new TranslatableString(getKey(@"widescreen_support_description"), @"Allows storyboards to use the full screen space, rather than be confined to a 4:3 area."); + + /// + /// "Epilepsy warning" + /// + public static LocalisableString EpilepsyWarning => new TranslatableString(getKey(@"epilepsy_warning"), @"Epilepsy warning"); + + /// + /// "Recommended if the storyboard or video contain scenes with rapidly flashing colours." + /// + public static LocalisableString EpilepsyWarningDescription => new TranslatableString(getKey(@"epilepsy_warning_description"), @"Recommended if the storyboard or video contain scenes with rapidly flashing colours."); + + /// + /// "Letterbox during breaks" + /// + public static LocalisableString LetterboxDuringBreaks => new TranslatableString(getKey(@"letterbox_during_breaks"), @"Letterbox during breaks"); + + /// + /// "Adds horizontal letterboxing to give a cinematic look during breaks." + /// + public static LocalisableString LetterboxDuringBreaksDescription => new TranslatableString(getKey(@"letterbox_during_breaks_description"), @"Adds horizontal letterboxing to give a cinematic look during breaks."); + + /// + /// "Samples match playback rate" + /// + public static LocalisableString SamplesMatchPlaybackRate => new TranslatableString(getKey(@"samples_match_playback_rate"), @"Samples match playback rate"); + + /// + /// "When enabled, all samples will speed up or slow down when rate-changing mods are enabled." + /// + public static LocalisableString SamplesMatchPlaybackRateDescription => new TranslatableString(getKey(@"samples_match_playback_rate_description"), @"When enabled, all samples will speed up or slow down when rate-changing mods are enabled."); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/EditorSetupDifficultyStrings.cs b/osu.Game/Localisation/EditorSetupDifficultyStrings.cs new file mode 100644 index 0000000000..cdb7837a64 --- /dev/null +++ b/osu.Game/Localisation/EditorSetupDifficultyStrings.cs @@ -0,0 +1,34 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorSetupDifficultyStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupDifficulty"; + + /// + /// "The size of all hit objects" + /// + public static LocalisableString CircleSizeDescription => new TranslatableString(getKey(@"circle_size_description"), @"The size of all hit objects"); + + /// + /// "The rate of passive health drain throughout playable time" + /// + public static LocalisableString DrainRateDescription => new TranslatableString(getKey(@"drain_rate_description"), @"The rate of passive health drain throughout playable time"); + + /// + /// "The speed at which objects are presented to the player" + /// + public static LocalisableString ApproachRateDescription => new TranslatableString(getKey(@"approach_rate_description"), @"The speed at which objects are presented to the player"); + + /// + /// "The harshness of hit windows and difficulty of special objects (ie. spinners)" + /// + public static LocalisableString OverallDifficultyDescription => new TranslatableString(getKey(@"overall_difficulty_description"), @"The harshness of hit windows and difficulty of special objects (ie. spinners)"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/EditorSetupMetadataStrings.cs b/osu.Game/Localisation/EditorSetupMetadataStrings.cs new file mode 100644 index 0000000000..576fa68643 --- /dev/null +++ b/osu.Game/Localisation/EditorSetupMetadataStrings.cs @@ -0,0 +1,39 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorSetupMetadataStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupMetadata"; + + /// + /// "Metadata" + /// + public static LocalisableString Metadata => new TranslatableString(getKey(@"metadata"), @"Metadata"); + + /// + /// "Romanised Artist" + /// + public static LocalisableString RomanisedArtist => new TranslatableString(getKey(@"romanised_artist"), @"Romanised Artist"); + + /// + /// "Romanised Title" + /// + public static LocalisableString RomanisedTitle => new TranslatableString(getKey(@"romanised_title"), @"Romanised Title"); + + /// + /// "Creator" + /// + public static LocalisableString Creator => new TranslatableString(getKey(@"creator"), @"Creator"); + + /// + /// "Difficulty Name" + /// + public static LocalisableString DifficultyName => new TranslatableString(getKey(@"difficulty_name"), @"Difficulty Name"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/EditorSetupResourcesStrings.cs b/osu.Game/Localisation/EditorSetupResourcesStrings.cs new file mode 100644 index 0000000000..493beae7fe --- /dev/null +++ b/osu.Game/Localisation/EditorSetupResourcesStrings.cs @@ -0,0 +1,44 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorSetupResourcesStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupResources"; + + /// + /// "Resources" + /// + public static LocalisableString Resources => new TranslatableString(getKey(@"resources"), @"Resources"); + + /// + /// "Audio Track" + /// + public static LocalisableString AudioTrack => new TranslatableString(getKey(@"audio_track"), @"Audio Track"); + + /// + /// "Click to select a track" + /// + public static LocalisableString ClickToSelectTrack => new TranslatableString(getKey(@"click_to_select_track"), @"Click to select a track"); + + /// + /// "Click to replace the track" + /// + public static LocalisableString ClickToReplaceTrack => new TranslatableString(getKey(@"click_to_replace_track"), @"Click to replace the track"); + + /// + /// "Click to select a background image" + /// + public static LocalisableString ClickToSelectBackground => new TranslatableString(getKey(@"click_to_select_background"), @"Click to select a background image"); + + /// + /// "Click to replace the background image" + /// + public static LocalisableString ClickToReplaceBackground => new TranslatableString(getKey(@"click_to_replace_background"), @"Click to replace the background image"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/EditorSetupRulesetStrings.cs b/osu.Game/Localisation/EditorSetupRulesetStrings.cs new file mode 100644 index 0000000000..a786b679a3 --- /dev/null +++ b/osu.Game/Localisation/EditorSetupRulesetStrings.cs @@ -0,0 +1,19 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorSetupRulesetStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupRuleset"; + + /// + /// "Ruleset ({0})" + /// + public static LocalisableString Ruleset(string arg0) => new TranslatableString(getKey(@"ruleset"), @"Ruleset ({0})", arg0); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/EditorSetupStrings.cs b/osu.Game/Localisation/EditorSetupStrings.cs new file mode 100644 index 0000000000..97ebd40b6f --- /dev/null +++ b/osu.Game/Localisation/EditorSetupStrings.cs @@ -0,0 +1,24 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorSetupStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.EditorSetup"; + + /// + /// "beatmap setup" + /// + public static LocalisableString BeatmapSetup => new TranslatableString(getKey(@"beatmap_setup"), @"beatmap setup"); + + /// + /// "change general settings of your beatmap" + /// + public static LocalisableString BeatmapSetupDescription => new TranslatableString(getKey(@"beatmap_setup_description"), @"change general settings of your beatmap"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Screens/Edit/Setup/ColoursSection.cs b/osu.Game/Screens/Edit/Setup/ColoursSection.cs index 621abf5580..5792613aa0 100644 --- a/osu.Game/Screens/Edit/Setup/ColoursSection.cs +++ b/osu.Game/Screens/Edit/Setup/ColoursSection.cs @@ -7,12 +7,14 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Edit.Setup { internal class ColoursSection : SetupSection { - public override LocalisableString Title => "Colours"; + public override LocalisableString Title => EditorSetupColoursStrings.Colours; private LabelledColourPalette comboColours; @@ -23,9 +25,9 @@ namespace osu.Game.Screens.Edit.Setup { comboColours = new LabelledColourPalette { - Label = "Hitcircle / Slider Combos", + Label = EditorSetupColoursStrings.HitcircleSliderCombos, FixedLabelWidth = LABEL_WIDTH, - ColourNamePrefix = "Combo" + ColourNamePrefix = MatchesStrings.MatchScoreStatsCombo } }; diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index 40bbfeaf7d..6214a17529 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -13,6 +13,7 @@ using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterfaceV2; using osuTK; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { @@ -29,7 +30,7 @@ namespace osu.Game.Screens.Edit.Setup private LabelledSwitchButton letterboxDuringBreaks; private LabelledSwitchButton samplesMatchPlaybackRate; - public override LocalisableString Title => "Design"; + public override LocalisableString Title => EditorSetupDesignStrings.Design; [BackgroundDependencyLoader] private void load() @@ -38,9 +39,9 @@ namespace osu.Game.Screens.Edit.Setup { EnableCountdown = new LabelledSwitchButton { - Label = "Enable countdown", + Label = EditorSetupDesignStrings.EnableCountdown, Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None }, - Description = "If enabled, an \"Are you ready? 3, 2, 1, GO!\" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so." + Description = EditorSetupDesignStrings.CountdownDescription }, CountdownSettings = new FillFlowContainer { @@ -52,41 +53,41 @@ namespace osu.Game.Screens.Edit.Setup { CountdownSpeed = new LabelledEnumDropdown { - Label = "Countdown speed", + Label = EditorSetupDesignStrings.CountdownSpeed, Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None ? Beatmap.BeatmapInfo.Countdown : CountdownType.Normal }, Items = Enum.GetValues(typeof(CountdownType)).Cast().Where(type => type != CountdownType.None) }, CountdownOffset = new LabelledNumberBox { - Label = "Countdown offset", + Label = EditorSetupDesignStrings.CountdownOffset, Current = { Value = Beatmap.BeatmapInfo.CountdownOffset.ToString() }, - Description = "If the countdown sounds off-time, use this to make it appear one or more beats early.", + Description = EditorSetupDesignStrings.CountdownOffsetDescription, } } }, Empty(), widescreenSupport = new LabelledSwitchButton { - Label = "Widescreen support", - Description = "Allows storyboards to use the full screen space, rather than be confined to a 4:3 area.", + Label = EditorSetupDesignStrings.WidescreenSupport, + Description = EditorSetupDesignStrings.WidescreenSupportDescription, Current = { Value = Beatmap.BeatmapInfo.WidescreenStoryboard } }, epilepsyWarning = new LabelledSwitchButton { - Label = "Epilepsy warning", - Description = "Recommended if the storyboard or video contain scenes with rapidly flashing colours.", + Label = EditorSetupDesignStrings.EpilepsyWarning, + Description = EditorSetupDesignStrings.EpilepsyWarningDescription, Current = { Value = Beatmap.BeatmapInfo.EpilepsyWarning } }, letterboxDuringBreaks = new LabelledSwitchButton { - Label = "Letterbox during breaks", - Description = "Adds horizontal letterboxing to give a cinematic look during breaks.", + Label = EditorSetupDesignStrings.LetterboxDuringBreaks, + Description = EditorSetupDesignStrings.LetterboxDuringBreaksDescription, Current = { Value = Beatmap.BeatmapInfo.LetterboxInBreaks } }, samplesMatchPlaybackRate = new LabelledSwitchButton { - Label = "Samples match playback rate", - Description = "When enabled, all samples will speed up or slow down when rate-changing mods are enabled.", + Label = EditorSetupDesignStrings.SamplesMatchPlaybackRate, + Description = EditorSetupDesignStrings.SamplesMatchPlaybackRateDescription, Current = { Value = Beatmap.BeatmapInfo.SamplesMatchPlaybackRate } } }; diff --git a/osu.Game/Screens/Edit/Setup/DifficultySection.cs b/osu.Game/Screens/Edit/Setup/DifficultySection.cs index 5ce5d05d64..d90997653c 100644 --- a/osu.Game/Screens/Edit/Setup/DifficultySection.cs +++ b/osu.Game/Screens/Edit/Setup/DifficultySection.cs @@ -11,6 +11,7 @@ using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Resources.Localisation.Web; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { @@ -21,7 +22,7 @@ namespace osu.Game.Screens.Edit.Setup private LabelledSliderBar approachRateSlider; private LabelledSliderBar overallDifficultySlider; - public override LocalisableString Title => "Difficulty"; + public override LocalisableString Title => BeatmapDiscussionsStrings.OwnerEditorVersion; [BackgroundDependencyLoader] private void load() @@ -32,7 +33,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = BeatmapsetsStrings.ShowStatsCs, FixedLabelWidth = LABEL_WIDTH, - Description = "The size of all hit objects", + Description = EditorSetupDifficultyStrings.CircleSizeDescription, Current = new BindableFloat(Beatmap.Difficulty.CircleSize) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, @@ -45,7 +46,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = BeatmapsetsStrings.ShowStatsDrain, FixedLabelWidth = LABEL_WIDTH, - Description = "The rate of passive health drain throughout playable time", + Description = EditorSetupDifficultyStrings.DrainRateDescription, Current = new BindableFloat(Beatmap.Difficulty.DrainRate) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, @@ -58,7 +59,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = BeatmapsetsStrings.ShowStatsAr, FixedLabelWidth = LABEL_WIDTH, - Description = "The speed at which objects are presented to the player", + Description = EditorSetupDifficultyStrings.ApproachRateDescription, Current = new BindableFloat(Beatmap.Difficulty.ApproachRate) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, @@ -71,7 +72,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = BeatmapsetsStrings.ShowStatsAccuracy, FixedLabelWidth = LABEL_WIDTH, - Description = "The harshness of hit windows and difficulty of special objects (ie. spinners)", + Description = EditorSetupDifficultyStrings.OverallDifficultyDescription, Current = new BindableFloat(Beatmap.Difficulty.OverallDifficulty) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, diff --git a/osu.Game/Screens/Edit/Setup/MetadataSection.cs b/osu.Game/Screens/Edit/Setup/MetadataSection.cs index 854dec2001..1af749160b 100644 --- a/osu.Game/Screens/Edit/Setup/MetadataSection.cs +++ b/osu.Game/Screens/Edit/Setup/MetadataSection.cs @@ -10,6 +10,7 @@ using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Resources.Localisation.Web; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { @@ -26,7 +27,7 @@ namespace osu.Game.Screens.Edit.Setup private LabelledTextBox sourceTextBox; private LabelledTextBox tagsTextBox; - public override LocalisableString Title => "Metadata"; + public override LocalisableString Title => EditorSetupMetadataStrings.Metadata; [BackgroundDependencyLoader] private void load() @@ -35,22 +36,22 @@ namespace osu.Game.Screens.Edit.Setup Children = new[] { - ArtistTextBox = createTextBox("Artist", + ArtistTextBox = createTextBox(ArtistStrings.TracksIndexFormArtist, !string.IsNullOrEmpty(metadata.ArtistUnicode) ? metadata.ArtistUnicode : metadata.Artist), - RomanisedArtistTextBox = createTextBox("Romanised Artist", + RomanisedArtistTextBox = createTextBox(EditorSetupMetadataStrings.RomanisedArtist, !string.IsNullOrEmpty(metadata.Artist) ? metadata.Artist : MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode)), Empty(), - TitleTextBox = createTextBox("Title", + TitleTextBox = createTextBox(BeatmapsetWatchesStrings.IndexTableTitle, !string.IsNullOrEmpty(metadata.TitleUnicode) ? metadata.TitleUnicode : metadata.Title), - RomanisedTitleTextBox = createTextBox("Romanised Title", + RomanisedTitleTextBox = createTextBox(EditorSetupMetadataStrings.RomanisedTitle, !string.IsNullOrEmpty(metadata.Title) ? metadata.Title : MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode)), Empty(), - creatorTextBox = createTextBox("Creator", metadata.Author.Username), - difficultyTextBox = createTextBox("Difficulty Name", Beatmap.BeatmapInfo.DifficultyName), + creatorTextBox = createTextBox(EditorSetupMetadataStrings.Creator, metadata.Author.Username), + difficultyTextBox = createTextBox(EditorSetupMetadataStrings.DifficultyName, Beatmap.BeatmapInfo.DifficultyName), sourceTextBox = createTextBox(BeatmapsetsStrings.ShowInfoSource, metadata.Source), tagsTextBox = createTextBox(BeatmapsetsStrings.ShowInfoTags, metadata.Tags) }; diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index 8c14feebbc..dfc849de7b 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Overlays; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { @@ -19,7 +20,7 @@ namespace osu.Game.Screens.Edit.Setup private LabelledFileChooser audioTrackChooser; private LabelledFileChooser backgroundChooser; - public override LocalisableString Title => "Resources"; + public override LocalisableString Title => EditorSetupResourcesStrings.Resources; [Resolved] private MusicController music { get; set; } @@ -43,13 +44,13 @@ namespace osu.Game.Screens.Edit.Setup { backgroundChooser = new LabelledFileChooser(".jpg", ".jpeg", ".png") { - Label = "Background", + Label = GameplaySettingsStrings.BackgroundHeader, FixedLabelWidth = LABEL_WIDTH, TabbableContentContainer = this }, audioTrackChooser = new LabelledFileChooser(".mp3", ".ogg") { - Label = "Audio Track", + Label = EditorSetupResourcesStrings.AudioTrack, FixedLabelWidth = LABEL_WIDTH, TabbableContentContainer = this }, @@ -144,12 +145,12 @@ namespace osu.Game.Screens.Edit.Setup private void updatePlaceholderText() { audioTrackChooser.Text = audioTrackChooser.Current.Value == null - ? "Click to select a track" - : "Click to replace the track"; + ? EditorSetupResourcesStrings.ClickToSelectTrack + : EditorSetupResourcesStrings.ClickToReplaceTrack; backgroundChooser.Text = backgroundChooser.Current.Value == null - ? "Click to select a background image" - : "Click to replace the background image"; + ? EditorSetupResourcesStrings.ClickToSelectBackground + : EditorSetupResourcesStrings.ClickToReplaceBackground; } } } diff --git a/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs b/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs index db0641feba..6b1b1128d4 100644 --- a/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs +++ b/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs @@ -5,12 +5,13 @@ using osu.Framework.Localisation; using osu.Game.Rulesets; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { public abstract class RulesetSetupSection : SetupSection { - public sealed override LocalisableString Title => $"Ruleset ({rulesetInfo.Name})"; + public sealed override LocalisableString Title => EditorSetupRulesetStrings.Ruleset(rulesetInfo.Name); private readonly RulesetInfo rulesetInfo; diff --git a/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs b/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs index c531f1da90..c1f6ab556c 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.Containers; using osu.Game.Overlays; using osuTK.Graphics; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { @@ -77,8 +78,8 @@ namespace osu.Game.Screens.Edit.Setup { public SetupScreenTitle() { - Title = "beatmap setup"; - Description = "change general settings of your beatmap"; + Title = EditorSetupStrings.BeatmapSetup; + Description = EditorSetupStrings.BeatmapSetupDescription; IconTexture = "Icons/Hexacons/social"; } } From 8cb2e11766b85d23ceb69b17275025090eb94328 Mon Sep 17 00:00:00 2001 From: naoei Date: Wed, 10 Aug 2022 15:51:11 -0400 Subject: [PATCH 0406/2686] Change most ruleset-accessible string types to Localisable strings --- osu.Game/Rulesets/Mods/IMod.cs | 3 ++- osu.Game/Rulesets/Mods/Mod.cs | 3 ++- osu.Game/Rulesets/Ruleset.cs | 5 +++-- osu.Game/Scoring/HitResultDisplayStatistic.cs | 5 +++-- osu.Game/Screens/Play/ResumeOverlay.cs | 3 ++- osu.Game/Screens/Ranking/Statistics/StatisticItem.cs | 5 +++-- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/Mods/IMod.cs b/osu.Game/Rulesets/Mods/IMod.cs index 30fa1ea8cb..1f9e26c9d7 100644 --- a/osu.Game/Rulesets/Mods/IMod.cs +++ b/osu.Game/Rulesets/Mods/IMod.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; namespace osu.Game.Rulesets.Mods { @@ -21,7 +22,7 @@ namespace osu.Game.Rulesets.Mods /// /// The user readable description of this mod. /// - string Description { get; } + LocalisableString Description { get; } /// /// The type of this mod. diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 0f3d758f74..e4c91d3037 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -9,6 +9,7 @@ using Newtonsoft.Json; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Framework.Testing; using osu.Game.Configuration; using osu.Game.Rulesets.UI; @@ -34,7 +35,7 @@ namespace osu.Game.Rulesets.Mods public virtual ModType Type => ModType.Fun; [JsonIgnore] - public abstract string Description { get; } + public abstract LocalisableString Description { get; } /// /// The tooltip to display for this mod when used in a . diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index c1ec6c30ef..50ce6b3b12 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -28,6 +28,7 @@ using osu.Game.Users; using JetBrains.Annotations; using osu.Framework.Extensions; using osu.Framework.Extensions.EnumExtensions; +using osu.Framework.Localisation; using osu.Framework.Testing; using osu.Game.Extensions; using osu.Game.Rulesets.Filter; @@ -313,7 +314,7 @@ namespace osu.Game.Rulesets /// /// All valid s along with a display-friendly name. /// - public IEnumerable<(HitResult result, string displayName)> GetHitResults() + public IEnumerable<(HitResult result, LocalisableString displayName)> GetHitResults() { var validResults = GetValidHitResults(); @@ -351,7 +352,7 @@ namespace osu.Game.Rulesets /// /// The result type to get the name for. /// The display name. - public virtual string GetDisplayNameForHitResult(HitResult result) => result.GetDescription(); + public virtual LocalisableString GetDisplayNameForHitResult(HitResult result) => result.GetLocalisableDescription(); /// /// Creates ruleset-specific beatmap filter criteria to be used on the song select screen. diff --git a/osu.Game/Scoring/HitResultDisplayStatistic.cs b/osu.Game/Scoring/HitResultDisplayStatistic.cs index 4603ff053e..20deff4875 100644 --- a/osu.Game/Scoring/HitResultDisplayStatistic.cs +++ b/osu.Game/Scoring/HitResultDisplayStatistic.cs @@ -3,6 +3,7 @@ #nullable disable +using osu.Framework.Localisation; using osu.Game.Rulesets.Scoring; namespace osu.Game.Scoring @@ -30,9 +31,9 @@ namespace osu.Game.Scoring /// /// A custom display name for the result type. May be provided by rulesets to give better clarity. /// - public string DisplayName { get; } + public LocalisableString DisplayName { get; } - public HitResultDisplayStatistic(HitResult result, int count, int? maxCount, string displayName) + public HitResultDisplayStatistic(HitResult result, int count, int? maxCount, LocalisableString displayName) { Result = result; Count = count; diff --git a/osu.Game/Screens/Play/ResumeOverlay.cs b/osu.Game/Screens/Play/ResumeOverlay.cs index 2be1f93f80..7ed95c4ce3 100644 --- a/osu.Game/Screens/Play/ResumeOverlay.cs +++ b/osu.Game/Screens/Play/ResumeOverlay.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; @@ -31,7 +32,7 @@ namespace osu.Game.Screens.Play protected const float TRANSITION_TIME = 500; - protected abstract string Message { get; } + protected abstract LocalisableString Message { get; } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs index 0e5cce59f8..ae5d81c696 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -7,6 +7,7 @@ using System; using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; namespace osu.Game.Screens.Ranking.Statistics { @@ -18,7 +19,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// /// The name of this item. /// - public readonly string Name; + public readonly LocalisableString Name; /// /// A function returning the content to be displayed. @@ -48,7 +49,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// A function returning the content to be displayed. /// Whether this item requires hit events. If true, will not be called if no hit events are available. /// The of this item. This can be thought of as the column dimension of an encompassing . - public StatisticItem([NotNull] string name, [NotNull] Func createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) + public StatisticItem(LocalisableString name, [NotNull] Func createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) { Name = name; RequiresHitEvents = requiresHitEvents; From 60dae70a180f33c6c55be46018e43bad8ba627ea Mon Sep 17 00:00:00 2001 From: naoei Date: Wed, 10 Aug 2022 15:54:48 -0400 Subject: [PATCH 0407/2686] Change mod description type to `LocalisableString` --- osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs | 3 ++- osu.Game/Rulesets/Mods/ModAutoplay.cs | 3 ++- osu.Game/Rulesets/Mods/ModBarrelRoll.cs | 3 ++- osu.Game/Rulesets/Mods/ModCinema.cs | 3 ++- osu.Game/Rulesets/Mods/ModClassic.cs | 3 ++- osu.Game/Rulesets/Mods/ModDaycore.cs | 3 ++- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 3 ++- osu.Game/Rulesets/Mods/ModDoubleTime.cs | 3 ++- osu.Game/Rulesets/Mods/ModFlashlight.cs | 3 ++- osu.Game/Rulesets/Mods/ModHalfTime.cs | 3 ++- osu.Game/Rulesets/Mods/ModHardRock.cs | 3 ++- osu.Game/Rulesets/Mods/ModMuted.cs | 2 +- osu.Game/Rulesets/Mods/ModNightcore.cs | 3 ++- osu.Game/Rulesets/Mods/ModNoFail.cs | 3 ++- osu.Game/Rulesets/Mods/ModNoMod.cs | 3 ++- osu.Game/Rulesets/Mods/ModPerfect.cs | 3 ++- osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 3 ++- osu.Game/Rulesets/Mods/ModWindDown.cs | 3 ++- osu.Game/Rulesets/Mods/ModWindUp.cs | 3 ++- osu.Game/Rulesets/Mods/MultiMod.cs | 3 ++- osu.Game/Rulesets/Mods/UnknownMod.cs | 4 +++- 21 files changed, 42 insertions(+), 21 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs b/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs index 38d26ed05a..e7996c6d43 100644 --- a/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs +++ b/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Audio; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -23,7 +24,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "AS"; - public override string Description => "Let track speed adapt to you."; + public override LocalisableString Description => "Let track speed adapt to you."; public override ModType Type => ModType.Fun; diff --git a/osu.Game/Rulesets/Mods/ModAutoplay.cs b/osu.Game/Rulesets/Mods/ModAutoplay.cs index ab49dd5575..6cafe0716d 100644 --- a/osu.Game/Rulesets/Mods/ModAutoplay.cs +++ b/osu.Game/Rulesets/Mods/ModAutoplay.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Replays; @@ -17,7 +18,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "AT"; public override IconUsage? Icon => OsuIcon.ModAuto; public override ModType Type => ModType.Automation; - public override string Description => "Watch a perfect automated play through the song."; + public override LocalisableString Description => "Watch a perfect automated play through the song."; public override double ScoreMultiplier => 1; public bool PerformFail() => false; diff --git a/osu.Game/Rulesets/Mods/ModBarrelRoll.cs b/osu.Game/Rulesets/Mods/ModBarrelRoll.cs index bacb953f76..0c301d293f 100644 --- a/osu.Game/Rulesets/Mods/ModBarrelRoll.cs +++ b/osu.Game/Rulesets/Mods/ModBarrelRoll.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; @@ -34,7 +35,7 @@ namespace osu.Game.Rulesets.Mods public override string Name => "Barrel Roll"; public override string Acronym => "BR"; - public override string Description => "The whole playfield is on a wheel!"; + public override LocalisableString Description => "The whole playfield is on a wheel!"; public override double ScoreMultiplier => 1; public override string SettingDescription => $"{SpinSpeed.Value:N2} rpm {Direction.Value.GetDescription().ToLowerInvariant()}"; diff --git a/osu.Game/Rulesets/Mods/ModCinema.cs b/osu.Game/Rulesets/Mods/ModCinema.cs index 99c4e71d1f..ae661c5f25 100644 --- a/osu.Game/Rulesets/Mods/ModCinema.cs +++ b/osu.Game/Rulesets/Mods/ModCinema.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; @@ -27,7 +28,7 @@ namespace osu.Game.Rulesets.Mods public override string Name => "Cinema"; public override string Acronym => "CN"; public override IconUsage? Icon => OsuIcon.ModCinema; - public override string Description => "Watch the video without visual distractions."; + public override LocalisableString Description => "Watch the video without visual distractions."; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModAutoplay)).ToArray(); diff --git a/osu.Game/Rulesets/Mods/ModClassic.cs b/osu.Game/Rulesets/Mods/ModClassic.cs index 1159955e11..55b16297e2 100644 --- a/osu.Game/Rulesets/Mods/ModClassic.cs +++ b/osu.Game/Rulesets/Mods/ModClassic.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; namespace osu.Game.Rulesets.Mods { @@ -15,7 +16,7 @@ namespace osu.Game.Rulesets.Mods public override IconUsage? Icon => FontAwesome.Solid.History; - public override string Description => "Feeling nostalgic?"; + public override LocalisableString Description => "Feeling nostalgic?"; public override ModType Type => ModType.Conversion; } diff --git a/osu.Game/Rulesets/Mods/ModDaycore.cs b/osu.Game/Rulesets/Mods/ModDaycore.cs index 9e8e44229e..de1a5ab56c 100644 --- a/osu.Game/Rulesets/Mods/ModDaycore.cs +++ b/osu.Game/Rulesets/Mods/ModDaycore.cs @@ -4,6 +4,7 @@ using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; namespace osu.Game.Rulesets.Mods { @@ -12,7 +13,7 @@ namespace osu.Game.Rulesets.Mods public override string Name => "Daycore"; public override string Acronym => "DC"; public override IconUsage? Icon => null; - public override string Description => "Whoaaaaa..."; + public override LocalisableString Description => "Whoaaaaa..."; private readonly BindableNumber tempoAdjust = new BindableDouble(1); private readonly BindableNumber freqAdjust = new BindableDouble(1); diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index eefa1531c4..4ed31eec78 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -14,7 +15,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => @"Difficulty Adjust"; - public override string Description => @"Override a beatmap's difficulty settings."; + public override LocalisableString Description => @"Override a beatmap's difficulty settings."; public override string Acronym => "DA"; diff --git a/osu.Game/Rulesets/Mods/ModDoubleTime.cs b/osu.Game/Rulesets/Mods/ModDoubleTime.cs index 1c71f5d055..d8a41ae658 100644 --- a/osu.Game/Rulesets/Mods/ModDoubleTime.cs +++ b/osu.Game/Rulesets/Mods/ModDoubleTime.cs @@ -3,6 +3,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics; @@ -14,7 +15,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "DT"; public override IconUsage? Icon => OsuIcon.ModDoubleTime; public override ModType Type => ModType.DifficultyIncrease; - public override string Description => "Zoooooooooom..."; + public override LocalisableString Description => "Zoooooooooom..."; [SettingSource("Speed increase", "The actual increase to apply")] public override BindableNumber SpeedChange { get; } = new BindableDouble diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 210dd56137..558605efc3 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Beatmaps.Timing; using osu.Game.Configuration; using osu.Game.Graphics; @@ -30,7 +31,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "FL"; public override IconUsage? Icon => OsuIcon.ModFlashlight; public override ModType Type => ModType.DifficultyIncrease; - public override string Description => "Restricted view area."; + public override LocalisableString Description => "Restricted view area."; [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")] public abstract BindableFloat SizeMultiplier { get; } diff --git a/osu.Game/Rulesets/Mods/ModHalfTime.cs b/osu.Game/Rulesets/Mods/ModHalfTime.cs index 13d89e30d6..8d8b97e79e 100644 --- a/osu.Game/Rulesets/Mods/ModHalfTime.cs +++ b/osu.Game/Rulesets/Mods/ModHalfTime.cs @@ -3,6 +3,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics; @@ -14,7 +15,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "HT"; public override IconUsage? Icon => OsuIcon.ModHalftime; public override ModType Type => ModType.DifficultyReduction; - public override string Description => "Less zoom..."; + public override LocalisableString Description => "Less zoom..."; [SettingSource("Speed decrease", "The actual decrease to apply")] public override BindableNumber SpeedChange { get; } = new BindableDouble diff --git a/osu.Game/Rulesets/Mods/ModHardRock.cs b/osu.Game/Rulesets/Mods/ModHardRock.cs index 0a5348a8cf..2886e59c54 100644 --- a/osu.Game/Rulesets/Mods/ModHardRock.cs +++ b/osu.Game/Rulesets/Mods/ModHardRock.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; @@ -14,7 +15,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "HR"; public override IconUsage? Icon => OsuIcon.ModHardRock; public override ModType Type => ModType.DifficultyIncrease; - public override string Description => "Everything just got a bit harder..."; + public override LocalisableString Description => "Everything just got a bit harder..."; public override Type[] IncompatibleMods => new[] { typeof(ModEasy), typeof(ModDifficultyAdjust) }; public void ReadFromDifficulty(IBeatmapDifficultyInfo difficulty) diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 55d5abfa82..9735d6b536 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mods public override string Name => "Muted"; public override string Acronym => "MU"; public override IconUsage? Icon => FontAwesome.Solid.VolumeMute; - public override string Description => "Can you still feel the rhythm without music?"; + public override LocalisableString Description => "Can you still feel the rhythm without music?"; public override ModType Type => ModType.Fun; public override double ScoreMultiplier => 1; } diff --git a/osu.Game/Rulesets/Mods/ModNightcore.cs b/osu.Game/Rulesets/Mods/ModNightcore.cs index c4417ec509..099bf386f3 100644 --- a/osu.Game/Rulesets/Mods/ModNightcore.cs +++ b/osu.Game/Rulesets/Mods/ModNightcore.cs @@ -7,6 +7,7 @@ using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Timing; @@ -23,7 +24,7 @@ namespace osu.Game.Rulesets.Mods public override string Name => "Nightcore"; public override string Acronym => "NC"; public override IconUsage? Icon => OsuIcon.ModNightcore; - public override string Description => "Uguuuuuuuu..."; + public override LocalisableString Description => "Uguuuuuuuu..."; } public abstract class ModNightcore : ModNightcore, IApplicableToDrawableRuleset diff --git a/osu.Game/Rulesets/Mods/ModNoFail.cs b/osu.Game/Rulesets/Mods/ModNoFail.cs index 5ebae17228..31bb4338b3 100644 --- a/osu.Game/Rulesets/Mods/ModNoFail.cs +++ b/osu.Game/Rulesets/Mods/ModNoFail.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics; namespace osu.Game.Rulesets.Mods @@ -13,7 +14,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "NF"; public override IconUsage? Icon => OsuIcon.ModNoFail; public override ModType Type => ModType.DifficultyReduction; - public override string Description => "You can't fail, no matter what."; + public override LocalisableString Description => "You can't fail, no matter what."; public override double ScoreMultiplier => 0.5; public override Type[] IncompatibleMods => new[] { typeof(ModRelax), typeof(ModFailCondition), typeof(ModAutoplay) }; } diff --git a/osu.Game/Rulesets/Mods/ModNoMod.cs b/osu.Game/Rulesets/Mods/ModNoMod.cs index 1009c5bc42..5dd4b317e7 100644 --- a/osu.Game/Rulesets/Mods/ModNoMod.cs +++ b/osu.Game/Rulesets/Mods/ModNoMod.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; namespace osu.Game.Rulesets.Mods { @@ -12,7 +13,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "No Mod"; public override string Acronym => "NM"; - public override string Description => "No mods applied."; + public override LocalisableString Description => "No mods applied."; public override double ScoreMultiplier => 1; public override IconUsage? Icon => FontAwesome.Solid.Ban; public override ModType Type => ModType.System; diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs index 9016a24f8d..804f23b6b7 100644 --- a/osu.Game/Rulesets/Mods/ModPerfect.cs +++ b/osu.Game/Rulesets/Mods/ModPerfect.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; @@ -17,7 +18,7 @@ namespace osu.Game.Rulesets.Mods public override IconUsage? Icon => OsuIcon.ModPerfect; public override ModType Type => ModType.DifficultyIncrease; public override double ScoreMultiplier => 1; - public override string Description => "SS or quit."; + public override LocalisableString Description => "SS or quit."; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModSuddenDeath)).ToArray(); diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index c8b835f78a..4e4e8662e8 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; @@ -16,7 +17,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "SD"; public override IconUsage? Icon => OsuIcon.ModSuddenDeath; public override ModType Type => ModType.DifficultyIncrease; - public override string Description => "Miss and fail."; + public override LocalisableString Description => "Miss and fail."; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModPerfect)).ToArray(); diff --git a/osu.Game/Rulesets/Mods/ModWindDown.cs b/osu.Game/Rulesets/Mods/ModWindDown.cs index 08bd44f7bd..e84bdab69c 100644 --- a/osu.Game/Rulesets/Mods/ModWindDown.cs +++ b/osu.Game/Rulesets/Mods/ModWindDown.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; namespace osu.Game.Rulesets.Mods @@ -13,7 +14,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "Wind Down"; public override string Acronym => "WD"; - public override string Description => "Sloooow doooown..."; + public override LocalisableString Description => "Sloooow doooown..."; public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleDown; public override double ScoreMultiplier => 1.0; diff --git a/osu.Game/Rulesets/Mods/ModWindUp.cs b/osu.Game/Rulesets/Mods/ModWindUp.cs index df8f781148..39cee50f96 100644 --- a/osu.Game/Rulesets/Mods/ModWindUp.cs +++ b/osu.Game/Rulesets/Mods/ModWindUp.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; namespace osu.Game.Rulesets.Mods @@ -13,7 +14,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "Wind Up"; public override string Acronym => "WU"; - public override string Description => "Can you keep up?"; + public override LocalisableString Description => "Can you keep up?"; public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleUp; public override double ScoreMultiplier => 1.0; diff --git a/osu.Game/Rulesets/Mods/MultiMod.cs b/osu.Game/Rulesets/Mods/MultiMod.cs index 1c41c6b8b3..9fbc0ddd97 100644 --- a/osu.Game/Rulesets/Mods/MultiMod.cs +++ b/osu.Game/Rulesets/Mods/MultiMod.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Framework.Localisation; namespace osu.Game.Rulesets.Mods { @@ -10,7 +11,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => string.Empty; public override string Acronym => string.Empty; - public override string Description => string.Empty; + public override LocalisableString Description => string.Empty; public override double ScoreMultiplier => 0; public Mod[] Mods { get; } diff --git a/osu.Game/Rulesets/Mods/UnknownMod.cs b/osu.Game/Rulesets/Mods/UnknownMod.cs index 72de0ad653..abe05996ff 100644 --- a/osu.Game/Rulesets/Mods/UnknownMod.cs +++ b/osu.Game/Rulesets/Mods/UnknownMod.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mods { public class UnknownMod : Mod @@ -12,7 +14,7 @@ namespace osu.Game.Rulesets.Mods public override string Name => $"Unknown mod ({OriginalAcronym})"; public override string Acronym => $"{OriginalAcronym}??"; - public override string Description => "This mod could not be resolved by the game."; + public override LocalisableString Description => "This mod could not be resolved by the game."; public override double ScoreMultiplier => 0; public override bool UserPlayable => false; From 1e356f61376984f11c23c5b03da8a3fa8a70c41b Mon Sep 17 00:00:00 2001 From: naoei Date: Wed, 10 Aug 2022 16:03:59 -0400 Subject: [PATCH 0408/2686] Revert localisation for `GetDisplayNameForHitResult` Came across an issue where `LeaderboardScoreTooltip` attempts to capitalize all letters for the `displayName`. Unsure if I should completely ignore it and localise it anyway. --- osu.Game/Rulesets/Ruleset.cs | 5 ++--- osu.Game/Scoring/HitResultDisplayStatistic.cs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 50ce6b3b12..c1ec6c30ef 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -28,7 +28,6 @@ using osu.Game.Users; using JetBrains.Annotations; using osu.Framework.Extensions; using osu.Framework.Extensions.EnumExtensions; -using osu.Framework.Localisation; using osu.Framework.Testing; using osu.Game.Extensions; using osu.Game.Rulesets.Filter; @@ -314,7 +313,7 @@ namespace osu.Game.Rulesets /// /// All valid s along with a display-friendly name. /// - public IEnumerable<(HitResult result, LocalisableString displayName)> GetHitResults() + public IEnumerable<(HitResult result, string displayName)> GetHitResults() { var validResults = GetValidHitResults(); @@ -352,7 +351,7 @@ namespace osu.Game.Rulesets /// /// The result type to get the name for. /// The display name. - public virtual LocalisableString GetDisplayNameForHitResult(HitResult result) => result.GetLocalisableDescription(); + public virtual string GetDisplayNameForHitResult(HitResult result) => result.GetDescription(); /// /// Creates ruleset-specific beatmap filter criteria to be used on the song select screen. diff --git a/osu.Game/Scoring/HitResultDisplayStatistic.cs b/osu.Game/Scoring/HitResultDisplayStatistic.cs index 20deff4875..4603ff053e 100644 --- a/osu.Game/Scoring/HitResultDisplayStatistic.cs +++ b/osu.Game/Scoring/HitResultDisplayStatistic.cs @@ -3,7 +3,6 @@ #nullable disable -using osu.Framework.Localisation; using osu.Game.Rulesets.Scoring; namespace osu.Game.Scoring @@ -31,9 +30,9 @@ namespace osu.Game.Scoring /// /// A custom display name for the result type. May be provided by rulesets to give better clarity. /// - public LocalisableString DisplayName { get; } + public string DisplayName { get; } - public HitResultDisplayStatistic(HitResult result, int count, int? maxCount, LocalisableString displayName) + public HitResultDisplayStatistic(HitResult result, int count, int? maxCount, string displayName) { Result = result; Count = count; From 6e13cf82e810504f8f7a3df4bd341c42853d6d69 Mon Sep 17 00:00:00 2001 From: naoei Date: Wed, 10 Aug 2022 16:05:34 -0400 Subject: [PATCH 0409/2686] Don't render statistic header if display string is null --- osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs | 4 ++-- osu.Game/Screens/Ranking/Statistics/StatisticItem.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs index 078ca97737..1cf46dcf04 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Ranking.Statistics private static Drawable createHeader(StatisticItem item) { - if (string.IsNullOrEmpty(item.Name)) + if (item.Name == null) return Empty(); return new FillFlowContainer @@ -82,7 +82,7 @@ namespace osu.Game.Screens.Ranking.Statistics { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Text = item.Name, + Text = item.Name.Value, Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), } } diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs index ae5d81c696..baabc90c6f 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// /// The name of this item. /// - public readonly LocalisableString Name; + public readonly LocalisableString? Name; /// /// A function returning the content to be displayed. From 3e38baca3c0280ecfb9bc9ef7f3c5c185ba9f0ca Mon Sep 17 00:00:00 2001 From: naoei Date: Wed, 10 Aug 2022 16:09:11 -0400 Subject: [PATCH 0410/2686] Change ruleset mod description types --- osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs | 3 ++- .../Mods/CatchModFloatingFruits.cs | 3 ++- osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs | 3 ++- osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs | 3 ++- osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs | 3 ++- osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs | 3 ++- osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs | 3 ++- osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs | 3 ++- osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs | 3 ++- osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs | 3 ++- osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs | 3 ++- osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs | 3 ++- osu.Game.Rulesets.Mania/Mods/ManiaModInvert.cs | 3 ++- osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs | 4 +++- osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs | 4 +++- osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs | 4 +++- osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs | 4 +++- osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs | 4 +++- osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs | 4 +++- osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs | 4 +++- osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs | 4 +++- osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs | 4 +++- osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs | 4 +++- osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs | 3 ++- osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModSingleTap.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs | 3 ++- osu.Game.Rulesets.Taiko/Mods/TaikoModEasy.cs | 3 ++- osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs | 3 ++- osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs | 3 ++- osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs | 3 ++- osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs | 3 ++- osu.Game.Tests/Mods/ModUtilsTest.cs | 5 +++-- osu.Game.Tests/Mods/TestCustomisableModRuleset.cs | 3 ++- .../DifficultyAdjustmentModCombinationsTest.cs | 11 ++++++----- osu.Game.Tests/Online/TestAPIModJsonSerialization.cs | 5 +++-- .../Online/TestAPIModMessagePackSerialization.cs | 7 ++++--- .../Visual/Gameplay/TestScenePlayerLoader.cs | 3 ++- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 3 ++- 60 files changed, 138 insertions(+), 68 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs b/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs index 16ef56d845..cac5b9aa6a 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModEasy.cs @@ -1,12 +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 osu.Framework.Localisation; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Catch.Mods { public class CatchModEasy : ModEasyWithExtraLives { - public override string Description => @"Larger fruits, more forgiving HP drain, less accuracy required, and three lives!"; + public override LocalisableString Description => @"Larger fruits, more forgiving HP drain, less accuracy required, and three lives!"; } } diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs index 63203dd57c..e12181d051 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFloatingFruits.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; @@ -14,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Mods { public override string Name => "Floating Fruits"; public override string Acronym => "FF"; - public override string Description => "The fruits are... floating?"; + public override LocalisableString Description => "The fruits are... floating?"; public override double ScoreMultiplier => 1; public override IconUsage? Icon => FontAwesome.Solid.Cloud; diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs index 51516edacd..d68430b64f 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs @@ -3,6 +3,7 @@ using System.Linq; using osu.Framework.Graphics; +using osu.Framework.Localisation; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Catch.UI; @@ -14,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Mods { public class CatchModHidden : ModHidden, IApplicableToDrawableRuleset { - public override string Description => @"Play with fading fruits."; + public override LocalisableString Description => @"Play with fading fruits."; public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1; private const double fade_out_offset_multiplier = 0.6; diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs b/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs index a97e940a64..4cd2efdc2f 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Catch.Objects; @@ -14,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Mods { public class CatchModMirror : ModMirror, IApplicableToBeatmap { - public override string Description => "Fruits are flipped horizontally."; + public override LocalisableString Description => "Fruits are flipped horizontally."; /// /// is used instead of , diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs index a24a6227fe..9038153e20 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Game.Rulesets.Mods; using osu.Framework.Utils; using osu.Game.Configuration; @@ -14,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Mods { public class CatchModNoScope : ModNoScope, IUpdatableByPlayfield { - public override string Description => "Where's the catcher?"; + public override LocalisableString Description => "Where's the catcher?"; [SettingSource( "Hidden at combo", diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs index 60f1614d98..69ae8328e9 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Mods; @@ -16,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Mods { public class CatchModRelax : ModRelax, IApplicableToDrawableRuleset, IApplicableToPlayer { - public override string Description => @"Use the mouse to control the catcher."; + public override LocalisableString Description => @"Use the mouse to control the catcher."; private DrawableRuleset drawableRuleset = null!; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs index 614ef76a3b..0d0c0d8f68 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.UI; @@ -18,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Mods public override double ScoreMultiplier => 1; - public override string Description => "No more tricky speed changes!"; + public override LocalisableString Description => "No more tricky speed changes!"; public override IconUsage? Icon => FontAwesome.Solid.Equals; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs index c78bf72979..2457aa75d7 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModDualStages.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 osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mods; @@ -11,7 +12,7 @@ namespace osu.Game.Rulesets.Mania.Mods { public override string Name => "Dual Stages"; public override string Acronym => "DS"; - public override string Description => @"Double the stages, double the fun!"; + public override LocalisableString Description => @"Double the stages, double the fun!"; public override ModType Type => ModType.Conversion; public override double ScoreMultiplier => 1; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs index 4093aeb2a7..5c8cd6a5ae 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModEasy.cs @@ -1,12 +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 osu.Framework.Localisation; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModEasy : ModEasyWithExtraLives { - public override string Description => @"More forgiving HP drain, less accuracy required, and three lives!"; + public override LocalisableString Description => @"More forgiving HP drain, less accuracy required, and three lives!"; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs index f80c9e1f7c..c6e9c339f4 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Framework.Localisation; using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Mods @@ -11,7 +12,7 @@ namespace osu.Game.Rulesets.Mania.Mods { public override string Name => "Fade In"; public override string Acronym => "FI"; - public override string Description => @"Keys appear out of nowhere!"; + public override LocalisableString Description => @"Keys appear out of nowhere!"; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModHidden)).ToArray(); diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs index e3ac624a6e..eeb6e94fc7 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHidden.cs @@ -3,13 +3,14 @@ using System; using System.Linq; +using osu.Framework.Localisation; using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModHidden : ManiaModPlayfieldCover { - public override string Description => @"Keys fade out before you hit them!"; + public override LocalisableString Description => @"Keys fade out before you hit them!"; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ManiaModFadeIn)).ToArray(); diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs index a65938184c..ca9bc89473 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs @@ -8,6 +8,7 @@ using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; using osu.Framework.Graphics.Sprites; using System.Collections.Generic; +using osu.Framework.Localisation; using osu.Game.Rulesets.Mania.Beatmaps; namespace osu.Game.Rulesets.Mania.Mods @@ -20,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Mods public override double ScoreMultiplier => 1; - public override string Description => @"Replaces all hold notes with normal notes."; + public override LocalisableString Description => @"Replaces all hold notes with normal notes."; public override IconUsage? Icon => FontAwesome.Solid.DotCircle; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModInvert.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModInvert.cs index 4cbdaee323..ef9154d180 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModInvert.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModInvert.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; @@ -20,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Mods public override string Acronym => "IN"; public override double ScoreMultiplier => 1; - public override string Description => "Hold the keys. To the beat."; + public override LocalisableString Description => "Hold the keys. To the beat."; public override IconUsage? Icon => FontAwesome.Solid.YinYang; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs index 948979505c..31f52610e9 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey1.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModKey1 : ManiaKeyMod @@ -8,6 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override int KeyCount => 1; public override string Name => "One Key"; public override string Acronym => "1K"; - public override string Description => @"Play with one key."; + public override LocalisableString Description => @"Play with one key."; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs index 684370fc3d..67e65b887a 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey10.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModKey10 : ManiaKeyMod @@ -8,6 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override int KeyCount => 10; public override string Name => "Ten Keys"; public override string Acronym => "10K"; - public override string Description => @"Play with ten keys."; + public override LocalisableString Description => @"Play with ten keys."; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs index de91902ca8..0f8148d252 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey2.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModKey2 : ManiaKeyMod @@ -8,6 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override int KeyCount => 2; public override string Name => "Two Keys"; public override string Acronym => "2K"; - public override string Description => @"Play with two keys."; + public override LocalisableString Description => @"Play with two keys."; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs index 8575a96bde..0f8af7940c 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey3.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModKey3 : ManiaKeyMod @@ -8,6 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override int KeyCount => 3; public override string Name => "Three Keys"; public override string Acronym => "3K"; - public override string Description => @"Play with three keys."; + public override LocalisableString Description => @"Play with three keys."; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs index 54ea3afa07..d3a4546dce 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey4.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModKey4 : ManiaKeyMod @@ -8,6 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override int KeyCount => 4; public override string Name => "Four Keys"; public override string Acronym => "4K"; - public override string Description => @"Play with four keys."; + public override LocalisableString Description => @"Play with four keys."; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs index e9a9bba5bd..693182a952 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey5.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModKey5 : ManiaKeyMod @@ -8,6 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override int KeyCount => 5; public override string Name => "Five Keys"; public override string Acronym => "5K"; - public override string Description => @"Play with five keys."; + public override LocalisableString Description => @"Play with five keys."; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs index b9606d1cb5..ab911292f7 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey6.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModKey6 : ManiaKeyMod @@ -8,6 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override int KeyCount => 6; public override string Name => "Six Keys"; public override string Acronym => "6K"; - public override string Description => @"Play with six keys."; + public override LocalisableString Description => @"Play with six keys."; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs index b80d794085..ab401ef1d0 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey7.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModKey7 : ManiaKeyMod @@ -8,6 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override int KeyCount => 7; public override string Name => "Seven Keys"; public override string Acronym => "7K"; - public override string Description => @"Play with seven keys."; + public override LocalisableString Description => @"Play with seven keys."; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs index 3462d634a4..b3e8a45dda 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey8.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModKey8 : ManiaKeyMod @@ -8,6 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override int KeyCount => 8; public override string Name => "Eight Keys"; public override string Acronym => "8K"; - public override string Description => @"Play with eight keys."; + public override LocalisableString Description => @"Play with eight keys."; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs index 83c505c048..5972cbf0fe 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModKey9.cs @@ -1,6 +1,8 @@ // 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.Localisation; + namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModKey9 : ManiaKeyMod @@ -8,6 +10,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override int KeyCount => 9; public override string Name => "Nine Keys"; public override string Acronym => "9K"; - public override string Description => @"Play with nine keys."; + public override LocalisableString Description => @"Play with nine keys."; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs index 9c3744ea98..f9690b4298 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs @@ -5,6 +5,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; using System.Linq; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; @@ -12,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModMirror : ModMirror, IApplicableToBeatmap { - public override string Description => "Notes are flipped horizontally."; + public override LocalisableString Description => "Notes are flipped horizontally."; public void ApplyToBeatmap(IBeatmap beatmap) { diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs index dfb02408d2..6ff070d703 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; @@ -14,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Mods { public class ManiaModRandom : ModRandom, IApplicableToBeatmap { - public override string Description => @"Shuffle around the keys!"; + public override LocalisableString Description => @"Shuffle around the keys!"; public void ApplyToBeatmap(IBeatmap beatmap) { diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs index d88cb17e84..9bf5d33d4a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAlternate.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; namespace osu.Game.Rulesets.Osu.Mods { @@ -11,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Name => @"Alternate"; public override string Acronym => @"AL"; - public override string Description => @"Don't use the same key twice in a row!"; + public override LocalisableString Description => @"Don't use the same key twice in a row!"; public override IconUsage? Icon => FontAwesome.Solid.Keyboard; public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModSingleTap) }).ToArray(); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs index e6889403a3..ec93f19e17 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; @@ -16,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Name => "Approach Different"; public override string Acronym => "AD"; - public override string Description => "Never trust the approach circles..."; + public override LocalisableString Description => "Never trust the approach circles..."; public override double ScoreMultiplier => 1; public override IconUsage? Icon { get; } = FontAwesome.Regular.Circle; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 872fcf7e9b..a42eaec96b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.StateChanges; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; @@ -20,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Acronym => "AP"; public override IconUsage? Icon => OsuIcon.ModAutopilot; public override ModType Type => ModType.Automation; - public override string Description => @"Automatic cursor movement - just follow the rhythm."; + public override LocalisableString Description => @"Automatic cursor movement - just follow the rhythm."; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail), typeof(ModAutoplay), typeof(OsuModMagnetised), typeof(OsuModRepel) }; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 56665db770..4c72667f15 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; @@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods public class OsuModBlinds : Mod, IApplicableToDrawableRuleset, IApplicableToHealthProcessor { public override string Name => "Blinds"; - public override string Description => "Play with blinds on your screen."; + public override LocalisableString Description => "Play with blinds on your screen."; public override string Acronym => "BL"; public override IconUsage? Icon => FontAwesome.Solid.Adjust; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs index ee6a7815e2..e624660410 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs @@ -3,6 +3,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; namespace osu.Game.Rulesets.Osu.Mods @@ -15,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override IconUsage? Icon => FontAwesome.Solid.CompressArrowsAlt; - public override string Description => "Hit them at the right size!"; + public override LocalisableString Description => "Hit them at the right size!"; [SettingSource("Starting Size", "The initial size multiplier applied to all objects.")] public override BindableNumber StartScale { get; } = new BindableFloat diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs b/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs index 06b5b6cfb8..281b36e70e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModEasy.cs @@ -1,12 +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 osu.Framework.Localisation; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Osu.Mods { public class OsuModEasy : ModEasyWithExtraLives { - public override string Description => @"Larger circles, more forgiving HP drain, less accuracy required, and three lives!"; + public override LocalisableString Description => @"Larger circles, more forgiving HP drain, less accuracy required, and three lives!"; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index 182d6eeb4b..b77c887cd3 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -3,6 +3,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; namespace osu.Game.Rulesets.Osu.Mods @@ -15,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override IconUsage? Icon => FontAwesome.Solid.ArrowsAltV; - public override string Description => "Hit them at the right size!"; + public override LocalisableString Description => "Hit them at the right size!"; [SettingSource("Starting Size", "The initial size multiplier applied to all objects.")] public override BindableNumber StartScale { get; } = new BindableFloat diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index 97f201b2cc..996ee1cddb 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; using osu.Framework.Graphics; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; @@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods [SettingSource("Only fade approach circles", "The main object body will not fade when enabled.")] public Bindable OnlyFadeApproachCircles { get; } = new BindableBool(); - public override string Description => @"Play with no approach circles and fading circles/sliders."; + public override LocalisableString Description => @"Play with no approach circles and fading circles/sliders."; public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1; public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSpinIn) }; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs index 9316f9ed74..6871c26750 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; @@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Acronym => "MG"; public override IconUsage? Icon => FontAwesome.Solid.Magnet; public override ModType Type => ModType.Fun; - public override string Description => "No need to chase the circles – your cursor is a magnet!"; + public override LocalisableString Description => "No need to chase the circles – your cursor is a magnet!"; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel) }; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs index 3faca0b01f..0a54d58718 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; @@ -13,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public class OsuModMirror : ModMirror, IApplicableToHitObject { - public override string Description => "Flip objects on the chosen axes."; + public override LocalisableString Description => "Flip objects on the chosen axes."; public override Type[] IncompatibleMods => new[] { typeof(ModHardRock) }; [SettingSource("Mirrored axes", "Choose which axes objects are mirrored over.")] diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs index 3eb8982f5d..817f7b599c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -17,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public class OsuModNoScope : ModNoScope, IUpdatableByPlayfield, IApplicableToBeatmap { - public override string Description => "Where's the cursor?"; + public override LocalisableString Description => "Where's the cursor?"; private PeriodTracker spinnerPeriods = null!; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 4f83154728..96c02a508b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; @@ -18,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods /// public class OsuModRandom : ModRandom, IApplicableToBeatmap { - public override string Description => "It never gets boring!"; + public override LocalisableString Description => "It never gets boring!"; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTarget)).ToArray(); diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 908bb34ed6..fac1cbfd47 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using osu.Framework.Localisation; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; @@ -18,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public class OsuModRelax : ModRelax, IUpdatableByPlayfield, IApplicableToDrawableRuleset, IApplicableToPlayer { - public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things."; + public override LocalisableString Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things."; public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot), typeof(OsuModMagnetised), typeof(OsuModAlternate), typeof(OsuModSingleTap) }).ToArray(); /// diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs index 211987ee32..54b594505c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; @@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Name => "Repel"; public override string Acronym => "RP"; public override ModType Type => ModType.Fun; - public override string Description => "Hit objects run away!"; + public override LocalisableString Description => "Hit objects run away!"; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModMagnetised) }; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSingleTap.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSingleTap.cs index b170d30448..91731b25cf 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSingleTap.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSingleTap.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Framework.Localisation; namespace osu.Game.Rulesets.Osu.Mods { @@ -10,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Name => @"Single Tap"; public override string Acronym => @"SG"; - public override string Description => @"You must only use one key!"; + public override LocalisableString Description => @"You must only use one key!"; public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAlternate) }).ToArray(); protected override bool CheckValidNewAction(OsuAction action) => LastAcceptedAction == null || LastAcceptedAction == action; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs index 95e7d13ee7..b0533d0cfa 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; @@ -18,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Acronym => "SI"; public override IconUsage? Icon => FontAwesome.Solid.Undo; public override ModType Type => ModType.Fun; - public override string Description => "Circles spin in. No approach circles."; + public override LocalisableString Description => "Circles spin in. No approach circles."; public override double ScoreMultiplier => 1; // todo: this mod needs to be incompatible with "hidden" due to forcing the circle to remain opaque, diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index d9ab749ad3..9708800daa 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; @@ -18,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Acronym => "SO"; public override IconUsage? Icon => OsuIcon.ModSpunOut; public override ModType Type => ModType.Automation; - public override string Description => @"Spinners will be automatically completed."; + public override LocalisableString Description => @"Spinners will be automatically completed."; public override double ScoreMultiplier => 0.9; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot), typeof(OsuModTarget) }; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index 0b34ab28a3..67b19124e1 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using System.Threading; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; @@ -23,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Name => @"Strict Tracking"; public override string Acronym => @"ST"; public override ModType Type => ModType.DifficultyIncrease; - public override string Description => @"Once you start a slider, follow precisely or get a miss."; + public override LocalisableString Description => @"Once you start a slider, follow precisely or get a miss."; public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => new[] { typeof(ModClassic), typeof(OsuModTarget) }; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 623157a427..82260db818 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -39,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Acronym => "TP"; public override ModType Type => ModType.Conversion; public override IconUsage? Icon => OsuIcon.ModTarget; - public override string Description => @"Practice keeping up with the beat of the song."; + public override LocalisableString Description => @"Practice keeping up with the beat of the song."; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs index 7276cc753c..fd5c46a226 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTouchDevice.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 osu.Framework.Localisation; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Osu.Mods @@ -9,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Name => "Touch Device"; public override string Acronym => "TD"; - public override string Description => "Automatically applied to plays on devices with a touchscreen."; + public override LocalisableString Description => "Automatically applied to plays on devices with a touchscreen."; public override double ScoreMultiplier => 1; public override ModType Type => ModType.System; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs index d862d36670..25d05a88a8 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Localisation; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; @@ -16,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Name => "Traceable"; public override string Acronym => "TC"; public override ModType Type => ModType.Fun; - public override string Description => "Put your faith in the approach circles..."; + public override LocalisableString Description => "Put your faith in the approach circles..."; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(IHidesApproachCircles) }; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs index 4354ecbe9a..2354cd50ae 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; @@ -18,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Acronym => "TR"; public override IconUsage? Icon => FontAwesome.Solid.ArrowsAlt; public override ModType Type => ModType.Fun; - public override string Description => "Everything rotates. EVERYTHING."; + public override LocalisableString Description => "Everything rotates. EVERYTHING."; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModWiggle), typeof(OsuModMagnetised), typeof(OsuModRepel) }; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs index 3f1c3aa812..a45338d91f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; @@ -20,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Acronym => "WG"; public override IconUsage? Icon => FontAwesome.Solid.Certificate; public override ModType Type => ModType.Fun; - public override string Description => "They just won't stay still..."; + public override LocalisableString Description => "They just won't stay still..."; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModTransform), typeof(OsuModMagnetised), typeof(OsuModRepel) }; diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModEasy.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModEasy.cs index ad6fdf59e2..009f2854f8 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModEasy.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModEasy.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 osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; @@ -8,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public class TaikoModEasy : ModEasy { - public override string Description => @"Beats move slower, and less accuracy required!"; + public override LocalisableString Description => @"Beats move slower, and less accuracy required!"; /// /// Multiplier factor added to the scrolling speed. diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs index 4c802978e3..4708ef9bf0 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModHidden.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; +using osu.Framework.Localisation; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -15,7 +16,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public class TaikoModHidden : ModHidden, IApplicableToDrawableRuleset { - public override string Description => @"Beats fade out before you hit them!"; + public override LocalisableString Description => @"Beats fade out before you hit them!"; public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1; /// diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs index 307a37bf2e..c0be0290e6 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModRandom.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; @@ -13,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public class TaikoModRandom : ModRandom, IApplicableToBeatmap { - public override string Description => @"Shuffle around the colours!"; + public override LocalisableString Description => @"Shuffle around the colours!"; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(TaikoModSwap)).ToArray(); public void ApplyToBeatmap(IBeatmap beatmap) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs index 7be70d9ac3..d1e9ab1428 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModRelax.cs @@ -1,12 +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 osu.Framework.Localisation; using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Taiko.Mods { public class TaikoModRelax : ModRelax { - public override string Description => @"No ninja-like spinners, demanding drumrolls or unexpected katu's."; + public override LocalisableString Description => @"No ninja-like spinners, demanding drumrolls or unexpected katu's."; } } diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs index 3cb337c41d..fc3913f56d 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModSwap.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Beatmaps; @@ -14,7 +15,7 @@ namespace osu.Game.Rulesets.Taiko.Mods { public override string Name => "Swap"; public override string Acronym => "SW"; - public override string Description => @"Dons become kats, kats become dons"; + public override LocalisableString Description => @"Dons become kats, kats become dons"; public override ModType Type => ModType.Conversion; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModRandom)).ToArray(); diff --git a/osu.Game.Tests/Mods/ModUtilsTest.cs b/osu.Game.Tests/Mods/ModUtilsTest.cs index 3b391f6756..aa41fd830b 100644 --- a/osu.Game.Tests/Mods/ModUtilsTest.cs +++ b/osu.Game.Tests/Mods/ModUtilsTest.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using Moq; using NUnit.Framework; +using osu.Framework.Localisation; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Utils; @@ -320,7 +321,7 @@ namespace osu.Game.Tests.Mods public class InvalidMultiplayerMod : Mod { public override string Name => string.Empty; - public override string Description => string.Empty; + public override LocalisableString Description => string.Empty; public override string Acronym => string.Empty; public override double ScoreMultiplier => 1; public override bool HasImplementation => true; @@ -331,7 +332,7 @@ namespace osu.Game.Tests.Mods private class InvalidMultiplayerFreeMod : Mod { public override string Name => string.Empty; - public override string Description => string.Empty; + public override LocalisableString Description => string.Empty; public override string Acronym => string.Empty; public override double ScoreMultiplier => 1; public override bool HasImplementation => true; diff --git a/osu.Game.Tests/Mods/TestCustomisableModRuleset.cs b/osu.Game.Tests/Mods/TestCustomisableModRuleset.cs index 9e3354935a..7df5448ff7 100644 --- a/osu.Game.Tests/Mods/TestCustomisableModRuleset.cs +++ b/osu.Game.Tests/Mods/TestCustomisableModRuleset.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets; @@ -60,7 +61,7 @@ namespace osu.Game.Tests.Mods { public override double ScoreMultiplier => 1.0; - public override string Description => "This is a customisable test mod."; + public override LocalisableString Description => "This is a customisable test mod."; public override ModType Type => ModType.Conversion; diff --git a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs index 8d1c266473..6637d640b2 100644 --- a/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs +++ b/osu.Game.Tests/NonVisual/DifficultyAdjustmentModCombinationsTest.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Preprocessing; @@ -160,7 +161,7 @@ namespace osu.Game.Tests.NonVisual { public override string Name => nameof(ModA); public override string Acronym => nameof(ModA); - public override string Description => string.Empty; + public override LocalisableString Description => string.Empty; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(ModIncompatibleWithA), typeof(ModIncompatibleWithAAndB) }; @@ -169,7 +170,7 @@ namespace osu.Game.Tests.NonVisual private class ModB : Mod { public override string Name => nameof(ModB); - public override string Description => string.Empty; + public override LocalisableString Description => string.Empty; public override string Acronym => nameof(ModB); public override double ScoreMultiplier => 1; @@ -180,7 +181,7 @@ namespace osu.Game.Tests.NonVisual { public override string Name => nameof(ModC); public override string Acronym => nameof(ModC); - public override string Description => string.Empty; + public override LocalisableString Description => string.Empty; public override double ScoreMultiplier => 1; } @@ -188,7 +189,7 @@ namespace osu.Game.Tests.NonVisual { public override string Name => $"Incompatible With {nameof(ModA)}"; public override string Acronym => $"Incompatible With {nameof(ModA)}"; - public override string Description => string.Empty; + public override LocalisableString Description => string.Empty; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(ModA) }; @@ -207,7 +208,7 @@ namespace osu.Game.Tests.NonVisual { public override string Name => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}"; public override string Acronym => $"Incompatible With {nameof(ModA)} and {nameof(ModB)}"; - public override string Description => string.Empty; + public override LocalisableString Description => string.Empty; public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(ModA), typeof(ModB) }; diff --git a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs index 7458508c7a..17709fb10f 100644 --- a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs +++ b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs @@ -9,6 +9,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NUnit.Framework; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Online.API; @@ -182,7 +183,7 @@ namespace osu.Game.Tests.Online { public override string Name => "Test Mod"; public override string Acronym => "TM"; - public override string Description => "This is a test mod."; + public override LocalisableString Description => "This is a test mod."; public override double ScoreMultiplier => 1; [SettingSource("Test")] @@ -199,7 +200,7 @@ namespace osu.Game.Tests.Online { public override string Name => "Test Mod"; public override string Acronym => "TMTR"; - public override string Description => "This is a test mod."; + public override LocalisableString Description => "This is a test mod."; public override double ScoreMultiplier => 1; [SettingSource("Initial rate", "The starting speed of the track")] diff --git a/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs b/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs index a89d68bf15..b17414e026 100644 --- a/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs +++ b/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using MessagePack; using NUnit.Framework; using osu.Framework.Bindables; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Online.API; @@ -102,7 +103,7 @@ namespace osu.Game.Tests.Online { public override string Name => "Test Mod"; public override string Acronym => "TM"; - public override string Description => "This is a test mod."; + public override LocalisableString Description => "This is a test mod."; public override double ScoreMultiplier => 1; [SettingSource("Test")] @@ -119,7 +120,7 @@ namespace osu.Game.Tests.Online { public override string Name => "Test Mod"; public override string Acronym => "TMTR"; - public override string Description => "This is a test mod."; + public override LocalisableString Description => "This is a test mod."; public override double ScoreMultiplier => 1; [SettingSource("Initial rate", "The starting speed of the track")] @@ -154,7 +155,7 @@ namespace osu.Game.Tests.Online { public override string Name => "Test Mod"; public override string Acronym => "TM"; - public override string Description => "This is a test mod."; + public override LocalisableString Description => "This is a test mod."; public override double ScoreMultiplier => 1; [SettingSource("Test")] diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 05474e3d39..94114e36f6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -13,6 +13,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Framework.Screens; using osu.Framework.Testing; @@ -374,7 +375,7 @@ namespace osu.Game.Tests.Visual.Gameplay public override string Name => string.Empty; public override string Acronym => string.Empty; public override double ScoreMultiplier => 1; - public override string Description => string.Empty; + public override LocalisableString Description => string.Empty; public bool Applied { get; private set; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 07473aa55b..a821a4a6b9 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -11,6 +11,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Graphics.UserInterface; @@ -540,7 +541,7 @@ namespace osu.Game.Tests.Visual.UserInterface { public override string Name => "Unimplemented mod"; public override string Acronym => "UM"; - public override string Description => "A mod that is not implemented."; + public override LocalisableString Description => "A mod that is not implemented."; public override double ScoreMultiplier => 1; public override ModType Type => ModType.Conversion; } From a42b8092af4e27af1978928bd61bf0b1e24ba65d Mon Sep 17 00:00:00 2001 From: naoei Date: Wed, 10 Aug 2022 16:09:58 -0400 Subject: [PATCH 0411/2686] Change message type osu resume overlay --- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index fc3f89a836..412505331b 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Game.Rulesets.Osu.UI.Cursor; using osu.Game.Screens.Play; using osuTK; @@ -28,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.UI public override CursorContainer LocalCursor => State.Value == Visibility.Visible ? localCursorContainer : null; - protected override string Message => "Click the orange cursor to resume"; + protected override LocalisableString Message => "Click the orange cursor to resume"; [BackgroundDependencyLoader] private void load() From 7cbe2fa522a1591a9eab3307a20255d252ad5ba7 Mon Sep 17 00:00:00 2001 From: naoei Date: Wed, 10 Aug 2022 16:12:16 -0400 Subject: [PATCH 0412/2686] Enable localisation for `SettingSourceAttribute` --- .../Configuration/SettingSourceAttribute.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game/Configuration/SettingSourceAttribute.cs b/osu.Game/Configuration/SettingSourceAttribute.cs index 21e67363c3..630b65ae82 100644 --- a/osu.Game/Configuration/SettingSourceAttribute.cs +++ b/osu.Game/Configuration/SettingSourceAttribute.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Reflection; using JetBrains.Annotations; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics; using osu.Framework.Localisation; @@ -43,12 +44,47 @@ namespace osu.Game.Configuration /// public Type? SettingControlType { get; set; } + public SettingSourceAttribute(Type declaringType, string label, string? description = null) + { + Label = getLocalisableStringFromMember(label) ?? string.Empty; + Description = getLocalisableStringFromMember(description) ?? string.Empty; + + LocalisableString? getLocalisableStringFromMember(string? member) + { + if (member == null) + return null; + + var property = declaringType.GetMember(member, BindingFlags.Static | BindingFlags.Public).FirstOrDefault(); + + if (property == null) + return null; + + switch (property) + { + case FieldInfo f: + return (LocalisableString)f.GetValue(null).AsNonNull(); + + case PropertyInfo p: + return (LocalisableString)p.GetValue(null).AsNonNull(); + + default: + throw new InvalidOperationException($"Member \"{member}\" was not found in type {declaringType} (must be a static field or property)"); + } + } + } + public SettingSourceAttribute(string? label, string? description = null) { Label = label ?? string.Empty; Description = description ?? string.Empty; } + public SettingSourceAttribute(Type declaringType, string label, string description, int orderPosition) + : this(declaringType, label, description) + { + OrderPosition = orderPosition; + } + public SettingSourceAttribute(string label, string description, int orderPosition) : this(label, description) { From 60abe8339801b2ddfd70d282f3d6e9dd02e403ee Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Wed, 10 Aug 2022 17:56:36 -0400 Subject: [PATCH 0413/2686] Remove newline --- osu.Game/OsuGame.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ca0ce916a2..073a99e406 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1144,7 +1144,6 @@ namespace osu.Game userProfile.Hide(); return true; } - else { ShowUser(new APIUser { Id = API.LocalUser.Value.Id }); From 9e80d3f71c01a2e5789348a9237bc1d92c4b6c2b Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 11 Aug 2022 00:42:22 +0200 Subject: [PATCH 0414/2686] Re-adjust timespan conditions in `KeysPerSecondCalculator` --- osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs index 96a6d5b8eb..890404a0aa 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs @@ -93,7 +93,7 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter double span = 1000 * rate; double relativeTime = workingClock.CurrentTime - timestamp; - return relativeTime >= 0 && relativeTime <= span; + return relativeTime > 0 && relativeTime <= span; } ~KeysPerSecondCalculator() From 46e372cb99ba47a86f17418353086e95a4ddd3fd Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 11 Aug 2022 00:43:15 +0200 Subject: [PATCH 0415/2686] Add more readiness checks in `KeysPerSecondCalculator` --- osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs index 890404a0aa..dddef9abaf 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs @@ -57,7 +57,7 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter private double maxTime = double.NegativeInfinity; - public bool Ready => workingClock != null && gameplayClock != null; + public bool Ready => workingClock != null && gameplayClock != null && listener != null; public int Value => timestamps.Count(isTimestampWithinSpan); public KeysPerSecondCalculator() From 0a94fb4039df50a5a48e55cae546221557fcff4d Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 11 Aug 2022 00:46:31 +0200 Subject: [PATCH 0416/2686] Make KPS counter strictly depending only on KPS calculator `KeysPerSecondCounter` now depends on `KeysPerSecondCalculator` via the `BackgroundDependencyLoaderAttribute` method, making it appear only in a gameplay context without requiring `GameplayClock` without using it. --- .../Play/HUD/KPSCounter/KeysPerSecondCounter.cs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs index d6f1d19770..47ebede623 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs @@ -10,7 +10,7 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Rulesets.UI; +// using osu.Game.Rulesets.UI; using osu.Game.Skinning; using osuTK; @@ -22,15 +22,7 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter private readonly Bindable valid = new Bindable(); - [Resolved] - private KeysPerSecondCalculator? calculator { get; set; } - - // This is to force the skin editor to show the component only in a Gameplay context - [Resolved] - private GameplayClock? gameplayClock { get; set; } - - [Resolved(canBeNull: true)] - private DrawableRuleset? drawableRuleset { get; set; } + private KeysPerSecondCalculator? calculator; protected override double RollingDuration => 350; @@ -42,8 +34,9 @@ namespace osu.Game.Screens.Play.HUD.KPSCounter } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, KeysPerSecondCalculator calculator) { + this.calculator = calculator; Colour = colours.BlueLighter; valid.BindValueChanged(e => DrawableCount.FadeTo(e.NewValue ? 1 : alpha_when_invalid, 1000, Easing.OutQuint)); From d58d5eebe2ec52e19142442dcdfd162d6263f213 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 11 Aug 2022 00:51:13 +0200 Subject: [PATCH 0417/2686] Add basic tests for KPS Created private mock classes to use them in place of `GameplayClock` and `DrawableRuleset`. --- .../Visual/Gameplay/TestSceneKeysPerSecond.cs | 306 ++++++++++++++++++ .../Gameplay/TestSceneKeysPerSecondCounter.cs | 9 - 2 files changed, 306 insertions(+), 9 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs delete mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs new file mode 100644 index 0000000000..4bda998c49 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs @@ -0,0 +1,306 @@ +// 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.Diagnostics; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Framework.Timing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.UI; +using osu.Game.Scoring; +using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD.KPSCounter; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneKeysPerSecond : OsuTestScene + { + private DependencyProvidingContainer? dependencyContainer; + private MockFrameStableClock? mainClock; + private KeysPerSecondCalculator? calculator; + private ManualInputListener? listener; + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create components", () => + { + var ruleset = CreateRuleset(); + + Debug.Assert(ruleset != null); + + Children = new Drawable[] + { + dependencyContainer = new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] + { + (typeof(GameplayClock), mainClock = new MockFrameStableClock(new MockFrameBasedClock())), + (typeof(DrawableRuleset), new DrawableCookieziRuleset(ruleset, mainClock)) + } + }, + }; + }); + } + + private void createCalculator() + { + AddStep("create calculator", () => + { + dependencyContainer!.Children = new Drawable[] + { + calculator = new KeysPerSecondCalculator + { + Listener = listener = new ManualInputListener() + }, + new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] { (typeof(KeysPerSecondCalculator), calculator) }, + Child = new KeysPerSecondCounter // For visual debugging, has no real purpose in the tests + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(5), + } + } + }; + }); + } + + [Test] + public void TestBasicConsistency() + { + createCalculator(); + + AddStep("Create gradually increasing KPS inputs", () => + { + addInputs(generateGraduallyIncreasingKps()); + }); + + for (int i = 0; i < 10; i++) + { + seek(i * 10000); + advanceForwards(2); + int kps = i + 1; + AddAssert($"{kps} KPS", () => calculator!.Value == kps); + } + } + + [Test] + public void TestRateAdjustConsistency() + { + createCalculator(); + + AddStep("Create consistent KPS inputs", () => addInputs(generateConsistentKps(10))); + + advanceForwards(2); + + for (double i = 1; i <= 2; i += 0.25) + { + changeRate(i); + double rate = i; + AddAssert($"KPS approx. = {i}", () => MathHelper.ApproximatelyEquivalent(calculator!.Value, 10 * rate, 0.5)); + } + + for (double i = 1; i >= 0.5; i -= 0.25) + { + changeRate(i); + double rate = i; + AddAssert($"KPS approx. = {i}", () => MathHelper.ApproximatelyEquivalent(calculator!.Value, 10 * rate, 0.5)); + } + } + + [Test] + public void TestInputsDiscardedOnRewind() + { + createCalculator(); + + AddStep("Create consistent KPS inputs", () => addInputs(generateConsistentKps(10))); + seek(1000); + + AddAssert("KPS = 10", () => calculator!.Value == 10); + + AddStep("Create delayed inputs", () => addInputs(generateConsistentKps(10, 50))); + seek(1000); + AddAssert("KPS didn't changed", () => calculator!.Value == 10); + } + + private void seek(double time) => AddStep($"Seek main clock to {time}ms", () => mainClock?.Seek(time)); + + private void changeRate(double rate) => AddStep($"Change rate to x{rate}", () => + (mainClock?.UnderlyingClock as MockFrameBasedClock)!.Rate = rate); + + private void advanceForwards(int frames = 1) => AddStep($"Advance main clock {frames} frame(s) forward.", () => + { + if (mainClock == null) return; + + MockFrameBasedClock underlyingClock = (MockFrameBasedClock)mainClock.UnderlyingClock; + underlyingClock.Backwards = false; + + for (int i = 0; i < frames; i++) + { + underlyingClock.ProcessFrame(); + } + }); + + private void addInputs(IEnumerable inputs) + { + Debug.Assert(mainClock != null && listener != null); + if (!inputs.Any()) return; + + double baseTime = mainClock.CurrentTime; + + foreach (double timestamp in inputs) + { + mainClock.Seek(timestamp); + listener.AddInput(); + } + + mainClock.Seek(baseTime); + } + + private IEnumerable generateGraduallyIncreasingKps() + { + IEnumerable? final = null; + + for (int i = 1; i <= 10; i++) + { + var currentKps = generateConsistentKps(i, (i - 1) * 10000); + + if (i == 1) + { + final = currentKps; + continue; + } + + final = final!.Concat(currentKps); + } + + return final!; + } + + private IEnumerable generateConsistentKps(double kps, double start = 0, double duration = 10) + { + double end = start + 1000 * duration; + + for (; start < end; start += 1000 / kps) + { + yield return start; + } + } + + protected override Ruleset CreateRuleset() => new ManiaRuleset(); + + #region Mock classes + + private class ManualInputListener : KeysPerSecondCalculator.InputListener + { + public override event Action? OnNewInput; + + public void AddInput() => OnNewInput?.Invoke(); + } + + private class MockFrameBasedClock : ManualClock, IFrameBasedClock + { + public const double FRAME_INTERVAL = 1000; + public bool Backwards; + + public MockFrameBasedClock() + { + Rate = 1; + IsRunning = true; + } + + public void ProcessFrame() + { + CurrentTime += FRAME_INTERVAL * Rate * (Backwards ? -1 : 1); + TimeInfo = new FrameTimeInfo + { + Current = CurrentTime, + Elapsed = FRAME_INTERVAL * Rate * (Backwards ? -1 : 1) + }; + } + + public void Seek(double time) + { + TimeInfo = new FrameTimeInfo + { + Elapsed = time - CurrentTime, + Current = CurrentTime = time + }; + } + + public double ElapsedFrameTime => TimeInfo.Elapsed; + public double FramesPerSecond => 1 / FRAME_INTERVAL; + public FrameTimeInfo TimeInfo { get; private set; } + } + + private class MockFrameStableClock : GameplayClock, IFrameStableClock + { + public MockFrameStableClock(MockFrameBasedClock underlyingClock) + : base(underlyingClock) + { + } + + public void Seek(double time) => (UnderlyingClock as MockFrameBasedClock)?.Seek(time); + + public IBindable IsCatchingUp => new Bindable(); + public IBindable WaitingOnFrames => new Bindable(); + } + + private class DrawableCookieziRuleset : DrawableRuleset + { + public DrawableCookieziRuleset(Ruleset ruleset, IFrameStableClock clock) + : base(ruleset) + { + FrameStableClock = clock; + } + +#pragma warning disable CS0067 + public override event Action? NewResult; + public override event Action? RevertResult; +#pragma warning restore CS0067 + public override Playfield? Playfield => null; + public override Container? Overlays => null; + public override Container? FrameStableComponents => null; + public override IFrameStableClock FrameStableClock { get; } + + internal override bool FrameStablePlayback { get; set; } + public override IReadOnlyList Mods => Array.Empty(); + public override IEnumerable Objects => Array.Empty(); + public override double GameplayStartTime => 0; + public override GameplayCursorContainer? Cursor => null; + + public override void SetReplayScore(Score replayScore) + { + } + + public override void SetRecordTarget(Score score) + { + } + + public override void RequestResume(Action continueResume) + { + } + + public override void CancelResume() + { + } + } + + #endregion + } +} diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs deleted file mode 100644 index 8bc2eae1d4..0000000000 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecondCounter.cs +++ /dev/null @@ -1,9 +0,0 @@ -// 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.Tests.Visual.Gameplay -{ - public class TestSceneKeysPerSecondCounter : OsuManualInputManagerTestScene - { - } -} From 0e1efbd865c96a2aa53c98f80cc1b00d287f2190 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 11 Aug 2022 01:03:47 +0200 Subject: [PATCH 0418/2686] Rename `DrawableCookieziRuleset` to `MockDrawableRuleset` --- osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs index 4bda998c49..edfba7f154 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.Gameplay CachedDependencies = new (Type, object)[] { (typeof(GameplayClock), mainClock = new MockFrameStableClock(new MockFrameBasedClock())), - (typeof(DrawableRuleset), new DrawableCookieziRuleset(ruleset, mainClock)) + (typeof(DrawableRuleset), new MockDrawableRuleset(ruleset, mainClock)) } }, }; @@ -261,9 +261,9 @@ namespace osu.Game.Tests.Visual.Gameplay public IBindable WaitingOnFrames => new Bindable(); } - private class DrawableCookieziRuleset : DrawableRuleset + private class MockDrawableRuleset : DrawableRuleset { - public DrawableCookieziRuleset(Ruleset ruleset, IFrameStableClock clock) + public MockDrawableRuleset(Ruleset ruleset, IFrameStableClock clock) : base(ruleset) { FrameStableClock = clock; From e5b534bb26b748cdfe1f756e80cb0fcc66f2367d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 11 Aug 2022 12:44:58 +0900 Subject: [PATCH 0419/2686] Add thread safety to `APIAccess.LocalUser` --- osu.Game/Online/API/APIAccess.cs | 16 +++++++++------- osu.Game/Online/API/IAPIProvider.cs | 3 --- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 42133160ca..66bd22df52 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -142,10 +142,10 @@ namespace osu.Game.Online.API // Show a placeholder user if saved credentials are available. // This is useful for storing local scores and showing a placeholder username after starting the game, // until a valid connection has been established. - localUser.Value = new APIUser + setLocalUser(new APIUser { Username = ProvidedUsername, - }; + }); } // save the username at this point, if the user requested for it to be. @@ -188,12 +188,12 @@ namespace osu.Game.Online.API else failConnectionProcess(); }; - userReq.Success += u => + userReq.Success += user => { - localUser.Value = u; - // todo: save/pull from settings - localUser.Value.Status.Value = new UserStatusOnline(); + user.Status.Value = new UserStatusOnline(); + + setLocalUser(user); failureCount = 0; }; @@ -453,7 +453,7 @@ namespace osu.Game.Online.API // Scheduled prior to state change such that the state changed event is invoked with the correct user and their friends present Schedule(() => { - localUser.Value = createGuestUser(); + setLocalUser(createGuestUser()); friends.Clear(); }); @@ -463,6 +463,8 @@ namespace osu.Game.Online.API private static APIUser createGuestUser() => new GuestUser(); + private void setLocalUser(APIUser user) => Scheduler.Add(() => localUser.Value = user, false); + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index 812aa7f09f..a90b11e354 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -13,19 +13,16 @@ namespace osu.Game.Online.API { /// /// The local user. - /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// IBindable LocalUser { get; } /// /// The user's friends. - /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// IBindableList Friends { get; } /// /// The current user's activity. - /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// IBindable Activity { get; } From e01383b138f33407a4efc04c6fbcb8a7d6082c91 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 11 Aug 2022 13:17:14 +0900 Subject: [PATCH 0420/2686] Tidy up user passing logic --- osu.Game/OsuGame.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 073a99e406..f7747c5d64 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1140,15 +1140,10 @@ namespace osu.Game case GlobalAction.ToggleProfile: if (userProfile.State.Value == Visibility.Visible) - { userProfile.Hide(); - return true; - } else - { - ShowUser(new APIUser { Id = API.LocalUser.Value.Id }); - return true; - } + ShowUser(API.LocalUser.Value); + return true; case GlobalAction.RandomSkin: // Don't allow random skin selection while in the skin editor. From 7ec67c28b90d8bd0d197026f8fdf6a571d00c6a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 11 Aug 2022 14:35:55 +0900 Subject: [PATCH 0421/2686] Set `Online` state sooner in connection process This isn't really required as such, but feels more correct. There was no reason for it to wait for the friend population to complete before deeming things to be "online". --- osu.Game/Online/API/APIAccess.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 66bd22df52..f353c48f03 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -195,6 +195,8 @@ namespace osu.Game.Online.API setLocalUser(user); + //we're connected! + state.Value = APIState.Online; failureCount = 0; }; @@ -208,13 +210,7 @@ namespace osu.Game.Online.API var friendsReq = new GetFriendsRequest(); friendsReq.Failure += _ => failConnectionProcess(); - friendsReq.Success += res => - { - friends.AddRange(res); - - //we're connected! - state.Value = APIState.Online; - }; + friendsReq.Success += res => friends.AddRange(res); if (!handleRequest(friendsReq)) { From 47196b19a5e4a025c073d9abb11e17ce63b4ee83 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 11 Aug 2022 14:36:28 +0900 Subject: [PATCH 0422/2686] Stop setting `Online` state in `handleRequest` This is already handled amicably by the `Failing` -> `Connecting` flow. Having this set in `handleRequest` throws things off, potentially leading to the `Online` state change before the user has been populated. --- osu.Game/Online/API/APIAccess.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index f353c48f03..72c88b1e92 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -334,8 +334,7 @@ namespace osu.Game.Online.API if (req.CompletionState != APIRequestCompletionState.Completed) return false; - // we could still be in initialisation, at which point we don't want to say we're Online yet. - if (IsLoggedIn) state.Value = APIState.Online; + // Reset failure count if this request succeeded. failureCount = 0; return true; } From 865d63f7681b6b2eb10f4e8ef5234f576e86942c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 11 Aug 2022 15:43:39 +0900 Subject: [PATCH 0423/2686] Refactor `APIAccess` main loop to read better --- osu.Game/Online/API/APIAccess.cs | 273 ++++++++++++++++--------------- 1 file changed, 143 insertions(+), 130 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 72c88b1e92..a0c8e0d555 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -104,127 +104,39 @@ namespace osu.Game.Online.API /// private int failureCount; + /// + /// The main API thread loop, which will continue to run until the game is shut down. + /// private void run() { while (!cancellationToken.IsCancellationRequested) { - switch (State.Value) + if (state.Value == APIState.Failing) { - case APIState.Failing: - //todo: replace this with a ping request. - log.Add(@"In a failing state, waiting a bit before we try again..."); - Thread.Sleep(5000); + // To recover from a failing state, falling through and running the full reconnection process seems safest for now. + // This could probably be replaced with a ping-style request if we want to avoid the reconnection overheads. + log.Add($@"{nameof(APIAccess)} is in a failing state, waiting a bit before we try again..."); + Thread.Sleep(5000); + } - if (!IsLoggedIn) goto case APIState.Connecting; + // Ensure that we have valid credentials. + // If not, setting the offline state will allow the game to prompt the user to provide new credentials. + if (!HasLogin) + { + state.Value = APIState.Offline; + Thread.Sleep(50); + continue; + } - if (queue.Count == 0) - { - log.Add(@"Queueing a ping request"); - Queue(new GetUserRequest()); - } + Debug.Assert(HasLogin); - break; + // Ensure that we are in an online state. If not, attempt a connect. + if (state.Value != APIState.Online) + { + attemptConnect(); - case APIState.Offline: - case APIState.Connecting: - // work to restore a connection... - if (!HasLogin) - { - state.Value = APIState.Offline; - Thread.Sleep(50); - continue; - } - - state.Value = APIState.Connecting; - - if (localUser.IsDefault) - { - // Show a placeholder user if saved credentials are available. - // This is useful for storing local scores and showing a placeholder username after starting the game, - // until a valid connection has been established. - setLocalUser(new APIUser - { - Username = ProvidedUsername, - }); - } - - // save the username at this point, if the user requested for it to be. - config.SetValue(OsuSetting.Username, config.Get(OsuSetting.SaveUsername) ? ProvidedUsername : string.Empty); - - if (!authentication.HasValidAccessToken) - { - LastLoginError = null; - - try - { - authentication.AuthenticateWithLogin(ProvidedUsername, password); - } - catch (Exception e) - { - //todo: this fails even on network-related issues. we should probably handle those differently. - LastLoginError = e; - log.Add(@"Login failed!"); - password = null; - authentication.Clear(); - continue; - } - } - - var userReq = new GetUserRequest(); - - userReq.Failure += ex => - { - if (ex is APIException) - { - LastLoginError = ex; - log.Add("Login failed on local user retrieval!"); - Logout(); - } - else if (ex is WebException webException && webException.Message == @"Unauthorized") - { - log.Add(@"Login no longer valid"); - Logout(); - } - else - failConnectionProcess(); - }; - userReq.Success += user => - { - // todo: save/pull from settings - user.Status.Value = new UserStatusOnline(); - - setLocalUser(user); - - //we're connected! - state.Value = APIState.Online; - failureCount = 0; - }; - - if (!handleRequest(userReq)) - { - failConnectionProcess(); - continue; - } - - // getting user's friends is considered part of the connection process. - var friendsReq = new GetFriendsRequest(); - - friendsReq.Failure += _ => failConnectionProcess(); - friendsReq.Success += res => friends.AddRange(res); - - if (!handleRequest(friendsReq)) - { - failConnectionProcess(); - continue; - } - - // The Success callback event is fired on the main thread, so we should wait for that to run before proceeding. - // Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests - // before actually going online. - while (State.Value > APIState.Offline && State.Value < APIState.Online) - Thread.Sleep(500); - - break; + if (state.Value != APIState.Online) + continue; } // hard bail if we can't get a valid access token. @@ -234,31 +146,132 @@ namespace osu.Game.Online.API continue; } - while (true) - { - APIRequest req; - - lock (queue) - { - if (queue.Count == 0) break; - - req = queue.Dequeue(); - } - - handleRequest(req); - } - + processQueuedRequests(); Thread.Sleep(50); } + } - void failConnectionProcess() + /// + /// Dequeue from the queue and run each request synchronously until the queue is empty. + /// + private void processQueuedRequests() + { + while (true) { - // if something went wrong during the connection process, we want to reset the state (but only if still connecting). - if (State.Value == APIState.Connecting) - state.Value = APIState.Failing; + APIRequest req; + + lock (queue) + { + if (queue.Count == 0) return; + + req = queue.Dequeue(); + } + + handleRequest(req); } } + /// + /// From a non-connected state, perform a full connection flow, obtaining OAuth tokens and populating the local user and friends. + /// + /// + /// This method takes control of and transitions from to either + /// - (successful connection) + /// - (failed connection but retrying) + /// - (failed and can't retry, clear credentials and require user interaction) + /// + /// Whether the connection attempt was successful. + private void attemptConnect() + { + state.Value = APIState.Connecting; + + if (localUser.IsDefault) + { + // Show a placeholder user if saved credentials are available. + // This is useful for storing local scores and showing a placeholder username after starting the game, + // until a valid connection has been established. + setLocalUser(new APIUser + { + Username = ProvidedUsername, + }); + } + + // save the username at this point, if the user requested for it to be. + config.SetValue(OsuSetting.Username, config.Get(OsuSetting.SaveUsername) ? ProvidedUsername : string.Empty); + + if (!authentication.HasValidAccessToken) + { + LastLoginError = null; + + try + { + authentication.AuthenticateWithLogin(ProvidedUsername, password); + } + catch (Exception e) + { + //todo: this fails even on network-related issues. we should probably handle those differently. + LastLoginError = e; + log.Add($@"Login failed for username {ProvidedUsername} ({LastLoginError.Message})!"); + + Logout(); + return; + } + } + + var userReq = new GetUserRequest(); + userReq.Failure += ex => + { + if (ex is APIException) + { + LastLoginError = ex; + log.Add($@"Login failed for username {ProvidedUsername} on user retrieval ({LastLoginError.Message})!"); + Logout(); + } + else if (ex is WebException webException && webException.Message == @"Unauthorized") + { + log.Add(@"Login no longer valid"); + Logout(); + } + else + { + state.Value = APIState.Failing; + } + }; + userReq.Success += user => + { + // todo: save/pull from settings + user.Status.Value = new UserStatusOnline(); + + setLocalUser(user); + + // we're connected! + state.Value = APIState.Online; + failureCount = 0; + }; + + if (!handleRequest(userReq)) + { + state.Value = APIState.Failing; + return; + } + + var friendsReq = new GetFriendsRequest(); + friendsReq.Failure += _ => state.Value = APIState.Failing; + friendsReq.Success += res => friends.AddRange(res); + + if (!handleRequest(friendsReq)) + { + state.Value = APIState.Failing; + return; + } + + // The Success callback event is fired on the main thread, so we should wait for that to run before proceeding. + // Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests + // before actually going online. + while (State.Value == APIState.Connecting && !cancellationToken.IsCancellationRequested) + Thread.Sleep(500); + } + public void Perform(APIRequest request) { try From 3c6461b9e4383174278cf3b4ab7493a6c076473d Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 11 Aug 2022 09:36:35 +0200 Subject: [PATCH 0424/2686] Remove KPS acronym usage --- .../Visual/Gameplay/TestSceneKeysPerSecond.cs | 2 +- osu.Game/Rulesets/UI/DrawableRuleset.cs | 6 +++--- osu.Game/Rulesets/UI/RulesetInputManager.cs | 16 ++++++---------- .../KeysPerSecondCalculator.cs | 2 +- .../KeysPerSecondCounter.cs | 4 ++-- osu.Game/Screens/Play/HUDOverlay.cs | 5 ++--- 6 files changed, 15 insertions(+), 20 deletions(-) rename osu.Game/Screens/Play/HUD/{KPSCounter => KeysPerSecond}/KeysPerSecondCalculator.cs (98%) rename osu.Game/Screens/Play/HUD/{KPSCounter => KeysPerSecond}/KeysPerSecondCounter.cs (98%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs index edfba7f154..5c1ca18dbc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs @@ -19,7 +19,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD.KPSCounter; +using osu.Game.Screens.Play.HUD.KeysPerSecond; using osuTK; namespace osu.Game.Tests.Visual.Gameplay diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index b28e3355a4..443e4392cf 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -30,7 +30,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD.KPSCounter; +using osu.Game.Screens.Play.HUD.KeysPerSecond; using osuTK; namespace osu.Game.Rulesets.UI @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.UI /// Displays an interactive ruleset gameplay instance. /// /// The type of HitObject contained by this DrawableRuleset. - public abstract class DrawableRuleset : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter, ICanAttachKpsCalculator + public abstract class DrawableRuleset : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter where TObject : HitObject { public override event Action NewResult; @@ -341,7 +341,7 @@ namespace osu.Game.Rulesets.UI public void Attach(KeyCounterDisplay keyCounter) => (KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(keyCounter); - public void Attach(KeysPerSecondCalculator kps) => (KeyBindingInputManager as ICanAttachKpsCalculator)?.Attach(kps); + public void Attach(KeysPerSecondCalculator calculator) => (KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(calculator); /// /// Creates a key conversion input manager. An exception will be thrown if a valid is not returned. diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 23e64153eb..2e9986ada6 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -20,12 +20,12 @@ using osu.Game.Input.Bindings; using osu.Game.Input.Handlers; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD.KPSCounter; +using osu.Game.Screens.Play.HUD.KeysPerSecond; using static osu.Game.Input.Handlers.ReplayInputHandler; namespace osu.Game.Rulesets.UI { - public abstract class RulesetInputManager : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler, IHasRecordingHandler, ICanAttachKpsCalculator + public abstract class RulesetInputManager : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler, IHasRecordingHandler where T : struct { public readonly KeyBindingContainer KeyBindingContainer; @@ -187,15 +187,15 @@ namespace osu.Game.Rulesets.UI #endregion - #region KPS Counter Attachment + #region Keys per second Counter Attachment - public void Attach(KeysPerSecondCalculator kps) + public void Attach(KeysPerSecondCalculator calculator) { var listener = new ActionListener(); KeyBindingContainer.Add(listener); - kps.Listener = listener; + calculator.Listener = listener; } public class ActionListener : KeysPerSecondCalculator.InputListener, IKeyBindingHandler @@ -257,11 +257,7 @@ namespace osu.Game.Rulesets.UI public interface ICanAttachKeyCounter { void Attach(KeyCounterDisplay keyCounter); - } - - public interface ICanAttachKpsCalculator - { - void Attach(KeysPerSecondCalculator keysPerSecondCalculator); + void Attach(KeysPerSecondCalculator calculator); } public class RulesetInputManagerInputState : InputState diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCalculator.cs similarity index 98% rename from osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs rename to osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCalculator.cs index dddef9abaf..ecc9c6ef86 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCalculator.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Timing; using osu.Game.Rulesets.UI; -namespace osu.Game.Screens.Play.HUD.KPSCounter +namespace osu.Game.Screens.Play.HUD.KeysPerSecond { public class KeysPerSecondCalculator : Component { diff --git a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs similarity index 98% rename from osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs rename to osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs index 47ebede623..6589dbb719 100644 --- a/osu.Game/Screens/Play/HUD/KPSCounter/KeysPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs @@ -10,11 +10,11 @@ using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -// using osu.Game.Rulesets.UI; using osu.Game.Skinning; using osuTK; +// using osu.Game.Rulesets.UI; -namespace osu.Game.Screens.Play.HUD.KPSCounter +namespace osu.Game.Screens.Play.HUD.KeysPerSecond { public class KeysPerSecondCounter : RollingCounter, ISkinnableDrawable { diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 1c28e04950..20a1a27f3d 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -22,7 +22,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Play.HUD.KPSCounter; +using osu.Game.Screens.Play.HUD.KeysPerSecond; using osu.Game.Skinning; using osuTK; @@ -127,7 +127,6 @@ namespace osu.Game.Screens.Play HoldToQuit = CreateHoldForMenuButton(), } }, - keysPerSecondCalculator = new KeysPerSecondCalculator() }; } @@ -265,7 +264,7 @@ namespace osu.Game.Screens.Play protected virtual void BindDrawableRuleset(DrawableRuleset drawableRuleset) { (drawableRuleset as ICanAttachKeyCounter)?.Attach(KeyCounter); - (drawableRuleset as ICanAttachKpsCalculator)?.Attach(keysPerSecondCalculator); + (drawableRuleset as ICanAttachKeyCounter)?.Attach(keysPerSecondCalculator); replayLoaded.BindTo(drawableRuleset.HasReplayLoaded); } From 787dee249da553736e006485582a8eaddcf54ef5 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 11 Aug 2022 10:37:06 +0200 Subject: [PATCH 0425/2686] Move `KeysPerSecondCalculator` instantiation from `HUDOverlay` to `Player` This prevents messing with *future* Skin (de)serialization --- osu.Game/Screens/Play/HUDOverlay.cs | 7 ++++--- osu.Game/Screens/Play/Player.cs | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 20a1a27f3d..1cddbcac41 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -50,8 +50,7 @@ namespace osu.Game.Screens.Play public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; - [Cached] - private readonly KeysPerSecondCalculator keysPerSecondCalculator; + private KeysPerSecondCalculator keysPerSecondCalculator; public Bindable ShowHealthBar = new Bindable(true); @@ -131,8 +130,10 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader(true)] - private void load(OsuConfigManager config, INotificationOverlay notificationOverlay) + private void load(OsuConfigManager config, INotificationOverlay notificationOverlay, KeysPerSecondCalculator calculator) { + keysPerSecondCalculator = calculator; + if (drawableRuleset != null) { BindDrawableRuleset(drawableRuleset); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e3844088e2..ba7e01a803 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -34,6 +34,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; +using osu.Game.Screens.Play.HUD.KeysPerSecond; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Users; @@ -122,6 +123,8 @@ namespace osu.Game.Screens.Play private SkipOverlay skipIntroOverlay; private SkipOverlay skipOutroOverlay; + protected KeysPerSecondCalculator KeysPerSecondCalculator { get; private set; } + protected ScoreProcessor ScoreProcessor { get; private set; } protected HealthProcessor HealthProcessor { get; private set; } @@ -226,6 +229,9 @@ namespace osu.Game.Screens.Play dependencies.CacheAs(ScoreProcessor); + KeysPerSecondCalculator = new KeysPerSecondCalculator(); + dependencies.CacheAs(KeysPerSecondCalculator); + HealthProcessor = ruleset.CreateHealthProcessor(playableBeatmap.HitObjects[0].StartTime); HealthProcessor.ApplyBeatmap(playableBeatmap); @@ -442,6 +448,7 @@ namespace osu.Game.Screens.Play OnRetry = Restart, OnQuit = () => PerformExit(true), }, + KeysPerSecondCalculator }, }; From d29cba80e9705a2a28c4dff23c0dd55312923654 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 11 Aug 2022 11:01:16 +0200 Subject: [PATCH 0426/2686] Remove useless comment in `KeysPerSecondCounter` --- osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs index 6589dbb719..7bd4d41242 100644 --- a/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs @@ -12,7 +12,6 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Skinning; using osuTK; -// using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Play.HUD.KeysPerSecond { From 9b252b1d81ce40307324e2a3197433dd874d464c Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 11 Aug 2022 11:58:30 +0200 Subject: [PATCH 0427/2686] Make `KeysPerSecondCalculator` dependency in `HUDOverlay` nullable --- osu.Game/Rulesets/UI/RulesetInputManager.cs | 2 ++ osu.Game/Screens/Play/HUDOverlay.cs | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 2e9986ada6..590a305f77 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -191,6 +191,8 @@ namespace osu.Game.Rulesets.UI public void Attach(KeysPerSecondCalculator calculator) { + if (calculator == null) return; + var listener = new ActionListener(); KeyBindingContainer.Add(listener); diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 1cddbcac41..458e19826b 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -50,7 +50,8 @@ namespace osu.Game.Screens.Play public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; - private KeysPerSecondCalculator keysPerSecondCalculator; + [Resolved(canBeNull: true)] + private KeysPerSecondCalculator keysPerSecondCalculator { get; set; } public Bindable ShowHealthBar = new Bindable(true); @@ -130,10 +131,8 @@ namespace osu.Game.Screens.Play } [BackgroundDependencyLoader(true)] - private void load(OsuConfigManager config, INotificationOverlay notificationOverlay, KeysPerSecondCalculator calculator) + private void load(OsuConfigManager config, INotificationOverlay notificationOverlay) { - keysPerSecondCalculator = calculator; - if (drawableRuleset != null) { BindDrawableRuleset(drawableRuleset); From 9f28c4c033264d8b7a8701c5b326a73abf65125b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 11 Aug 2022 19:47:32 +0900 Subject: [PATCH 0428/2686] Adjust test values --- .../OsuDifficultyCalculatorTest.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs index 46f7c461f8..7e995f2dde 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs @@ -17,18 +17,18 @@ namespace osu.Game.Rulesets.Osu.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Osu"; - [TestCase(6.6369583000323935d, 206, "diffcalc-test")] - [TestCase(1.4476531024675374d, 45, "zero-length-sliders")] + [TestCase(6.7115569159190587d, 206, "diffcalc-test")] + [TestCase(1.4391311903612753d, 45, "zero-length-sliders")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(8.8816128335486386d, 206, "diffcalc-test")] - [TestCase(1.7540389962596916d, 45, "zero-length-sliders")] + [TestCase(8.9757300665532966d, 206, "diffcalc-test")] + [TestCase(1.7437232654020756d, 45, "zero-length-sliders")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new OsuModDoubleTime()); - [TestCase(6.6369583000323935d, 239, "diffcalc-test")] - [TestCase(1.4476531024675374d, 54, "zero-length-sliders")] + [TestCase(6.7115569159190587d, 239, "diffcalc-test")] + [TestCase(1.4391311903612753d, 54, "zero-length-sliders")] public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic()); From d88f247594374bb74be92bc9ac1c1eaba7569280 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 11 Aug 2022 20:38:08 +0900 Subject: [PATCH 0429/2686] Fix possible null reference inspection --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 8a358e24d0..ded5b978ba 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Input.Bindings private InputManager? parentInputManager; - public GlobalActionContainer(OsuGameBase game) + public GlobalActionContainer(OsuGameBase? game) : base(matchingMode: KeyCombinationMatchingMode.Modifiers) { if (game is IKeyBindingHandler) From 3525dfb0f15242880092fde6ddc361b7e40b6c1d Mon Sep 17 00:00:00 2001 From: OliBomby Date: Fri, 12 Aug 2022 01:17:33 +0200 Subject: [PATCH 0430/2686] added merging feature --- .../Edit/OsuSelectionHandler.cs | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 4a6d94f303..f9d4fbfc72 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -6,13 +6,16 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Utils; using osu.Game.Extensions; +using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components; using osuTK; @@ -23,6 +26,12 @@ namespace osu.Game.Rulesets.Osu.Edit [Resolved(CanBeNull = true)] private IDistanceSnapProvider? snapProvider { get; set; } + [Resolved(CanBeNull = true)] + private EditorBeatmap? editorBeatmap { get; set; } + + [Resolved(CanBeNull = true)] + private IEditorChangeHandler? changeHandler { get; set; } + /// /// During a transform, the initial origin is stored so it can be used throughout the operation. /// @@ -322,5 +331,105 @@ namespace osu.Game.Rulesets.Osu.Edit private OsuHitObject[] selectedMovableObjects => SelectedItems.OfType() .Where(h => !(h is Spinner)) .ToArray(); + + /// + /// All osu! hitobjects which can be merged. + /// + private OsuHitObject[] selectedMergeableObjects => SelectedItems.OfType() + .Where(h => h is HitCircle or Slider) + .OrderBy(h => h.StartTime) + .ToArray(); + + private void mergeSelection() + { + if (editorBeatmap == null || changeHandler == null || selectedMergeableObjects.Length < 2) + return; + + changeHandler.BeginChange(); + + // Have an initial slider object. + var firstHitObject = selectedMergeableObjects[0]; + var mergedHitObject = firstHitObject as Slider ?? new Slider + { + StartTime = firstHitObject.StartTime, + Position = firstHitObject.Position, + NewCombo = firstHitObject.NewCombo, + SampleControlPoint = firstHitObject.SampleControlPoint, + }; + + if (mergedHitObject.Path.ControlPoints.Count == 0) + { + mergedHitObject.Path.ControlPoints.Add(new PathControlPoint(Vector2.Zero, PathType.Linear)); + } + + // Merge all the selected hit objects into one slider path. + bool lastCircle = firstHitObject is HitCircle; + + foreach (var selectedMergeableObject in selectedMergeableObjects.Skip(1)) + { + if (selectedMergeableObject is IHasPath hasPath) + { + var offset = lastCircle ? selectedMergeableObject.Position - mergedHitObject.Position : mergedHitObject.Path.ControlPoints[^1].Position; + float distanceToLastControlPoint = Vector2.Distance(mergedHitObject.Path.ControlPoints[^1].Position, offset); + + // Calculate the distance required to travel to the expected distance of the merging slider. + mergedHitObject.Path.ExpectedDistance.Value = mergedHitObject.Path.CalculatedDistance + distanceToLastControlPoint + hasPath.Path.Distance; + + // Remove the last control point if it sits exactly on the start of the next control point. + if (Precision.AlmostEquals(distanceToLastControlPoint, 0)) + { + mergedHitObject.Path.ControlPoints.RemoveAt(mergedHitObject.Path.ControlPoints.Count - 1); + } + + mergedHitObject.Path.ControlPoints.AddRange(hasPath.Path.ControlPoints.Select(o => new PathControlPoint(o.Position + offset, o.Type))); + lastCircle = false; + } + else + { + // Turn the last control point into a linear type if this is the first merging circle in a sequence, so the subsequent control points can be inherited path type. + if (!lastCircle) + { + mergedHitObject.Path.ControlPoints.Last().Type = PathType.Linear; + } + + mergedHitObject.Path.ControlPoints.Add(new PathControlPoint(selectedMergeableObject.Position - mergedHitObject.Position)); + mergedHitObject.Path.ExpectedDistance.Value = null; + lastCircle = true; + } + } + + // Make sure only the merged hit object is in the beatmap. + if (firstHitObject is Slider) + { + foreach (var selectedMergeableObject in selectedMergeableObjects.Skip(1)) + { + editorBeatmap.Remove(selectedMergeableObject); + } + } + else + { + foreach (var selectedMergeableObject in selectedMergeableObjects) + { + editorBeatmap.Remove(selectedMergeableObject); + } + + editorBeatmap.Add(mergedHitObject); + } + + // Make sure the merged hitobject is selected. + SelectedItems.Clear(); + SelectedItems.Add(mergedHitObject); + + changeHandler.EndChange(); + } + + protected override IEnumerable GetContextMenuItemsForSelection(IEnumerable> selection) + { + foreach (var item in base.GetContextMenuItemsForSelection(selection)) + yield return item; + + if (selection.Count() > 1 && selection.All(o => o.Item is HitCircle or Slider)) + yield return new OsuMenuItem("Merge selection", MenuItemType.Destructive, mergeSelection); + } } } From 037f56077bdbcc993e46f23fd682e43fc2f86941 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Fri, 12 Aug 2022 13:29:04 +1000 Subject: [PATCH 0431/2686] Apply Flashlight grid nerf --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 12 ++++++++++++ .../Difficulty/Skills/Flashlight.cs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index fcf4179a3b..f1ae68ec73 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -18,11 +18,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators private const double min_velocity = 0.5; private const double slider_multiplier = 1.3; + private const double min_grid_multiplier = 0.35; + /// /// Evaluates the difficulty of memorising and hitting an object, based on: /// /// distance between a number of previous objects and the current object, /// the visual opacity of the current object, + /// the angle made by the current object, /// length and speed of the current object (for sliders), /// and whether the hidden mod is enabled. /// @@ -77,6 +80,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (hidden) result *= 1.0 + hidden_bonus; + // Nerf patterns with angles that are commonly used in grid maps. + // 0 deg, 60 deg, 120 deg and 180 deg are commonly used in hexgrid maps. + // 0 deg, 45 deg, 90 deg, 135 deg and 180 deg are commonly used in squaregrid maps. + if (osuCurrent.Angle != null) { + double hexgrid_multiplier = 1.0 - Math.Pow(Math.Cos((180 / 60.0) * (double)(osuCurrent.Angle)), 20.0); + double squaregrid_multiplier = 1.0 - Math.Pow(Math.Cos((180 / 45.0) * (double)(osuCurrent.Angle)), 20.0); + result *= (1.0 - min_grid_multiplier) * hexgrid_multiplier * squaregrid_multiplier + min_grid_multiplier; + } + double sliderBonus = 0.0; if (osuCurrent.BaseObject is Slider osuSlider) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 84ef109598..03130031ea 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills hasHiddenMod = mods.Any(m => m is OsuModHidden); } - private double skillMultiplier => 0.05; + private double skillMultiplier => 0.06; private double strainDecayBase => 0.15; private double currentStrain; From ac4213ecee5c2d2e22c8b7b0d0fbec1cc295443d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Aug 2022 12:30:11 +0900 Subject: [PATCH 0432/2686] Adjust relax mod multiplayer to 0.5x Has previously been discussed internally. Probably good to get this out before the next full reprocess of scores server-side. The multiplier here was @smoogipoo's suggested value. I'd be willing to go lower if this is seen at too high, but it should be a round number to make it easy for users to understand the max score available to them. --- osu.Game/Rulesets/Mods/ModRelax.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModRelax.cs b/osu.Game/Rulesets/Mods/ModRelax.cs index e5995ff180..a79c69b416 100644 --- a/osu.Game/Rulesets/Mods/ModRelax.cs +++ b/osu.Game/Rulesets/Mods/ModRelax.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "RX"; public override IconUsage? Icon => OsuIcon.ModRelax; public override ModType Type => ModType.Automation; - public override double ScoreMultiplier => 1; + public override double ScoreMultiplier => 0.5; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModNoFail), typeof(ModFailCondition) }; } } From f70588a423b50c20030ab621ad6dd2d549ad935b Mon Sep 17 00:00:00 2001 From: MBmasher Date: Fri, 12 Aug 2022 14:08:32 +1000 Subject: [PATCH 0433/2686] Add newline before brace --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index f1ae68ec73..29434dcf49 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -83,7 +83,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // Nerf patterns with angles that are commonly used in grid maps. // 0 deg, 60 deg, 120 deg and 180 deg are commonly used in hexgrid maps. // 0 deg, 45 deg, 90 deg, 135 deg and 180 deg are commonly used in squaregrid maps. - if (osuCurrent.Angle != null) { + if (osuCurrent.Angle != null) + { double hexgrid_multiplier = 1.0 - Math.Pow(Math.Cos((180 / 60.0) * (double)(osuCurrent.Angle)), 20.0); double squaregrid_multiplier = 1.0 - Math.Pow(Math.Cos((180 / 45.0) * (double)(osuCurrent.Angle)), 20.0); result *= (1.0 - min_grid_multiplier) * hexgrid_multiplier * squaregrid_multiplier + min_grid_multiplier; From 21c5fed45f48830d24ec448840b22f4b38e7504e Mon Sep 17 00:00:00 2001 From: MBmasher Date: Fri, 12 Aug 2022 14:09:16 +1000 Subject: [PATCH 0434/2686] Adjust capitalisation --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 29434dcf49..9d2696c978 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -85,9 +85,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // 0 deg, 45 deg, 90 deg, 135 deg and 180 deg are commonly used in squaregrid maps. if (osuCurrent.Angle != null) { - double hexgrid_multiplier = 1.0 - Math.Pow(Math.Cos((180 / 60.0) * (double)(osuCurrent.Angle)), 20.0); - double squaregrid_multiplier = 1.0 - Math.Pow(Math.Cos((180 / 45.0) * (double)(osuCurrent.Angle)), 20.0); - result *= (1.0 - min_grid_multiplier) * hexgrid_multiplier * squaregrid_multiplier + min_grid_multiplier; + double hexgridMultiplier = 1.0 - Math.Pow(Math.Cos((180 / 60.0) * (double)(osuCurrent.Angle)), 20.0); + double squaregridMultiplier = 1.0 - Math.Pow(Math.Cos((180 / 45.0) * (double)(osuCurrent.Angle)), 20.0); + result *= (1.0 - min_grid_multiplier) * hexgridMultiplier * squaregridMultiplier + min_grid_multiplier; } double sliderBonus = 0.0; From 38afc53bad96157459e66ee0920b8120e6bf375d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Aug 2022 13:40:29 +0900 Subject: [PATCH 0435/2686] Update interactive visual test runs to use development directory --- osu.Game/Tests/VisualTestRunner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/VisualTestRunner.cs b/osu.Game/Tests/VisualTestRunner.cs index bd98482768..c8279b9e3c 100644 --- a/osu.Game/Tests/VisualTestRunner.cs +++ b/osu.Game/Tests/VisualTestRunner.cs @@ -14,7 +14,7 @@ namespace osu.Game.Tests [STAThread] public static int Main(string[] args) { - using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true, })) + using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu-development", new HostOptions { BindIPC = true, })) { host.Run(new OsuTestBrowser()); return 0; From 5111bad86ce647bc34c2873b7d9407a73323a477 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Aug 2022 14:15:12 +0900 Subject: [PATCH 0436/2686] Refactor `TestScenePlaylistOverlay` to use realm for testing Removes the dual-purpose flow which existed only for testing. --- .../UserInterface/TestScenePlaylistOverlay.cs | 48 ++++++++++++------- osu.Game/Overlays/Music/PlaylistOverlay.cs | 6 +-- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index ee5ef2f364..652afa80be 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -1,18 +1,20 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using osu.Framework.Bindables; +using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Collections; using osu.Game.Database; -using osu.Game.Graphics.Containers; using osu.Game.Overlays.Music; +using osu.Game.Rulesets; using osu.Game.Tests.Resources; using osuTK; using osuTK.Input; @@ -21,13 +23,27 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestScenePlaylistOverlay : OsuManualInputManagerTestScene { - private readonly BindableList> beatmapSets = new BindableList>(); + protected override bool UseFreshStoragePerRun => true; - private PlaylistOverlay playlistOverlay; + private PlaylistOverlay playlistOverlay = null!; - private Live first; + private Live first = null!; - private const int item_count = 100; + private BeatmapManager beatmapManager = null!; + + private const int item_count = 20; + + private List beatmapSets => beatmapManager.GetAllUsableBeatmapSets(); + + [BackgroundDependencyLoader] + private void load(GameHost host) + { + Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, Audio, Resources, host, Beatmap.Default)); + Dependencies.Cache(Realm); + + beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely(); + } [SetUp] public void Setup() => Schedule(() => @@ -46,16 +62,12 @@ namespace osu.Game.Tests.Visual.UserInterface } }; - beatmapSets.Clear(); - for (int i = 0; i < item_count; i++) { - beatmapSets.Add(TestResources.CreateTestBeatmapSetInfo().ToLiveUnmanaged()); + beatmapManager.Import(TestResources.CreateTestBeatmapSetInfo()); } - first = beatmapSets.First(); - - playlistOverlay.BeatmapSets.BindTo(beatmapSets); + first = beatmapSets.First().ToLive(Realm); }); [Test] @@ -70,9 +82,13 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait for animations to complete", () => !playlistOverlay.Transforms.Any()); + PlaylistItem firstItem = null!; + AddStep("hold 1st item handle", () => { - var handle = this.ChildrenOfType>.PlaylistItemHandle>().First(); + firstItem = this.ChildrenOfType().First(); + var handle = firstItem.ChildrenOfType().First(); + InputManager.MoveMouseTo(handle.ScreenSpaceDrawQuad.Centre); InputManager.PressButton(MouseButton.Left); }); @@ -83,7 +99,7 @@ namespace osu.Game.Tests.Visual.UserInterface InputManager.MoveMouseTo(item.ScreenSpaceDrawQuad.BottomLeft); }); - AddAssert("song 1 is 5th", () => beatmapSets[4].Equals(first)); + AddAssert("first is moved", () => playlistOverlay.ChildrenOfType().Single().Items.ElementAt(4).Value.Equals(firstItem.Model.Value)); AddStep("release handle", () => InputManager.ReleaseButton(MouseButton.Left)); } diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index e33fc8064f..9fe2fd5279 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -26,8 +26,6 @@ namespace osu.Game.Overlays.Music private const float transition_duration = 600; private const float playlist_height = 510; - public IBindableList> BeatmapSets => beatmapSets; - private readonly BindableList> beatmapSets = new BindableList>(); private readonly Bindable beatmap = new Bindable(); @@ -104,9 +102,7 @@ namespace osu.Game.Overlays.Music { base.LoadComplete(); - // tests might bind externally, in which case we don't want to involve realm. - if (beatmapSets.Count == 0) - beatmapSubscription = realm.RegisterForNotifications(r => r.All().Where(s => !s.DeletePending), beatmapsChanged); + beatmapSubscription = realm.RegisterForNotifications(r => r.All().Where(s => !s.DeletePending), beatmapsChanged); list.Items.BindTo(beatmapSets); beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo.ToLive(realm), true); From a90967715cdaa1b8b9830f37ef3c8681999cf64b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Aug 2022 14:44:19 +0900 Subject: [PATCH 0437/2686] Add test coverage of new imports not correctly being filtered by collection filter --- osu.Game.Tests/Resources/TestResources.cs | 5 +- .../UserInterface/TestScenePlaylistOverlay.cs | 66 ++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index ee29cc8644..6bce03869d 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -128,6 +128,8 @@ namespace osu.Game.Tests.Resources var rulesetInfo = getRuleset(); + string hash = Guid.NewGuid().ToString().ComputeMD5Hash(); + yield return new BeatmapInfo { OnlineID = beatmapId, @@ -136,7 +138,8 @@ namespace osu.Game.Tests.Resources Length = length, BeatmapSet = beatmapSet, BPM = bpm, - Hash = Guid.NewGuid().ToString().ComputeMD5Hash(), + Hash = hash, + MD5Hash = hash, Ruleset = rulesetInfo, Metadata = metadata.DeepClone(), Difficulty = new BeatmapDifficulty diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index 652afa80be..e67eebf721 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -27,8 +27,6 @@ namespace osu.Game.Tests.Visual.UserInterface private PlaylistOverlay playlistOverlay = null!; - private Live first = null!; - private BeatmapManager beatmapManager = null!; private const int item_count = 20; @@ -67,7 +65,7 @@ namespace osu.Game.Tests.Visual.UserInterface beatmapManager.Import(TestResources.CreateTestBeatmapSetInfo()); } - first = beatmapSets.First().ToLive(Realm); + beatmapSets.First().ToLive(Realm); }); [Test] @@ -117,6 +115,68 @@ namespace osu.Game.Tests.Visual.UserInterface () => playlistOverlay.ChildrenOfType() .Where(item => item.MatchingFilter) .All(item => item.FilterTerms.Any(term => term.ToString().Contains("10")))); + + AddStep("Import new non-matching beatmap", () => + { + var testBeatmapSetInfo = TestResources.CreateTestBeatmapSetInfo(1); + testBeatmapSetInfo.Beatmaps.Single().Metadata.Title = "no guid"; + beatmapManager.Import(testBeatmapSetInfo); + }); + + AddStep("Force realm refresh", () => Realm.Run(r => r.Refresh())); + + AddAssert("results filtered correctly", + () => playlistOverlay.ChildrenOfType() + .Where(item => item.MatchingFilter) + .All(item => item.FilterTerms.Any(term => term.ToString().Contains("10")))); + } + + [Test] + public void TestCollectionFiltering() + { + NowPlayingCollectionDropdown collectionDropdown() => playlistOverlay.ChildrenOfType().Single(); + + AddStep("Add collection", () => + { + Dependencies.Get().Write(r => + { + r.RemoveAll(); + r.Add(new BeatmapCollection("wang")); + }); + }); + + AddUntilStep("wait for dropdown to have new collection", () => collectionDropdown().Items.Count() == 2); + + AddStep("Filter to collection", () => + { + collectionDropdown().Current.Value = collectionDropdown().Items.Last(); + }); + + AddUntilStep("No items present", () => !playlistOverlay.ChildrenOfType().Any(i => i.MatchingFilter)); + + AddStep("Import new non-matching beatmap", () => + { + beatmapManager.Import(TestResources.CreateTestBeatmapSetInfo(1)); + }); + + AddStep("Force realm refresh", () => Realm.Run(r => r.Refresh())); + + AddUntilStep("No items matching", () => !playlistOverlay.ChildrenOfType().Any(i => i.MatchingFilter)); + + BeatmapSetInfo collectionAddedBeatmapSet = null!; + + AddStep("Import new matching beatmap", () => + { + collectionAddedBeatmapSet = TestResources.CreateTestBeatmapSetInfo(1); + + beatmapManager.Import(collectionAddedBeatmapSet); + Realm.Write(r => r.All().First().BeatmapMD5Hashes.Add(collectionAddedBeatmapSet.Beatmaps.First().MD5Hash)); + }); + + AddStep("Force realm refresh", () => Realm.Run(r => r.Refresh())); + + AddUntilStep("Only matching item", + () => playlistOverlay.ChildrenOfType().Where(i => i.MatchingFilter).Select(i => i.Model.ID), () => Is.EquivalentTo(new[] { collectionAddedBeatmapSet.ID })); } } } From b76e5757e17100c171df813235dc43d104e52c04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Aug 2022 14:44:05 +0900 Subject: [PATCH 0438/2686] Fix `InSelectedCollection` not being applied to newly imported beatmaps --- osu.Game/Overlays/Music/Playlist.cs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Music/Playlist.cs b/osu.Game/Overlays/Music/Playlist.cs index 2bb0ff1085..15fc54a337 100644 --- a/osu.Game/Overlays/Music/Playlist.cs +++ b/osu.Game/Overlays/Music/Playlist.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. -#nullable disable - using System; using System.Linq; using osu.Framework.Bindables; @@ -17,10 +15,12 @@ namespace osu.Game.Overlays.Music { public class Playlist : OsuRearrangeableListContainer> { - public Action> RequestSelection; + public Action>? RequestSelection; public readonly Bindable> SelectedSet = new Bindable>(); + private FilterCriteria currentCriteria = new FilterCriteria(); + public new MarginPadding Padding { get => base.Padding; @@ -31,26 +31,22 @@ namespace osu.Game.Overlays.Music { var items = (SearchContainer>>)ListContainer; - string[] currentCollectionHashes = criteria.Collection?.PerformRead(c => c.BeatmapMD5Hashes.ToArray()); + string[]? currentCollectionHashes = criteria.Collection?.PerformRead(c => c.BeatmapMD5Hashes.ToArray()); foreach (var item in items.OfType()) { - if (currentCollectionHashes == null) - item.InSelectedCollection = true; - else - { - item.InSelectedCollection = item.Model.Value.Beatmaps.Select(b => b.MD5Hash) - .Any(currentCollectionHashes.Contains); - } + item.InSelectedCollection = currentCollectionHashes == null || item.Model.Value.Beatmaps.Select(b => b.MD5Hash).Any(currentCollectionHashes.Contains); } items.SearchTerm = criteria.SearchText; + currentCriteria = criteria; } - public Live FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); + public Live? FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); protected override OsuRearrangeableListItem> CreateOsuDrawable(Live item) => new PlaylistItem(item) { + InSelectedCollection = currentCriteria.Collection?.PerformRead(c => item.Value.Beatmaps.Select(b => b.MD5Hash).Any(c.BeatmapMD5Hashes.Contains)) != false, SelectedSet = { BindTarget = SelectedSet }, RequestSelection = set => RequestSelection?.Invoke(set) }; From e5e9841652c84ac5ab688d6c1137f83349b56a85 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 12 Aug 2022 15:25:35 +0900 Subject: [PATCH 0439/2686] Apply multiple other mod debuffs as decided in pull request discussion --- osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs | 2 +- osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs | 2 +- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 2 +- osu.Game/Rulesets/Mods/ModRelax.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs index 614ef76a3b..73dfaaa878 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModConstantSpeed.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Mods public override string Acronym => "CS"; - public override double ScoreMultiplier => 1; + public override double ScoreMultiplier => 0.9; public override string Description => "No more tricky speed changes!"; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index 872fcf7e9b..9229c0393d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override IconUsage? Icon => OsuIcon.ModAutopilot; public override ModType Type => ModType.Automation; public override string Description => @"Automatic cursor movement - just follow the rhythm."; - public override double ScoreMultiplier => 1; + public override double ScoreMultiplier => 0.1; public override Type[] IncompatibleMods => new[] { typeof(OsuModSpunOut), typeof(ModRelax), typeof(ModFailCondition), typeof(ModNoFail), typeof(ModAutoplay), typeof(OsuModMagnetised), typeof(OsuModRepel) }; public bool PerformFail() => false; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs index 9316f9ed74..7f7d6f70d2 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override IconUsage? Icon => FontAwesome.Solid.Magnet; public override ModType Type => ModType.Fun; public override string Description => "No need to chase the circles – your cursor is a magnet!"; - public override double ScoreMultiplier => 1; + public override double ScoreMultiplier => 0.5; public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel) }; private IFrameStableClock gameplayClock = null!; diff --git a/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs b/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs index 38d26ed05a..7b84db844b 100644 --- a/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs +++ b/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mods public override ModType Type => ModType.Fun; - public override double ScoreMultiplier => 1; + public override double ScoreMultiplier => 0.5; public override bool ValidForMultiplayer => false; public override bool ValidForMultiplayerAsFreeMod => false; diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index eefa1531c4..62a257608a 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mods public override IconUsage? Icon => FontAwesome.Solid.Hammer; - public override double ScoreMultiplier => 1.0; + public sealed override double ScoreMultiplier => 0.5; public override bool RequiresConfiguration => true; diff --git a/osu.Game/Rulesets/Mods/ModRelax.cs b/osu.Game/Rulesets/Mods/ModRelax.cs index a79c69b416..e1506e3a12 100644 --- a/osu.Game/Rulesets/Mods/ModRelax.cs +++ b/osu.Game/Rulesets/Mods/ModRelax.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "RX"; public override IconUsage? Icon => OsuIcon.ModRelax; public override ModType Type => ModType.Automation; - public override double ScoreMultiplier => 0.5; + public sealed override double ScoreMultiplier => 0.1; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModNoFail), typeof(ModFailCondition) }; } } From 9d1b0b5836395db80779f25e3b184904857641d0 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 12 Aug 2022 22:32:27 +0900 Subject: [PATCH 0440/2686] Revert sealing --- osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs | 2 +- osu.Game/Rulesets/Mods/ModRelax.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs index 62a257608a..b7435ec3ec 100644 --- a/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs +++ b/osu.Game/Rulesets/Mods/ModDifficultyAdjust.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mods public override IconUsage? Icon => FontAwesome.Solid.Hammer; - public sealed override double ScoreMultiplier => 0.5; + public override double ScoreMultiplier => 0.5; public override bool RequiresConfiguration => true; diff --git a/osu.Game/Rulesets/Mods/ModRelax.cs b/osu.Game/Rulesets/Mods/ModRelax.cs index e1506e3a12..49c10339ee 100644 --- a/osu.Game/Rulesets/Mods/ModRelax.cs +++ b/osu.Game/Rulesets/Mods/ModRelax.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "RX"; public override IconUsage? Icon => OsuIcon.ModRelax; public override ModType Type => ModType.Automation; - public sealed override double ScoreMultiplier => 0.1; + public override double ScoreMultiplier => 0.1; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModNoFail), typeof(ModFailCondition) }; } } From 78fe72476de7ea3b591596480059741182259b45 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sat, 13 Aug 2022 00:01:40 +0200 Subject: [PATCH 0441/2686] Adjust parameters --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 716fa990c9..3c0642ca15 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -46,9 +46,9 @@ namespace osu.Game.Rulesets.Osu.Mods if (i == 0 || (positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo && rng.NextDouble() < 0.6) || OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject, true) || - (OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject) && rng.NextDouble() < 0.3)) + (OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject) && rng.NextDouble() < 0.4)) { - sequenceOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.0012f); + sequenceOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.001f); flowDirection = !flowDirection; } From 8c624d3269902ea8f83e874fbfebd204c97b8206 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sat, 13 Aug 2022 00:57:49 +0200 Subject: [PATCH 0442/2686] Add comments and improve code readability --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 62 +++++++++++++++++----- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 3c0642ca15..0a89f3eb43 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Linq; using osu.Framework.Utils; using osu.Game.Beatmaps; @@ -29,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToBeatmap(IBeatmap beatmap) { - if (!(beatmap is OsuBeatmap osuBeatmap)) + if (beatmap is not OsuBeatmap osuBeatmap) return; Seed.Value ??= RNG.Next(); @@ -38,17 +39,17 @@ namespace osu.Game.Rulesets.Osu.Mods var positionInfos = OsuHitObjectGenerationUtils.GeneratePositionInfos(osuBeatmap.HitObjects); - float sequenceOffset = 0; + // Offsets the angles of all hit objects in a "section" by the same amount. + float sectionOffset = 0; + + // Whether the angles are positive or negative (clockwise or counter-clockwise flow). bool flowDirection = false; for (int i = 0; i < positionInfos.Count; i++) { - if (i == 0 || - (positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo && rng.NextDouble() < 0.6) || - OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject, true) || - (OsuHitObjectGenerationUtils.IsHitObjectOnBeat(osuBeatmap, positionInfos[i - 1].HitObject) && rng.NextDouble() < 0.4)) + if (shouldStartNewSection(osuBeatmap, positionInfos, i, 0.6f, 0.4f)) { - sequenceOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.001f); + sectionOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.001f); flowDirection = !flowDirection; } @@ -59,21 +60,25 @@ namespace osu.Game.Rulesets.Osu.Mods } else { + // Offsets only the angle of the current hit object if a flow change occurs. float flowChangeOffset = 0; + + // Offsets only the angle of the current hit object. float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.002f); - if (positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo && rng.NextDouble() < 0.6) + if (shouldApplyFlowChange(positionInfos, i, 0.6f)) { flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.002f); flowDirection = !flowDirection; } - positionInfos[i].RelativeAngle = getRelativeTargetAngle( - positionInfos[i].DistanceFromPrevious, - (sequenceOffset + oneTimeOffset) * positionInfos[i].DistanceFromPrevious + - flowChangeOffset * (playfield_diagonal - positionInfos[i].DistanceFromPrevious), - flowDirection - ); + float totalOffset = + // sectionOffset and oneTimeOffset should mainly affect patterns with large spacing. + (sectionOffset + oneTimeOffset) * positionInfos[i].DistanceFromPrevious + + // flowChangeOffset should mainly affect streams. + flowChangeOffset * (playfield_diagonal - positionInfos[i].DistanceFromPrevious); + + positionInfos[i].RelativeAngle = getRelativeTargetAngle(positionInfos[i].DistanceFromPrevious, totalOffset, flowDirection); } } @@ -89,5 +94,34 @@ namespace osu.Game.Rulesets.Osu.Mods float relativeAngle = (float)Math.PI - angle; return flowDirection ? -relativeAngle : relativeAngle; } + + /// + /// A new section should be started...
+ /// ...at the beginning of the .
+ /// ...on every combo start with a probability of (excluding new-combo-spam and 1-2-combos).
+ /// ...on every downbeat.
+ /// ...on every beat with a probability of .
+ ///
+ /// Whether a new section should be started at the current . + private bool shouldStartNewSection( + OsuBeatmap beatmap, + IReadOnlyList positionInfos, + int i, + float newComboProbability, + float beatProbability + ) => + i == 0 || + (positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo && rng?.NextDouble() < newComboProbability) || + OsuHitObjectGenerationUtils.IsHitObjectOnBeat(beatmap, positionInfos[i - 1].HitObject, true) || + (OsuHitObjectGenerationUtils.IsHitObjectOnBeat(beatmap, positionInfos[i - 1].HitObject) && rng?.NextDouble() < beatProbability); + + /// + /// A flow change should occur on every combo start with a probability of (excluding new-combo-spam and 1-2-combos). + /// + /// Whether a flow change should be applied at the current . + private bool shouldApplyFlowChange(IReadOnlyList positionInfos, int i, float probability) => + positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && + positionInfos[i - 1].HitObject.NewCombo && + rng?.NextDouble() < probability; } } From 7a41b9f25a35c375670103baad777e15ea231e59 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sat, 13 Aug 2022 03:11:58 +0200 Subject: [PATCH 0443/2686] Adjust angle and `sectionOffset` calculations --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 0a89f3eb43..2be1ad231a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Mods { if (shouldStartNewSection(osuBeatmap, positionInfos, i, 0.6f, 0.4f)) { - sectionOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.001f); + sectionOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.0008f); flowDirection = !flowDirection; } @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Mods /// Whether the relative angle should be positive or negative. private static float getRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) { - float angle = (float)(2.16 / (1 + 200 * Math.Exp(0.036 * (targetDistance - 320))) + 0.5 + offset); + float angle = (float)(2.16 / (1 + 200 * Math.Exp(0.036 * (targetDistance - 310))) + 0.5 + offset); float relativeAngle = (float)Math.PI - angle; return flowDirection ? -relativeAngle : relativeAngle; } From e08f71797ec89bbcf41be2689a6f9d939623d4ba Mon Sep 17 00:00:00 2001 From: Ryuki Date: Sat, 13 Aug 2022 04:27:26 +0200 Subject: [PATCH 0444/2686] Change displayed metric from "KPS" to "clicks/s" --- .../HUD/KeysPerSecond/KeysPerSecondCounter.cs | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs index 7bd4d41242..a5c122f5b1 100644 --- a/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs @@ -80,13 +80,30 @@ namespace osu.Game.Screens.Play.HUD.KeysPerSecond Origin = Anchor.BottomLeft, Font = OsuFont.Numeric.With(size: 16, fixedWidth: true) }, - new OsuSpriteText + new FillFlowContainer { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Font = OsuFont.Numeric.With(size: 8, fixedWidth: true), - Text = @"KPS", - Padding = new MarginPadding { Bottom = 1.5f }, // align baseline better + Direction = FillDirection.Vertical, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + Font = OsuFont.Numeric.With(size: 6, fixedWidth: false), + Text = @"clicks", + }, + new OsuSpriteText + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + Font = OsuFont.Numeric.With(size: 6, fixedWidth: false), + Text = @"/sec", + Padding = new MarginPadding { Bottom = 3f }, // align baseline better + } + } } } }; From fa2ebe1d5f8fde264e4253f16195fb73f9db0b35 Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 13 Aug 2022 18:02:29 +0800 Subject: [PATCH 0445/2686] add basic touch functionality --- osu.Game.Rulesets.Catch/CatchInputManager.cs | 2 ++ osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/osu.Game.Rulesets.Catch/CatchInputManager.cs b/osu.Game.Rulesets.Catch/CatchInputManager.cs index 86f35c8cee..5b62154a34 100644 --- a/osu.Game.Rulesets.Catch/CatchInputManager.cs +++ b/osu.Game.Rulesets.Catch/CatchInputManager.cs @@ -4,11 +4,13 @@ #nullable disable using System.ComponentModel; +using osu.Framework.Allocation; using osu.Framework.Input.Bindings; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Catch { + [Cached] public class CatchInputManager : RulesetInputManager { public CatchInputManager(RulesetInfo ruleset) diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index b6cea92173..83dc5770a6 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -4,6 +4,7 @@ #nullable disable using System.Collections.Generic; +using osu.Framework.Allocation; using osu.Framework.Input; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -32,6 +33,13 @@ namespace osu.Game.Rulesets.Catch.UI TimeRange.Value = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450); } + [BackgroundDependencyLoader] + private void load() + { + KeyBindingInputManager.Add(new TouchInputField()); + } + + protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay); protected override ReplayRecorder CreateReplayRecorder(Score score) => new CatchReplayRecorder(score, (CatchPlayfield)Playfield); From 757d236e14460ad5af6a1f3b7b901c713cd492d6 Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 13 Aug 2022 18:55:31 +0800 Subject: [PATCH 0446/2686] Add the UI file --- osu.Game.Rulesets.Catch/UI/TouchInputField.cs | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/UI/TouchInputField.cs diff --git a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs new file mode 100644 index 0000000000..1219ebd02d --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs @@ -0,0 +1,280 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using System.Diagnostics; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osuTK.Graphics; +using osuTK; +using System.Collections.Generic; + +namespace osu.Game.Rulesets.Catch.UI +{ + public class TouchInputField : VisibilityContainer + { + public enum TouchCatchAction + { + MoveLeft = 0, + MoveRight = 1, + DashLeft = 2, + DashRight = 3, + None = 4 + } + + private Dictionary trackedActions = new Dictionary(); + + private KeyBindingContainer keyBindingContainer = null!; + + private Container mainContent = null!; + + // Fill values with null because UI is not declared in constructor + private ArrowHitbox leftBox = null!; + private ArrowHitbox rightBox = null!; + private ArrowHitbox leftDashBox = null!; + private ArrowHitbox rightDashBox = null!; + + [BackgroundDependencyLoader] + private void load(CatchInputManager catchInputManager, OsuColour colours) + { + Show(); + Debug.Assert(catchInputManager.KeyBindingContainer != null); + + keyBindingContainer = catchInputManager.KeyBindingContainer; + + // Container should handle input everywhere. + RelativeSizeAxes = Axes.Both; + + + Children = new Drawable[] + { + mainContent = new Container + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Children = new Drawable[] + { + leftBox = new ArrowHitbox(TouchCatchAction.MoveLeft, ref trackedActions, colours.Blue) + { + Anchor = Anchor.TopLeft, + Origin = Anchor.CentreLeft, + X = 0, + RelativePositionAxes = Axes.Both, + Size = new Vector2(100.0f, 100.0f) + }, + rightBox = new ArrowHitbox(TouchCatchAction.MoveRight, ref trackedActions, colours.Blue) + { + Anchor = Anchor.TopRight, + Origin = Anchor.CentreRight, + X = 0, + RelativePositionAxes = Axes.Both, + Size = new Vector2(100.0f, 100.0f), + }, + leftDashBox = new ArrowHitbox(TouchCatchAction.DashLeft, ref trackedActions, colours.Pink) + { + Anchor = Anchor.TopLeft, + Origin = Anchor.CentreLeft, + X = 0.1f, + RelativePositionAxes = Axes.Both, + Size = new Vector2(100.0f, 100.0f), + }, + rightDashBox = new ArrowHitbox(TouchCatchAction.DashRight, ref trackedActions, colours.Pink) + { + Anchor = Anchor.TopRight, + Origin = Anchor.CentreRight, + X = -0.1f, + RelativePositionAxes = Axes.Both, + Size = new Vector2(100.0f, 100.0f), + }, + } + }, + }; + } + + protected override bool OnKeyDown(KeyDownEvent e) + { + // Hide whenever the keyboard is used. + Hide(); + return false; + } + + protected override bool OnMouseDown(MouseDownEvent e) + { + if (getTouchCatchActionFromInput(e.MousePosition) != TouchCatchAction.None) + return false; + + handleDown(e.Button, e.ScreenSpaceMousePosition); + return true; + } + + protected override void OnMouseUp(MouseUpEvent e) + { + if (getTouchCatchActionFromInput(e.MousePosition) != TouchCatchAction.None) + return; + + handleUp(e.Button); + base.OnMouseUp(e); + } + + protected override void OnTouchMove(TouchMoveEvent e) + { + // I'm not sure if this is posible but let's be safe + if (!trackedActions.ContainsKey(e.Touch.Source)) + trackedActions.Add(e.Touch.Source, TouchCatchAction.None); + + trackedActions[e.Touch.Source] = getTouchCatchActionFromInput(e.MousePosition); + + calculateActiveKeys(); + + base.OnTouchMove(e); + } + + protected override bool OnTouchDown(TouchDownEvent e) + { + handleDown(e.Touch.Source, e.ScreenSpaceTouchDownPosition); + return true; + } + + protected override void OnTouchUp(TouchUpEvent e) + { + handleUp(e.Touch.Source); + base.OnTouchUp(e); + } + + private CatchAction removeDashFromAction(TouchCatchAction touchCatchAction) + { + if (touchCatchAction == TouchCatchAction.DashLeft || touchCatchAction == TouchCatchAction.MoveLeft) + return CatchAction.MoveLeft; + return CatchAction.MoveRight; + } + + private void calculateActiveKeys() + { + if (trackedActions.ContainsValue(TouchCatchAction.DashLeft) || trackedActions.ContainsValue(TouchCatchAction.MoveLeft)) + keyBindingContainer.TriggerPressed(CatchAction.MoveLeft); + else + keyBindingContainer.TriggerReleased(CatchAction.MoveLeft); + + if (trackedActions.ContainsValue(TouchCatchAction.DashRight) || trackedActions.ContainsValue(TouchCatchAction.MoveRight)) + keyBindingContainer.TriggerPressed(CatchAction.MoveRight); + else + keyBindingContainer.TriggerReleased(CatchAction.MoveRight); + + if (trackedActions.ContainsValue(TouchCatchAction.DashRight) || trackedActions.ContainsValue(TouchCatchAction.DashLeft)) + keyBindingContainer.TriggerPressed(CatchAction.Dash); + else + keyBindingContainer.TriggerReleased(CatchAction.Dash); + } + + private void handleDown(object source, Vector2 position) + { + Show(); + + TouchCatchAction catchAction = getTouchCatchActionFromInput(position); + + // Not too sure how this can happen, but let's avoid throwing. + if (trackedActions.ContainsKey(source)) + return; + + trackedActions.Add(source, catchAction); + calculateActiveKeys(); + } + + private void handleUp(object source) + { + trackedActions.Remove(source); + + calculateActiveKeys(); + } + + private TouchCatchAction getTouchCatchActionFromInput(Vector2 inputPosition) + { + if (leftDashBox.Contains(inputPosition)) + return TouchCatchAction.DashLeft; + if (rightDashBox.Contains(inputPosition)) + return TouchCatchAction.DashRight; + if (leftBox.Contains(inputPosition)) + return TouchCatchAction.MoveLeft; + if (rightBox.Contains(inputPosition)) + return TouchCatchAction.MoveRight; + return TouchCatchAction.None; + } + + protected override void PopIn() + { + mainContent.FadeIn(500, Easing.OutQuint); + } + + protected override void PopOut() + { + mainContent.FadeOut(300); + } + + private class ArrowHitbox : CompositeDrawable, IKeyBindingHandler + { + private readonly TouchCatchAction handledAction; + + private readonly Box overlay; + + private readonly Dictionary trackedActions; + + private bool isHiglighted = false; + + public ArrowHitbox(TouchCatchAction handledAction, ref Dictionary trackedActions, Color4 colour) + { + this.handledAction = handledAction; + this.trackedActions = trackedActions; + + InternalChildren = new Drawable[] + { + new Container + { + Width = 1, + Height = 1, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + overlay = new Box + { + Alpha = 0, + Colour = colour.Multiply(1.4f).Darken(2.8f), + Blending = BlendingParameters.Additive, + Size = new Vector2(100.0f, 100.0f), + }, + new Box + { + Alpha = 0.5f, + Colour = colour, + Size = new Vector2(100.0f, 100.0f), + } + } + } + }; + } + + public bool OnPressed(KeyBindingPressEvent _) + { + if (trackedActions.ContainsValue(handledAction)) + { + isHiglighted = true; + overlay.FadeTo(0.5f, 80, Easing.OutQuint); + } + return false; + } + + public void OnReleased(KeyBindingReleaseEvent _) + { + if (isHiglighted && !trackedActions.ContainsValue(handledAction)) + { + isHiglighted = false; + overlay.FadeOut(1000, Easing.Out); + } + } + } + } +} From 09e45f39b2aa8c1bb3f359133c3ca30b564629ea Mon Sep 17 00:00:00 2001 From: Josh Date: Sat, 13 Aug 2022 19:55:47 +0800 Subject: [PATCH 0447/2686] Add the touchinputfield file because it was untracked --- osu.Game.Rulesets.Catch/UI/TouchInputField.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs index 1219ebd02d..cb853d1abd 100644 --- a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs +++ b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs @@ -146,13 +146,6 @@ namespace osu.Game.Rulesets.Catch.UI base.OnTouchUp(e); } - private CatchAction removeDashFromAction(TouchCatchAction touchCatchAction) - { - if (touchCatchAction == TouchCatchAction.DashLeft || touchCatchAction == TouchCatchAction.MoveLeft) - return CatchAction.MoveLeft; - return CatchAction.MoveRight; - } - private void calculateActiveKeys() { if (trackedActions.ContainsValue(TouchCatchAction.DashLeft) || trackedActions.ContainsValue(TouchCatchAction.MoveLeft)) From b05acb00738ed25463fbdacbee9b7da68ed01f58 Mon Sep 17 00:00:00 2001 From: basseX Date: Sat, 13 Aug 2022 21:32:24 +0200 Subject: [PATCH 0448/2686] Make `CommentMarkdownTextFlowContainer` render images --- osu.Game/Overlays/Comments/CommentMarkdownContainer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs index e94a1b0147..58f020fd9e 100644 --- a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs +++ b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs @@ -18,8 +18,10 @@ namespace osu.Game.Overlays.Comments private class CommentMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer { - // Don't render image in comment for now - protected override void AddImage(LinkInline linkInline) { } + protected override void AddImage(LinkInline linkInline) + { + AddDrawable(new OsuMarkdownImage(linkInline)); + } } private class CommentMarkdownHeading : OsuMarkdownHeading From 932becc4b227ff2eef4419be68a16fae5151888e Mon Sep 17 00:00:00 2001 From: basseX Date: Sun, 14 Aug 2022 10:11:49 +0200 Subject: [PATCH 0449/2686] Remove `CommentMarkdownTextFlowContainer` and rather use base-class `OsuMarkdownTextFlowContainer` --- .../Overlays/Comments/CommentMarkdownContainer.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs index 58f020fd9e..45b8172994 100644 --- a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs +++ b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs @@ -4,7 +4,6 @@ #nullable disable using Markdig.Syntax; -using Markdig.Syntax.Inlines; using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Graphics.Containers.Markdown; @@ -12,18 +11,10 @@ namespace osu.Game.Overlays.Comments { public class CommentMarkdownContainer : OsuMarkdownContainer { - public override MarkdownTextFlowContainer CreateTextFlow() => new CommentMarkdownTextFlowContainer(); + public override MarkdownTextFlowContainer CreateTextFlow() => new OsuMarkdownTextFlowContainer(); protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new CommentMarkdownHeading(headingBlock); - private class CommentMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer - { - protected override void AddImage(LinkInline linkInline) - { - AddDrawable(new OsuMarkdownImage(linkInline)); - } - } - private class CommentMarkdownHeading : OsuMarkdownHeading { public CommentMarkdownHeading(HeadingBlock headingBlock) From 383afe04f35159262e34d437c7835e292d81125a Mon Sep 17 00:00:00 2001 From: basseX Date: Sun, 14 Aug 2022 15:15:36 +0200 Subject: [PATCH 0450/2686] Remove not needed override --- osu.Game/Overlays/Comments/CommentMarkdownContainer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs index 45b8172994..8fc011b2bf 100644 --- a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs +++ b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs @@ -11,8 +11,6 @@ namespace osu.Game.Overlays.Comments { public class CommentMarkdownContainer : OsuMarkdownContainer { - public override MarkdownTextFlowContainer CreateTextFlow() => new OsuMarkdownTextFlowContainer(); - protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new CommentMarkdownHeading(headingBlock); private class CommentMarkdownHeading : OsuMarkdownHeading From d5f10cbb9d1396ab10c32981c436729fb4c2c639 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Sun, 14 Aug 2022 18:53:00 +0200 Subject: [PATCH 0451/2686] Revert 787dee24 and initialize calculator in `HUDOverlay` --- osu.Game/Screens/Play/HUDOverlay.cs | 5 +++-- osu.Game/Screens/Play/Player.cs | 7 ------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 458e19826b..20f7f7d6c2 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -50,8 +50,8 @@ namespace osu.Game.Screens.Play public readonly HoldForMenuButton HoldToQuit; public readonly PlayerSettingsOverlay PlayerSettingsOverlay; - [Resolved(canBeNull: true)] - private KeysPerSecondCalculator keysPerSecondCalculator { get; set; } + [Cached] + private readonly KeysPerSecondCalculator keysPerSecondCalculator; public Bindable ShowHealthBar = new Bindable(true); @@ -127,6 +127,7 @@ namespace osu.Game.Screens.Play HoldToQuit = CreateHoldForMenuButton(), } }, + keysPerSecondCalculator = new KeysPerSecondCalculator() }; } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index ba7e01a803..e3844088e2 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -34,7 +34,6 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; -using osu.Game.Screens.Play.HUD.KeysPerSecond; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Users; @@ -123,8 +122,6 @@ namespace osu.Game.Screens.Play private SkipOverlay skipIntroOverlay; private SkipOverlay skipOutroOverlay; - protected KeysPerSecondCalculator KeysPerSecondCalculator { get; private set; } - protected ScoreProcessor ScoreProcessor { get; private set; } protected HealthProcessor HealthProcessor { get; private set; } @@ -229,9 +226,6 @@ namespace osu.Game.Screens.Play dependencies.CacheAs(ScoreProcessor); - KeysPerSecondCalculator = new KeysPerSecondCalculator(); - dependencies.CacheAs(KeysPerSecondCalculator); - HealthProcessor = ruleset.CreateHealthProcessor(playableBeatmap.HitObjects[0].StartTime); HealthProcessor.ApplyBeatmap(playableBeatmap); @@ -448,7 +442,6 @@ namespace osu.Game.Screens.Play OnRetry = Restart, OnQuit = () => PerformExit(true), }, - KeysPerSecondCalculator }, }; From 5106c00a9c5010f751b428a7b0726d95bc5b7620 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sun, 14 Aug 2022 19:02:29 +0200 Subject: [PATCH 0452/2686] Improve code quality --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 54 +++++++++++----------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 2be1ad231a..ce54d87dfa 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Mods for (int i = 0; i < positionInfos.Count; i++) { - if (shouldStartNewSection(osuBeatmap, positionInfos, i, 0.6f, 0.4f)) + if (shouldStartNewSection(osuBeatmap, positionInfos, i)) { sectionOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.0008f); flowDirection = !flowDirection; @@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Osu.Mods // Offsets only the angle of the current hit object. float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.002f); - if (shouldApplyFlowChange(positionInfos, i, 0.6f)) + if (shouldApplyFlowChange(positionInfos, i)) { flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.002f); flowDirection = !flowDirection; @@ -95,33 +95,35 @@ namespace osu.Game.Rulesets.Osu.Mods return flowDirection ? -relativeAngle : relativeAngle; } - /// - /// A new section should be started...
- /// ...at the beginning of the .
- /// ...on every combo start with a probability of (excluding new-combo-spam and 1-2-combos).
- /// ...on every downbeat.
- /// ...on every beat with a probability of .
- ///
/// Whether a new section should be started at the current . - private bool shouldStartNewSection( - OsuBeatmap beatmap, - IReadOnlyList positionInfos, - int i, - float newComboProbability, - float beatProbability - ) => - i == 0 || - (positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo && rng?.NextDouble() < newComboProbability) || - OsuHitObjectGenerationUtils.IsHitObjectOnBeat(beatmap, positionInfos[i - 1].HitObject, true) || - (OsuHitObjectGenerationUtils.IsHitObjectOnBeat(beatmap, positionInfos[i - 1].HitObject) && rng?.NextDouble() < beatProbability); + private bool shouldStartNewSection(OsuBeatmap beatmap, IReadOnlyList positionInfos, int i) + { + if (i == 0) + return true; + + // Exclude new-combo-spam and 1-2-combos. + bool previousObjectStartedCombo = positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && + positionInfos[i - 1].HitObject.NewCombo; + bool previousObjectWasOnDownbeat = OsuHitObjectGenerationUtils.IsHitObjectOnBeat(beatmap, positionInfos[i - 1].HitObject, true); + bool previousObjectWasOnBeat = OsuHitObjectGenerationUtils.IsHitObjectOnBeat(beatmap, positionInfos[i - 1].HitObject); + + return (previousObjectStartedCombo && randomBool(0.6f)) || + previousObjectWasOnDownbeat || + (previousObjectWasOnBeat && randomBool(0.4f)); + } - /// - /// A flow change should occur on every combo start with a probability of (excluding new-combo-spam and 1-2-combos). - /// /// Whether a flow change should be applied at the current . - private bool shouldApplyFlowChange(IReadOnlyList positionInfos, int i, float probability) => - positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && - positionInfos[i - 1].HitObject.NewCombo && + private bool shouldApplyFlowChange(IReadOnlyList positionInfos, int i) + { + // Exclude new-combo-spam and 1-2-combos. + bool previousObjectStartedCombo = positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && + positionInfos[i - 1].HitObject.NewCombo; + + return previousObjectStartedCombo && randomBool(0.6f); + } + + /// true with a probability of , false otherwise. + private bool randomBool(float probability) => rng?.NextDouble() < probability; } } From 9dc806506e55ca13b39241b50e71a1b7da7a332b Mon Sep 17 00:00:00 2001 From: Ryuki Date: Sun, 14 Aug 2022 19:09:34 +0200 Subject: [PATCH 0453/2686] Make `ActionListener` and `KeysPerSecondCalculator` not rely on events to add timestamps --- .../Visual/Gameplay/TestSceneKeysPerSecond.cs | 13 +++++----- osu.Game/Rulesets/UI/RulesetInputManager.cs | 11 +++++--- .../KeysPerSecond/KeysPerSecondCalculator.cs | 25 ++++++------------- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs index 5c1ca18dbc..ac7b7521c9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs @@ -61,10 +61,7 @@ namespace osu.Game.Tests.Visual.Gameplay { dependencyContainer!.Children = new Drawable[] { - calculator = new KeysPerSecondCalculator - { - Listener = listener = new ManualInputListener() - }, + calculator = new KeysPerSecondCalculator(), new DependencyProvidingContainer { RelativeSizeAxes = Axes.Both, @@ -77,6 +74,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } }; + calculator!.Listener = listener = new ManualInputListener(calculator!); }); } @@ -208,9 +206,12 @@ namespace osu.Game.Tests.Visual.Gameplay private class ManualInputListener : KeysPerSecondCalculator.InputListener { - public override event Action? OnNewInput; + public void AddInput() => Calculator.AddTimestamp(); - public void AddInput() => OnNewInput?.Invoke(); + public ManualInputListener(KeysPerSecondCalculator calculator) + : base(calculator) + { + } } private class MockFrameBasedClock : ManualClock, IFrameBasedClock diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 590a305f77..23580bc40a 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -193,7 +193,7 @@ namespace osu.Game.Rulesets.UI { if (calculator == null) return; - var listener = new ActionListener(); + var listener = new ActionListener(calculator); KeyBindingContainer.Add(listener); @@ -202,11 +202,9 @@ namespace osu.Game.Rulesets.UI public class ActionListener : KeysPerSecondCalculator.InputListener, IKeyBindingHandler { - public override event Action OnNewInput; - public bool OnPressed(KeyBindingPressEvent e) { - OnNewInput?.Invoke(); + Calculator.AddTimestamp(); return false; } @@ -214,6 +212,11 @@ namespace osu.Game.Rulesets.UI public void OnReleased(KeyBindingReleaseEvent e) { } + + public ActionListener(KeysPerSecondCalculator calculator) + : base(calculator) + { + } } #endregion diff --git a/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCalculator.cs index ecc9c6ef86..20ab09e9cc 100644 --- a/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCalculator.cs @@ -29,7 +29,6 @@ namespace osu.Game.Screens.Play.HUD.KeysPerSecond { onResetRequested?.Invoke(); listener = value; - listener.OnNewInput += addTimestamp; } } @@ -43,12 +42,9 @@ namespace osu.Game.Screens.Play.HUD.KeysPerSecond { get { - if (gameplayClock != null) + if (gameplayClock?.TrueGameplayRate > 0) { - if (gameplayClock.TrueGameplayRate > 0) - { - baseRate = gameplayClock.TrueGameplayRate; - } + baseRate = gameplayClock.TrueGameplayRate; } return baseRate; @@ -71,12 +67,9 @@ namespace osu.Game.Screens.Play.HUD.KeysPerSecond { timestamps.Clear(); maxTime = double.NegativeInfinity; - - if (listener != null) - listener.OnNewInput -= addTimestamp; } - private void addTimestamp() + public void AddTimestamp() { if (workingClock == null) return; @@ -96,20 +89,16 @@ namespace osu.Game.Screens.Play.HUD.KeysPerSecond return relativeTime > 0 && relativeTime <= span; } - ~KeysPerSecondCalculator() - { - cleanUp(); - } - public abstract class InputListener : Component { - protected InputListener() + protected KeysPerSecondCalculator Calculator; + + protected InputListener(KeysPerSecondCalculator calculator) { RelativeSizeAxes = Axes.Both; Depth = float.MinValue; + Calculator = calculator; } - - public abstract event Action? OnNewInput; } } } From 2aa3a1b50d558b8c01097b7c601889848596d8f6 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Sun, 14 Aug 2022 20:12:11 +0200 Subject: [PATCH 0454/2686] Rename all "KeysPerSecond" usages to "ClicksPerSecond" --- ...sPerSecond.cs => TestSceneClicksPerSecond.cs} | 16 ++++++++-------- osu.Game/Rulesets/UI/DrawableRuleset.cs | 4 ++-- osu.Game/Rulesets/UI/RulesetInputManager.cs | 10 +++++----- .../ClicksPerSecondCalculator.cs} | 10 +++++----- .../ClicksPerSecondCounter.cs} | 10 +++++----- osu.Game/Screens/Play/HUDOverlay.cs | 8 ++++---- 6 files changed, 29 insertions(+), 29 deletions(-) rename osu.Game.Tests/Visual/Gameplay/{TestSceneKeysPerSecond.cs => TestSceneClicksPerSecond.cs} (94%) rename osu.Game/Screens/Play/HUD/{KeysPerSecond/KeysPerSecondCalculator.cs => ClicksPerSecond/ClicksPerSecondCalculator.cs} (90%) rename osu.Game/Screens/Play/HUD/{KeysPerSecond/KeysPerSecondCounter.cs => ClicksPerSecond/ClicksPerSecondCounter.cs} (92%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs similarity index 94% rename from osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs index ac7b7521c9..8a5bd1af0f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeysPerSecond.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs @@ -19,16 +19,16 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD.KeysPerSecond; +using osu.Game.Screens.Play.HUD.ClicksPerSecond; using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneKeysPerSecond : OsuTestScene + public class TestSceneClicksPerSecond : OsuTestScene { private DependencyProvidingContainer? dependencyContainer; private MockFrameStableClock? mainClock; - private KeysPerSecondCalculator? calculator; + private ClicksPerSecondCalculator? calculator; private ManualInputListener? listener; [SetUpSteps] @@ -61,12 +61,12 @@ namespace osu.Game.Tests.Visual.Gameplay { dependencyContainer!.Children = new Drawable[] { - calculator = new KeysPerSecondCalculator(), + calculator = new ClicksPerSecondCalculator(), new DependencyProvidingContainer { RelativeSizeAxes = Axes.Both, - CachedDependencies = new (Type, object)[] { (typeof(KeysPerSecondCalculator), calculator) }, - Child = new KeysPerSecondCounter // For visual debugging, has no real purpose in the tests + CachedDependencies = new (Type, object)[] { (typeof(ClicksPerSecondCalculator), calculator) }, + Child = new ClicksPerSecondCounter // For visual debugging, has no real purpose in the tests { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -204,11 +204,11 @@ namespace osu.Game.Tests.Visual.Gameplay #region Mock classes - private class ManualInputListener : KeysPerSecondCalculator.InputListener + private class ManualInputListener : ClicksPerSecondCalculator.InputListener { public void AddInput() => Calculator.AddTimestamp(); - public ManualInputListener(KeysPerSecondCalculator calculator) + public ManualInputListener(ClicksPerSecondCalculator calculator) : base(calculator) { } diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 443e4392cf..cb483bff81 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -30,7 +30,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD.KeysPerSecond; +using osu.Game.Screens.Play.HUD.ClicksPerSecond; using osuTK; namespace osu.Game.Rulesets.UI @@ -341,7 +341,7 @@ namespace osu.Game.Rulesets.UI public void Attach(KeyCounterDisplay keyCounter) => (KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(keyCounter); - public void Attach(KeysPerSecondCalculator calculator) => (KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(calculator); + public void Attach(ClicksPerSecondCalculator calculator) => (KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(calculator); /// /// Creates a key conversion input manager. An exception will be thrown if a valid is not returned. diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 23580bc40a..4b7ce22cfc 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -20,7 +20,7 @@ using osu.Game.Input.Bindings; using osu.Game.Input.Handlers; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; -using osu.Game.Screens.Play.HUD.KeysPerSecond; +using osu.Game.Screens.Play.HUD.ClicksPerSecond; using static osu.Game.Input.Handlers.ReplayInputHandler; namespace osu.Game.Rulesets.UI @@ -189,7 +189,7 @@ namespace osu.Game.Rulesets.UI #region Keys per second Counter Attachment - public void Attach(KeysPerSecondCalculator calculator) + public void Attach(ClicksPerSecondCalculator calculator) { if (calculator == null) return; @@ -200,7 +200,7 @@ namespace osu.Game.Rulesets.UI calculator.Listener = listener; } - public class ActionListener : KeysPerSecondCalculator.InputListener, IKeyBindingHandler + public class ActionListener : ClicksPerSecondCalculator.InputListener, IKeyBindingHandler { public bool OnPressed(KeyBindingPressEvent e) { @@ -213,7 +213,7 @@ namespace osu.Game.Rulesets.UI { } - public ActionListener(KeysPerSecondCalculator calculator) + public ActionListener(ClicksPerSecondCalculator calculator) : base(calculator) { } @@ -262,7 +262,7 @@ namespace osu.Game.Rulesets.UI public interface ICanAttachKeyCounter { void Attach(KeyCounterDisplay keyCounter); - void Attach(KeysPerSecondCalculator calculator); + void Attach(ClicksPerSecondCalculator calculator); } public class RulesetInputManagerInputState : InputState diff --git a/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs similarity index 90% rename from osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCalculator.cs rename to osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs index 20ab09e9cc..9dc8615fb6 100644 --- a/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs @@ -9,9 +9,9 @@ using osu.Framework.Graphics; using osu.Framework.Timing; using osu.Game.Rulesets.UI; -namespace osu.Game.Screens.Play.HUD.KeysPerSecond +namespace osu.Game.Screens.Play.HUD.ClicksPerSecond { - public class KeysPerSecondCalculator : Component + public class ClicksPerSecondCalculator : Component { private readonly List timestamps; @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Play.HUD.KeysPerSecond public bool Ready => workingClock != null && gameplayClock != null && listener != null; public int Value => timestamps.Count(isTimestampWithinSpan); - public KeysPerSecondCalculator() + public ClicksPerSecondCalculator() { RelativeSizeAxes = Axes.Both; timestamps = new List(); @@ -91,9 +91,9 @@ namespace osu.Game.Screens.Play.HUD.KeysPerSecond public abstract class InputListener : Component { - protected KeysPerSecondCalculator Calculator; + protected ClicksPerSecondCalculator Calculator; - protected InputListener(KeysPerSecondCalculator calculator) + protected InputListener(ClicksPerSecondCalculator calculator) { RelativeSizeAxes = Axes.Both; Depth = float.MinValue; diff --git a/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs similarity index 92% rename from osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs rename to osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs index a5c122f5b1..049f38ba4c 100644 --- a/osu.Game/Screens/Play/HUD/KeysPerSecond/KeysPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs @@ -13,27 +13,27 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Skinning; using osuTK; -namespace osu.Game.Screens.Play.HUD.KeysPerSecond +namespace osu.Game.Screens.Play.HUD.ClicksPerSecond { - public class KeysPerSecondCounter : RollingCounter, ISkinnableDrawable + public class ClicksPerSecondCounter : RollingCounter, ISkinnableDrawable { private const float alpha_when_invalid = 0.3f; private readonly Bindable valid = new Bindable(); - private KeysPerSecondCalculator? calculator; + private ClicksPerSecondCalculator? calculator; protected override double RollingDuration => 350; public bool UsesFixedAnchor { get; set; } - public KeysPerSecondCounter() + public ClicksPerSecondCounter() { Current.Value = 0; } [BackgroundDependencyLoader] - private void load(OsuColour colours, KeysPerSecondCalculator calculator) + private void load(OsuColour colours, ClicksPerSecondCalculator calculator) { this.calculator = calculator; Colour = colours.BlueLighter; diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 20f7f7d6c2..b27efaf13a 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -22,7 +22,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Play.HUD.KeysPerSecond; +using osu.Game.Screens.Play.HUD.ClicksPerSecond; using osu.Game.Skinning; using osuTK; @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Play public readonly PlayerSettingsOverlay PlayerSettingsOverlay; [Cached] - private readonly KeysPerSecondCalculator keysPerSecondCalculator; + private readonly ClicksPerSecondCalculator clicksPerSecondCalculator; public Bindable ShowHealthBar = new Bindable(true); @@ -127,7 +127,7 @@ namespace osu.Game.Screens.Play HoldToQuit = CreateHoldForMenuButton(), } }, - keysPerSecondCalculator = new KeysPerSecondCalculator() + clicksPerSecondCalculator = new ClicksPerSecondCalculator() }; } @@ -265,7 +265,7 @@ namespace osu.Game.Screens.Play protected virtual void BindDrawableRuleset(DrawableRuleset drawableRuleset) { (drawableRuleset as ICanAttachKeyCounter)?.Attach(KeyCounter); - (drawableRuleset as ICanAttachKeyCounter)?.Attach(keysPerSecondCalculator); + (drawableRuleset as ICanAttachKeyCounter)?.Attach(clicksPerSecondCalculator); replayLoaded.BindTo(drawableRuleset.HasReplayLoaded); } From 18ce784ae0270137909b820836e825d6d4ab9319 Mon Sep 17 00:00:00 2001 From: naoei Date: Sun, 14 Aug 2022 14:51:35 -0400 Subject: [PATCH 0455/2686] Allow StatisticItem's name param to be nullable --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- osu.Game/Screens/Ranking/Statistics/StatisticItem.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 4723416c30..f787bb3c41 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -395,7 +395,7 @@ namespace osu.Game.Rulesets.Mania { Columns = new[] { - new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + new StatisticItem(null, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] { new AverageHitError(score.HitEvents), new UnstableRate(score.HitEvents) diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 302194e91a..8070e6464d 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -316,7 +316,7 @@ namespace osu.Game.Rulesets.Osu { Columns = new[] { - new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + new StatisticItem(null, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] { new AverageHitError(timedHitEvents), new UnstableRate(timedHitEvents) diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 223e268d7f..961864c36a 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -238,7 +238,7 @@ namespace osu.Game.Rulesets.Taiko { Columns = new[] { - new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + new StatisticItem(null, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] { new AverageHitError(timedHitEvents), new UnstableRate(timedHitEvents) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs index baabc90c6f..a3c51b4876 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// A function returning the content to be displayed. /// Whether this item requires hit events. If true, will not be called if no hit events are available. /// The of this item. This can be thought of as the column dimension of an encompassing . - public StatisticItem(LocalisableString name, [NotNull] Func createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) + public StatisticItem(LocalisableString? name, [NotNull] Func createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) { Name = name; RequiresHitEvents = requiresHitEvents; From 45e9eda9e7cb98b7c2e57019e692f0bf2c0b940d Mon Sep 17 00:00:00 2001 From: naoei Date: Sun, 14 Aug 2022 14:54:02 -0400 Subject: [PATCH 0456/2686] Localise hit result name --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 3 ++- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 3 ++- osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 ++- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 3 ++- osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs | 8 +++++--- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 4 ++-- osu.Game/Rulesets/Ruleset.cs | 5 +++-- osu.Game/Scoring/HitResultDisplayStatistic.cs | 5 +++-- 8 files changed, 21 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index f832d99807..ed151855b1 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -23,6 +23,7 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Scoring; using System; using osu.Framework.Extensions.EnumExtensions; +using osu.Framework.Localisation; using osu.Game.Rulesets.Catch.Edit; using osu.Game.Rulesets.Catch.Skinning.Legacy; using osu.Game.Rulesets.Edit; @@ -162,7 +163,7 @@ namespace osu.Game.Rulesets.Catch }; } - public override string GetDisplayNameForHitResult(HitResult result) + public override LocalisableString GetDisplayNameForHitResult(HitResult result) { switch (result) { diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index f787bb3c41..2167e5e5ac 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -15,6 +15,7 @@ using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Replays.Types; @@ -356,7 +357,7 @@ namespace osu.Game.Rulesets.Mania }; } - public override string GetDisplayNameForHitResult(HitResult result) + public override LocalisableString GetDisplayNameForHitResult(HitResult result) { switch (result) { diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 8070e6464d..f7df949414 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -32,6 +32,7 @@ using osu.Game.Skinning; using System; using System.Linq; using osu.Framework.Extensions.EnumExtensions; +using osu.Framework.Localisation; using osu.Game.Rulesets.Osu.Edit.Setup; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Skinning.Legacy; @@ -253,7 +254,7 @@ namespace osu.Game.Rulesets.Osu }; } - public override string GetDisplayNameForHitResult(HitResult result) + public override LocalisableString GetDisplayNameForHitResult(HitResult result) { switch (result) { diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 961864c36a..555c272954 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -25,6 +25,7 @@ using osu.Game.Scoring; using System; using System.Linq; using osu.Framework.Extensions.EnumExtensions; +using osu.Framework.Localisation; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Taiko.Edit; using osu.Game.Rulesets.Taiko.Objects; @@ -192,7 +193,7 @@ namespace osu.Game.Rulesets.Taiko }; } - public override string GetDisplayNameForHitResult(HitResult result) + public override LocalisableString GetDisplayNameForHitResult(HitResult result) { switch (result) { diff --git a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs index 53a4719050..2f3ece0e3b 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs @@ -10,6 +10,8 @@ using osuTK; using osu.Game.Graphics.Sprites; using osu.Game.Graphics; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Localisation; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; @@ -126,7 +128,7 @@ namespace osu.Game.Online.Leaderboards private class HitResultCell : CompositeDrawable { - private readonly string displayName; + private readonly LocalisableString displayName; private readonly HitResult result; private readonly int count; @@ -134,7 +136,7 @@ namespace osu.Game.Online.Leaderboards { AutoSizeAxes = Axes.Both; - displayName = stat.DisplayName; + displayName = stat.DisplayName.ToUpper(); result = stat.Result; count = stat.Count; } @@ -153,7 +155,7 @@ namespace osu.Game.Online.Leaderboards new OsuSpriteText { Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), - Text = displayName.ToUpperInvariant(), + Text = displayName.ToUpper(), Colour = colours.ForHitResult(result), }, new OsuSpriteText diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 5463c7a50f..11aefd435d 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -59,7 +59,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores /// /// The statistics that appear in the table, in order of appearance. /// - private readonly List<(HitResult result, string displayName)> statisticResultTypes = new List<(HitResult, string)>(); + private readonly List<(HitResult result, LocalisableString displayName)> statisticResultTypes = new List<(HitResult, LocalisableString)>(); private bool showPerformancePoints; @@ -114,7 +114,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores if (result.IsBonus()) continue; - string displayName = ruleset.GetDisplayNameForHitResult(result); + var displayName = ruleset.GetDisplayNameForHitResult(result); columns.Add(new TableColumn(displayName, Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 35, maxSize: 60))); statisticResultTypes.Add((result, displayName)); diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index c1ec6c30ef..50ce6b3b12 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -28,6 +28,7 @@ using osu.Game.Users; using JetBrains.Annotations; using osu.Framework.Extensions; using osu.Framework.Extensions.EnumExtensions; +using osu.Framework.Localisation; using osu.Framework.Testing; using osu.Game.Extensions; using osu.Game.Rulesets.Filter; @@ -313,7 +314,7 @@ namespace osu.Game.Rulesets /// /// All valid s along with a display-friendly name. /// - public IEnumerable<(HitResult result, string displayName)> GetHitResults() + public IEnumerable<(HitResult result, LocalisableString displayName)> GetHitResults() { var validResults = GetValidHitResults(); @@ -351,7 +352,7 @@ namespace osu.Game.Rulesets /// /// The result type to get the name for. /// The display name. - public virtual string GetDisplayNameForHitResult(HitResult result) => result.GetDescription(); + public virtual LocalisableString GetDisplayNameForHitResult(HitResult result) => result.GetLocalisableDescription(); /// /// Creates ruleset-specific beatmap filter criteria to be used on the song select screen. diff --git a/osu.Game/Scoring/HitResultDisplayStatistic.cs b/osu.Game/Scoring/HitResultDisplayStatistic.cs index 4603ff053e..20deff4875 100644 --- a/osu.Game/Scoring/HitResultDisplayStatistic.cs +++ b/osu.Game/Scoring/HitResultDisplayStatistic.cs @@ -3,6 +3,7 @@ #nullable disable +using osu.Framework.Localisation; using osu.Game.Rulesets.Scoring; namespace osu.Game.Scoring @@ -30,9 +31,9 @@ namespace osu.Game.Scoring /// /// A custom display name for the result type. May be provided by rulesets to give better clarity. /// - public string DisplayName { get; } + public LocalisableString DisplayName { get; } - public HitResultDisplayStatistic(HitResult result, int count, int? maxCount, string displayName) + public HitResultDisplayStatistic(HitResult result, int count, int? maxCount, LocalisableString displayName) { Result = result; Count = count; From 784ce4d23ded91bd0a13c36aabe432bb27445670 Mon Sep 17 00:00:00 2001 From: naoei Date: Sun, 14 Aug 2022 15:03:05 -0400 Subject: [PATCH 0457/2686] Add test coverage for localisable setting source --- .../Visual/Settings/TestSceneSettingsSource.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs index 98de712703..dc2a687bd5 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Overlays.Settings; using osuTK; @@ -39,6 +40,9 @@ namespace osu.Game.Tests.Visual.Settings [SettingSource("Sample bool", "Clicking this changes a setting")] public BindableBool TickBindable { get; } = new BindableBool(); + [SettingSource(typeof(TestStrings), nameof(TestStrings.LocalisableLabel), nameof(TestStrings.LocalisableDescription))] + public BindableBool LocalisableBindable { get; } = new BindableBool(true); + [SettingSource("Sample float", "Change something for a mod")] public BindableFloat SliderBindable { get; } = new BindableFloat { @@ -75,5 +79,11 @@ namespace osu.Game.Tests.Visual.Settings Value1, Value2 } + + private class TestStrings + { + public static LocalisableString LocalisableLabel => new LocalisableString("Sample localisable label"); + public static LocalisableString LocalisableDescription => new LocalisableString("Sample localisable description"); + } } } From 623e90a7b23da45c21d4449b7efb058f6113e808 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 15:05:35 +0900 Subject: [PATCH 0458/2686] Fix div-by-zero in `SongProgress` when no object duration could be calculated --- osu.Game/Screens/Play/HUD/SongProgress.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index 09afd7a9d3..85bb42193b 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -94,7 +94,10 @@ namespace osu.Game.Screens.Play.HUD double objectOffsetCurrent = currentTime - FirstHitTime; double objectDuration = LastHitTime - FirstHitTime; - UpdateProgress(objectOffsetCurrent / objectDuration, false); + if (objectDuration == 0) + UpdateProgress(0, false); + else + UpdateProgress(objectOffsetCurrent / objectDuration, false); } } } From 00879357083fca475c4cfabc4a9acc67b7765b8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 18:05:19 +0900 Subject: [PATCH 0459/2686] Update `TestSceneSpinnerRotation` to use constraint-based assertions --- .../TestSceneSpinnerRotation.cs | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index d1796f2231..b7f91c22f4 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -12,7 +10,6 @@ using osu.Framework.Audio; using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Framework.Timing; -using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Replays; using osu.Game.Rulesets.Objects; @@ -36,16 +33,16 @@ namespace osu.Game.Rulesets.Osu.Tests private const double spinner_duration = 6000; [Resolved] - private AudioManager audioManager { get; set; } + private AudioManager audioManager { get; set; } = null!; protected override bool Autoplay => true; protected override TestPlayer CreatePlayer(Ruleset ruleset) => new ScoreExposedPlayer(); - protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null) => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager); - private DrawableSpinner drawableSpinner; + private DrawableSpinner drawableSpinner = null!; private SpriteIcon spinnerSymbol => drawableSpinner.ChildrenOfType().Single(); [SetUpSteps] @@ -67,12 +64,12 @@ namespace osu.Game.Rulesets.Osu.Tests { trackerRotationTolerance = Math.Abs(drawableSpinner.RotationTracker.Rotation * 0.1f); }); - AddAssert("is disc rotation not almost 0", () => !Precision.AlmostEquals(drawableSpinner.RotationTracker.Rotation, 0, 100)); - AddAssert("is disc rotation absolute not almost 0", () => !Precision.AlmostEquals(drawableSpinner.Result.RateAdjustedRotation, 0, 100)); + AddAssert("is disc rotation not almost 0", () => drawableSpinner.RotationTracker.Rotation, () => Is.Not.EqualTo(0).Within(100)); + AddAssert("is disc rotation absolute not almost 0", () => drawableSpinner.Result.RateAdjustedRotation, () => Is.Not.EqualTo(0).Within(100)); addSeekStep(0); - AddAssert("is disc rotation almost 0", () => Precision.AlmostEquals(drawableSpinner.RotationTracker.Rotation, 0, trackerRotationTolerance)); - AddAssert("is disc rotation absolute almost 0", () => Precision.AlmostEquals(drawableSpinner.Result.RateAdjustedRotation, 0, 100)); + AddAssert("is disc rotation almost 0", () => drawableSpinner.RotationTracker.Rotation, () => Is.EqualTo(0).Within(trackerRotationTolerance)); + AddAssert("is disc rotation absolute almost 0", () => drawableSpinner.Result.RateAdjustedRotation, () => Is.EqualTo(0).Within(100)); } [Test] @@ -100,20 +97,20 @@ namespace osu.Game.Rulesets.Osu.Tests // we want to make sure that the rotation at time 2500 is in the same direction as at time 5000, but about half-way in. // due to the exponential damping applied we're allowing a larger margin of error of about 10% // (5% relative to the final rotation value, but we're half-way through the spin). - () => Precision.AlmostEquals(drawableSpinner.RotationTracker.Rotation, finalTrackerRotation / 2, trackerRotationTolerance)); + () => drawableSpinner.RotationTracker.Rotation, () => Is.EqualTo(finalTrackerRotation / 2).Within(trackerRotationTolerance)); AddAssert("symbol rotation rewound", - () => Precision.AlmostEquals(spinnerSymbol.Rotation, finalSpinnerSymbolRotation / 2, spinnerSymbolRotationTolerance)); + () => spinnerSymbol.Rotation, () => Is.EqualTo(finalSpinnerSymbolRotation / 2).Within(spinnerSymbolRotationTolerance)); AddAssert("is cumulative rotation rewound", // cumulative rotation is not damped, so we're treating it as the "ground truth" and allowing a comparatively smaller margin of error. - () => Precision.AlmostEquals(drawableSpinner.Result.RateAdjustedRotation, finalCumulativeTrackerRotation / 2, 100)); + () => drawableSpinner.Result.RateAdjustedRotation, () => Is.EqualTo(finalCumulativeTrackerRotation / 2).Within(100)); addSeekStep(spinner_start_time + 5000); AddAssert("is disc rotation almost same", - () => Precision.AlmostEquals(drawableSpinner.RotationTracker.Rotation, finalTrackerRotation, trackerRotationTolerance)); + () => drawableSpinner.RotationTracker.Rotation, () => Is.EqualTo(finalTrackerRotation).Within(trackerRotationTolerance)); AddAssert("is symbol rotation almost same", - () => Precision.AlmostEquals(spinnerSymbol.Rotation, finalSpinnerSymbolRotation, spinnerSymbolRotationTolerance)); + () => spinnerSymbol.Rotation, () => Is.EqualTo(finalSpinnerSymbolRotation).Within(spinnerSymbolRotationTolerance)); AddAssert("is cumulative rotation almost same", - () => Precision.AlmostEquals(drawableSpinner.Result.RateAdjustedRotation, finalCumulativeTrackerRotation, 100)); + () => drawableSpinner.Result.RateAdjustedRotation, () => Is.EqualTo(finalCumulativeTrackerRotation).Within(100)); } [Test] @@ -177,10 +174,10 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("retrieve spm", () => estimatedSpm = drawableSpinner.SpinsPerMinute.Value); addSeekStep(2000); - AddAssert("spm still valid", () => Precision.AlmostEquals(drawableSpinner.SpinsPerMinute.Value, estimatedSpm, 1.0)); + AddAssert("spm still valid", () => drawableSpinner.SpinsPerMinute.Value, () => Is.EqualTo(estimatedSpm).Within(1.0)); addSeekStep(1000); - AddAssert("spm still valid", () => Precision.AlmostEquals(drawableSpinner.SpinsPerMinute.Value, estimatedSpm, 1.0)); + AddAssert("spm still valid", () => drawableSpinner.SpinsPerMinute.Value, () => Is.EqualTo(estimatedSpm).Within(1.0)); } [TestCase(0.5)] @@ -202,14 +199,14 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("adjust track rate", () => ((MasterGameplayClockContainer)Player.GameplayClockContainer).UserPlaybackRate.Value = rate); addSeekStep(1000); - AddAssert("progress almost same", () => Precision.AlmostEquals(expectedProgress, drawableSpinner.Progress, 0.05)); - AddAssert("spm almost same", () => Precision.AlmostEquals(expectedSpm, drawableSpinner.SpinsPerMinute.Value, 2.0)); + AddAssert("progress almost same", () => expectedProgress, () => Is.EqualTo(drawableSpinner.Progress).Within(0.05)); + AddAssert("spm almost same", () => expectedSpm, () => Is.EqualTo(drawableSpinner.SpinsPerMinute.Value).Within(2.0)); } private void addSeekStep(double time) { AddStep($"seek to {time}", () => Player.GameplayClockContainer.Seek(time)); - AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100)); + AddUntilStep("wait for seek to finish", () => time, () => Is.EqualTo(Player.DrawableRuleset.FrameStableClock.CurrentTime).Within(100)); } private void transformReplay(Func replayTransformation) => AddStep("set replay", () => From 58146598c8d4513011748a39a5ad97bd2a36f355 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 18:06:42 +0900 Subject: [PATCH 0460/2686] Update `TestSceneEditorClock` to use constraint-based assertions --- .../Visual/Editing/TestSceneEditorClock.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs index 96ba802a5f..3c6820e49b 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.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. -#nullable disable - using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -65,7 +63,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("seek near end", () => Clock.Seek(Clock.TrackLength - 250)); AddUntilStep("clock stops", () => !Clock.IsRunning); - AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength); + AddUntilStep("clock stopped at end", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength)); AddStep("start clock again", () => Clock.Start()); AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500); @@ -80,7 +78,7 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("clock stopped", () => !Clock.IsRunning); AddStep("seek exactly to end", () => Clock.Seek(Clock.TrackLength)); - AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength); + AddAssert("clock stopped at end", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength)); AddStep("start clock again", () => Clock.Start()); AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500); @@ -92,16 +90,16 @@ namespace osu.Game.Tests.Visual.Editing AddStep("stop clock", () => Clock.Stop()); AddStep("seek before start time", () => Clock.Seek(-1000)); - AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0); + AddAssert("time is clamped to 0", () => Clock.CurrentTime, () => Is.EqualTo(0)); AddStep("seek beyond track length", () => Clock.Seek(Clock.TrackLength + 1000)); - AddAssert("time is clamped to track length", () => Clock.CurrentTime == Clock.TrackLength); + AddAssert("time is clamped to track length", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength)); AddStep("seek smoothly before start time", () => Clock.SeekSmoothlyTo(-1000)); - AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0); + AddUntilStep("time is clamped to 0", () => Clock.CurrentTime, () => Is.EqualTo(0)); AddStep("seek smoothly beyond track length", () => Clock.SeekSmoothlyTo(Clock.TrackLength + 1000)); - AddAssert("time is clamped to track length", () => Clock.CurrentTime == Clock.TrackLength); + AddUntilStep("time is clamped to track length", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength)); } protected override void Dispose(bool isDisposing) From 95c1b488a7ebfcf4872b5249f9e266940c7d7fb4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 16:55:55 +0900 Subject: [PATCH 0461/2686] Add non-null assertion to `FrameStabilityContainer` --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index dcd7141419..b4a0d83bf2 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -129,6 +130,8 @@ namespace osu.Game.Rulesets.UI if (parentGameplayClock == null) setClock(); // LoadComplete may not be run yet, but we still want the clock. + Debug.Assert(parentGameplayClock != null); + double proposedTime = parentGameplayClock.CurrentTime; if (FrameStablePlayback) From 224f3eaa8470a0ea66e596122e0fb0fc78d6c788 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 16:56:16 +0900 Subject: [PATCH 0462/2686] Make `GameplayClockContainer` non-`abstract` and use in `MultiSpectatorPlayer` --- .../Spectate/MultiSpectatorPlayer.cs | 43 +++++++------------ .../Screens/Play/GameplayClockContainer.cs | 8 ++-- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index a0558f97a9..68eae76030 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -1,12 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -26,7 +22,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The score containing the player's replay. /// The clock controlling the gameplay running state. - public MultiSpectatorPlayer([NotNull] Score score, [NotNull] ISpectatorPlayerClock spectatorPlayerClock) + public MultiSpectatorPlayer(Score score, ISpectatorPlayerClock spectatorPlayerClock) : base(score, new PlayerConfiguration { AllowUserInteraction = false }) { this.spectatorPlayerClock = spectatorPlayerClock; @@ -41,6 +37,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate HUDOverlay.HoldToQuit.Expire(); } + protected override void Update() + { + // The player clock's running state is controlled externally, but the local pausing state needs to be updated to start/stop gameplay. + CatchUpSpectatorPlayerClock catchUpClock = (CatchUpSpectatorPlayerClock)GameplayClockContainer.SourceClock; + + if (catchUpClock.IsRunning) + GameplayClockContainer.Start(); + else + GameplayClockContainer.Stop(); + + base.Update(); + } + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -50,28 +59,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) - => new SpectatorGameplayClockContainer(spectatorPlayerClock); - - private class SpectatorGameplayClockContainer : GameplayClockContainer - { - public SpectatorGameplayClockContainer([NotNull] IClock sourceClock) - : base(sourceClock) - { - } - - protected override void Update() - { - // The SourceClock here is always a CatchUpSpectatorPlayerClock. - // The player clock's running state is controlled externally, but the local pausing state needs to be updated to stop gameplay. - if (SourceClock.IsRunning) - Start(); - else - Stop(); - - base.Update(); - } - - protected override GameplayClock CreateGameplayClock(IFrameBasedClock source) => new GameplayClock(source); - } + => new GameplayClockContainer(spectatorPlayerClock); } } diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index b37d15e06c..ffecb1d9a5 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Play /// /// Encapsulates gameplay timing logic and provides a via DI for gameplay components to use. /// - public abstract class GameplayClockContainer : Container, IAdjustableClock + public class GameplayClockContainer : Container, IAdjustableClock { /// /// The final clock which is exposed to gameplay components. @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Play /// /// The source clock. /// - protected IClock SourceClock { get; private set; } + public IClock SourceClock { get; private set; } /// /// Invoked when a seek has been performed via @@ -68,7 +68,7 @@ namespace osu.Game.Screens.Play /// Creates a new . /// /// The source used for timing. - protected GameplayClockContainer(IClock sourceClock) + public GameplayClockContainer(IClock sourceClock) { SourceClock = sourceClock; @@ -193,7 +193,7 @@ namespace osu.Game.Screens.Play /// /// The providing the source time. /// The final . - protected abstract GameplayClock CreateGameplayClock(IFrameBasedClock source); + protected virtual GameplayClock CreateGameplayClock(IFrameBasedClock source) => new GameplayClock(source); #region IAdjustableClock From 6d782181427564409bb9c4b030f1e49d87db4dd7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 17:06:24 +0900 Subject: [PATCH 0463/2686] Update usages of `GameplayClockContainer.GameplayClock` to access properties directly --- .../Mods/TestSceneOsuModDoubleTime.cs | 2 +- .../TestSceneMasterGameplayClockContainer.cs | 8 ++--- .../Gameplay/TestSceneStoryboardSamples.cs | 2 +- .../Visual/Gameplay/TestSceneLeadIn.cs | 4 +-- .../Gameplay/TestSceneOverlayActivation.cs | 2 +- .../Visual/Gameplay/TestScenePause.cs | 4 +-- .../Visual/Gameplay/TestSceneSkipOverlay.cs | 5 +-- .../Visual/Gameplay/TestSceneSongProgress.cs | 2 +- .../Gameplay/TestSceneStoryboardWithOutro.cs | 10 +++--- .../TestSceneMultiSpectatorScreen.cs | 2 +- .../Multiplayer/TestSceneMultiplayer.cs | 2 +- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../Screens/Play/GameplayClockContainer.cs | 32 ++++++++++++------- osu.Game/Screens/Play/Player.cs | 8 ++--- 14 files changed, 48 insertions(+), 37 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs index 335ef31019..8df8afe147 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods { Mod = mod, PassCondition = () => Player.ScoreProcessor.JudgedHits >= 2 && - Precision.AlmostEquals(Player.GameplayClockContainer.GameplayClock.Rate, mod.SpeedChange.Value) + Precision.AlmostEquals(Player.GameplayClockContainer.Rate, mod.SpeedChange.Value) }); } } diff --git a/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs b/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs index 5f403f9487..abd734b96c 100644 --- a/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs +++ b/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tests.Gameplay }); AddStep("start clock", () => gameplayClockContainer.Start()); - AddUntilStep("elapsed greater than zero", () => gameplayClockContainer.GameplayClock.ElapsedFrameTime > 0); + AddUntilStep("elapsed greater than zero", () => gameplayClockContainer.ElapsedFrameTime > 0); } [Test] @@ -60,16 +60,16 @@ namespace osu.Game.Tests.Gameplay }); AddStep("start clock", () => gameplayClockContainer.Start()); - AddUntilStep("current time greater 2000", () => gameplayClockContainer.GameplayClock.CurrentTime > 2000); + AddUntilStep("current time greater 2000", () => gameplayClockContainer.CurrentTime > 2000); double timeAtReset = 0; AddStep("reset clock", () => { - timeAtReset = gameplayClockContainer.GameplayClock.CurrentTime; + timeAtReset = gameplayClockContainer.CurrentTime; gameplayClockContainer.Reset(); }); - AddAssert("current time < time at reset", () => gameplayClockContainer.GameplayClock.CurrentTime < timeAtReset); + AddAssert("current time < time at reset", () => gameplayClockContainer.CurrentTime < timeAtReset); } [Test] diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index f05244ab88..3ccf6c5d33 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -141,7 +141,7 @@ namespace osu.Game.Tests.Gameplay beatmapSkinSourceContainer.Add(sample = new TestDrawableStoryboardSample(new StoryboardSampleInfo("test-sample", 1, 1)) { - Clock = gameplayContainer.GameplayClock + Clock = gameplayContainer }); }); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs index 7f4276f819..0d80d29cab 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs @@ -130,7 +130,7 @@ namespace osu.Game.Tests.Visual.Gameplay public double FirstHitObjectTime => DrawableRuleset.Objects.First().StartTime; - public double GameplayClockTime => GameplayClockContainer.GameplayClock.CurrentTime; + public double GameplayClockTime => GameplayClockContainer.CurrentTime; protected override void UpdateAfterChildren() { @@ -138,7 +138,7 @@ namespace osu.Game.Tests.Visual.Gameplay if (!FirstFrameClockTime.HasValue) { - FirstFrameClockTime = GameplayClockContainer.GameplayClock.CurrentTime; + FirstFrameClockTime = GameplayClockContainer.CurrentTime; AddInternal(new OsuSpriteText { Text = $"GameplayStartTime: {DrawableRuleset.GameplayStartTime} " diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs index 3e637f1870..789e7e770f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Gameplay base.SetUpSteps(); AddUntilStep("gameplay has started", - () => Player.GameplayClockContainer.GameplayClock.CurrentTime > Player.DrawableRuleset.GameplayStartTime); + () => Player.GameplayClockContainer.CurrentTime > Player.DrawableRuleset.GameplayStartTime); } [Test] diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index 71cc1f7b23..cad8c62233 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -313,7 +313,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("pause again", () => { Player.Pause(); - return !Player.GameplayClockContainer.GameplayClock.IsRunning; + return !Player.GameplayClockContainer.IsRunning; }); AddAssert("loop is playing", () => getLoop().IsPlaying); @@ -378,7 +378,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("pause overlay " + (isShown ? "shown" : "hidden"), () => Player.PauseOverlayVisible == isShown); private void confirmClockRunning(bool isRunning) => - AddUntilStep("clock " + (isRunning ? "running" : "stopped"), () => Player.GameplayClockContainer.GameplayClock.IsRunning == isRunning); + AddUntilStep("clock " + (isRunning ? "running" : "stopped"), () => Player.GameplayClockContainer.IsRunning == isRunning); protected override bool AllowFail => true; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs index 5c73db15df..b6b3650c83 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Timing; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Play; using osuTK; @@ -22,7 +23,7 @@ namespace osu.Game.Tests.Visual.Gameplay private double increment; private GameplayClockContainer gameplayClockContainer; - private GameplayClock gameplayClock; + private IFrameBasedClock gameplayClock; private const double skip_time = 6000; @@ -51,7 +52,7 @@ namespace osu.Game.Tests.Visual.Gameplay }; gameplayClockContainer.Start(); - gameplayClock = gameplayClockContainer.GameplayClock; + gameplayClock = gameplayClockContainer; }); [Test] diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index 9eb71b9cf7..146cbfb052 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual.Gameplay Add(gameplayClockContainer = new MasterGameplayClockContainer(Beatmap.Value, skip_target_time)); - Dependencies.CacheAs(gameplayClockContainer.GameplayClock); + Dependencies.CacheAs(gameplayClockContainer); } [SetUpSteps] diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs index e2b2ad85a3..e2c825df0b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs @@ -64,7 +64,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestStoryboardNoSkipOutro() { CreateTest(); - AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration); + AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration); AddUntilStep("wait for score shown", () => Player.IsScoreShown); } @@ -100,7 +100,7 @@ namespace osu.Game.Tests.Visual.Gameplay }); AddUntilStep("wait for fail", () => Player.GameplayState.HasFailed); - AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration); + AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration); AddUntilStep("wait for fail overlay", () => Player.FailOverlay.State.Value == Visibility.Visible); } @@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("set ShowResults = false", () => showResults = false); }); - AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration); + AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration); AddWaitStep("wait", 10); AddAssert("no score shown", () => !Player.IsScoreShown); } @@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestStoryboardEndsBeforeCompletion() { CreateTest(() => AddStep("set storyboard duration to .1s", () => currentStoryboardDuration = 100)); - AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration); + AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration); AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); AddUntilStep("wait for score shown", () => Player.IsScoreShown); } @@ -138,7 +138,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("skip overlay content not visible", () => fadeContainer().State == Visibility.Hidden); AddUntilStep("skip overlay content becomes visible", () => fadeContainer().State == Visibility.Visible); - AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= currentStoryboardDuration); + AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration); } [Test] diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 706d493fd6..a2e3ab7318 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -451,7 +451,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } private void checkPaused(int userId, bool state) - => AddUntilStep($"{userId} is {(state ? "paused" : "playing")}", () => getPlayer(userId).ChildrenOfType().First().GameplayClock.IsRunning != state); + => AddUntilStep($"{userId} is {(state ? "paused" : "playing")}", () => getPlayer(userId).ChildrenOfType().First().IsRunning != state); private void checkPausedInstant(int userId, bool state) { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 269867be73..6098a3e794 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -671,7 +671,7 @@ namespace osu.Game.Tests.Visual.Multiplayer for (double i = 1000; i < TestResources.QUICK_BEATMAP_LENGTH; i += 1000) { double time = i; - AddUntilStep($"wait for time > {i}", () => this.ChildrenOfType().SingleOrDefault()?.GameplayClock.CurrentTime > time); + AddUntilStep($"wait for time > {i}", () => this.ChildrenOfType().SingleOrDefault()?.CurrentTime > time); } AddUntilStep("wait for results", () => multiplayerComponents.CurrentScreen is ResultsScreen); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 5cd9e0ddf9..7ed0be50e5 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -126,7 +126,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate for (int i = 0; i < Users.Count; i++) { - grid.Add(instances[i] = new PlayerArea(Users[i], masterClockContainer.GameplayClock)); + grid.Add(instances[i] = new PlayerArea(Users[i], masterClockContainer)); syncManager.AddPlayerClock(instances[i].GameplayClock); } diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index ffecb1d9a5..2cc1fe8eaf 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -1,11 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Logging; @@ -16,13 +15,8 @@ namespace osu.Game.Screens.Play /// /// Encapsulates gameplay timing logic and provides a via DI for gameplay components to use. /// - public class GameplayClockContainer : Container, IAdjustableClock + public class GameplayClockContainer : Container, IAdjustableClock, IFrameBasedClock { - /// - /// The final clock which is exposed to gameplay components. - /// - public GameplayClock GameplayClock { get; private set; } - /// /// Whether gameplay is paused. /// @@ -41,7 +35,7 @@ namespace osu.Game.Screens.Play /// /// Invoked when a seek has been performed via /// - public event Action OnSeek; + public event Action? OnSeek; private double? startTime; @@ -59,11 +53,16 @@ namespace osu.Game.Screens.Play { startTime = value; - if (GameplayClock != null) + if (GameplayClock.IsNotNull()) GameplayClock.StartTime = value; } } + /// + /// The final clock which is exposed to gameplay components. + /// + protected GameplayClock GameplayClock { get; private set; } = null!; + /// /// Creates a new . /// @@ -215,12 +214,23 @@ namespace osu.Game.Screens.Play set => throw new NotSupportedException(); } - double IClock.Rate => GameplayClock.Rate; + public double Rate => GameplayClock.Rate; public double CurrentTime => GameplayClock.CurrentTime; public bool IsRunning => GameplayClock.IsRunning; #endregion + + public void ProcessFrame() + { + // Handled via update. Don't process here to safeguard from external usages potentially processing frames additional times. + } + + public double ElapsedFrameTime => GameplayClock.ElapsedFrameTime; + + public double FramesPerSecond => GameplayClock.FramesPerSecond; + + public FrameTimeInfo TimeInfo => GameplayClock.TimeInfo; } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 08b6da1921..0ef09e4029 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -475,7 +475,7 @@ namespace osu.Game.Screens.Play private void updateSampleDisabledState() { - samplePlaybackDisabled.Value = DrawableRuleset.FrameStableClock.IsCatchingUp.Value || GameplayClockContainer.GameplayClock.IsPaused.Value; + samplePlaybackDisabled.Value = DrawableRuleset.FrameStableClock.IsCatchingUp.Value || GameplayClockContainer.IsPaused.Value; } private void updatePauseOnFocusLostState() @@ -877,7 +877,7 @@ namespace osu.Game.Screens.Play private double? lastPauseActionTime; protected bool PauseCooldownActive => - lastPauseActionTime.HasValue && GameplayClockContainer.GameplayClock.CurrentTime < lastPauseActionTime + pause_cooldown; + lastPauseActionTime.HasValue && GameplayClockContainer.CurrentTime < lastPauseActionTime + pause_cooldown; /// /// A set of conditionals which defines whether the current game state and configuration allows for @@ -915,7 +915,7 @@ namespace osu.Game.Screens.Play GameplayClockContainer.Stop(); PauseOverlay.Show(); - lastPauseActionTime = GameplayClockContainer.GameplayClock.CurrentTime; + lastPauseActionTime = GameplayClockContainer.CurrentTime; return true; } @@ -1005,7 +1005,7 @@ namespace osu.Game.Screens.Play /// protected virtual void StartGameplay() { - if (GameplayClockContainer.GameplayClock.IsRunning) + if (GameplayClockContainer.IsRunning) throw new InvalidOperationException($"{nameof(StartGameplay)} should not be called when the gameplay clock is already running"); GameplayClockContainer.Reset(true); From ff497c452fd48978b5f4b7021086f01368c4d62d Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 15 Aug 2022 17:23:29 +0800 Subject: [PATCH 0464/2686] Fix formatting + Add tests + fix touch UI --- .../TestSceneCatchTouchInput.cs | 45 ++++++++ .../UI/DrawableCatchRuleset.cs | 1 - osu.Game.Rulesets.Catch/UI/TouchInputField.cs | 104 +++++++++++------- 3 files changed, 110 insertions(+), 40 deletions(-) create mode 100644 osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs new file mode 100644 index 0000000000..03d031a0a8 --- /dev/null +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs @@ -0,0 +1,45 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Catch.Tests +{ + [TestFixture] + public class TestSceneCatchTouchInput : OsuTestScene + { + private TouchInputField touchInputField = null!; + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create inputfield", () => + { + Child = new CatchInputManager(new CatchRuleset().RulesetInfo) + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + touchInputField = new TouchInputField + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + } + }; + }); + } + + [Test] + public void TestInputField() + { + AddStep("show inputfield", () => touchInputField.Show()); + } + } +} diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index 83dc5770a6..b84d0c60d5 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -39,7 +39,6 @@ namespace osu.Game.Rulesets.Catch.UI KeyBindingInputManager.Add(new TouchInputField()); } - protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay); protected override ReplayRecorder CreateReplayRecorder(Score score) => new CatchReplayRecorder(score, (CatchPlayfield)Playfield); diff --git a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs index cb853d1abd..3b92ffa445 100644 --- a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs +++ b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs @@ -50,48 +50,70 @@ namespace osu.Game.Rulesets.Catch.UI // Container should handle input everywhere. RelativeSizeAxes = Axes.Both; - Children = new Drawable[] { mainContent = new Container { RelativeSizeAxes = Axes.Both, RelativePositionAxes = Axes.Both, + Alpha = 0, Children = new Drawable[] { - leftBox = new ArrowHitbox(TouchCatchAction.MoveLeft, ref trackedActions, colours.Blue) + new Container { - Anchor = Anchor.TopLeft, + RelativeSizeAxes = Axes.Both, + Width = 0.15f, + Height = 1, + Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - X = 0, - RelativePositionAxes = Axes.Both, - Size = new Vector2(100.0f, 100.0f) + Children = new Drawable[] + { + leftBox = new ArrowHitbox(TouchCatchAction.MoveLeft, ref trackedActions, colours.Gray2) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Width = 0.5f, + }, + leftDashBox = new ArrowHitbox(TouchCatchAction.DashLeft, ref trackedActions, colours.Gray3) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Width = 0.5f, + } + } }, - rightBox = new ArrowHitbox(TouchCatchAction.MoveRight, ref trackedActions, colours.Blue) + new Container { - Anchor = Anchor.TopRight, + RelativeSizeAxes = Axes.Both, + Width = 0.15f, + Height = 1, + Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - X = 0, - RelativePositionAxes = Axes.Both, - Size = new Vector2(100.0f, 100.0f), + Children = new Drawable[] + { + rightBox = new ArrowHitbox(TouchCatchAction.MoveRight, ref trackedActions, colours.Gray2) + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Width = 0.5f, + }, + rightDashBox = new ArrowHitbox(TouchCatchAction.DashRight, ref trackedActions, colours.Gray3) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Width = 0.5f, + }, + } }, - leftDashBox = new ArrowHitbox(TouchCatchAction.DashLeft, ref trackedActions, colours.Pink) - { - Anchor = Anchor.TopLeft, - Origin = Anchor.CentreLeft, - X = 0.1f, - RelativePositionAxes = Axes.Both, - Size = new Vector2(100.0f, 100.0f), - }, - rightDashBox = new ArrowHitbox(TouchCatchAction.DashRight, ref trackedActions, colours.Pink) - { - Anchor = Anchor.TopRight, - Origin = Anchor.CentreRight, - X = -0.1f, - RelativePositionAxes = Axes.Both, - Size = new Vector2(100.0f, 100.0f), - }, - } + }, }, }; } @@ -99,13 +121,13 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool OnKeyDown(KeyDownEvent e) { // Hide whenever the keyboard is used. - Hide(); + PopOut(); return false; } protected override bool OnMouseDown(MouseDownEvent e) { - if (getTouchCatchActionFromInput(e.MousePosition) != TouchCatchAction.None) + if (getTouchCatchActionFromInput(e.ScreenSpaceMousePosition) == TouchCatchAction.None) return false; handleDown(e.Button, e.ScreenSpaceMousePosition); @@ -114,14 +136,15 @@ namespace osu.Game.Rulesets.Catch.UI protected override void OnMouseUp(MouseUpEvent e) { - if (getTouchCatchActionFromInput(e.MousePosition) != TouchCatchAction.None) + if (getTouchCatchActionFromInput(e.ScreenSpaceMousePosition) == TouchCatchAction.None) return; handleUp(e.Button); base.OnMouseUp(e); } - protected override void OnTouchMove(TouchMoveEvent e) + /* I plan to come back to this code to add touch support + * protected override void OnTouchMove(TouchMoveEvent e) { // I'm not sure if this is posible but let's be safe if (!trackedActions.ContainsKey(e.Touch.Source)) @@ -132,7 +155,7 @@ namespace osu.Game.Rulesets.Catch.UI calculateActiveKeys(); base.OnTouchMove(e); - } + }*/ protected override bool OnTouchDown(TouchDownEvent e) { @@ -166,7 +189,7 @@ namespace osu.Game.Rulesets.Catch.UI private void handleDown(object source, Vector2 position) { - Show(); + PopIn(); TouchCatchAction catchAction = getTouchCatchActionFromInput(position); @@ -195,6 +218,7 @@ namespace osu.Game.Rulesets.Catch.UI return TouchCatchAction.MoveLeft; if (rightBox.Contains(inputPosition)) return TouchCatchAction.MoveRight; + return TouchCatchAction.None; } @@ -216,7 +240,7 @@ namespace osu.Game.Rulesets.Catch.UI private readonly Dictionary trackedActions; - private bool isHiglighted = false; + private bool isHiglighted; public ArrowHitbox(TouchCatchAction handledAction, ref Dictionary trackedActions, Color4 colour) { @@ -228,7 +252,6 @@ namespace osu.Game.Rulesets.Catch.UI new Container { Width = 1, - Height = 1, RelativeSizeAxes = Axes.Both, Children = new Drawable[] { @@ -237,13 +260,15 @@ namespace osu.Game.Rulesets.Catch.UI Alpha = 0, Colour = colour.Multiply(1.4f).Darken(2.8f), Blending = BlendingParameters.Additive, - Size = new Vector2(100.0f, 100.0f), + Width = 1, + RelativeSizeAxes = Axes.Both, }, new Box { - Alpha = 0.5f, + Alpha = 0.8f, Colour = colour, - Size = new Vector2(100.0f, 100.0f), + Width = 1, + RelativeSizeAxes = Axes.Both, } } } @@ -257,6 +282,7 @@ namespace osu.Game.Rulesets.Catch.UI isHiglighted = true; overlay.FadeTo(0.5f, 80, Easing.OutQuint); } + return false; } From c8764cb3336ffd3818d5df49f2d1e226770c0fd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 17:11:22 +0900 Subject: [PATCH 0465/2686] Move all usage of `GameplayClock` to `IGameplayClock` --- .../Default/SpinnerRotationTracker.cs | 2 +- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 2 +- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +- .../TestSceneSkinEditorMultipleSkins.cs | 2 +- .../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +- .../Rulesets/UI/FrameStabilityContainer.cs | 8 ++--- osu.Game/Screens/Play/ComboEffects.cs | 2 +- osu.Game/Screens/Play/GameplayClock.cs | 18 ++-------- .../Screens/Play/GameplayClockContainer.cs | 2 +- osu.Game/Screens/Play/HUD/SongProgress.cs | 2 +- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 4 +-- osu.Game/Screens/Play/IGameplayClock.cs | 34 +++++++++++++++++++ osu.Game/Screens/Play/SkipOverlay.cs | 2 +- .../Drawables/DrawableStoryboard.cs | 2 +- 14 files changed, 53 insertions(+), 31 deletions(-) create mode 100644 osu.Game/Screens/Play/IGameplayClock.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs index f9ed8b8721..554ea3ac90 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default private bool rotationTransferred; [Resolved(canBeNull: true)] - private GameplayClock gameplayClock { get; set; } + private IGameplayClock gameplayClock { get; set; } protected override void Update() { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index d4f3d0f390..d6c49b026e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Gameplay (typeof(ScoreProcessor), actualComponentsContainer.Dependencies.Get()), (typeof(HealthProcessor), actualComponentsContainer.Dependencies.Get()), (typeof(GameplayState), actualComponentsContainer.Dependencies.Get()), - (typeof(GameplayClock), actualComponentsContainer.Dependencies.Get()) + (typeof(IGameplayClock), actualComponentsContainer.Dependencies.Get()) }, }; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index fb97f94dbb..574f749e28 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset()); [Cached] - private readonly GameplayClock gameplayClock = new GameplayClock(new FramedClock()); + private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock()); // best way to check without exposing. private Drawable hideTarget => hudOverlay.KeyCounter; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs index 3eb92b3e97..e694b396ad 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual.Gameplay private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset()); [Cached] - private readonly GameplayClock gameplayClock = new GameplayClock(new FramedClock()); + private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock()); [SetUpSteps] public void SetUpSteps() diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs index ee2827122d..6b990ce93c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Gameplay private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset()); [Cached] - private readonly GameplayClock gameplayClock = new GameplayClock(new FramedClock()); + private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock()); private IEnumerable hudOverlays => CreatedDrawables.OfType(); diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index b4a0d83bf2..bfad22b4f0 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.UI public IFrameStableClock FrameStableClock => frameStableClock; - [Cached(typeof(GameplayClock))] + [Cached(typeof(IGameplayClock))] private readonly FrameStabilityClock frameStableClock; public FrameStabilityContainer(double gameplayStartTime = double.MinValue) @@ -64,12 +64,12 @@ namespace osu.Game.Rulesets.UI private int direction = 1; [BackgroundDependencyLoader(true)] - private void load(GameplayClock clock) + private void load(IGameplayClock clock) { if (clock != null) { parentGameplayClock = frameStableClock.ParentGameplayClock = clock; - frameStableClock.IsPaused.BindTo(clock.IsPaused); + ((IBindable)frameStableClock.IsPaused).BindTo(clock.IsPaused); } } @@ -272,7 +272,7 @@ namespace osu.Game.Rulesets.UI private class FrameStabilityClock : GameplayClock, IFrameStableClock { - public GameplayClock ParentGameplayClock; + public IGameplayClock ParentGameplayClock; public readonly Bindable IsCatchingUp = new Bindable(); diff --git a/osu.Game/Screens/Play/ComboEffects.cs b/osu.Game/Screens/Play/ComboEffects.cs index 77681401bb..442b061af7 100644 --- a/osu.Game/Screens/Play/ComboEffects.cs +++ b/osu.Game/Screens/Play/ComboEffects.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Play private ISamplePlaybackDisabler samplePlaybackDisabler { get; set; } [Resolved] - private GameplayClock gameplayClock { get; set; } + private IGameplayClock gameplayClock { get; set; } private void onComboChange(ValueChangedEvent combo) { diff --git a/osu.Game/Screens/Play/GameplayClock.cs b/osu.Game/Screens/Play/GameplayClock.cs index 6af795cfd8..454229fb31 100644 --- a/osu.Game/Screens/Play/GameplayClock.cs +++ b/osu.Game/Screens/Play/GameplayClock.cs @@ -19,15 +19,14 @@ namespace osu.Game.Screens.Play /// , as this should only be done once to ensure accuracy. /// /// - public class GameplayClock : IFrameBasedClock + public class GameplayClock : IGameplayClock { internal readonly IFrameBasedClock UnderlyingClock; public readonly BindableBool IsPaused = new BindableBool(); - /// - /// All adjustments applied to this clock which don't come from gameplay or mods. - /// + IBindable IGameplayClock.IsPaused => IsPaused; + public virtual IEnumerable> NonGameplayAdjustments => Enumerable.Empty>(); public GameplayClock(IFrameBasedClock underlyingClock) @@ -35,23 +34,12 @@ namespace osu.Game.Screens.Play UnderlyingClock = underlyingClock; } - /// - /// The time from which the clock should start. Will be seeked to on calling . - /// - /// - /// If not set, a value of zero will be used. - /// Importantly, the value will be inferred from the current ruleset in unless specified. - /// public double? StartTime { get; internal set; } public double CurrentTime => UnderlyingClock.CurrentTime; public double Rate => UnderlyingClock.Rate; - /// - /// The rate of gameplay when playback is at 100%. - /// This excludes any seeking / user adjustments. - /// public double TrueGameplayRate { get diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 2cc1fe8eaf..f7f115eddb 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -81,7 +81,7 @@ namespace osu.Game.Screens.Play { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.CacheAs(GameplayClock = CreateGameplayClock(AdjustableSource)); + dependencies.CacheAs(GameplayClock = CreateGameplayClock(AdjustableSource)); GameplayClock.StartTime = StartTime; GameplayClock.IsPaused.BindTo(IsPaused); diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index 85bb42193b..f368edbfb9 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play.HUD public bool UsesFixedAnchor { get; set; } [Resolved] - protected GameplayClock GameplayClock { get; private set; } = null!; + protected IGameplayClock GameplayClock { get; private set; } = null!; [Resolved(canBeNull: true)] private DrawableRuleset? drawableRuleset { get; set; } diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 8f10e84509..96a4c5f2bc 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -38,10 +38,10 @@ namespace osu.Game.Screens.Play.HUD set => endTime = value; } - private GameplayClock gameplayClock; + private IGameplayClock gameplayClock; [BackgroundDependencyLoader(true)] - private void load(OsuColour colours, GameplayClock clock) + private void load(OsuColour colours, IGameplayClock clock) { if (clock != null) gameplayClock = clock; diff --git a/osu.Game/Screens/Play/IGameplayClock.cs b/osu.Game/Screens/Play/IGameplayClock.cs new file mode 100644 index 0000000000..c3d61be5d5 --- /dev/null +++ b/osu.Game/Screens/Play/IGameplayClock.cs @@ -0,0 +1,34 @@ +// 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 osu.Framework.Bindables; +using osu.Framework.Timing; + +namespace osu.Game.Screens.Play +{ + public interface IGameplayClock : IFrameBasedClock + { + /// + /// The rate of gameplay when playback is at 100%. + /// This excludes any seeking / user adjustments. + /// + double TrueGameplayRate { get; } + + /// + /// The time from which the clock should start. Will be seeked to on calling . + /// + /// + /// If not set, a value of zero will be used. + /// Importantly, the value will be inferred from the current ruleset in unless specified. + /// + double? StartTime { get; } + + /// + /// All adjustments applied to this clock which don't come from gameplay or mods. + /// + IEnumerable> NonGameplayAdjustments { get; } + + IBindable IsPaused { get; } + } +} diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 3e2cf9a756..687705ff1b 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Play private bool isClickable; [Resolved] - private GameplayClock gameplayClock { get; set; } + private IGameplayClock gameplayClock { get; set; } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index 8343f14050..6295604438 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -85,7 +85,7 @@ namespace osu.Game.Storyboards.Drawables } [BackgroundDependencyLoader(true)] - private void load(GameplayClock clock, CancellationToken? cancellationToken, GameHost host, RealmAccess realm) + private void load(IGameplayClock clock, CancellationToken? cancellationToken, GameHost host, RealmAccess realm) { if (clock != null) Clock = clock; From f81c7644b40b9348bcc92bad75ae1559e0e975f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 17:36:18 +0900 Subject: [PATCH 0466/2686] Make `GameplayClockContainer` also an `IGameplayClock` and expose to remaining tests --- .../Gameplay/TestSceneStoryboardSamples.cs | 2 -- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +- .../TestSceneSkinEditorMultipleSkins.cs | 2 +- .../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +- .../Visual/Gameplay/TestSceneSongProgress.cs | 2 +- osu.Game/Screens/Play/GameplayClockContainer.cs | 17 ++++++++++++----- osu.Game/Screens/Play/Player.cs | 2 +- .../Screens/Play/ScreenSuspensionHandler.cs | 2 +- 8 files changed, 18 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index 3ccf6c5d33..18ae2cb7c8 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -77,7 +77,6 @@ namespace osu.Game.Tests.Gameplay Add(gameplayContainer = new MasterGameplayClockContainer(working, 0) { - IsPaused = { Value = true }, Child = new FrameStabilityContainer { Child = sample = new DrawableStoryboardSample(new StoryboardSampleInfo(string.Empty, 0, 1)) @@ -106,7 +105,6 @@ namespace osu.Game.Tests.Gameplay Add(gameplayContainer = new MasterGameplayClockContainer(working, start_time) { StartTime = start_time, - IsPaused = { Value = true }, Child = new FrameStabilityContainer { Child = sample = new DrawableStoryboardSample(new StoryboardSampleInfo(string.Empty, 0, 1)) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 574f749e28..3e2698bc05 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached] private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset()); - [Cached] + [Cached(typeof(IGameplayClock))] private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock()); // best way to check without exposing. diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs index e694b396ad..e29101ba8d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached] private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset()); - [Cached] + [Cached(typeof(IGameplayClock))] private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock()); [SetUpSteps] diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs index 6b990ce93c..00e4171eac 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached] private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset()); - [Cached] + [Cached(typeof(IGameplayClock))] private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock()); private IEnumerable hudOverlays => CreatedDrawables.OfType(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index 146cbfb052..3487f4dbff 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual.Gameplay Add(gameplayClockContainer = new MasterGameplayClockContainer(Beatmap.Value, skip_target_time)); - Dependencies.CacheAs(gameplayClockContainer); + Dependencies.CacheAs(gameplayClockContainer); } [SetUpSteps] diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index f7f115eddb..8400e0a9c2 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -2,6 +2,7 @@ // 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; using osu.Framework.Extensions.ObjectExtensions; @@ -15,12 +16,14 @@ namespace osu.Game.Screens.Play /// /// Encapsulates gameplay timing logic and provides a via DI for gameplay components to use. /// - public class GameplayClockContainer : Container, IAdjustableClock, IFrameBasedClock + public class GameplayClockContainer : Container, IAdjustableClock, IGameplayClock { /// /// Whether gameplay is paused. /// - public readonly BindableBool IsPaused = new BindableBool(true); + public IBindable IsPaused => isPaused; + + private readonly BindableBool isPaused = new BindableBool(true); /// /// The adjustable source clock used for gameplay. Should be used for seeks and clock control. @@ -58,6 +61,8 @@ namespace osu.Game.Screens.Play } } + public IEnumerable> NonGameplayAdjustments => GameplayClock.NonGameplayAdjustments; + /// /// The final clock which is exposed to gameplay components. /// @@ -84,7 +89,7 @@ namespace osu.Game.Screens.Play dependencies.CacheAs(GameplayClock = CreateGameplayClock(AdjustableSource)); GameplayClock.StartTime = StartTime; - GameplayClock.IsPaused.BindTo(IsPaused); + GameplayClock.IsPaused.BindTo(isPaused); return dependencies; } @@ -105,7 +110,7 @@ namespace osu.Game.Screens.Play AdjustableSource.Start(); } - IsPaused.Value = false; + isPaused.Value = false; } /// @@ -127,7 +132,7 @@ namespace osu.Game.Screens.Play /// /// Stops gameplay. /// - public void Stop() => IsPaused.Value = true; + public void Stop() => isPaused.Value = true; /// /// Resets this and the source to an initial state ready for gameplay. @@ -232,5 +237,7 @@ namespace osu.Game.Screens.Play public double FramesPerSecond => GameplayClock.FramesPerSecond; public FrameTimeInfo TimeInfo => GameplayClock.TimeInfo; + + public double TrueGameplayRate => GameplayClock.TrueGameplayRate; } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 0ef09e4029..51b2042d1b 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -330,7 +330,7 @@ namespace osu.Game.Screens.Play DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updateGameplayState()); // bind clock into components that require it - DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused); + ((IBindable)DrawableRuleset.IsPaused).BindTo(GameplayClockContainer.IsPaused); DrawableRuleset.NewResult += r => { diff --git a/osu.Game/Screens/Play/ScreenSuspensionHandler.cs b/osu.Game/Screens/Play/ScreenSuspensionHandler.cs index 59b92a1b97..cc1254975c 100644 --- a/osu.Game/Screens/Play/ScreenSuspensionHandler.cs +++ b/osu.Game/Screens/Play/ScreenSuspensionHandler.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Play public class ScreenSuspensionHandler : Component { private readonly GameplayClockContainer gameplayClockContainer; - private Bindable isPaused; + private IBindable isPaused; private readonly Bindable disableSuspensionBindable = new Bindable(); From c5f8529d20a57f198a4fb6be7c68090cef7c4fe3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 17:57:26 +0900 Subject: [PATCH 0467/2686] Mark unused methods as `NotImplemented` for safety --- osu.Game/Screens/Play/GameplayClockContainer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 8400e0a9c2..bf689dcfe1 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -209,9 +209,7 @@ namespace osu.Game.Screens.Play void IAdjustableClock.Reset() => Reset(); - public void ResetSpeedAdjustments() - { - } + public void ResetSpeedAdjustments() => throw new NotImplementedException(); double IAdjustableClock.Rate { From cc982d374cf569d645051e87249a47a46b45b2f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 18:14:57 +0900 Subject: [PATCH 0468/2686] Cache self rather than `GameplayClock` --- osu.Game/Screens/Play/GameplayClockContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index bf689dcfe1..df1eb32f99 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -86,7 +86,9 @@ namespace osu.Game.Screens.Play { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.CacheAs(GameplayClock = CreateGameplayClock(AdjustableSource)); + GameplayClock = CreateGameplayClock(AdjustableSource); + + dependencies.CacheAs(this); GameplayClock.StartTime = StartTime; GameplayClock.IsPaused.BindTo(isPaused); From be7367b90e5023004bd8352084054eaa8607911a Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 15 Aug 2022 17:52:26 +0800 Subject: [PATCH 0469/2686] Invert the dash and normal hits. --- osu.Game.Rulesets.Catch/UI/TouchInputField.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs index 3b92ffa445..771902df65 100644 --- a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs +++ b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs @@ -68,18 +68,18 @@ namespace osu.Game.Rulesets.Catch.UI Origin = Anchor.CentreLeft, Children = new Drawable[] { - leftBox = new ArrowHitbox(TouchCatchAction.MoveLeft, ref trackedActions, colours.Gray2) + leftBox = new ArrowHitbox(TouchCatchAction.MoveLeft, ref trackedActions, colours.Gray3) { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.Both, RelativePositionAxes = Axes.Both, Width = 0.5f, }, - leftDashBox = new ArrowHitbox(TouchCatchAction.DashLeft, ref trackedActions, colours.Gray3) + leftDashBox = new ArrowHitbox(TouchCatchAction.DashLeft, ref trackedActions, colours.Gray2) { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, RelativeSizeAxes = Axes.Both, RelativePositionAxes = Axes.Both, Width = 0.5f, @@ -95,18 +95,18 @@ namespace osu.Game.Rulesets.Catch.UI Origin = Anchor.CentreRight, Children = new Drawable[] { - rightBox = new ArrowHitbox(TouchCatchAction.MoveRight, ref trackedActions, colours.Gray2) + rightBox = new ArrowHitbox(TouchCatchAction.MoveRight, ref trackedActions, colours.Gray3) { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, RelativeSizeAxes = Axes.Both, RelativePositionAxes = Axes.Both, Width = 0.5f, }, - rightDashBox = new ArrowHitbox(TouchCatchAction.DashRight, ref trackedActions, colours.Gray3) + rightDashBox = new ArrowHitbox(TouchCatchAction.DashRight, ref trackedActions, colours.Gray2) { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.Both, RelativePositionAxes = Axes.Both, Width = 0.5f, From 27569e2ed5f0006d9066a05cf2f5d44cb703bc8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 18:53:10 +0900 Subject: [PATCH 0470/2686] Remove `FrameStableClock` (and redirect usages to `FrameStabilityContainer`) --- osu.Game.Tests/NonVisual/GameplayClockTest.cs | 3 +- .../Visual/Gameplay/TestSceneSpectator.cs | 2 +- osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 +- .../Rulesets/UI/FrameStabilityContainer.cs | 97 ++++++++++--------- osu.Game/Rulesets/UI/IFrameStableClock.cs | 2 - osu.Game/Screens/Play/GameplayClock.cs | 8 +- .../Screens/Play/GameplayClockContainer.cs | 2 +- osu.Game/Screens/Play/IGameplayClock.cs | 2 +- .../Play/MasterGameplayClockContainer.cs | 2 +- 9 files changed, 63 insertions(+), 57 deletions(-) diff --git a/osu.Game.Tests/NonVisual/GameplayClockTest.cs b/osu.Game.Tests/NonVisual/GameplayClockTest.cs index 5b8aacd281..162734f9da 100644 --- a/osu.Game.Tests/NonVisual/GameplayClockTest.cs +++ b/osu.Game.Tests/NonVisual/GameplayClockTest.cs @@ -4,6 +4,7 @@ #nullable disable using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Timing; @@ -30,7 +31,7 @@ namespace osu.Game.Tests.NonVisual { public List> MutableNonGameplayAdjustments { get; } = new List>(); - public override IEnumerable> NonGameplayAdjustments => MutableNonGameplayAdjustments; + public override IEnumerable NonGameplayAdjustments => MutableNonGameplayAdjustments.Select(b => b.Value); public TestGameplayClock(IFrameBasedClock underlyingClock) : base(underlyingClock) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index a42e86933f..0aa412a4fd 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -363,7 +363,7 @@ namespace osu.Game.Tests.Visual.Gameplay private Player player => Stack.CurrentScreen as Player; private double currentFrameStableTime - => player.ChildrenOfType().First().FrameStableClock.CurrentTime; + => player.ChildrenOfType().First().CurrentTime; private void waitForPlayer() => AddUntilStep("wait for player", () => (Stack.CurrentScreen as Player)?.IsLoaded == true); diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index f7f62d2af0..59c1146995 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.UI public override Container FrameStableComponents { get; } = new Container { RelativeSizeAxes = Axes.Both }; - public override IFrameStableClock FrameStableClock => frameStabilityContainer.FrameStableClock; + public override IFrameStableClock FrameStableClock => frameStabilityContainer; private bool frameStablePlayback = true; diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index bfad22b4f0..7b7003302a 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.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. -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics; @@ -21,7 +19,9 @@ namespace osu.Game.Rulesets.UI /// A container which consumes a parent gameplay clock and standardises frame counts for children. /// Will ensure a minimum of 50 frames per clock second is maintained, regardless of any system lag or seeks. /// - public class FrameStabilityContainer : Container, IHasReplayHandler + [Cached(typeof(IGameplayClock))] + [Cached(typeof(IFrameStableClock))] + public class FrameStabilityContainer : Container, IHasReplayHandler, IFrameStableClock, IGameplayClock { private readonly double gameplayStartTime; @@ -35,16 +35,17 @@ namespace osu.Game.Rulesets.UI /// internal bool FrameStablePlayback = true; - public IFrameStableClock FrameStableClock => frameStableClock; + public readonly Bindable IsCatchingUp = new Bindable(); - [Cached(typeof(IGameplayClock))] - private readonly FrameStabilityClock frameStableClock; + public readonly Bindable WaitingOnFrames = new Bindable(); + + public IBindable IsPaused { get; } = new BindableBool(); public FrameStabilityContainer(double gameplayStartTime = double.MinValue) { RelativeSizeAxes = Axes.Both; - frameStableClock = new FrameStabilityClock(framedClock = new FramedClock(manualClock = new ManualClock())); + framedClock = new FramedClock(manualClock = new ManualClock()); this.gameplayStartTime = gameplayStartTime; } @@ -53,7 +54,7 @@ namespace osu.Game.Rulesets.UI private readonly FramedClock framedClock; - private IFrameBasedClock parentGameplayClock; + private IGameplayClock? parentGameplayClock; /// /// The current direction of playback to be exposed to frame stable children. @@ -63,13 +64,13 @@ namespace osu.Game.Rulesets.UI /// private int direction = 1; - [BackgroundDependencyLoader(true)] - private void load(IGameplayClock clock) + [BackgroundDependencyLoader] + private void load(IGameplayClock? clock) { if (clock != null) { - parentGameplayClock = frameStableClock.ParentGameplayClock = clock; - ((IBindable)frameStableClock.IsPaused).BindTo(clock.IsPaused); + parentGameplayClock = clock; + IsPaused.BindTo(parentGameplayClock.IsPaused); } } @@ -111,12 +112,12 @@ namespace osu.Game.Rulesets.UI private void updateClock() { - if (frameStableClock.WaitingOnFrames.Value) + if (WaitingOnFrames.Value) { // if waiting on frames, run one update loop to determine if frames have arrived. state = PlaybackState.Valid; } - else if (frameStableClock.IsPaused.Value) + else if (IsPaused.Value) { // time should not advance while paused, nor should anything run. state = PlaybackState.NotValid; @@ -154,8 +155,8 @@ namespace osu.Game.Rulesets.UI double timeBehind = Math.Abs(proposedTime - parentGameplayClock.CurrentTime); - frameStableClock.IsCatchingUp.Value = timeBehind > 200; - frameStableClock.WaitingOnFrames.Value = state == PlaybackState.NotValid; + IsCatchingUp.Value = timeBehind > 200; + WaitingOnFrames.Value = state == PlaybackState.NotValid; manualClock.CurrentTime = proposedTime; manualClock.Rate = Math.Abs(parentGameplayClock.Rate) * direction; @@ -177,6 +178,8 @@ namespace osu.Game.Rulesets.UI /// Whether playback is still valid. private bool updateReplay(ref double proposedTime) { + Debug.Assert(ReplayInputHandler != null); + double? newTime; if (FrameStablePlayback) @@ -238,18 +241,39 @@ namespace osu.Game.Rulesets.UI private void setClock() { - if (parentGameplayClock == null) - { - // in case a parent gameplay clock isn't available, just use the parent clock. - parentGameplayClock ??= Clock; - } - else - { - Clock = frameStableClock; - } + if (parentGameplayClock != null) + Clock = this; } - public ReplayInputHandler ReplayInputHandler { get; set; } + public ReplayInputHandler? ReplayInputHandler { get; set; } + + #region Delegation of IFrameStableClock + + public double CurrentTime => framedClock.CurrentTime; + + public double Rate => framedClock.Rate; + + public bool IsRunning => framedClock.IsRunning; + + public void ProcessFrame() => framedClock.ProcessFrame(); + + public double ElapsedFrameTime => framedClock.ElapsedFrameTime; + + public double FramesPerSecond => framedClock.FramesPerSecond; + + public FrameTimeInfo TimeInfo => framedClock.TimeInfo; + + #endregion + + #region Delegation of IGameplayClock + + public double TrueGameplayRate => parentGameplayClock?.TrueGameplayRate ?? 1; + + public double? StartTime => parentGameplayClock?.StartTime; + + public IEnumerable NonGameplayAdjustments => parentGameplayClock?.NonGameplayAdjustments ?? Enumerable.Empty(); + + #endregion private enum PlaybackState { @@ -270,24 +294,7 @@ namespace osu.Game.Rulesets.UI Valid } - private class FrameStabilityClock : GameplayClock, IFrameStableClock - { - public IGameplayClock ParentGameplayClock; - - public readonly Bindable IsCatchingUp = new Bindable(); - - public readonly Bindable WaitingOnFrames = new Bindable(); - - public override IEnumerable> NonGameplayAdjustments => ParentGameplayClock?.NonGameplayAdjustments ?? Enumerable.Empty>(); - - public FrameStabilityClock(FramedClock underlyingClock) - : base(underlyingClock) - { - } - - IBindable IFrameStableClock.IsCatchingUp => IsCatchingUp; - - IBindable IFrameStableClock.WaitingOnFrames => WaitingOnFrames; - } + IBindable IFrameStableClock.IsCatchingUp => IsCatchingUp; + IBindable IFrameStableClock.WaitingOnFrames => WaitingOnFrames; } } diff --git a/osu.Game/Rulesets/UI/IFrameStableClock.cs b/osu.Game/Rulesets/UI/IFrameStableClock.cs index 132605adaf..569ef5e06c 100644 --- a/osu.Game/Rulesets/UI/IFrameStableClock.cs +++ b/osu.Game/Rulesets/UI/IFrameStableClock.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. -#nullable disable - using osu.Framework.Bindables; using osu.Framework.Timing; diff --git a/osu.Game/Screens/Play/GameplayClock.cs b/osu.Game/Screens/Play/GameplayClock.cs index 454229fb31..b650922173 100644 --- a/osu.Game/Screens/Play/GameplayClock.cs +++ b/osu.Game/Screens/Play/GameplayClock.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play IBindable IGameplayClock.IsPaused => IsPaused; - public virtual IEnumerable> NonGameplayAdjustments => Enumerable.Empty>(); + public virtual IEnumerable NonGameplayAdjustments => Enumerable.Empty(); public GameplayClock(IFrameBasedClock underlyingClock) { @@ -46,12 +46,12 @@ namespace osu.Game.Screens.Play { double baseRate = Rate; - foreach (var adjustment in NonGameplayAdjustments) + foreach (double adjustment in NonGameplayAdjustments) { - if (Precision.AlmostEquals(adjustment.Value, 0)) + if (Precision.AlmostEquals(adjustment, 0)) return 0; - baseRate /= adjustment.Value; + baseRate /= adjustment; } return baseRate; diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index df1eb32f99..27b37094ad 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -61,7 +61,7 @@ namespace osu.Game.Screens.Play } } - public IEnumerable> NonGameplayAdjustments => GameplayClock.NonGameplayAdjustments; + public IEnumerable NonGameplayAdjustments => GameplayClock.NonGameplayAdjustments; /// /// The final clock which is exposed to gameplay components. diff --git a/osu.Game/Screens/Play/IGameplayClock.cs b/osu.Game/Screens/Play/IGameplayClock.cs index c3d61be5d5..5f54ce691a 100644 --- a/osu.Game/Screens/Play/IGameplayClock.cs +++ b/osu.Game/Screens/Play/IGameplayClock.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play /// /// All adjustments applied to this clock which don't come from gameplay or mods. /// - IEnumerable> NonGameplayAdjustments { get; } + IEnumerable NonGameplayAdjustments { get; } IBindable IsPaused { get; } } diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index d7f6992fee..587d2d40a1 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -303,7 +303,7 @@ namespace osu.Game.Screens.Play private class MasterGameplayClock : GameplayClock { public readonly List> MutableNonGameplayAdjustments = new List>(); - public override IEnumerable> NonGameplayAdjustments => MutableNonGameplayAdjustments; + public override IEnumerable NonGameplayAdjustments => MutableNonGameplayAdjustments.Select(b => b.Value); public MasterGameplayClock(FramedOffsetClock underlyingClock) : base(underlyingClock) From 828b6f2c30b779d4cee1d10c798c3b9a1353d305 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 19:01:28 +0900 Subject: [PATCH 0471/2686] Remove unnecessary `setClock` shenanigans --- .../Rulesets/UI/FrameStabilityContainer.cs | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 7b7003302a..c115a0b6ac 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.UI protected override void LoadComplete() { base.LoadComplete(); - setClock(); + Clock = this; } private PlaybackState state; @@ -128,12 +128,7 @@ namespace osu.Game.Rulesets.UI state = PlaybackState.Valid; } - if (parentGameplayClock == null) - setClock(); // LoadComplete may not be run yet, but we still want the clock. - - Debug.Assert(parentGameplayClock != null); - - double proposedTime = parentGameplayClock.CurrentTime; + double proposedTime = Clock.CurrentTime; if (FrameStablePlayback) // if we require frame stability, the proposed time will be adjusted to move at most one known @@ -153,14 +148,14 @@ namespace osu.Game.Rulesets.UI if (state == PlaybackState.Valid && proposedTime != manualClock.CurrentTime) direction = proposedTime >= manualClock.CurrentTime ? 1 : -1; - double timeBehind = Math.Abs(proposedTime - parentGameplayClock.CurrentTime); + double timeBehind = Math.Abs(proposedTime - Clock.CurrentTime); IsCatchingUp.Value = timeBehind > 200; WaitingOnFrames.Value = state == PlaybackState.NotValid; manualClock.CurrentTime = proposedTime; - manualClock.Rate = Math.Abs(parentGameplayClock.Rate) * direction; - manualClock.IsRunning = parentGameplayClock.IsRunning; + manualClock.Rate = Math.Abs(Clock.Rate) * direction; + manualClock.IsRunning = Clock.IsRunning; // determine whether catch-up is required. if (state == PlaybackState.Valid && timeBehind > 0) @@ -239,12 +234,6 @@ namespace osu.Game.Rulesets.UI } } - private void setClock() - { - if (parentGameplayClock != null) - Clock = this; - } - public ReplayInputHandler? ReplayInputHandler { get; set; } #region Delegation of IFrameStableClock From 04d88b82163a9cf3895073784bfd53fb797451ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 19:17:22 +0900 Subject: [PATCH 0472/2686] Use constraint based assertions in `TestSceneFrameStabilityContainer` --- .../Visual/Gameplay/TestSceneFrameStabilityContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFrameStabilityContainer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFrameStabilityContainer.cs index 97ffbfc796..ef74024b4b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFrameStabilityContainer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFrameStabilityContainer.cs @@ -137,13 +137,13 @@ namespace osu.Game.Tests.Visual.Gameplay private void seekManualTo(double time) => AddStep($"seek manual clock to {time}", () => manualClock.CurrentTime = time); - private void confirmSeek(double time) => AddUntilStep($"wait for seek to {time}", () => consumer.Clock.CurrentTime == time); + private void confirmSeek(double time) => AddUntilStep($"wait for seek to {time}", () => consumer.Clock.CurrentTime, () => Is.EqualTo(time)); private void checkFrameCount(int frames) => - AddAssert($"elapsed frames is {frames}", () => consumer.ElapsedFrames == frames); + AddAssert($"elapsed frames is {frames}", () => consumer.ElapsedFrames, () => Is.EqualTo(frames)); private void checkRate(double rate) => - AddAssert($"clock rate is {rate}", () => consumer.Clock.Rate == rate); + AddAssert($"clock rate is {rate}", () => consumer.Clock.Rate, () => Is.EqualTo(rate)); public class ClockConsumingChild : CompositeDrawable { From 9bc2e91de01864e16711765869e264ade0cd1ae0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 19:17:41 +0900 Subject: [PATCH 0473/2686] Fix incorrect handling of reference clocks when no parent `IGameplayClock` is available --- .../Rulesets/UI/FrameStabilityContainer.cs | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index c115a0b6ac..411217e314 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -10,6 +10,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; +using osu.Framework.Utils; using osu.Game.Input.Handlers; using osu.Game.Screens.Play; @@ -56,6 +57,8 @@ namespace osu.Game.Rulesets.UI private IGameplayClock? parentGameplayClock; + private IClock referenceClock = null!; + /// /// The current direction of playback to be exposed to frame stable children. /// @@ -65,18 +68,15 @@ namespace osu.Game.Rulesets.UI private int direction = 1; [BackgroundDependencyLoader] - private void load(IGameplayClock? clock) + private void load(IGameplayClock? gameplayClock) { - if (clock != null) + if (gameplayClock != null) { - parentGameplayClock = clock; + parentGameplayClock = gameplayClock; IsPaused.BindTo(parentGameplayClock.IsPaused); } - } - protected override void LoadComplete() - { - base.LoadComplete(); + referenceClock = gameplayClock ?? Clock; Clock = this; } @@ -128,7 +128,7 @@ namespace osu.Game.Rulesets.UI state = PlaybackState.Valid; } - double proposedTime = Clock.CurrentTime; + double proposedTime = referenceClock.CurrentTime; if (FrameStablePlayback) // if we require frame stability, the proposed time will be adjusted to move at most one known @@ -148,14 +148,14 @@ namespace osu.Game.Rulesets.UI if (state == PlaybackState.Valid && proposedTime != manualClock.CurrentTime) direction = proposedTime >= manualClock.CurrentTime ? 1 : -1; - double timeBehind = Math.Abs(proposedTime - Clock.CurrentTime); + double timeBehind = Math.Abs(proposedTime - CurrentTime); IsCatchingUp.Value = timeBehind > 200; WaitingOnFrames.Value = state == PlaybackState.NotValid; manualClock.CurrentTime = proposedTime; - manualClock.Rate = Math.Abs(Clock.Rate) * direction; - manualClock.IsRunning = Clock.IsRunning; + manualClock.Rate = Math.Abs(referenceClock.Rate) * direction; + manualClock.IsRunning = referenceClock.IsRunning; // determine whether catch-up is required. if (state == PlaybackState.Valid && timeBehind > 0) @@ -244,7 +244,7 @@ namespace osu.Game.Rulesets.UI public bool IsRunning => framedClock.IsRunning; - public void ProcessFrame() => framedClock.ProcessFrame(); + public void ProcessFrame() { } public double ElapsedFrameTime => framedClock.ElapsedFrameTime; @@ -256,7 +256,23 @@ namespace osu.Game.Rulesets.UI #region Delegation of IGameplayClock - public double TrueGameplayRate => parentGameplayClock?.TrueGameplayRate ?? 1; + public double TrueGameplayRate + { + get + { + double baseRate = Rate; + + foreach (double adjustment in NonGameplayAdjustments) + { + if (Precision.AlmostEquals(adjustment, 0)) + return 0; + + baseRate /= adjustment; + } + + return baseRate; + } + } public double? StartTime => parentGameplayClock?.StartTime; From fff2b57905d75b0cb6d57f7183202e0fa80a2a4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 19:28:12 +0900 Subject: [PATCH 0474/2686] Tidy up and document `FrameStabilityContainer` --- .../Rulesets/UI/FrameStabilityContainer.cs | 97 +++++++++++-------- 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 411217e314..aa21b03b9d 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.UI [Cached(typeof(IFrameStableClock))] public class FrameStabilityContainer : Container, IHasReplayHandler, IFrameStableClock, IGameplayClock { - private readonly double gameplayStartTime; + public ReplayInputHandler? ReplayInputHandler { get; set; } /// /// The number of frames (per parent frame) which can be run in an attempt to catch-up to real-time. @@ -34,13 +34,48 @@ namespace osu.Game.Rulesets.UI /// /// Whether to enable frame-stable playback. /// - internal bool FrameStablePlayback = true; + internal bool FrameStablePlayback { get; set; } = true; - public readonly Bindable IsCatchingUp = new Bindable(); + protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && state != PlaybackState.NotValid; - public readonly Bindable WaitingOnFrames = new Bindable(); + private readonly Bindable isCatchingUp = new Bindable(); - public IBindable IsPaused { get; } = new BindableBool(); + private readonly Bindable waitingOnFrames = new Bindable(); + + private readonly double gameplayStartTime; + + private IGameplayClock? parentGameplayClock; + + /// + /// A clock which is used as reference for time, rate and running state. + /// + private IClock referenceClock = null!; + + /// + /// A local manual clock which tracks the reference clock. + /// Values are transferred from each update call. + /// + private readonly ManualClock manualClock; + + /// + /// The main framed clock which has stability applied to it. + /// This gets exposed to children as an . + /// + private readonly FramedClock framedClock; + + /// + /// The current direction of playback to be exposed to frame stable children. + /// + /// + /// Initially it is presumed that playback will proceed in the forward direction. + /// + private int direction = 1; + + private PlaybackState state; + + private bool hasReplayAttached => ReplayInputHandler != null; + + private bool firstConsumption = true; public FrameStabilityContainer(double gameplayStartTime = double.MinValue) { @@ -51,22 +86,6 @@ namespace osu.Game.Rulesets.UI this.gameplayStartTime = gameplayStartTime; } - private readonly ManualClock manualClock; - - private readonly FramedClock framedClock; - - private IGameplayClock? parentGameplayClock; - - private IClock referenceClock = null!; - - /// - /// The current direction of playback to be exposed to frame stable children. - /// - /// - /// Initially it is presumed that playback will proceed in the forward direction. - /// - private int direction = 1; - [BackgroundDependencyLoader] private void load(IGameplayClock? gameplayClock) { @@ -80,16 +99,6 @@ namespace osu.Game.Rulesets.UI Clock = this; } - private PlaybackState state; - - protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && state != PlaybackState.NotValid; - - private bool hasReplayAttached => ReplayInputHandler != null; - - private const double sixty_frame_time = 1000.0 / 60; - - private bool firstConsumption = true; - public override bool UpdateSubTree() { int loops = MaxCatchUpFrames; @@ -112,7 +121,7 @@ namespace osu.Game.Rulesets.UI private void updateClock() { - if (WaitingOnFrames.Value) + if (waitingOnFrames.Value) { // if waiting on frames, run one update loop to determine if frames have arrived. state = PlaybackState.Valid; @@ -150,8 +159,8 @@ namespace osu.Game.Rulesets.UI double timeBehind = Math.Abs(proposedTime - CurrentTime); - IsCatchingUp.Value = timeBehind > 200; - WaitingOnFrames.Value = state == PlaybackState.NotValid; + isCatchingUp.Value = timeBehind > 200; + waitingOnFrames.Value = state == PlaybackState.NotValid; manualClock.CurrentTime = proposedTime; manualClock.Rate = Math.Abs(referenceClock.Rate) * direction; @@ -211,6 +220,8 @@ namespace osu.Game.Rulesets.UI /// The time which is to be displayed. private void applyFrameStability(ref double proposedTime) { + const double sixty_frame_time = 1000.0 / 60; + if (firstConsumption) { // On the first update, frame-stability seeking would result in unexpected/unwanted behaviour. @@ -234,9 +245,9 @@ namespace osu.Game.Rulesets.UI } } - public ReplayInputHandler? ReplayInputHandler { get; set; } + #region Delegation of IGameplayClock - #region Delegation of IFrameStableClock + public IBindable IsPaused { get; } = new BindableBool(); public double CurrentTime => framedClock.CurrentTime; @@ -252,10 +263,6 @@ namespace osu.Game.Rulesets.UI public FrameTimeInfo TimeInfo => framedClock.TimeInfo; - #endregion - - #region Delegation of IGameplayClock - public double TrueGameplayRate { get @@ -280,6 +287,13 @@ namespace osu.Game.Rulesets.UI #endregion + #region Delegation of IFrameStableClock + + IBindable IFrameStableClock.IsCatchingUp => isCatchingUp; + IBindable IFrameStableClock.WaitingOnFrames => waitingOnFrames; + + #endregion + private enum PlaybackState { /// @@ -298,8 +312,5 @@ namespace osu.Game.Rulesets.UI /// Valid } - - IBindable IFrameStableClock.IsCatchingUp => IsCatchingUp; - IBindable IFrameStableClock.WaitingOnFrames => WaitingOnFrames; } } From 1fc3d005c072d3d41c493de4a47e437fd544aa3c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 19:31:01 +0900 Subject: [PATCH 0475/2686] Seal `FrameStabilityContainer` No one should ever derive from this class. It is already too complex. --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index aa21b03b9d..cdb2157c4a 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.UI /// [Cached(typeof(IGameplayClock))] [Cached(typeof(IFrameStableClock))] - public class FrameStabilityContainer : Container, IHasReplayHandler, IFrameStableClock, IGameplayClock + public sealed class FrameStabilityContainer : Container, IHasReplayHandler, IFrameStableClock, IGameplayClock { public ReplayInputHandler? ReplayInputHandler { get; set; } From 87760bbc066b7e30b0b4a2986acd7f452a53b664 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 20:16:14 +0900 Subject: [PATCH 0476/2686] Fix `IsCatchingUp` not being in correct state --- .../Gameplay/TestSceneGameplaySamplePlayback.cs | 12 +++++------- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySamplePlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySamplePlayback.cs index f1084bca5f..1fe2dfd4df 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySamplePlayback.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySamplePlayback.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -21,22 +19,22 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestAllSamplesStopDuringSeek() { - DrawableSlider slider = null; - PoolableSkinnableSample[] samples = null; - ISamplePlaybackDisabler sampleDisabler = null; + DrawableSlider? slider = null; + PoolableSkinnableSample[] samples = null!; + ISamplePlaybackDisabler sampleDisabler = null!; AddUntilStep("get variables", () => { sampleDisabler = Player; slider = Player.ChildrenOfType().MinBy(s => s.HitObject.StartTime); - samples = slider?.ChildrenOfType().ToArray(); + samples = slider.ChildrenOfType().ToArray(); return slider != null; }); AddUntilStep("wait for slider sliding then seek", () => { - if (!slider.Tracking.Value) + if (slider?.Tracking.Value != true) return false; if (!samples.Any(s => s.Playing)) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 411217e314..e75e5cc5f3 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -148,7 +148,7 @@ namespace osu.Game.Rulesets.UI if (state == PlaybackState.Valid && proposedTime != manualClock.CurrentTime) direction = proposedTime >= manualClock.CurrentTime ? 1 : -1; - double timeBehind = Math.Abs(proposedTime - CurrentTime); + double timeBehind = Math.Abs(proposedTime - referenceClock.CurrentTime); IsCatchingUp.Value = timeBehind > 200; WaitingOnFrames.Value = state == PlaybackState.NotValid; From 704568ae3b099a693b53c2c81703b77aa057a16e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 19:46:29 +0900 Subject: [PATCH 0477/2686] Remove remaining usage of `GameplayClock` --- osu.Game.Tests/NonVisual/GameplayClockTest.cs | 16 +--- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +- .../TestSceneSkinEditorMultipleSkins.cs | 2 +- .../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +- osu.Game/Screens/Play/GameplayClock.cs | 76 ------------------- .../Screens/Play/GameplayClockContainer.cs | 48 ++++++------ .../Play/MasterGameplayClockContainer.cs | 30 +++----- 7 files changed, 42 insertions(+), 134 deletions(-) delete mode 100644 osu.Game/Screens/Play/GameplayClock.cs diff --git a/osu.Game.Tests/NonVisual/GameplayClockTest.cs b/osu.Game.Tests/NonVisual/GameplayClockTest.cs index 162734f9da..9854a5731e 100644 --- a/osu.Game.Tests/NonVisual/GameplayClockTest.cs +++ b/osu.Game.Tests/NonVisual/GameplayClockTest.cs @@ -1,12 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; -using System.Linq; using NUnit.Framework; -using osu.Framework.Bindables; using osu.Framework.Timing; using osu.Game.Screens.Play; @@ -20,20 +16,16 @@ namespace osu.Game.Tests.NonVisual public void TestTrueGameplayRateWithZeroAdjustment(double underlyingClockRate) { var framedClock = new FramedClock(new ManualClock { Rate = underlyingClockRate }); - var gameplayClock = new TestGameplayClock(framedClock); - - gameplayClock.MutableNonGameplayAdjustments.Add(new BindableDouble()); + var gameplayClock = new TestGameplayClockContainer(framedClock); Assert.That(gameplayClock.TrueGameplayRate, Is.EqualTo(0)); } - private class TestGameplayClock : GameplayClock + private class TestGameplayClockContainer : GameplayClockContainer { - public List> MutableNonGameplayAdjustments { get; } = new List>(); + public override IEnumerable NonGameplayAdjustments => new[] { 0.0 }; - public override IEnumerable NonGameplayAdjustments => MutableNonGameplayAdjustments.Select(b => b.Value); - - public TestGameplayClock(IFrameBasedClock underlyingClock) + public TestGameplayClockContainer(IFrameBasedClock underlyingClock) : base(underlyingClock) { } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 3e2698bc05..da6604a653 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset()); [Cached(typeof(IGameplayClock))] - private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock()); + private readonly IGameplayClock gameplayClock = new GameplayClockContainer(new FramedClock()); // best way to check without exposing. private Drawable hideTarget => hudOverlay.KeyCounter; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs index e29101ba8d..6c02ddab14 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual.Gameplay private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset()); [Cached(typeof(IGameplayClock))] - private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock()); + private readonly IGameplayClock gameplayClock = new GameplayClockContainer(new FramedClock()); [SetUpSteps] public void SetUpSteps() diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs index 00e4171eac..485c76ac5c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Gameplay private GameplayState gameplayState = TestGameplayState.Create(new OsuRuleset()); [Cached(typeof(IGameplayClock))] - private readonly IGameplayClock gameplayClock = new GameplayClock(new FramedClock()); + private readonly IGameplayClock gameplayClock = new GameplayClockContainer(new FramedClock()); private IEnumerable hudOverlays => CreatedDrawables.OfType(); diff --git a/osu.Game/Screens/Play/GameplayClock.cs b/osu.Game/Screens/Play/GameplayClock.cs deleted file mode 100644 index b650922173..0000000000 --- a/osu.Game/Screens/Play/GameplayClock.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Bindables; -using osu.Framework.Timing; -using osu.Framework.Utils; - -namespace osu.Game.Screens.Play -{ - /// - /// A clock which is used for gameplay elements that need to follow audio time 1:1. - /// Exposed via DI by . - /// - /// The main purpose of this clock is to stop components using it from accidentally processing the main - /// , as this should only be done once to ensure accuracy. - /// - /// - public class GameplayClock : IGameplayClock - { - internal readonly IFrameBasedClock UnderlyingClock; - - public readonly BindableBool IsPaused = new BindableBool(); - - IBindable IGameplayClock.IsPaused => IsPaused; - - public virtual IEnumerable NonGameplayAdjustments => Enumerable.Empty(); - - public GameplayClock(IFrameBasedClock underlyingClock) - { - UnderlyingClock = underlyingClock; - } - - public double? StartTime { get; internal set; } - - public double CurrentTime => UnderlyingClock.CurrentTime; - - public double Rate => UnderlyingClock.Rate; - - public double TrueGameplayRate - { - get - { - double baseRate = Rate; - - foreach (double adjustment in NonGameplayAdjustments) - { - if (Precision.AlmostEquals(adjustment, 0)) - return 0; - - baseRate /= adjustment; - } - - return baseRate; - } - } - - public bool IsRunning => UnderlyingClock.IsRunning; - - public void ProcessFrame() - { - // intentionally not updating the underlying clock (handled externally). - } - - public double ElapsedFrameTime => UnderlyingClock.ElapsedFrameTime; - - public double FramesPerSecond => UnderlyingClock.FramesPerSecond; - - public FrameTimeInfo TimeInfo => UnderlyingClock.TimeInfo; - - public IClock Source => UnderlyingClock; - } -} diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 27b37094ad..468e172714 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -3,13 +3,14 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Framework.Timing; +using osu.Framework.Utils; namespace osu.Game.Screens.Play { @@ -40,8 +41,6 @@ namespace osu.Game.Screens.Play /// public event Action? OnSeek; - private double? startTime; - /// /// The time from which the clock should start. Will be seeked to on calling . /// @@ -49,24 +48,14 @@ namespace osu.Game.Screens.Play /// If not set, a value of zero will be used. /// Importantly, the value will be inferred from the current ruleset in unless specified. /// - public double? StartTime - { - get => startTime; - set - { - startTime = value; + public double? StartTime { get; set; } - if (GameplayClock.IsNotNull()) - GameplayClock.StartTime = value; - } - } - - public IEnumerable NonGameplayAdjustments => GameplayClock.NonGameplayAdjustments; + public virtual IEnumerable NonGameplayAdjustments => Enumerable.Empty(); /// /// The final clock which is exposed to gameplay components. /// - protected GameplayClock GameplayClock { get; private set; } = null!; + protected IFrameBasedClock GameplayClock { get; private set; } = null!; /// /// Creates a new . @@ -90,9 +79,6 @@ namespace osu.Game.Screens.Play dependencies.CacheAs(this); - GameplayClock.StartTime = StartTime; - GameplayClock.IsPaused.BindTo(isPaused); - return dependencies; } @@ -126,7 +112,7 @@ namespace osu.Game.Screens.Play AdjustableSource.Seek(time); // Manually process to make sure the gameplay clock is correctly updated after a seek. - GameplayClock.UnderlyingClock.ProcessFrame(); + GameplayClock.ProcessFrame(); OnSeek?.Invoke(); } @@ -174,7 +160,7 @@ namespace osu.Game.Screens.Play protected override void Update() { if (!IsPaused.Value) - GameplayClock.UnderlyingClock.ProcessFrame(); + GameplayClock.ProcessFrame(); base.Update(); } @@ -199,7 +185,7 @@ namespace osu.Game.Screens.Play /// /// The providing the source time. /// The final . - protected virtual GameplayClock CreateGameplayClock(IFrameBasedClock source) => new GameplayClock(source); + protected virtual IFrameBasedClock CreateGameplayClock(IFrameBasedClock source) => source; #region IAdjustableClock @@ -238,6 +224,22 @@ namespace osu.Game.Screens.Play public FrameTimeInfo TimeInfo => GameplayClock.TimeInfo; - public double TrueGameplayRate => GameplayClock.TrueGameplayRate; + public double TrueGameplayRate + { + get + { + double baseRate = Rate; + + foreach (double adjustment in NonGameplayAdjustments) + { + if (Precision.AlmostEquals(adjustment, 0)) + return 0; + + baseRate /= adjustment; + } + + return baseRate; + } + } } } diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 587d2d40a1..0427792392 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -54,7 +54,6 @@ namespace osu.Game.Screens.Play private HardwareCorrectionOffsetClock userGlobalOffsetClock = null!; private HardwareCorrectionOffsetClock userBeatmapOffsetClock = null!; private HardwareCorrectionOffsetClock platformOffsetClock = null!; - private MasterGameplayClock masterGameplayClock = null!; private Bindable userAudioOffset = null!; private IDisposable? beatmapOffsetSubscription; @@ -150,7 +149,7 @@ namespace osu.Game.Screens.Play // We must also process underlying gameplay clocks to update rate-adjusted offsets with the new frequency adjustment. // Without doing this, an initial seek may be performed with the wrong offset. - GameplayClock.UnderlyingClock.ProcessFrame(); + GameplayClock.ProcessFrame(); } } @@ -191,7 +190,7 @@ namespace osu.Game.Screens.Play Seek(skipTarget); } - protected override GameplayClock CreateGameplayClock(IFrameBasedClock source) + protected override IFrameBasedClock CreateGameplayClock(IFrameBasedClock source) { // Lazer's audio timings in general doesn't match stable. This is the result of user testing, albeit limited. // This only seems to be required on windows. We need to eventually figure out why, with a bit of luck. @@ -199,9 +198,7 @@ namespace osu.Game.Screens.Play // the final usable gameplay clock with user-set offsets applied. userGlobalOffsetClock = new HardwareCorrectionOffsetClock(platformOffsetClock, pauseFreqAdjust); - userBeatmapOffsetClock = new HardwareCorrectionOffsetClock(userGlobalOffsetClock, pauseFreqAdjust); - - return masterGameplayClock = new MasterGameplayClock(userBeatmapOffsetClock); + return userBeatmapOffsetClock = new HardwareCorrectionOffsetClock(userGlobalOffsetClock, pauseFreqAdjust); } /// @@ -224,8 +221,8 @@ namespace osu.Game.Screens.Play Track.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); Track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); - masterGameplayClock.MutableNonGameplayAdjustments.Add(pauseFreqAdjust); - masterGameplayClock.MutableNonGameplayAdjustments.Add(UserPlaybackRate); + nonGameplayAdjustments.Add(pauseFreqAdjust); + nonGameplayAdjustments.Add(UserPlaybackRate); speedAdjustmentsApplied = true; } @@ -238,8 +235,8 @@ namespace osu.Game.Screens.Play Track.RemoveAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); Track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); - masterGameplayClock.MutableNonGameplayAdjustments.Remove(pauseFreqAdjust); - masterGameplayClock.MutableNonGameplayAdjustments.Remove(UserPlaybackRate); + nonGameplayAdjustments.Remove(pauseFreqAdjust); + nonGameplayAdjustments.Remove(UserPlaybackRate); speedAdjustmentsApplied = false; } @@ -252,7 +249,7 @@ namespace osu.Game.Screens.Play } ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo; - IClock IBeatSyncProvider.Clock => GameplayClock; + IClock IBeatSyncProvider.Clock => this; ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; private class HardwareCorrectionOffsetClock : FramedOffsetClock @@ -300,15 +297,8 @@ namespace osu.Game.Screens.Play } } - private class MasterGameplayClock : GameplayClock - { - public readonly List> MutableNonGameplayAdjustments = new List>(); - public override IEnumerable NonGameplayAdjustments => MutableNonGameplayAdjustments.Select(b => b.Value); + private readonly List> nonGameplayAdjustments = new List>(); - public MasterGameplayClock(FramedOffsetClock underlyingClock) - : base(underlyingClock) - { - } - } + public override IEnumerable NonGameplayAdjustments => nonGameplayAdjustments.Select(b => b.Value); } } From 1696a905bace1db3a55b919fe503dc1a24d0d481 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 19:59:08 +0900 Subject: [PATCH 0478/2686] Reduce exposed properties in `GameplayClockContainer` --- ...kTest.cs => GameplayClockContainerTest.cs} | 2 +- .../Screens/Play/GameplayClockContainer.cs | 68 +++++++++---------- .../Play/MasterGameplayClockContainer.cs | 26 ++++--- 3 files changed, 50 insertions(+), 46 deletions(-) rename osu.Game.Tests/NonVisual/{GameplayClockTest.cs => GameplayClockContainerTest.cs} (96%) diff --git a/osu.Game.Tests/NonVisual/GameplayClockTest.cs b/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs similarity index 96% rename from osu.Game.Tests/NonVisual/GameplayClockTest.cs rename to osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs index 9854a5731e..f9f4ead644 100644 --- a/osu.Game.Tests/NonVisual/GameplayClockTest.cs +++ b/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs @@ -9,7 +9,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Tests.NonVisual { [TestFixture] - public class GameplayClockTest + public class GameplayClockContainerTest { [TestCase(0)] [TestCase(1)] diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 468e172714..a5d6cbf2e1 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -15,7 +15,7 @@ using osu.Framework.Utils; namespace osu.Game.Screens.Play { /// - /// Encapsulates gameplay timing logic and provides a via DI for gameplay components to use. + /// Encapsulates gameplay timing logic and provides a via DI for gameplay components to use. /// public class GameplayClockContainer : Container, IAdjustableClock, IGameplayClock { @@ -24,15 +24,8 @@ namespace osu.Game.Screens.Play /// public IBindable IsPaused => isPaused; - private readonly BindableBool isPaused = new BindableBool(true); - /// - /// The adjustable source clock used for gameplay. Should be used for seeks and clock control. - /// - protected readonly DecoupleableInterpolatingFramedClock AdjustableSource; - - /// - /// The source clock. + /// The source clock. Should generally not be used for any timekeeping purposes. /// public IClock SourceClock { get; private set; } @@ -55,7 +48,14 @@ namespace osu.Game.Screens.Play /// /// The final clock which is exposed to gameplay components. /// - protected IFrameBasedClock GameplayClock { get; private set; } = null!; + protected IFrameBasedClock FramedClock { get; private set; } = null!; + + private readonly BindableBool isPaused = new BindableBool(true); + + /// + /// The adjustable source clock used for gameplay. Should be used for seeks and clock control. + /// + private readonly DecoupleableInterpolatingFramedClock decoupledClock; /// /// Creates a new . @@ -67,7 +67,7 @@ namespace osu.Game.Screens.Play RelativeSizeAxes = Axes.Both; - AdjustableSource = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; + decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; IsPaused.BindValueChanged(OnIsPausedChanged); } @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Play { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - GameplayClock = CreateGameplayClock(AdjustableSource); + FramedClock = CreateGameplayClock(decoupledClock); dependencies.CacheAs(this); @@ -89,13 +89,13 @@ namespace osu.Game.Screens.Play { ensureSourceClockSet(); - if (!AdjustableSource.IsRunning) + if (!decoupledClock.IsRunning) { // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time // This accounts for the clock source potentially taking time to enter a completely stopped state - Seek(GameplayClock.CurrentTime); + Seek(FramedClock.CurrentTime); - AdjustableSource.Start(); + decoupledClock.Start(); } isPaused.Value = false; @@ -109,10 +109,10 @@ namespace osu.Game.Screens.Play { Logger.Log($"{nameof(GameplayClockContainer)} seeking to {time}"); - AdjustableSource.Seek(time); + decoupledClock.Seek(time); // Manually process to make sure the gameplay clock is correctly updated after a seek. - GameplayClock.ProcessFrame(); + FramedClock.ProcessFrame(); OnSeek?.Invoke(); } @@ -129,7 +129,7 @@ namespace osu.Game.Screens.Play public void Reset(bool startClock = false) { // Manually stop the source in order to not affect the IsPaused state. - AdjustableSource.Stop(); + decoupledClock.Stop(); if (!IsPaused.Value || startClock) Start(); @@ -142,10 +142,10 @@ namespace osu.Game.Screens.Play /// Changes the source clock. /// /// The new source. - protected void ChangeSource(IClock sourceClock) => AdjustableSource.ChangeSource(SourceClock = sourceClock); + protected void ChangeSource(IClock sourceClock) => decoupledClock.ChangeSource(SourceClock = sourceClock); /// - /// Ensures that the is set to , if it hasn't been given a source yet. + /// Ensures that the is set to , if it hasn't been given a source yet. /// This is usually done before a seek to avoid accidentally seeking only the adjustable source in decoupled mode, /// but not the actual source clock. /// That will pretty much only happen on the very first call of this method, as the source clock is passed in the constructor, @@ -153,38 +153,38 @@ namespace osu.Game.Screens.Play /// private void ensureSourceClockSet() { - if (AdjustableSource.Source == null) + if (decoupledClock.Source == null) ChangeSource(SourceClock); } protected override void Update() { if (!IsPaused.Value) - GameplayClock.ProcessFrame(); + FramedClock.ProcessFrame(); base.Update(); } /// - /// Invoked when the value of is changed to start or stop the clock. + /// Invoked when the value of is changed to start or stop the clock. /// /// Whether the clock should now be paused. protected virtual void OnIsPausedChanged(ValueChangedEvent isPaused) { if (isPaused.NewValue) - AdjustableSource.Stop(); + decoupledClock.Stop(); else - AdjustableSource.Start(); + decoupledClock.Start(); } /// - /// Creates the final which is exposed via DI to be used by gameplay components. + /// Creates the final which is exposed via DI to be used by gameplay components. /// /// /// Any intermediate clocks such as platform offsets should be applied here. /// /// The providing the source time. - /// The final . + /// The final . protected virtual IFrameBasedClock CreateGameplayClock(IFrameBasedClock source) => source; #region IAdjustableClock @@ -201,15 +201,15 @@ namespace osu.Game.Screens.Play double IAdjustableClock.Rate { - get => GameplayClock.Rate; + get => FramedClock.Rate; set => throw new NotSupportedException(); } - public double Rate => GameplayClock.Rate; + public double Rate => FramedClock.Rate; - public double CurrentTime => GameplayClock.CurrentTime; + public double CurrentTime => FramedClock.CurrentTime; - public bool IsRunning => GameplayClock.IsRunning; + public bool IsRunning => FramedClock.IsRunning; #endregion @@ -218,11 +218,11 @@ namespace osu.Game.Screens.Play // Handled via update. Don't process here to safeguard from external usages potentially processing frames additional times. } - public double ElapsedFrameTime => GameplayClock.ElapsedFrameTime; + public double ElapsedFrameTime => FramedClock.ElapsedFrameTime; - public double FramesPerSecond => GameplayClock.FramesPerSecond; + public double FramesPerSecond => FramedClock.FramesPerSecond; - public FrameTimeInfo TimeInfo => GameplayClock.TimeInfo; + public FrameTimeInfo TimeInfo => FramedClock.TimeInfo; public double TrueGameplayRate { diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 0427792392..ea4f767109 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -35,8 +35,6 @@ namespace osu.Game.Screens.Play /// public const double MINIMUM_SKIP_TIME = 1000; - protected Track Track => (Track)SourceClock; - public readonly BindableNumber UserPlaybackRate = new BindableDouble(1) { Default = 1, @@ -133,7 +131,7 @@ namespace osu.Game.Screens.Play this.TransformBindableTo(pauseFreqAdjust, 0, 200, Easing.Out).OnComplete(_ => { if (IsPaused.Value == isPaused.NewValue) - AdjustableSource.Stop(); + base.OnIsPausedChanged(isPaused); }); } else @@ -142,14 +140,14 @@ namespace osu.Game.Screens.Play else { if (isPaused.NewValue) - AdjustableSource.Stop(); + base.OnIsPausedChanged(isPaused); // If not yet loaded, we still want to ensure relevant state is correct, as it is used for offset calculations. pauseFreqAdjust.Value = isPaused.NewValue ? 0 : 1; // We must also process underlying gameplay clocks to update rate-adjusted offsets with the new frequency adjustment. // Without doing this, an initial seek may be performed with the wrong offset. - GameplayClock.ProcessFrame(); + FramedClock.ProcessFrame(); } } @@ -178,12 +176,12 @@ namespace osu.Game.Screens.Play /// public void Skip() { - if (GameplayClock.CurrentTime > skipTargetTime - MINIMUM_SKIP_TIME) + if (FramedClock.CurrentTime > skipTargetTime - MINIMUM_SKIP_TIME) return; double skipTarget = skipTargetTime - MINIMUM_SKIP_TIME; - if (GameplayClock.CurrentTime < 0 && skipTarget > 6000) + if (FramedClock.CurrentTime < 0 && skipTarget > 6000) // double skip exception for storyboards with very long intros skipTarget = 0; @@ -218,8 +216,11 @@ namespace osu.Game.Screens.Play if (speedAdjustmentsApplied) return; - Track.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); - Track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); + if (SourceClock is Track track) + { + track.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); + track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); + } nonGameplayAdjustments.Add(pauseFreqAdjust); nonGameplayAdjustments.Add(UserPlaybackRate); @@ -232,8 +233,11 @@ namespace osu.Game.Screens.Play if (!speedAdjustmentsApplied) return; - Track.RemoveAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); - Track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); + if (SourceClock is Track track) + { + track.RemoveAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); + track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); + } nonGameplayAdjustments.Remove(pauseFreqAdjust); nonGameplayAdjustments.Remove(UserPlaybackRate); From 61a8873266d5345b22163a8aaaac26bdeacadd92 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 15 Aug 2022 20:09:07 +0900 Subject: [PATCH 0479/2686] Ensure `GameplayClockContainer`'s `FramedClock` is always non-null --- osu.Game/Screens/Play/GameplayClockContainer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index a5d6cbf2e1..ac846b45c4 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Play /// /// The final clock which is exposed to gameplay components. /// - protected IFrameBasedClock FramedClock { get; private set; } = null!; + protected IFrameBasedClock FramedClock { get; private set; } private readonly BindableBool isPaused = new BindableBool(true); @@ -69,6 +69,9 @@ namespace osu.Game.Screens.Play decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; IsPaused.BindValueChanged(OnIsPausedChanged); + + // this will be replaced during load, but non-null for tests which don't add this component to the hierarchy. + FramedClock = new FramedClock(); } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) From 502e31dd37b3b8be70aeb55b0efde4e51e15244a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Aug 2022 21:26:54 +0900 Subject: [PATCH 0480/2686] General refactoring --- .../Preprocessing/Colour/Data/MonoEncoding.cs | 1 - .../TaikoColourDifficultyPreprocessor.cs | 79 ++++++++----------- .../Colour/TaikoDifficultyHitObjectColour.cs | 9 +-- .../Preprocessing/TaikoDifficultyHitObject.cs | 43 +++++----- .../Difficulty/Skills/Colour.cs | 2 - .../Difficulty/Skills/Peaks.cs | 2 - 6 files changed, 57 insertions(+), 79 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs index 7eee8896ac..0e998696f9 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs @@ -15,7 +15,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { /// /// List of s that are encoded within this . - /// This is not declared as to avoid circular dependencies. /// public List EncodedData { get; private set; } = new List(); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 517e240682..7b7fab26b1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -9,8 +9,7 @@ using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { /// - /// Utility class to perform various encodings. This is separated out from the encoding classes to prevent circular - /// dependencies. + /// Utility class to perform various encodings. /// public class TaikoColourDifficultyPreprocessor { @@ -26,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour // Assign indexing and encoding data to all relevant objects. Only the first note of each encoding type is // assigned with the relevant encodings. - encodings.ForEach(coupledEncoding => + foreach (var coupledEncoding in encodings) { coupledEncoding.Payload[0].Payload[0].EncodedData[0].Colour.CoupledColourEncoding = coupledEncoding; @@ -48,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour monoEncoding.EncodedData[0].Colour.MonoEncoding = monoEncoding; } } - }); + } return colours; } @@ -58,35 +57,29 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// public static List EncodeMono(List data) { - List encoded = new List(); - - MonoEncoding? lastEncoded = null; + List encodings = new List(); + MonoEncoding? currentEncoding = null; for (int i = 0; i < data.Count; i++) { TaikoDifficultyHitObject taikoObject = (TaikoDifficultyHitObject)data[i]; + // This ignores all non-note objects, which may or may not be the desired behaviour TaikoDifficultyHitObject? previousObject = taikoObject.PreviousNote(0); - // If the colour changed or if this is the first object in the run, create a new mono encoding - if - ( - previousObject == null || // First object in the list - (taikoObject.BaseObject as Hit)?.Type != (previousObject.BaseObject as Hit)?.Type - ) + // If this is the first object in the list or the colour changed, create a new mono encoding + if (currentEncoding == null || (taikoObject.BaseObject as Hit)?.Type != (previousObject?.BaseObject as Hit)?.Type) { - lastEncoded = new MonoEncoding(); - lastEncoded.EncodedData.Add(taikoObject); - encoded.Add(lastEncoded); + currentEncoding = new MonoEncoding(); + encodings.Add(currentEncoding); continue; } - // If we're here, we're in the same encoding as the previous object, thus lastEncoded is not null. // Add the current object to the encoded payload. - lastEncoded!.EncodedData.Add(taikoObject); + currentEncoding.EncodedData.Add(taikoObject); } - return encoded; + return encodings; } /// @@ -94,27 +87,24 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// public static List EncodeColour(List data) { - List encoded = new List(); - ColourEncoding? lastEncoded = null; + List encodings = new List(); + ColourEncoding? currentEncoding = null; for (int i = 0; i < data.Count; i++) { - // Starts a new ColourEncoding if the previous MonoEncoding has a different mono length, or if this is - // the first MonoEncoding in the list. - if (lastEncoded == null || data[i].RunLength != data[i - 1].RunLength) + // Start a new ColourEncoding if the previous MonoEncoding has a different mono length, or if this is the first MonoEncoding in the list. + if (currentEncoding == null || data[i].RunLength != data[i - 1].RunLength) { - lastEncoded = new ColourEncoding(); - lastEncoded.Payload.Add(data[i]); - encoded.Add(lastEncoded); + currentEncoding = new ColourEncoding(); + encodings.Add(currentEncoding); continue; } - // If we're here, we're in the same encoding as the previous object. Add the current MonoEncoding to the - // encoded payload. - lastEncoded.Payload.Add(data[i]); + // Add the current MonoEncoding to the encoded payload. + currentEncoding.Payload.Add(data[i]); } - return encoded; + return encodings; } /// @@ -122,16 +112,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// public static List EncodeCoupledColour(List data) { - List encoded = new List(); - CoupledColourEncoding? lastEncoded = null; + List encodings = new List(); + CoupledColourEncoding? currentEncoding = null; for (int i = 0; i < data.Count; i++) { - // Starts a new CoupledColourEncoding. ColourEncodings that should be grouped together will be handled - // later within this loop. - lastEncoded = new CoupledColourEncoding + // Start a new CoupledColourEncoding. ColourEncodings that should be grouped together will be handled later within this loop. + currentEncoding = new CoupledColourEncoding { - Previous = lastEncoded + Previous = currentEncoding }; // Determine if future ColourEncodings should be grouped. @@ -140,7 +129,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour if (!isCoupled) { // If not, add the current ColourEncoding to the encoded payload and continue. - lastEncoded.Payload.Add(data[i]); + currentEncoding.Payload.Add(data[i]); } else { @@ -148,27 +137,27 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour // subsequent ColourEncodings should be grouped by increasing i and doing the appropriate isCoupled check. while (isCoupled) { - lastEncoded.Payload.Add(data[i]); + currentEncoding.Payload.Add(data[i]); i++; isCoupled = i < data.Count - 2 && data[i].IsRepetitionOf(data[i + 2]); } // Skip over viewed data and add the rest to the payload - lastEncoded.Payload.Add(data[i]); - lastEncoded.Payload.Add(data[i + 1]); + currentEncoding.Payload.Add(data[i]); + currentEncoding.Payload.Add(data[i + 1]); i++; } - encoded.Add(lastEncoded); + encodings.Add(currentEncoding); } // Final pass to find repetition intervals - for (int i = 0; i < encoded.Count; i++) + for (int i = 0; i < encodings.Count; i++) { - encoded[i].FindRepetitionInterval(); + encodings[i].FindRepetitionInterval(); } - return encoded; + return encodings; } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs index 6a6b427393..41080eeb33 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs @@ -11,20 +11,17 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour public class TaikoDifficultyHitObjectColour { /// - /// encoding that encodes this note, only present if this is the first note within a - /// + /// The that encodes this note, only present if this is the first note within a /// public MonoEncoding? MonoEncoding; /// - /// encoding that encodes this note, only present if this is the first note within - /// a + /// The that encodes this note, only present if this is the first note within a /// public ColourEncoding? ColourEncoding; /// - /// encoding that encodes this note, only present if this is the first note - /// within a + /// The that encodes this note, only present if this is the first note within a /// public CoupledColourEncoding? CoupledColourEncoding; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index fd9a225f6a..e7a8abfd38 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -45,9 +45,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// /// Colour data for this hit object. This is used by colour evaluator to calculate colour difficulty, but can be used /// by other skills in the future. - /// This need to be writeable by TaikoDifficultyHitObjectColour so that it can assign potentially reused instances /// - public TaikoDifficultyHitObjectColour Colour; + public readonly TaikoDifficultyHitObjectColour Colour; /// /// Creates a new difficulty hit object. @@ -59,7 +58,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing /// The list of all s in the current beatmap. /// The list of centre (don) s in the current beatmap. /// The list of rim (kat) s in the current beatmap. - /// The list of s that is a hit (i.e. not a slider or spinner) in the current beatmap. + /// The list of s that is a hit (i.e. not a drumroll or swell) in the current beatmap. /// The position of this in the list. public TaikoDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject lastLastObject, double clockRate, List objects, @@ -68,33 +67,31 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing List noteObjects, int index) : base(hitObject, lastObject, clockRate, objects, index) { - // Create the Colour object, its properties should be filled in by TaikoDifficultyPreprocessor - Colour = new TaikoDifficultyHitObjectColour(); - - var currentHit = hitObject as Hit; noteDifficultyHitObjects = noteObjects; + // Create the Colour object, its properties should be filled in by TaikoDifficultyPreprocessor + Colour = new TaikoDifficultyHitObjectColour(); Rhythm = getClosestRhythm(lastObject, lastLastObject, clockRate); - HitType? hitType = currentHit?.Type; - if (hitType == HitType.Centre) + switch ((hitObject as Hit)?.Type) { - MonoIndex = centreHitObjects.Count; - centreHitObjects.Add(this); - monoDifficultyHitObjects = centreHitObjects; - } - else if (hitType == HitType.Rim) - { - MonoIndex = rimHitObjects.Count; - rimHitObjects.Add(this); - monoDifficultyHitObjects = rimHitObjects; - } + case HitType.Centre: + MonoIndex = centreHitObjects.Count; + centreHitObjects.Add(this); + monoDifficultyHitObjects = centreHitObjects; + break; - // Need to be done after HitType is set. - if (hitType == null) return; + case HitType.Rim: + MonoIndex = rimHitObjects.Count; + rimHitObjects.Add(this); + monoDifficultyHitObjects = rimHitObjects; + break; - NoteIndex = noteObjects.Count; - noteObjects.Add(this); + default: + NoteIndex = noteObjects.Count; + noteObjects.Add(this); + break; + } } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index 386135ea4d..dac0beadda 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.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. -#nullable disable - using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs index 3e3bc543e1..ec8e754c5c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Peaks.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; From 94c6beeaf7c465ff22b229863388701f94b71314 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Aug 2022 21:30:40 +0900 Subject: [PATCH 0481/2686] Use ctor in a place that looks visually weird I read through this thinking "why doesn't Previous get assigned to currentEncoding here? But it's because the initializer runs right after the ctor and before the "method" returns. So really there's 3 operations running on one line here - ctor, init, and assignment. --- .../Preprocessing/Colour/Data/ColourEncoding.cs | 2 +- .../Preprocessing/Colour/Data/CoupledColourEncoding.cs | 9 +++++++-- .../Colour/TaikoColourDifficultyPreprocessor.cs | 5 +---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs index 04066e7539..cd39a3d232 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// /// s that are grouped together within this . /// - public List Payload { get; private set; } = new List(); + public readonly List Payload = new List(); /// /// The parent that contains this diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs index 9d204225fc..1b831eedd8 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs @@ -20,12 +20,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// /// The s that are grouped together within this . /// - public List Payload = new List(); + public readonly List Payload = new List(); /// /// The previous . This is used to determine the repetition interval. /// - public CoupledColourEncoding? Previous = null; + public readonly CoupledColourEncoding? Previous; /// /// How many between the current and previous identical . @@ -33,6 +33,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public int RepetitionInterval { get; private set; } = max_repetition_interval + 1; + public CoupledColourEncoding(CoupledColourEncoding? previous) + { + Previous = previous; + } + /// /// Returns true if other is considered a repetition of this encoding. This is true if other's first two payloads /// have identical mono lengths. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 7b7fab26b1..2d69f5fe35 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -118,10 +118,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour for (int i = 0; i < data.Count; i++) { // Start a new CoupledColourEncoding. ColourEncodings that should be grouped together will be handled later within this loop. - currentEncoding = new CoupledColourEncoding - { - Previous = currentEncoding - }; + currentEncoding = new CoupledColourEncoding(currentEncoding); // Determine if future ColourEncodings should be grouped. bool isCoupled = i < data.Count - 2 && data[i].IsRepetitionOf(data[i + 2]); From 21d29980329a4ff4b114abb3cf4430ee3e7eff8d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Aug 2022 21:35:34 +0900 Subject: [PATCH 0482/2686] Privatise internals of TaikoColourDifficultyPreprocessor --- .../TaikoColourDifficultyPreprocessor.cs | 34 +++++++++---------- .../TaikoDifficultyPreprocessor.cs | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 2d69f5fe35..2b047a4336 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// /// Utility class to perform various encodings. /// - public class TaikoColourDifficultyPreprocessor + public static class TaikoColourDifficultyPreprocessor { /// /// Processes and encodes a list of s into a list of s, @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour public static List ProcessAndAssign(List hitObjects) { List colours = new List(); - List encodings = Encode(hitObjects); + List encodings = encode(hitObjects); // Assign indexing and encoding data to all relevant objects. Only the first note of each encoding type is // assigned with the relevant encodings. @@ -52,10 +52,22 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour return colours; } + /// + /// Encodes a list of s into a list of s. + /// + private static List encode(List data) + { + List firstPass = encodeMono(data); + List secondPass = encodeColour(firstPass); + List thirdPass = encodeCoupledColour(secondPass); + + return thirdPass; + } + /// /// Encodes a list of s into a list of s. /// - public static List EncodeMono(List data) + private static List encodeMono(List data) { List encodings = new List(); MonoEncoding? currentEncoding = null; @@ -85,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// /// Encodes a list of s into a list of s. /// - public static List EncodeColour(List data) + private static List encodeColour(List data) { List encodings = new List(); ColourEncoding? currentEncoding = null; @@ -110,7 +122,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// /// Encodes a list of s into a list of s. /// - public static List EncodeCoupledColour(List data) + private static List encodeCoupledColour(List data) { List encodings = new List(); CoupledColourEncoding? currentEncoding = null; @@ -156,17 +168,5 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour return encodings; } - - /// - /// Encodes a list of s into a list of s. - /// - public static List Encode(List data) - { - List firstPass = EncodeMono(data); - List secondPass = EncodeColour(firstPass); - List thirdPass = EncodeCoupledColour(secondPass); - - return thirdPass; - } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs index c5ee8de809..2223c8e2d1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing { - public class TaikoDifficultyPreprocessor + public static class TaikoDifficultyPreprocessor { /// /// Does preprocessing on a list of s. From 78283ce3c5993133c227c1113e8891e0b03fb4ab Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Aug 2022 21:38:40 +0900 Subject: [PATCH 0483/2686] Remove TaikoDifficultyPreprocessor --- .../TaikoColourDifficultyPreprocessor.cs | 5 +---- .../TaikoDifficultyPreprocessor.cs | 21 ------------------- .../Difficulty/TaikoDifficultyCalculator.cs | 5 ++++- 3 files changed, 5 insertions(+), 26 deletions(-) delete mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 2b047a4336..38d51aef91 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -18,9 +18,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// assigning the appropriate s to each , /// and pre-evaluating colour difficulty of each . /// - public static List ProcessAndAssign(List hitObjects) + public static void ProcessAndAssign(List hitObjects) { - List colours = new List(); List encodings = encode(hitObjects); // Assign indexing and encoding data to all relevant objects. Only the first note of each encoding type is @@ -48,8 +47,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour } } } - - return colours; } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs deleted file mode 100644 index 2223c8e2d1..0000000000 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyPreprocessor.cs +++ /dev/null @@ -1,21 +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.Collections.Generic; -using osu.Game.Rulesets.Difficulty.Preprocessing; -using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; - -namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing -{ - public static class TaikoDifficultyPreprocessor - { - /// - /// Does preprocessing on a list of s. - /// - public static List Process(List difficultyHitObjects) - { - TaikoColourDifficultyPreprocessor.ProcessAndAssign(difficultyHitObjects); - return difficultyHitObjects; - } - } -} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index ceaa3c56b5..ea2f04a3d9 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour; using osu.Game.Rulesets.Taiko.Difficulty.Skills; using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Rulesets.Taiko.Objects; @@ -63,7 +64,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty ); } - return TaikoDifficultyPreprocessor.Process(difficultyHitObjects); + TaikoColourDifficultyPreprocessor.ProcessAndAssign(difficultyHitObjects); + + return difficultyHitObjects; } protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) From 4d4ee05981ca32f09d6a4c1996b8a765705821f5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Aug 2022 21:48:04 +0900 Subject: [PATCH 0484/2686] Whoops I meant to remove these --- .../Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 38d51aef91..0d1d3cd7a9 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -81,7 +81,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { currentEncoding = new MonoEncoding(); encodings.Add(currentEncoding); - continue; } // Add the current object to the encoded payload. @@ -106,7 +105,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { currentEncoding = new ColourEncoding(); encodings.Add(currentEncoding); - continue; } // Add the current MonoEncoding to the encoded payload. From c03e47317a30cd9ac914f481cbb71677586eac72 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Aug 2022 21:54:23 +0900 Subject: [PATCH 0485/2686] Fix notes not being added to list --- .../Difficulty/Preprocessing/TaikoDifficultyHitObject.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs index e7a8abfd38..4aaee50c18 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObject.cs @@ -86,11 +86,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing rimHitObjects.Add(this); monoDifficultyHitObjects = rimHitObjects; break; + } - default: - NoteIndex = noteObjects.Count; - noteObjects.Add(this); - break; + if (hitObject is Hit) + { + NoteIndex = noteObjects.Count; + noteObjects.Add(this); } } From 8e0049c00548ef64c7faee7ed480370c274efe95 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 15 Aug 2022 21:57:35 +0900 Subject: [PATCH 0486/2686] Add back null check --- .../Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 0d1d3cd7a9..81ba219bc0 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour TaikoDifficultyHitObject? previousObject = taikoObject.PreviousNote(0); // If this is the first object in the list or the colour changed, create a new mono encoding - if (currentEncoding == null || (taikoObject.BaseObject as Hit)?.Type != (previousObject?.BaseObject as Hit)?.Type) + if (currentEncoding == null || previousObject == null || (taikoObject.BaseObject as Hit)?.Type != (previousObject.BaseObject as Hit)?.Type) { currentEncoding = new MonoEncoding(); encodings.Add(currentEncoding); From 797a8da996cd16aa5e0543a9b4482a4ba2483df1 Mon Sep 17 00:00:00 2001 From: its5Q Date: Tue, 16 Aug 2022 01:14:16 +1000 Subject: [PATCH 0487/2686] Replace osu-web strings with new strings and merge to single file --- .../Localisation/EditorSetupColoursStrings.cs | 24 --- .../Localisation/EditorSetupDesignStrings.cs | 84 -------- .../EditorSetupDifficultyStrings.cs | 34 ---- .../EditorSetupMetadataStrings.cs | 39 ---- .../EditorSetupResourcesStrings.cs | 44 ----- .../Localisation/EditorSetupRulesetStrings.cs | 19 -- osu.Game/Localisation/EditorSetupStrings.cs | 180 ++++++++++++++++++ osu.Game/Screens/Edit/Setup/ColoursSection.cs | 8 +- osu.Game/Screens/Edit/Setup/DesignSection.cs | 28 +-- .../Screens/Edit/Setup/DifficultySection.cs | 10 +- .../Screens/Edit/Setup/MetadataSection.cs | 14 +- .../Screens/Edit/Setup/ResourcesSection.cs | 12 +- .../Screens/Edit/Setup/RulesetSetupSection.cs | 2 +- 13 files changed, 216 insertions(+), 282 deletions(-) delete mode 100644 osu.Game/Localisation/EditorSetupColoursStrings.cs delete mode 100644 osu.Game/Localisation/EditorSetupDesignStrings.cs delete mode 100644 osu.Game/Localisation/EditorSetupDifficultyStrings.cs delete mode 100644 osu.Game/Localisation/EditorSetupMetadataStrings.cs delete mode 100644 osu.Game/Localisation/EditorSetupResourcesStrings.cs delete mode 100644 osu.Game/Localisation/EditorSetupRulesetStrings.cs diff --git a/osu.Game/Localisation/EditorSetupColoursStrings.cs b/osu.Game/Localisation/EditorSetupColoursStrings.cs deleted file mode 100644 index e08240a7d2..0000000000 --- a/osu.Game/Localisation/EditorSetupColoursStrings.cs +++ /dev/null @@ -1,24 +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.Localisation; - -namespace osu.Game.Localisation -{ - public static class EditorSetupColoursStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupColours"; - - /// - /// "Colours" - /// - public static LocalisableString Colours => new TranslatableString(getKey(@"colours"), @"Colours"); - - /// - /// "Hitcircle / Slider Combos" - /// - public static LocalisableString HitcircleSliderCombos => new TranslatableString(getKey(@"hitcircle_slider_combos"), @"Hitcircle / Slider Combos"); - - private static string getKey(string key) => $@"{prefix}:{key}"; - } -} diff --git a/osu.Game/Localisation/EditorSetupDesignStrings.cs b/osu.Game/Localisation/EditorSetupDesignStrings.cs deleted file mode 100644 index 0a5e383b76..0000000000 --- a/osu.Game/Localisation/EditorSetupDesignStrings.cs +++ /dev/null @@ -1,84 +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.Localisation; - -namespace osu.Game.Localisation -{ - public static class EditorSetupDesignStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupDesign"; - - /// - /// "Design" - /// - public static LocalisableString Design => new TranslatableString(getKey(@"design"), @"Design"); - - /// - /// "Enable countdown" - /// - public static LocalisableString EnableCountdown => new TranslatableString(getKey(@"enable_countdown"), @"Enable countdown"); - - /// - /// "If enabled, an "Are you ready? 3, 2, 1, GO!" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so." - /// - public static LocalisableString CountdownDescription => new TranslatableString(getKey(@"countdown_description"), @"If enabled, an ""Are you ready? 3, 2, 1, GO!"" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so."); - - /// - /// "Countdown speed" - /// - public static LocalisableString CountdownSpeed => new TranslatableString(getKey(@"countdown_speed"), @"Countdown speed"); - - /// - /// "If the countdown sounds off-time, use this to make it appear one or more beats early." - /// - public static LocalisableString CountdownOffsetDescription => new TranslatableString(getKey(@"countdown_offset_description"), @"If the countdown sounds off-time, use this to make it appear one or more beats early."); - - /// - /// "Countdown offset" - /// - public static LocalisableString CountdownOffset => new TranslatableString(getKey(@"countdown_offset"), @"Countdown offset"); - - /// - /// "Widescreen support" - /// - public static LocalisableString WidescreenSupport => new TranslatableString(getKey(@"widescreen_support"), @"Widescreen support"); - - /// - /// "Allows storyboards to use the full screen space, rather than be confined to a 4:3 area." - /// - public static LocalisableString WidescreenSupportDescription => new TranslatableString(getKey(@"widescreen_support_description"), @"Allows storyboards to use the full screen space, rather than be confined to a 4:3 area."); - - /// - /// "Epilepsy warning" - /// - public static LocalisableString EpilepsyWarning => new TranslatableString(getKey(@"epilepsy_warning"), @"Epilepsy warning"); - - /// - /// "Recommended if the storyboard or video contain scenes with rapidly flashing colours." - /// - public static LocalisableString EpilepsyWarningDescription => new TranslatableString(getKey(@"epilepsy_warning_description"), @"Recommended if the storyboard or video contain scenes with rapidly flashing colours."); - - /// - /// "Letterbox during breaks" - /// - public static LocalisableString LetterboxDuringBreaks => new TranslatableString(getKey(@"letterbox_during_breaks"), @"Letterbox during breaks"); - - /// - /// "Adds horizontal letterboxing to give a cinematic look during breaks." - /// - public static LocalisableString LetterboxDuringBreaksDescription => new TranslatableString(getKey(@"letterbox_during_breaks_description"), @"Adds horizontal letterboxing to give a cinematic look during breaks."); - - /// - /// "Samples match playback rate" - /// - public static LocalisableString SamplesMatchPlaybackRate => new TranslatableString(getKey(@"samples_match_playback_rate"), @"Samples match playback rate"); - - /// - /// "When enabled, all samples will speed up or slow down when rate-changing mods are enabled." - /// - public static LocalisableString SamplesMatchPlaybackRateDescription => new TranslatableString(getKey(@"samples_match_playback_rate_description"), @"When enabled, all samples will speed up or slow down when rate-changing mods are enabled."); - - private static string getKey(string key) => $@"{prefix}:{key}"; - } -} diff --git a/osu.Game/Localisation/EditorSetupDifficultyStrings.cs b/osu.Game/Localisation/EditorSetupDifficultyStrings.cs deleted file mode 100644 index cdb7837a64..0000000000 --- a/osu.Game/Localisation/EditorSetupDifficultyStrings.cs +++ /dev/null @@ -1,34 +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.Localisation; - -namespace osu.Game.Localisation -{ - public static class EditorSetupDifficultyStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupDifficulty"; - - /// - /// "The size of all hit objects" - /// - public static LocalisableString CircleSizeDescription => new TranslatableString(getKey(@"circle_size_description"), @"The size of all hit objects"); - - /// - /// "The rate of passive health drain throughout playable time" - /// - public static LocalisableString DrainRateDescription => new TranslatableString(getKey(@"drain_rate_description"), @"The rate of passive health drain throughout playable time"); - - /// - /// "The speed at which objects are presented to the player" - /// - public static LocalisableString ApproachRateDescription => new TranslatableString(getKey(@"approach_rate_description"), @"The speed at which objects are presented to the player"); - - /// - /// "The harshness of hit windows and difficulty of special objects (ie. spinners)" - /// - public static LocalisableString OverallDifficultyDescription => new TranslatableString(getKey(@"overall_difficulty_description"), @"The harshness of hit windows and difficulty of special objects (ie. spinners)"); - - private static string getKey(string key) => $@"{prefix}:{key}"; - } -} diff --git a/osu.Game/Localisation/EditorSetupMetadataStrings.cs b/osu.Game/Localisation/EditorSetupMetadataStrings.cs deleted file mode 100644 index 576fa68643..0000000000 --- a/osu.Game/Localisation/EditorSetupMetadataStrings.cs +++ /dev/null @@ -1,39 +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.Localisation; - -namespace osu.Game.Localisation -{ - public static class EditorSetupMetadataStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupMetadata"; - - /// - /// "Metadata" - /// - public static LocalisableString Metadata => new TranslatableString(getKey(@"metadata"), @"Metadata"); - - /// - /// "Romanised Artist" - /// - public static LocalisableString RomanisedArtist => new TranslatableString(getKey(@"romanised_artist"), @"Romanised Artist"); - - /// - /// "Romanised Title" - /// - public static LocalisableString RomanisedTitle => new TranslatableString(getKey(@"romanised_title"), @"Romanised Title"); - - /// - /// "Creator" - /// - public static LocalisableString Creator => new TranslatableString(getKey(@"creator"), @"Creator"); - - /// - /// "Difficulty Name" - /// - public static LocalisableString DifficultyName => new TranslatableString(getKey(@"difficulty_name"), @"Difficulty Name"); - - private static string getKey(string key) => $@"{prefix}:{key}"; - } -} diff --git a/osu.Game/Localisation/EditorSetupResourcesStrings.cs b/osu.Game/Localisation/EditorSetupResourcesStrings.cs deleted file mode 100644 index 493beae7fe..0000000000 --- a/osu.Game/Localisation/EditorSetupResourcesStrings.cs +++ /dev/null @@ -1,44 +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.Localisation; - -namespace osu.Game.Localisation -{ - public static class EditorSetupResourcesStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupResources"; - - /// - /// "Resources" - /// - public static LocalisableString Resources => new TranslatableString(getKey(@"resources"), @"Resources"); - - /// - /// "Audio Track" - /// - public static LocalisableString AudioTrack => new TranslatableString(getKey(@"audio_track"), @"Audio Track"); - - /// - /// "Click to select a track" - /// - public static LocalisableString ClickToSelectTrack => new TranslatableString(getKey(@"click_to_select_track"), @"Click to select a track"); - - /// - /// "Click to replace the track" - /// - public static LocalisableString ClickToReplaceTrack => new TranslatableString(getKey(@"click_to_replace_track"), @"Click to replace the track"); - - /// - /// "Click to select a background image" - /// - public static LocalisableString ClickToSelectBackground => new TranslatableString(getKey(@"click_to_select_background"), @"Click to select a background image"); - - /// - /// "Click to replace the background image" - /// - public static LocalisableString ClickToReplaceBackground => new TranslatableString(getKey(@"click_to_replace_background"), @"Click to replace the background image"); - - private static string getKey(string key) => $@"{prefix}:{key}"; - } -} diff --git a/osu.Game/Localisation/EditorSetupRulesetStrings.cs b/osu.Game/Localisation/EditorSetupRulesetStrings.cs deleted file mode 100644 index a786b679a3..0000000000 --- a/osu.Game/Localisation/EditorSetupRulesetStrings.cs +++ /dev/null @@ -1,19 +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.Localisation; - -namespace osu.Game.Localisation -{ - public static class EditorSetupRulesetStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.EditorSetupRuleset"; - - /// - /// "Ruleset ({0})" - /// - public static LocalisableString Ruleset(string arg0) => new TranslatableString(getKey(@"ruleset"), @"Ruleset ({0})", arg0); - - private static string getKey(string key) => $@"{prefix}:{key}"; - } -} diff --git a/osu.Game/Localisation/EditorSetupStrings.cs b/osu.Game/Localisation/EditorSetupStrings.cs index 97ebd40b6f..9512f3ff14 100644 --- a/osu.Game/Localisation/EditorSetupStrings.cs +++ b/osu.Game/Localisation/EditorSetupStrings.cs @@ -19,6 +19,186 @@ namespace osu.Game.Localisation /// public static LocalisableString BeatmapSetupDescription => new TranslatableString(getKey(@"beatmap_setup_description"), @"change general settings of your beatmap"); + /// + /// "Colours" + /// + public static LocalisableString ColoursHeader => new TranslatableString(getKey(@"colours_header"), @"Colours"); + + /// + /// "Hitcircle / Slider Combos" + /// + public static LocalisableString HitcircleSliderCombos => new TranslatableString(getKey(@"hitcircle_slider_combos"), @"Hitcircle / Slider Combos"); + + /// + /// "Design" + /// + public static LocalisableString DesignHeader => new TranslatableString(getKey(@"design_header"), @"Design"); + + /// + /// "Enable countdown" + /// + public static LocalisableString EnableCountdown => new TranslatableString(getKey(@"enable_countdown"), @"Enable countdown"); + + /// + /// "If enabled, an "Are you ready? 3, 2, 1, GO!" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so." + /// + public static LocalisableString CountdownDescription => new TranslatableString(getKey(@"countdown_description"), @"If enabled, an ""Are you ready? 3, 2, 1, GO!"" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so."); + + /// + /// "Countdown speed" + /// + public static LocalisableString CountdownSpeed => new TranslatableString(getKey(@"countdown_speed"), @"Countdown speed"); + + /// + /// "If the countdown sounds off-time, use this to make it appear one or more beats early." + /// + public static LocalisableString CountdownOffsetDescription => new TranslatableString(getKey(@"countdown_offset_description"), @"If the countdown sounds off-time, use this to make it appear one or more beats early."); + + /// + /// "Countdown offset" + /// + public static LocalisableString CountdownOffset => new TranslatableString(getKey(@"countdown_offset"), @"Countdown offset"); + + /// + /// "Widescreen support" + /// + public static LocalisableString WidescreenSupport => new TranslatableString(getKey(@"widescreen_support"), @"Widescreen support"); + + /// + /// "Allows storyboards to use the full screen space, rather than be confined to a 4:3 area." + /// + public static LocalisableString WidescreenSupportDescription => new TranslatableString(getKey(@"widescreen_support_description"), @"Allows storyboards to use the full screen space, rather than be confined to a 4:3 area."); + + /// + /// "Epilepsy warning" + /// + public static LocalisableString EpilepsyWarning => new TranslatableString(getKey(@"epilepsy_warning"), @"Epilepsy warning"); + + /// + /// "Recommended if the storyboard or video contain scenes with rapidly flashing colours." + /// + public static LocalisableString EpilepsyWarningDescription => new TranslatableString(getKey(@"epilepsy_warning_description"), @"Recommended if the storyboard or video contain scenes with rapidly flashing colours."); + + /// + /// "Letterbox during breaks" + /// + public static LocalisableString LetterboxDuringBreaks => new TranslatableString(getKey(@"letterbox_during_breaks"), @"Letterbox during breaks"); + + /// + /// "Adds horizontal letterboxing to give a cinematic look during breaks." + /// + public static LocalisableString LetterboxDuringBreaksDescription => new TranslatableString(getKey(@"letterbox_during_breaks_description"), @"Adds horizontal letterboxing to give a cinematic look during breaks."); + + /// + /// "Samples match playback rate" + /// + public static LocalisableString SamplesMatchPlaybackRate => new TranslatableString(getKey(@"samples_match_playback_rate"), @"Samples match playback rate"); + + /// + /// "When enabled, all samples will speed up or slow down when rate-changing mods are enabled." + /// + public static LocalisableString SamplesMatchPlaybackRateDescription => new TranslatableString(getKey(@"samples_match_playback_rate_description"), @"When enabled, all samples will speed up or slow down when rate-changing mods are enabled."); + + /// + /// "The size of all hit objects" + /// + public static LocalisableString CircleSizeDescription => new TranslatableString(getKey(@"circle_size_description"), @"The size of all hit objects"); + + /// + /// "The rate of passive health drain throughout playable time" + /// + public static LocalisableString DrainRateDescription => new TranslatableString(getKey(@"drain_rate_description"), @"The rate of passive health drain throughout playable time"); + + /// + /// "The speed at which objects are presented to the player" + /// + public static LocalisableString ApproachRateDescription => new TranslatableString(getKey(@"approach_rate_description"), @"The speed at which objects are presented to the player"); + + /// + /// "The harshness of hit windows and difficulty of special objects (ie. spinners)" + /// + public static LocalisableString OverallDifficultyDescription => new TranslatableString(getKey(@"overall_difficulty_description"), @"The harshness of hit windows and difficulty of special objects (ie. spinners)"); + + /// + /// "Metadata" + /// + public static LocalisableString MetadataHeader => new TranslatableString(getKey(@"metadata_header"), @"Metadata"); + + /// + /// "Romanised Artist" + /// + public static LocalisableString RomanisedArtist => new TranslatableString(getKey(@"romanised_artist"), @"Romanised Artist"); + + /// + /// "Romanised Title" + /// + public static LocalisableString RomanisedTitle => new TranslatableString(getKey(@"romanised_title"), @"Romanised Title"); + + /// + /// "Creator" + /// + public static LocalisableString Creator => new TranslatableString(getKey(@"creator"), @"Creator"); + + /// + /// "Difficulty Name" + /// + public static LocalisableString DifficultyName => new TranslatableString(getKey(@"difficulty_name"), @"Difficulty Name"); + + /// + /// "Resources" + /// + public static LocalisableString ResourcesHeader => new TranslatableString(getKey(@"resources_header"), @"Resources"); + + /// + /// "Audio Track" + /// + public static LocalisableString AudioTrack => new TranslatableString(getKey(@"audio_track"), @"Audio Track"); + + /// + /// "Click to select a track" + /// + public static LocalisableString ClickToSelectTrack => new TranslatableString(getKey(@"click_to_select_track"), @"Click to select a track"); + + /// + /// "Click to replace the track" + /// + public static LocalisableString ClickToReplaceTrack => new TranslatableString(getKey(@"click_to_replace_track"), @"Click to replace the track"); + + /// + /// "Click to select a background image" + /// + public static LocalisableString ClickToSelectBackground => new TranslatableString(getKey(@"click_to_select_background"), @"Click to select a background image"); + + /// + /// "Click to replace the background image" + /// + public static LocalisableString ClickToReplaceBackground => new TranslatableString(getKey(@"click_to_replace_background"), @"Click to replace the background image"); + + /// + /// "Ruleset ({0})" + /// + public static LocalisableString RulesetHeader(string arg0) => new TranslatableString(getKey(@"ruleset"), @"Ruleset ({0})", arg0); + + /// + /// "Combo" + /// + public static LocalisableString ComboColourPrefix => new TranslatableString(getKey(@"combo_colour_prefix"), @"Combo"); + + /// + /// "Artist" + /// + public static LocalisableString Artist => new TranslatableString(getKey(@"artist"), @"Artist"); + + /// + /// "Title" + /// + public static LocalisableString Title => new TranslatableString(getKey(@"title"), @"Title"); + + /// + /// "Difficulty" + /// + public static LocalisableString DifficultyHeader => new TranslatableString(getKey(@"difficulty_header"), @"Difficulty"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/Edit/Setup/ColoursSection.cs b/osu.Game/Screens/Edit/Setup/ColoursSection.cs index 5792613aa0..607086fdba 100644 --- a/osu.Game/Screens/Edit/Setup/ColoursSection.cs +++ b/osu.Game/Screens/Edit/Setup/ColoursSection.cs @@ -8,13 +8,12 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; -using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Edit.Setup { internal class ColoursSection : SetupSection { - public override LocalisableString Title => EditorSetupColoursStrings.Colours; + public override LocalisableString Title => EditorSetupStrings.ColoursHeader; private LabelledColourPalette comboColours; @@ -25,10 +24,9 @@ namespace osu.Game.Screens.Edit.Setup { comboColours = new LabelledColourPalette { - Label = EditorSetupColoursStrings.HitcircleSliderCombos, + Label = EditorSetupStrings.HitcircleSliderCombos, FixedLabelWidth = LABEL_WIDTH, - ColourNamePrefix = MatchesStrings.MatchScoreStatsCombo - } + ColourNamePrefix = EditorSetupStrings.ComboColourPrefix } }; if (Beatmap.BeatmapSkin != null) diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index 6214a17529..03d4b061d1 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Edit.Setup private LabelledSwitchButton letterboxDuringBreaks; private LabelledSwitchButton samplesMatchPlaybackRate; - public override LocalisableString Title => EditorSetupDesignStrings.Design; + public override LocalisableString Title => EditorSetupStrings.DesignHeader; [BackgroundDependencyLoader] private void load() @@ -39,9 +39,9 @@ namespace osu.Game.Screens.Edit.Setup { EnableCountdown = new LabelledSwitchButton { - Label = EditorSetupDesignStrings.EnableCountdown, + Label = EditorSetupStrings.EnableCountdown, Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None }, - Description = EditorSetupDesignStrings.CountdownDescription + Description = EditorSetupStrings.CountdownDescription }, CountdownSettings = new FillFlowContainer { @@ -53,41 +53,41 @@ namespace osu.Game.Screens.Edit.Setup { CountdownSpeed = new LabelledEnumDropdown { - Label = EditorSetupDesignStrings.CountdownSpeed, + Label = EditorSetupStrings.CountdownSpeed, Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None ? Beatmap.BeatmapInfo.Countdown : CountdownType.Normal }, Items = Enum.GetValues(typeof(CountdownType)).Cast().Where(type => type != CountdownType.None) }, CountdownOffset = new LabelledNumberBox { - Label = EditorSetupDesignStrings.CountdownOffset, + Label = EditorSetupStrings.CountdownOffset, Current = { Value = Beatmap.BeatmapInfo.CountdownOffset.ToString() }, - Description = EditorSetupDesignStrings.CountdownOffsetDescription, + Description = EditorSetupStrings.CountdownOffsetDescription, } } }, Empty(), widescreenSupport = new LabelledSwitchButton { - Label = EditorSetupDesignStrings.WidescreenSupport, - Description = EditorSetupDesignStrings.WidescreenSupportDescription, + Label = EditorSetupStrings.WidescreenSupport, + Description = EditorSetupStrings.WidescreenSupportDescription, Current = { Value = Beatmap.BeatmapInfo.WidescreenStoryboard } }, epilepsyWarning = new LabelledSwitchButton { - Label = EditorSetupDesignStrings.EpilepsyWarning, - Description = EditorSetupDesignStrings.EpilepsyWarningDescription, + Label = EditorSetupStrings.EpilepsyWarning, + Description = EditorSetupStrings.EpilepsyWarningDescription, Current = { Value = Beatmap.BeatmapInfo.EpilepsyWarning } }, letterboxDuringBreaks = new LabelledSwitchButton { - Label = EditorSetupDesignStrings.LetterboxDuringBreaks, - Description = EditorSetupDesignStrings.LetterboxDuringBreaksDescription, + Label = EditorSetupStrings.LetterboxDuringBreaks, + Description = EditorSetupStrings.LetterboxDuringBreaksDescription, Current = { Value = Beatmap.BeatmapInfo.LetterboxInBreaks } }, samplesMatchPlaybackRate = new LabelledSwitchButton { - Label = EditorSetupDesignStrings.SamplesMatchPlaybackRate, - Description = EditorSetupDesignStrings.SamplesMatchPlaybackRateDescription, + Label = EditorSetupStrings.SamplesMatchPlaybackRate, + Description = EditorSetupStrings.SamplesMatchPlaybackRateDescription, Current = { Value = Beatmap.BeatmapInfo.SamplesMatchPlaybackRate } } }; diff --git a/osu.Game/Screens/Edit/Setup/DifficultySection.cs b/osu.Game/Screens/Edit/Setup/DifficultySection.cs index d90997653c..93e1c1ee1b 100644 --- a/osu.Game/Screens/Edit/Setup/DifficultySection.cs +++ b/osu.Game/Screens/Edit/Setup/DifficultySection.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Edit.Setup private LabelledSliderBar approachRateSlider; private LabelledSliderBar overallDifficultySlider; - public override LocalisableString Title => BeatmapDiscussionsStrings.OwnerEditorVersion; + public override LocalisableString Title => EditorSetupStrings.DifficultyHeader; [BackgroundDependencyLoader] private void load() @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = BeatmapsetsStrings.ShowStatsCs, FixedLabelWidth = LABEL_WIDTH, - Description = EditorSetupDifficultyStrings.CircleSizeDescription, + Description = EditorSetupStrings.CircleSizeDescription, Current = new BindableFloat(Beatmap.Difficulty.CircleSize) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = BeatmapsetsStrings.ShowStatsDrain, FixedLabelWidth = LABEL_WIDTH, - Description = EditorSetupDifficultyStrings.DrainRateDescription, + Description = EditorSetupStrings.DrainRateDescription, Current = new BindableFloat(Beatmap.Difficulty.DrainRate) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = BeatmapsetsStrings.ShowStatsAr, FixedLabelWidth = LABEL_WIDTH, - Description = EditorSetupDifficultyStrings.ApproachRateDescription, + Description = EditorSetupStrings.ApproachRateDescription, Current = new BindableFloat(Beatmap.Difficulty.ApproachRate) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, @@ -72,7 +72,7 @@ namespace osu.Game.Screens.Edit.Setup { Label = BeatmapsetsStrings.ShowStatsAccuracy, FixedLabelWidth = LABEL_WIDTH, - Description = EditorSetupDifficultyStrings.OverallDifficultyDescription, + Description = EditorSetupStrings.OverallDifficultyDescription, Current = new BindableFloat(Beatmap.Difficulty.OverallDifficulty) { Default = BeatmapDifficulty.DEFAULT_DIFFICULTY, diff --git a/osu.Game/Screens/Edit/Setup/MetadataSection.cs b/osu.Game/Screens/Edit/Setup/MetadataSection.cs index 1af749160b..807e68dad0 100644 --- a/osu.Game/Screens/Edit/Setup/MetadataSection.cs +++ b/osu.Game/Screens/Edit/Setup/MetadataSection.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Edit.Setup private LabelledTextBox sourceTextBox; private LabelledTextBox tagsTextBox; - public override LocalisableString Title => EditorSetupMetadataStrings.Metadata; + public override LocalisableString Title => EditorSetupStrings.MetadataHeader; [BackgroundDependencyLoader] private void load() @@ -36,22 +36,22 @@ namespace osu.Game.Screens.Edit.Setup Children = new[] { - ArtistTextBox = createTextBox(ArtistStrings.TracksIndexFormArtist, + ArtistTextBox = createTextBox(EditorSetupStrings.Artist, !string.IsNullOrEmpty(metadata.ArtistUnicode) ? metadata.ArtistUnicode : metadata.Artist), - RomanisedArtistTextBox = createTextBox(EditorSetupMetadataStrings.RomanisedArtist, + RomanisedArtistTextBox = createTextBox(EditorSetupStrings.RomanisedArtist, !string.IsNullOrEmpty(metadata.Artist) ? metadata.Artist : MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode)), Empty(), - TitleTextBox = createTextBox(BeatmapsetWatchesStrings.IndexTableTitle, + TitleTextBox = createTextBox(EditorSetupStrings.Title, !string.IsNullOrEmpty(metadata.TitleUnicode) ? metadata.TitleUnicode : metadata.Title), - RomanisedTitleTextBox = createTextBox(EditorSetupMetadataStrings.RomanisedTitle, + RomanisedTitleTextBox = createTextBox(EditorSetupStrings.RomanisedTitle, !string.IsNullOrEmpty(metadata.Title) ? metadata.Title : MetadataUtils.StripNonRomanisedCharacters(metadata.ArtistUnicode)), Empty(), - creatorTextBox = createTextBox(EditorSetupMetadataStrings.Creator, metadata.Author.Username), - difficultyTextBox = createTextBox(EditorSetupMetadataStrings.DifficultyName, Beatmap.BeatmapInfo.DifficultyName), + creatorTextBox = createTextBox(EditorSetupStrings.Creator, metadata.Author.Username), + difficultyTextBox = createTextBox(EditorSetupStrings.DifficultyName, Beatmap.BeatmapInfo.DifficultyName), sourceTextBox = createTextBox(BeatmapsetsStrings.ShowInfoSource, metadata.Source), tagsTextBox = createTextBox(BeatmapsetsStrings.ShowInfoTags, metadata.Tags) }; diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index dfc849de7b..efa50bf084 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Edit.Setup private LabelledFileChooser audioTrackChooser; private LabelledFileChooser backgroundChooser; - public override LocalisableString Title => EditorSetupResourcesStrings.Resources; + public override LocalisableString Title => EditorSetupStrings.ResourcesHeader; [Resolved] private MusicController music { get; set; } @@ -50,7 +50,7 @@ namespace osu.Game.Screens.Edit.Setup }, audioTrackChooser = new LabelledFileChooser(".mp3", ".ogg") { - Label = EditorSetupResourcesStrings.AudioTrack, + Label = EditorSetupStrings.AudioTrack, FixedLabelWidth = LABEL_WIDTH, TabbableContentContainer = this }, @@ -145,12 +145,12 @@ namespace osu.Game.Screens.Edit.Setup private void updatePlaceholderText() { audioTrackChooser.Text = audioTrackChooser.Current.Value == null - ? EditorSetupResourcesStrings.ClickToSelectTrack - : EditorSetupResourcesStrings.ClickToReplaceTrack; + ? EditorSetupStrings.ClickToSelectTrack + : EditorSetupStrings.ClickToReplaceTrack; backgroundChooser.Text = backgroundChooser.Current.Value == null - ? EditorSetupResourcesStrings.ClickToSelectBackground - : EditorSetupResourcesStrings.ClickToReplaceBackground; + ? EditorSetupStrings.ClickToSelectBackground + : EditorSetupStrings.ClickToReplaceBackground; } } } diff --git a/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs b/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs index 6b1b1128d4..d6664e860b 100644 --- a/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs +++ b/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Edit.Setup { public abstract class RulesetSetupSection : SetupSection { - public sealed override LocalisableString Title => EditorSetupRulesetStrings.Ruleset(rulesetInfo.Name); + public sealed override LocalisableString Title => EditorSetupStrings.RulesetHeader(rulesetInfo.Name); private readonly RulesetInfo rulesetInfo; From 3abc333813218a832ef3f2c229af4da5c52abbbf Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 15 Aug 2022 17:18:55 +0200 Subject: [PATCH 0488/2686] added hotkey for merging selection --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index f9d4fbfc72..e3cd31f6a3 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Extensions; using osu.Game.Graphics.UserInterface; @@ -18,6 +19,7 @@ using osu.Game.Rulesets.Osu.UI; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components; using osuTK; +using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit { @@ -62,6 +64,17 @@ namespace osu.Game.Rulesets.Osu.Edit referencePathTypes = null; } + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.Key == Key.M && e.ControlPressed && e.ShiftPressed) + { + mergeSelection(); + return true; + } + + return false; + } + public override bool HandleMovement(MoveSelectionEvent moveEvent) { var hitObjects = selectedMovableObjects; From d261be873439cf0618188c25784bfdf38c8a7452 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 15 Aug 2022 17:19:04 +0200 Subject: [PATCH 0489/2686] added visual tests --- .../Editor/TestSceneObjectMerging.cs | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs new file mode 100644 index 0000000000..8387f9c74c --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs @@ -0,0 +1,179 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Utils; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Objects; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Rulesets.Osu.Tests.Editor +{ + public class TestSceneObjectMerging : TestSceneOsuEditor + { + [Test] + public void TestSimpleMerge() + { + HitCircle circle1 = null; + HitCircle circle2 = null; + + AddStep("select first two circles", () => + { + circle1 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle); + circle2 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle && h != circle1); + EditorClock.Seek(circle1.StartTime); + EditorBeatmap.SelectedHitObjects.Add(circle1); + EditorBeatmap.SelectedHitObjects.Add(circle2); + }); + + mergeSelection(); + + AddAssert("slider created", () => sliderCreatedFor( + (pos: circle1.Position, pathType: PathType.Linear), + (pos: circle2.Position, pathType: null))); + + AddStep("undo", () => Editor.Undo()); + AddAssert("merged objects restored", () => objectsRestored(circle1, circle2)); + } + + [Test] + public void TestMergeCircleSlider() + { + HitCircle circle1 = null; + Slider slider = null; + HitCircle circle2 = null; + + AddStep("select a circle, slider, circle", () => + { + circle1 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle); + slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider && h.StartTime > circle1.StartTime); + circle2 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle && h.StartTime > slider.StartTime); + EditorClock.Seek(circle1.StartTime); + EditorBeatmap.SelectedHitObjects.Add(circle1); + EditorBeatmap.SelectedHitObjects.Add(slider); + EditorBeatmap.SelectedHitObjects.Add(circle2); + }); + + mergeSelection(); + + AddAssert("slider created", () => + { + var controlPoints = slider.Path.ControlPoints; + (Vector2, PathType?)[] args = new (Vector2, PathType?)[controlPoints.Count + 2]; + args[0] = (circle1.Position, PathType.Linear); + + for (int i = 0; i < controlPoints.Count; i++) + { + args[i + 1] = (controlPoints[i].Position + slider.Position, i == controlPoints.Count - 1 ? PathType.Linear : controlPoints[i].Type); + } + + args[^1] = (circle2.Position, null); + return sliderCreatedFor(args); + }); + + AddStep("undo", () => Editor.Undo()); + AddAssert("merged objects restored", () => objectsRestored(circle1, slider, circle2)); + } + + [Test] + public void TestMergeSliderSlider() + { + Slider slider1 = null; + SliderPath slider1Path = null; + Slider slider2 = null; + + AddStep("select two sliders", () => + { + slider1 = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider); + slider1Path = new SliderPath(slider1.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray(), slider1.Path.ExpectedDistance.Value); + slider2 = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider && h.StartTime > slider1.StartTime); + EditorClock.Seek(slider1.StartTime); + EditorBeatmap.SelectedHitObjects.Add(slider1); + EditorBeatmap.SelectedHitObjects.Add(slider2); + }); + + mergeSelection(); + + AddAssert("slider created", () => + { + var controlPoints1 = slider1Path.ControlPoints; + var controlPoints2 = slider2.Path.ControlPoints; + (Vector2, PathType?)[] args = new (Vector2, PathType?)[controlPoints1.Count + controlPoints2.Count - 1]; + + for (int i = 0; i < controlPoints1.Count - 1; i++) + { + args[i] = (controlPoints1[i].Position + slider1.Position, controlPoints1[i].Type); + } + + for (int i = 0; i < controlPoints2.Count; i++) + { + args[i + controlPoints1.Count - 1] = (controlPoints2[i].Position + controlPoints1[^1].Position + slider1.Position, controlPoints2[i].Type); + } + + return sliderCreatedFor(args); + }); + + AddAssert("merged slider matches first slider", () => + { + var mergedSlider = (Slider)EditorBeatmap.SelectedHitObjects.First(); + return mergedSlider.HeadCircle.Samples.SequenceEqual(slider1.HeadCircle.Samples) + && mergedSlider.TailCircle.Samples.SequenceEqual(slider1.TailCircle.Samples) + && mergedSlider.Samples.SequenceEqual(slider1.Samples) + && mergedSlider.SampleControlPoint.IsRedundant(slider1.SampleControlPoint); + }); + + AddAssert("slider end is at same completion for last slider", () => + { + var mergedSlider = (Slider)EditorBeatmap.SelectedHitObjects.First(); + return Precision.AlmostEquals(mergedSlider.Path.Distance, slider1Path.CalculatedDistance + slider2.Path.Distance); + }); + } + + private void mergeSelection() + { + AddStep("merge selection", () => + { + InputManager.PressKey(Key.LControl); + InputManager.PressKey(Key.LShift); + InputManager.Key(Key.M); + InputManager.ReleaseKey(Key.LShift); + InputManager.ReleaseKey(Key.LControl); + }); + } + + private bool sliderCreatedFor(params (Vector2 pos, PathType? pathType)[] expectedControlPoints) + { + if (EditorBeatmap.SelectedHitObjects.Count != 1) + return false; + + var mergedSlider = (Slider)EditorBeatmap.SelectedHitObjects.First(); + int i = 0; + + foreach ((Vector2 pos, PathType? pathType) in expectedControlPoints) + { + var controlPoint = mergedSlider.Path.ControlPoints[i++]; + + if (!Precision.AlmostEquals(controlPoint.Position + mergedSlider.Position, pos) || controlPoint.Type != pathType) + return false; + } + + return true; + } + + private bool objectsRestored(params HitObject[] objects) + { + foreach (var hitObject in objects) + { + if (EditorBeatmap.HitObjects.Contains(hitObject)) + return false; + } + + return true; + } + } +} From b5e54113485d5c511bc179a67a2f0794cd78ec55 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 15 Aug 2022 18:07:55 +0200 Subject: [PATCH 0490/2686] remove copyright notice from new file --- osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs index 8387f9c74c..9b90c0ef05 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs @@ -1,6 +1,3 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - #nullable disable using System.Linq; From 5ff2e41a553be9a9dfcc6e6f47f1d99026818061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 14 Aug 2022 21:35:09 +0200 Subject: [PATCH 0491/2686] Add preset column to mod select test scene --- .../TestSceneModSelectOverlay.cs | 49 ++++++++++++------- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 18 +++---- osu.Game/Screens/Select/SongSelect.cs | 2 +- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 07473aa55b..b3aa49ad55 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -1,14 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; @@ -29,10 +28,18 @@ namespace osu.Game.Tests.Visual.UserInterface [TestFixture] public class TestSceneModSelectOverlay : OsuManualInputManagerTestScene { - [Resolved] - private RulesetStore rulesetStore { get; set; } + protected override bool UseFreshStoragePerRun => true; - private UserModSelectOverlay modSelectOverlay; + private RulesetStore rulesetStore = null!; + + private TestModSelectOverlay modSelectOverlay = null!; + + [BackgroundDependencyLoader] + private void load() + { + Dependencies.Cache(rulesetStore = new RealmRulesetStore(Realm)); + Dependencies.Cache(Realm); + } [SetUpSteps] public void SetUpSteps() @@ -44,7 +51,7 @@ namespace osu.Game.Tests.Visual.UserInterface private void createScreen() { - AddStep("create screen", () => Child = modSelectOverlay = new UserModSelectOverlay + AddStep("create screen", () => Child = modSelectOverlay = new TestModSelectOverlay { RelativeSizeAxes = Axes.Both, State = { Value = Visibility.Visible }, @@ -137,7 +144,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("any column dimmed", () => this.ChildrenOfType().Any(column => !column.Active.Value)); - ModSelectColumn lastColumn = null; + ModSelectColumn lastColumn = null!; AddAssert("last column dimmed", () => !this.ChildrenOfType().Last().Active.Value); AddStep("request scroll to last column", () => @@ -170,7 +177,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("dismiss mod customisation via toggle", () => { - InputManager.MoveMouseTo(modSelectOverlay.ChildrenOfType().Single()); + InputManager.MoveMouseTo(modSelectOverlay.CustomisationButton); InputManager.Click(MouseButton.Left); }); assertCustomisationToggleState(disabled: false, active: false); @@ -224,8 +231,8 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestSettingsNotCrossPolluting() { - Bindable> selectedMods2 = null; - ModSelectOverlay modSelectOverlay2 = null; + Bindable> selectedMods2 = null!; + ModSelectOverlay modSelectOverlay2 = null!; createScreen(); AddStep("select diff adjust", () => SelectedMods.Value = new Mod[] { new OsuModDifficultyAdjust() }); @@ -353,7 +360,7 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestExternallySetModIsReplacedByOverlayInstance() { Mod external = new OsuModDoubleTime(); - Mod overlayButtonMod = null; + Mod overlayButtonMod = null!; createScreen(); changeRuleset(0); @@ -460,12 +467,12 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("select difficulty adjust", () => SelectedMods.Value = new Mod[] { new OsuModDifficultyAdjust() }); assertCustomisationToggleState(disabled: false, active: true); - AddAssert("back button disabled", () => !this.ChildrenOfType().First().Enabled.Value); + AddAssert("back button disabled", () => !modSelectOverlay.BackButton.Enabled.Value); AddStep("dismiss customisation area", () => InputManager.Key(Key.Escape)); AddStep("click back button", () => { - InputManager.MoveMouseTo(this.ChildrenOfType().First()); + InputManager.MoveMouseTo(modSelectOverlay.BackButton); InputManager.Click(MouseButton.Left); }); AddAssert("mod select hidden", () => modSelectOverlay.State.Value == Visibility.Hidden); @@ -474,7 +481,7 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestColumnHiding() { - AddStep("create screen", () => Child = modSelectOverlay = new UserModSelectOverlay + AddStep("create screen", () => Child = modSelectOverlay = new TestModSelectOverlay { RelativeSizeAxes = Axes.Both, State = { Value = Visibility.Visible }, @@ -527,15 +534,21 @@ namespace osu.Game.Tests.Visual.UserInterface private void assertCustomisationToggleState(bool disabled, bool active) { - ShearedToggleButton getToggle() => modSelectOverlay.ChildrenOfType().Single(); - - AddAssert($"customisation toggle is {(disabled ? "" : "not ")}disabled", () => getToggle().Active.Disabled == disabled); - AddAssert($"customisation toggle is {(active ? "" : "not ")}active", () => getToggle().Active.Value == active); + AddAssert($"customisation toggle is {(disabled ? "" : "not ")}disabled", () => modSelectOverlay.CustomisationButton.AsNonNull().Active.Disabled == disabled); + AddAssert($"customisation toggle is {(active ? "" : "not ")}active", () => modSelectOverlay.CustomisationButton.AsNonNull().Active.Value == active); } private ModPanel getPanelForMod(Type modType) => modSelectOverlay.ChildrenOfType().Single(panel => panel.Mod.GetType() == modType); + private class TestModSelectOverlay : UserModSelectOverlay + { + protected override bool ShowPresets => true; + + public new ShearedButton BackButton => base.BackButton; + public new ShearedToggleButton? CustomisationButton => base.CustomisationButton; + } + private class TestUnimplementedMod : Mod { public override string Name => "Unimplemented mod"; diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index adc008e1f7..5973b919e5 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -87,7 +87,7 @@ namespace osu.Game.Overlays.Mods { if (AllowCustomisation) { - yield return customisationButton = new ShearedToggleButton(BUTTON_WIDTH) + yield return CustomisationButton = new ShearedToggleButton(BUTTON_WIDTH) { Text = ModSelectOverlayStrings.ModCustomisation, Active = { BindTarget = customisationVisible } @@ -107,11 +107,11 @@ namespace osu.Game.Overlays.Mods private ColumnScrollContainer columnScroll = null!; private ColumnFlowContainer columnFlow = null!; private FillFlowContainer footerButtonFlow = null!; - private ShearedButton backButton = null!; private DifficultyMultiplierDisplay? multiplierDisplay; - private ShearedToggleButton? customisationButton; + protected ShearedButton BackButton { get; private set; } = null!; + protected ShearedToggleButton? CustomisationButton { get; private set; } private Sample? columnAppearSample; @@ -214,7 +214,7 @@ namespace osu.Game.Overlays.Mods Horizontal = 70 }, Spacing = new Vector2(10), - ChildrenEnumerable = CreateFooterButtons().Prepend(backButton = new ShearedButton(BUTTON_WIDTH) + ChildrenEnumerable = CreateFooterButtons().Prepend(BackButton = new ShearedButton(BUTTON_WIDTH) { Text = CommonStrings.Back, Action = Hide, @@ -358,7 +358,7 @@ namespace osu.Game.Overlays.Mods private void updateCustomisation(ValueChangedEvent> valueChangedEvent) { - if (customisationButton == null) + if (CustomisationButton == null) return; bool anyCustomisableMod = false; @@ -394,7 +394,7 @@ namespace osu.Game.Overlays.Mods foreach (var button in footerButtonFlow) { - if (button != customisationButton) + if (button != CustomisationButton) button.Enabled.Value = !customisationVisible.Value; } @@ -587,14 +587,14 @@ namespace osu.Game.Overlays.Mods { if (customisationVisible.Value) { - Debug.Assert(customisationButton != null); - customisationButton.TriggerClick(); + Debug.Assert(CustomisationButton != null); + CustomisationButton.TriggerClick(); if (!immediate) return; } - backButton.TriggerClick(); + BackButton.TriggerClick(); } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 33ff31857f..d4e4b09303 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -928,7 +928,7 @@ namespace osu.Game.Screens.Select } } - private class SoloModSelectOverlay : UserModSelectOverlay + internal class SoloModSelectOverlay : UserModSelectOverlay { protected override bool ShowPresets => true; } From f860bc11eedcb928f2112e7605f7b025862ece64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 15 Aug 2022 20:34:09 +0200 Subject: [PATCH 0492/2686] Fix several schedule-related issues arising from new column addition --- osu.Game/Overlays/Mods/ModColumn.cs | 7 ++++++- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 13 ++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index 7a2c727a00..cf123f0347 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -66,7 +66,10 @@ namespace osu.Game.Overlays.Mods private IModHotkeyHandler hotkeyHandler = null!; private Task? latestLoadTask; - internal bool ItemsLoaded => latestLoadTask?.IsCompleted == true; + private bool itemsLoaded; + internal bool ItemsLoaded => latestLoadTask?.IsCompleted == true && itemsLoaded; + + public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; public ModColumn(ModType modType, bool allowIncompatibleSelection) { @@ -132,10 +135,12 @@ namespace osu.Game.Overlays.Mods var panels = availableMods.Select(mod => CreateModPanel(mod).With(panel => panel.Shear = Vector2.Zero)); + itemsLoaded = false; latestLoadTask = LoadComponentsAsync(panels, loaded => { ItemsFlow.ChildrenEnumerable = loaded; updateState(); + itemsLoaded = true; }, (cancellationTokenSource = new CancellationTokenSource()).Token); } diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 5973b919e5..cd3b5bacec 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -708,7 +708,18 @@ namespace osu.Game.Overlays.Mods FinishTransforms(); } - protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate || (Column as ModColumn)?.SelectionAnimationRunning == true; + protected override bool RequiresChildrenUpdate + { + get + { + bool result = base.RequiresChildrenUpdate; + + if (Column is ModColumn modColumn) + result |= !modColumn.ItemsLoaded || modColumn.SelectionAnimationRunning; + + return result; + } + } private void updateState() { From f0ad31b65097aba89467643c04c6b11cf62b2e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 15 Aug 2022 18:44:51 +0200 Subject: [PATCH 0493/2686] Add failing test case --- .../TestSceneModSelectOverlay.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index b3aa49ad55..f17f93a875 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -47,6 +47,26 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("clear contents", Clear); AddStep("reset ruleset", () => Ruleset.Value = rulesetStore.GetRuleset(0)); AddStep("reset mods", () => SelectedMods.SetDefault()); + AddStep("set up presets", () => + { + Realm.Write(r => + { + r.RemoveAll(); + r.Add(new ModPreset + { + Name = "AR0", + Description = "Too... many... circles...", + Ruleset = r.Find(OsuRuleset.SHORT_NAME), + Mods = new[] + { + new OsuModDifficultyAdjust + { + ApproachRate = { Value = 0 } + } + } + }); + }); + }); } private void createScreen() @@ -200,6 +220,13 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("select mod without configuration", () => SelectedMods.Value = new[] { new OsuModAutoplay() }); assertCustomisationToggleState(disabled: true, active: false); // config was dismissed without explicit user action. + + AddStep("select mod preset with mod requiring configuration", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().First()); + InputManager.Click(MouseButton.Left); + }); + assertCustomisationToggleState(disabled: false, active: false); } [Test] From 10daac675294d6c9fa894af5b0521de218f30253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 15 Aug 2022 19:40:05 +0200 Subject: [PATCH 0494/2686] Only open mod customisation panel on explicit selection of single mod --- osu.Game/Overlays/Mods/ModPanel.cs | 16 ++++++++++++++++ osu.Game/Overlays/Mods/ModSelectOverlay.cs | 19 ++++++++++--------- osu.Game/Overlays/Mods/ModState.cs | 7 +++++++ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModPanel.cs b/osu.Game/Overlays/Mods/ModPanel.cs index 6ef6ab0595..0ab6293faf 100644 --- a/osu.Game/Overlays/Mods/ModPanel.cs +++ b/osu.Game/Overlays/Mods/ModPanel.cs @@ -37,6 +37,8 @@ namespace osu.Game.Overlays.Mods Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), Scale = new Vector2(HEIGHT / ModSwitchSmall.DEFAULT_SIZE) }; + + Action = select; } public ModPanel(Mod mod) @@ -57,6 +59,20 @@ namespace osu.Game.Overlays.Mods Filtered.BindValueChanged(_ => updateFilterState(), true); } + private void select() + { + if (!Active.Value) + { + modState.RequiresConfiguration = Mod.RequiresConfiguration; + Active.Value = true; + } + else + { + modState.RequiresConfiguration = false; + Active.Value = false; + } + } + #region Filtering support private void updateFilterState() diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index cd3b5bacec..66ecb9fd78 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -247,8 +247,8 @@ namespace osu.Game.Overlays.Mods modSettingChangeTracker?.Dispose(); updateMultiplier(); - updateCustomisation(val); updateFromExternalSelection(); + updateCustomisation(); if (AllowCustomisation) { @@ -356,25 +356,26 @@ namespace osu.Game.Overlays.Mods multiplierDisplay.Current.Value = multiplier; } - private void updateCustomisation(ValueChangedEvent> valueChangedEvent) + private void updateCustomisation() { if (CustomisationButton == null) return; - bool anyCustomisableMod = false; - bool anyModWithRequiredCustomisationAdded = false; + bool anyCustomisableModActive = false; + bool anyModRequiresCustomisation = false; - foreach (var mod in SelectedMods.Value) + foreach (var modState in allAvailableMods) { - anyCustomisableMod |= mod.GetSettingsSourceProperties().Any(); - anyModWithRequiredCustomisationAdded |= valueChangedEvent.OldValue.All(m => m.GetType() != mod.GetType()) && mod.RequiresConfiguration; + anyCustomisableModActive |= modState.Active.Value && modState.Mod.GetSettingsSourceProperties().Any(); + anyModRequiresCustomisation |= modState.RequiresConfiguration; + modState.RequiresConfiguration = false; } - if (anyCustomisableMod) + if (anyCustomisableModActive) { customisationVisible.Disabled = false; - if (anyModWithRequiredCustomisationAdded && !customisationVisible.Value) + if (anyModRequiresCustomisation && !customisationVisible.Value) customisationVisible.Value = true; } else diff --git a/osu.Game/Overlays/Mods/ModState.cs b/osu.Game/Overlays/Mods/ModState.cs index 79880b85a5..a3806b1936 100644 --- a/osu.Game/Overlays/Mods/ModState.cs +++ b/osu.Game/Overlays/Mods/ModState.cs @@ -24,6 +24,13 @@ namespace osu.Game.Overlays.Mods /// public BindableBool Active { get; } = new BindableBool(); + /// + /// Whether the mod requires further customisation. + /// This flag is read by the to determine if the customisation panel should be opened after a mod change + /// and cleared after reading. + /// + public bool RequiresConfiguration { get; set; } + /// /// Whether the mod is currently filtered out due to not matching imposed criteria. /// From a494e55d938c009e6917f673ca43919c1f2d2300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 15 Aug 2022 19:46:17 +0200 Subject: [PATCH 0495/2686] Adjust test scene to reflect new behaviour --- .../UserInterface/TestSceneModSelectOverlay.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index f17f93a875..6f9edb1b8a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -192,7 +192,11 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("select customisable mod", () => SelectedMods.Value = new[] { new OsuModDoubleTime() }); assertCustomisationToggleState(disabled: false, active: false); - AddStep("select mod requiring configuration", () => SelectedMods.Value = new[] { new OsuModDifficultyAdjust() }); + AddStep("select mod requiring configuration externally", () => SelectedMods.Value = new[] { new OsuModDifficultyAdjust() }); + assertCustomisationToggleState(disabled: false, active: false); + + AddStep("reset mods", () => SelectedMods.SetDefault()); + AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick()); assertCustomisationToggleState(disabled: false, active: true); AddStep("dismiss mod customisation via toggle", () => @@ -203,7 +207,7 @@ namespace osu.Game.Tests.Visual.UserInterface assertCustomisationToggleState(disabled: false, active: false); AddStep("reset mods", () => SelectedMods.SetDefault()); - AddStep("select mod requiring configuration", () => SelectedMods.Value = new[] { new OsuModDifficultyAdjust() }); + AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick()); assertCustomisationToggleState(disabled: false, active: true); AddStep("dismiss mod customisation via keyboard", () => InputManager.Key(Key.Escape)); @@ -215,7 +219,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("select mod without configuration", () => SelectedMods.Value = new[] { new OsuModAutoplay() }); assertCustomisationToggleState(disabled: true, active: false); - AddStep("select mod requiring configuration", () => SelectedMods.Value = new[] { new OsuModDifficultyAdjust() }); + AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick()); assertCustomisationToggleState(disabled: false, active: true); AddStep("select mod without configuration", () => SelectedMods.Value = new[] { new OsuModAutoplay() }); @@ -235,7 +239,7 @@ namespace osu.Game.Tests.Visual.UserInterface createScreen(); assertCustomisationToggleState(disabled: true, active: false); - AddStep("select mod requiring configuration", () => SelectedMods.Value = new[] { new OsuModDifficultyAdjust() }); + AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick()); assertCustomisationToggleState(disabled: false, active: true); AddStep("move mouse to settings area", () => InputManager.MoveMouseTo(this.ChildrenOfType().Single())); @@ -262,7 +266,7 @@ namespace osu.Game.Tests.Visual.UserInterface ModSelectOverlay modSelectOverlay2 = null!; createScreen(); - AddStep("select diff adjust", () => SelectedMods.Value = new Mod[] { new OsuModDifficultyAdjust() }); + AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick()); AddStep("set setting", () => modSelectOverlay.ChildrenOfType>().First().Current.Value = 8); @@ -492,7 +496,7 @@ namespace osu.Game.Tests.Visual.UserInterface createScreen(); changeRuleset(0); - AddStep("select difficulty adjust", () => SelectedMods.Value = new Mod[] { new OsuModDifficultyAdjust() }); + AddStep("select difficulty adjust via panel", () => getPanelForMod(typeof(OsuModDifficultyAdjust)).TriggerClick()); assertCustomisationToggleState(disabled: false, active: true); AddAssert("back button disabled", () => !modSelectOverlay.BackButton.Enabled.Value); From 7c2ada9b209f1a887e026aac48c9cadeb3d7905f Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 15 Aug 2022 21:11:06 +0200 Subject: [PATCH 0496/2686] Revert "remove copyright notice from new file" This reverts commit b5e54113485d5c511bc179a67a2f0794cd78ec55. --- osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs index 9b90c0ef05..8387f9c74c 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs @@ -1,3 +1,6 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + #nullable disable using System.Linq; From d140e0df14224da4163c9e5049aa3eec0bf5ce1d Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 15 Aug 2022 21:15:23 +0200 Subject: [PATCH 0497/2686] remove nullable disable annotation --- .../Editor/TestSceneObjectMerging.cs | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs index 8387f9c74c..63e6760514 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.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. -#nullable disable - using System.Linq; using NUnit.Framework; using osu.Framework.Utils; @@ -19,8 +17,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor [Test] public void TestSimpleMerge() { - HitCircle circle1 = null; - HitCircle circle2 = null; + HitCircle? circle1 = null; + HitCircle? circle2 = null; AddStep("select first two circles", () => { @@ -33,20 +31,20 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor mergeSelection(); - AddAssert("slider created", () => sliderCreatedFor( + AddAssert("slider created", () => circle1 is not null && circle2 is not null && sliderCreatedFor( (pos: circle1.Position, pathType: PathType.Linear), (pos: circle2.Position, pathType: null))); AddStep("undo", () => Editor.Undo()); - AddAssert("merged objects restored", () => objectsRestored(circle1, circle2)); + AddAssert("merged objects restored", () => circle1 is not null && circle2 is not null && objectsRestored(circle1, circle2)); } [Test] public void TestMergeCircleSlider() { - HitCircle circle1 = null; - Slider slider = null; - HitCircle circle2 = null; + HitCircle? circle1 = null; + Slider? slider = null; + HitCircle? circle2 = null; AddStep("select a circle, slider, circle", () => { @@ -63,6 +61,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddAssert("slider created", () => { + if (circle1 is null || circle2 is null || slider is null) + return false; + var controlPoints = slider.Path.ControlPoints; (Vector2, PathType?)[] args = new (Vector2, PathType?)[controlPoints.Count + 2]; args[0] = (circle1.Position, PathType.Linear); @@ -77,15 +78,15 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor }); AddStep("undo", () => Editor.Undo()); - AddAssert("merged objects restored", () => objectsRestored(circle1, slider, circle2)); + AddAssert("merged objects restored", () => circle1 is not null && circle2 is not null && slider is not null && objectsRestored(circle1, slider, circle2)); } [Test] public void TestMergeSliderSlider() { - Slider slider1 = null; - SliderPath slider1Path = null; - Slider slider2 = null; + Slider? slider1 = null; + SliderPath? slider1Path = null; + Slider? slider2 = null; AddStep("select two sliders", () => { @@ -101,6 +102,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddAssert("slider created", () => { + if (slider1 is null || slider2 is null || slider1Path is null) + return false; + var controlPoints1 = slider1Path.ControlPoints; var controlPoints2 = slider2.Path.ControlPoints; (Vector2, PathType?)[] args = new (Vector2, PathType?)[controlPoints1.Count + controlPoints2.Count - 1]; @@ -121,14 +125,17 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddAssert("merged slider matches first slider", () => { var mergedSlider = (Slider)EditorBeatmap.SelectedHitObjects.First(); - return mergedSlider.HeadCircle.Samples.SequenceEqual(slider1.HeadCircle.Samples) - && mergedSlider.TailCircle.Samples.SequenceEqual(slider1.TailCircle.Samples) - && mergedSlider.Samples.SequenceEqual(slider1.Samples) - && mergedSlider.SampleControlPoint.IsRedundant(slider1.SampleControlPoint); + return slider1 is not null && mergedSlider.HeadCircle.Samples.SequenceEqual(slider1.HeadCircle.Samples) + && mergedSlider.TailCircle.Samples.SequenceEqual(slider1.TailCircle.Samples) + && mergedSlider.Samples.SequenceEqual(slider1.Samples) + && mergedSlider.SampleControlPoint.IsRedundant(slider1.SampleControlPoint); }); AddAssert("slider end is at same completion for last slider", () => { + if (slider1Path is null || slider2 is null) + return false; + var mergedSlider = (Slider)EditorBeatmap.SelectedHitObjects.First(); return Precision.AlmostEquals(mergedSlider.Path.Distance, slider1Path.CalculatedDistance + slider2.Path.Distance); }); From b33e0f5e1cd3421503eacfc6283210cd2be7c0d6 Mon Sep 17 00:00:00 2001 From: 63411 <62799417+molneya@users.noreply.github.com> Date: Tue, 16 Aug 2022 11:03:18 +0800 Subject: [PATCH 0498/2686] update comment and deltaTime check --- osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs index 657dfbb575..d5cee47178 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs @@ -78,8 +78,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills individualStrains[column] = applyDecay(individualStrains[column], startTime - startTimes[column], individual_decay_base); individualStrains[column] += 2.0 * holdFactor; - // individualStrain should be the hardest individualStrain column for notes in a chord - individualStrain = maniaCurrent.DeltaTime == 0 ? Math.Max(individualStrain, individualStrains[column]) : individualStrains[column]; + // For notes at the same time (in a chord), the individualStrain should be the hardest individualStrain out of those columns + individualStrain = maniaCurrent.DeltaTime <= 1 ? Math.Max(individualStrain, individualStrains[column]) : individualStrains[column]; // Decay and increase overallStrain overallStrain = applyDecay(overallStrain, current.DeltaTime, overall_decay_base); From a15e6f19aa48d2ce7ec39387f0373cc4d7bde144 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 13:35:57 +0900 Subject: [PATCH 0499/2686] Fix running `TestScenePlayerLoader` interactively leaving volume in a bad state --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 81 +++++++++++++++---- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 05474e3d39..dbbedf37ae 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -56,6 +56,10 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly ChangelogOverlay changelogOverlay; + private double savedTrackVolume; + private double savedMasterVolume; + private bool savedMutedState; + public TestScenePlayerLoader() { AddRange(new Drawable[] @@ -75,11 +79,7 @@ namespace osu.Game.Tests.Visual.Gameplay } [SetUp] - public void Setup() => Schedule(() => - { - player = null; - audioManager.Volume.SetDefault(); - }); + public void Setup() => Schedule(() => player = null); /// /// Sets the input manager child to a new test player loader container instance. @@ -147,6 +147,7 @@ namespace osu.Game.Tests.Visual.Gameplay moveMouse(); return player?.LoadState == LoadState.Ready; }); + AddRepeatStep("move mouse", moveMouse, 20); AddAssert("loader still active", () => loader.IsCurrentScreen()); @@ -154,6 +155,8 @@ namespace osu.Game.Tests.Visual.Gameplay void moveMouse() { + notificationOverlay.State.Value = Visibility.Hidden; + InputManager.MoveMouseTo( loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft + (loader.VisualSettings.ScreenSpaceDrawQuad.BottomRight - loader.VisualSettings.ScreenSpaceDrawQuad.TopLeft) @@ -274,6 +277,8 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("load player", () => resetPlayer(false, beforeLoad)); AddUntilStep("wait for player", () => player?.LoadState == LoadState.Ready); + saveVolumes(); + AddAssert("check for notification", () => notificationOverlay.UnreadCount.Value == 1); AddStep("click notification", () => { @@ -287,6 +292,8 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("check " + volumeName, assert); + restoreVolumes(); + AddUntilStep("wait for player load", () => player.IsLoaded); } @@ -294,6 +301,9 @@ namespace osu.Game.Tests.Visual.Gameplay [TestCase(false)] public void TestEpilepsyWarning(bool warning) { + saveVolumes(); + setFullVolume(); + AddStep("change epilepsy warning", () => epilepsyWarning = warning); AddStep("load dummy beatmap", () => resetPlayer(false)); @@ -306,6 +316,30 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("sound volume decreased", () => Beatmap.Value.Track.AggregateVolume.Value == 0.25); AddUntilStep("sound volume restored", () => Beatmap.Value.Track.AggregateVolume.Value == 1); } + + restoreVolumes(); + } + + [Test] + public void TestEpilepsyWarningEarlyExit() + { + saveVolumes(); + setFullVolume(); + + AddStep("set epilepsy warning", () => epilepsyWarning = true); + AddStep("load dummy beatmap", () => resetPlayer(false)); + + AddUntilStep("wait for current", () => loader.IsCurrentScreen()); + + AddUntilStep("wait for epilepsy warning", () => getWarning().Alpha > 0); + AddUntilStep("warning is shown", () => getWarning().State.Value == Visibility.Visible); + + AddStep("exit early", () => loader.Exit()); + + AddUntilStep("warning is hidden", () => getWarning().State.Value == Visibility.Hidden); + AddUntilStep("sound volume restored", () => Beatmap.Value.Track.AggregateVolume.Value == 1); + + restoreVolumes(); } [TestCase(true, 1.0, false)] // on battery, above cutoff --> no warning @@ -336,21 +370,34 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for player load", () => player.IsLoaded); } - [Test] - public void TestEpilepsyWarningEarlyExit() + private void restoreVolumes() { - AddStep("set epilepsy warning", () => epilepsyWarning = true); - AddStep("load dummy beatmap", () => resetPlayer(false)); + AddStep("restore previous volumes", () => + { + audioManager.VolumeTrack.Value = savedTrackVolume; + audioManager.Volume.Value = savedMasterVolume; + volumeOverlay.IsMuted.Value = savedMutedState; + }); + } - AddUntilStep("wait for current", () => loader.IsCurrentScreen()); + private void setFullVolume() + { + AddStep("set volumes to 100%", () => + { + audioManager.VolumeTrack.Value = 1; + audioManager.Volume.Value = 1; + volumeOverlay.IsMuted.Value = false; + }); + } - AddUntilStep("wait for epilepsy warning", () => getWarning().Alpha > 0); - AddUntilStep("warning is shown", () => getWarning().State.Value == Visibility.Visible); - - AddStep("exit early", () => loader.Exit()); - - AddUntilStep("warning is hidden", () => getWarning().State.Value == Visibility.Hidden); - AddUntilStep("sound volume restored", () => Beatmap.Value.Track.AggregateVolume.Value == 1); + private void saveVolumes() + { + AddStep("save previous volumes", () => + { + savedTrackVolume = audioManager.VolumeTrack.Value; + savedMasterVolume = audioManager.Volume.Value; + savedMutedState = volumeOverlay.IsMuted.Value; + }); } private EpilepsyWarning getWarning() => loader.ChildrenOfType().SingleOrDefault(); From 6761f869f993493598f9de7d2d192b1ba7cef8ed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 13:04:56 +0900 Subject: [PATCH 0500/2686] Modify flow to avoid weird bindable and value resetting --- .../Visual/Mods/TestSceneModFailCondition.cs | 2 +- osu.Game/Screens/Play/Player.cs | 21 +++++++------------ osu.Game/Screens/Play/PlayerLoader.cs | 15 ++++--------- osu.Game/Screens/Ranking/ResultsScreen.cs | 2 +- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs b/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs index 91fa09b414..23c1eda7f7 100644 --- a/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs +++ b/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Mods protected override TestPlayer CreateModPlayer(Ruleset ruleset) { var player = base.CreateModPlayer(ruleset); - player.RestartRequested = () => restartRequested = true; + player.RestartRequested = _ => restartRequested = true; return player; } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 7ed68aa5b7..4f6bb1d37a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -77,15 +77,10 @@ namespace osu.Game.Screens.Play /// protected virtual bool PauseOnFocusLost => true; - public Action RestartRequested; + public Action RestartRequested; private bool isRestarting; - /// - /// Is set to true when the quick retry hotkey has been pressed. - /// - public Bindable IsQuickRestart = new Bindable(); - private Bindable mouseWheelDisabled; private readonly Bindable storyboardReplacesBackground = new Bindable(); @@ -272,7 +267,7 @@ namespace osu.Game.Screens.Play FailOverlay = new FailOverlay { SaveReplay = prepareAndImportScore, - OnRetry = Restart, + OnRetry = () => Restart(), OnQuit = () => PerformExit(true), }, new HotkeyExitOverlay @@ -298,9 +293,8 @@ namespace osu.Game.Screens.Play { if (!this.IsCurrentScreen()) return; - IsQuickRestart.Value = true; fadeOut(true); - Restart(); + Restart(true); }, }); } @@ -453,7 +447,7 @@ namespace osu.Game.Screens.Play { OnResume = Resume, Retries = RestartCount, - OnRetry = Restart, + OnRetry = () => Restart(), OnQuit = () => PerformExit(true), }, }, @@ -660,7 +654,8 @@ namespace osu.Game.Screens.Play /// Restart gameplay via a parent . /// This can be called from a child screen in order to trigger the restart process. /// - public void Restart() + /// Whether a quick restart was requested (skipping intro etc.). + public void Restart(bool quickRestart = false) { if (!Configuration.AllowRestart) return; @@ -672,7 +667,7 @@ namespace osu.Game.Screens.Play musicController.Stop(); sampleRestart?.Play(); - RestartRequested?.Invoke(); + RestartRequested?.Invoke(quickRestart); PerformExit(false); } @@ -852,7 +847,7 @@ namespace osu.Game.Screens.Play failAnimationLayer.Start(); if (GameplayState.Mods.OfType().Any(m => m.RestartOnFail)) - Restart(); + Restart(true); return true; } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 76092fbaa3..e6bd1367ef 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -123,7 +123,7 @@ namespace osu.Game.Screens.Play private EpilepsyWarning? epilepsyWarning; - private bool isHotKeyRestart; + private bool quickRestart; [Resolved(CanBeNull = true)] private INotificationOverlay? notificationOverlay { get; set; } @@ -363,17 +363,12 @@ namespace osu.Game.Screens.Play return; CurrentPlayer = createPlayer(); + CurrentPlayer.Configuration.AutomaticallySkipIntro = quickRestart; CurrentPlayer.RestartCount = restartCount++; CurrentPlayer.RestartRequested = restartRequested; LoadTask = LoadComponentAsync(CurrentPlayer, _ => { - if (isHotKeyRestart) - { - CurrentPlayer.Configuration.AutomaticallySkipIntro = true; - isHotKeyRestart = false; - } - MetadataInfo.Loading = false; OnPlayerLoaded(); }); @@ -383,11 +378,9 @@ namespace osu.Game.Screens.Play { } - private void restartRequested() + private void restartRequested(bool quickRestartRequested) { - if (CurrentPlayer != null) - isHotKeyRestart = CurrentPlayer.IsQuickRestart.Value; - + quickRestart = quickRestartRequested; hideOverlays = true; ValidForResume = true; } diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index c530febcae..226216b0f0 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -177,7 +177,7 @@ namespace osu.Game.Screens.Ranking { if (!this.IsCurrentScreen()) return; - player?.Restart(); + player?.Restart(true); }, }); } From 9a1a7bae891c1b13a90ccf72354ee1fad6a1e6fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 14:17:28 +0900 Subject: [PATCH 0501/2686] Make test actually test things --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 38 +++++++++++++++---- osu.Game/Screens/Play/SkipOverlay.cs | 2 + 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index b0308dcd22..1fd517d1a6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -29,6 +29,7 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Utils; using osuTK.Input; +using SkipOverlay = osu.Game.Screens.Play.SkipOverlay; namespace osu.Game.Tests.Visual.Gameplay { @@ -98,7 +99,13 @@ namespace osu.Game.Tests.Visual.Gameplay private void prepareBeatmap() { var workingBeatmap = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); + + // Add intro time to test quick retry skipping (TestQuickRetry). + workingBeatmap.BeatmapInfo.AudioLeadIn = 60000; + + // Turn on epilepsy warning to test warning display (TestEpilepsyWarning). workingBeatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning; + Beatmap.Value = workingBeatmap; foreach (var mod in SelectedMods.Value.OfType()) @@ -356,17 +363,32 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestQuickRetry() { + TestPlayer getCurrentPlayer() => loader.CurrentPlayer as TestPlayer; + bool checkSkipButtonVisible() => player.ChildrenOfType().FirstOrDefault()?.IsButtonVisible == true; + + TestPlayer previousPlayer = null; + AddStep("load dummy beatmap", () => resetPlayer(false)); - AddUntilStep("wait for current", () => player.IsCurrentScreen()); - AddStep("Restart map normally", () => player.Restart()); - AddUntilStep("wait for current", () => player.IsCurrentScreen()); + AddUntilStep("wait for current", () => getCurrentPlayer()?.IsCurrentScreen() == true); + AddStep("store previous player", () => previousPlayer = getCurrentPlayer()); - AddStep("Restart map with quick retry hotkey", () => - { - InputManager.UseParentInput = true; - InputManager.PressKey(Key.Tilde); - }); + AddStep("Restart map normally", () => getCurrentPlayer().Restart()); + AddUntilStep("wait for load", () => getCurrentPlayer()?.LoadedBeatmapSuccessfully == true); + + AddUntilStep("restart completed", () => getCurrentPlayer() != null && getCurrentPlayer() != previousPlayer); + AddStep("store previous player", () => previousPlayer = getCurrentPlayer()); + + AddUntilStep("skip button visible", checkSkipButtonVisible); + + AddStep("press quick retry key", () => InputManager.PressKey(Key.Tilde)); + AddUntilStep("restart completed", () => getCurrentPlayer() != null && getCurrentPlayer() != previousPlayer); + AddStep("release quick retry key", () => InputManager.ReleaseKey(Key.Tilde)); + + AddUntilStep("wait for load", () => getCurrentPlayer()?.LoadedBeatmapSuccessfully == true); + + AddUntilStep("time reached zero", () => getCurrentPlayer()?.GameplayClockContainer.CurrentTime > 0); + AddUntilStep("skip button not visible", () => !checkSkipButtonVisible()); } private EpilepsyWarning getWarning() => loader.ChildrenOfType().SingleOrDefault(); diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 70a8345c1f..0629d0ae23 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -46,6 +46,8 @@ namespace osu.Game.Screens.Play [Resolved] private IGameplayClock gameplayClock { get; set; } + internal bool IsButtonVisible => fadeContainer.State == Visibility.Visible && buttonContainer.State.Value == Visibility.Visible; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; /// From 63819648dfda22157edd7c029cea5a6db06b8235 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 14:27:02 +0900 Subject: [PATCH 0502/2686] Fix up flow of actual skip operation --- osu.Game/Screens/Play/Player.cs | 7 ++----- osu.Game/Screens/Play/SkipOverlay.cs | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 4f6bb1d37a..6827ff04d3 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -372,11 +372,8 @@ namespace osu.Game.Screens.Play IsBreakTime.BindTo(breakTracker.IsBreakTime); IsBreakTime.BindValueChanged(onBreakTimeChanged, true); - skipIntroOverlay.IsSkippable.ValueChanged += e => - { - if (Configuration.AutomaticallySkipIntro && e.NewValue && RestartCount > 0) - performUserRequestedSkip(); - }; + if (Configuration.AutomaticallySkipIntro) + skipIntroOverlay.SkipWhenReady(); } protected virtual GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) => new MasterGameplayClockContainer(beatmap, gameplayStart); diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 0629d0ae23..5c9a706549 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -8,7 +8,6 @@ using osu.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.Shapes; @@ -40,8 +39,7 @@ namespace osu.Game.Screens.Play private double displayTime; private bool isClickable; - - public IBindable IsSkippable = new Bindable(); + private bool skipQueued; [Resolved] private IGameplayClock gameplayClock { get; set; } @@ -94,8 +92,6 @@ namespace osu.Game.Screens.Play } } }; - - IsSkippable.BindTo(button.Enabled); } private const double fade_time = 300; @@ -130,6 +126,20 @@ namespace osu.Game.Screens.Play displayTime = gameplayClock.CurrentTime; fadeContainer.TriggerShow(); + + if (skipQueued) + { + Scheduler.AddDelayed(() => button.TriggerClick(), 200); + skipQueued = false; + } + } + + public void SkipWhenReady() + { + if (IsLoaded) + button.TriggerClick(); + else + skipQueued = true; } protected override void Update() From e870ac6456c334577f4cc57fff54305179cae041 Mon Sep 17 00:00:00 2001 From: its5Q Date: Tue, 16 Aug 2022 15:51:54 +1000 Subject: [PATCH 0503/2686] Fix code quality for CI --- osu.Game/Screens/Edit/Setup/ColoursSection.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Setup/ColoursSection.cs b/osu.Game/Screens/Edit/Setup/ColoursSection.cs index 607086fdba..9334967a3e 100644 --- a/osu.Game/Screens/Edit/Setup/ColoursSection.cs +++ b/osu.Game/Screens/Edit/Setup/ColoursSection.cs @@ -26,7 +26,8 @@ namespace osu.Game.Screens.Edit.Setup { Label = EditorSetupStrings.HitcircleSliderCombos, FixedLabelWidth = LABEL_WIDTH, - ColourNamePrefix = EditorSetupStrings.ComboColourPrefix } + ColourNamePrefix = EditorSetupStrings.ComboColourPrefix + } }; if (Beatmap.BeatmapSkin != null) From ea50936d718bd21a78fea574811cc7b560a651f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 15:26:29 +0900 Subject: [PATCH 0504/2686] Fix slider ticks playing back at infinite rate while making changes to a slider in the editor --- osu.Game/Screens/Edit/Editor.cs | 19 ++++++------------- osu.Game/Screens/Edit/EditorBeatmap.cs | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 89f9aec5ee..90e912bd6d 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -225,8 +225,6 @@ namespace osu.Game.Screens.Edit dependencies.CacheAs(clock); AddInternal(clock); - clock.SeekingOrStopped.BindValueChanged(_ => updateSampleDisabledState()); - // todo: remove caching of this and consume via editorBeatmap? dependencies.Cache(beatDivisor); @@ -428,7 +426,12 @@ namespace osu.Game.Screens.Edit protected override void Update() { base.Update(); + clock.ProcessFrame(); + + samplePlaybackDisabled.Value = clock.SeekingOrStopped.Value + || currentScreen is not ComposeScreen + || editorBeatmap.UpdateInProgress; } public bool OnPressed(KeyBindingPressEvent e) @@ -822,16 +825,10 @@ namespace osu.Game.Screens.Edit } finally { - updateSampleDisabledState(); rebindClipboardBindables(); } } - private void updateSampleDisabledState() - { - samplePlaybackDisabled.Value = clock.SeekingOrStopped.Value || !(currentScreen is ComposeScreen); - } - private void seek(UIEvent e, int direction) { double amount = e.ShiftPressed ? 4 : 1; @@ -936,11 +933,7 @@ namespace osu.Game.Screens.Edit protected void SwitchToDifficulty(BeatmapInfo nextBeatmap) => loader?.ScheduleSwitchToExistingDifficulty(nextBeatmap, GetState(nextBeatmap.Ruleset)); - private void cancelExit() - { - updateSampleDisabledState(); - loader?.CancelPendingDifficultySwitch(); - } + private void cancelExit() => loader?.CancelPendingDifficultySwitch(); public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime); diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 96425e8bc8..b9b0879fa4 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -10,6 +10,7 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Legacy; @@ -22,6 +23,15 @@ namespace osu.Game.Screens.Edit { public class EditorBeatmap : TransactionalCommitComponent, IBeatmap, IBeatSnapProvider { + /// + /// While performing updates on hitobjects, this will momentarily become true. + /// + /// + /// This is intended to be used to avoid performing operations (like playback of samples) + /// while mutating hitobjects. + /// + public bool UpdateInProgress { get; private set; } + /// /// Invoked when a is added to this . /// @@ -225,8 +235,12 @@ namespace osu.Game.Screens.Edit { // updates are debounced regardless of whether a batch is active. batchPendingUpdates.Add(hitObject); + + advertiseUpdateInProgress(); } + private ScheduledDelegate updateCompleteDelegate; + /// /// Update all hit objects with potentially changed difficulty or control point data. /// @@ -234,6 +248,8 @@ namespace osu.Game.Screens.Edit { foreach (var h in HitObjects) batchPendingUpdates.Add(h); + + advertiseUpdateInProgress(); } /// @@ -333,6 +349,15 @@ namespace osu.Game.Screens.Edit /// public void Clear() => RemoveRange(HitObjects.ToArray()); + private void advertiseUpdateInProgress() + { + UpdateInProgress = true; + + // Debounce is arbitrarily high enough to avoid flip-flopping the value each other frame. + updateCompleteDelegate?.Cancel(); + updateCompleteDelegate = Scheduler.AddDelayed(() => UpdateInProgress = false, 50); + } + private void processHitObject(HitObject hitObject) => hitObject.ApplyDefaults(ControlPointInfo, PlayableBeatmap.Difficulty); private void trackStartTime(HitObject hitObject) From e636fcd9b8312be89cf884ca98066becf4720288 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 15:35:32 +0900 Subject: [PATCH 0505/2686] Use DI'd components from parent class rather than fetching locally --- .../Edit/OsuSelectionHandler.cs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index e3cd31f6a3..44fbbd9591 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -16,7 +16,6 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; -using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components; using osuTK; using osuTK.Input; @@ -28,12 +27,6 @@ namespace osu.Game.Rulesets.Osu.Edit [Resolved(CanBeNull = true)] private IDistanceSnapProvider? snapProvider { get; set; } - [Resolved(CanBeNull = true)] - private EditorBeatmap? editorBeatmap { get; set; } - - [Resolved(CanBeNull = true)] - private IEditorChangeHandler? changeHandler { get; set; } - /// /// During a transform, the initial origin is stored so it can be used throughout the operation. /// @@ -355,10 +348,10 @@ namespace osu.Game.Rulesets.Osu.Edit private void mergeSelection() { - if (editorBeatmap == null || changeHandler == null || selectedMergeableObjects.Length < 2) + if (EditorBeatmap == null || ChangeHandler == null || selectedMergeableObjects.Length < 2) return; - changeHandler.BeginChange(); + ChangeHandler.BeginChange(); // Have an initial slider object. var firstHitObject = selectedMergeableObjects[0]; @@ -416,24 +409,24 @@ namespace osu.Game.Rulesets.Osu.Edit { foreach (var selectedMergeableObject in selectedMergeableObjects.Skip(1)) { - editorBeatmap.Remove(selectedMergeableObject); + EditorBeatmap.Remove(selectedMergeableObject); } } else { foreach (var selectedMergeableObject in selectedMergeableObjects) { - editorBeatmap.Remove(selectedMergeableObject); + EditorBeatmap.Remove(selectedMergeableObject); } - editorBeatmap.Add(mergedHitObject); + EditorBeatmap.Add(mergedHitObject); } // Make sure the merged hitobject is selected. SelectedItems.Clear(); SelectedItems.Add(mergedHitObject); - changeHandler.EndChange(); + ChangeHandler.EndChange(); } protected override IEnumerable GetContextMenuItemsForSelection(IEnumerable> selection) From ecb9351babd55217c0b28a5e20c3274be44669b2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 15:36:43 +0900 Subject: [PATCH 0506/2686] Remove unnecessary null pre-checks --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 44fbbd9591..363a191e34 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -348,10 +348,10 @@ namespace osu.Game.Rulesets.Osu.Edit private void mergeSelection() { - if (EditorBeatmap == null || ChangeHandler == null || selectedMergeableObjects.Length < 2) + if (selectedMergeableObjects.Length < 2) return; - ChangeHandler.BeginChange(); + ChangeHandler?.BeginChange(); // Have an initial slider object. var firstHitObject = selectedMergeableObjects[0]; @@ -426,7 +426,7 @@ namespace osu.Game.Rulesets.Osu.Edit SelectedItems.Clear(); SelectedItems.Add(mergedHitObject); - ChangeHandler.EndChange(); + ChangeHandler?.EndChange(); } protected override IEnumerable GetContextMenuItemsForSelection(IEnumerable> selection) From 7cc9fdbaa0d19f847cdc57264bc6652746ac91b3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 15:37:38 +0900 Subject: [PATCH 0507/2686] Simplify context menu check by using existing mergeable object list --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 363a191e34..663bf03a00 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -335,7 +335,7 @@ namespace osu.Game.Rulesets.Osu.Edit /// All osu! hitobjects which can be moved/rotated/scaled. /// private OsuHitObject[] selectedMovableObjects => SelectedItems.OfType() - .Where(h => !(h is Spinner)) + .Where(h => h is not Spinner) .ToArray(); /// @@ -434,7 +434,7 @@ namespace osu.Game.Rulesets.Osu.Edit foreach (var item in base.GetContextMenuItemsForSelection(selection)) yield return item; - if (selection.Count() > 1 && selection.All(o => o.Item is HitCircle or Slider)) + if (selectedMergeableObjects.Length > 1) yield return new OsuMenuItem("Merge selection", MenuItemType.Destructive, mergeSelection); } } From 0833a6fb9a3dec55c464f211340f1d51a1bbdb97 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 15:38:13 +0900 Subject: [PATCH 0508/2686] Avoid multiple iteration of LINQ query using a local --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 663bf03a00..f3c0a05bc2 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -348,13 +348,15 @@ namespace osu.Game.Rulesets.Osu.Edit private void mergeSelection() { - if (selectedMergeableObjects.Length < 2) + var mergeableObjects = selectedMergeableObjects; + + if (mergeableObjects.Length < 2) return; ChangeHandler?.BeginChange(); // Have an initial slider object. - var firstHitObject = selectedMergeableObjects[0]; + var firstHitObject = mergeableObjects[0]; var mergedHitObject = firstHitObject as Slider ?? new Slider { StartTime = firstHitObject.StartTime, @@ -371,7 +373,7 @@ namespace osu.Game.Rulesets.Osu.Edit // Merge all the selected hit objects into one slider path. bool lastCircle = firstHitObject is HitCircle; - foreach (var selectedMergeableObject in selectedMergeableObjects.Skip(1)) + foreach (var selectedMergeableObject in mergeableObjects.Skip(1)) { if (selectedMergeableObject is IHasPath hasPath) { @@ -407,14 +409,14 @@ namespace osu.Game.Rulesets.Osu.Edit // Make sure only the merged hit object is in the beatmap. if (firstHitObject is Slider) { - foreach (var selectedMergeableObject in selectedMergeableObjects.Skip(1)) + foreach (var selectedMergeableObject in mergeableObjects.Skip(1)) { EditorBeatmap.Remove(selectedMergeableObject); } } else { - foreach (var selectedMergeableObject in selectedMergeableObjects) + foreach (var selectedMergeableObject in mergeableObjects) { EditorBeatmap.Remove(selectedMergeableObject); } From 11f38e539f6571ff1811db64883a219e2930f5c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 16:01:19 +0900 Subject: [PATCH 0509/2686] Rename property to `LastLocalUpdate` --- osu.Game/Beatmaps/BeatmapInfo.cs | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- osu.Game/Database/RealmAccess.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 29f04e5a54..32b7f0b29b 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -105,7 +105,7 @@ namespace osu.Game.Beatmaps /// /// The last time of a local modification (via the editor). /// - public DateTimeOffset? LastUpdated { get; set; } + public DateTimeOffset? LastLocalUpdate { get; set; } /// /// The last time online metadata was applied to this beatmap. diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d6ef1e0173..d736765dd9 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -314,7 +314,7 @@ namespace osu.Game.Beatmaps beatmapInfo.MD5Hash = stream.ComputeMD5Hash(); beatmapInfo.Hash = stream.ComputeSHA2Hash(); - beatmapInfo.LastUpdated = DateTimeOffset.Now; + beatmapInfo.LastLocalUpdate = DateTimeOffset.Now; beatmapInfo.Status = BeatmapOnlineStatus.LocallyModified; AddFile(setInfo, stream, createBeatmapFilenameFromMetadata(beatmapInfo)); diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 40ac3b7422..cdaf35a1fb 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -68,7 +68,7 @@ namespace osu.Game.Database /// 20 2022-07-21 Added LastAppliedDifficultyVersion to RulesetInfo, changed default value of BeatmapInfo.StarRating to -1. /// 21 2022-07-27 Migrate collections to realm (BeatmapCollection). /// 22 2022-07-31 Added ModPreset. - /// 23 2022-08-01 Added LastUpdated to BeatmapInfo. + /// 23 2022-08-01 Added LastLocalUpdate to BeatmapInfo. /// private const int schema_version = 23; From 9d2c2b71cf07a172a0f83e246e79e6b06822e29a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 16:21:35 +0900 Subject: [PATCH 0510/2686] Change conditional to check for insertions in addition to modifications It is possible that the import process itself marks the previous beatmaps as deleted due to an overlap in metadata or otherwise. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index e9419e7156..e9f676d32f 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -273,11 +273,13 @@ namespace osu.Game.Screens.Select // Check if the current selection was potentially deleted by re-querying its validity. bool selectedSetMarkedDeleted = realm.Run(r => r.Find(SelectedBeatmapSet.ID))?.DeletePending != false; - if (selectedSetMarkedDeleted && changes.NewModifiedIndices.Any()) + int[] modifiedAndInserted = changes.NewModifiedIndices.Concat(changes.InsertedIndices).ToArray(); + + if (selectedSetMarkedDeleted && modifiedAndInserted.Any()) { // If it is no longer valid, make the bold assumption that an updated version will be available in the modified indices. // This relies on the full update operation being in a single transaction, so please don't change that. - foreach (int i in changes.NewModifiedIndices) + foreach (int i in modifiedAndInserted) { var beatmapSetInfo = sender[i]; From ee153a345c34c825852883723a8339a2593c062a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 16:31:56 +0900 Subject: [PATCH 0511/2686] Add a few more overlooked beatmap save states on setup screen modifications --- osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs | 1 + osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs | 1 + osu.Game/Screens/Edit/Setup/DifficultySection.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs b/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs index b602a67baa..81c41ab628 100644 --- a/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs +++ b/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs @@ -43,6 +43,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Setup private void updateBeatmap() { Beatmap.BeatmapInfo.SpecialStyle = specialStyle.Current.Value; + Beatmap.SaveState(); } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs b/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs index d8471aca1a..2889832ff1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs +++ b/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs @@ -49,6 +49,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Setup private void updateBeatmap() { Beatmap.BeatmapInfo.StackLeniency = stackLeniency.Current.Value; + Beatmap.SaveState(); } } } diff --git a/osu.Game/Screens/Edit/Setup/DifficultySection.cs b/osu.Game/Screens/Edit/Setup/DifficultySection.cs index 5ce5d05d64..ce44445683 100644 --- a/osu.Game/Screens/Edit/Setup/DifficultySection.cs +++ b/osu.Game/Screens/Edit/Setup/DifficultySection.cs @@ -96,6 +96,7 @@ namespace osu.Game.Screens.Edit.Setup Beatmap.Difficulty.OverallDifficulty = overallDifficultySlider.Current.Value; Beatmap.UpdateAllHitObjects(); + Beatmap.SaveState(); } } } From 1a7ddc004075c0ebb9774a64080314dfe1a3e7a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 16:43:05 +0900 Subject: [PATCH 0512/2686] Fix re-importing existing collections not correctly adding new items --- osu.Game/Database/LegacyCollectionImporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/LegacyCollectionImporter.cs b/osu.Game/Database/LegacyCollectionImporter.cs index 4bb28bf731..6d3e3fb76a 100644 --- a/osu.Game/Database/LegacyCollectionImporter.cs +++ b/osu.Game/Database/LegacyCollectionImporter.cs @@ -89,7 +89,7 @@ namespace osu.Game.Database if (existing != null) { - foreach (string newBeatmap in existing.BeatmapMD5Hashes) + foreach (string newBeatmap in collection.BeatmapMD5Hashes) { if (!existing.BeatmapMD5Hashes.Contains(newBeatmap)) existing.BeatmapMD5Hashes.Add(newBeatmap); From 5ac314077a706610c86ff9e3926fe57f0d46df10 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 16 Aug 2022 18:09:04 +0900 Subject: [PATCH 0513/2686] Improve intro timings when not using osu! theme Roughly as proposed in https://github.com/ppy/osu/discussions/19687. --- osu.Game/Screens/Menu/IntroCircles.cs | 11 ++++++++--- osu.Game/Screens/Menu/IntroScreen.cs | 14 ++++++++++---- osu.Game/Screens/Menu/IntroTriangles.cs | 15 +++++++++------ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index faa9a267ce..5f481ed00e 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -19,8 +19,11 @@ namespace osu.Game.Screens.Menu protected override string BeatmapFile => "circles.osz"; + public const double TRACK_START_DELAY_NON_THEMED = 1000; + private const double track_start_delay_themed = 600; + + private const double delay_for_menu = 2900; private const double delay_step_one = 2300; - private const double delay_step_two = 600; private Sample welcome; @@ -44,14 +47,16 @@ namespace osu.Game.Screens.Menu { welcome?.Play(); + double trackStartDelay = UsingThemedIntro ? track_start_delay_themed : TRACK_START_DELAY_NON_THEMED; + Scheduler.AddDelayed(delegate { StartTrack(); PrepareMenuLoad(); - Scheduler.AddDelayed(LoadMenu, delay_step_one); - }, delay_step_two); + Scheduler.AddDelayed(LoadMenu, delay_for_menu - trackStartDelay); + }, trackStartDelay); logo.ScaleTo(1); logo.FadeIn(); diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index a2ecd7eacb..bf713997f7 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -272,11 +272,17 @@ namespace osu.Game.Screens.Menu FadeInBackground(200); } - protected virtual void StartTrack() + protected void StartTrack() { - // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. - if (UsingThemedIntro) - Track.Start(); + var drawableTrack = musicController.CurrentTrack; + + drawableTrack.Start(); + + if (!UsingThemedIntro) + { + drawableTrack.VolumeTo(0).Then() + .VolumeTo(1, 2000, Easing.OutQuint); + } } protected override void LogoArriving(OsuLogo logo, bool resuming) diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 6ad0350e43..4ec79b852a 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -84,9 +84,17 @@ namespace osu.Game.Screens.Menu return; if (!UsingThemedIntro) + { + // If the user has requested no theme, fallback to the same intro voice and delay as IntroCircles. + // The triangles intro voice and theme are combined which makes it impossible to use. welcome?.Play(); + Scheduler.AddDelayed(StartTrack, IntroCircles.TRACK_START_DELAY_NON_THEMED); + } + else + StartTrack(); - StartTrack(); + // no-op for the case of themed intro, no harm in calling for both scenarios as a safety measure. + decoupledClock.Start(); }); } } @@ -99,11 +107,6 @@ namespace osu.Game.Screens.Menu intro.Expire(); } - protected override void StartTrack() - { - decoupledClock.Start(); - } - private class TrianglesIntroSequence : CompositeDrawable { private readonly OsuLogo logo; From 43e471c2a5832621ca91a4eea98650511a678bff Mon Sep 17 00:00:00 2001 From: StanR Date: Tue, 16 Aug 2022 16:12:13 +0300 Subject: [PATCH 0514/2686] Clamp effective miss count to maximum amount of possible braks --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 3c82c2dc33..fb0eff5cb2 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -270,8 +270,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty comboBasedMissCount = fullComboThreshold / Math.Max(1.0, scoreMaxCombo); } - // Clamp miss count since it's derived from combo and can be higher than total hits and that breaks some calculations - comboBasedMissCount = Math.Min(comboBasedMissCount, totalHits); + // Clamp miss count to maximum amount of possible breaks + comboBasedMissCount = Math.Min(comboBasedMissCount, countOk + countMeh + countMiss); return Math.Max(countMiss, comboBasedMissCount); } From 6bfdfeb15356941abc40ec1e1b5cdd4e293b04cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 16 Aug 2022 22:41:32 +0200 Subject: [PATCH 0515/2686] Refactor mod panel selection logic to avoid overwriting --- osu.Game/Overlays/Mods/ModPanel.cs | 22 +++++++++------------- osu.Game/Overlays/Mods/ModPresetPanel.cs | 16 +++++++++------- osu.Game/Overlays/Mods/ModSelectPanel.cs | 18 +++++++++++++++++- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModPanel.cs b/osu.Game/Overlays/Mods/ModPanel.cs index 0ab6293faf..8fc7d5a738 100644 --- a/osu.Game/Overlays/Mods/ModPanel.cs +++ b/osu.Game/Overlays/Mods/ModPanel.cs @@ -37,8 +37,6 @@ namespace osu.Game.Overlays.Mods Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), Scale = new Vector2(HEIGHT / ModSwitchSmall.DEFAULT_SIZE) }; - - Action = select; } public ModPanel(Mod mod) @@ -59,18 +57,16 @@ namespace osu.Game.Overlays.Mods Filtered.BindValueChanged(_ => updateFilterState(), true); } - private void select() + protected override void Select() { - if (!Active.Value) - { - modState.RequiresConfiguration = Mod.RequiresConfiguration; - Active.Value = true; - } - else - { - modState.RequiresConfiguration = false; - Active.Value = false; - } + modState.RequiresConfiguration = Mod.RequiresConfiguration; + Active.Value = true; + } + + protected override void Deselect() + { + modState.RequiresConfiguration = false; + Active.Value = false; } #region Filtering support diff --git a/osu.Game/Overlays/Mods/ModPresetPanel.cs b/osu.Game/Overlays/Mods/ModPresetPanel.cs index a259645479..b314a19142 100644 --- a/osu.Game/Overlays/Mods/ModPresetPanel.cs +++ b/osu.Game/Overlays/Mods/ModPresetPanel.cs @@ -37,8 +37,6 @@ namespace osu.Game.Overlays.Mods Title = preset.Value.Name; Description = preset.Value.Description; - - Action = toggleRequestedByUser; } [BackgroundDependencyLoader] @@ -54,15 +52,19 @@ namespace osu.Game.Overlays.Mods selectedMods.BindValueChanged(_ => selectedModsChanged(), true); } - private void toggleRequestedByUser() + protected override void Select() + { + // if the preset is not active at the point of the user click, then set the mods using the preset directly, discarding any previous selections, + // which will also have the side effect of activating the preset (see `updateActiveState()`). + selectedMods.Value = Preset.Value.Mods.ToArray(); + } + + protected override void Deselect() { - // if the preset is not active at the point of the user click, then set the mods using the preset directly, discarding any previous selections. // if the preset is active when the user has clicked it, then it means that the set of active mods is exactly equal to the set of mods in the preset // (there are no other active mods than what the preset specifies, and the mod settings match exactly). // therefore it's safe to just clear selected mods, since it will have the effect of toggling the preset off. - selectedMods.Value = !Active.Value - ? Preset.Value.Mods.ToArray() - : Array.Empty(); + selectedMods.Value = Array.Empty(); } private void selectedModsChanged() diff --git a/osu.Game/Overlays/Mods/ModSelectPanel.cs b/osu.Game/Overlays/Mods/ModSelectPanel.cs index b3df00f8f9..27abface0c 100644 --- a/osu.Game/Overlays/Mods/ModSelectPanel.cs +++ b/osu.Game/Overlays/Mods/ModSelectPanel.cs @@ -143,9 +143,25 @@ namespace osu.Game.Overlays.Mods } }; - Action = () => Active.Toggle(); + Action = () => + { + if (!Active.Value) + Select(); + else + Deselect(); + }; } + /// + /// Performs all actions necessary to select this . + /// + protected abstract void Select(); + + /// + /// Performs all actions necessary to deselect this . + /// + protected abstract void Deselect(); + [BackgroundDependencyLoader] private void load(AudioManager audio, ISamplePlaybackDisabler? samplePlaybackDisabler) { From 3109066e340d01f24b8c6c6e9b8787b35c0c2fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 16 Aug 2022 22:42:30 +0200 Subject: [PATCH 0516/2686] Rename `{Requires -> Pending}Configuration` --- osu.Game/Overlays/Mods/ModPanel.cs | 4 ++-- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 8 ++++---- osu.Game/Overlays/Mods/ModState.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModPanel.cs b/osu.Game/Overlays/Mods/ModPanel.cs index 8fc7d5a738..7bdb9511ac 100644 --- a/osu.Game/Overlays/Mods/ModPanel.cs +++ b/osu.Game/Overlays/Mods/ModPanel.cs @@ -59,13 +59,13 @@ namespace osu.Game.Overlays.Mods protected override void Select() { - modState.RequiresConfiguration = Mod.RequiresConfiguration; + modState.PendingConfiguration = Mod.RequiresConfiguration; Active.Value = true; } protected override void Deselect() { - modState.RequiresConfiguration = false; + modState.PendingConfiguration = false; Active.Value = false; } diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 66ecb9fd78..b993aca0ca 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -362,20 +362,20 @@ namespace osu.Game.Overlays.Mods return; bool anyCustomisableModActive = false; - bool anyModRequiresCustomisation = false; + bool anyModPendingConfiguration = false; foreach (var modState in allAvailableMods) { anyCustomisableModActive |= modState.Active.Value && modState.Mod.GetSettingsSourceProperties().Any(); - anyModRequiresCustomisation |= modState.RequiresConfiguration; - modState.RequiresConfiguration = false; + anyModPendingConfiguration |= modState.PendingConfiguration; + modState.PendingConfiguration = false; } if (anyCustomisableModActive) { customisationVisible.Disabled = false; - if (anyModRequiresCustomisation && !customisationVisible.Value) + if (anyModPendingConfiguration && !customisationVisible.Value) customisationVisible.Value = true; } else diff --git a/osu.Game/Overlays/Mods/ModState.cs b/osu.Game/Overlays/Mods/ModState.cs index a3806b1936..3ee890e876 100644 --- a/osu.Game/Overlays/Mods/ModState.cs +++ b/osu.Game/Overlays/Mods/ModState.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Mods /// This flag is read by the to determine if the customisation panel should be opened after a mod change /// and cleared after reading. /// - public bool RequiresConfiguration { get; set; } + public bool PendingConfiguration { get; set; } /// /// Whether the mod is currently filtered out due to not matching imposed criteria. From d021218d78cf102b45bf52d3670e5be9fc507a64 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 16 Aug 2022 23:05:35 +0200 Subject: [PATCH 0517/2686] added test for objects which cant be merged --- .../Editor/TestSceneObjectMerging.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs index 63e6760514..b68231ce64 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs @@ -141,6 +141,33 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor }); } + [Test] + public void TestNonMerge() + { + HitCircle? circle1 = null; + HitCircle? circle2 = null; + Spinner? spinner = null; + + AddStep("select first two circles and spinner", () => + { + circle1 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle); + circle2 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle && h != circle1); + spinner = (Spinner)EditorBeatmap.HitObjects.First(h => h is Spinner); + EditorClock.Seek(spinner.StartTime); + EditorBeatmap.SelectedHitObjects.Add(circle1); + EditorBeatmap.SelectedHitObjects.Add(circle2); + EditorBeatmap.SelectedHitObjects.Add(spinner); + }); + + mergeSelection(); + + AddAssert("slider created", () => circle1 is not null && circle2 is not null && sliderCreatedFor( + (pos: circle1.Position, pathType: PathType.Linear), + (pos: circle2.Position, pathType: null))); + + AddAssert("spinner not merged", () => EditorBeatmap.HitObjects.Contains(spinner)); + } + private void mergeSelection() { AddStep("merge selection", () => From 37799e3b31edc2fe4b71ce8308fbceecb2ec8646 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 13:20:24 +0900 Subject: [PATCH 0518/2686] Allow preparing preview point without looping --- osu.Game/Beatmaps/IWorkingBeatmap.cs | 2 +- osu.Game/Beatmaps/WorkingBeatmap.cs | 4 ++-- osu.Game/Screens/Menu/MainMenu.cs | 2 +- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/IWorkingBeatmap.cs b/osu.Game/Beatmaps/IWorkingBeatmap.cs index 548341cc77..a39766abe1 100644 --- a/osu.Game/Beatmaps/IWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/IWorkingBeatmap.cs @@ -134,6 +134,6 @@ namespace osu.Game.Beatmaps /// /// Reads the correct track restart point from beatmap metadata and sets looping to enabled. /// - void PrepareTrackForPreviewLooping(); + void PrepareTrackForPreview(bool looping); } } diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 16464932e0..301610ee58 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -110,9 +110,9 @@ namespace osu.Game.Beatmaps public Track LoadTrack() => track = GetBeatmapTrack() ?? GetVirtualTrack(1000); - public void PrepareTrackForPreviewLooping() + public void PrepareTrackForPreview(bool looping) { - Track.Looping = true; + Track.Looping = looping; Track.RestartPoint = Metadata.PreviewTime; if (Track.RestartPoint == -1) diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 066a37055c..0071ada05a 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -192,7 +192,7 @@ namespace osu.Game.Screens.Menu // presume the track is the current beatmap's track. not sure how correct this assumption is but it has worked until now. if (!track.IsRunning) { - Beatmap.Value.PrepareTrackForPreviewLooping(); + Beatmap.Value.PrepareTrackForPreview(false); track.Restart(); } } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 25f2a94a3c..03216180fb 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -485,7 +485,7 @@ namespace osu.Game.Screens.OnlinePlay.Match if (track != null) { - Beatmap.Value.PrepareTrackForPreviewLooping(); + Beatmap.Value.PrepareTrackForPreview(true); music?.EnsurePlayingSomething(); } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 33ff31857f..0c2ca6d4af 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -683,7 +683,7 @@ namespace osu.Game.Screens.Select } private void ensureTrackLooping(IWorkingBeatmap beatmap, TrackChangeDirection changeDirection) - => beatmap.PrepareTrackForPreviewLooping(); + => beatmap.PrepareTrackForPreview(true); public override bool OnBackButton() { From d9346abb9c3b390357d060441fc7020915573c9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 13:20:40 +0900 Subject: [PATCH 0519/2686] Tweak intro timings more and ensure non-theme tracks play from preview point --- osu.Game/Screens/Menu/IntroCircles.cs | 10 +++------- osu.Game/Screens/Menu/IntroScreen.cs | 14 ++++++++++---- osu.Game/Screens/Menu/IntroTriangles.cs | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index 5f481ed00e..7a4bdb231f 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -19,11 +19,9 @@ namespace osu.Game.Screens.Menu protected override string BeatmapFile => "circles.osz"; - public const double TRACK_START_DELAY_NON_THEMED = 1000; - private const double track_start_delay_themed = 600; + public const double TRACK_START_DELAY = 600; private const double delay_for_menu = 2900; - private const double delay_step_one = 2300; private Sample welcome; @@ -47,16 +45,14 @@ namespace osu.Game.Screens.Menu { welcome?.Play(); - double trackStartDelay = UsingThemedIntro ? track_start_delay_themed : TRACK_START_DELAY_NON_THEMED; - Scheduler.AddDelayed(delegate { StartTrack(); PrepareMenuLoad(); - Scheduler.AddDelayed(LoadMenu, delay_for_menu - trackStartDelay); - }, trackStartDelay); + Scheduler.AddDelayed(LoadMenu, delay_for_menu - TRACK_START_DELAY); + }, TRACK_START_DELAY); logo.ScaleTo(1); logo.FadeIn(); diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index bf713997f7..bd49eba663 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -276,12 +276,18 @@ namespace osu.Game.Screens.Menu { var drawableTrack = musicController.CurrentTrack; - drawableTrack.Start(); - if (!UsingThemedIntro) { - drawableTrack.VolumeTo(0).Then() - .VolumeTo(1, 2000, Easing.OutQuint); + initialBeatmap.PrepareTrackForPreview(false); + + drawableTrack.VolumeTo(0); + drawableTrack.Restart(); + drawableTrack.VolumeTo(1, 2200, Easing.InCubic); + } + else + + { + drawableTrack.Restart(); } } diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 4ec79b852a..d777f78df2 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -88,7 +88,7 @@ namespace osu.Game.Screens.Menu // If the user has requested no theme, fallback to the same intro voice and delay as IntroCircles. // The triangles intro voice and theme are combined which makes it impossible to use. welcome?.Play(); - Scheduler.AddDelayed(StartTrack, IntroCircles.TRACK_START_DELAY_NON_THEMED); + Scheduler.AddDelayed(StartTrack, IntroCircles.TRACK_START_DELAY); } else StartTrack(); From 0ff5547b8356fe9e06f1c3dc1325f2073bdfd608 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 13:35:44 +0900 Subject: [PATCH 0520/2686] Make `changeHandler` optional in `convertToStream` method to match new implementation --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index bd11cc826f..794551dab7 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -251,13 +251,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void convertToStream() { - if (editorBeatmap == null || changeHandler == null || beatDivisor == null) + if (editorBeatmap == null || beatDivisor == null) return; var timingPoint = editorBeatmap.ControlPointInfo.TimingPointAt(HitObject.StartTime); double streamSpacing = timingPoint.BeatLength / beatDivisor.Value; - changeHandler.BeginChange(); + changeHandler?.BeginChange(); int i = 0; double time = HitObject.StartTime; @@ -292,7 +292,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders editorBeatmap.Remove(HitObject); - changeHandler.EndChange(); + changeHandler?.EndChange(); } public override MenuItem[] ContextMenuItems => new MenuItem[] From 8b5ac55fca7b2cb3a5bf6a826de7f461aee14b3e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 17 Aug 2022 13:48:06 +0900 Subject: [PATCH 0521/2686] Remove newline --- osu.Game/Screens/Menu/IntroScreen.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index bd49eba663..a07ebb463a 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -285,7 +285,6 @@ namespace osu.Game.Screens.Menu drawableTrack.VolumeTo(1, 2200, Easing.InCubic); } else - { drawableTrack.Restart(); } From 8ce50e98a6ef52132350f77f186d9c01dec2b681 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 14:04:55 +0900 Subject: [PATCH 0522/2686] Move delegate debounce logic to `Editor` itself --- osu.Game/Screens/Edit/Editor.cs | 21 ++++++++++++++++++++- osu.Game/Screens/Edit/EditorBeatmap.cs | 24 ++++++++---------------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 90e912bd6d..9cf0a0fc0c 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -24,6 +24,7 @@ using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Framework.Threading; using osu.Framework.Timing; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -231,6 +232,8 @@ namespace osu.Game.Screens.Edit AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, loadableBeatmap.GetSkin(), loadableBeatmap.BeatmapInfo)); dependencies.CacheAs(editorBeatmap); + editorBeatmap.UpdateInProgress.BindValueChanged(updateInProgress); + canSave = editorBeatmap.BeatmapInfo.Ruleset.CreateInstance() is ILegacyRuleset; if (canSave) @@ -431,7 +434,7 @@ namespace osu.Game.Screens.Edit samplePlaybackDisabled.Value = clock.SeekingOrStopped.Value || currentScreen is not ComposeScreen - || editorBeatmap.UpdateInProgress; + || temporaryMuteFromUpdateInProgress; } public bool OnPressed(KeyBindingPressEvent e) @@ -717,6 +720,22 @@ namespace osu.Game.Screens.Edit this.Exit(); } + #region Mute from update application + + private ScheduledDelegate temporaryMuteRestorationDelegate; + private bool temporaryMuteFromUpdateInProgress; + + private void updateInProgress(ValueChangedEvent obj) + { + temporaryMuteFromUpdateInProgress = true; + + // Debounce is arbitrarily high enough to avoid flip-flopping the value each other frame. + temporaryMuteRestorationDelegate?.Cancel(); + temporaryMuteRestorationDelegate = Scheduler.AddDelayed(() => temporaryMuteFromUpdateInProgress = false, 50); + } + + #endregion + #region Clipboard support private EditorMenuItem cutMenuItem; diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index b9b0879fa4..6154485bc2 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -10,7 +10,6 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Legacy; @@ -24,13 +23,15 @@ namespace osu.Game.Screens.Edit public class EditorBeatmap : TransactionalCommitComponent, IBeatmap, IBeatSnapProvider { /// - /// While performing updates on hitobjects, this will momentarily become true. + /// Will become true when a new update is queued, and false when all updates have been applied. /// /// /// This is intended to be used to avoid performing operations (like playback of samples) /// while mutating hitobjects. /// - public bool UpdateInProgress { get; private set; } + public IBindable UpdateInProgress => updateInProgress; + + private readonly BindableBool updateInProgress = new BindableBool(); /// /// Invoked when a is added to this . @@ -236,11 +237,9 @@ namespace osu.Game.Screens.Edit // updates are debounced regardless of whether a batch is active. batchPendingUpdates.Add(hitObject); - advertiseUpdateInProgress(); + updateInProgress.Value = true; } - private ScheduledDelegate updateCompleteDelegate; - /// /// Update all hit objects with potentially changed difficulty or control point data. /// @@ -249,7 +248,7 @@ namespace osu.Game.Screens.Edit foreach (var h in HitObjects) batchPendingUpdates.Add(h); - advertiseUpdateInProgress(); + updateInProgress.Value = true; } /// @@ -342,6 +341,8 @@ namespace osu.Game.Screens.Edit foreach (var h in deletes) HitObjectRemoved?.Invoke(h); foreach (var h in inserts) HitObjectAdded?.Invoke(h); foreach (var h in updates) HitObjectUpdated?.Invoke(h); + + updateInProgress.Value = false; } /// @@ -349,15 +350,6 @@ namespace osu.Game.Screens.Edit /// public void Clear() => RemoveRange(HitObjects.ToArray()); - private void advertiseUpdateInProgress() - { - UpdateInProgress = true; - - // Debounce is arbitrarily high enough to avoid flip-flopping the value each other frame. - updateCompleteDelegate?.Cancel(); - updateCompleteDelegate = Scheduler.AddDelayed(() => UpdateInProgress = false, 50); - } - private void processHitObject(HitObject hitObject) => hitObject.ApplyDefaults(ControlPointInfo, PlayableBeatmap.Difficulty); private void trackStartTime(HitObject hitObject) From 6b9dec599698d8ee371837eb47b84e6b182d165a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 14:32:21 +0900 Subject: [PATCH 0523/2686] Restore original event flow to allow for `OnSuspend` case to work correctly --- osu.Game/Screens/Edit/Editor.cs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 9cf0a0fc0c..a7cbe1f1ad 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -226,6 +226,8 @@ namespace osu.Game.Screens.Edit dependencies.CacheAs(clock); AddInternal(clock); + clock.SeekingOrStopped.BindValueChanged(_ => updateSampleDisabledState()); + // todo: remove caching of this and consume via editorBeatmap? dependencies.Cache(beatDivisor); @@ -429,12 +431,7 @@ namespace osu.Game.Screens.Edit protected override void Update() { base.Update(); - clock.ProcessFrame(); - - samplePlaybackDisabled.Value = clock.SeekingOrStopped.Value - || currentScreen is not ComposeScreen - || temporaryMuteFromUpdateInProgress; } public bool OnPressed(KeyBindingPressEvent e) @@ -728,10 +725,15 @@ namespace osu.Game.Screens.Edit private void updateInProgress(ValueChangedEvent obj) { temporaryMuteFromUpdateInProgress = true; + updateSampleDisabledState(); // Debounce is arbitrarily high enough to avoid flip-flopping the value each other frame. temporaryMuteRestorationDelegate?.Cancel(); - temporaryMuteRestorationDelegate = Scheduler.AddDelayed(() => temporaryMuteFromUpdateInProgress = false, 50); + temporaryMuteRestorationDelegate = Scheduler.AddDelayed(() => + { + temporaryMuteFromUpdateInProgress = false; + updateSampleDisabledState(); + }, 50); } #endregion @@ -844,10 +846,18 @@ namespace osu.Game.Screens.Edit } finally { + updateSampleDisabledState(); rebindClipboardBindables(); } } + private void updateSampleDisabledState() + { + samplePlaybackDisabled.Value = clock.SeekingOrStopped.Value + || currentScreen is not ComposeScreen + || temporaryMuteFromUpdateInProgress; + } + private void seek(UIEvent e, int direction) { double amount = e.ShiftPressed ? 4 : 1; @@ -952,7 +962,11 @@ namespace osu.Game.Screens.Edit protected void SwitchToDifficulty(BeatmapInfo nextBeatmap) => loader?.ScheduleSwitchToExistingDifficulty(nextBeatmap, GetState(nextBeatmap.Ruleset)); - private void cancelExit() => loader?.CancelPendingDifficultySwitch(); + private void cancelExit() + { + updateSampleDisabledState(); + loader?.CancelPendingDifficultySwitch(); + } public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime); From 21b364cd7758f9574b94f3bdd97970e905c6bd18 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 14:48:00 +0900 Subject: [PATCH 0524/2686] Fix nullref in tests as `initialBeatmap` may be null --- osu.Game/Screens/Menu/IntroScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index a07ebb463a..409c7d6c8d 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -278,7 +278,7 @@ namespace osu.Game.Screens.Menu if (!UsingThemedIntro) { - initialBeatmap.PrepareTrackForPreview(false); + initialBeatmap?.PrepareTrackForPreview(false); drawableTrack.VolumeTo(0); drawableTrack.Restart(); From 7191fbb6d615c327b3a67dfe3a871fa5d0ba8fbd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 16:40:07 +0900 Subject: [PATCH 0525/2686] 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 247140ceef..74e5b49167 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c17d45e84a..c3c9834724 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 5bfb53bc9d..da48550efb 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From a5ac69a5549a11c4d12f2614a7afe589e438a136 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 16:42:34 +0900 Subject: [PATCH 0526/2686] Update various dependencies --- .../osu.Game.Rulesets.Osu.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game/osu.Game.csproj | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 4349d25cb3..36c40c0fe2 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 7615b3e8be..65679deb01 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -7,7 +7,7 @@ - + WinExe diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c3c9834724..d67f8415e7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,9 +23,9 @@ - - - + + + @@ -35,13 +35,13 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + - + From 3a0017c87b31a05b3b872f35793027356cb4e063 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 17 Aug 2022 17:07:06 +0900 Subject: [PATCH 0527/2686] Fix flaky quick retry test --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index a38089e023..b0d7eadaa7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -432,7 +432,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("restart completed", () => getCurrentPlayer() != null && getCurrentPlayer() != previousPlayer); AddStep("release quick retry key", () => InputManager.ReleaseKey(Key.Tilde)); - AddUntilStep("wait for load", () => getCurrentPlayer()?.LoadedBeatmapSuccessfully == true); + AddUntilStep("wait for player", () => getCurrentPlayer()?.LoadState == LoadState.Ready); AddUntilStep("time reached zero", () => getCurrentPlayer()?.GameplayClockContainer.CurrentTime > 0); AddUntilStep("skip button not visible", () => !checkSkipButtonVisible()); From 243fe56b1dc13987b12203537db12ab9a559ff3a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 17:11:17 +0900 Subject: [PATCH 0528/2686] Realm bump for props --- osu.Android.props | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 74e5b49167..6dbc6cc377 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -56,6 +56,6 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index da48550efb..463af1143f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -89,6 +89,6 @@ - + From fca076b9886f8552797e24b23c9f52603c718e5f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 17:17:22 +0900 Subject: [PATCH 0529/2686] Fix edge case of realm backup cascading failure --- osu.Game/Database/RealmAccess.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index cdaf35a1fb..dd219cc1aa 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -902,7 +902,14 @@ namespace osu.Game.Database { using (var source = storage.GetStream(Filename, mode: FileMode.Open)) using (var destination = storage.GetStream(backupFilename, FileAccess.Write, FileMode.CreateNew)) + { + // source may not exist. + if (source == null) + return; + source.CopyTo(destination); + } + return; } catch (IOException) From e1e6be039a234a3d0ba2cd44588a0cd0881dac0f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 18:20:47 +0900 Subject: [PATCH 0530/2686] Don't create destination stream if backup source doesn't exist --- osu.Game/Database/RealmAccess.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index dd219cc1aa..0f2e724567 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -901,13 +901,13 @@ namespace osu.Game.Database try { using (var source = storage.GetStream(Filename, mode: FileMode.Open)) - using (var destination = storage.GetStream(backupFilename, FileAccess.Write, FileMode.CreateNew)) { // source may not exist. if (source == null) return; - source.CopyTo(destination); + using (var destination = storage.GetStream(backupFilename, FileAccess.Write, FileMode.CreateNew)) + source.CopyTo(destination); } return; From 203b8b22b90216a26a02ae69294d52a41a248711 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 17 Aug 2022 19:02:13 +0900 Subject: [PATCH 0531/2686] Adjust tests --- .../ManiaDifficultyCalculatorTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs index 9e4db1f1c9..4ae6cb9c7c 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaDifficultyCalculatorTest.cs @@ -16,11 +16,11 @@ namespace osu.Game.Rulesets.Mania.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Mania"; - [TestCase(2.3449735700206298d, 242, "diffcalc-test")] + [TestCase(2.3493769750220914d, 242, "diffcalc-test")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(2.7879104989252959d, 242, "diffcalc-test")] + [TestCase(2.797245912537965d, 242, "diffcalc-test")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new ManiaModDoubleTime()); From f381bc91159db110cd5535bf46d2d0d878e93822 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 17 Aug 2022 19:03:48 +0900 Subject: [PATCH 0532/2686] Add explanatory comment --- osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs index d5cee47178..2c7c84de97 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs @@ -89,6 +89,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills startTimes[column] = startTime; endTimes[column] = endTime; + // By subtracting CurrentStrain, this skill effectively only considers the maximum strain of any one hitobject within each strain section. return individualStrain + overallStrain - CurrentStrain; } From 4ef4d66f491e6717ca9c3aece472e2b820e0563f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 16:39:24 +0900 Subject: [PATCH 0533/2686] Add some extra initial state checks to `TestSceneEditorSeekSnapping` --- osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs index d24baa6f63..2465512dae 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs @@ -173,6 +173,7 @@ namespace osu.Game.Tests.Visual.Editing reset(); AddStep("Seek(49)", () => Clock.Seek(49)); + checkTime(49); AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); checkTime(50); AddStep("Seek(49.999)", () => Clock.Seek(49.999)); @@ -207,6 +208,7 @@ namespace osu.Game.Tests.Visual.Editing reset(); AddStep("Seek(450)", () => Clock.Seek(450)); + checkTime(450); AddStep("SeekBackward", () => Clock.SeekBackward()); checkTime(400); AddStep("SeekBackward", () => Clock.SeekBackward()); @@ -228,6 +230,7 @@ namespace osu.Game.Tests.Visual.Editing reset(); AddStep("Seek(450)", () => Clock.Seek(450)); + checkTime(450); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); checkTime(400); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); @@ -252,6 +255,7 @@ namespace osu.Game.Tests.Visual.Editing reset(); AddStep("Seek(451)", () => Clock.Seek(451)); + checkTime(451); AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); checkTime(450); AddStep("Seek(450.999)", () => Clock.Seek(450.999)); @@ -276,6 +280,7 @@ namespace osu.Game.Tests.Visual.Editing double lastTime = 0; AddStep("Seek(0)", () => Clock.Seek(0)); + checkTime(0); for (int i = 0; i < 9; i++) { From 7d8fbc4dbc3408204dcd41f63063ed41642e702f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 17:36:41 +0900 Subject: [PATCH 0534/2686] Refactor `TestSceneDrawableTaikoMascot` to read a bit better --- .../Skinning/TestSceneDrawableTaikoMascot.cs | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs index ef95358d34..7dadac85bb 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using Humanizer; @@ -36,7 +34,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning TimeRange = { Value = 5000 }, }; - private TaikoScoreProcessor scoreProcessor; + private TaikoScoreProcessor scoreProcessor = null!; private IEnumerable mascots => this.ChildrenOfType(); @@ -89,9 +87,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [Test] public void TestIdleState() { - AddStep("set beatmap", () => setBeatmap()); - - createDrawableRuleset(); + prepareTest(false); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle); assertStateAfterResult(new JudgementResult(new Hit.StrongNestedHit(), new TaikoStrongJudgement()) { Type = HitResult.IgnoreMiss }, TaikoMascotAnimationState.Idle); @@ -100,9 +96,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [Test] public void TestKiaiState() { - AddStep("set beatmap", () => setBeatmap(true)); - - createDrawableRuleset(); + prepareTest(true); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Ok }, TaikoMascotAnimationState.Kiai); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoStrongJudgement()) { Type = HitResult.IgnoreMiss }, TaikoMascotAnimationState.Kiai); @@ -112,9 +106,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [Test] public void TestMissState() { - AddStep("set beatmap", () => setBeatmap()); - - createDrawableRuleset(); + prepareTest(false); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Fail); @@ -128,7 +120,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning { AddStep("set beatmap", () => setBeatmap(kiai)); - createDrawableRuleset(); + prepareTest(kiai); AddRepeatStep("reach 49 combo", () => applyNewResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }), 49); @@ -139,9 +131,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [TestCase(false, TaikoMascotAnimationState.Idle)] public void TestClearStateOnClearedSwell(bool kiai, TaikoMascotAnimationState expectedStateAfterClear) { - AddStep("set beatmap", () => setBeatmap(kiai)); - - createDrawableRuleset(); + prepareTest(kiai); assertStateAfterResult(new JudgementResult(new Swell(), new TaikoSwellJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Clear); AddUntilStep($"state reverts to {expectedStateAfterClear.ToString().ToLowerInvariant()}", () => allMascotsIn(expectedStateAfterClear)); @@ -175,25 +165,27 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning scoreProcessor.ApplyBeatmap(Beatmap.Value.Beatmap); } - private void createDrawableRuleset() + private void prepareTest(bool kiai) { - AddUntilStep("wait for beatmap to be loaded", () => Beatmap.Value.Track.IsLoaded); + AddStep("set beatmap", () => setBeatmap(kiai)); AddStep("create drawable ruleset", () => { - Beatmap.Value.Track.Start(); - SetContents(_ => { var ruleset = new TaikoRuleset(); return new DrawableTaikoRuleset(ruleset, Beatmap.Value.GetPlayableBeatmap(ruleset.RulesetInfo)); }); }); + + AddUntilStep("wait for track to be loaded", () => MusicController.TrackLoaded); + AddStep("start track", () => MusicController.CurrentTrack.Restart()); + AddUntilStep("wait for track started", () => MusicController.IsPlaying); } private void assertStateAfterResult(JudgementResult judgementResult, TaikoMascotAnimationState expectedState) { - TaikoMascotAnimationState[] mascotStates = null; + TaikoMascotAnimationState[] mascotStates = null!; AddStep($"{judgementResult.Type.ToString().ToLowerInvariant()} result for {judgementResult.Judgement.GetType().Name.Humanize(LetterCasing.LowerCase)}", () => @@ -204,7 +196,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning Schedule(() => mascotStates = animatedMascots.Select(mascot => mascot.State.Value).ToArray()); }); - AddAssert($"state is {expectedState.ToString().ToLowerInvariant()}", () => mascotStates.All(state => state == expectedState)); + AddAssert($"state is {expectedState.ToString().ToLowerInvariant()}", () => mascotStates.Distinct(), () => Is.EquivalentTo(new[] { expectedState })); } private void applyNewResult(JudgementResult judgementResult) From 553ae4781f0eb3dc6ca26c3def0ce1c43dd87d01 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 18:51:57 +0900 Subject: [PATCH 0535/2686] Remove unnecessary local implementation in `TestScenePlaybackControl` --- .../Visual/Editing/TestScenePlaybackControl.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestScenePlaybackControl.cs b/osu.Game.Tests/Visual/Editing/TestScenePlaybackControl.cs index 78f650f0fa..674476d644 100644 --- a/osu.Game.Tests/Visual/Editing/TestScenePlaybackControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestScenePlaybackControl.cs @@ -1,13 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Game.Beatmaps; -using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components; using osuTK; @@ -19,19 +15,12 @@ namespace osu.Game.Tests.Visual.Editing [BackgroundDependencyLoader] private void load() { - var clock = new EditorClock { IsCoupled = false }; - Dependencies.CacheAs(clock); - - var playback = new PlaybackControl + Child = new PlaybackControl { Anchor = Anchor.Centre, Origin = Anchor.Centre, Size = new Vector2(200, 100) }; - - Beatmap.Value = CreateWorkingBeatmap(new Beatmap()); - - Child = playback; } } } From d40d09a5442159c249e8cec887d004b5ca53f1b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 23:03:39 +0900 Subject: [PATCH 0536/2686] Rename method to be more specific and standardise `setBeatmap` calls --- .../Skinning/TestSceneDrawableTaikoMascot.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs index 7dadac85bb..9163f994c5 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs @@ -63,6 +63,8 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [Test] public void TestInitialState() { + AddStep("set beatmap", () => setBeatmap()); + AddStep("create mascot", () => SetContents(_ => new DrawableTaikoMascot { RelativeSizeAxes = Axes.Both })); AddAssert("mascot initially idle", () => allMascotsIn(TaikoMascotAnimationState.Idle)); @@ -87,7 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [Test] public void TestIdleState() { - prepareTest(false); + prepareDrawableRulesetAndBeatmap(false); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle); assertStateAfterResult(new JudgementResult(new Hit.StrongNestedHit(), new TaikoStrongJudgement()) { Type = HitResult.IgnoreMiss }, TaikoMascotAnimationState.Idle); @@ -96,7 +98,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [Test] public void TestKiaiState() { - prepareTest(true); + prepareDrawableRulesetAndBeatmap(true); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Ok }, TaikoMascotAnimationState.Kiai); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoStrongJudgement()) { Type = HitResult.IgnoreMiss }, TaikoMascotAnimationState.Kiai); @@ -106,7 +108,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [Test] public void TestMissState() { - prepareTest(false); + prepareDrawableRulesetAndBeatmap(false); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Fail); @@ -118,9 +120,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [TestCase(false)] public void TestClearStateOnComboMilestone(bool kiai) { - AddStep("set beatmap", () => setBeatmap(kiai)); - - prepareTest(kiai); + prepareDrawableRulesetAndBeatmap(kiai); AddRepeatStep("reach 49 combo", () => applyNewResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }), 49); @@ -131,7 +131,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [TestCase(false, TaikoMascotAnimationState.Idle)] public void TestClearStateOnClearedSwell(bool kiai, TaikoMascotAnimationState expectedStateAfterClear) { - prepareTest(kiai); + prepareDrawableRulesetAndBeatmap(kiai); assertStateAfterResult(new JudgementResult(new Swell(), new TaikoSwellJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Clear); AddUntilStep($"state reverts to {expectedStateAfterClear.ToString().ToLowerInvariant()}", () => allMascotsIn(expectedStateAfterClear)); @@ -165,7 +165,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning scoreProcessor.ApplyBeatmap(Beatmap.Value.Beatmap); } - private void prepareTest(bool kiai) + private void prepareDrawableRulesetAndBeatmap(bool kiai) { AddStep("set beatmap", () => setBeatmap(kiai)); From 3d14b14cfe4b53c78ce0a641e45ad525939fddb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 17 Aug 2022 21:52:55 +0200 Subject: [PATCH 0537/2686] Use alternative method for checking panel readiness to eliminate bool flag --- osu.Game/Overlays/Mods/ModColumn.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index cf123f0347..b9f7114f74 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -66,8 +66,8 @@ namespace osu.Game.Overlays.Mods private IModHotkeyHandler hotkeyHandler = null!; private Task? latestLoadTask; - private bool itemsLoaded; - internal bool ItemsLoaded => latestLoadTask?.IsCompleted == true && itemsLoaded; + private ICollection? latestLoadedPanels; + internal bool ItemsLoaded => latestLoadTask?.IsCompleted == true && latestLoadedPanels?.All(panel => panel.Parent != null) == true; public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; @@ -133,14 +133,13 @@ namespace osu.Game.Overlays.Mods { cancellationTokenSource?.Cancel(); - var panels = availableMods.Select(mod => CreateModPanel(mod).With(panel => panel.Shear = Vector2.Zero)); + var panels = availableMods.Select(mod => CreateModPanel(mod).With(panel => panel.Shear = Vector2.Zero)).ToArray(); + latestLoadedPanels = panels; - itemsLoaded = false; latestLoadTask = LoadComponentsAsync(panels, loaded => { ItemsFlow.ChildrenEnumerable = loaded; updateState(); - itemsLoaded = true; }, (cancellationTokenSource = new CancellationTokenSource()).Token); } From d06959e1ddcf0e13b82c1eb1eca97c52ef034e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 17 Aug 2022 22:03:35 +0200 Subject: [PATCH 0538/2686] Update incorrect xmldoc --- osu.Game/Screens/Ranking/Statistics/StatisticItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs index a3c51b4876..e1ea352f1c 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// /// Creates a new , to be displayed inside a in the results screen. /// - /// The name of the item. Can be to hide the item header. + /// The name of the item. Can be to hide the item header. /// A function returning the content to be displayed. /// Whether this item requires hit events. If true, will not be called if no hit events are available. /// The of this item. This can be thought of as the column dimension of an encompassing . From cb6339a20b50d1c8f250f0ca1588bb03c5341963 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Thu, 18 Aug 2022 01:29:03 +0200 Subject: [PATCH 0539/2686] added slider splitting option --- .../Components/PathControlPointVisualiser.cs | 48 +++++++++++-- .../Sliders/SliderSelectionBlueprint.cs | 70 ++++++++++++++++++- 2 files changed, 111 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 0506e8ab8a..3fb7ec93e6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -43,6 +43,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private InputManager inputManager; public Action> RemoveControlPointsRequested; + public Action> SplitControlPointsRequested; [Resolved(CanBeNull = true)] private IDistanceSnapProvider snapProvider { get; set; } @@ -104,6 +105,28 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components return true; } + // The slider can only be split on control points which connect two different slider segments. + private bool splittable(PathControlPointPiece p) => p.ControlPoint.Type.HasValue && p != Pieces[0] && p != Pieces[^1]; + + private bool splitSelected() + { + List toSplit = Pieces.Where(p => p.IsSelected.Value && splittable(p)).Select(p => p.ControlPoint).ToList(); + + // Ensure that there are any points to be split + if (toSplit.Count == 0) + return false; + + changeHandler?.BeginChange(); + SplitControlPointsRequested?.Invoke(toSplit); + changeHandler?.EndChange(); + + // Since pieces are re-used, they will not point to the deleted control points while remaining selected + foreach (var piece in Pieces) + piece.IsSelected.Value = false; + + return true; + } + private void onControlPointsChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) @@ -322,6 +345,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components if (count == 0) return null; + var splittablePieces = selectedPieces.Where(splittable).ToList(); + int splittableCount = splittablePieces.Count; + List items = new List(); if (!selectedPieces.Contains(Pieces[0])) @@ -333,14 +359,24 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components items.Add(createMenuItemForPathType(PathType.Bezier)); items.Add(createMenuItemForPathType(PathType.Catmull)); - return new MenuItem[] + var menuItems = new MenuItem[splittableCount > 0 ? 3 : 2]; + int i = 0; + + menuItems[i++] = new OsuMenuItem($"Delete {"control point".ToQuantity(count, count > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", MenuItemType.Destructive, + () => DeleteSelected()); + + if (splittableCount > 0) { - new OsuMenuItem($"Delete {"control point".ToQuantity(count, count > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", MenuItemType.Destructive, () => DeleteSelected()), - new OsuMenuItem("Curve type") - { - Items = items - } + menuItems[i++] = new OsuMenuItem($"Split {"control point".ToQuantity(splittableCount, splittableCount > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", + MenuItemType.Destructive, () => splitSelected()); + } + + menuItems[i] = new OsuMenuItem("Curve type") + { + Items = items }; + + return menuItems; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 794551dab7..70993ef7ac 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Utils; +using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; @@ -111,7 +112,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { AddInternal(ControlPointVisualiser = new PathControlPointVisualiser(HitObject, true) { - RemoveControlPointsRequested = removeControlPoints + RemoveControlPointsRequested = removeControlPoints, + SplitControlPointsRequested = splitControlPoints }); base.OnSelected(); @@ -249,6 +251,72 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders HitObject.Position += first; } + private void splitControlPoints(List toSplit) + { + // Ensure that there are any points to be split + if (toSplit.Count == 0) + return; + + foreach (var c in toSplit) + { + if (c == controlPoints[0] || c == controlPoints[^1] || c.Type is null) + continue; + + // Split off the section of slider before this control point so the remaining control points to split are in the latter part of the slider. + var splitControlPoints = controlPoints.TakeWhile(current => current != c).ToList(); + + if (splitControlPoints.Count == 0) + continue; + + foreach (var current in splitControlPoints) + { + controlPoints.Remove(current); + } + + splitControlPoints.Add(c); + + // Turn the control points which were split off into a new slider. + var samplePoint = (SampleControlPoint)HitObject.SampleControlPoint.DeepClone(); + samplePoint.Time = HitObject.StartTime; + var difficultyPoint = (DifficultyControlPoint)HitObject.DifficultyControlPoint.DeepClone(); + difficultyPoint.Time = HitObject.StartTime; + + var newSlider = new Slider + { + StartTime = HitObject.StartTime, + Position = HitObject.Position + splitControlPoints[0].Position, + NewCombo = HitObject.NewCombo, + SampleControlPoint = samplePoint, + DifficultyControlPoint = difficultyPoint, + Samples = HitObject.Samples.Select(s => s.With()).ToList(), + RepeatCount = HitObject.RepeatCount, + NodeSamples = HitObject.NodeSamples.Select(n => (IList)n.Select(s => s.With()).ToList()).ToList(), + Path = new SliderPath(splitControlPoints.Select(o => new PathControlPoint(o.Position - splitControlPoints[0].Position, o == splitControlPoints[^1] ? null : o.Type)).ToArray()) + }; + + editorBeatmap.Add(newSlider); + + HitObject.NewCombo = false; + HitObject.Path.ExpectedDistance.Value -= newSlider.Path.CalculatedDistance; + HitObject.StartTime += newSlider.SpanDuration; + + // In case the remainder of the slider has no length left over, give it length anyways so we don't get a 0 length slider. + if (HitObject.Path.ExpectedDistance.Value <= Precision.DOUBLE_EPSILON) + { + HitObject.Path.ExpectedDistance.Value = null; + } + } + + editorBeatmap.SelectedHitObjects.Clear(); + + // The path will have a non-zero offset if the head is removed, but sliders don't support this behaviour since the head is positioned at the slider's position + // So the slider needs to be offset by this amount instead, and all control points offset backwards such that the path is re-positioned at (0, 0) + Vector2 first = controlPoints[0].Position; + foreach (var c in controlPoints) + c.Position -= first; + HitObject.Position += first; + } + private void convertToStream() { if (editorBeatmap == null || beatDivisor == null) From 9735728cf65df91f4276414ee2d749f4235342a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 15:08:09 +0900 Subject: [PATCH 0540/2686] Reverse conditionals to better define intent in `addSourceClockAdjustments` --- .../Play/MasterGameplayClockContainer.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index ea4f767109..94967df840 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -216,11 +216,11 @@ namespace osu.Game.Screens.Play if (speedAdjustmentsApplied) return; - if (SourceClock is Track track) - { - track.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); - track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); - } + if (SourceClock is not Track track) + return; + + track.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); + track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); nonGameplayAdjustments.Add(pauseFreqAdjust); nonGameplayAdjustments.Add(UserPlaybackRate); @@ -233,11 +233,11 @@ namespace osu.Game.Screens.Play if (!speedAdjustmentsApplied) return; - if (SourceClock is Track track) - { - track.RemoveAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); - track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); - } + if (SourceClock is not Track track) + return; + + track.RemoveAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); + track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); nonGameplayAdjustments.Remove(pauseFreqAdjust); nonGameplayAdjustments.Remove(UserPlaybackRate); From 7512c126b79b06e84eb23eab38e09a777a14c8f0 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 18 Aug 2022 13:41:22 +0900 Subject: [PATCH 0541/2686] Upgrade LocalisationAnalyser and disable warning --- .globalconfig | 4 ++++ osu.Game/osu.Game.csproj | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.globalconfig b/.globalconfig index 462dbc74ed..a7b652c454 100644 --- a/.globalconfig +++ b/.globalconfig @@ -53,3 +53,7 @@ dotnet_diagnostic.CA2225.severity = none # Banned APIs dotnet_diagnostic.RS0030.severity = error + +# Temporarily disable analysing CanBeNull = true in NRT contexts due to mobile issues. +# See: https://github.com/ppy/osu/pull/19677 +dotnet_diagnostic.OSUF001.severity = none \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d67f8415e7..28452c0a74 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -31,7 +31,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 40b1554feab6e5d161c0f1f5315c1048a515a880 Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 18 Aug 2022 14:12:03 +0800 Subject: [PATCH 0542/2686] Change FindRepetitionInterval to start with one previous encoding --- .../Preprocessing/Colour/Data/CoupledColourEncoding.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs index 1b831eedd8..3f692e9d3d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs @@ -60,14 +60,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public void FindRepetitionInterval() { - if (Previous?.Previous == null) + if (Previous == null) { RepetitionInterval = max_repetition_interval + 1; return; } - CoupledColourEncoding? other = Previous.Previous; - int interval = 2; + CoupledColourEncoding? other = Previous; + int interval = 1; while (interval < max_repetition_interval) { From e55b94d4121d30db257a9bd231fbd921c59a7c8f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 18 Aug 2022 15:18:35 +0900 Subject: [PATCH 0543/2686] Also upgrade tools --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index cbd0231fdb..57694d7f57 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -21,7 +21,7 @@ ] }, "ppy.localisationanalyser.tools": { - "version": "2022.607.0", + "version": "2022.809.0", "commands": [ "localisation" ] From e0edaf996fa36c5ca15414739d34431de878da55 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 16:03:37 +0900 Subject: [PATCH 0544/2686] Test ruleset compatibility during initial startup to avoid runtime errors As we continue to break the ruleset API, it makes more sense to proactively check known changes and bail early during ruleset loading to avoid a user experiencing a crash at a random point during execution. This is a RFC and needs to be tested against known broken rulesets. There might be some other calls we want to add in addition to the ones I've listed. --- osu.Game/Rulesets/RealmRulesetStore.cs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/RealmRulesetStore.cs b/osu.Game/Rulesets/RealmRulesetStore.cs index 62a7a13c07..c014b2d095 100644 --- a/osu.Game/Rulesets/RealmRulesetStore.cs +++ b/osu.Game/Rulesets/RealmRulesetStore.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Logging; using osu.Framework.Platform; +using osu.Game.Beatmaps; using osu.Game.Database; namespace osu.Game.Rulesets @@ -83,17 +84,36 @@ namespace osu.Game.Rulesets r.InstantiationInfo = instanceInfo.InstantiationInfo; r.Available = true; + testRulesetCompatibility(r); + detachedRulesets.Add(r.Clone()); } catch (Exception ex) { r.Available = false; - Logger.Log($"Could not load ruleset {r}: {ex.Message}"); + Logger.Log($"Could not load ruleset {r.Name}. Please check for an update from the developer.", level: LogLevel.Error); + Logger.Log($"Ruleset load failed with {ex.Message}"); } } availableRulesets.AddRange(detachedRulesets.OrderBy(r => r)); }); } + + private void testRulesetCompatibility(RulesetInfo rulesetInfo) + { + // do various operations to ensure that we are in a good state. + // if we can avoid loading the ruleset at this point (rather than erroring later in runtime) then that is preferred. + var instance = rulesetInfo.CreateInstance(); + + instance.CreateAllMods(); + instance.CreateIcon(); + instance.CreateResourceStore(); + + var beatmap = new Beatmap(); + var converter = instance.CreateBeatmapConverter(beatmap); + + instance.CreateBeatmapProcessor(converter.Convert()); + } } } From b0a740071e93ff1a899d969f1fcf8f4a83bf95c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 16:14:38 +0900 Subject: [PATCH 0545/2686] Centralise logging of failed ruleset loads --- osu.Game/Rulesets/RealmRulesetStore.cs | 4 +--- osu.Game/Rulesets/RulesetStore.cs | 10 ++++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/RealmRulesetStore.cs b/osu.Game/Rulesets/RealmRulesetStore.cs index c014b2d095..7b1f3a3f6c 100644 --- a/osu.Game/Rulesets/RealmRulesetStore.cs +++ b/osu.Game/Rulesets/RealmRulesetStore.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Extensions.ObjectExtensions; -using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Database; @@ -91,8 +90,7 @@ namespace osu.Game.Rulesets catch (Exception ex) { r.Available = false; - Logger.Log($"Could not load ruleset {r.Name}. Please check for an update from the developer.", level: LogLevel.Error); - Logger.Log($"Ruleset load failed with {ex.Message}"); + LogFailedLoad(r.Name, ex); } } diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 6b3e43cc1c..fdbcd0ed1e 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -138,7 +138,7 @@ namespace osu.Game.Rulesets } catch (Exception e) { - Logger.Error(e, $"Failed to load ruleset {filename}"); + LogFailedLoad(filename, e); } } @@ -158,7 +158,7 @@ namespace osu.Game.Rulesets } catch (Exception e) { - Logger.Error(e, $"Failed to add ruleset {assembly}"); + LogFailedLoad(assembly.FullName, e); } } @@ -173,6 +173,12 @@ namespace osu.Game.Rulesets AppDomain.CurrentDomain.AssemblyResolve -= resolveRulesetDependencyAssembly; } + protected void LogFailedLoad(string name, Exception exception) + { + Logger.Log($"Could not load ruleset {name}. Please check for an update from the developer.", level: LogLevel.Error); + Logger.Log($"Ruleset load failed: {exception}"); + } + #region Implementation of IRulesetStore IRulesetInfo? IRulesetStore.GetRuleset(int id) => GetRuleset(id); From bb46f72f9ee3e48b6d723e634119eb737cb086fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 16:17:50 +0900 Subject: [PATCH 0546/2686] Fix `Pippidon` crash on empty beatmap conversion --- .../Beatmaps/PippidonBeatmapConverter.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Beatmaps/PippidonBeatmapConverter.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Beatmaps/PippidonBeatmapConverter.cs index 8f0b31ef1b..0a4fa84ce1 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Beatmaps/PippidonBeatmapConverter.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Beatmaps/PippidonBeatmapConverter.cs @@ -21,8 +21,11 @@ namespace osu.Game.Rulesets.Pippidon.Beatmaps public PippidonBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) : base(beatmap, ruleset) { - minPosition = beatmap.HitObjects.Min(getUsablePosition); - maxPosition = beatmap.HitObjects.Max(getUsablePosition); + if (beatmap.HitObjects.Any()) + { + minPosition = beatmap.HitObjects.Min(getUsablePosition); + maxPosition = beatmap.HitObjects.Max(getUsablePosition); + } } public override bool CanConvert() => Beatmap.HitObjects.All(h => h is IHasXPosition && h is IHasYPosition); From 48fac9f8a55bf1e63260d905b2fe48ea0fc148d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 16:50:08 +0900 Subject: [PATCH 0547/2686] Fix taiko drum rolls with zero length being placeable in editor Addresses https://github.com/ppy/osu/discussions/19808. --- .../Edit/Blueprints/TaikoSpanPlacementBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs index e49043e58e..23a005190a 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Taiko.Edit.Blueprints return; base.OnMouseUp(e); - EndPlacement(true); + EndPlacement(spanPlacementObject.Duration > 0); } public override void UpdateTimeAndPosition(SnapResult result) From ad28bfc9b2495752857f66d1ba346a2a55da3338 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 17:05:09 +0900 Subject: [PATCH 0548/2686] Fix taiko blueprints displaying incorrectly for drum rolls --- .../Objects/Drawables/DrawableDrumRoll.cs | 3 +++ .../Skinning/Legacy/LegacyCirclePiece.cs | 4 ++++ .../Skinning/Legacy/LegacyDrumRoll.cs | 18 +++++++++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 04ed6d0b87..68e334332e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osuTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; using osu.Framework.Input.Events; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; @@ -30,6 +31,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private const int rolling_hits_for_engaged_colour = 5; + public override Quad ScreenSpaceDrawQuad => MainPiece.Drawable.ScreenSpaceDrawQuad; + /// /// Rolling number of tick hits. This increases for hits and decreases for misses. /// diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs index 7f813e7b27..399bd9260d 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects; @@ -20,6 +21,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { private Drawable backgroundLayer; + // required for editor blueprints (not sure why these circle pieces are zero size). + public override Quad ScreenSpaceDrawQuad => backgroundLayer.ScreenSpaceDrawQuad; + public LegacyCirclePiece() { RelativeSizeAxes = Axes.Both; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs index d3bf70e603..040d8ff965 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Graphics; @@ -16,11 +17,22 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class LegacyDrumRoll : CompositeDrawable, IHasAccentColour { + public override Quad ScreenSpaceDrawQuad + { + get + { + var headDrawQuad = headCircle.ScreenSpaceDrawQuad; + var tailDrawQuad = tailCircle.ScreenSpaceDrawQuad; + + return new Quad(headDrawQuad.TopLeft, tailDrawQuad.TopRight, headDrawQuad.BottomLeft, tailDrawQuad.BottomRight); + } + } + private LegacyCirclePiece headCircle; private Sprite body; - private Sprite end; + private Sprite tailCircle; public LegacyDrumRoll() { @@ -32,7 +44,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { InternalChildren = new Drawable[] { - end = new Sprite + tailCircle = new Sprite { Anchor = Anchor.CentreRight, Origin = Anchor.CentreLeft, @@ -82,7 +94,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy headCircle.AccentColour = colour; body.Colour = colour; - end.Colour = colour; + tailCircle.Colour = colour; } } } From 5d8d584afb802369c03e602cae5fc4f704073d3f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 18 Aug 2022 18:08:46 +0900 Subject: [PATCH 0549/2686] Fix some backwards asserts --- osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index b7f91c22f4..c01b2576e8 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -199,14 +199,14 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("adjust track rate", () => ((MasterGameplayClockContainer)Player.GameplayClockContainer).UserPlaybackRate.Value = rate); addSeekStep(1000); - AddAssert("progress almost same", () => expectedProgress, () => Is.EqualTo(drawableSpinner.Progress).Within(0.05)); - AddAssert("spm almost same", () => expectedSpm, () => Is.EqualTo(drawableSpinner.SpinsPerMinute.Value).Within(2.0)); + AddAssert("progress almost same", () => drawableSpinner.Progress, () => Is.EqualTo(expectedProgress).Within(0.05)); + AddAssert("spm almost same", () => drawableSpinner.SpinsPerMinute.Value, () => Is.EqualTo(expectedSpm).Within(2.0)); } private void addSeekStep(double time) { AddStep($"seek to {time}", () => Player.GameplayClockContainer.Seek(time)); - AddUntilStep("wait for seek to finish", () => time, () => Is.EqualTo(Player.DrawableRuleset.FrameStableClock.CurrentTime).Within(100)); + AddUntilStep("wait for seek to finish", () => Player.DrawableRuleset.FrameStableClock.CurrentTime, () => Is.EqualTo(time).Within(100)); } private void transformReplay(Func replayTransformation) => AddStep("set replay", () => From 32e127a6fa995d63363d95d97e7089a5039ad895 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 15:39:28 +0900 Subject: [PATCH 0550/2686] Add `FramedBeatmapClock` Expose `IsCoupled` in `FramedBeatmapClock` for now to provide editor compatibility --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 167 ++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 osu.Game/Beatmaps/FramedBeatmapClock.cs diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs new file mode 100644 index 0000000000..925cc88fbd --- /dev/null +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -0,0 +1,167 @@ +// 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; +using osu.Framework.Allocation; +using osu.Framework.Audio.Track; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Timing; +using osu.Game.Configuration; +using osu.Game.Database; +using osu.Game.Screens.Play; + +namespace osu.Game.Beatmaps +{ + public class FramedBeatmapClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock + { + /// + /// The length of the underlying beatmap track. Will default to 60 seconds if unavailable. + /// + public double TrackLength => Track?.Length ?? 60000; + + /// + /// The underlying beatmap track, if available. + /// + public Track? Track { get; private set; } // TODO: virtual rather than null? + + private readonly OffsetCorrectionClock userGlobalOffsetClock; + private readonly OffsetCorrectionClock platformOffsetClock; + private readonly OffsetCorrectionClock finalOffsetClock; + + private Bindable userAudioOffset = null!; + + private IDisposable? beatmapOffsetSubscription; + + private readonly DecoupleableInterpolatingFramedClock decoupledClock; + + private double totalAppliedOffset => userGlobalOffsetClock.RateAdjustedOffset + finalOffsetClock.RateAdjustedOffset + platformOffsetClock.RateAdjustedOffset; + + [Resolved] + private OsuConfigManager config { get; set; } = null!; + + [Resolved] + private RealmAccess realm { get; set; } = null!; + + [Resolved] + private IBindable beatmap { get; set; } = null!; + + public bool IsCoupled + { + get => decoupledClock.IsCoupled; + set => decoupledClock.IsCoupled = value; + } + + public FramedBeatmapClock(IClock? sourceClock = null) + { + // TODO: Unused for now? + var pauseFreqAdjust = new BindableDouble(1); + + // A decoupled clock is used to ensure precise time values even when the host audio subsystem is not reporting + // high precision times (on windows there's generally only 5-10ms reporting intervals, as an example). + decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true }; + decoupledClock.ChangeSource(sourceClock); + + // Audio timings in general with newer BASS versions don't match stable. + // This only seems to be required on windows. We need to eventually figure out why, with a bit of luck. + platformOffsetClock = new OffsetCorrectionClock(decoupledClock, pauseFreqAdjust) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 15 : 0 }; + + // User global offset (set in settings) should also be applied. + userGlobalOffsetClock = new OffsetCorrectionClock(platformOffsetClock, pauseFreqAdjust); + + // User per-beatmap offset will be applied to this final clock. + finalOffsetClock = new OffsetCorrectionClock(userGlobalOffsetClock, pauseFreqAdjust); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); + userAudioOffset.BindValueChanged(offset => userGlobalOffsetClock.Offset = offset.NewValue, true); + + beatmapOffsetSubscription = realm.SubscribeToPropertyChanged( + r => r.Find(beatmap.Value.BeatmapInfo.ID)?.UserSettings, + settings => settings.Offset, + val => finalOffsetClock.Offset = val); + } + + protected override void Update() + { + base.Update(); + finalOffsetClock.ProcessFrame(); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + beatmapOffsetSubscription?.Dispose(); + } + + #region Delegation of IAdjustableClock / ISourceChangeableClock to decoupled clock. + + public void ChangeSource(IClock? source) + { + Track = source as Track; + decoupledClock.ChangeSource(source); + } + + public IClock? Source => decoupledClock.Source; + + public void Reset() + { + decoupledClock.Reset(); + finalOffsetClock.ProcessFrame(); + } + + public void Start() + { + decoupledClock.Start(); + finalOffsetClock.ProcessFrame(); + } + + public void Stop() + { + decoupledClock.Stop(); + finalOffsetClock.ProcessFrame(); + } + + public bool Seek(double position) + { + bool success = decoupledClock.Seek(position - totalAppliedOffset); + finalOffsetClock.ProcessFrame(); + + return success; + } + + public void ResetSpeedAdjustments() => decoupledClock.ResetSpeedAdjustments(); + + public double Rate + { + get => decoupledClock.Rate; + set => decoupledClock.Rate = value; + } + + #endregion + + #region Delegation of IFrameBasedClock to clock with all offsets applied + + public double CurrentTime => finalOffsetClock.CurrentTime; + + public bool IsRunning => finalOffsetClock.IsRunning; + + public void ProcessFrame() + { + // Noop to ensure an external consumer doesn't process the internal clock an extra time. + } + + public double ElapsedFrameTime => finalOffsetClock.ElapsedFrameTime; + + public double FramesPerSecond => finalOffsetClock.FramesPerSecond; + + public FrameTimeInfo TimeInfo => finalOffsetClock.TimeInfo; + + #endregion + } +} From 6003afafc790f20d78f884cde36b8cfa78980fe6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 14:52:47 +0900 Subject: [PATCH 0551/2686] Use `FramedBeatmapClock` in `GameplayClockContainer` --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 98 +++++++++++++------ .../Screens/Play/GameplayClockContainer.cs | 86 +++++++--------- .../Play/MasterGameplayClockContainer.cs | 78 +++------------ 3 files changed, 113 insertions(+), 149 deletions(-) diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index 925cc88fbd..f3219b972e 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Audio.Track; @@ -16,6 +17,8 @@ namespace osu.Game.Beatmaps { public class FramedBeatmapClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock { + private readonly bool applyOffsets; + /// /// The length of the underlying beatmap track. Will default to 60 seconds if unavailable. /// @@ -26,9 +29,16 @@ namespace osu.Game.Beatmaps /// public Track? Track { get; private set; } // TODO: virtual rather than null? - private readonly OffsetCorrectionClock userGlobalOffsetClock; - private readonly OffsetCorrectionClock platformOffsetClock; - private readonly OffsetCorrectionClock finalOffsetClock; + /// + /// The total frequency adjustment from pause transforms. Should eventually be handled in a better way. + /// + public readonly BindableDouble ExternalPauseFrequencyAdjust = new BindableDouble(1); + + private readonly OffsetCorrectionClock? userGlobalOffsetClock; + private readonly OffsetCorrectionClock? platformOffsetClock; + private readonly OffsetCorrectionClock? userBeatmapOffsetClock; + + private readonly IFrameBasedClock finalClockSource; private Bindable userAudioOffset = null!; @@ -36,7 +46,20 @@ namespace osu.Game.Beatmaps private readonly DecoupleableInterpolatingFramedClock decoupledClock; - private double totalAppliedOffset => userGlobalOffsetClock.RateAdjustedOffset + finalOffsetClock.RateAdjustedOffset + platformOffsetClock.RateAdjustedOffset; + private double totalAppliedOffset + { + get + { + if (!applyOffsets) + return 0; + + Debug.Assert(userGlobalOffsetClock != null); + Debug.Assert(userBeatmapOffsetClock != null); + Debug.Assert(platformOffsetClock != null); + + return userGlobalOffsetClock.RateAdjustedOffset + userBeatmapOffsetClock.RateAdjustedOffset + platformOffsetClock.RateAdjustedOffset; + } + } [Resolved] private OsuConfigManager config { get; set; } = null!; @@ -53,44 +76,59 @@ namespace osu.Game.Beatmaps set => decoupledClock.IsCoupled = value; } - public FramedBeatmapClock(IClock? sourceClock = null) + public FramedBeatmapClock(IClock? sourceClock = null, bool applyOffsets = false) { - // TODO: Unused for now? - var pauseFreqAdjust = new BindableDouble(1); + this.applyOffsets = applyOffsets; // A decoupled clock is used to ensure precise time values even when the host audio subsystem is not reporting // high precision times (on windows there's generally only 5-10ms reporting intervals, as an example). decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true }; decoupledClock.ChangeSource(sourceClock); - // Audio timings in general with newer BASS versions don't match stable. - // This only seems to be required on windows. We need to eventually figure out why, with a bit of luck. - platformOffsetClock = new OffsetCorrectionClock(decoupledClock, pauseFreqAdjust) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 15 : 0 }; + if (applyOffsets) + { + // Audio timings in general with newer BASS versions don't match stable. + // This only seems to be required on windows. We need to eventually figure out why, with a bit of luck. + platformOffsetClock = new OffsetCorrectionClock(decoupledClock, ExternalPauseFrequencyAdjust) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 15 : 0 }; - // User global offset (set in settings) should also be applied. - userGlobalOffsetClock = new OffsetCorrectionClock(platformOffsetClock, pauseFreqAdjust); + // User global offset (set in settings) should also be applied. + userGlobalOffsetClock = new OffsetCorrectionClock(platformOffsetClock, ExternalPauseFrequencyAdjust); - // User per-beatmap offset will be applied to this final clock. - finalOffsetClock = new OffsetCorrectionClock(userGlobalOffsetClock, pauseFreqAdjust); + // User per-beatmap offset will be applied to this final clock. + finalClockSource = userBeatmapOffsetClock = new OffsetCorrectionClock(userGlobalOffsetClock, ExternalPauseFrequencyAdjust); + } + else + { + finalClockSource = decoupledClock; + } } protected override void LoadComplete() { base.LoadComplete(); - userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); - userAudioOffset.BindValueChanged(offset => userGlobalOffsetClock.Offset = offset.NewValue, true); + if (applyOffsets) + { + Debug.Assert(userBeatmapOffsetClock != null); + Debug.Assert(userGlobalOffsetClock != null); - beatmapOffsetSubscription = realm.SubscribeToPropertyChanged( - r => r.Find(beatmap.Value.BeatmapInfo.ID)?.UserSettings, - settings => settings.Offset, - val => finalOffsetClock.Offset = val); + userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); + userAudioOffset.BindValueChanged(offset => userGlobalOffsetClock.Offset = offset.NewValue, true); + + beatmapOffsetSubscription = realm.SubscribeToPropertyChanged( + r => r.Find(beatmap.Value.BeatmapInfo.ID)?.UserSettings, + settings => settings.Offset, + val => + { + userBeatmapOffsetClock.Offset = val; + }); + } } protected override void Update() { base.Update(); - finalOffsetClock.ProcessFrame(); + finalClockSource.ProcessFrame(); } protected override void Dispose(bool isDisposing) @@ -112,25 +150,25 @@ namespace osu.Game.Beatmaps public void Reset() { decoupledClock.Reset(); - finalOffsetClock.ProcessFrame(); + finalClockSource.ProcessFrame(); } public void Start() { decoupledClock.Start(); - finalOffsetClock.ProcessFrame(); + finalClockSource.ProcessFrame(); } public void Stop() { decoupledClock.Stop(); - finalOffsetClock.ProcessFrame(); + finalClockSource.ProcessFrame(); } public bool Seek(double position) { bool success = decoupledClock.Seek(position - totalAppliedOffset); - finalOffsetClock.ProcessFrame(); + finalClockSource.ProcessFrame(); return success; } @@ -147,20 +185,20 @@ namespace osu.Game.Beatmaps #region Delegation of IFrameBasedClock to clock with all offsets applied - public double CurrentTime => finalOffsetClock.CurrentTime; + public double CurrentTime => finalClockSource.CurrentTime; - public bool IsRunning => finalOffsetClock.IsRunning; + public bool IsRunning => finalClockSource.IsRunning; public void ProcessFrame() { // Noop to ensure an external consumer doesn't process the internal clock an extra time. } - public double ElapsedFrameTime => finalOffsetClock.ElapsedFrameTime; + public double ElapsedFrameTime => finalClockSource.ElapsedFrameTime; - public double FramesPerSecond => finalOffsetClock.FramesPerSecond; + public double FramesPerSecond => finalClockSource.FramesPerSecond; - public FrameTimeInfo TimeInfo => finalOffsetClock.TimeInfo; + public FrameTimeInfo TimeInfo => finalClockSource.TimeInfo; #endregion } diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index ac846b45c4..de28f86824 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -11,12 +11,14 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Framework.Timing; using osu.Framework.Utils; +using osu.Game.Beatmaps; namespace osu.Game.Screens.Play { /// /// Encapsulates gameplay timing logic and provides a via DI for gameplay components to use. /// + [Cached(typeof(IGameplayClock))] public class GameplayClockContainer : Container, IAdjustableClock, IGameplayClock { /// @@ -45,44 +47,34 @@ namespace osu.Game.Screens.Play public virtual IEnumerable NonGameplayAdjustments => Enumerable.Empty(); - /// - /// The final clock which is exposed to gameplay components. - /// - protected IFrameBasedClock FramedClock { get; private set; } - private readonly BindableBool isPaused = new BindableBool(true); /// /// The adjustable source clock used for gameplay. Should be used for seeks and clock control. + /// This is the final clock exposed to gameplay components as an . /// - private readonly DecoupleableInterpolatingFramedClock decoupledClock; + protected readonly FramedBeatmapClock GameplayClock; + + protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; /// /// Creates a new . /// /// The source used for timing. - public GameplayClockContainer(IClock sourceClock) + /// Whether to apply platform, user and beatmap offsets to the mix. + public GameplayClockContainer(IClock sourceClock, bool applyOffsets = false) { SourceClock = sourceClock; RelativeSizeAxes = Axes.Both; - decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; + InternalChildren = new Drawable[] + { + GameplayClock = new FramedBeatmapClock(sourceClock, applyOffsets) { IsCoupled = false }, + Content + }; + IsPaused.BindValueChanged(OnIsPausedChanged); - - // this will be replaced during load, but non-null for tests which don't add this component to the hierarchy. - FramedClock = new FramedClock(); - } - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - - FramedClock = CreateGameplayClock(decoupledClock); - - dependencies.CacheAs(this); - - return dependencies; } /// @@ -92,13 +84,13 @@ namespace osu.Game.Screens.Play { ensureSourceClockSet(); - if (!decoupledClock.IsRunning) + if (!GameplayClock.IsRunning) { // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time // This accounts for the clock source potentially taking time to enter a completely stopped state - Seek(FramedClock.CurrentTime); + Seek(GameplayClock.CurrentTime); - decoupledClock.Start(); + GameplayClock.Start(); } isPaused.Value = false; @@ -112,10 +104,10 @@ namespace osu.Game.Screens.Play { Logger.Log($"{nameof(GameplayClockContainer)} seeking to {time}"); - decoupledClock.Seek(time); + GameplayClock.Seek(time); // Manually process to make sure the gameplay clock is correctly updated after a seek. - FramedClock.ProcessFrame(); + GameplayClock.ProcessFrame(); OnSeek?.Invoke(); } @@ -132,7 +124,7 @@ namespace osu.Game.Screens.Play public void Reset(bool startClock = false) { // Manually stop the source in order to not affect the IsPaused state. - decoupledClock.Stop(); + GameplayClock.Stop(); if (!IsPaused.Value || startClock) Start(); @@ -145,10 +137,10 @@ namespace osu.Game.Screens.Play /// Changes the source clock. /// /// The new source. - protected void ChangeSource(IClock sourceClock) => decoupledClock.ChangeSource(SourceClock = sourceClock); + protected void ChangeSource(IClock sourceClock) => GameplayClock.ChangeSource(SourceClock = sourceClock); /// - /// Ensures that the is set to , if it hasn't been given a source yet. + /// Ensures that the is set to , if it hasn't been given a source yet. /// This is usually done before a seek to avoid accidentally seeking only the adjustable source in decoupled mode, /// but not the actual source clock. /// That will pretty much only happen on the very first call of this method, as the source clock is passed in the constructor, @@ -156,40 +148,30 @@ namespace osu.Game.Screens.Play /// private void ensureSourceClockSet() { - if (decoupledClock.Source == null) + if (GameplayClock.Source == null) ChangeSource(SourceClock); } protected override void Update() { if (!IsPaused.Value) - FramedClock.ProcessFrame(); + GameplayClock.ProcessFrame(); base.Update(); } /// - /// Invoked when the value of is changed to start or stop the clock. + /// Invoked when the value of is changed to start or stop the clock. /// /// Whether the clock should now be paused. protected virtual void OnIsPausedChanged(ValueChangedEvent isPaused) { if (isPaused.NewValue) - decoupledClock.Stop(); + GameplayClock.Stop(); else - decoupledClock.Start(); + GameplayClock.Start(); } - /// - /// Creates the final which is exposed via DI to be used by gameplay components. - /// - /// - /// Any intermediate clocks such as platform offsets should be applied here. - /// - /// The providing the source time. - /// The final . - protected virtual IFrameBasedClock CreateGameplayClock(IFrameBasedClock source) => source; - #region IAdjustableClock bool IAdjustableClock.Seek(double position) @@ -204,15 +186,15 @@ namespace osu.Game.Screens.Play double IAdjustableClock.Rate { - get => FramedClock.Rate; + get => GameplayClock.Rate; set => throw new NotSupportedException(); } - public double Rate => FramedClock.Rate; + public double Rate => GameplayClock.Rate; - public double CurrentTime => FramedClock.CurrentTime; + public double CurrentTime => GameplayClock.CurrentTime; - public bool IsRunning => FramedClock.IsRunning; + public bool IsRunning => GameplayClock.IsRunning; #endregion @@ -221,11 +203,11 @@ namespace osu.Game.Screens.Play // Handled via update. Don't process here to safeguard from external usages potentially processing frames additional times. } - public double ElapsedFrameTime => FramedClock.ElapsedFrameTime; + public double ElapsedFrameTime => GameplayClock.ElapsedFrameTime; - public double FramesPerSecond => FramedClock.FramesPerSecond; + public double FramesPerSecond => GameplayClock.FramesPerSecond; - public FrameTimeInfo TimeInfo => FramedClock.TimeInfo; + public FrameTimeInfo TimeInfo => GameplayClock.TimeInfo; public double TrueGameplayRate { diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index d26f0c6311..51f57f27b8 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Framework; -using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; @@ -13,8 +11,6 @@ using osu.Framework.Graphics; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Configuration; -using osu.Game.Database; namespace osu.Game.Screens.Play { @@ -43,28 +39,10 @@ namespace osu.Game.Screens.Play Precision = 0.1, }; - private double totalAppliedOffset => userBeatmapOffsetClock.RateAdjustedOffset + userGlobalOffsetClock.RateAdjustedOffset + platformOffsetClock.RateAdjustedOffset; - - private readonly BindableDouble pauseFreqAdjust = new BindableDouble(); // Important that this starts at zero, matching the paused state of the clock. - private readonly WorkingBeatmap beatmap; - private OffsetCorrectionClock userGlobalOffsetClock = null!; - private OffsetCorrectionClock userBeatmapOffsetClock = null!; - private OffsetCorrectionClock platformOffsetClock = null!; - - private Bindable userAudioOffset = null!; - - private IDisposable? beatmapOffsetSubscription; - private readonly double skipTargetTime; - [Resolved] - private RealmAccess realm { get; set; } = null!; - - [Resolved] - private OsuConfigManager config { get; set; } = null!; - private readonly List> nonGameplayAdjustments = new List>(); public override IEnumerable NonGameplayAdjustments => nonGameplayAdjustments.Select(b => b.Value); @@ -75,7 +53,7 @@ namespace osu.Game.Screens.Play /// The beatmap to be used for time and metadata references. /// The latest time which should be used when introducing gameplay. Will be used when skipping forward. public MasterGameplayClockContainer(WorkingBeatmap beatmap, double skipTargetTime) - : base(beatmap.Track) + : base(beatmap.Track, true) { this.beatmap = beatmap; this.skipTargetTime = skipTargetTime; @@ -85,14 +63,6 @@ namespace osu.Game.Screens.Play { base.LoadComplete(); - userAudioOffset = config.GetBindable(OsuSetting.AudioOffset); - userAudioOffset.BindValueChanged(offset => userGlobalOffsetClock.Offset = offset.NewValue, true); - - beatmapOffsetSubscription = realm.SubscribeToPropertyChanged( - r => r.Find(beatmap.BeatmapInfo.ID)?.UserSettings, - settings => settings.Offset, - val => userBeatmapOffsetClock.Offset = val); - // Reset may have been called externally before LoadComplete. // If it was, and the clock is in a playing state, we want to ensure that it isn't stopped here. bool isStarted = !IsPaused.Value; @@ -133,14 +103,14 @@ namespace osu.Game.Screens.Play // During normal operation, the source is stopped after performing a frequency ramp. if (isPaused.NewValue) { - this.TransformBindableTo(pauseFreqAdjust, 0, 200, Easing.Out).OnComplete(_ => + this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 0, 200, Easing.Out).OnComplete(_ => { if (IsPaused.Value == isPaused.NewValue) base.OnIsPausedChanged(isPaused); }); } else - this.TransformBindableTo(pauseFreqAdjust, 1, 200, Easing.In); + this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 1, 200, Easing.In); } else { @@ -148,11 +118,11 @@ namespace osu.Game.Screens.Play base.OnIsPausedChanged(isPaused); // If not yet loaded, we still want to ensure relevant state is correct, as it is used for offset calculations. - pauseFreqAdjust.Value = isPaused.NewValue ? 0 : 1; + GameplayClock.ExternalPauseFrequencyAdjust.Value = isPaused.NewValue ? 0 : 1; // We must also process underlying gameplay clocks to update rate-adjusted offsets with the new frequency adjustment. // Without doing this, an initial seek may be performed with the wrong offset. - FramedClock.ProcessFrame(); + GameplayClock.ProcessFrame(); } } @@ -162,48 +132,23 @@ namespace osu.Game.Screens.Play base.Start(); } - /// - /// Seek to a specific time in gameplay. - /// - /// - /// Adjusts for any offsets which have been applied (so the seek may not be the expected point in time on the underlying audio track). - /// - /// The destination time to seek to. - public override void Seek(double time) - { - // remove the offset component here because most of the time we want the seek to be aligned to gameplay, not the audio track. - // we may want to consider reversing the application of offsets in the future as it may feel more correct. - base.Seek(time - totalAppliedOffset); - } - /// /// Skip forward to the next valid skip point. /// public void Skip() { - if (FramedClock.CurrentTime > skipTargetTime - MINIMUM_SKIP_TIME) + if (GameplayClock.CurrentTime > skipTargetTime - MINIMUM_SKIP_TIME) return; double skipTarget = skipTargetTime - MINIMUM_SKIP_TIME; - if (FramedClock.CurrentTime < 0 && skipTarget > 6000) + if (GameplayClock.CurrentTime < 0 && skipTarget > 6000) // double skip exception for storyboards with very long intros skipTarget = 0; Seek(skipTarget); } - protected override IFrameBasedClock CreateGameplayClock(IFrameBasedClock source) - { - // Lazer's audio timings in general doesn't match stable. This is the result of user testing, albeit limited. - // This only seems to be required on windows. We need to eventually figure out why, with a bit of luck. - platformOffsetClock = new OffsetCorrectionClock(source, pauseFreqAdjust) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 15 : 0 }; - - // the final usable gameplay clock with user-set offsets applied. - userGlobalOffsetClock = new OffsetCorrectionClock(platformOffsetClock, pauseFreqAdjust); - return userBeatmapOffsetClock = new OffsetCorrectionClock(userGlobalOffsetClock, pauseFreqAdjust); - } - /// /// Changes the backing clock to avoid using the originally provided track. /// @@ -224,10 +169,10 @@ namespace osu.Game.Screens.Play if (SourceClock is not Track track) return; - track.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); + track.AddAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); - nonGameplayAdjustments.Add(pauseFreqAdjust); + nonGameplayAdjustments.Add(GameplayClock.ExternalPauseFrequencyAdjust); nonGameplayAdjustments.Add(UserPlaybackRate); speedAdjustmentsApplied = true; @@ -241,10 +186,10 @@ namespace osu.Game.Screens.Play if (SourceClock is not Track track) return; - track.RemoveAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); + track.RemoveAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); - nonGameplayAdjustments.Remove(pauseFreqAdjust); + nonGameplayAdjustments.Remove(GameplayClock.ExternalPauseFrequencyAdjust); nonGameplayAdjustments.Remove(UserPlaybackRate); speedAdjustmentsApplied = false; @@ -253,7 +198,6 @@ namespace osu.Game.Screens.Play protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - beatmapOffsetSubscription?.Dispose(); removeSourceClockAdjustments(); } From bcc153f7387c0eb8273990397d6e9bb113f698b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 15:01:47 +0900 Subject: [PATCH 0552/2686] Add xmldoc and reorganise `FramedBeatmapClock` --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 45 +++++++++++++++---------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index f3219b972e..90ff0588a6 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -15,6 +15,15 @@ using osu.Game.Screens.Play; namespace osu.Game.Beatmaps { + /// + /// A clock intended to be the single source-of-truth for beatmap timing. + /// + /// It provides some functionality: + /// - Applies (and tracks changes of) beatmap, user, and platform offsets. + /// - Adjusts operations to account for said offsets, seeking in raw time values. + /// - Exposes track length. + /// - Allows changing the source to a new track (for cases like editor track updating). + /// public class FramedBeatmapClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock { private readonly bool applyOffsets; @@ -46,21 +55,6 @@ namespace osu.Game.Beatmaps private readonly DecoupleableInterpolatingFramedClock decoupledClock; - private double totalAppliedOffset - { - get - { - if (!applyOffsets) - return 0; - - Debug.Assert(userGlobalOffsetClock != null); - Debug.Assert(userBeatmapOffsetClock != null); - Debug.Assert(platformOffsetClock != null); - - return userGlobalOffsetClock.RateAdjustedOffset + userBeatmapOffsetClock.RateAdjustedOffset + platformOffsetClock.RateAdjustedOffset; - } - } - [Resolved] private OsuConfigManager config { get; set; } = null!; @@ -131,10 +125,19 @@ namespace osu.Game.Beatmaps finalClockSource.ProcessFrame(); } - protected override void Dispose(bool isDisposing) + private double totalAppliedOffset { - base.Dispose(isDisposing); - beatmapOffsetSubscription?.Dispose(); + get + { + if (!applyOffsets) + return 0; + + Debug.Assert(userGlobalOffsetClock != null); + Debug.Assert(userBeatmapOffsetClock != null); + Debug.Assert(platformOffsetClock != null); + + return userGlobalOffsetClock.RateAdjustedOffset + userBeatmapOffsetClock.RateAdjustedOffset + platformOffsetClock.RateAdjustedOffset; + } } #region Delegation of IAdjustableClock / ISourceChangeableClock to decoupled clock. @@ -201,5 +204,11 @@ namespace osu.Game.Beatmaps public FrameTimeInfo TimeInfo => finalClockSource.TimeInfo; #endregion + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + beatmapOffsetSubscription?.Dispose(); + } } } From 728cd96508ebdc0b19af16f3ac620e45d44704b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 16:32:43 +0900 Subject: [PATCH 0553/2686] Update `TestSceneLeadIn` to use new assert style --- .../Visual/Gameplay/TestSceneLeadIn.cs | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs index 0d80d29cab..25251bf1d6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.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. -#nullable disable - using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; @@ -19,7 +17,7 @@ namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneLeadIn : RateAdjustedBeatmapTestScene { - private LeadInPlayer player; + private LeadInPlayer player = null!; private const double lenience_ms = 10; @@ -36,11 +34,7 @@ namespace osu.Game.Tests.Visual.Gameplay BeatmapInfo = { AudioLeadIn = leadIn } }); - AddStep("check first frame time", () => - { - Assert.That(player.FirstFrameClockTime, Is.Not.Null); - Assert.That(player.FirstFrameClockTime.Value, Is.EqualTo(expectedStartTime).Within(lenience_ms)); - }); + checkFirstFrameTime(expectedStartTime); } [TestCase(1000, 0)] @@ -59,11 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), storyboard); - AddStep("check first frame time", () => - { - Assert.That(player.FirstFrameClockTime, Is.Not.Null); - Assert.That(player.FirstFrameClockTime.Value, Is.EqualTo(expectedStartTime).Within(lenience_ms)); - }); + checkFirstFrameTime(expectedStartTime); } [TestCase(1000, 0, false)] @@ -97,14 +87,13 @@ namespace osu.Game.Tests.Visual.Gameplay loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), storyboard); - AddStep("check first frame time", () => - { - Assert.That(player.FirstFrameClockTime, Is.Not.Null); - Assert.That(player.FirstFrameClockTime.Value, Is.EqualTo(expectedStartTime).Within(lenience_ms)); - }); + checkFirstFrameTime(expectedStartTime); } - private void loadPlayerWithBeatmap(IBeatmap beatmap, Storyboard storyboard = null) + private void checkFirstFrameTime(double expectedStartTime) => + AddAssert("check first frame time", () => player.FirstFrameClockTime, () => Is.EqualTo(expectedStartTime).Within(lenience_ms)); + + private void loadPlayerWithBeatmap(IBeatmap beatmap, Storyboard? storyboard = null) { AddStep("create player", () => { @@ -126,12 +115,8 @@ namespace osu.Game.Tests.Visual.Gameplay public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer; - public double GameplayStartTime => DrawableRuleset.GameplayStartTime; - public double FirstHitObjectTime => DrawableRuleset.Objects.First().StartTime; - public double GameplayClockTime => GameplayClockContainer.CurrentTime; - protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); From 2c6fd1ec6e681c2599a81775784e80f4ae866f26 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 18:10:20 +0900 Subject: [PATCH 0554/2686] Fix `GameplayClockContainer potentially resetting external seeks --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 2 +- osu.Game/Screens/Play/GameplayClockContainer.cs | 8 ++++---- osu.Game/Screens/Play/HUD/SongProgress.cs | 2 +- osu.Game/Screens/Play/IGameplayClock.cs | 6 +++--- .../Screens/Play/MasterGameplayClockContainer.cs | 14 +------------- 5 files changed, 10 insertions(+), 22 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index e41802808f..ab9558e77d 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -281,7 +281,7 @@ namespace osu.Game.Rulesets.UI } } - public double? StartTime => parentGameplayClock?.StartTime; + public double StartTime => parentGameplayClock?.StartTime ?? 0; public IEnumerable NonGameplayAdjustments => parentGameplayClock?.NonGameplayAdjustments ?? Enumerable.Empty(); diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index de28f86824..33f4f26dfb 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -40,10 +40,10 @@ namespace osu.Game.Screens.Play /// The time from which the clock should start. Will be seeked to on calling . /// /// - /// If not set, a value of zero will be used. - /// Importantly, the value will be inferred from the current ruleset in unless specified. + /// By default, a value of zero will be used. + /// Importantly, the value will be inferred from the current beatmap in by default. /// - public double? StartTime { get; set; } + public double StartTime { get; set; } = 0; public virtual IEnumerable NonGameplayAdjustments => Enumerable.Empty(); @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Play Start(); ensureSourceClockSet(); - Seek(StartTime ?? 0); + Seek(StartTime); } /// diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index f368edbfb9..0b6494bd8a 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -82,7 +82,7 @@ namespace osu.Game.Screens.Play.HUD if (isInIntro) { - double introStartTime = GameplayClock.StartTime ?? 0; + double introStartTime = GameplayClock.StartTime; double introOffsetCurrent = currentTime - introStartTime; double introDuration = FirstHitTime - introStartTime; diff --git a/osu.Game/Screens/Play/IGameplayClock.cs b/osu.Game/Screens/Play/IGameplayClock.cs index 5f54ce691a..ea567090ad 100644 --- a/osu.Game/Screens/Play/IGameplayClock.cs +++ b/osu.Game/Screens/Play/IGameplayClock.cs @@ -19,10 +19,10 @@ namespace osu.Game.Screens.Play /// The time from which the clock should start. Will be seeked to on calling . /// /// - /// If not set, a value of zero will be used. - /// Importantly, the value will be inferred from the current ruleset in unless specified. + /// By default, a value of zero will be used. + /// Importantly, the value will be inferred from the current beatmap in by default. /// - double? StartTime { get; } + double StartTime { get; } /// /// All adjustments applied to this clock which don't come from gameplay or mods. diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 51f57f27b8..eca0c92f8f 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -57,20 +57,8 @@ namespace osu.Game.Screens.Play { this.beatmap = beatmap; this.skipTargetTime = skipTargetTime; - } - protected override void LoadComplete() - { - base.LoadComplete(); - - // Reset may have been called externally before LoadComplete. - // If it was, and the clock is in a playing state, we want to ensure that it isn't stopped here. - bool isStarted = !IsPaused.Value; - - // If a custom start time was not specified, calculate the best value to use. - StartTime ??= findEarliestStartTime(); - - Reset(startClock: isStarted); + StartTime = findEarliestStartTime(); } private double findEarliestStartTime() From 343efa1d119dfdca5a342f70be5a563b2b8062ad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 2 Aug 2022 18:30:25 +0900 Subject: [PATCH 0555/2686] Split `OffsetCorrectionClock` out of `MasterGameplayClockContainer` --- .../Play/MasterGameplayClockContainer.cs | 67 ++++--------------- .../Screens/Play/OffsetCorrectionClock.cs | 53 +++++++++++++++ 2 files changed, 65 insertions(+), 55 deletions(-) create mode 100644 osu.Game/Screens/Play/OffsetCorrectionClock.cs diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 94967df840..d26f0c6311 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -49,9 +49,10 @@ namespace osu.Game.Screens.Play private readonly WorkingBeatmap beatmap; - private HardwareCorrectionOffsetClock userGlobalOffsetClock = null!; - private HardwareCorrectionOffsetClock userBeatmapOffsetClock = null!; - private HardwareCorrectionOffsetClock platformOffsetClock = null!; + private OffsetCorrectionClock userGlobalOffsetClock = null!; + private OffsetCorrectionClock userBeatmapOffsetClock = null!; + private OffsetCorrectionClock platformOffsetClock = null!; + private Bindable userAudioOffset = null!; private IDisposable? beatmapOffsetSubscription; @@ -64,6 +65,10 @@ namespace osu.Game.Screens.Play [Resolved] private OsuConfigManager config { get; set; } = null!; + private readonly List> nonGameplayAdjustments = new List>(); + + public override IEnumerable NonGameplayAdjustments => nonGameplayAdjustments.Select(b => b.Value); + /// /// Create a new master gameplay clock container. /// @@ -192,11 +197,11 @@ namespace osu.Game.Screens.Play { // Lazer's audio timings in general doesn't match stable. This is the result of user testing, albeit limited. // This only seems to be required on windows. We need to eventually figure out why, with a bit of luck. - platformOffsetClock = new HardwareCorrectionOffsetClock(source, pauseFreqAdjust) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 15 : 0 }; + platformOffsetClock = new OffsetCorrectionClock(source, pauseFreqAdjust) { Offset = RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? 15 : 0 }; // the final usable gameplay clock with user-set offsets applied. - userGlobalOffsetClock = new HardwareCorrectionOffsetClock(platformOffsetClock, pauseFreqAdjust); - return userBeatmapOffsetClock = new HardwareCorrectionOffsetClock(userGlobalOffsetClock, pauseFreqAdjust); + userGlobalOffsetClock = new OffsetCorrectionClock(platformOffsetClock, pauseFreqAdjust); + return userBeatmapOffsetClock = new OffsetCorrectionClock(userGlobalOffsetClock, pauseFreqAdjust); } /// @@ -254,55 +259,7 @@ namespace osu.Game.Screens.Play ControlPointInfo IBeatSyncProvider.ControlPoints => beatmap.Beatmap.ControlPointInfo; IClock IBeatSyncProvider.Clock => this; + ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; - - private class HardwareCorrectionOffsetClock : FramedOffsetClock - { - private readonly BindableDouble pauseRateAdjust; - - private double offset; - - public new double Offset - { - get => offset; - set - { - if (value == offset) - return; - - offset = value; - - updateOffset(); - } - } - - public double RateAdjustedOffset => base.Offset; - - public HardwareCorrectionOffsetClock(IClock source, BindableDouble pauseRateAdjust) - : base(source) - { - this.pauseRateAdjust = pauseRateAdjust; - } - - public override void ProcessFrame() - { - base.ProcessFrame(); - updateOffset(); - } - - private void updateOffset() - { - // changing this during the pause transform effect will cause a potentially large offset to be suddenly applied as we approach zero rate. - if (pauseRateAdjust.Value == 1) - { - // we always want to apply the same real-time offset, so it should be adjusted by the difference in playback rate (from realtime) to achieve this. - base.Offset = Offset * Rate; - } - } - } - - private readonly List> nonGameplayAdjustments = new List>(); - - public override IEnumerable NonGameplayAdjustments => nonGameplayAdjustments.Select(b => b.Value); } } diff --git a/osu.Game/Screens/Play/OffsetCorrectionClock.cs b/osu.Game/Screens/Play/OffsetCorrectionClock.cs new file mode 100644 index 0000000000..207980f45c --- /dev/null +++ b/osu.Game/Screens/Play/OffsetCorrectionClock.cs @@ -0,0 +1,53 @@ +// 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.Framework.Timing; + +namespace osu.Game.Screens.Play +{ + public class OffsetCorrectionClock : FramedOffsetClock + { + private readonly BindableDouble pauseRateAdjust; + + private double offset; + + public new double Offset + { + get => offset; + set + { + if (value == offset) + return; + + offset = value; + + updateOffset(); + } + } + + public double RateAdjustedOffset => base.Offset; + + public OffsetCorrectionClock(IClock source, BindableDouble pauseRateAdjust) + : base(source) + { + this.pauseRateAdjust = pauseRateAdjust; + } + + public override void ProcessFrame() + { + base.ProcessFrame(); + updateOffset(); + } + + private void updateOffset() + { + // changing this during the pause transform effect will cause a potentially large offset to be suddenly applied as we approach zero rate. + if (pauseRateAdjust.Value == 1) + { + // we always want to apply the same real-time offset, so it should be adjusted by the difference in playback rate (from realtime) to achieve this. + base.Offset = Offset * Rate; + } + } + } +} From 43879633db8810209ffeab2ed1f7d8f9f36a06ad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 18:28:55 +0900 Subject: [PATCH 0556/2686] Ensure setting a `StartTime` on a `GameplayClockContainer` always resets to the new time --- .../Gameplay/TestSceneStoryboardSamples.cs | 3 +++ osu.Game/Screens/Play/GameplayClockContainer.cs | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index 18ae2cb7c8..afdcedb485 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -90,6 +90,9 @@ namespace osu.Game.Tests.Gameplay AddUntilStep("sample has lifetime end", () => sample.LifetimeEnd < double.MaxValue); } + /// + /// Sample at 0ms, start time at 1000ms (so the sample should not be played). + /// [Test] public void TestSampleHasLifetimeEndWithInitialClockTime() { diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 33f4f26dfb..ae9779434d 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -38,12 +38,23 @@ namespace osu.Game.Screens.Play /// /// The time from which the clock should start. Will be seeked to on calling . + /// Settting a start time will to the new value. /// /// /// By default, a value of zero will be used. /// Importantly, the value will be inferred from the current beatmap in by default. /// - public double StartTime { get; set; } = 0; + public double StartTime + { + get => startTime; + set + { + startTime = value; + Reset(); + } + } + + private double startTime; public virtual IEnumerable NonGameplayAdjustments => Enumerable.Empty(); From 2eba8650cae909516b1a38c97c249d82cb25acbc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 16:32:43 +0900 Subject: [PATCH 0557/2686] Update `TestSceneLeadIn` to use new assert style --- .../Visual/Gameplay/TestSceneLeadIn.cs | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs index 0d80d29cab..25251bf1d6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.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. -#nullable disable - using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; @@ -19,7 +17,7 @@ namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneLeadIn : RateAdjustedBeatmapTestScene { - private LeadInPlayer player; + private LeadInPlayer player = null!; private const double lenience_ms = 10; @@ -36,11 +34,7 @@ namespace osu.Game.Tests.Visual.Gameplay BeatmapInfo = { AudioLeadIn = leadIn } }); - AddStep("check first frame time", () => - { - Assert.That(player.FirstFrameClockTime, Is.Not.Null); - Assert.That(player.FirstFrameClockTime.Value, Is.EqualTo(expectedStartTime).Within(lenience_ms)); - }); + checkFirstFrameTime(expectedStartTime); } [TestCase(1000, 0)] @@ -59,11 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), storyboard); - AddStep("check first frame time", () => - { - Assert.That(player.FirstFrameClockTime, Is.Not.Null); - Assert.That(player.FirstFrameClockTime.Value, Is.EqualTo(expectedStartTime).Within(lenience_ms)); - }); + checkFirstFrameTime(expectedStartTime); } [TestCase(1000, 0, false)] @@ -97,14 +87,13 @@ namespace osu.Game.Tests.Visual.Gameplay loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), storyboard); - AddStep("check first frame time", () => - { - Assert.That(player.FirstFrameClockTime, Is.Not.Null); - Assert.That(player.FirstFrameClockTime.Value, Is.EqualTo(expectedStartTime).Within(lenience_ms)); - }); + checkFirstFrameTime(expectedStartTime); } - private void loadPlayerWithBeatmap(IBeatmap beatmap, Storyboard storyboard = null) + private void checkFirstFrameTime(double expectedStartTime) => + AddAssert("check first frame time", () => player.FirstFrameClockTime, () => Is.EqualTo(expectedStartTime).Within(lenience_ms)); + + private void loadPlayerWithBeatmap(IBeatmap beatmap, Storyboard? storyboard = null) { AddStep("create player", () => { @@ -126,12 +115,8 @@ namespace osu.Game.Tests.Visual.Gameplay public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer; - public double GameplayStartTime => DrawableRuleset.GameplayStartTime; - public double FirstHitObjectTime => DrawableRuleset.Objects.First().StartTime; - public double GameplayClockTime => GameplayClockContainer.CurrentTime; - protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); From cc86909633782c406521d11840c9974fc7f8ab33 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 18:55:36 +0900 Subject: [PATCH 0558/2686] Increase lenience on `TestSceneLeadIn` tests I've gone through these in detail and can't find an issue with the actual flow of things. For whatever reason, the new structure has a slightly higher delay, likely due to performing less `Seek` calls (previously a `Seek` was called after the clock start which may have been making this more accurate on the first `Player.Update`). I don't think it really matters that this is slightly off, but we'll see how this plays out. --- osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs index 25251bf1d6..c066f1417c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Gameplay { private LeadInPlayer player = null!; - private const double lenience_ms = 10; + private const double lenience_ms = 100; private const double first_hit_object = 2170; From 0e228791c0c8353c0a277b9bb2b0aa7e8b5a41be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 19:02:13 +0900 Subject: [PATCH 0559/2686] Remove unnecessary `Reset` call in `MultiSpectatorScreen` --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 7ed0be50e5..f200702e80 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -160,8 +160,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { base.LoadComplete(); - masterClockContainer.Reset(); - syncManager.ReadyToStart += onReadyToStart; syncManager.MasterState.BindValueChanged(onMasterStateChanged, true); } From 7bc96431a782870ab9951edd63f194951bd942f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 19:08:23 +0900 Subject: [PATCH 0560/2686] Remove unnecessary `virtual` spec from `GameplayClockContainer.Seek` --- osu.Game/Screens/Play/GameplayClockContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index ae9779434d..6c900a727f 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -111,7 +111,7 @@ namespace osu.Game.Screens.Play /// Seek to a specific time in gameplay. /// /// The destination time to seek to. - public virtual void Seek(double time) + public void Seek(double time) { Logger.Log($"{nameof(GameplayClockContainer)} seeking to {time}"); From 1d774f3f12b1858275ae0d19608f7cdd872a65d2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 19:12:49 +0900 Subject: [PATCH 0561/2686] Remove redundant `ProcessFrame` calls Of note, I'm not sure whether the `IsPaused` check was meaningful, but it's not reimplemented in the new `FramedBeatmapClock`. --- osu.Game/Screens/Play/GameplayClockContainer.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 6c900a727f..8770c58430 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -117,9 +117,6 @@ namespace osu.Game.Screens.Play GameplayClock.Seek(time); - // Manually process to make sure the gameplay clock is correctly updated after a seek. - GameplayClock.ProcessFrame(); - OnSeek?.Invoke(); } @@ -163,14 +160,6 @@ namespace osu.Game.Screens.Play ChangeSource(SourceClock); } - protected override void Update() - { - if (!IsPaused.Value) - GameplayClock.ProcessFrame(); - - base.Update(); - } - /// /// Invoked when the value of is changed to start or stop the clock. /// From 3de35a15180fd37a72df6ae3bb72d589797f25ef Mon Sep 17 00:00:00 2001 From: Ryuki Date: Thu, 18 Aug 2022 18:40:02 +0200 Subject: [PATCH 0562/2686] Update calculator and tests to match changes on clocks --- .../Gameplay/TestSceneClicksPerSecond.cs | 22 ++++++++++++++++--- .../ClicksPerSecondCalculator.cs | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs index 8a5bd1af0f..69868e07b4 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Gameplay RelativeSizeAxes = Axes.Both, CachedDependencies = new (Type, object)[] { - (typeof(GameplayClock), mainClock = new MockFrameStableClock(new MockFrameBasedClock())), + (typeof(IGameplayClock), mainClock = new MockFrameStableClock(new MockFrameBasedClock())), (typeof(DrawableRuleset), new MockDrawableRuleset(ruleset, mainClock)) } }, @@ -249,17 +249,33 @@ namespace osu.Game.Tests.Visual.Gameplay public FrameTimeInfo TimeInfo { get; private set; } } - private class MockFrameStableClock : GameplayClock, IFrameStableClock + private class MockFrameStableClock : IGameplayClock, IFrameStableClock { + internal readonly IFrameBasedClock UnderlyingClock; + + public readonly BindableBool IsPaused = new BindableBool(); + public MockFrameStableClock(MockFrameBasedClock underlyingClock) - : base(underlyingClock) { + UnderlyingClock = underlyingClock; } public void Seek(double time) => (UnderlyingClock as MockFrameBasedClock)?.Seek(time); public IBindable IsCatchingUp => new Bindable(); public IBindable WaitingOnFrames => new Bindable(); + public double CurrentTime => UnderlyingClock.CurrentTime; + public double Rate => UnderlyingClock.Rate; + public bool IsRunning => UnderlyingClock.IsRunning; + public void ProcessFrame() => UnderlyingClock.ProcessFrame(); + + public double ElapsedFrameTime => UnderlyingClock.ElapsedFrameTime; + public double FramesPerSecond => UnderlyingClock.FramesPerSecond; + public FrameTimeInfo TimeInfo => UnderlyingClock.TimeInfo; + public double TrueGameplayRate => UnderlyingClock.Rate; + public double? StartTime => 0; + public IEnumerable NonGameplayAdjustments => Enumerable.Empty(); + IBindable IGameplayClock.IsPaused => IsPaused; } private class MockDrawableRuleset : DrawableRuleset diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs index 9dc8615fb6..d9c3c6ffec 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond private InputListener? listener; [Resolved] - private GameplayClock? gameplayClock { get; set; } + private IGameplayClock? gameplayClock { get; set; } [Resolved(canBeNull: true)] private DrawableRuleset? drawableRuleset { get; set; } From 15d49b0357f444fde1079a4eb095f5b1d9a8a5cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 19 Aug 2022 01:19:24 +0900 Subject: [PATCH 0563/2686] Update `TestSceneSpectator` to user new assert style --- osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index 0aa412a4fd..929af7f84d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -85,7 +85,7 @@ namespace osu.Game.Tests.Visual.Gameplay sendFrames(startTime: gameplay_start); - AddAssert("time is greater than seek target", () => currentFrameStableTime > gameplay_start); + AddAssert("time is greater than seek target", () => currentFrameStableTime, () => Is.GreaterThan(gameplay_start)); } /// @@ -119,7 +119,7 @@ namespace osu.Game.Tests.Visual.Gameplay waitForPlayer(); AddUntilStep("state is playing", () => spectatorClient.WatchedUserStates[streamingUser.Id].State == SpectatedUserState.Playing); - AddAssert("time is greater than seek target", () => currentFrameStableTime > gameplay_start); + AddAssert("time is greater than seek target", () => currentFrameStableTime, () => Is.GreaterThan(gameplay_start)); } [Test] @@ -147,7 +147,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for frame starvation", () => replayHandler.WaitingForFrame); checkPaused(true); - AddAssert("time advanced", () => currentFrameStableTime > pausedTime); + AddAssert("time advanced", () => currentFrameStableTime, () => Is.GreaterThan(pausedTime)); } [Test] @@ -176,7 +176,7 @@ namespace osu.Game.Tests.Visual.Gameplay sendFrames(300); - AddUntilStep("playing from correct point in time", () => player.ChildrenOfType().First().FrameStableClock.CurrentTime > 30000); + AddUntilStep("playing from correct point in time", () => player.ChildrenOfType().First().FrameStableClock.CurrentTime, () => Is.GreaterThan(30000)); } [Test] From 3eb1cda6aab101637516a5027311c3264858f3dc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 19 Aug 2022 01:40:12 +0900 Subject: [PATCH 0564/2686] Reorganise call order of `Start` / `Reset` to make more sense --- osu.Game/Screens/Play/GameplayClockContainer.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 8770c58430..9f13d15890 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -89,22 +89,22 @@ namespace osu.Game.Screens.Play } /// - /// Starts gameplay. + /// Starts gameplay and marks un-paused state. /// public virtual void Start() { ensureSourceClockSet(); + isPaused.Value = false; + + // the clock may be stopped via internal means (ie. not via `IsPaused`). if (!GameplayClock.IsRunning) { // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time // This accounts for the clock source potentially taking time to enter a completely stopped state Seek(GameplayClock.CurrentTime); - GameplayClock.Start(); } - - isPaused.Value = false; } /// @@ -121,7 +121,7 @@ namespace osu.Game.Screens.Play } /// - /// Stops gameplay. + /// Stops gameplay and marks paused state. /// public void Stop() => isPaused.Value = true; @@ -134,11 +134,11 @@ namespace osu.Game.Screens.Play // Manually stop the source in order to not affect the IsPaused state. GameplayClock.Stop(); - if (!IsPaused.Value || startClock) - Start(); - ensureSourceClockSet(); Seek(StartTime); + + if (!IsPaused.Value || startClock) + Start(); } /// From 7add3a69508abd2d2cffc9f9ec0ebe329b9faa26 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Thu, 18 Aug 2022 19:00:54 +0200 Subject: [PATCH 0565/2686] ar var test --- osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs | 61 +++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs new file mode 100644 index 0000000000..e291e92901 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs @@ -0,0 +1,61 @@ +// 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.Framework.Bindables; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Mods +{ + public class OsuModFlash : ModWithVisibilityAdjustment, IApplicableAfterBeatmapConversion + { + public override string Name => "Var AR Test"; + public override string Acronym => "TP"; + public override ModType Type => ModType.Fun; + public override IconUsage? Icon => FontAwesome.Regular.Sun; + public override string Description => @"how far will your reading stretch"; + public override double ScoreMultiplier => 1.03; + + public override void ApplyToBeatmap(IBeatmap beatmap) + { + base.ApplyToBeatmap(beatmap); + double lastObjectEnd = beatmap.HitObjects.LastOrDefault()?.GetEndTime() ?? 0; + + foreach (var obj in beatmap.HitObjects.OfType()) + applyVariableAr(obj); + + void applyVariableAr(OsuHitObject osuObject) + { + double percentageofmap = osuObject.StartTime / lastObjectEnd; + osuObject.TimePreempt = (percentageofmap * osuObject.TimePreempt) * ARadded.Value + osuObject.TimePreempt; + foreach (var nested in osuObject.NestedHitObjects.OfType()) + applyVariableAr(nested); + } + } + + protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) + { + } + + protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) + { + } + + [SettingSource("Additional AR", "how much AR change to add")] + public BindableDouble ARadded { get; } = new BindableDouble(1) + { + Precision = 0.1f, + MinValue = 0, + MaxValue = 10, + }; + + /*[SettingSource("Additional Ar", "how much ar change to add")] + public BindableBool scaledown { get; } = new BindableBool();*/ + } +} From 4c24d8ed58ff64f69f474f9f38d45a3e7372bb2d Mon Sep 17 00:00:00 2001 From: its5Q Date: Fri, 19 Aug 2022 03:17:05 +1000 Subject: [PATCH 0566/2686] Improve string consistency --- osu.Game/Localisation/EditorSetupStrings.cs | 8 ++++---- osu.Game/Screens/Edit/Setup/ColoursSection.cs | 2 +- osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Localisation/EditorSetupStrings.cs b/osu.Game/Localisation/EditorSetupStrings.cs index 9512f3ff14..0431b9cf76 100644 --- a/osu.Game/Localisation/EditorSetupStrings.cs +++ b/osu.Game/Localisation/EditorSetupStrings.cs @@ -10,9 +10,9 @@ namespace osu.Game.Localisation private const string prefix = @"osu.Game.Resources.Localisation.EditorSetup"; /// - /// "beatmap setup" + /// "Beatmap Setup" /// - public static LocalisableString BeatmapSetup => new TranslatableString(getKey(@"beatmap_setup"), @"beatmap setup"); + public static LocalisableString BeatmapSetup => new TranslatableString(getKey(@"beatmap_setup"), @"Beatmap Setup"); /// /// "change general settings of your beatmap" @@ -25,9 +25,9 @@ namespace osu.Game.Localisation public static LocalisableString ColoursHeader => new TranslatableString(getKey(@"colours_header"), @"Colours"); /// - /// "Hitcircle / Slider Combos" + /// "Hit circle / Slider Combos" /// - public static LocalisableString HitcircleSliderCombos => new TranslatableString(getKey(@"hitcircle_slider_combos"), @"Hitcircle / Slider Combos"); + public static LocalisableString HitCircleSliderCombos => new TranslatableString(getKey(@"hit_circle_slider_combos"), @"Hit circle / Slider Combos"); /// /// "Design" diff --git a/osu.Game/Screens/Edit/Setup/ColoursSection.cs b/osu.Game/Screens/Edit/Setup/ColoursSection.cs index 9334967a3e..e3fcdedd1b 100644 --- a/osu.Game/Screens/Edit/Setup/ColoursSection.cs +++ b/osu.Game/Screens/Edit/Setup/ColoursSection.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit.Setup { comboColours = new LabelledColourPalette { - Label = EditorSetupStrings.HitcircleSliderCombos, + Label = EditorSetupStrings.HitCircleSliderCombos, FixedLabelWidth = LABEL_WIDTH, ColourNamePrefix = EditorSetupStrings.ComboColourPrefix } diff --git a/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs b/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs index c1f6ab556c..9486b3728b 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs @@ -4,6 +4,7 @@ #nullable disable using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -78,7 +79,7 @@ namespace osu.Game.Screens.Edit.Setup { public SetupScreenTitle() { - Title = EditorSetupStrings.BeatmapSetup; + Title = EditorSetupStrings.BeatmapSetup.ToLower(); Description = EditorSetupStrings.BeatmapSetupDescription; IconTexture = "Icons/Hexacons/social"; } From 89eb0a4079c4b5564e47623008ff81067a2e4a08 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Fri, 19 Aug 2022 01:10:54 +0200 Subject: [PATCH 0567/2686] Added TestScene for slider splitting --- .../Editor/TestSceneSliderSplitting.cs | 127 ++++++++++++++++++ .../Sliders/SliderSelectionBlueprint.cs | 8 +- 2 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs new file mode 100644 index 0000000000..4693d56789 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs @@ -0,0 +1,127 @@ +// 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 NUnit.Framework; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Tests.Beatmaps; +using osu.Game.Tests.Visual; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Tests.Editor +{ + public class TestSceneSliderSplitting : EditorTestScene + { + protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false); + + private ComposeBlueprintContainer blueprintContainer + => Editor.ChildrenOfType().First(); + + private ContextMenuContainer contextMenuContainer + => Editor.ChildrenOfType().First(); + + private Slider? slider; + private PathControlPointVisualiser? visualiser; + + [Test] + public void TestBasicSplit() + { + AddStep("add slider", () => + { + slider = new Slider + { + Position = new Vector2(0, 50), + Path = new SliderPath(new[] + { + new PathControlPoint(Vector2.Zero, PathType.PerfectCurve), + new PathControlPoint(new Vector2(150, 150)), + new PathControlPoint(new Vector2(300, 0), PathType.PerfectCurve), + new PathControlPoint(new Vector2(400, 0)), + new PathControlPoint(new Vector2(400, 150)) + }) + }; + + EditorBeatmap.Add(slider); + }); + + AddStep("select added slider", () => + { + EditorBeatmap.SelectedHitObjects.Add(slider); + visualiser = blueprintContainer.SelectionBlueprints.First(o => o.Item == slider).ChildrenOfType().First(); + }); + + moveMouseToControlPoint(2); + AddStep("select control point", () => + { + if (visualiser is not null) visualiser.Pieces[2].IsSelected.Value = true; + }); + addContextMenuItemStep("Split control point"); + } + + [Test] + public void TestStartTimeOffsetPlusDeselect() + { + HitCircle? circle = null; + + AddStep("add circle", () => + { + circle = new HitCircle(); + + EditorBeatmap.Add(circle); + }); + + AddStep("select added circle", () => + { + EditorBeatmap.SelectedHitObjects.Add(circle); + }); + + AddStep("add another circle", () => + { + var circle2 = new HitCircle(); + + EditorBeatmap.Add(circle2); + }); + + AddStep("change time of selected circle and deselect", () => + { + if (circle is null) return; + + circle.StartTime += 1; + EditorBeatmap.SelectedHitObjects.Clear(); + }); + } + + private void moveMouseToControlPoint(int index) + { + AddStep($"move mouse to control point {index}", () => + { + if (slider is null || visualiser is null) return; + + Vector2 position = slider.Path.ControlPoints[index].Position + slider.Position; + InputManager.MoveMouseTo(visualiser.Pieces[0].Parent.ToScreenSpace(position)); + }); + } + + private void addContextMenuItemStep(string contextMenuText) + { + AddStep($"click context menu item \"{contextMenuText}\"", () => + { + if (visualiser is null) return; + + MenuItem? item = visualiser.ContextMenuItems.FirstOrDefault(menuItem => menuItem.Text.Value == contextMenuText); + + item?.Action?.Value(); + }); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 70993ef7ac..e28dbb485d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -294,11 +294,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders Path = new SliderPath(splitControlPoints.Select(o => new PathControlPoint(o.Position - splitControlPoints[0].Position, o == splitControlPoints[^1] ? null : o.Type)).ToArray()) }; + HitObject.StartTime += 1; + editorBeatmap.Add(newSlider); HitObject.NewCombo = false; HitObject.Path.ExpectedDistance.Value -= newSlider.Path.CalculatedDistance; - HitObject.StartTime += newSlider.SpanDuration; + HitObject.StartTime += newSlider.SpanDuration - 1; // In case the remainder of the slider has no length left over, give it length anyways so we don't get a 0 length slider. if (HitObject.Path.ExpectedDistance.Value <= Precision.DOUBLE_EPSILON) @@ -307,14 +309,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders } } - editorBeatmap.SelectedHitObjects.Clear(); - // The path will have a non-zero offset if the head is removed, but sliders don't support this behaviour since the head is positioned at the slider's position // So the slider needs to be offset by this amount instead, and all control points offset backwards such that the path is re-positioned at (0, 0) Vector2 first = controlPoints[0].Position; foreach (var c in controlPoints) c.Position -= first; HitObject.Position += first; + + editorBeatmap.SelectedHitObjects.Clear(); } private void convertToStream() From 41408a3106215074c6c2d71944b5efa7790ebaf1 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 19 Aug 2022 15:51:27 +0900 Subject: [PATCH 0568/2686] Add audio feedback for text selection --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 1650d2b274..2718465b9c 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -46,8 +46,16 @@ namespace osu.Game.Graphics.UserInterface private Sample? textCommittedSample; private Sample? caretMovedSample; + private Sample? selectCharSample; + private Sample? selectWordSample; + private Sample? selectAllSample; + private Sample? deselectSample; + private OsuCaret? caret; + private bool selectionStarted; + private double sampleLastPlaybackTime; + public OsuTextBox() { Height = 40; @@ -78,6 +86,11 @@ namespace osu.Game.Graphics.UserInterface textRemovedSample = audio.Samples.Get(@"Keyboard/key-delete"); textCommittedSample = audio.Samples.Get(@"Keyboard/key-confirm"); caretMovedSample = audio.Samples.Get(@"Keyboard/key-movement"); + + selectCharSample = audio.Samples.Get(@"Keyboard/select-char"); + selectWordSample = audio.Samples.Get(@"Keyboard/select-word"); + selectAllSample = audio.Samples.Get(@"Keyboard/select-all"); + deselectSample = audio.Samples.Get(@"Keyboard/deselect"); } private Color4 selectionColour; @@ -112,7 +125,72 @@ namespace osu.Game.Graphics.UserInterface { base.OnCaretMoved(selecting); - caretMovedSample?.Play(); + if (!selecting) + caretMovedSample?.Play(); + } + + protected override void OnTextSelectionChanged(TextSelectionType selectionType) + { + base.OnTextSelectionChanged(selectionType); + + if (selectionType == TextSelectionType.Word) + { + if (!selectionStarted) + playSelectSample(selectionType); + else + playSelectSample(); + } + else + { + playSelectSample(selectionType); + } + + selectionStarted = true; + } + + protected override void OnTextDeselected() + { + if (selectionStarted) + playSelectSample(TextSelectionType.Deselect); + + selectionStarted = false; + + base.OnTextDeselected(); + } + + private void playSelectSample(TextSelectionType selectionType = TextSelectionType.Character) + { + if (Time.Current < sampleLastPlaybackTime + 15) return; + + SampleChannel? channel; + double pitch = 0.98 + RNG.NextDouble(0.04); + + switch (selectionType) + { + case TextSelectionType.All: + channel = selectAllSample?.GetChannel(); + break; + + case TextSelectionType.Word: + channel = selectWordSample?.GetChannel(); + break; + + case TextSelectionType.Deselect: + channel = deselectSample?.GetChannel(); + break; + + default: + channel = selectCharSample?.GetChannel(); + pitch += (SelectedText.Length / (float)Text.Length) * 0.15f; + break; + } + + if (channel == null) return; + + channel.Frequency.Value = pitch; + channel.Play(); + + sampleLastPlaybackTime = Time.Current; } protected override void OnImeComposition(string newComposition, int removedTextLength, int addedTextLength, bool caretMoved) From 5dcd4ce7c52de316d3b2f8665ffccfc86c3b9ada Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 19 Aug 2022 15:31:03 +0800 Subject: [PATCH 0569/2686] Naming changes --- .../Difficulty/Evaluators/ColourEvaluator.cs | 12 ++--- ...rEncoding.cs => AlternatingMonoPattern.cs} | 22 ++++----- .../Data/{MonoEncoding.cs => MonoStreak.cs} | 10 ++-- ...lourEncoding.cs => RepeatingHitPattern.cs} | 28 +++++------ .../TaikoColourDifficultyPreprocessor.cs | 46 +++++++++---------- .../Colour/TaikoDifficultyHitObjectColour.cs | 6 +-- 6 files changed, 62 insertions(+), 62 deletions(-) rename osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/{ColourEncoding.cs => AlternatingMonoPattern.cs} (54%) rename osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/{MonoEncoding.cs => MonoStreak.cs} (81%) rename osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/{CoupledColourEncoding.cs => RepeatingHitPattern.cs} (59%) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 30094dc869..912a02f30e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -26,25 +26,25 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators } /// - /// Evaluate the difficulty of the first note of a . + /// Evaluate the difficulty of the first note of a . /// - public static double EvaluateDifficultyOf(MonoEncoding encoding) + public static double EvaluateDifficultyOf(MonoStreak encoding) { return sigmoid(encoding.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(encoding.Parent!) * 0.5; } /// - /// Evaluate the difficulty of the first note of a . + /// Evaluate the difficulty of the first note of a . /// - public static double EvaluateDifficultyOf(ColourEncoding encoding) + public static double EvaluateDifficultyOf(AlternatingMonoPattern encoding) { return sigmoid(encoding.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(encoding.Parent!); } /// - /// Evaluate the difficulty of the first note of a . + /// Evaluate the difficulty of the first note of a . /// - public static double EvaluateDifficultyOf(CoupledColourEncoding encoding) + public static double EvaluateDifficultyOf(RepeatingHitPatterns encoding) { return 2 * (1 - sigmoid(encoding.RepetitionInterval, 2, 2, 0.5, 1)); } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs similarity index 54% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs index cd39a3d232..bb4ddc73d0 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/ColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs @@ -7,20 +7,20 @@ using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { /// - /// Encodes a list of s. - /// s with the same are grouped together. + /// Encodes a list of s. + /// s with the same are grouped together. /// - public class ColourEncoding + public class AlternatingMonoPattern { /// - /// s that are grouped together within this . + /// s that are grouped together within this . /// - public readonly List Payload = new List(); + public readonly List Payload = new List(); /// - /// The parent that contains this + /// The parent that contains this /// - public CoupledColourEncoding? Parent; + public RepeatingHitPatterns? Parent; /// /// Index of this encoding within it's parent encoding @@ -28,10 +28,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data public int Index; /// - /// Determine if this is a repetition of another . This + /// Determine if this is a repetition of another . This /// is a strict comparison and is true if and only if the colour sequence is exactly the same. /// - public bool IsRepetitionOf(ColourEncoding other) + public bool IsRepetitionOf(AlternatingMonoPattern other) { return HasIdenticalMonoLength(other) && other.Payload.Count == Payload.Count && @@ -40,9 +40,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data } /// - /// Determine if this has the same mono length of another . + /// Determine if this has the same mono length of another . /// - public bool HasIdenticalMonoLength(ColourEncoding other) + public bool HasIdenticalMonoLength(AlternatingMonoPattern other) { return other.Payload[0].RunLength == Payload[0].RunLength; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs similarity index 81% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs index 0e998696f9..26175d9559 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs @@ -9,19 +9,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { /// /// Encode colour information for a sequence of s. Consecutive s - /// of the same are encoded within the same . + /// of the same are encoded within the same . /// - public class MonoEncoding + public class MonoStreak { /// - /// List of s that are encoded within this . + /// List of s that are encoded within this . /// public List EncodedData { get; private set; } = new List(); /// - /// The parent that contains this + /// The parent that contains this /// - public ColourEncoding? Parent; + public AlternatingMonoPattern? Parent; /// /// Index of this encoding within it's parent encoding diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPattern.cs similarity index 59% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPattern.cs index 3f692e9d3d..91b41b80e7 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/CoupledColourEncoding.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPattern.cs @@ -7,33 +7,33 @@ using System.Collections.Generic; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { /// - /// Encodes a list of s, grouped together by back and forth repetition of the same - /// . Also stores the repetition interval between this and the previous . + /// Encodes a list of s, grouped together by back and forth repetition of the same + /// . Also stores the repetition interval between this and the previous . /// - public class CoupledColourEncoding + public class RepeatingHitPatterns { /// - /// Maximum amount of s to look back to find a repetition. + /// Maximum amount of s to look back to find a repetition. /// private const int max_repetition_interval = 16; /// - /// The s that are grouped together within this . + /// The s that are grouped together within this . /// - public readonly List Payload = new List(); + public readonly List Payload = new List(); /// - /// The previous . This is used to determine the repetition interval. + /// The previous . This is used to determine the repetition interval. /// - public readonly CoupledColourEncoding? Previous; + public readonly RepeatingHitPatterns? Previous; /// - /// How many between the current and previous identical . + /// How many between the current and previous identical . /// If no repetition is found this will have a value of + 1. /// public int RepetitionInterval { get; private set; } = max_repetition_interval + 1; - public CoupledColourEncoding(CoupledColourEncoding? previous) + public RepeatingHitPatterns(RepeatingHitPatterns? previous) { Previous = previous; } @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// Returns true if other is considered a repetition of this encoding. This is true if other's first two payloads /// have identical mono lengths. /// - private bool isRepetitionOf(CoupledColourEncoding other) + private bool isRepetitionOf(RepeatingHitPatterns other) { if (Payload.Count != other.Payload.Count) return false; @@ -55,8 +55,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data } /// - /// Finds the closest previous that has the identical . - /// Interval is defined as the amount of chunks between the current and repeated encoding. + /// Finds the closest previous that has the identical . + /// Interval is defined as the amount of chunks between the current and repeated encoding. /// public void FindRepetitionInterval() { @@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data return; } - CoupledColourEncoding? other = Previous; + RepeatingHitPatterns? other = Previous; int interval = 1; while (interval < max_repetition_interval) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 81ba219bc0..5ae659574d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// public static void ProcessAndAssign(List hitObjects) { - List encodings = encode(hitObjects); + List encodings = encode(hitObjects); // Assign indexing and encoding data to all relevant objects. Only the first note of each encoding type is // assigned with the relevant encodings. @@ -33,14 +33,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour // documentation. for (int i = 0; i < coupledEncoding.Payload.Count; ++i) { - ColourEncoding colourEncoding = coupledEncoding.Payload[i]; + AlternatingMonoPattern colourEncoding = coupledEncoding.Payload[i]; colourEncoding.Parent = coupledEncoding; colourEncoding.Index = i; colourEncoding.Payload[0].EncodedData[0].Colour.ColourEncoding = colourEncoding; for (int j = 0; j < colourEncoding.Payload.Count; ++j) { - MonoEncoding monoEncoding = colourEncoding.Payload[j]; + MonoStreak monoEncoding = colourEncoding.Payload[j]; monoEncoding.Parent = colourEncoding; monoEncoding.Index = j; monoEncoding.EncodedData[0].Colour.MonoEncoding = monoEncoding; @@ -50,24 +50,24 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour } /// - /// Encodes a list of s into a list of s. + /// Encodes a list of s into a list of s. /// - private static List encode(List data) + private static List encode(List data) { - List firstPass = encodeMono(data); - List secondPass = encodeColour(firstPass); - List thirdPass = encodeCoupledColour(secondPass); + List firstPass = encodeMono(data); + List secondPass = encodeColour(firstPass); + List thirdPass = encodeCoupledColour(secondPass); return thirdPass; } /// - /// Encodes a list of s into a list of s. + /// Encodes a list of s into a list of s. /// - private static List encodeMono(List data) + private static List encodeMono(List data) { - List encodings = new List(); - MonoEncoding? currentEncoding = null; + List encodings = new List(); + MonoStreak? currentEncoding = null; for (int i = 0; i < data.Count; i++) { @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour // If this is the first object in the list or the colour changed, create a new mono encoding if (currentEncoding == null || previousObject == null || (taikoObject.BaseObject as Hit)?.Type != (previousObject.BaseObject as Hit)?.Type) { - currentEncoding = new MonoEncoding(); + currentEncoding = new MonoStreak(); encodings.Add(currentEncoding); } @@ -91,19 +91,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour } /// - /// Encodes a list of s into a list of s. + /// Encodes a list of s into a list of s. /// - private static List encodeColour(List data) + private static List encodeColour(List data) { - List encodings = new List(); - ColourEncoding? currentEncoding = null; + List encodings = new List(); + AlternatingMonoPattern? currentEncoding = null; for (int i = 0; i < data.Count; i++) { // Start a new ColourEncoding if the previous MonoEncoding has a different mono length, or if this is the first MonoEncoding in the list. if (currentEncoding == null || data[i].RunLength != data[i - 1].RunLength) { - currentEncoding = new ColourEncoding(); + currentEncoding = new AlternatingMonoPattern(); encodings.Add(currentEncoding); } @@ -115,17 +115,17 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour } /// - /// Encodes a list of s into a list of s. + /// Encodes a list of s into a list of s. /// - private static List encodeCoupledColour(List data) + private static List encodeCoupledColour(List data) { - List encodings = new List(); - CoupledColourEncoding? currentEncoding = null; + List encodings = new List(); + RepeatingHitPatterns? currentEncoding = null; for (int i = 0; i < data.Count; i++) { // Start a new CoupledColourEncoding. ColourEncodings that should be grouped together will be handled later within this loop. - currentEncoding = new CoupledColourEncoding(currentEncoding); + currentEncoding = new RepeatingHitPatterns(currentEncoding); // Determine if future ColourEncodings should be grouped. bool isCoupled = i < data.Count - 2 && data[i].IsRepetitionOf(data[i + 2]); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs index 41080eeb33..708ce8ecd0 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs @@ -13,16 +13,16 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// /// The that encodes this note, only present if this is the first note within a /// - public MonoEncoding? MonoEncoding; + public MonoStreak? MonoEncoding; /// /// The that encodes this note, only present if this is the first note within a /// - public ColourEncoding? ColourEncoding; + public AlternatingMonoPattern? ColourEncoding; /// /// The that encodes this note, only present if this is the first note within a /// - public CoupledColourEncoding? CoupledColourEncoding; + public RepeatingHitPatterns? CoupledColourEncoding; } } From 51176e95772736807b05d0158f8a79d14018dada Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 19 Aug 2022 15:45:43 +0800 Subject: [PATCH 0570/2686] Naming changes --- .../Difficulty/Evaluators/ColourEvaluator.cs | 24 ++-- .../Colour/Data/AlternatingMonoPattern.cs | 12 +- .../Preprocessing/Colour/Data/MonoStreak.cs | 6 +- .../Colour/Data/RepeatingHitPattern.cs | 14 +-- .../TaikoColourDifficultyPreprocessor.cs | 108 +++++++++--------- .../Colour/TaikoDifficultyHitObjectColour.cs | 12 +- .../Difficulty/Skills/Colour.cs | 4 +- 7 files changed, 90 insertions(+), 90 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 912a02f30e..afddedf962 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -28,25 +28,25 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// /// Evaluate the difficulty of the first note of a . /// - public static double EvaluateDifficultyOf(MonoStreak encoding) + public static double EvaluateDifficultyOf(MonoStreak monoStreak) { - return sigmoid(encoding.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(encoding.Parent!) * 0.5; + return sigmoid(monoStreak.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(monoStreak.Parent!) * 0.5; } /// /// Evaluate the difficulty of the first note of a . /// - public static double EvaluateDifficultyOf(AlternatingMonoPattern encoding) + public static double EvaluateDifficultyOf(AlternatingMonoPattern alternatingMonoPattern) { - return sigmoid(encoding.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(encoding.Parent!); + return sigmoid(alternatingMonoPattern.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(alternatingMonoPattern.Parent!); } /// /// Evaluate the difficulty of the first note of a . /// - public static double EvaluateDifficultyOf(RepeatingHitPatterns encoding) + public static double EvaluateDifficultyOf(RepeatingHitPatterns repeatingHitPattern) { - return 2 * (1 - sigmoid(encoding.RepetitionInterval, 2, 2, 0.5, 1)); + return 2 * (1 - sigmoid(repeatingHitPattern.RepetitionInterval, 2, 2, 0.5, 1)); } public static double EvaluateDifficultyOf(DifficultyHitObject hitObject) @@ -54,12 +54,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)hitObject).Colour; double difficulty = 0.0d; - if (colour.MonoEncoding != null) // Difficulty for MonoEncoding - difficulty += EvaluateDifficultyOf(colour.MonoEncoding); - if (colour.ColourEncoding != null) // Difficulty for ColourEncoding - difficulty += EvaluateDifficultyOf(colour.ColourEncoding); - if (colour.CoupledColourEncoding != null) // Difficulty for CoupledColourEncoding - difficulty += EvaluateDifficultyOf(colour.CoupledColourEncoding); + if (colour.MonoStreak != null) // Difficulty for MonoStreak + difficulty += EvaluateDifficultyOf(colour.MonoStreak); + if (colour.AlternatingMonoPattern != null) // Difficulty for AlternatingMonoPattern + difficulty += EvaluateDifficultyOf(colour.AlternatingMonoPattern); + if (colour.RepeatingHitPatterns != null) // Difficulty for RepeatingHitPattern + difficulty += EvaluateDifficultyOf(colour.RepeatingHitPatterns); return difficulty; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs index bb4ddc73d0..9d2df877d3 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// /// s that are grouped together within this . /// - public readonly List Payload = new List(); + public readonly List MonoStreaks = new List(); /// /// The parent that contains this @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data public RepeatingHitPatterns? Parent; /// - /// Index of this encoding within it's parent encoding + /// Index of this within it's parent /// public int Index; @@ -34,9 +34,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data public bool IsRepetitionOf(AlternatingMonoPattern other) { return HasIdenticalMonoLength(other) && - other.Payload.Count == Payload.Count && - (other.Payload[0].EncodedData[0].BaseObject as Hit)?.Type == - (Payload[0].EncodedData[0].BaseObject as Hit)?.Type; + other.MonoStreaks.Count == MonoStreaks.Count && + (other.MonoStreaks[0].HitObjects[0].BaseObject as Hit)?.Type == + (MonoStreaks[0].HitObjects[0].BaseObject as Hit)?.Type; } /// @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public bool HasIdenticalMonoLength(AlternatingMonoPattern other) { - return other.Payload[0].RunLength == Payload[0].RunLength; + return other.MonoStreaks[0].RunLength == MonoStreaks[0].RunLength; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs index 26175d9559..82a09d61fe 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// /// List of s that are encoded within this . /// - public List EncodedData { get; private set; } = new List(); + public List HitObjects { get; private set; } = new List(); /// /// The parent that contains this @@ -24,13 +24,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data public AlternatingMonoPattern? Parent; /// - /// Index of this encoding within it's parent encoding + /// Index of this within it's parent /// public int Index; /// /// How long the mono pattern encoded within is /// - public int RunLength => EncodedData.Count; + public int RunLength => HitObjects.Count; } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPattern.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPattern.cs index 91b41b80e7..d5ce2d0a55 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPattern.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPattern.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// /// The s that are grouped together within this . /// - public readonly List Payload = new List(); + public readonly List AlternatingMonoPatterns = new List(); /// /// The previous . This is used to determine the repetition interval. @@ -39,24 +39,24 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data } /// - /// Returns true if other is considered a repetition of this encoding. This is true if other's first two payloads + /// Returns true if other is considered a repetition of this pattern. This is true if other's first two payloads /// have identical mono lengths. /// private bool isRepetitionOf(RepeatingHitPatterns other) { - if (Payload.Count != other.Payload.Count) return false; + if (AlternatingMonoPatterns.Count != other.AlternatingMonoPatterns.Count) return false; - for (int i = 0; i < Math.Min(Payload.Count, 2); i++) + for (int i = 0; i < Math.Min(AlternatingMonoPatterns.Count, 2); i++) { - if (!Payload[i].HasIdenticalMonoLength(other.Payload[i])) return false; + if (!AlternatingMonoPatterns[i].HasIdenticalMonoLength(other.AlternatingMonoPatterns[i])) return false; } return true; } /// - /// Finds the closest previous that has the identical . - /// Interval is defined as the amount of chunks between the current and repeated encoding. + /// Finds the closest previous that has the identical . + /// Interval is defined as the amount of chunks between the current and repeated patterns. /// public void FindRepetitionInterval() { diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 5ae659574d..bd46957fc0 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -20,30 +20,30 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// public static void ProcessAndAssign(List hitObjects) { - List encodings = encode(hitObjects); + List hitPatterns = encode(hitObjects); // Assign indexing and encoding data to all relevant objects. Only the first note of each encoding type is // assigned with the relevant encodings. - foreach (var coupledEncoding in encodings) + foreach (var repeatingHitPattern in hitPatterns) { - coupledEncoding.Payload[0].Payload[0].EncodedData[0].Colour.CoupledColourEncoding = coupledEncoding; + repeatingHitPattern.AlternatingMonoPatterns[0].MonoStreaks[0].HitObjects[0].Colour.RepeatingHitPatterns = repeatingHitPattern; // The outermost loop is kept a ForEach loop since it doesn't need index information, and we want to - // keep i and j for ColourEncoding's and MonoEncoding's index respectively, to keep it in line with + // keep i and j for AlternatingMonoPattern's and MonoStreak's index respectively, to keep it in line with // documentation. - for (int i = 0; i < coupledEncoding.Payload.Count; ++i) + for (int i = 0; i < repeatingHitPattern.AlternatingMonoPatterns.Count; ++i) { - AlternatingMonoPattern colourEncoding = coupledEncoding.Payload[i]; - colourEncoding.Parent = coupledEncoding; - colourEncoding.Index = i; - colourEncoding.Payload[0].EncodedData[0].Colour.ColourEncoding = colourEncoding; + AlternatingMonoPattern monoPattern = repeatingHitPattern.AlternatingMonoPatterns[i]; + monoPattern.Parent = repeatingHitPattern; + monoPattern.Index = i; + monoPattern.MonoStreaks[0].HitObjects[0].Colour.AlternatingMonoPattern = monoPattern; - for (int j = 0; j < colourEncoding.Payload.Count; ++j) + for (int j = 0; j < monoPattern.MonoStreaks.Count; ++j) { - MonoStreak monoEncoding = colourEncoding.Payload[j]; - monoEncoding.Parent = colourEncoding; - monoEncoding.Index = j; - monoEncoding.EncodedData[0].Colour.MonoEncoding = monoEncoding; + MonoStreak monoStreak = monoPattern.MonoStreaks[j]; + monoStreak.Parent = monoPattern; + monoStreak.Index = j; + monoStreak.HitObjects[0].Colour.MonoStreak = monoStreak; } } } @@ -54,20 +54,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// private static List encode(List data) { - List firstPass = encodeMono(data); - List secondPass = encodeColour(firstPass); - List thirdPass = encodeCoupledColour(secondPass); + List monoStreaks = encodeMonoStreak(data); + List alternatingMonoPatterns = encodeAlternatingMonoPattern(monoStreaks); + List repeatingHitPatterns = encodeRepeatingHitPattern(alternatingMonoPatterns); - return thirdPass; + return repeatingHitPatterns; } /// /// Encodes a list of s into a list of s. /// - private static List encodeMono(List data) + private static List encodeMonoStreak(List data) { - List encodings = new List(); - MonoStreak? currentEncoding = null; + List monoStreaks = new List(); + MonoStreak? currentMonoStreak = null; for (int i = 0; i < data.Count; i++) { @@ -76,92 +76,92 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour // This ignores all non-note objects, which may or may not be the desired behaviour TaikoDifficultyHitObject? previousObject = taikoObject.PreviousNote(0); - // If this is the first object in the list or the colour changed, create a new mono encoding - if (currentEncoding == null || previousObject == null || (taikoObject.BaseObject as Hit)?.Type != (previousObject.BaseObject as Hit)?.Type) + // If this is the first object in the list or the colour changed, create a new mono streak + if (currentMonoStreak == null || previousObject == null || (taikoObject.BaseObject as Hit)?.Type != (previousObject.BaseObject as Hit)?.Type) { - currentEncoding = new MonoStreak(); - encodings.Add(currentEncoding); + currentMonoStreak = new MonoStreak(); + monoStreaks.Add(currentMonoStreak); } // Add the current object to the encoded payload. - currentEncoding.EncodedData.Add(taikoObject); + currentMonoStreak.HitObjects.Add(taikoObject); } - return encodings; + return monoStreaks; } /// /// Encodes a list of s into a list of s. /// - private static List encodeColour(List data) + private static List encodeAlternatingMonoPattern(List data) { - List encodings = new List(); - AlternatingMonoPattern? currentEncoding = null; + List monoPatterns = new List(); + AlternatingMonoPattern? currentMonoPattern = null; for (int i = 0; i < data.Count; i++) { - // Start a new ColourEncoding if the previous MonoEncoding has a different mono length, or if this is the first MonoEncoding in the list. - if (currentEncoding == null || data[i].RunLength != data[i - 1].RunLength) + // Start a new AlternatingMonoPattern if the previous MonoStreak has a different mono length, or if this is the first MonoStreak in the list. + if (currentMonoPattern == null || data[i].RunLength != data[i - 1].RunLength) { - currentEncoding = new AlternatingMonoPattern(); - encodings.Add(currentEncoding); + currentMonoPattern = new AlternatingMonoPattern(); + monoPatterns.Add(currentMonoPattern); } - // Add the current MonoEncoding to the encoded payload. - currentEncoding.Payload.Add(data[i]); + // Add the current MonoStreak to the encoded payload. + currentMonoPattern.MonoStreaks.Add(data[i]); } - return encodings; + return monoPatterns; } /// /// Encodes a list of s into a list of s. /// - private static List encodeCoupledColour(List data) + private static List encodeRepeatingHitPattern(List data) { - List encodings = new List(); - RepeatingHitPatterns? currentEncoding = null; + List hitPatterns = new List(); + RepeatingHitPatterns? currentHitPattern = null; for (int i = 0; i < data.Count; i++) { - // Start a new CoupledColourEncoding. ColourEncodings that should be grouped together will be handled later within this loop. - currentEncoding = new RepeatingHitPatterns(currentEncoding); + // Start a new RepeatingHitPattern. AlternatingMonoPatterns that should be grouped together will be handled later within this loop. + currentHitPattern = new RepeatingHitPatterns(currentHitPattern); - // Determine if future ColourEncodings should be grouped. + // Determine if future AlternatingMonoPatterns should be grouped. bool isCoupled = i < data.Count - 2 && data[i].IsRepetitionOf(data[i + 2]); if (!isCoupled) { - // If not, add the current ColourEncoding to the encoded payload and continue. - currentEncoding.Payload.Add(data[i]); + // If not, add the current AlternatingMonoPattern to the encoded payload and continue. + currentHitPattern.AlternatingMonoPatterns.Add(data[i]); } else { - // If so, add the current ColourEncoding to the encoded payload and start repeatedly checking if the - // subsequent ColourEncodings should be grouped by increasing i and doing the appropriate isCoupled check. + // If so, add the current AlternatingMonoPattern to the encoded payload and start repeatedly checking if the + // subsequent AlternatingMonoPatterns should be grouped by increasing i and doing the appropriate isCoupled check. while (isCoupled) { - currentEncoding.Payload.Add(data[i]); + currentHitPattern.AlternatingMonoPatterns.Add(data[i]); i++; isCoupled = i < data.Count - 2 && data[i].IsRepetitionOf(data[i + 2]); } // Skip over viewed data and add the rest to the payload - currentEncoding.Payload.Add(data[i]); - currentEncoding.Payload.Add(data[i + 1]); + currentHitPattern.AlternatingMonoPatterns.Add(data[i]); + currentHitPattern.AlternatingMonoPatterns.Add(data[i + 1]); i++; } - encodings.Add(currentEncoding); + hitPatterns.Add(currentHitPattern); } // Final pass to find repetition intervals - for (int i = 0; i < encodings.Count; i++) + for (int i = 0; i < hitPatterns.Count; i++) { - encodings[i].FindRepetitionInterval(); + hitPatterns[i].FindRepetitionInterval(); } - return encodings; + return hitPatterns; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs index 708ce8ecd0..c631b8d4a8 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs @@ -11,18 +11,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour public class TaikoDifficultyHitObjectColour { /// - /// The that encodes this note, only present if this is the first note within a + /// The that encodes this note, only present if this is the first note within a /// - public MonoStreak? MonoEncoding; + public MonoStreak? MonoStreak; /// - /// The that encodes this note, only present if this is the first note within a + /// The that encodes this note, only present if this is the first note within a /// - public AlternatingMonoPattern? ColourEncoding; + public AlternatingMonoPattern? AlternatingMonoPattern; /// - /// The that encodes this note, only present if this is the first note within a + /// The that encodes this note, only present if this is the first note within a /// - public RepeatingHitPatterns? CoupledColourEncoding; + public RepeatingHitPatterns? RepeatingHitPatterns; } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index dac0beadda..2d45b5eed0 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { protected override double SkillMultiplier => 0.12; - // This is set to decay slower than other skills, due to the fact that only the first note of each Mono/Colour/Coupled - // encoding having any difficulty values, and we want to allow colour difficulty to be able to build up even on + // This is set to decay slower than other skills, due to the fact that only the first note of each encoding class + // having any difficulty values, and we want to allow colour difficulty to be able to build up even on // slower maps. protected override double StrainDecayBase => 0.8; From a26de0a10f4f32131b658df3ffdb2c47026f027d Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 19 Aug 2022 16:05:34 +0800 Subject: [PATCH 0571/2686] Add HitType property to MonoStreak --- .../Preprocessing/Colour/Data/AlternatingMonoPattern.cs | 3 +-- .../Difficulty/Preprocessing/Colour/Data/MonoStreak.cs | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs index 9d2df877d3..5e6f32cce2 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs @@ -35,8 +35,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { return HasIdenticalMonoLength(other) && other.MonoStreaks.Count == MonoStreaks.Count && - (other.MonoStreaks[0].HitObjects[0].BaseObject as Hit)?.Type == - (MonoStreaks[0].HitObjects[0].BaseObject as Hit)?.Type; + other.MonoStreaks[0].HitType == MonoStreaks[0].HitType; } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs index 82a09d61fe..9ebea156a5 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { /// /// Encode colour information for a sequence of s. Consecutive s - /// of the same are encoded within the same . + /// of the same are encoded within the same . /// public class MonoStreak { @@ -28,6 +28,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public int Index; + public HitType? HitType => (HitObjects[0].BaseObject as Hit)?.Type; + /// /// How long the mono pattern encoded within is /// From 684efefb50c16657af99b8da4e0298155b0fd314 Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 19 Aug 2022 16:13:36 +0800 Subject: [PATCH 0572/2686] Add FirstHitObject as a property of encoding classes --- .../Difficulty/Evaluators/ColourEvaluator.cs | 4 ++-- .../Preprocessing/Colour/Data/AlternatingMonoPattern.cs | 5 +++++ .../Difficulty/Preprocessing/Colour/Data/MonoStreak.cs | 8 ++++++++ .../{RepeatingHitPattern.cs => RepeatingHitPatterns.cs} | 5 +++++ .../Colour/TaikoColourDifficultyPreprocessor.cs | 6 +++--- .../Colour/TaikoDifficultyHitObjectColour.cs | 4 ++-- 6 files changed, 25 insertions(+), 7 deletions(-) rename osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/{RepeatingHitPattern.cs => RepeatingHitPatterns.cs} (93%) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index afddedf962..6c685e854e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -58,8 +58,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators difficulty += EvaluateDifficultyOf(colour.MonoStreak); if (colour.AlternatingMonoPattern != null) // Difficulty for AlternatingMonoPattern difficulty += EvaluateDifficultyOf(colour.AlternatingMonoPattern); - if (colour.RepeatingHitPatterns != null) // Difficulty for RepeatingHitPattern - difficulty += EvaluateDifficultyOf(colour.RepeatingHitPatterns); + if (colour.RepeatingHitPattern != null) // Difficulty for RepeatingHitPattern + difficulty += EvaluateDifficultyOf(colour.RepeatingHitPattern); return difficulty; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs index 5e6f32cce2..450eefe75c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs @@ -27,6 +27,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public int Index; + /// + /// The first in this . + /// + public TaikoDifficultyHitObject FirstHitObject => MonoStreaks[0].FirstHitObject; + /// /// Determine if this is a repetition of another . This /// is a strict comparison and is true if and only if the colour sequence is exactly the same. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs index 9ebea156a5..4e15043acf 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs @@ -28,6 +28,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public int Index; + /// + /// The first in this . + /// + public TaikoDifficultyHitObject FirstHitObject => HitObjects[0]; + + /// + /// The hit type of all objects encoded within this + /// public HitType? HitType => (HitObjects[0].BaseObject as Hit)?.Type; /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPattern.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs similarity index 93% rename from osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPattern.cs rename to osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs index d5ce2d0a55..fe0dc6dd9a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPattern.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs @@ -22,6 +22,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public readonly List AlternatingMonoPatterns = new List(); + /// + /// The parent in this + /// + public TaikoDifficultyHitObject FirstHitObject => AlternatingMonoPatterns[0].FirstHitObject; + /// /// The previous . This is used to determine the repetition interval. /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index bd46957fc0..d19e05f4e0 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour // assigned with the relevant encodings. foreach (var repeatingHitPattern in hitPatterns) { - repeatingHitPattern.AlternatingMonoPatterns[0].MonoStreaks[0].HitObjects[0].Colour.RepeatingHitPatterns = repeatingHitPattern; + repeatingHitPattern.FirstHitObject.Colour.RepeatingHitPattern = repeatingHitPattern; // The outermost loop is kept a ForEach loop since it doesn't need index information, and we want to // keep i and j for AlternatingMonoPattern's and MonoStreak's index respectively, to keep it in line with @@ -36,14 +36,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour AlternatingMonoPattern monoPattern = repeatingHitPattern.AlternatingMonoPatterns[i]; monoPattern.Parent = repeatingHitPattern; monoPattern.Index = i; - monoPattern.MonoStreaks[0].HitObjects[0].Colour.AlternatingMonoPattern = monoPattern; + monoPattern.FirstHitObject.Colour.AlternatingMonoPattern = monoPattern; for (int j = 0; j < monoPattern.MonoStreaks.Count; ++j) { MonoStreak monoStreak = monoPattern.MonoStreaks[j]; monoStreak.Parent = monoPattern; monoStreak.Index = j; - monoStreak.HitObjects[0].Colour.MonoStreak = monoStreak; + monoStreak.FirstHitObject.Colour.MonoStreak = monoStreak; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs index c631b8d4a8..9c147eee9c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs @@ -21,8 +21,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour public AlternatingMonoPattern? AlternatingMonoPattern; /// - /// The that encodes this note, only present if this is the first note within a + /// The that encodes this note, only present if this is the first note within a /// - public RepeatingHitPatterns? RepeatingHitPatterns; + public RepeatingHitPatterns? RepeatingHitPattern; } } From f3e1287f04addc40f7e7ef98fe6a89d5681e5df3 Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 19 Aug 2022 16:19:45 +0800 Subject: [PATCH 0573/2686] Remove redundant using statement --- .../Preprocessing/Colour/Data/AlternatingMonoPattern.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs index 450eefe75c..60d4e55a64 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { From 3f0da1406562de9e432b0caee474e0685640a417 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 19 Aug 2022 17:39:51 +0900 Subject: [PATCH 0574/2686] Delay start operation by one frame to allow children to see initial start time --- osu.Game/Screens/Play/GameplayClockContainer.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 9f13d15890..acbbeb1e1b 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -103,7 +103,11 @@ namespace osu.Game.Screens.Play // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time // This accounts for the clock source potentially taking time to enter a completely stopped state Seek(GameplayClock.CurrentTime); - GameplayClock.Start(); + + // Delay the start operation to ensure all children components get the initial seek time. + // Without this, children may get a start time beyond StartTime without seeing the time has elapsed. + // This can manifest as events which should be fired at the precise StartTime not firing. + SchedulerAfterChildren.Add(GameplayClock.Start); } } From 426c4c9bf74412bedfc09dd9b28e43b3e0ace905 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 19 Aug 2022 20:39:53 +0900 Subject: [PATCH 0575/2686] 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 6dbc6cc377..5fdf715e3a 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 28452c0a74..aca0ccaf5b 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 463af1143f..fa1bbd587a 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 41321521e57c8c996f64c14a93c178425f801f41 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 19 Aug 2022 20:40:05 +0900 Subject: [PATCH 0576/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 5fdf715e3a..17a6178641 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index aca0ccaf5b..0613db891b 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index fa1bbd587a..bf1e4e350c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + From c3c44c19cdbe96ed5305286e79ec64f0ebea9d4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 19 Aug 2022 20:43:15 +0900 Subject: [PATCH 0577/2686] Use `CompositeComponent` in various locations --- osu.Game/Online/PollingComponent.cs | 2 +- .../Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/PollingComponent.cs b/osu.Game/Online/PollingComponent.cs index d54b8ca75d..fcea650e2d 100644 --- a/osu.Game/Online/PollingComponent.cs +++ b/osu.Game/Online/PollingComponent.cs @@ -16,7 +16,7 @@ namespace osu.Game.Online /// /// A component which requires a constant polling process. /// - public abstract class PollingComponent : CompositeDrawable // switch away from Component because InternalChildren are used in usages. + public abstract class PollingComponent : CompositeComponent { private double? lastTimePolled; diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs index 2fd8445980..bb8ec4f6ff 100644 --- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs @@ -27,13 +27,10 @@ namespace osu.Game.Online.Rooms /// This differs from a regular download tracking composite as this accounts for the /// databased beatmap set's checksum, to disallow from playing with an altered version of the beatmap. /// - public class OnlinePlayBeatmapAvailabilityTracker : CompositeDrawable + public class OnlinePlayBeatmapAvailabilityTracker : CompositeComponent { public readonly IBindable SelectedItem = new Bindable(); - // Required to allow child components to update. Can potentially be replaced with a `CompositeComponent` class if or when we make one. - protected override bool RequiresChildrenUpdate => true; - [Resolved] private RealmAccess realm { get; set; } = null!; From 7bf318541c90d2ea8778157167029fc60fbff233 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 19 Aug 2022 20:57:55 +0900 Subject: [PATCH 0578/2686] Reword comment to hopefully read better --- osu.Game/Screens/Play/GameplayClockContainer.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index acbbeb1e1b..6dab13c950 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -104,9 +104,16 @@ namespace osu.Game.Screens.Play // This accounts for the clock source potentially taking time to enter a completely stopped state Seek(GameplayClock.CurrentTime); - // Delay the start operation to ensure all children components get the initial seek time. - // Without this, children may get a start time beyond StartTime without seeing the time has elapsed. - // This can manifest as events which should be fired at the precise StartTime not firing. + // The case which cause this to be added is FrameStabilityContainer, which manages its own current and elapsed time. + // Because we generally update our own current time quicker than children can query it (via Start/Seek/Update), + // this means that the first frame ever exposed to children may have a non-zero current time. + // + // If the child component is not aware of the parent ElapsedFrameTime (which is the case for FrameStabilityContainer) + // they will take on the new CurrentTime with a zero elapsed time. This can in turn cause components to behave incorrectly + // if they are intending to trigger events at the precise StartTime (ie. DrawableStoryboardSample). + // + // By scheduling the start call, children are guaranteed to receive one frame at the original start time, allowing + // then to progress with a correct locally calculated elapsed time. SchedulerAfterChildren.Add(GameplayClock.Start); } } From fea31cc895b12c91252e611157093f94ad36a7a3 Mon Sep 17 00:00:00 2001 From: Jay L Date: Fri, 19 Aug 2022 22:57:28 +1000 Subject: [PATCH 0579/2686] introduce effective misscount, accuracy rescale --- .../Difficulty/TaikoPerformanceCalculator.cs | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 2c2dbddf13..9567277a61 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -21,6 +21,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private int countMeh; private int countMiss; + private double effectiveMissCount; + public TaikoPerformanceCalculator() : base(new TaikoRuleset()) { @@ -35,7 +37,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); - double multiplier = 1.12; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things + // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the misspenalty for shorter object counts lower than 1000, past 1000 is 1:1. + effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; + + double multiplier = 1.13; if (score.Mods.Any(m => m is ModHidden)) multiplier *= 1.075; @@ -55,6 +60,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { Difficulty = difficultyValue, Accuracy = accuracyValue, + EffectiveMissCount = effectiveMissCount, Total = totalValue }; } @@ -66,18 +72,21 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0); difficultyValue *= lengthBonus; - difficultyValue *= Math.Pow(0.986, countMiss); + difficultyValue *= Math.Pow(0.986, effectiveMissCount); if (score.Mods.Any(m => m is ModEasy)) - difficultyValue *= 0.980; + difficultyValue *= 0.985; if (score.Mods.Any(m => m is ModHidden)) difficultyValue *= 1.025; + if (score.Mods.Any(m => m is ModHardRock)) + difficultyValue *= 1.050; + if (score.Mods.Any(m => m is ModFlashlight)) difficultyValue *= 1.05 * lengthBonus; - return difficultyValue * Math.Pow(score.Accuracy, 1.5); + return difficultyValue * Math.Pow(score.Accuracy, 2.0); } private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes) @@ -85,18 +94,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (attributes.GreatHitWindow <= 0) return 0; - double accuracyValue = Math.Pow(140.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 12.0) * 27; + double accuracyValue = Math.Pow(60.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 8.0) * Math.Pow(attributes.StarRating, 0.4) * 27.0; double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); accuracyValue *= lengthBonus; - // Slight HDFL Bonus for accuracy. + // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden)) - accuracyValue *= 1.10 * lengthBonus; + accuracyValue *= Math.Max(1.050, 1.075 * lengthBonus); return accuracyValue; } private int totalHits => countGreat + countOk + countMeh + countMiss; + + private int totalSuccessfulHits => countGreat + countOk + countMeh; } } From b30fba143065e6eeefe5a6604df9525e1a4c66b7 Mon Sep 17 00:00:00 2001 From: Jay L Date: Fri, 19 Aug 2022 22:57:40 +1000 Subject: [PATCH 0580/2686] emc attribute --- .../Difficulty/TaikoPerformanceAttributes.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs index 68d0038b24..b61c13a2df 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs @@ -17,6 +17,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty [JsonProperty("accuracy")] public double Accuracy { get; set; } + [JsonProperty("effective_miss_count")] + public double EffectiveMissCount { get; set; } + public override IEnumerable GetAttributesForDisplay() { foreach (var attribute in base.GetAttributesForDisplay()) From faf143b11aab5c7a1783fe624b84fecd2f0cf30e Mon Sep 17 00:00:00 2001 From: Jay L Date: Fri, 19 Aug 2022 23:15:38 +1000 Subject: [PATCH 0581/2686] fix comment --- .../Difficulty/TaikoPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 9567277a61..bc745da0fe 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); - // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the misspenalty for shorter object counts lower than 1000, past 1000 is 1:1. + // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000. effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; double multiplier = 1.13; From c1da5091191bfac75eb2b5b3294f58addd1b64a5 Mon Sep 17 00:00:00 2001 From: Jay L Date: Fri, 19 Aug 2022 23:23:40 +1000 Subject: [PATCH 0582/2686] round numerical value this is painfully annoying me --- .../Difficulty/TaikoPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index bc745da0fe..7b0aa47ba5 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty difficultyValue *= 1.050; if (score.Mods.Any(m => m is ModFlashlight)) - difficultyValue *= 1.05 * lengthBonus; + difficultyValue *= 1.050 * lengthBonus; return difficultyValue * Math.Pow(score.Accuracy, 2.0); } From d1519343f6040c2f0752956ad406f3c42152f731 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Fri, 19 Aug 2022 18:29:01 +0200 Subject: [PATCH 0583/2686] Improved visual tests for slider splitting --- .../Editor/TestSceneSliderSplitting.cs | 108 ++++++++++++++---- .../Sliders/SliderSelectionBlueprint.cs | 1 + 2 files changed, 88 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs index 4693d56789..198d521a85 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs @@ -3,9 +3,9 @@ using System.Linq; using NUnit.Framework; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -27,15 +27,14 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor private ComposeBlueprintContainer blueprintContainer => Editor.ChildrenOfType().First(); - private ContextMenuContainer contextMenuContainer - => Editor.ChildrenOfType().First(); - private Slider? slider; private PathControlPointVisualiser? visualiser; [Test] public void TestBasicSplit() { + double endTime = 0; + AddStep("add slider", () => { slider = new Slider @@ -52,6 +51,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor }; EditorBeatmap.Add(slider); + + endTime = slider.EndTime; }); AddStep("select added slider", () => @@ -66,39 +67,104 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor if (visualiser is not null) visualiser.Pieces[2].IsSelected.Value = true; }); addContextMenuItemStep("Split control point"); + + AddAssert("slider split", () => slider is not null && EditorBeatmap.HitObjects.Count == 2 && + sliderCreatedFor((Slider)EditorBeatmap.HitObjects[0], 0, slider.StartTime, + (new Vector2(0, 50), PathType.PerfectCurve), + (new Vector2(150, 200), null), + (new Vector2(300, 50), null) + ) && sliderCreatedFor((Slider)EditorBeatmap.HitObjects[1], slider.StartTime, endTime, + (new Vector2(300, 50), PathType.PerfectCurve), + (new Vector2(400, 50), null), + (new Vector2(400, 200), null) + )); + + AddStep("undo", () => Editor.Undo()); + AddAssert("original slider restored", () => EditorBeatmap.HitObjects.Count == 1 && sliderCreatedFor((Slider)EditorBeatmap.HitObjects[0], 0, endTime, + (new Vector2(0, 50), PathType.PerfectCurve), + (new Vector2(150, 200), null), + (new Vector2(300, 50), PathType.PerfectCurve), + (new Vector2(400, 50), null), + (new Vector2(400, 200), null) + )); } [Test] - public void TestStartTimeOffsetPlusDeselect() + public void TestDoubleSplit() { - HitCircle? circle = null; + double endTime = 0; - AddStep("add circle", () => + AddStep("add slider", () => { - circle = new HitCircle(); + slider = new Slider + { + Position = new Vector2(0, 50), + Path = new SliderPath(new[] + { + new PathControlPoint(Vector2.Zero, PathType.PerfectCurve), + new PathControlPoint(new Vector2(150, 150)), + new PathControlPoint(new Vector2(300, 0), PathType.Bezier), + new PathControlPoint(new Vector2(400, 0)), + new PathControlPoint(new Vector2(400, 150), PathType.Catmull), + new PathControlPoint(new Vector2(300, 200)), + new PathControlPoint(new Vector2(400, 250)) + }) + }; - EditorBeatmap.Add(circle); + EditorBeatmap.Add(slider); + + endTime = slider.EndTime; }); - AddStep("select added circle", () => + AddStep("select added slider", () => { - EditorBeatmap.SelectedHitObjects.Add(circle); + EditorBeatmap.SelectedHitObjects.Add(slider); + visualiser = blueprintContainer.SelectionBlueprints.First(o => o.Item == slider).ChildrenOfType().First(); }); - AddStep("add another circle", () => + moveMouseToControlPoint(2); + AddStep("select first control point", () => { - var circle2 = new HitCircle(); - - EditorBeatmap.Add(circle2); + if (visualiser is not null) visualiser.Pieces[2].IsSelected.Value = true; }); - - AddStep("change time of selected circle and deselect", () => + moveMouseToControlPoint(4); + AddStep("select second control point", () => { - if (circle is null) return; - - circle.StartTime += 1; - EditorBeatmap.SelectedHitObjects.Clear(); + if (visualiser is not null) visualiser.Pieces[4].IsSelected.Value = true; }); + addContextMenuItemStep("Split 2 control points"); + + AddAssert("slider split", () => slider is not null && EditorBeatmap.HitObjects.Count == 3 && + sliderCreatedFor((Slider)EditorBeatmap.HitObjects[0], 0, EditorBeatmap.HitObjects[1].StartTime, + (new Vector2(0, 50), PathType.PerfectCurve), + (new Vector2(150, 200), null), + (new Vector2(300, 50), null) + ) && sliderCreatedFor((Slider)EditorBeatmap.HitObjects[1], EditorBeatmap.HitObjects[0].GetEndTime(), slider.StartTime, + (new Vector2(300, 50), PathType.Bezier), + (new Vector2(400, 50), null), + (new Vector2(400, 200), null) + ) && sliderCreatedFor((Slider)EditorBeatmap.HitObjects[2], EditorBeatmap.HitObjects[1].GetEndTime(), endTime, + (new Vector2(400, 200), PathType.Catmull), + (new Vector2(300, 250), null), + (new Vector2(400, 300), null) + )); + } + + private bool sliderCreatedFor(Slider s, double startTime, double endTime, params (Vector2 pos, PathType? pathType)[] expectedControlPoints) + { + if (!Precision.AlmostEquals(s.StartTime, startTime, 1) || !Precision.AlmostEquals(s.EndTime, endTime, 1)) return false; + + int i = 0; + + foreach ((Vector2 pos, PathType? pathType) in expectedControlPoints) + { + var controlPoint = s.Path.ControlPoints[i++]; + + if (!Precision.AlmostEquals(controlPoint.Position + s.Position, pos) || controlPoint.Type != pathType) + return false; + } + + return true; } private void moveMouseToControlPoint(int index) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index e28dbb485d..d903ada6e2 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -294,6 +294,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders Path = new SliderPath(splitControlPoints.Select(o => new PathControlPoint(o.Position - splitControlPoints[0].Position, o == splitControlPoints[^1] ? null : o.Type)).ToArray()) }; + // Increase the start time of the slider before adding the new slider so the new slider is immediately inserted at the correct index and internal state remains valid. HitObject.StartTime += 1; editorBeatmap.Add(newSlider); From 91e6f4c4eefeac62597e5ce18da8f6a8a0dceab7 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Fri, 19 Aug 2022 19:31:47 +0200 Subject: [PATCH 0584/2686] fix TestPerfectCurveChangeToBezier --- .../Editor/TestScenePathControlPointVisualiser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs index f196353f87..6d93c3fcf9 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs @@ -182,7 +182,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor { AddStep($"click context menu item \"{contextMenuText}\"", () => { - MenuItem item = visualiser.ContextMenuItems[1].Items.FirstOrDefault(menuItem => menuItem.Text.Value == contextMenuText); + MenuItem item = visualiser.ContextMenuItems.FirstOrDefault(menuItem => menuItem.Text.Value == "Curve type")?.Items.FirstOrDefault(menuItem => menuItem.Text.Value == contextMenuText); item?.Action?.Value(); }); From 65f7ecec835da17236201a96cd9182e791981529 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Sat, 20 Aug 2022 00:26:04 +0200 Subject: [PATCH 0585/2686] moving all controlpoints at once for slider --- .../Edit/OsuSelectionHandler.cs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index f3c0a05bc2..bb78db68da 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -127,13 +127,14 @@ namespace osu.Game.Rulesets.Osu.Edit { didFlip = true; - foreach (var point in slider.Path.ControlPoints) - { - point.Position = new Vector2( - (direction == Direction.Horizontal ? -1 : 1) * point.Position.X, - (direction == Direction.Vertical ? -1 : 1) * point.Position.Y - ); - } + var controlPoints = slider.Path.ControlPoints.Select(p => + new PathControlPoint(new Vector2( + (direction == Direction.Horizontal ? -1 : 1) * p.Position.X, + (direction == Direction.Vertical ? -1 : 1) * p.Position.Y + ), p.Type)).ToArray(); + + slider.Path.ControlPoints.Clear(); + slider.Path.ControlPoints.AddRange(controlPoints); } } @@ -183,8 +184,11 @@ namespace osu.Game.Rulesets.Osu.Edit if (h is IHasPath path) { - foreach (var point in path.Path.ControlPoints) - point.Position = RotatePointAroundOrigin(point.Position, Vector2.Zero, delta); + var controlPoints = path.Path.ControlPoints.Select(p => + new PathControlPoint(RotatePointAroundOrigin(p.Position, Vector2.Zero, delta), p.Type)).ToArray(); + + path.Path.ControlPoints.Clear(); + path.Path.ControlPoints.AddRange(controlPoints); } } From 36e202c70ec33051b28d36be48b53d914d71ee05 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 20 Aug 2022 11:38:43 +0900 Subject: [PATCH 0586/2686] Add inline comment explaining necessity to use `AddRange` for slider transform operations --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index bb78db68da..061c5008c5 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -133,6 +133,8 @@ namespace osu.Game.Rulesets.Osu.Edit (direction == Direction.Vertical ? -1 : 1) * p.Position.Y ), p.Type)).ToArray(); + // Importantly, update as a single operation so automatic adjustment of control points to different + // curve types does not unexpectedly trigger and change the slider's shape. slider.Path.ControlPoints.Clear(); slider.Path.ControlPoints.AddRange(controlPoints); } @@ -187,6 +189,8 @@ namespace osu.Game.Rulesets.Osu.Edit var controlPoints = path.Path.ControlPoints.Select(p => new PathControlPoint(RotatePointAroundOrigin(p.Position, Vector2.Zero, delta), p.Type)).ToArray(); + // Importantly, update as a single operation so automatic adjustment of control points to different + // curve types does not unexpectedly trigger and change the slider's shape. path.Path.ControlPoints.Clear(); path.Path.ControlPoints.AddRange(controlPoints); } From 885ea4270b5bbad78a48690abdaa5f95e136b5c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 20 Aug 2022 14:03:54 +0900 Subject: [PATCH 0587/2686] Reorder context menu items and tidy up surrounding code --- .../Components/PathControlPointVisualiser.cs | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 3fb7ec93e6..48e1d6405d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -105,12 +105,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components return true; } - // The slider can only be split on control points which connect two different slider segments. - private bool splittable(PathControlPointPiece p) => p.ControlPoint.Type.HasValue && p != Pieces[0] && p != Pieces[^1]; - private bool splitSelected() { - List toSplit = Pieces.Where(p => p.IsSelected.Value && splittable(p)).Select(p => p.ControlPoint).ToList(); + List toSplit = Pieces.Where(p => p.IsSelected.Value && isSplittable(p)).Select(p => p.ControlPoint).ToList(); // Ensure that there are any points to be split if (toSplit.Count == 0) @@ -127,6 +124,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components return true; } + private bool isSplittable(PathControlPointPiece p) => + // A slider can only be split on control points which connect two different slider segments. + p.ControlPoint.Type.HasValue && p != Pieces.FirstOrDefault() && p != Pieces.LastOrDefault(); + private void onControlPointsChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) @@ -345,38 +346,42 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components if (count == 0) return null; - var splittablePieces = selectedPieces.Where(splittable).ToList(); + var splittablePieces = selectedPieces.Where(isSplittable).ToList(); int splittableCount = splittablePieces.Count; - List items = new List(); + List curveTypeItems = new List(); if (!selectedPieces.Contains(Pieces[0])) - items.Add(createMenuItemForPathType(null)); + curveTypeItems.Add(createMenuItemForPathType(null)); // todo: hide/disable items which aren't valid for selected points - items.Add(createMenuItemForPathType(PathType.Linear)); - items.Add(createMenuItemForPathType(PathType.PerfectCurve)); - items.Add(createMenuItemForPathType(PathType.Bezier)); - items.Add(createMenuItemForPathType(PathType.Catmull)); + curveTypeItems.Add(createMenuItemForPathType(PathType.Linear)); + curveTypeItems.Add(createMenuItemForPathType(PathType.PerfectCurve)); + curveTypeItems.Add(createMenuItemForPathType(PathType.Bezier)); + curveTypeItems.Add(createMenuItemForPathType(PathType.Catmull)); - var menuItems = new MenuItem[splittableCount > 0 ? 3 : 2]; - int i = 0; - - menuItems[i++] = new OsuMenuItem($"Delete {"control point".ToQuantity(count, count > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", MenuItemType.Destructive, - () => DeleteSelected()); + var menuItems = new List + { + new OsuMenuItem("Curve type") + { + Items = curveTypeItems + } + }; if (splittableCount > 0) { - menuItems[i++] = new OsuMenuItem($"Split {"control point".ToQuantity(splittableCount, splittableCount > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", - MenuItemType.Destructive, () => splitSelected()); + menuItems.Add(new OsuMenuItem($"Split {"control point".ToQuantity(splittableCount, splittableCount > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", + MenuItemType.Destructive, + () => splitSelected())); } - menuItems[i] = new OsuMenuItem("Curve type") - { - Items = items - }; + menuItems.Add( + new OsuMenuItem($"Delete {"control point".ToQuantity(count, count > 1 ? ShowQuantityAs.Numeric : ShowQuantityAs.None)}", + MenuItemType.Destructive, + () => DeleteSelected()) + ); - return menuItems; + return menuItems.ToArray(); } } From a1e849c4db045a111d93083d02931f97be5a9df3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 20 Aug 2022 16:22:35 +0900 Subject: [PATCH 0588/2686] Ensure that `DummyAPIAccess` runs all queued tasks on disposal --- osu.Game/Online/API/DummyAPIAccess.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 07d544260e..7dc34d1293 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -128,5 +128,13 @@ namespace osu.Game.Online.API IBindable IAPIProvider.Activity => Activity; public void FailNextLogin() => shouldFailNextLogin = true; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + // Ensure (as much as we can) that any pending tasks are run. + Scheduler.Update(); + } } } From 8566e93c72f38b9459b4769e1eda18a7d95d4644 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 20 Aug 2022 17:19:17 +0900 Subject: [PATCH 0589/2686] Guard against `SubmittingPlayer` potentially getting stuck waiting on request forever --- osu.Game/Screens/Play/SubmittingPlayer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index 02a95ae9eb..be77304076 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading.Tasks; using JetBrains.Annotations; using osu.Framework.Allocation; -using osu.Framework.Extensions; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Beatmaps; @@ -84,7 +83,10 @@ namespace osu.Game.Screens.Play api.Queue(req); - tcs.Task.WaitSafely(); + // Generally a timeout would not happen here as APIAccess will timeout first. + if (!tcs.Task.Wait(60000)) + handleTokenFailure(new InvalidOperationException("Token retrieval timed out (request never run)")); + return true; void handleTokenFailure(Exception exception) From 614ae815c0f1a5ae6315507fd40c7aedf418c7e7 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Sat, 20 Aug 2022 15:57:03 +0200 Subject: [PATCH 0590/2686] Added tests for making sure flipping and rotating retains perfect control point type --- .../Editor/TestSceneSliderSnapping.cs | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs index a72f2031c9..59f40894e0 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs @@ -12,6 +12,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Input.Bindings; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; using osu.Game.Rulesets.Osu.Objects; @@ -55,9 +56,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor { ControlPoints = { - new PathControlPoint(Vector2.Zero), - new PathControlPoint(OsuPlayfield.BASE_SIZE * 2 / 5), - new PathControlPoint(OsuPlayfield.BASE_SIZE * 3 / 5) + new PathControlPoint(Vector2.Zero, PathType.PerfectCurve), + new PathControlPoint(new Vector2(136, 205)), + new PathControlPoint(new Vector2(-4, 226)) } } })); @@ -99,8 +100,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddStep("move mouse to new point location", () => { var firstPiece = this.ChildrenOfType().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[0]); - var secondPiece = this.ChildrenOfType().Single(piece => piece.ControlPoint == slider.Path.ControlPoints[1]); - InputManager.MoveMouseTo((firstPiece.ScreenSpaceDrawQuad.Centre + secondPiece.ScreenSpaceDrawQuad.Centre) / 2); + var pos = slider.Path.PositionAt(0.25d) + slider.Position; + InputManager.MoveMouseTo(firstPiece.Parent.ToScreenSpace(pos)); }); AddStep("move slider end", () => { @@ -175,6 +176,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor assertSliderSnapped(false); } + [Test] + public void TestRotatingSliderRetainsPerfectControlPointType() + { + OsuSelectionHandler selectionHandler = null; + + AddAssert("first control point perfect", () => slider.Path.ControlPoints[0].Type == PathType.PerfectCurve); + + AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider)); + AddStep("rotate 90 degrees ccw", () => + { + selectionHandler = this.ChildrenOfType().Single(); + selectionHandler.HandleRotation(-90); + }); + + AddAssert("first control point still perfect", () => slider.Path.ControlPoints[0].Type == PathType.PerfectCurve); + } + [Test] public void TestFlippingSliderDoesNotSnap() { @@ -200,6 +218,23 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor assertSliderSnapped(false); } + [Test] + public void TestFlippingSliderRetainsPerfectControlPointType() + { + OsuSelectionHandler selectionHandler = null; + + AddAssert("first control point perfect", () => slider.Path.ControlPoints[0].Type == PathType.PerfectCurve); + + AddStep("select slider", () => EditorBeatmap.SelectedHitObjects.Add(slider)); + AddStep("flip slider horizontally", () => + { + selectionHandler = this.ChildrenOfType().Single(); + selectionHandler.OnPressed(new KeyBindingPressEvent(InputManager.CurrentState, GlobalAction.EditorFlipVertically)); + }); + + AddAssert("first control point still perfect", () => slider.Path.ControlPoints[0].Type == PathType.PerfectCurve); + } + [Test] public void TestReversingSliderDoesNotSnap() { From 7732fb21d5de1873483c713e3a8a70354b616bdb Mon Sep 17 00:00:00 2001 From: OliBomby Date: Sat, 20 Aug 2022 16:09:02 +0200 Subject: [PATCH 0591/2686] fix code quality --- osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs index 59f40894e0..e864afe056 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs @@ -179,7 +179,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor [Test] public void TestRotatingSliderRetainsPerfectControlPointType() { - OsuSelectionHandler selectionHandler = null; + OsuSelectionHandler selectionHandler; AddAssert("first control point perfect", () => slider.Path.ControlPoints[0].Type == PathType.PerfectCurve); @@ -221,7 +221,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor [Test] public void TestFlippingSliderRetainsPerfectControlPointType() { - OsuSelectionHandler selectionHandler = null; + OsuSelectionHandler selectionHandler; AddAssert("first control point perfect", () => slider.Path.ControlPoints[0].Type == PathType.PerfectCurve); From 3ac6500423a8c7607989e855de3eda71484eca8f Mon Sep 17 00:00:00 2001 From: Ryuki Date: Fri, 19 Aug 2022 00:49:03 +0200 Subject: [PATCH 0592/2686] Add new test resources for CPS counter --- .../Archives/modified-default-20220818.osk | Bin 0 -> 1145 bytes osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 4 +++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Resources/Archives/modified-default-20220818.osk diff --git a/osu.Game.Tests/Resources/Archives/modified-default-20220818.osk b/osu.Game.Tests/Resources/Archives/modified-default-20220818.osk new file mode 100644 index 0000000000000000000000000000000000000000..92215cbf8655decffeedfabd902ed0e8923bab66 GIT binary patch literal 1145 zcmWIWW@Zs#U|`^2NLVTqs`|jDa|)2R0W8A6P@J8arxn6S=HYqNAcrbLkFt<8S zdHCG=Wxv;FdCR48&5>TQc#^zr@Z(j<8zY0+!z(-V9<9<3Kyi8A6BC6ZpsPE9m=}ma zF3-$M%h$^)&d*!@>}gOyz$foBzM-3f0#51cg@#E_w1`>3Opjh`99S~7VrLd3s^caHu3EB{k%8ea&}Cvk$N45^=6Qs= zIOpdUYt#t>`Il0=~M34Q~2k%>zY_|J@Sq?YP0NlkD**?k?0eZrEh$HT#c&P z9%mv}`qyo)_ritmZ>gHp6`p^0>BQEfRwWm`?gy+5d263H)tddC+uj3ECk}@!ESGR@ALFKi%qnSq2%um-l#P&Pw z=#<$j^rQXL#=;|O+LN{a9{(t3aqe3de_f6Z*MX%+dkuuRR`--M_xVM-9hRSy`v1+3 zDecZRMT{q9mY8*gr!_ZO|AU)E;K zooDlh4K<=Qcl+?N03(VK0p5&EA`G~*98eboG=eBt z21M6|p4_2&7#JFNL3P0sKe|@*#E8%u4osrhlP09~Q;lPaH>i}<7Hjn}qAp8WR J3xP@)7yzY8uFwDg literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index c7eb334f25..1b03f8ef6b 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -36,7 +36,9 @@ namespace osu.Game.Tests.Skins "Archives/modified-default-20220723.osk", "Archives/modified-classic-20220723.osk", // Covers legacy song progress, UR counter, colour hit error metre. - "Archives/modified-classic-20220801.osk" + "Archives/modified-classic-20220801.osk", + // Covers clicks/s counter + "Archives/modified-default-20220818.osk" }; /// From 9386d352b869fad05071601fb834ed2e00ce19d3 Mon Sep 17 00:00:00 2001 From: naoei Date: Sat, 20 Aug 2022 21:48:35 -0400 Subject: [PATCH 0593/2686] Make StatisticItem.Name not nullable --- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- osu.Game/Screens/Ranking/Statistics/StatisticItem.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 555c272954..04bb08395b 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -239,7 +239,7 @@ namespace osu.Game.Rulesets.Taiko { Columns = new[] { - new StatisticItem(null, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] { new AverageHitError(timedHitEvents), new UnstableRate(timedHitEvents) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs index e1ea352f1c..e3ac054d1b 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// /// The name of this item. /// - public readonly LocalisableString? Name; + public readonly LocalisableString Name; /// /// A function returning the content to be displayed. @@ -49,7 +49,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// A function returning the content to be displayed. /// Whether this item requires hit events. If true, will not be called if no hit events are available. /// The of this item. This can be thought of as the column dimension of an encompassing . - public StatisticItem(LocalisableString? name, [NotNull] Func createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) + public StatisticItem(LocalisableString name, [NotNull] Func createContent, bool requiresHitEvents = false, [CanBeNull] Dimension dimension = null) { Name = name; RequiresHitEvents = requiresHitEvents; From 29ef1c8db8fcc5e53dbb9385768489149eaa5d6e Mon Sep 17 00:00:00 2001 From: naoei Date: Sat, 20 Aug 2022 21:48:53 -0400 Subject: [PATCH 0594/2686] Check if StatisticItem.Name is null or empty --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 2167e5e5ac..25749cb3d6 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -396,7 +396,7 @@ namespace osu.Game.Rulesets.Mania { Columns = new[] { - new StatisticItem(null, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] { new AverageHitError(score.HitEvents), new UnstableRate(score.HitEvents) diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index f7df949414..7f58f29d4b 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -317,7 +317,7 @@ namespace osu.Game.Rulesets.Osu { Columns = new[] { - new StatisticItem(null, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] + new StatisticItem(string.Empty, () => new SimpleStatisticTable(3, new SimpleStatisticItem[] { new AverageHitError(timedHitEvents), new UnstableRate(timedHitEvents) diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs index 1cf46dcf04..1505585205 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs @@ -8,6 +8,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; @@ -59,7 +60,7 @@ namespace osu.Game.Screens.Ranking.Statistics private static Drawable createHeader(StatisticItem item) { - if (item.Name == null) + if (LocalisableString.IsNullOrEmpty(item.Name)) return Empty(); return new FillFlowContainer @@ -82,7 +83,7 @@ namespace osu.Game.Screens.Ranking.Statistics { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Text = item.Name.Value, + Text = item.Name, Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), } } From 5cf54a788adc5601a518b41409a91a9daca76534 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Sun, 21 Aug 2022 03:15:30 +0200 Subject: [PATCH 0595/2686] Code cleanup for CPS counter --- .../ClicksPerSecond/ClicksPerSecondCounter.cs | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs index 049f38ba4c..3ff06d5217 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -19,9 +18,8 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond { private const float alpha_when_invalid = 0.3f; - private readonly Bindable valid = new Bindable(); - - private ClicksPerSecondCalculator? calculator; + [Resolved(canBeNull: false)] + private ClicksPerSecondCalculator calculator { get; set; } = null!; protected override double RollingDuration => 350; @@ -33,26 +31,19 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond } [BackgroundDependencyLoader] - private void load(OsuColour colours, ClicksPerSecondCalculator calculator) + private void load(OsuColour colours) { - this.calculator = calculator; Colour = colours.BlueLighter; - valid.BindValueChanged(e => - DrawableCount.FadeTo(e.NewValue ? 1 : alpha_when_invalid, 1000, Easing.OutQuint)); } protected override void Update() { base.Update(); - valid.Value = calculator != null && calculator.Ready; - Current.Value = calculator != null ? calculator.Ready ? calculator.Value : 0 : 0; + Current.Value = calculator.Ready ? calculator.Value : 0; } - protected override IHasText CreateText() => new TextComponent - { - Alpha = alpha_when_invalid - }; + protected override IHasText CreateText() => new TextComponent(); private class TextComponent : CompositeDrawable, IHasText { From aa15e84beab530d093119d4ca09f44fdc5f8eaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 21 Aug 2022 23:07:42 +0200 Subject: [PATCH 0596/2686] Adjust rounding in mod select difficulty multiplier to match song select footer The 0.01 `Precision` spec on `DifficultyMultiplierDisplay.Current` would cause the difficulty multiplier to use a different midpoint rounding strategy than `double.ToString()`, which is the one that the song select footer relies on. For example, a value of 0.015 would be rounded down to 0.01 by `double.ToString()`, but rounded up to 0.02 by `BindableDouble`. Fix the discrepancy by just deleting the `Precision` spec. Since the value of the bindable would go through `ToLocalisableString(@"N2")` anyway, it was redundant as is. Fixes #19889. --- osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index 255d01466f..835883fb93 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -31,10 +31,7 @@ namespace osu.Game.Overlays.Mods set => current.Current = value; } - private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(1) - { - Precision = 0.01 - }; + private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(1); private readonly Box underlayBackground; private readonly Box contentBackground; From c56390cd7b4f7f4c442a321e9a71ce1293e72a3d Mon Sep 17 00:00:00 2001 From: Ryuki Date: Mon, 22 Aug 2022 00:03:24 +0200 Subject: [PATCH 0597/2686] Use less custom classes for CPS tests --- .../Gameplay/TestSceneClicksPerSecond.cs | 272 +++++++++--------- 1 file changed, 144 insertions(+), 128 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs index 69868e07b4..375726dd9a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using NUnit.Framework; using osu.Framework.Bindables; @@ -13,9 +14,9 @@ using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Rulesets; using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -27,9 +28,12 @@ namespace osu.Game.Tests.Visual.Gameplay public class TestSceneClicksPerSecond : OsuTestScene { private DependencyProvidingContainer? dependencyContainer; - private MockFrameStableClock? mainClock; private ClicksPerSecondCalculator? calculator; private ManualInputListener? listener; + private GameplayClockContainer? gameplayClockContainer; + private ManualClock? manualClock; + private DrawableRuleset? drawableRuleset; + private IFrameStableClock? frameStableClock; [SetUpSteps] public void SetUpSteps() @@ -40,41 +44,20 @@ namespace osu.Game.Tests.Visual.Gameplay Debug.Assert(ruleset != null); - Children = new Drawable[] + Child = gameplayClockContainer = new GameplayClockContainer(manualClock = new ManualClock()); + gameplayClockContainer.AddRange(new Drawable[] { + drawableRuleset = new TestDrawableRuleset(frameStableClock = new TestFrameStableClock(manualClock)), dependencyContainer = new DependencyProvidingContainer { RelativeSizeAxes = Axes.Both, CachedDependencies = new (Type, object)[] { - (typeof(IGameplayClock), mainClock = new MockFrameStableClock(new MockFrameBasedClock())), - (typeof(DrawableRuleset), new MockDrawableRuleset(ruleset, mainClock)) - } - }, - }; - }); - } - - private void createCalculator() - { - AddStep("create calculator", () => - { - dependencyContainer!.Children = new Drawable[] - { - calculator = new ClicksPerSecondCalculator(), - new DependencyProvidingContainer - { - RelativeSizeAxes = Axes.Both, - CachedDependencies = new (Type, object)[] { (typeof(ClicksPerSecondCalculator), calculator) }, - Child = new ClicksPerSecondCounter // For visual debugging, has no real purpose in the tests - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(5), + (typeof(DrawableRuleset), drawableRuleset), + (typeof(IGameplayClock), gameplayClockContainer) } } - }; - calculator!.Listener = listener = new ManualInputListener(calculator!); + }); }); } @@ -82,6 +65,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestBasicConsistency() { createCalculator(); + startClock(); AddStep("Create gradually increasing KPS inputs", () => { @@ -101,6 +85,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestRateAdjustConsistency() { createCalculator(); + startClock(); AddStep("Create consistent KPS inputs", () => addInputs(generateConsistentKps(10))); @@ -125,6 +110,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestInputsDiscardedOnRewind() { createCalculator(); + startClock(); AddStep("Create consistent KPS inputs", () => addInputs(generateConsistentKps(10))); seek(1000); @@ -136,38 +122,79 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("KPS didn't changed", () => calculator!.Value == 10); } - private void seek(double time) => AddStep($"Seek main clock to {time}ms", () => mainClock?.Seek(time)); - - private void changeRate(double rate) => AddStep($"Change rate to x{rate}", () => - (mainClock?.UnderlyingClock as MockFrameBasedClock)!.Rate = rate); - - private void advanceForwards(int frames = 1) => AddStep($"Advance main clock {frames} frame(s) forward.", () => + private void seekAllClocks(double time) { - if (mainClock == null) return; + gameplayClockContainer?.Seek(time); + manualClock!.CurrentTime = time; + } - MockFrameBasedClock underlyingClock = (MockFrameBasedClock)mainClock.UnderlyingClock; - underlyingClock.Backwards = false; + protected override Ruleset CreateRuleset() => new OsuRuleset(); - for (int i = 0; i < frames; i++) + #region Quick steps methods + + private void createCalculator() + { + AddStep("create calculator", () => { - underlyingClock.ProcessFrame(); - } + Debug.Assert(dependencyContainer?.Dependencies.Get(typeof(DrawableRuleset)) is DrawableRuleset); + dependencyContainer!.Children = new Drawable[] + { + calculator = new ClicksPerSecondCalculator(), + new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] { (typeof(ClicksPerSecondCalculator), calculator) }, + Child = new ClicksPerSecondCounter // For visual debugging, has no real purpose in the tests + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(5), + } + } + }; + calculator!.Listener = listener = new ManualInputListener(calculator!); + }); + } + + private void seek(double time) => AddStep($"Seek clocks to {time}ms", () => seekAllClocks(time)); + + private void changeRate(double rate) => AddStep($"Change rate to x{rate}", () => manualClock!.Rate = rate); + + private void advanceForwards(double time) => + AddStep($"Advance clocks {time} seconds forward.", () => + { + gameplayClockContainer!.Seek(gameplayClockContainer.CurrentTime + time * manualClock!.Rate); + + for (int i = 0; i < time; i++) + { + frameStableClock?.ProcessFrame(); + } + }); + + private void startClock() => AddStep("Start clocks", () => + { + gameplayClockContainer?.Start(); + manualClock!.Rate = 1; }); + #endregion + + #region Input generation + private void addInputs(IEnumerable inputs) { - Debug.Assert(mainClock != null && listener != null); + Debug.Assert(manualClock != null && listener != null && gameplayClockContainer != null); if (!inputs.Any()) return; - double baseTime = mainClock.CurrentTime; + double baseTime = gameplayClockContainer.CurrentTime; foreach (double timestamp in inputs) { - mainClock.Seek(timestamp); + seekAllClocks(timestamp); listener.AddInput(); } - mainClock.Seek(baseTime); + seekAllClocks(baseTime); } private IEnumerable generateGraduallyIncreasingKps() @@ -200,9 +227,52 @@ namespace osu.Game.Tests.Visual.Gameplay } } - protected override Ruleset CreateRuleset() => new ManiaRuleset(); + #endregion - #region Mock classes + #region Test classes + + private class TestFrameStableClock : IFrameStableClock + { + public TestFrameStableClock(IClock source, double startTime = 0) + { + this.source = source; + StartTime = startTime; + + if (source is ManualClock manualClock) + { + manualClock.CurrentTime = startTime; + } + } + + public double CurrentTime => source.CurrentTime; + public double Rate => source.Rate; + public bool IsRunning => source.IsRunning; + + private IClock source; + + public void ProcessFrame() + { + if (source is ManualClock manualClock) + { + manualClock.CurrentTime += 1000 * Rate; + } + + TimeInfo = new FrameTimeInfo + { + Elapsed = 1000 * Rate, + Current = CurrentTime + }; + } + + public double ElapsedFrameTime => TimeInfo.Elapsed; + public double FramesPerSecond => 1 / ElapsedFrameTime * 1000; + public FrameTimeInfo TimeInfo { get; private set; } + + public double? StartTime { get; } + public IEnumerable NonGameplayAdjustments => Enumerable.Empty(); + public IBindable IsCatchingUp => new Bindable(); + public IBindable WaitingOnFrames => new Bindable(); + } private class ManualInputListener : ClicksPerSecondCalculator.InputListener { @@ -214,108 +284,54 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class MockFrameBasedClock : ManualClock, IFrameBasedClock +#nullable disable + + [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] + private class TestDrawableRuleset : DrawableRuleset { - public const double FRAME_INTERVAL = 1000; - public bool Backwards; + public override IEnumerable Objects => Enumerable.Empty(); - public MockFrameBasedClock() + public override event Action NewResult { - Rate = 1; - IsRunning = true; + add => throw new InvalidOperationException($"{nameof(NewResult)} operations not supported in test context"); + remove => throw new InvalidOperationException($"{nameof(NewResult)} operations not supported in test context"); } - public void ProcessFrame() + public override event Action RevertResult { - CurrentTime += FRAME_INTERVAL * Rate * (Backwards ? -1 : 1); - TimeInfo = new FrameTimeInfo - { - Current = CurrentTime, - Elapsed = FRAME_INTERVAL * Rate * (Backwards ? -1 : 1) - }; + add => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); + remove => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); } - public void Seek(double time) - { - TimeInfo = new FrameTimeInfo - { - Elapsed = time - CurrentTime, - Current = CurrentTime = time - }; - } - - public double ElapsedFrameTime => TimeInfo.Elapsed; - public double FramesPerSecond => 1 / FRAME_INTERVAL; - public FrameTimeInfo TimeInfo { get; private set; } - } - - private class MockFrameStableClock : IGameplayClock, IFrameStableClock - { - internal readonly IFrameBasedClock UnderlyingClock; - - public readonly BindableBool IsPaused = new BindableBool(); - - public MockFrameStableClock(MockFrameBasedClock underlyingClock) - { - UnderlyingClock = underlyingClock; - } - - public void Seek(double time) => (UnderlyingClock as MockFrameBasedClock)?.Seek(time); - - public IBindable IsCatchingUp => new Bindable(); - public IBindable WaitingOnFrames => new Bindable(); - public double CurrentTime => UnderlyingClock.CurrentTime; - public double Rate => UnderlyingClock.Rate; - public bool IsRunning => UnderlyingClock.IsRunning; - public void ProcessFrame() => UnderlyingClock.ProcessFrame(); - - public double ElapsedFrameTime => UnderlyingClock.ElapsedFrameTime; - public double FramesPerSecond => UnderlyingClock.FramesPerSecond; - public FrameTimeInfo TimeInfo => UnderlyingClock.TimeInfo; - public double TrueGameplayRate => UnderlyingClock.Rate; - public double? StartTime => 0; - public IEnumerable NonGameplayAdjustments => Enumerable.Empty(); - IBindable IGameplayClock.IsPaused => IsPaused; - } - - private class MockDrawableRuleset : DrawableRuleset - { - public MockDrawableRuleset(Ruleset ruleset, IFrameStableClock clock) - : base(ruleset) - { - FrameStableClock = clock; - } - -#pragma warning disable CS0067 - public override event Action? NewResult; - public override event Action? RevertResult; -#pragma warning restore CS0067 - public override Playfield? Playfield => null; - public override Container? Overlays => null; - public override Container? FrameStableComponents => null; + public override Playfield Playfield => null; + public override Container Overlays => null; + public override Container FrameStableComponents => null; public override IFrameStableClock FrameStableClock { get; } internal override bool FrameStablePlayback { get; set; } public override IReadOnlyList Mods => Array.Empty(); - public override IEnumerable Objects => Array.Empty(); + public override double GameplayStartTime => 0; - public override GameplayCursorContainer? Cursor => null; + public override GameplayCursorContainer Cursor => null; - public override void SetReplayScore(Score replayScore) + public TestDrawableRuleset() + : base(new OsuRuleset()) { } - public override void SetRecordTarget(Score score) + public TestDrawableRuleset(IFrameStableClock frameStableClock) + : this() { + FrameStableClock = frameStableClock; } - public override void RequestResume(Action continueResume) - { - } + public override void SetReplayScore(Score replayScore) => throw new NotImplementedException(); - public override void CancelResume() - { - } + public override void SetRecordTarget(Score score) => throw new NotImplementedException(); + + public override void RequestResume(Action continueResume) => throw new NotImplementedException(); + + public override void CancelResume() => throw new NotImplementedException(); } #endregion From c6a739f5a84acf2af368dbae2d80db911511e941 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Sun, 21 Aug 2022 23:09:33 -0400 Subject: [PATCH 0598/2686] Add date submitted sorting --- osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs | 6 ++++++ osu.Game/Screens/Select/Filter/SortMode.cs | 3 +++ 2 files changed, 9 insertions(+) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 59d9318962..5a48d8d493 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -99,6 +99,12 @@ namespace osu.Game.Screens.Select.Carousel case SortMode.Difficulty: return compareUsingAggregateMax(otherSet, b => b.StarRating); + + case SortMode.DateSubmitted: + if (BeatmapSet.DateSubmitted == null || otherSet.BeatmapSet.DateSubmitted == null) + return 0; + + return otherSet.BeatmapSet.DateSubmitted.Value.CompareTo(BeatmapSet.DateSubmitted.Value); } } diff --git a/osu.Game/Screens/Select/Filter/SortMode.cs b/osu.Game/Screens/Select/Filter/SortMode.cs index 1e60ea3bac..c77bdbfbc6 100644 --- a/osu.Game/Screens/Select/Filter/SortMode.cs +++ b/osu.Game/Screens/Select/Filter/SortMode.cs @@ -20,6 +20,9 @@ namespace osu.Game.Screens.Select.Filter [LocalisableDescription(typeof(SortStrings), nameof(SortStrings.ArtistTracksBpm))] BPM, + [Description("Date Submitted")] + DateSubmitted, + [Description("Date Added")] DateAdded, From e1fa959f0b97189eeac72a20c95ed6fe667164c7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 Aug 2022 12:59:52 +0900 Subject: [PATCH 0599/2686] Fix language change removing mod column bold text --- osu.Game/Overlays/Mods/ModSelectColumn.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModSelectColumn.cs b/osu.Game/Overlays/Mods/ModSelectColumn.cs index 0224631577..d5dc079628 100644 --- a/osu.Game/Overlays/Mods/ModSelectColumn.cs +++ b/osu.Game/Overlays/Mods/ModSelectColumn.cs @@ -159,12 +159,15 @@ namespace osu.Game.Overlays.Mods int wordIndex = 0; - headerText.AddText(text, t => + ITextPart part = headerText.AddText(text, t => { if (wordIndex == 0) t.Font = t.Font.With(weight: FontWeight.SemiBold); wordIndex += 1; }); + + // Reset the index so that if the parts are refreshed (e.g. through changes in localisation) the correct word is re-emboldened. + part.DrawablePartsRecreated += _ => wordIndex = 0; } [BackgroundDependencyLoader] From 85d0b7fc57ffe7c040167c49ee26fd0fa145a772 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 14:02:20 +0900 Subject: [PATCH 0600/2686] Reword class xmldoc to better explain that offset application is optional --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index 90ff0588a6..62f1af3ef2 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -19,8 +19,8 @@ namespace osu.Game.Beatmaps /// A clock intended to be the single source-of-truth for beatmap timing. /// /// It provides some functionality: - /// - Applies (and tracks changes of) beatmap, user, and platform offsets. - /// - Adjusts operations to account for said offsets, seeking in raw time values. + /// - Optionally applies (and tracks changes of) beatmap, user, and platform offsets (see ctor argument applyOffsets). + /// - Adjusts operations to account for any applied offsets, seeking in raw "beatmap" time values. /// - Exposes track length. /// - Allows changing the source to a new track (for cases like editor track updating). /// From ba23ce75c2d16bbf40d7d945d426644d044645f2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 14:02:41 +0900 Subject: [PATCH 0601/2686] Make `FramedBeatmapClock.Track` non-null --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index 62f1af3ef2..b4a96ed46a 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -31,12 +31,12 @@ namespace osu.Game.Beatmaps /// /// The length of the underlying beatmap track. Will default to 60 seconds if unavailable. /// - public double TrackLength => Track?.Length ?? 60000; + public double TrackLength => Track.Length; /// /// The underlying beatmap track, if available. /// - public Track? Track { get; private set; } // TODO: virtual rather than null? + public Track Track { get; private set; } = new TrackVirtual(60000); /// /// The total frequency adjustment from pause transforms. Should eventually be handled in a better way. @@ -144,7 +144,7 @@ namespace osu.Game.Beatmaps public void ChangeSource(IClock? source) { - Track = source as Track; + Track = source as Track ?? new TrackVirtual(60000); decoupledClock.ChangeSource(source); } From 17a1df281c34c5c5ffa8b25f34acdaa3b0b9a4ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 14:03:51 +0900 Subject: [PATCH 0602/2686] Fix incorrect implicit null specification for user audio offset bindable --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index b4a96ed46a..3166f688ea 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -49,7 +49,7 @@ namespace osu.Game.Beatmaps private readonly IFrameBasedClock finalClockSource; - private Bindable userAudioOffset = null!; + private Bindable? userAudioOffset; private IDisposable? beatmapOffsetSubscription; From af2e82d7d54fb19cc04dd14715348ea5ebf56b61 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 14:11:06 +0900 Subject: [PATCH 0603/2686] Move operation of setting `GameplayClockContainer.StartTime` to `Reset` call --- .../Gameplay/TestSceneStoryboardSamples.cs | 3 ++- .../Screens/Edit/GameplayTest/EditorPlayer.cs | 6 +++++- .../Spectate/MultiSpectatorScreen.cs | 3 +-- .../Screens/Play/GameplayClockContainer.cs | 21 +++++++------------ .../Play/MasterGameplayClockContainer.cs | 2 +- osu.Game/Screens/Play/Player.cs | 5 ++--- 6 files changed, 19 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index afdcedb485..dcaeadf82a 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -107,12 +107,13 @@ namespace osu.Game.Tests.Gameplay Add(gameplayContainer = new MasterGameplayClockContainer(working, start_time) { - StartTime = start_time, Child = new FrameStabilityContainer { Child = sample = new DrawableStoryboardSample(new StoryboardSampleInfo(string.Empty, 0, 1)) } }); + + gameplayContainer.Reset(start_time); }); AddStep("start time", () => gameplayContainer.Start()); diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs index fd230a97bc..94975b6b5e 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs @@ -27,7 +27,11 @@ namespace osu.Game.Screens.Edit.GameplayTest } protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) - => new MasterGameplayClockContainer(beatmap, gameplayStart) { StartTime = editorState.Time }; + { + var masterGameplayClockContainer = new MasterGameplayClockContainer(beatmap, gameplayStart); + masterGameplayClockContainer.Reset(editorState.Time); + return masterGameplayClockContainer; + } protected override void LoadComplete() { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index f200702e80..940f9078a8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -192,8 +192,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate .DefaultIfEmpty(0) .Min(); - masterClockContainer.StartTime = startTime; - masterClockContainer.Reset(true); + masterClockContainer.Reset(startTime, true); // Although the clock has been started, this flag is set to allow for later synchronisation state changes to also be able to start it. canStartMasterClock = true; diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 6dab13c950..f3dcf1a64c 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -38,23 +38,13 @@ namespace osu.Game.Screens.Play /// /// The time from which the clock should start. Will be seeked to on calling . - /// Settting a start time will to the new value. + /// Can be adjusted by calling with a time value. /// /// /// By default, a value of zero will be used. /// Importantly, the value will be inferred from the current beatmap in by default. /// - public double StartTime - { - get => startTime; - set - { - startTime = value; - Reset(); - } - } - - private double startTime; + public double StartTime { get; private set; } public virtual IEnumerable NonGameplayAdjustments => Enumerable.Empty(); @@ -139,13 +129,18 @@ namespace osu.Game.Screens.Play /// /// Resets this and the source to an initial state ready for gameplay. /// + /// The time to seek to on resetting. If null, the existing will be used. /// Whether to start the clock immediately, if not already started. - public void Reset(bool startClock = false) + public void Reset(double? time = null, bool startClock = false) { // Manually stop the source in order to not affect the IsPaused state. GameplayClock.Stop(); ensureSourceClockSet(); + + if (time != null) + StartTime = time.Value; + Seek(StartTime); if (!IsPaused.Value || startClock) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index eca0c92f8f..c3c92eb0fe 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -58,7 +58,7 @@ namespace osu.Game.Screens.Play this.beatmap = beatmap; this.skipTargetTime = skipTargetTime; - StartTime = findEarliestStartTime(); + Reset(findEarliestStartTime()); } private double findEarliestStartTime() diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 6827ff04d3..d8db41c833 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -640,8 +640,7 @@ namespace osu.Game.Screens.Play bool wasFrameStable = DrawableRuleset.FrameStablePlayback; DrawableRuleset.FrameStablePlayback = false; - GameplayClockContainer.StartTime = time; - GameplayClockContainer.Reset(); + GameplayClockContainer.Reset(time); // Delay resetting frame-stable playback for one frame to give the FrameStabilityContainer a chance to seek. frameStablePlaybackResetDelegate = ScheduleAfterChildren(() => DrawableRuleset.FrameStablePlayback = wasFrameStable); @@ -1012,7 +1011,7 @@ namespace osu.Game.Screens.Play if (GameplayClockContainer.IsRunning) throw new InvalidOperationException($"{nameof(StartGameplay)} should not be called when the gameplay clock is already running"); - GameplayClockContainer.Reset(true); + GameplayClockContainer.Reset(startClock: true); } public override void OnSuspending(ScreenTransitionEvent e) From e6b669db8e62c5d25c1db41d4285b2ab8b3a2ced Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 14:14:44 +0900 Subject: [PATCH 0604/2686] Elaborate with example of `GameplayClockContainer` managing its own `Stop` state --- osu.Game/Screens/Play/GameplayClockContainer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index f3dcf1a64c..a00ae27781 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -88,6 +88,7 @@ namespace osu.Game.Screens.Play isPaused.Value = false; // the clock may be stopped via internal means (ie. not via `IsPaused`). + // see Reset() calling `GameplayClock.Stop()` as one example. if (!GameplayClock.IsRunning) { // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time From 9d31f61ca91cd8b3a1815692070083079febe93a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 14:35:44 +0900 Subject: [PATCH 0605/2686] Don't throw when a ruleset type is completely missing --- osu.Game/Rulesets/RealmRulesetStore.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/RealmRulesetStore.cs b/osu.Game/Rulesets/RealmRulesetStore.cs index 7b1f3a3f6c..dba7f47f2f 100644 --- a/osu.Game/Rulesets/RealmRulesetStore.cs +++ b/osu.Game/Rulesets/RealmRulesetStore.cs @@ -68,8 +68,14 @@ namespace osu.Game.Rulesets { try { - var resolvedType = Type.GetType(r.InstantiationInfo) - ?? throw new RulesetLoadException(@"Type could not be resolved"); + var resolvedType = Type.GetType(r.InstantiationInfo); + + if (resolvedType == null) + { + // ruleset DLL was probably deleted. + r.Available = false; + continue; + } var instanceInfo = (Activator.CreateInstance(resolvedType) as Ruleset)?.RulesetInfo ?? throw new RulesetLoadException(@"Instantiation failure"); From d199b3b1009afcf776d1f14bba86a910fff37f3f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 14:51:00 +0900 Subject: [PATCH 0606/2686] Update `GetVariantName` to also support localisation --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../Settings/Sections/Input/VariantBindingsSubsection.cs | 2 -- osu.Game/Rulesets/Ruleset.cs | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 25749cb3d6..ac6060ceed 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -312,7 +312,7 @@ namespace osu.Game.Rulesets.Mania return Array.Empty(); } - public override string GetVariantName(int variant) + public override LocalisableString GetVariantName(int variant) { switch (getPlayfieldType(variant)) { diff --git a/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs index 23f91fba4b..a0f069b3bb 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.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. -#nullable disable - using osu.Framework.Localisation; using osu.Game.Rulesets; diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 50ce6b3b12..0968d78ed7 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -289,7 +289,7 @@ namespace osu.Game.Rulesets /// /// The variant. /// A descriptive name of the variant. - public virtual string GetVariantName(int variant) => string.Empty; + public virtual LocalisableString GetVariantName(int variant) => string.Empty; /// /// For rulesets which support legacy (osu-stable) replay conversion, this method will create an empty replay frame From 19bba143ee74fd21eed399ca35b1f806bc1d43b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 15:57:24 +0900 Subject: [PATCH 0607/2686] Fix editor crashing on mobile releases --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index e41802808f..8f3e077050 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -86,7 +86,7 @@ namespace osu.Game.Rulesets.UI this.gameplayStartTime = gameplayStartTime; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(IGameplayClock? gameplayClock) { if (gameplayClock != null) From 09ef13908ca8c9f82cd691bc47c6c1657e14e133 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Mon, 22 Aug 2022 03:20:27 -0400 Subject: [PATCH 0608/2686] Adjust to reviews --- osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs | 1 + osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index 5b17b412ae..f1f7c47e1b 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -56,6 +56,7 @@ namespace osu.Game.Screens.Select.Carousel criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode); match &= criteria.Sort != SortMode.DateRanked || BeatmapInfo.BeatmapSet?.DateRanked != null; + match &= criteria.Sort != SortMode.DateSubmitted || BeatmapInfo.BeatmapSet?.DateSubmitted != null; match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating); diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 5a48d8d493..8298c73fe9 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -101,6 +101,7 @@ namespace osu.Game.Screens.Select.Carousel return compareUsingAggregateMax(otherSet, b => b.StarRating); case SortMode.DateSubmitted: + // Beatmaps which have no submitted date should already be filtered away in this mode. if (BeatmapSet.DateSubmitted == null || otherSet.BeatmapSet.DateSubmitted == null) return 0; From f5710d8000d3bc11c4a2065f411105c53e249914 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 16:10:55 +0900 Subject: [PATCH 0609/2686] Add ruleset API versioning --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 ++ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 ++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 ++ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 ++ osu.Game/Rulesets/Ruleset.cs | 17 +++++++++++++++++ 5 files changed, 25 insertions(+) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index ed151855b1..f94bf276a0 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -43,6 +43,8 @@ namespace osu.Game.Rulesets.Catch public const string SHORT_NAME = "fruits"; + public override string RulesetAPIVersionSupported => "internal"; + public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { new KeyBinding(InputKey.Z, CatchAction.MoveLeft), diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index ac6060ceed..b1fe4b30c4 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -60,6 +60,8 @@ namespace osu.Game.Rulesets.Mania public const string SHORT_NAME = "mania"; + public override string RulesetAPIVersionSupported => "internal"; + public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this); public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new ManiaLegacySkinTransformer(skin, beatmap); diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 7f58f29d4b..4400dfbb65 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -54,6 +54,8 @@ namespace osu.Game.Rulesets.Osu public const string SHORT_NAME = "osu"; + public override string RulesetAPIVersionSupported => "internal"; + public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { new KeyBinding(InputKey.Z, OsuAction.LeftButton), diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 04bb08395b..275c7144a7 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -49,6 +49,8 @@ namespace osu.Game.Rulesets.Taiko public const string SHORT_NAME = "taiko"; + public override string RulesetAPIVersionSupported => "internal"; + public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { new KeyBinding(InputKey.MouseLeft, TaikoAction.LeftCentre), diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 0968d78ed7..63f5906f46 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -44,6 +44,23 @@ namespace osu.Game.Rulesets private static readonly ConcurrentDictionary mod_reference_cache = new ConcurrentDictionary(); + /// + /// Version history: + /// 2022.205.0 FramedReplayInputHandler.CollectPendingInputs renamed to FramedReplayHandler.CollectReplayInputs. + /// 2022.822.0 All strings return values have been converted to LocalisableString to allow for localisation support. + /// + public const string CURRENT_RULESET_API_VERSION = "2022.822.0"; + + /// + /// Define the ruleset API version supported by this ruleset. + /// Ruleset implementations should be updated to support the latest version to ensure they can still be loaded. + /// + /// + /// When updating a ruleset to support the latest API, you should set this to . + /// See https://github.com/ppy/osu/wiki/Breaking-Changes for full details on required ongoing changes. + /// + public virtual string RulesetAPIVersionSupported => string.Empty; + /// /// A queryable source containing all available mods. /// Call for consumption purposes. From 758a554180fb61f21dbc8b9eae6d90d674358ded Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 16:31:25 +0900 Subject: [PATCH 0610/2686] Add basic check for correct ruleset API version --- osu.Game/Rulesets/RealmRulesetStore.cs | 28 +++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/RealmRulesetStore.cs b/osu.Game/Rulesets/RealmRulesetStore.cs index dba7f47f2f..590f118b68 100644 --- a/osu.Game/Rulesets/RealmRulesetStore.cs +++ b/osu.Game/Rulesets/RealmRulesetStore.cs @@ -77,9 +77,16 @@ namespace osu.Game.Rulesets continue; } - var instanceInfo = (Activator.CreateInstance(resolvedType) as Ruleset)?.RulesetInfo + var instance = (Activator.CreateInstance(resolvedType) as Ruleset); + var instanceInfo = instance?.RulesetInfo ?? throw new RulesetLoadException(@"Instantiation failure"); + if (!checkRulesetUpToDate(instance)) + { + throw new ArgumentOutOfRangeException(nameof(instance.RulesetAPIVersionSupported), + $"Ruleset API version is too old (was {instance.RulesetAPIVersionSupported}, expected {Ruleset.CURRENT_RULESET_API_VERSION})"); + } + // If a ruleset isn't up-to-date with the API, it could cause a crash at an arbitrary point of execution. // To eagerly handle cases of missing implementations, enumerate all types here and mark as non-available on throw. resolvedType.Assembly.GetTypes(); @@ -104,6 +111,25 @@ namespace osu.Game.Rulesets }); } + private bool checkRulesetUpToDate(Ruleset instance) + { + switch (instance.RulesetAPIVersionSupported) + { + // The default `virtual` implementation leaves the version string empty. + // Consider rulesets which haven't override the version as up-to-date for now. + // At some point (once ruleset devs add versioning), we'll probably want to disallow this for deployed builds. + case @"": + // Rulesets which are bundled with the game. Saves having to update their versions each bump. + case @"internal": + // Ruleset is up-to-date, all good. + case Ruleset.CURRENT_RULESET_API_VERSION: + return true; + + default: + return false; + } + } + private void testRulesetCompatibility(RulesetInfo rulesetInfo) { // do various operations to ensure that we are in a good state. From c2036d3893a0c556742e88a42fd6363fe0ecb766 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Mon, 22 Aug 2022 03:39:46 -0400 Subject: [PATCH 0611/2686] Moved filter exclusion --- .../Screens/Select/Carousel/CarouselBeatmap.cs | 3 --- .../Screens/Select/Carousel/CarouselBeatmapSet.cs | 14 +++++++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs index f1f7c47e1b..03490ff37b 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs @@ -55,9 +55,6 @@ namespace osu.Game.Screens.Select.Carousel match &= !criteria.Artist.HasFilter || criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) || criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode); - match &= criteria.Sort != SortMode.DateRanked || BeatmapInfo.BeatmapSet?.DateRanked != null; - match &= criteria.Sort != SortMode.DateSubmitted || BeatmapInfo.BeatmapSet?.DateSubmitted != null; - match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating); if (match && criteria.SearchTerms.Length > 0) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 8298c73fe9..1c82bdedcf 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -129,7 +129,19 @@ namespace osu.Game.Screens.Select.Carousel public override void Filter(FilterCriteria criteria) { base.Filter(criteria); - Filtered.Value = Items.All(i => i.Filtered.Value); + bool match = Items.All(i => i.Filtered.Value); + + if (BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true) + { + // only check ruleset equality or convertability for selected beatmap + Filtered.Value = !match; + return; + } + + match &= criteria.Sort != SortMode.DateRanked || BeatmapSet?.DateRanked != null; + match &= criteria.Sort != SortMode.DateSubmitted || BeatmapSet?.DateSubmitted != null; + + Filtered.Value = match; } public override string ToString() => BeatmapSet.ToString(); From c86a75aa5fb125b79da55b7efcf77fbdb831175f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 17:03:20 +0900 Subject: [PATCH 0612/2686] Update `OsuConfigManager` in line with `ConfigManager` logging changes --- osu.Game/Configuration/OsuConfigManager.cs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index fb585e9cbd..5f49557685 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -4,10 +4,8 @@ #nullable disable using System; -using System.Collections.Generic; using System.Diagnostics; using System.Globalization; -using System.Linq; using osu.Framework.Configuration; using osu.Framework.Configuration.Tracking; using osu.Framework.Extensions; @@ -31,6 +29,12 @@ namespace osu.Game.Configuration [ExcludeFromDynamicCompile] public class OsuConfigManager : IniConfigManager { + public OsuConfigManager(Storage storage) + : base(storage) + { + Migrate(); + } + protected override void InitialiseDefaults() { // UI/selection defaults @@ -172,12 +176,9 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.LastProcessedMetadataId, -1); } - public IDictionary GetLoggableState() => - new Dictionary(ConfigStore.Where(kvp => !keyContainsPrivateInformation(kvp.Key)).ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToString())); - - private static bool keyContainsPrivateInformation(OsuSetting argKey) + protected override bool CheckLookupContainsPrivateInformation(OsuSetting lookup) { - switch (argKey) + switch (lookup) { case OsuSetting.Token: return true; @@ -186,12 +187,6 @@ namespace osu.Game.Configuration return false; } - public OsuConfigManager(Storage storage) - : base(storage) - { - Migrate(); - } - public void Migrate() { // arrives as 2020.123.0 From 22072ee16a9a5fd9bfe9acd7f8567f79f9f98088 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 17:03:30 +0900 Subject: [PATCH 0613/2686] Include framework configuration in sentry output --- osu.Game/Utils/SentryLogger.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Utils/SentryLogger.cs b/osu.Game/Utils/SentryLogger.cs index 33dc548e9a..8c39a2d15a 100644 --- a/osu.Game/Utils/SentryLogger.cs +++ b/osu.Game/Utils/SentryLogger.cs @@ -9,6 +9,7 @@ using System.Net; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Configuration; using osu.Framework.Logging; using osu.Framework.Statistics; using osu.Game.Beatmaps; @@ -112,8 +113,8 @@ namespace osu.Game.Utils scope.Contexts[@"config"] = new { - Game = game.Dependencies.Get().GetLoggableState() - // TODO: add framework config here. needs some consideration on how to expose. + Game = game.Dependencies.Get().GetCurrentConfigurationForLogging(), + Framework = game.Dependencies.Get().GetCurrentConfigurationForLogging(), }; game.Dependencies.Get().Run(realm => From b5970495242d9555fad30c52a33b1e66f3f3a4e9 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Mon, 22 Aug 2022 10:47:37 +0200 Subject: [PATCH 0614/2686] Code cleanup for CPS tests - Remove null-forgiving operator usages - Fix code quality issues mentionned by NVika --- .../Gameplay/TestSceneClicksPerSecond.cs | 48 +++++++++---------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs index 375726dd9a..137ab7acdb 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs @@ -27,11 +27,11 @@ namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneClicksPerSecond : OsuTestScene { - private DependencyProvidingContainer? dependencyContainer; - private ClicksPerSecondCalculator? calculator; + private DependencyProvidingContainer dependencyContainer = null!; + private ClicksPerSecondCalculator calculator = null!; private ManualInputListener? listener; - private GameplayClockContainer? gameplayClockContainer; - private ManualClock? manualClock; + private GameplayClockContainer gameplayClockContainer = null!; + private ManualClock manualClock = null!; private DrawableRuleset? drawableRuleset; private IFrameStableClock? frameStableClock; @@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.Gameplay seek(i * 10000); advanceForwards(2); int kps = i + 1; - AddAssert($"{kps} KPS", () => calculator!.Value == kps); + AddAssert($"{kps} KPS", () => calculator.Value == kps); } } @@ -95,14 +95,14 @@ namespace osu.Game.Tests.Visual.Gameplay { changeRate(i); double rate = i; - AddAssert($"KPS approx. = {i}", () => MathHelper.ApproximatelyEquivalent(calculator!.Value, 10 * rate, 0.5)); + AddAssert($"KPS approx. = {i}", () => MathHelper.ApproximatelyEquivalent(calculator.Value, 10 * rate, 0.5)); } for (double i = 1; i >= 0.5; i -= 0.25) { changeRate(i); double rate = i; - AddAssert($"KPS approx. = {i}", () => MathHelper.ApproximatelyEquivalent(calculator!.Value, 10 * rate, 0.5)); + AddAssert($"KPS approx. = {i}", () => MathHelper.ApproximatelyEquivalent(calculator.Value, 10 * rate, 0.5)); } } @@ -115,17 +115,17 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("Create consistent KPS inputs", () => addInputs(generateConsistentKps(10))); seek(1000); - AddAssert("KPS = 10", () => calculator!.Value == 10); + AddAssert("KPS = 10", () => calculator.Value == 10); AddStep("Create delayed inputs", () => addInputs(generateConsistentKps(10, 50))); seek(1000); - AddAssert("KPS didn't changed", () => calculator!.Value == 10); + AddAssert("KPS didn't changed", () => calculator.Value == 10); } private void seekAllClocks(double time) { - gameplayClockContainer?.Seek(time); - manualClock!.CurrentTime = time; + gameplayClockContainer.Seek(time); + manualClock.CurrentTime = time; } protected override Ruleset CreateRuleset() => new OsuRuleset(); @@ -136,8 +136,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("create calculator", () => { - Debug.Assert(dependencyContainer?.Dependencies.Get(typeof(DrawableRuleset)) is DrawableRuleset); - dependencyContainer!.Children = new Drawable[] + dependencyContainer.Children = new Drawable[] { calculator = new ClicksPerSecondCalculator(), new DependencyProvidingContainer @@ -152,18 +151,18 @@ namespace osu.Game.Tests.Visual.Gameplay } } }; - calculator!.Listener = listener = new ManualInputListener(calculator!); + calculator.Listener = listener = new ManualInputListener(calculator); }); } private void seek(double time) => AddStep($"Seek clocks to {time}ms", () => seekAllClocks(time)); - private void changeRate(double rate) => AddStep($"Change rate to x{rate}", () => manualClock!.Rate = rate); + private void changeRate(double rate) => AddStep($"Change rate to x{rate}", () => manualClock.Rate = rate); private void advanceForwards(double time) => AddStep($"Advance clocks {time} seconds forward.", () => { - gameplayClockContainer!.Seek(gameplayClockContainer.CurrentTime + time * manualClock!.Rate); + gameplayClockContainer.Seek(gameplayClockContainer.CurrentTime + time * manualClock.Rate); for (int i = 0; i < time; i++) { @@ -173,8 +172,8 @@ namespace osu.Game.Tests.Visual.Gameplay private void startClock() => AddStep("Start clocks", () => { - gameplayClockContainer?.Start(); - manualClock!.Rate = 1; + gameplayClockContainer.Start(); + manualClock.Rate = 1; }); #endregion @@ -183,7 +182,6 @@ namespace osu.Game.Tests.Visual.Gameplay private void addInputs(IEnumerable inputs) { - Debug.Assert(manualClock != null && listener != null && gameplayClockContainer != null); if (!inputs.Any()) return; double baseTime = gameplayClockContainer.CurrentTime; @@ -191,7 +189,7 @@ namespace osu.Game.Tests.Visual.Gameplay foreach (double timestamp in inputs) { seekAllClocks(timestamp); - listener.AddInput(); + listener?.AddInput(); } seekAllClocks(baseTime); @@ -199,7 +197,7 @@ namespace osu.Game.Tests.Visual.Gameplay private IEnumerable generateGraduallyIncreasingKps() { - IEnumerable? final = null; + IEnumerable final = null!; for (int i = 1; i <= 10; i++) { @@ -211,10 +209,10 @@ namespace osu.Game.Tests.Visual.Gameplay continue; } - final = final!.Concat(currentKps); + final = final.Concat(currentKps); } - return final!; + return final; } private IEnumerable generateConsistentKps(double kps, double start = 0, double duration = 10) @@ -236,7 +234,6 @@ namespace osu.Game.Tests.Visual.Gameplay public TestFrameStableClock(IClock source, double startTime = 0) { this.source = source; - StartTime = startTime; if (source is ManualClock manualClock) { @@ -248,7 +245,7 @@ namespace osu.Game.Tests.Visual.Gameplay public double Rate => source.Rate; public bool IsRunning => source.IsRunning; - private IClock source; + private readonly IClock source; public void ProcessFrame() { @@ -268,7 +265,6 @@ namespace osu.Game.Tests.Visual.Gameplay public double FramesPerSecond => 1 / ElapsedFrameTime * 1000; public FrameTimeInfo TimeInfo { get; private set; } - public double? StartTime { get; } public IEnumerable NonGameplayAdjustments => Enumerable.Empty(); public IBindable IsCatchingUp => new Bindable(); public IBindable WaitingOnFrames => new Bindable(); From 3acbcac4d1a215bb0e17ebb36c3f93309d018cb0 Mon Sep 17 00:00:00 2001 From: Jay L Date: Mon, 22 Aug 2022 19:45:51 +1000 Subject: [PATCH 0615/2686] fix NaN PP on 0 object count --- .../Difficulty/TaikoPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 7b0aa47ba5..6b1ea58129 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000. - effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; + effectiveMissCount = Math.Max(1.0, Math.Min(0, 1000.0 / totalSuccessfulHits)) * countMiss; double multiplier = 1.13; From 5d3d8681d498aaaa5990d7955f30b570e2fc3215 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 Aug 2022 19:14:06 +0900 Subject: [PATCH 0616/2686] Invert creation of clocks in multi spectator --- .../OnlinePlay/TestSceneCatchUpSyncManager.cs | 85 +++++++------------ .../Spectate/CatchUpSyncManager.cs | 14 +-- .../Multiplayer/Spectate/ISyncManager.cs | 12 +-- .../Spectate/MultiSpectatorScreen.cs | 7 +- .../Multiplayer/Spectate/PlayerArea.cs | 8 +- 5 files changed, 50 insertions(+), 76 deletions(-) diff --git a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs index 6c639ee539..88c4850fa7 100644 --- a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs +++ b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs @@ -4,11 +4,13 @@ #nullable disable using System; +using System.Collections.Generic; using NUnit.Framework; -using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate; +using osu.Game.Screens.Play; using osu.Game.Tests.Visual; namespace osu.Game.Tests.OnlinePlay @@ -16,20 +18,34 @@ namespace osu.Game.Tests.OnlinePlay [HeadlessTest] public class TestSceneCatchUpSyncManager : OsuTestScene { - private TestManualClock master; + private GameplayClockContainer master; private CatchUpSyncManager syncManager; - private TestSpectatorPlayerClock player1; - private TestSpectatorPlayerClock player2; + private Dictionary clocksById; + private ISpectatorPlayerClock player1; + private ISpectatorPlayerClock player2; [SetUp] public void Setup() { - syncManager = new CatchUpSyncManager(master = new TestManualClock()); - syncManager.AddPlayerClock(player1 = new TestSpectatorPlayerClock(1)); - syncManager.AddPlayerClock(player2 = new TestSpectatorPlayerClock(2)); + syncManager = new CatchUpSyncManager(master = new GameplayClockContainer(new TestManualClock())); + player1 = syncManager.AddClock(); + player2 = syncManager.AddClock(); - Schedule(() => Child = syncManager); + clocksById = new Dictionary + { + { player1, 1 }, + { player2, 2 } + }; + + Schedule(() => + { + Children = new Drawable[] + { + syncManager, + master + }; + }); } [Test] @@ -129,8 +145,8 @@ namespace osu.Game.Tests.OnlinePlay assertPlayerClockState(() => player1, false); } - private void setWaiting(Func playerClock, bool waiting) - => AddStep($"set player clock {playerClock().Id} waiting = {waiting}", () => playerClock().WaitingOnFrames.Value = waiting); + private void setWaiting(Func playerClock, bool waiting) + => AddStep($"set player clock {clocksById[playerClock()]} waiting = {waiting}", () => playerClock().WaitingOnFrames.Value = waiting); private void setAllWaiting(bool waiting) => AddStep($"set all player clocks waiting = {waiting}", () => { @@ -144,51 +160,14 @@ namespace osu.Game.Tests.OnlinePlay /// /// clock.Time = master.Time - offsetFromMaster /// - private void setPlayerClockTime(Func playerClock, double offsetFromMaster) - => AddStep($"set player clock {playerClock().Id} = master - {offsetFromMaster}", () => playerClock().Seek(master.CurrentTime - offsetFromMaster)); + private void setPlayerClockTime(Func playerClock, double offsetFromMaster) + => AddStep($"set player clock {clocksById[playerClock()]} = master - {offsetFromMaster}", () => playerClock().Seek(master.CurrentTime - offsetFromMaster)); - private void assertCatchingUp(Func playerClock, bool catchingUp) => - AddAssert($"player clock {playerClock().Id} {(catchingUp ? "is" : "is not")} catching up", () => playerClock().IsCatchingUp == catchingUp); + private void assertCatchingUp(Func playerClock, bool catchingUp) => + AddAssert($"player clock {clocksById[playerClock()]} {(catchingUp ? "is" : "is not")} catching up", () => playerClock().IsCatchingUp == catchingUp); - private void assertPlayerClockState(Func playerClock, bool running) - => AddAssert($"player clock {playerClock().Id} {(running ? "is" : "is not")} running", () => playerClock().IsRunning == running); - - private class TestSpectatorPlayerClock : TestManualClock, ISpectatorPlayerClock - { - public Bindable WaitingOnFrames { get; } = new Bindable(true); - - public bool IsCatchingUp { get; set; } - - public IFrameBasedClock Source - { - set => throw new NotImplementedException(); - } - - public readonly int Id; - - public TestSpectatorPlayerClock(int id) - { - Id = id; - - WaitingOnFrames.BindValueChanged(waiting => - { - if (waiting.NewValue) - Stop(); - else - Start(); - }); - } - - public void ProcessFrame() - { - } - - public double ElapsedFrameTime => 0; - - public double FramesPerSecond => 0; - - public FrameTimeInfo TimeInfo => default; - } + private void assertPlayerClockState(Func playerClock, bool running) + => AddAssert($"player clock {clocksById[playerClock()]} {(running ? "is" : "is not")} running", () => playerClock().IsRunning == running); private class TestManualClock : ManualClock, IAdjustableClock { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs index 663025923c..b0ebe23292 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs @@ -5,11 +5,10 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Timing; +using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { @@ -38,7 +37,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The master clock which is used to control the timing of all player clocks clocks. /// - public IAdjustableClock MasterClock { get; } + public GameplayClockContainer MasterClock { get; } public IBindable MasterState => masterState; @@ -52,18 +51,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private bool hasStarted; private double? firstStartAttemptTime; - public CatchUpSyncManager(IAdjustableClock master) + public CatchUpSyncManager(GameplayClockContainer master) { MasterClock = master; } - public void AddPlayerClock(ISpectatorPlayerClock clock) + public ISpectatorPlayerClock AddClock() { - Debug.Assert(!playerClocks.Contains(clock)); + var clock = new CatchUpSpectatorPlayerClock { Source = MasterClock }; playerClocks.Add(clock); + return clock; } - public void RemovePlayerClock(ISpectatorPlayerClock clock) + public void RemoveClock(ISpectatorPlayerClock clock) { playerClocks.Remove(clock); clock.Stop(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs index 577100d4ba..49707ed975 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs @@ -5,7 +5,7 @@ using System; using osu.Framework.Bindables; -using osu.Framework.Timing; +using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { @@ -22,7 +22,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The master clock which player clocks should synchronise to. /// - IAdjustableClock MasterClock { get; } + GameplayClockContainer MasterClock { get; } /// /// An event which is invoked when the state of is changed. @@ -30,15 +30,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate IBindable MasterState { get; } /// - /// Adds an to manage. + /// Adds a new managed . /// - /// The to add. - void AddPlayerClock(ISpectatorPlayerClock clock); + /// The added . + ISpectatorPlayerClock AddClock(); /// /// Removes an , stopping it from being managed by this . /// /// The to remove. - void RemovePlayerClock(ISpectatorPlayerClock clock); + void RemoveClock(ISpectatorPlayerClock clock); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 7ed0be50e5..96f08ef446 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -125,10 +125,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate }; for (int i = 0; i < Users.Count; i++) - { - grid.Add(instances[i] = new PlayerArea(Users[i], masterClockContainer)); - syncManager.AddPlayerClock(instances[i].GameplayClock); - } + grid.Add(instances[i] = new PlayerArea(Users[i], syncManager.AddClock())); LoadComponentAsync(leaderboard = new MultiSpectatorLeaderboard(users) { @@ -242,7 +239,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate var instance = instances.Single(i => i.UserId == userId); instance.FadeColour(colours.Gray4, 400, Easing.OutQuint); - syncManager.RemovePlayerClock(instance.GameplayClock); + syncManager.RemoveClock(instance.GameplayClock); } public override bool OnBackButton() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index 302d04b531..a013a9e41d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -11,7 +11,6 @@ using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; @@ -45,7 +44,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// The used to control the gameplay running state of a loaded . /// [NotNull] - public readonly ISpectatorPlayerClock GameplayClock = new CatchUpSpectatorPlayerClock(); + public readonly ISpectatorPlayerClock GameplayClock; /// /// The currently-loaded score. @@ -58,9 +57,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly LoadingLayer loadingLayer; private OsuScreenStack stack; - public PlayerArea(int userId, IFrameBasedClock masterClock) + public PlayerArea(int userId, [NotNull] ISpectatorPlayerClock clock) { UserId = userId; + GameplayClock = clock; RelativeSizeAxes = Axes.Both; Masking = true; @@ -77,8 +77,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate }; audioContainer.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment); - - GameplayClock.Source = masterClock; } [Resolved] From 489e172a7660c07030eb38799f9e23681cecf813 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 22 Aug 2022 19:43:18 +0900 Subject: [PATCH 0617/2686] Simplify track start/stop/paused tracking --- .../Screens/Play/GameplayClockContainer.cs | 79 ++++++++++--------- .../Play/MasterGameplayClockContainer.cs | 39 +++++---- 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index a00ae27781..897d2cbdcd 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -74,39 +74,41 @@ namespace osu.Game.Screens.Play GameplayClock = new FramedBeatmapClock(sourceClock, applyOffsets) { IsCoupled = false }, Content }; - - IsPaused.BindValueChanged(OnIsPausedChanged); } /// /// Starts gameplay and marks un-paused state. /// - public virtual void Start() + public void Start() { - ensureSourceClockSet(); + if (!isPaused.Value) + return; isPaused.Value = false; - // the clock may be stopped via internal means (ie. not via `IsPaused`). - // see Reset() calling `GameplayClock.Stop()` as one example. - if (!GameplayClock.IsRunning) - { - // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time - // This accounts for the clock source potentially taking time to enter a completely stopped state - Seek(GameplayClock.CurrentTime); + ensureSourceClockSet(); - // The case which cause this to be added is FrameStabilityContainer, which manages its own current and elapsed time. - // Because we generally update our own current time quicker than children can query it (via Start/Seek/Update), - // this means that the first frame ever exposed to children may have a non-zero current time. - // - // If the child component is not aware of the parent ElapsedFrameTime (which is the case for FrameStabilityContainer) - // they will take on the new CurrentTime with a zero elapsed time. This can in turn cause components to behave incorrectly - // if they are intending to trigger events at the precise StartTime (ie. DrawableStoryboardSample). - // - // By scheduling the start call, children are guaranteed to receive one frame at the original start time, allowing - // then to progress with a correct locally calculated elapsed time. - SchedulerAfterChildren.Add(GameplayClock.Start); - } + // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time + // This accounts for the clock source potentially taking time to enter a completely stopped state + Seek(GameplayClock.CurrentTime); + + // The case which cause this to be added is FrameStabilityContainer, which manages its own current and elapsed time. + // Because we generally update our own current time quicker than children can query it (via Start/Seek/Update), + // this means that the first frame ever exposed to children may have a non-zero current time. + // + // If the child component is not aware of the parent ElapsedFrameTime (which is the case for FrameStabilityContainer) + // they will take on the new CurrentTime with a zero elapsed time. This can in turn cause components to behave incorrectly + // if they are intending to trigger events at the precise StartTime (ie. DrawableStoryboardSample). + // + // By scheduling the start call, children are guaranteed to receive one frame at the original start time, allowing + // then to progress with a correct locally calculated elapsed time. + SchedulerAfterChildren.Add(() => + { + if (isPaused.Value) + return; + + StartGameplayClock(); + }); } /// @@ -125,7 +127,17 @@ namespace osu.Game.Screens.Play /// /// Stops gameplay and marks paused state. /// - public void Stop() => isPaused.Value = true; + public void Stop() + { + if (isPaused.Value) + return; + + isPaused.Value = true; + StopGameplayClock(); + } + + protected virtual void StartGameplayClock() => GameplayClock.Start(); + protected virtual void StopGameplayClock() => GameplayClock.Stop(); /// /// Resets this and the source to an initial state ready for gameplay. @@ -134,8 +146,9 @@ namespace osu.Game.Screens.Play /// Whether to start the clock immediately, if not already started. public void Reset(double? time = null, bool startClock = false) { - // Manually stop the source in order to not affect the IsPaused state. - GameplayClock.Stop(); + bool wasPaused = isPaused.Value; + + Stop(); ensureSourceClockSet(); @@ -144,7 +157,7 @@ namespace osu.Game.Screens.Play Seek(StartTime); - if (!IsPaused.Value || startClock) + if (!wasPaused || startClock) Start(); } @@ -167,18 +180,6 @@ namespace osu.Game.Screens.Play ChangeSource(SourceClock); } - /// - /// Invoked when the value of is changed to start or stop the clock. - /// - /// Whether the clock should now be paused. - protected virtual void OnIsPausedChanged(ValueChangedEvent isPaused) - { - if (isPaused.NewValue) - GameplayClock.Stop(); - else - GameplayClock.Start(); - } - #region IAdjustableClock bool IAdjustableClock.Seek(double position) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index c3c92eb0fe..168a5658f5 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -84,29 +84,23 @@ namespace osu.Game.Screens.Play return time; } - protected override void OnIsPausedChanged(ValueChangedEvent isPaused) + protected override void StopGameplayClock() { if (IsLoaded) { // During normal operation, the source is stopped after performing a frequency ramp. - if (isPaused.NewValue) + this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 0, 200, Easing.Out).OnComplete(_ => { - this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 0, 200, Easing.Out).OnComplete(_ => - { - if (IsPaused.Value == isPaused.NewValue) - base.OnIsPausedChanged(isPaused); - }); - } - else - this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 1, 200, Easing.In); + if (IsPaused.Value) + base.StopGameplayClock(); + }); } else { - if (isPaused.NewValue) - base.OnIsPausedChanged(isPaused); + base.StopGameplayClock(); // If not yet loaded, we still want to ensure relevant state is correct, as it is used for offset calculations. - GameplayClock.ExternalPauseFrequencyAdjust.Value = isPaused.NewValue ? 0 : 1; + GameplayClock.ExternalPauseFrequencyAdjust.Value = 0; // We must also process underlying gameplay clocks to update rate-adjusted offsets with the new frequency adjustment. // Without doing this, an initial seek may be performed with the wrong offset. @@ -114,10 +108,25 @@ namespace osu.Game.Screens.Play } } - public override void Start() + protected override void StartGameplayClock() { addSourceClockAdjustments(); - base.Start(); + + base.StartGameplayClock(); + + if (IsLoaded) + { + this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 1, 200, Easing.In); + } + else + { + // If not yet loaded, we still want to ensure relevant state is correct, as it is used for offset calculations. + GameplayClock.ExternalPauseFrequencyAdjust.Value = 1; + + // We must also process underlying gameplay clocks to update rate-adjusted offsets with the new frequency adjustment. + // Without doing this, an initial seek may be performed with the wrong offset. + GameplayClock.ProcessFrame(); + } } /// From c59298f0ce6f310300306bda1f7d3655c29d8c76 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 Aug 2022 21:52:43 +0900 Subject: [PATCH 0618/2686] Enable NRT --- .../Spectate/CatchUpSpectatorPlayerClock.cs | 13 +++++------ .../Spectate/CatchUpSyncManager.cs | 6 ++--- .../Spectate/ISpectatorPlayerClock.cs | 2 -- .../Multiplayer/Spectate/ISyncManager.cs | 4 +--- .../Spectate/MultiSpectatorScreen.cs | 22 +++++++++---------- .../Multiplayer/Spectate/PlayerArea.cs | 21 +++++++----------- 6 files changed, 27 insertions(+), 41 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs index 34388bf9b1..93e1ea3c24 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs @@ -17,15 +17,17 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public const double CATCHUP_RATE = 2; - /// - /// The source clock. - /// - public IFrameBasedClock? Source { get; set; } + public IFrameBasedClock Source { get; set; } public double CurrentTime { get; private set; } public bool IsRunning { get; private set; } + public CatchUpSpectatorPlayerClock(IFrameBasedClock source) + { + Source = source; + } + public void Reset() => CurrentTime = 0; public void Start() => IsRunning = true; @@ -67,9 +69,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate ElapsedFrameTime = 0; FramesPerSecond = 0; - if (Source == null) - return; - Source.ProcessFrame(); if (IsRunning) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs index b0ebe23292..ede2600671 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -32,7 +30,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public const double MAXIMUM_START_DELAY = 15000; - public event Action ReadyToStart; + public event Action? ReadyToStart; /// /// The master clock which is used to control the timing of all player clocks clocks. @@ -58,7 +56,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public ISpectatorPlayerClock AddClock() { - var clock = new CatchUpSpectatorPlayerClock { Source = MasterClock }; + var clock = new CatchUpSpectatorPlayerClock(MasterClock); playerClocks.Add(clock); return clock; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs index 194a3bdcc2..b2ecb105c2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.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. -#nullable disable - using osu.Framework.Bindables; using osu.Framework.Timing; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs index 49707ed975..9281e4c1cf 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.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. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Game.Screens.Play; @@ -17,7 +15,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// An event which is invoked when gameplay is ready to start. /// - event Action ReadyToStart; + event Action? ReadyToStart; /// /// The master clock which player clocks should synchronise to. diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 96f08ef446..5a24d74955 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -1,13 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; @@ -42,17 +40,17 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate protected override UserActivity InitialActivity => new UserActivity.SpectatingMultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; [Resolved] - private MultiplayerClient multiplayerClient { get; set; } + private MultiplayerClient multiplayerClient { get; set; } = null!; private readonly PlayerArea[] instances; - private MasterGameplayClockContainer masterClockContainer; - private ISyncManager syncManager; - private PlayerGrid grid; - private MultiSpectatorLeaderboard leaderboard; - private PlayerArea currentAudioSource; + private MasterGameplayClockContainer masterClockContainer = null!; + private ISyncManager syncManager = null!; + private PlayerGrid grid = null!; + private MultiSpectatorLeaderboard leaderboard = null!; + private PlayerArea? currentAudioSource; private bool canStartMasterClock; private readonly Room room; @@ -178,7 +176,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } } - private bool isCandidateAudioSource([CanBeNull] ISpectatorPlayerClock clock) + private bool isCandidateAudioSource(ISpectatorPlayerClock? clock) => clock?.IsRunning == true && !clock.IsCatchingUp && !clock.WaitingOnFrames.Value; private void onReadyToStart() @@ -186,7 +184,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate // Seek the master clock to the gameplay time. // This is chosen as the first available frame in the players' replays, which matches the seek by each individual SpectatorPlayer. double startTime = instances.Where(i => i.Score != null) - .SelectMany(i => i.Score.Replay.Frames) + .SelectMany(i => i.Score.AsNonNull().Replay.Frames) .Select(f => f.Time) .DefaultIfEmpty(0) .Min(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index a013a9e41d..7e679383c4 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -1,11 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; @@ -28,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// Raised after is called on . /// - public event Action OnGameplayStarted; + public event Action? OnGameplayStarted; /// /// Whether a is loaded in the area. @@ -43,21 +40,22 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The used to control the gameplay running state of a loaded . /// - [NotNull] public readonly ISpectatorPlayerClock GameplayClock; /// /// The currently-loaded score. /// - [CanBeNull] - public Score Score { get; private set; } + public Score? Score { get; private set; } + + [Resolved] + private IBindable beatmap { get; set; } = null!; private readonly BindableDouble volumeAdjustment = new BindableDouble(); private readonly Container gameplayContent; private readonly LoadingLayer loadingLayer; - private OsuScreenStack stack; + private OsuScreenStack? stack; - public PlayerArea(int userId, [NotNull] ISpectatorPlayerClock clock) + public PlayerArea(int userId, ISpectatorPlayerClock clock) { UserId = userId; GameplayClock = clock; @@ -79,10 +77,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate audioContainer.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment); } - [Resolved] - private IBindable beatmap { get; set; } - - public void LoadScore([NotNull] Score score) + public void LoadScore(Score score) { if (Score != null) throw new InvalidOperationException($"Cannot load a new score on a {nameof(PlayerArea)} that has an existing score."); From 1098e24c40afef4ee684706d2050e0e9dae9bd61 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Mon, 22 Aug 2022 14:24:52 +0100 Subject: [PATCH 0619/2686] Improved UprightUnscaledContainer --- osu.Game/Extensions/DrawableExtensions.cs | 36 ---------- .../Graphics/Containers/GrowToFitContainer.cs | 21 ------ .../Containers/UprightUnscaledContainer.cs | 66 ++++++++++++++++++- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 33 +++------- 4 files changed, 73 insertions(+), 83 deletions(-) delete mode 100644 osu.Game/Graphics/Containers/GrowToFitContainer.cs diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index 320b9d7996..35f2d61437 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -8,7 +8,6 @@ using osu.Game.Configuration; using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; using osuTK; -using System; namespace osu.Game.Extensions { @@ -80,40 +79,5 @@ namespace osu.Game.Extensions container.Add(child.CreateInstance()); } } - - /// - /// Keeps the drawable upright and unstretched preventing it from being rotated, sheared, scaled or flipped with its Parent. - /// - /// The drawable. - public static void KeepUprightAndUnscaled(this Drawable drawable) - { - // Decomposes the inverse of the parent FrawInfo.Matrix into rotation, shear and scale. - var parentMatrix = drawable.Parent.DrawInfo.Matrix; - parentMatrix.Transpose(); - - // Remove Translation. - parentMatrix.M13 = 0.0f; - parentMatrix.M23 = 0.0f; - - Matrix3 C = parentMatrix.Inverted(); - - // Extract the rotation. - float angle = MathF.Atan2(C.M21, C.M11); - drawable.Rotation = MathHelper.RadiansToDegrees(angle); - - // Remove rotation from the C matrix so that it only contains shear and scale. - Matrix3 m = Matrix3.CreateRotationZ(-angle); - m.Transpose(); - C = m * C; - - // Extract shear and scale. - float alpha, sx, sy; - sx = C.M11; - sy = C.M22; - alpha = C.M12 / C.M22; - - drawable.Scale = new Vector2(sx, sy); - drawable.Shear = new Vector2(-alpha, 0); - } } } diff --git a/osu.Game/Graphics/Containers/GrowToFitContainer.cs b/osu.Game/Graphics/Containers/GrowToFitContainer.cs deleted file mode 100644 index 9b4ad0dba9..0000000000 --- a/osu.Game/Graphics/Containers/GrowToFitContainer.cs +++ /dev/null @@ -1,21 +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 osu.Framework.Graphics.Containers; - -namespace osu.Game.Graphics.Containers -{ - /// - /// A container that grows in size to fit its child and retains its size when its child shrinks - /// - public class GrowToFitContainer : Container - { - protected override void Update() - { - base.Update(); - Height = Math.Max(Child.Height, Height); - Width = Math.Max(Child.Width, Width); - } - } -} diff --git a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs index cdb839fdec..b6c3b56c4a 100644 --- a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs +++ b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs @@ -4,6 +4,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Layout; +using osuTK; +using System; namespace osu.Game.Graphics.Containers { @@ -12,21 +14,81 @@ namespace osu.Game.Graphics.Containers /// public class UprightUnscaledContainer : Container { + protected override Container Content => content; + private readonly Container content; + public UprightUnscaledContainer() { + InternalChild = content = new GrowToFitContainer(); AddLayout(layout); } - private LayoutValue layout = new LayoutValue(Invalidation.DrawInfo, InvalidationSource.Parent); + private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawInfo, InvalidationSource.Parent); protected override void Update() { base.Update(); + if (!layout.IsValid) { - Extensions.DrawableExtensions.KeepUprightAndUnscaled(this); + keepUprightAndUnscaled(); layout.Validate(); } } + + /// + /// Keeps the drawable upright and unstretched preventing it from being rotated, sheared, scaled or flipped with its Parent. + /// + private void keepUprightAndUnscaled() + { + // Decomposes the inverse of the parent FrawInfo.Matrix into rotation, shear and scale. + var parentMatrix = Parent.DrawInfo.Matrix; + + // Remove Translation. + parentMatrix.M31 = 0.0f; + parentMatrix.M32 = 0.0f; + + Matrix3 reversedParrent = parentMatrix.Inverted(); + + // Extract the rotation. + float angle = MathF.Atan2(reversedParrent.M12, reversedParrent.M11); + Rotation = MathHelper.RadiansToDegrees(angle); + + // Remove rotation from the C matrix so that it only contains shear and scale. + Matrix3 m = Matrix3.CreateRotationZ(-angle); + reversedParrent *= m; + + // Extract shear and scale. + float sx = reversedParrent.M11; + float sy = reversedParrent.M22; + float alpha = reversedParrent.M21 / reversedParrent.M22; + + Scale = new Vector2(sx, sy); + Shear = new Vector2(-alpha, 0); + } + + /// + /// A container that grows in size to fit its children and retains its size when its children shrink + /// + private class GrowToFitContainer : Container + { + protected override Container Content => content; + private readonly Container content; + + public GrowToFitContainer() + { + InternalChild = content = new Container + { + AutoSizeAxes = Axes.Both, + }; + } + + protected override void Update() + { + base.Update(); + Height = Math.Max(content.Height, Height); + Width = Math.Max(content.Width, Width); + } + } } } diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 069492fd80..c4cdc0cb29 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -60,17 +60,12 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, - Child = new GrowToFitContainer + Child = timeCurrent = new OsuSpriteText { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = timeCurrent = new OsuSpriteText - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Colour = colours.BlueLighter, - Font = OsuFont.Numeric, - } + Colour = colours.BlueLighter, + Font = OsuFont.Numeric, } } }, @@ -84,17 +79,12 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, - Child = new GrowToFitContainer + Child = progress = new OsuSpriteText { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = progress = new OsuSpriteText - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Colour = colours.BlueLighter, - Font = OsuFont.Numeric, - } + Colour = colours.BlueLighter, + Font = OsuFont.Numeric, } } }, @@ -108,17 +98,12 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, - Child = new GrowToFitContainer + Child = timeLeft = new OsuSpriteText { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = timeLeft = new OsuSpriteText - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Colour = colours.BlueLighter, - Font = OsuFont.Numeric, - } + Colour = colours.BlueLighter, + Font = OsuFont.Numeric, } } } From 55f1b43329612a62184cafdf500b1e4371214e64 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Mon, 22 Aug 2022 13:41:36 -0400 Subject: [PATCH 0620/2686] Removed check --- osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 1c82bdedcf..6c134a4ab8 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -131,13 +131,6 @@ namespace osu.Game.Screens.Select.Carousel base.Filter(criteria); bool match = Items.All(i => i.Filtered.Value); - if (BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true) - { - // only check ruleset equality or convertability for selected beatmap - Filtered.Value = !match; - return; - } - match &= criteria.Sort != SortMode.DateRanked || BeatmapSet?.DateRanked != null; match &= criteria.Sort != SortMode.DateSubmitted || BeatmapSet?.DateSubmitted != null; From e8d4bc4497c3fe3f7f2606db471a48fce87393cb Mon Sep 17 00:00:00 2001 From: Khang Date: Mon, 22 Aug 2022 21:04:26 -0400 Subject: [PATCH 0621/2686] Allow NaN during beatmap parsing if desired --- osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs | 7 ++++++- osu.Game/Beatmaps/Formats/Parsing.cs | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs b/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs index f3673b0e7f..339063633a 100644 --- a/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/ParsingTest.cs @@ -14,7 +14,12 @@ namespace osu.Game.Tests.Beatmaps.Formats public class ParsingTest { [Test] - public void TestNaNHandling() => allThrow("NaN"); + public void TestNaNHandling() + { + allThrow("NaN"); + Assert.That(Parsing.ParseFloat("NaN", allowNaN: true), Is.NaN); + Assert.That(Parsing.ParseDouble("NaN", allowNaN: true), Is.NaN); + } [Test] public void TestBadStringHandling() => allThrow("Random string 123"); diff --git a/osu.Game/Beatmaps/Formats/Parsing.cs b/osu.Game/Beatmaps/Formats/Parsing.cs index ce04f27020..9b0d200077 100644 --- a/osu.Game/Beatmaps/Formats/Parsing.cs +++ b/osu.Game/Beatmaps/Formats/Parsing.cs @@ -17,26 +17,26 @@ namespace osu.Game.Beatmaps.Formats public const double MAX_PARSE_VALUE = int.MaxValue; - public static float ParseFloat(string input, float parseLimit = (float)MAX_PARSE_VALUE) + public static float ParseFloat(string input, float parseLimit = (float)MAX_PARSE_VALUE, bool allowNaN = false) { float output = float.Parse(input, CultureInfo.InvariantCulture); if (output < -parseLimit) throw new OverflowException("Value is too low"); if (output > parseLimit) throw new OverflowException("Value is too high"); - if (float.IsNaN(output)) throw new FormatException("Not a number"); + if (!allowNaN && float.IsNaN(output)) throw new FormatException("Not a number"); return output; } - public static double ParseDouble(string input, double parseLimit = MAX_PARSE_VALUE) + public static double ParseDouble(string input, double parseLimit = MAX_PARSE_VALUE, bool allowNaN = false) { double output = double.Parse(input, CultureInfo.InvariantCulture); if (output < -parseLimit) throw new OverflowException("Value is too low"); if (output > parseLimit) throw new OverflowException("Value is too high"); - if (double.IsNaN(output)) throw new FormatException("Not a number"); + if (!allowNaN && double.IsNaN(output)) throw new FormatException("Not a number"); return output; } From 9f08c474caf57d8a84a510653c72a7f01ccf2b8d Mon Sep 17 00:00:00 2001 From: Khang Date: Mon, 22 Aug 2022 21:44:25 -0400 Subject: [PATCH 0622/2686] Treat NaN slider velocity timing points as 1.0x but without slider ticks --- .../Objects/JuiceStream.cs | 5 ++++- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 2 +- .../Mods/OsuModStrictTracking.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 8 ++++++- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 2 +- .../Beatmaps/SliderEventGenerationTest.cs | 17 ++++++++++----- .../ControlPoints/DifficultyControlPoint.cs | 15 ++++++++++--- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 8 ++++++- .../Rulesets/Objects/SliderEventGenerator.cs | 21 +++++++++++-------- 9 files changed, 57 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 311e15116e..a9c7d938d2 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -40,6 +40,9 @@ namespace osu.Game.Rulesets.Catch.Objects [JsonIgnore] public double TickDistance => tickDistanceFactor * DifficultyControlPoint.SliderVelocity; + [JsonIgnore] + public bool GenerateTicks => DifficultyControlPoint.GenerateTicks; + /// /// The length of one span of this . /// @@ -64,7 +67,7 @@ namespace osu.Game.Rulesets.Catch.Objects int nodeIndex = 0; SliderEventDescriptor? lastEvent = null; - foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken)) + foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, GenerateTicks, cancellationToken)) { // generate tiny droplets since the last point if (lastEvent != null) diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 22fab15c1b..4ec039c405 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -117,7 +117,7 @@ namespace osu.Game.Rulesets.Mania.Objects private void createTicks(CancellationToken cancellationToken) { - if (tickSpacing == 0) + if (tickSpacing == 0 || !DifficultyControlPoint.GenerateTicks) return; for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index 67b19124e1..eb59122686 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Mods protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { - var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken); + var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, GenerateTicks, cancellationToken); foreach (var e in sliderEvents) { diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index a5468ff613..31117c0836 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -142,6 +142,11 @@ namespace osu.Game.Rulesets.Osu.Objects /// public double TickDistanceMultiplier = 1; + /// + /// Whether this should generate s. + /// + public bool GenerateTicks { get; private set; } + /// /// Whether this 's judgement is fully handled by its nested s. /// If false, this will be judged proportionally to the number of nested s hit. @@ -170,13 +175,14 @@ namespace osu.Game.Rulesets.Osu.Objects Velocity = scoringDistance / timingPoint.BeatLength; TickDistance = scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier; + GenerateTicks = DifficultyControlPoint.GenerateTicks; } protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { base.CreateNestedHitObjects(cancellationToken); - var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken); + var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, GenerateTicks, cancellationToken); foreach (var e in sliderEvents) { diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index e1619e2857..09e465c37b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Taiko.Objects private void createTicks(CancellationToken cancellationToken) { - if (tickSpacing == 0) + if (tickSpacing == 0 || !DifficultyControlPoint.GenerateTicks) return; bool first = true; diff --git a/osu.Game.Tests/Beatmaps/SliderEventGenerationTest.cs b/osu.Game.Tests/Beatmaps/SliderEventGenerationTest.cs index d30ab3dea1..077398f015 100644 --- a/osu.Game.Tests/Beatmaps/SliderEventGenerationTest.cs +++ b/osu.Game.Tests/Beatmaps/SliderEventGenerationTest.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestSingleSpan() { - var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, null).ToArray(); + var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, null, true).ToArray(); Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head)); Assert.That(events[0].Time, Is.EqualTo(start_time)); @@ -33,7 +33,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestRepeat() { - var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 2, null).ToArray(); + var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 2, null, true).ToArray(); Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head)); Assert.That(events[0].Time, Is.EqualTo(start_time)); @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestNonEvenTicks() { - var events = SliderEventGenerator.Generate(start_time, span_duration, 1, 300, span_duration, 2, null).ToArray(); + var events = SliderEventGenerator.Generate(start_time, span_duration, 1, 300, span_duration, 2, null, true).ToArray(); Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head)); Assert.That(events[0].Time, Is.EqualTo(start_time)); @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestLegacyLastTickOffset() { - var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, 100).ToArray(); + var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, 100, true).ToArray(); Assert.That(events[2].Type, Is.EqualTo(SliderEventType.LegacyLastTick)); Assert.That(events[2].Time, Is.EqualTo(900)); @@ -99,7 +99,7 @@ namespace osu.Game.Tests.Beatmaps const double velocity = 5; const double min_distance = velocity * 10; - var events = SliderEventGenerator.Generate(start_time, span_duration, velocity, velocity, span_duration, 2, 0).ToArray(); + var events = SliderEventGenerator.Generate(start_time, span_duration, velocity, velocity, span_duration, 2, 0, true).ToArray(); Assert.Multiple(() => { @@ -114,5 +114,12 @@ namespace osu.Game.Tests.Beatmaps } }); } + + [Test] + public void TestNoTickGeneration() + { + var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, null, false).ToArray(); + Assert.That(events.Any(e => e.Type == SliderEventType.Tick), Is.False); + } } } diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs index c199d1da59..dfa3552469 100644 --- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs @@ -40,13 +40,21 @@ namespace osu.Game.Beatmaps.ControlPoints set => SliderVelocityBindable.Value = value; } + /// + /// Whether or not slider ticks should be generated at this control point. + /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). + /// + public bool GenerateTicks { get; set; } = true; + public override bool IsRedundant(ControlPoint? existing) => existing is DifficultyControlPoint existingDifficulty - && SliderVelocity == existingDifficulty.SliderVelocity; + && SliderVelocity == existingDifficulty.SliderVelocity + && GenerateTicks == existingDifficulty.GenerateTicks; public override void CopyFrom(ControlPoint other) { SliderVelocity = ((DifficultyControlPoint)other).SliderVelocity; + GenerateTicks = ((DifficultyControlPoint)other).GenerateTicks; base.CopyFrom(other); } @@ -57,8 +65,9 @@ namespace osu.Game.Beatmaps.ControlPoints public bool Equals(DifficultyControlPoint? other) => base.Equals(other) - && SliderVelocity == other.SliderVelocity; + && SliderVelocity == other.SliderVelocity + && GenerateTicks == other.GenerateTicks; - public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SliderVelocity); + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SliderVelocity, GenerateTicks); } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 89d3465ab6..3d3661745a 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -373,7 +373,9 @@ namespace osu.Game.Beatmaps.Formats string[] split = line.Split(','); double time = getOffsetTime(Parsing.ParseDouble(split[0].Trim())); - double beatLength = Parsing.ParseDouble(split[1].Trim()); + double beatLength = Parsing.ParseDouble(split[1].Trim(), allowNaN: true); + + // If beatLength is NaN, speedMultiplier should still be 1 because all comparisons against NaN are false. double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1; TimeSignature timeSignature = TimeSignature.SimpleQuadruple; @@ -412,6 +414,9 @@ namespace osu.Game.Beatmaps.Formats if (timingChange) { + if (double.IsNaN(beatLength)) + throw new InvalidDataException("Beat length cannot be NaN in a timing control point"); + var controlPoint = CreateTimingControlPoint(); controlPoint.BeatLength = beatLength; @@ -425,6 +430,7 @@ namespace osu.Game.Beatmaps.Formats #pragma warning restore 618 { SliderVelocity = speedMultiplier, + GenerateTicks = !double.IsNaN(beatLength), }, timingChange); var effectPoint = new EffectControlPoint diff --git a/osu.Game/Rulesets/Objects/SliderEventGenerator.cs b/osu.Game/Rulesets/Objects/SliderEventGenerator.cs index d32a7cb16d..b77d15d565 100644 --- a/osu.Game/Rulesets/Objects/SliderEventGenerator.cs +++ b/osu.Game/Rulesets/Objects/SliderEventGenerator.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Objects { // ReSharper disable once MethodOverloadWithOptionalParameter public static IEnumerable Generate(double startTime, double spanDuration, double velocity, double tickDistance, double totalDistance, int spanCount, - double? legacyLastTickOffset, CancellationToken cancellationToken = default) + double? legacyLastTickOffset, bool shouldGenerateTicks, CancellationToken cancellationToken = default) { // A very lenient maximum length of a slider for ticks to be generated. // This exists for edge cases such as /b/1573664 where the beatmap has been edited by the user, and should never be reached in normal usage. @@ -41,16 +41,19 @@ namespace osu.Game.Rulesets.Objects double spanStartTime = startTime + span * spanDuration; bool reversed = span % 2 == 1; - var ticks = generateTicks(span, spanStartTime, spanDuration, reversed, length, tickDistance, minDistanceFromEnd, cancellationToken); - - if (reversed) + if (shouldGenerateTicks) { - // For repeat spans, ticks are returned in reverse-StartTime order, which is undesirable for some rulesets - ticks = ticks.Reverse(); - } + var ticks = generateTicks(span, spanStartTime, spanDuration, reversed, length, tickDistance, minDistanceFromEnd, cancellationToken); - foreach (var e in ticks) - yield return e; + if (reversed) + { + // For repeat spans, ticks are returned in reverse-StartTime order, which is undesirable for some rulesets + ticks = ticks.Reverse(); + } + + foreach (var e in ticks) + yield return e; + } if (span < spanCount - 1) { From 8f708c1dcf30e7300b8f0c71ab48989a234f5cda Mon Sep 17 00:00:00 2001 From: Khang Date: Mon, 22 Aug 2022 22:43:44 -0400 Subject: [PATCH 0623/2686] Turn GenerateTicks into a bindable to pass code quality tests --- .../ControlPoints/DifficultyControlPoint.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs index dfa3552469..ca49d316e0 100644 --- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs @@ -16,6 +16,7 @@ namespace osu.Game.Beatmaps.ControlPoints public static readonly DifficultyControlPoint DEFAULT = new DifficultyControlPoint { SliderVelocityBindable = { Disabled = true }, + GenerateTicksBindable = { Disabled = true }, }; /// @@ -29,6 +30,12 @@ namespace osu.Game.Beatmaps.ControlPoints MaxValue = 10 }; + /// + /// Whether or not slider ticks should be generated at this control point. + /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). + /// + public readonly BindableBool GenerateTicksBindable = new BindableBool(true); + public override Color4 GetRepresentingColour(OsuColour colours) => colours.Lime1; /// @@ -44,7 +51,11 @@ namespace osu.Game.Beatmaps.ControlPoints /// Whether or not slider ticks should be generated at this control point. /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). /// - public bool GenerateTicks { get; set; } = true; + public bool GenerateTicks + { + get => GenerateTicksBindable.Value; + set => GenerateTicksBindable.Value = value; + } public override bool IsRedundant(ControlPoint? existing) => existing is DifficultyControlPoint existingDifficulty From a81672f3dc9e885651f78852675fadb76940ace2 Mon Sep 17 00:00:00 2001 From: Khang Date: Mon, 22 Aug 2022 23:31:24 -0400 Subject: [PATCH 0624/2686] Use an infinite tick distance instead of directly disabling tick generation for SliderEventGenerator --- .../Objects/JuiceStream.cs | 5 +---- .../Mods/OsuModStrictTracking.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 10 ++------- .../Beatmaps/SliderEventGenerationTest.cs | 17 +++++---------- .../Rulesets/Objects/SliderEventGenerator.cs | 21 ++++++++----------- 5 files changed, 18 insertions(+), 37 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index a9c7d938d2..311e15116e 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -40,9 +40,6 @@ namespace osu.Game.Rulesets.Catch.Objects [JsonIgnore] public double TickDistance => tickDistanceFactor * DifficultyControlPoint.SliderVelocity; - [JsonIgnore] - public bool GenerateTicks => DifficultyControlPoint.GenerateTicks; - /// /// The length of one span of this . /// @@ -67,7 +64,7 @@ namespace osu.Game.Rulesets.Catch.Objects int nodeIndex = 0; SliderEventDescriptor? lastEvent = null; - foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, GenerateTicks, cancellationToken)) + foreach (var e in SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken)) { // generate tiny droplets since the last point if (lastEvent != null) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index eb59122686..67b19124e1 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Mods protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { - var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, GenerateTicks, cancellationToken); + var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken); foreach (var e in sliderEvents) { diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 31117c0836..0689c49085 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -142,11 +142,6 @@ namespace osu.Game.Rulesets.Osu.Objects /// public double TickDistanceMultiplier = 1; - /// - /// Whether this should generate s. - /// - public bool GenerateTicks { get; private set; } - /// /// Whether this 's judgement is fully handled by its nested s. /// If false, this will be judged proportionally to the number of nested s hit. @@ -174,15 +169,14 @@ namespace osu.Game.Rulesets.Osu.Objects double scoringDistance = BASE_SCORING_DISTANCE * difficulty.SliderMultiplier * DifficultyControlPoint.SliderVelocity; Velocity = scoringDistance / timingPoint.BeatLength; - TickDistance = scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier; - GenerateTicks = DifficultyControlPoint.GenerateTicks; + TickDistance = DifficultyControlPoint.GenerateTicks ? (scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier) : double.PositiveInfinity; } protected override void CreateNestedHitObjects(CancellationToken cancellationToken) { base.CreateNestedHitObjects(cancellationToken); - var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, GenerateTicks, cancellationToken); + var sliderEvents = SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset, cancellationToken); foreach (var e in sliderEvents) { diff --git a/osu.Game.Tests/Beatmaps/SliderEventGenerationTest.cs b/osu.Game.Tests/Beatmaps/SliderEventGenerationTest.cs index 077398f015..d30ab3dea1 100644 --- a/osu.Game.Tests/Beatmaps/SliderEventGenerationTest.cs +++ b/osu.Game.Tests/Beatmaps/SliderEventGenerationTest.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestSingleSpan() { - var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, null, true).ToArray(); + var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, null).ToArray(); Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head)); Assert.That(events[0].Time, Is.EqualTo(start_time)); @@ -33,7 +33,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestRepeat() { - var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 2, null, true).ToArray(); + var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 2, null).ToArray(); Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head)); Assert.That(events[0].Time, Is.EqualTo(start_time)); @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestNonEvenTicks() { - var events = SliderEventGenerator.Generate(start_time, span_duration, 1, 300, span_duration, 2, null, true).ToArray(); + var events = SliderEventGenerator.Generate(start_time, span_duration, 1, 300, span_duration, 2, null).ToArray(); Assert.That(events[0].Type, Is.EqualTo(SliderEventType.Head)); Assert.That(events[0].Time, Is.EqualTo(start_time)); @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Beatmaps [Test] public void TestLegacyLastTickOffset() { - var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, 100, true).ToArray(); + var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, 100).ToArray(); Assert.That(events[2].Type, Is.EqualTo(SliderEventType.LegacyLastTick)); Assert.That(events[2].Time, Is.EqualTo(900)); @@ -99,7 +99,7 @@ namespace osu.Game.Tests.Beatmaps const double velocity = 5; const double min_distance = velocity * 10; - var events = SliderEventGenerator.Generate(start_time, span_duration, velocity, velocity, span_duration, 2, 0, true).ToArray(); + var events = SliderEventGenerator.Generate(start_time, span_duration, velocity, velocity, span_duration, 2, 0).ToArray(); Assert.Multiple(() => { @@ -114,12 +114,5 @@ namespace osu.Game.Tests.Beatmaps } }); } - - [Test] - public void TestNoTickGeneration() - { - var events = SliderEventGenerator.Generate(start_time, span_duration, 1, span_duration / 2, span_duration, 1, null, false).ToArray(); - Assert.That(events.Any(e => e.Type == SliderEventType.Tick), Is.False); - } } } diff --git a/osu.Game/Rulesets/Objects/SliderEventGenerator.cs b/osu.Game/Rulesets/Objects/SliderEventGenerator.cs index b77d15d565..d32a7cb16d 100644 --- a/osu.Game/Rulesets/Objects/SliderEventGenerator.cs +++ b/osu.Game/Rulesets/Objects/SliderEventGenerator.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Objects { // ReSharper disable once MethodOverloadWithOptionalParameter public static IEnumerable Generate(double startTime, double spanDuration, double velocity, double tickDistance, double totalDistance, int spanCount, - double? legacyLastTickOffset, bool shouldGenerateTicks, CancellationToken cancellationToken = default) + double? legacyLastTickOffset, CancellationToken cancellationToken = default) { // A very lenient maximum length of a slider for ticks to be generated. // This exists for edge cases such as /b/1573664 where the beatmap has been edited by the user, and should never be reached in normal usage. @@ -41,20 +41,17 @@ namespace osu.Game.Rulesets.Objects double spanStartTime = startTime + span * spanDuration; bool reversed = span % 2 == 1; - if (shouldGenerateTicks) + var ticks = generateTicks(span, spanStartTime, spanDuration, reversed, length, tickDistance, minDistanceFromEnd, cancellationToken); + + if (reversed) { - var ticks = generateTicks(span, spanStartTime, spanDuration, reversed, length, tickDistance, minDistanceFromEnd, cancellationToken); - - if (reversed) - { - // For repeat spans, ticks are returned in reverse-StartTime order, which is undesirable for some rulesets - ticks = ticks.Reverse(); - } - - foreach (var e in ticks) - yield return e; + // For repeat spans, ticks are returned in reverse-StartTime order, which is undesirable for some rulesets + ticks = ticks.Reverse(); } + foreach (var e in ticks) + yield return e; + if (span < spanCount - 1) { yield return new SliderEventDescriptor From 1191b6c080491c454286ddcab0178a204a7a518f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 23 Aug 2022 13:44:41 +0900 Subject: [PATCH 0625/2686] Remove unused `Source_Set` implementation on `ISpectatorPlayerClock` --- .../Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs | 2 +- .../OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs index 93e1ea3c24..8d8f6a373a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public const double CATCHUP_RATE = 2; - public IFrameBasedClock Source { get; set; } + public readonly IFrameBasedClock Source; public double CurrentTime { get; private set; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs index b2ecb105c2..a2e6df9282 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs @@ -33,10 +33,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// Of note, this will be false if this clock is *ahead* of the master clock. /// bool IsCatchingUp { get; set; } - - /// - /// The source clock - /// - IFrameBasedClock Source { set; } } } From 553897f2f024483b0c2282086f9db8de81604844 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 23 Aug 2022 13:52:43 +0900 Subject: [PATCH 0626/2686] Remove `AddClock` method to `CreateManagedClock` --- osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs | 4 ++-- .../OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs | 4 ++-- .../OnlinePlay/Multiplayer/Spectate/ISyncManager.cs | 8 ++++---- .../Multiplayer/Spectate/MultiSpectatorScreen.cs | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs index 88c4850fa7..db14dc95b2 100644 --- a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs +++ b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs @@ -29,8 +29,8 @@ namespace osu.Game.Tests.OnlinePlay public void Setup() { syncManager = new CatchUpSyncManager(master = new GameplayClockContainer(new TestManualClock())); - player1 = syncManager.AddClock(); - player2 = syncManager.AddClock(); + player1 = syncManager.CreateManagedClock(); + player2 = syncManager.CreateManagedClock(); clocksById = new Dictionary { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs index ede2600671..4e563ec69a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs @@ -54,14 +54,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate MasterClock = master; } - public ISpectatorPlayerClock AddClock() + public ISpectatorPlayerClock CreateManagedClock() { var clock = new CatchUpSpectatorPlayerClock(MasterClock); playerClocks.Add(clock); return clock; } - public void RemoveClock(ISpectatorPlayerClock clock) + public void RemoveManagedClock(ISpectatorPlayerClock clock) { playerClocks.Remove(clock); clock.Stop(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs index 9281e4c1cf..5615e02336 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs @@ -28,15 +28,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate IBindable MasterState { get; } /// - /// Adds a new managed . + /// Create a new managed . /// - /// The added . - ISpectatorPlayerClock AddClock(); + /// The newly created . + ISpectatorPlayerClock CreateManagedClock(); /// /// Removes an , stopping it from being managed by this . /// /// The to remove. - void RemoveClock(ISpectatorPlayerClock clock); + void RemoveManagedClock(ISpectatorPlayerClock clock); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 5a24d74955..3d04ae8f3c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -123,7 +123,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate }; for (int i = 0; i < Users.Count; i++) - grid.Add(instances[i] = new PlayerArea(Users[i], syncManager.AddClock())); + grid.Add(instances[i] = new PlayerArea(Users[i], syncManager.CreateManagedClock())); LoadComponentAsync(leaderboard = new MultiSpectatorLeaderboard(users) { @@ -237,7 +237,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate var instance = instances.Single(i => i.UserId == userId); instance.FadeColour(colours.Gray4, 400, Easing.OutQuint); - syncManager.RemoveClock(instance.GameplayClock); + syncManager.RemoveManagedClock(instance.GameplayClock); } public override bool OnBackButton() From fbe8de2757ca2a752163bd6a2d61a4d788b55301 Mon Sep 17 00:00:00 2001 From: Khang Date: Tue, 23 Aug 2022 00:57:25 -0400 Subject: [PATCH 0627/2686] Disable the GetHashCode warning instead of using bindables --- .../ControlPoints/DifficultyControlPoint.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs index ca49d316e0..ddb2b1e95c 100644 --- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs @@ -16,7 +16,6 @@ namespace osu.Game.Beatmaps.ControlPoints public static readonly DifficultyControlPoint DEFAULT = new DifficultyControlPoint { SliderVelocityBindable = { Disabled = true }, - GenerateTicksBindable = { Disabled = true }, }; /// @@ -30,12 +29,6 @@ namespace osu.Game.Beatmaps.ControlPoints MaxValue = 10 }; - /// - /// Whether or not slider ticks should be generated at this control point. - /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). - /// - public readonly BindableBool GenerateTicksBindable = new BindableBool(true); - public override Color4 GetRepresentingColour(OsuColour colours) => colours.Lime1; /// @@ -51,11 +44,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// Whether or not slider ticks should be generated at this control point. /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). /// - public bool GenerateTicks - { - get => GenerateTicksBindable.Value; - set => GenerateTicksBindable.Value = value; - } + public bool GenerateTicks { get; set; } = true; public override bool IsRedundant(ControlPoint? existing) => existing is DifficultyControlPoint existingDifficulty @@ -79,6 +68,7 @@ namespace osu.Game.Beatmaps.ControlPoints && SliderVelocity == other.SliderVelocity && GenerateTicks == other.GenerateTicks; + // ReSharper disable once NonReadonlyMemberInGetHashCode public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SliderVelocity, GenerateTicks); } } From 690e048864351f03b75902383ed1c785ed0d5eba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 23 Aug 2022 17:00:00 +0900 Subject: [PATCH 0628/2686] Ensure all initial imports are completed before running playlist overlay tests steps --- .../Visual/UserInterface/TestScenePlaylistOverlay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index e67eebf721..fde2d82b16 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -66,6 +66,9 @@ namespace osu.Game.Tests.Visual.UserInterface } beatmapSets.First().ToLive(Realm); + + // Ensure all the initial imports are present before running any tests. + Realm.Run(r => r.Refresh()); }); [Test] From a62deae3cce7a7f2fdd02f80ee5d88bc86272680 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 23 Aug 2022 17:06:32 +0900 Subject: [PATCH 0629/2686] Use local realm rather than fetching from dependencies --- osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index fde2d82b16..f280230da7 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -141,7 +141,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Add collection", () => { - Dependencies.Get().Write(r => + Realm.Write(r => { r.RemoveAll(); r.Add(new BeatmapCollection("wang")); From 9a579871c088774196835ee37ed89ce36ea181c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 23 Aug 2022 17:20:26 +0900 Subject: [PATCH 0630/2686] Remove pointless initial import --- .../Visual/UserInterface/TestScenePlaylistOverlay.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index f280230da7..d87bcfa5dd 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Platform; @@ -39,8 +38,6 @@ namespace osu.Game.Tests.Visual.UserInterface Dependencies.Cache(new RealmRulesetStore(Realm)); Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, Audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); - - beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely(); } [SetUp] From db004c9d9f441360b6bcffb0743090964ba47d85 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 23 Aug 2022 17:33:09 +0900 Subject: [PATCH 0631/2686] Fix collection dropdown potentially overwriting value change with schedule hotfix --- osu.Game/Collections/CollectionDropdown.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Collections/CollectionDropdown.cs b/osu.Game/Collections/CollectionDropdown.cs index 43a4d90aa8..71341f51a4 100644 --- a/osu.Game/Collections/CollectionDropdown.cs +++ b/osu.Game/Collections/CollectionDropdown.cs @@ -75,7 +75,14 @@ namespace osu.Game.Collections // changes. It's not great but honestly the whole dropdown menu structure isn't great. This needs to be fixed, but I'll issue // a warning that it's going to be a frustrating journey. Current.Value = allBeatmaps; - Schedule(() => Current.Value = filters.SingleOrDefault(f => f.Collection != null && f.Collection.ID == selectedItem?.ID) ?? filters[0]); + Schedule(() => + { + // current may have changed before the scheduled call is run. + if (Current.Value != allBeatmaps) + return; + + Current.Value = filters.SingleOrDefault(f => f.Collection != null && f.Collection.ID == selectedItem?.ID) ?? filters[0]; + }); // Trigger a re-filter if the current item was in the change set. if (selectedItem != null && changes != null) From 29fed0c4a3c1cfb445d0a57d78771ac4fcada63d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 23 Aug 2022 18:32:56 +0900 Subject: [PATCH 0632/2686] Avoid setting the source clock until gameplay is ready to start Without this change, the audio track may audibly seek during load proceedings. --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 3 +-- osu.Game/Screens/Play/GameplayClockContainer.cs | 4 ++-- osu.Game/Screens/Play/MasterGameplayClockContainer.cs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index 3166f688ea..c86f25640f 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -70,14 +70,13 @@ namespace osu.Game.Beatmaps set => decoupledClock.IsCoupled = value; } - public FramedBeatmapClock(IClock? sourceClock = null, bool applyOffsets = false) + public FramedBeatmapClock(bool applyOffsets = false) { this.applyOffsets = applyOffsets; // A decoupled clock is used to ensure precise time values even when the host audio subsystem is not reporting // high precision times (on windows there's generally only 5-10ms reporting intervals, as an example). decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true }; - decoupledClock.ChangeSource(sourceClock); if (applyOffsets) { diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 897d2cbdcd..21fffb2992 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Play /// By default, a value of zero will be used. /// Importantly, the value will be inferred from the current beatmap in by default. /// - public double StartTime { get; private set; } + public double StartTime { get; protected set; } public virtual IEnumerable NonGameplayAdjustments => Enumerable.Empty(); @@ -71,7 +71,7 @@ namespace osu.Game.Screens.Play InternalChildren = new Drawable[] { - GameplayClock = new FramedBeatmapClock(sourceClock, applyOffsets) { IsCoupled = false }, + GameplayClock = new FramedBeatmapClock(applyOffsets) { IsCoupled = false }, Content }; } diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 168a5658f5..238817ad05 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -58,7 +58,7 @@ namespace osu.Game.Screens.Play this.beatmap = beatmap; this.skipTargetTime = skipTargetTime; - Reset(findEarliestStartTime()); + StartTime = findEarliestStartTime(); } private double findEarliestStartTime() From c840977acb72cd9d10fe90caf7c1d6ccacfa9c44 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 23 Aug 2022 20:42:20 +0900 Subject: [PATCH 0633/2686] Fix filtering potentially not running after new items added --- osu.Game/Overlays/Music/Playlist.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Music/Playlist.cs b/osu.Game/Overlays/Music/Playlist.cs index 15fc54a337..b48257a61a 100644 --- a/osu.Game/Overlays/Music/Playlist.cs +++ b/osu.Game/Overlays/Music/Playlist.cs @@ -27,6 +27,12 @@ namespace osu.Game.Overlays.Music set => base.Padding = value; } + protected override void OnItemsChanged() + { + base.OnItemsChanged(); + Filter(currentCriteria); + } + public void Filter(FilterCriteria criteria) { var items = (SearchContainer>>)ListContainer; @@ -44,12 +50,12 @@ namespace osu.Game.Overlays.Music public Live? FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter); - protected override OsuRearrangeableListItem> CreateOsuDrawable(Live item) => new PlaylistItem(item) - { - InSelectedCollection = currentCriteria.Collection?.PerformRead(c => item.Value.Beatmaps.Select(b => b.MD5Hash).Any(c.BeatmapMD5Hashes.Contains)) != false, - SelectedSet = { BindTarget = SelectedSet }, - RequestSelection = set => RequestSelection?.Invoke(set) - }; + protected override OsuRearrangeableListItem> CreateOsuDrawable(Live item) => + new PlaylistItem(item) + { + SelectedSet = { BindTarget = SelectedSet }, + RequestSelection = set => RequestSelection?.Invoke(set) + }; protected override FillFlowContainer>> CreateListFillFlowContainer() => new SearchContainer>> { From c1ced85b5e4fd5afe86e064774fda164be0ce88c Mon Sep 17 00:00:00 2001 From: Khang Date: Tue, 23 Aug 2022 14:07:18 -0400 Subject: [PATCH 0634/2686] Move GenerateTicks to LegacyDifficultyControlPoint and remove support for NaN slider velocity support for other rulesets (at least for now) --- .../Objects/JuiceStream.cs | 6 +++++- osu.Game.Rulesets.Mania/Objects/HoldNote.cs | 2 +- osu.Game.Rulesets.Osu/Objects/Slider.cs | 10 +++++++++- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 2 +- .../ControlPoints/DifficultyControlPoint.cs | 16 +++------------ .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 1 - osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 20 ++++++++++++++++--- 7 files changed, 36 insertions(+), 21 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 311e15116e..2a5564297c 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -11,6 +11,7 @@ using Newtonsoft.Json; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Formats; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -50,9 +51,12 @@ namespace osu.Game.Rulesets.Catch.Objects base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); +#pragma warning disable 618 + bool generateTicks = (DifficultyControlPoint as LegacyBeatmapDecoder.LegacyDifficultyControlPoint)?.GenerateTicks ?? true; +#pragma warning restore 618 velocityFactor = base_scoring_distance * difficulty.SliderMultiplier / timingPoint.BeatLength; - tickDistanceFactor = base_scoring_distance * difficulty.SliderMultiplier / difficulty.SliderTickRate; + tickDistanceFactor = generateTicks ? (base_scoring_distance * difficulty.SliderMultiplier / difficulty.SliderTickRate) : double.PositiveInfinity; } protected override void CreateNestedHitObjects(CancellationToken cancellationToken) diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs index 4ec039c405..22fab15c1b 100644 --- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs @@ -117,7 +117,7 @@ namespace osu.Game.Rulesets.Mania.Objects private void createTicks(CancellationToken cancellationToken) { - if (tickSpacing == 0 || !DifficultyControlPoint.GenerateTicks) + if (tickSpacing == 0) return; for (double t = StartTime + tickSpacing; t <= EndTime - tickSpacing; t += tickSpacing) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 0689c49085..df1252c060 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -14,6 +14,8 @@ using osu.Framework.Caching; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Formats; +using osu.Game.Beatmaps.Legacy; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Scoring; @@ -166,10 +168,16 @@ namespace osu.Game.Rulesets.Osu.Objects TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); + var legacyInfo = controlPointInfo as LegacyControlPointInfo; +#pragma warning disable 618 + var legacyDifficultyPoint = legacyInfo?.DifficultyPointAt(StartTime) as LegacyBeatmapDecoder.LegacyDifficultyControlPoint; +#pragma warning restore 618 + double scoringDistance = BASE_SCORING_DISTANCE * difficulty.SliderMultiplier * DifficultyControlPoint.SliderVelocity; + bool generateTicks = legacyDifficultyPoint?.GenerateTicks ?? true; Velocity = scoringDistance / timingPoint.BeatLength; - TickDistance = DifficultyControlPoint.GenerateTicks ? (scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier) : double.PositiveInfinity; + TickDistance = generateTicks ? (scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier) : double.PositiveInfinity; } protected override void CreateNestedHitObjects(CancellationToken cancellationToken) diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 09e465c37b..e1619e2857 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Taiko.Objects private void createTicks(CancellationToken cancellationToken) { - if (tickSpacing == 0 || !DifficultyControlPoint.GenerateTicks) + if (tickSpacing == 0) return; bool first = true; diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs index ddb2b1e95c..c199d1da59 100644 --- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs @@ -40,21 +40,13 @@ namespace osu.Game.Beatmaps.ControlPoints set => SliderVelocityBindable.Value = value; } - /// - /// Whether or not slider ticks should be generated at this control point. - /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). - /// - public bool GenerateTicks { get; set; } = true; - public override bool IsRedundant(ControlPoint? existing) => existing is DifficultyControlPoint existingDifficulty - && SliderVelocity == existingDifficulty.SliderVelocity - && GenerateTicks == existingDifficulty.GenerateTicks; + && SliderVelocity == existingDifficulty.SliderVelocity; public override void CopyFrom(ControlPoint other) { SliderVelocity = ((DifficultyControlPoint)other).SliderVelocity; - GenerateTicks = ((DifficultyControlPoint)other).GenerateTicks; base.CopyFrom(other); } @@ -65,10 +57,8 @@ namespace osu.Game.Beatmaps.ControlPoints public bool Equals(DifficultyControlPoint? other) => base.Equals(other) - && SliderVelocity == other.SliderVelocity - && GenerateTicks == other.GenerateTicks; + && SliderVelocity == other.SliderVelocity; - // ReSharper disable once NonReadonlyMemberInGetHashCode - public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SliderVelocity, GenerateTicks); + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), SliderVelocity); } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 3d3661745a..f064d89e19 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -430,7 +430,6 @@ namespace osu.Game.Beatmaps.Formats #pragma warning restore 618 { SliderVelocity = speedMultiplier, - GenerateTicks = !double.IsNaN(beatLength), }, timingChange); var effectPoint = new EffectControlPoint diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 52e760a068..c3fd16e86f 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -168,11 +168,18 @@ namespace osu.Game.Beatmaps.Formats /// public double BpmMultiplier { get; private set; } + /// + /// Whether or not slider ticks should be generated at this control point. + /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). + /// + public bool GenerateTicks { get; private set; } = true; + public LegacyDifficultyControlPoint(double beatLength) : this() { // Note: In stable, the division occurs on floats, but with compiler optimisations turned on actually seems to occur on doubles via some .NET black magic (possibly inlining?). BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; + GenerateTicks = !double.IsNaN(beatLength); } public LegacyDifficultyControlPoint() @@ -180,11 +187,17 @@ namespace osu.Game.Beatmaps.Formats SliderVelocityBindable.Precision = double.Epsilon; } + public override bool IsRedundant(ControlPoint? existing) + => existing is LegacyDifficultyControlPoint existingLegacyDifficulty + && base.IsRedundant(existing) + && GenerateTicks == existingLegacyDifficulty.GenerateTicks; + public override void CopyFrom(ControlPoint other) { base.CopyFrom(other); BpmMultiplier = ((LegacyDifficultyControlPoint)other).BpmMultiplier; + GenerateTicks = ((LegacyDifficultyControlPoint)other).GenerateTicks; } public override bool Equals(ControlPoint? other) @@ -193,10 +206,11 @@ namespace osu.Game.Beatmaps.Formats public bool Equals(LegacyDifficultyControlPoint? other) => base.Equals(other) - && BpmMultiplier == other.BpmMultiplier; + && BpmMultiplier == other.BpmMultiplier + && GenerateTicks == other.GenerateTicks; - // ReSharper disable once NonReadonlyMemberInGetHashCode - public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier); + // ReSharper disable twice NonReadonlyMemberInGetHashCode + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier, GenerateTicks); } internal class LegacySampleControlPoint : SampleControlPoint, IEquatable From ada61e6fe7121960b2f531ff08bb29379ade63b1 Mon Sep 17 00:00:00 2001 From: Khang Date: Tue, 23 Aug 2022 14:10:26 -0400 Subject: [PATCH 0635/2686] Forgot to undo broken changes in JuiceStream --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 2a5564297c..311e15116e 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -11,7 +11,6 @@ using Newtonsoft.Json; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Beatmaps.Formats; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -51,12 +50,9 @@ namespace osu.Game.Rulesets.Catch.Objects base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); -#pragma warning disable 618 - bool generateTicks = (DifficultyControlPoint as LegacyBeatmapDecoder.LegacyDifficultyControlPoint)?.GenerateTicks ?? true; -#pragma warning restore 618 velocityFactor = base_scoring_distance * difficulty.SliderMultiplier / timingPoint.BeatLength; - tickDistanceFactor = generateTicks ? (base_scoring_distance * difficulty.SliderMultiplier / difficulty.SliderTickRate) : double.PositiveInfinity; + tickDistanceFactor = base_scoring_distance * difficulty.SliderMultiplier / difficulty.SliderTickRate; } protected override void CreateNestedHitObjects(CancellationToken cancellationToken) From ec9daec93bcea47e7983564db3fb75b1c531733a Mon Sep 17 00:00:00 2001 From: Khang Date: Tue, 23 Aug 2022 14:18:40 -0400 Subject: [PATCH 0636/2686] Remove unnecessary workaround --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index df1252c060..a7495a2809 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -167,10 +167,8 @@ namespace osu.Game.Rulesets.Osu.Objects base.ApplyDefaultsToSelf(controlPointInfo, difficulty); TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); - - var legacyInfo = controlPointInfo as LegacyControlPointInfo; #pragma warning disable 618 - var legacyDifficultyPoint = legacyInfo?.DifficultyPointAt(StartTime) as LegacyBeatmapDecoder.LegacyDifficultyControlPoint; + var legacyDifficultyPoint = DifficultyControlPoint as LegacyBeatmapDecoder.LegacyDifficultyControlPoint; #pragma warning restore 618 double scoringDistance = BASE_SCORING_DISTANCE * difficulty.SliderMultiplier * DifficultyControlPoint.SliderVelocity; From 1f9cdff0139a84830cc099537b2cad7e9552c3f6 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 23 Aug 2022 22:19:40 +0200 Subject: [PATCH 0637/2686] remove these lines --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index d903ada6e2..de40d8e03b 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -277,9 +277,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders // Turn the control points which were split off into a new slider. var samplePoint = (SampleControlPoint)HitObject.SampleControlPoint.DeepClone(); - samplePoint.Time = HitObject.StartTime; var difficultyPoint = (DifficultyControlPoint)HitObject.DifficultyControlPoint.DeepClone(); - difficultyPoint.Time = HitObject.StartTime; var newSlider = new Slider { From 631ea9a3edaf0ba8c27b685be971521a07931fbf Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 23 Aug 2022 23:28:50 +0200 Subject: [PATCH 0638/2686] added a gap between objects and made it theoretically possible to retain sample control point --- .../Editor/TestSceneSliderSplitting.cs | 72 +++++++++++++++++-- .../Sliders/SliderSelectionBlueprint.cs | 8 ++- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs index 198d521a85..015952c59a 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -30,6 +31,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor private Slider? slider; private PathControlPointVisualiser? visualiser; + private const double split_gap = 100; + [Test] public void TestBasicSplit() { @@ -69,11 +72,11 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor addContextMenuItemStep("Split control point"); AddAssert("slider split", () => slider is not null && EditorBeatmap.HitObjects.Count == 2 && - sliderCreatedFor((Slider)EditorBeatmap.HitObjects[0], 0, slider.StartTime, + sliderCreatedFor((Slider)EditorBeatmap.HitObjects[0], 0, EditorBeatmap.HitObjects[1].StartTime - split_gap, (new Vector2(0, 50), PathType.PerfectCurve), (new Vector2(150, 200), null), (new Vector2(300, 50), null) - ) && sliderCreatedFor((Slider)EditorBeatmap.HitObjects[1], slider.StartTime, endTime, + ) && sliderCreatedFor((Slider)EditorBeatmap.HitObjects[1], slider.StartTime, endTime + split_gap, (new Vector2(300, 50), PathType.PerfectCurve), (new Vector2(400, 50), null), (new Vector2(400, 200), null) @@ -135,21 +138,80 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor addContextMenuItemStep("Split 2 control points"); AddAssert("slider split", () => slider is not null && EditorBeatmap.HitObjects.Count == 3 && - sliderCreatedFor((Slider)EditorBeatmap.HitObjects[0], 0, EditorBeatmap.HitObjects[1].StartTime, + sliderCreatedFor((Slider)EditorBeatmap.HitObjects[0], 0, EditorBeatmap.HitObjects[1].StartTime - split_gap, (new Vector2(0, 50), PathType.PerfectCurve), (new Vector2(150, 200), null), (new Vector2(300, 50), null) - ) && sliderCreatedFor((Slider)EditorBeatmap.HitObjects[1], EditorBeatmap.HitObjects[0].GetEndTime(), slider.StartTime, + ) && sliderCreatedFor((Slider)EditorBeatmap.HitObjects[1], EditorBeatmap.HitObjects[0].GetEndTime() + split_gap, slider.StartTime - split_gap, (new Vector2(300, 50), PathType.Bezier), (new Vector2(400, 50), null), (new Vector2(400, 200), null) - ) && sliderCreatedFor((Slider)EditorBeatmap.HitObjects[2], EditorBeatmap.HitObjects[1].GetEndTime(), endTime, + ) && sliderCreatedFor((Slider)EditorBeatmap.HitObjects[2], EditorBeatmap.HitObjects[1].GetEndTime() + split_gap, endTime + split_gap * 2, (new Vector2(400, 200), PathType.Catmull), (new Vector2(300, 250), null), (new Vector2(400, 300), null) )); } + [Test] + public void TestSplitRetainsHitsounds() + { + HitSampleInfo? sample = null; + + AddStep("add slider", () => + { + slider = new Slider + { + Position = new Vector2(0, 50), + LegacyLastTickOffset = 36, // This is necessary for undo to retain the sample control point + Path = new SliderPath(new[] + { + new PathControlPoint(Vector2.Zero, PathType.PerfectCurve), + new PathControlPoint(new Vector2(150, 150)), + new PathControlPoint(new Vector2(300, 0), PathType.PerfectCurve), + new PathControlPoint(new Vector2(400, 0)), + new PathControlPoint(new Vector2(400, 150)) + }) + }; + + EditorBeatmap.Add(slider); + }); + + AddStep("add hitsounds", () => + { + if (slider is null) return; + + slider.SampleControlPoint.SampleBank = "soft"; + slider.SampleControlPoint.SampleVolume = 70; + sample = new HitSampleInfo("hitwhistle"); + slider.Samples.Add(sample); + }); + + AddStep("select added slider", () => + { + EditorBeatmap.SelectedHitObjects.Add(slider); + visualiser = blueprintContainer.SelectionBlueprints.First(o => o.Item == slider).ChildrenOfType().First(); + }); + + moveMouseToControlPoint(2); + AddStep("select control point", () => + { + if (visualiser is not null) visualiser.Pieces[2].IsSelected.Value = true; + }); + addContextMenuItemStep("Split control point"); + AddAssert("sliders have hitsounds", hasHitsounds); + + AddStep("select first slider", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects[0])); + AddStep("remove first slider", () => EditorBeatmap.RemoveAt(0)); + AddStep("undo", () => Editor.Undo()); + AddAssert("sliders have hitsounds", hasHitsounds); + + bool hasHitsounds() => sample is not null && + EditorBeatmap.HitObjects.All(o => o.SampleControlPoint.SampleBank == "soft" && + o.SampleControlPoint.SampleVolume == 70 && + o.Samples.Contains(sample)); + } + private bool sliderCreatedFor(Slider s, double startTime, double endTime, params (Vector2 pos, PathType? pathType)[] expectedControlPoints) { if (!Precision.AlmostEquals(s.StartTime, startTime, 1) || !Precision.AlmostEquals(s.EndTime, endTime, 1)) return false; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index de40d8e03b..14ed305b25 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -253,6 +253,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void splitControlPoints(List toSplit) { + // Arbitrary gap in milliseconds to put between split slider pieces + const double split_gap = 100; + // Ensure that there are any points to be split if (toSplit.Count == 0) return; @@ -286,6 +289,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders NewCombo = HitObject.NewCombo, SampleControlPoint = samplePoint, DifficultyControlPoint = difficultyPoint, + LegacyLastTickOffset = HitObject.LegacyLastTickOffset, Samples = HitObject.Samples.Select(s => s.With()).ToList(), RepeatCount = HitObject.RepeatCount, NodeSamples = HitObject.NodeSamples.Select(n => (IList)n.Select(s => s.With()).ToList()).ToList(), @@ -293,13 +297,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders }; // Increase the start time of the slider before adding the new slider so the new slider is immediately inserted at the correct index and internal state remains valid. - HitObject.StartTime += 1; + HitObject.StartTime += split_gap; editorBeatmap.Add(newSlider); HitObject.NewCombo = false; HitObject.Path.ExpectedDistance.Value -= newSlider.Path.CalculatedDistance; - HitObject.StartTime += newSlider.SpanDuration - 1; + HitObject.StartTime += newSlider.SpanDuration; // In case the remainder of the slider has no length left over, give it length anyways so we don't get a 0 length slider. if (HitObject.Path.ExpectedDistance.Value <= Precision.DOUBLE_EPSILON) From fb9bb2d42dd8884cfd4d93e15024d791a69e2eda Mon Sep 17 00:00:00 2001 From: vun Date: Wed, 24 Aug 2022 08:57:13 +0800 Subject: [PATCH 0639/2686] Declare Parent as non-nullable --- .../Difficulty/Evaluators/ColourEvaluator.cs | 4 ++-- .../Preprocessing/Colour/Data/AlternatingMonoPattern.cs | 2 +- .../Difficulty/Preprocessing/Colour/Data/MonoStreak.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 6c685e854e..7d88be2f70 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// public static double EvaluateDifficultyOf(MonoStreak monoStreak) { - return sigmoid(monoStreak.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(monoStreak.Parent!) * 0.5; + return sigmoid(monoStreak.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(monoStreak.Parent) * 0.5; } /// @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// public static double EvaluateDifficultyOf(AlternatingMonoPattern alternatingMonoPattern) { - return sigmoid(alternatingMonoPattern.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(alternatingMonoPattern.Parent!); + return sigmoid(alternatingMonoPattern.Index, 2, 2, 0.5, 1) * EvaluateDifficultyOf(alternatingMonoPattern.Parent); } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs index 60d4e55a64..7910a8262b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// /// The parent that contains this /// - public RepeatingHitPatterns? Parent; + public RepeatingHitPatterns Parent = null!; /// /// Index of this within it's parent diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs index 4e15043acf..174988bed7 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// /// The parent that contains this /// - public AlternatingMonoPattern? Parent; + public AlternatingMonoPattern Parent = null!; /// /// Index of this within it's parent From 46d000b8cebb271f25e254c24b06a3c269ec71d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 11:50:19 +0900 Subject: [PATCH 0640/2686] Fix test regressions on windows due to `Reset` never being called I'm not sure this is great. Without calling `Reset`, the correct initial time may not be set (ever). In practice this doesn't happen anywhere in the gameplay flow, but something worth noting. This change is required now that `Reset` isn't called in the constructor. It couldn't be called in the constructor because it would cause the audio track to reset its position too early. What an ordeal. --- osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index dcaeadf82a..577933eae3 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -84,7 +84,7 @@ namespace osu.Game.Tests.Gameplay }); }); - AddStep("reset clock", () => gameplayContainer.Start()); + AddStep("reset clock", () => gameplayContainer.Reset(startClock: true)); AddUntilStep("sample played", () => sample.RequestedPlaying); AddUntilStep("sample has lifetime end", () => sample.LifetimeEnd < double.MaxValue); @@ -147,7 +147,7 @@ namespace osu.Game.Tests.Gameplay }); }); - AddStep("start", () => gameplayContainer.Start()); + AddStep("reset clock", () => gameplayContainer.Reset(startClock: true)); AddUntilStep("sample played", () => sample.IsPlayed); AddUntilStep("sample has lifetime end", () => sample.LifetimeEnd < double.MaxValue); From 85fbe7abca4274014c1fdfe4473ca053bda1337b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 13:11:53 +0900 Subject: [PATCH 0641/2686] Fix multiplayer spectator getting stuck --- .../Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs | 5 ++++- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs index 8d8f6a373a..5625a79afa 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs @@ -73,7 +73,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate if (IsRunning) { - double elapsedSource = Source.ElapsedFrameTime; + // When in catch-up mode, the source is usually not running. + // In such a case, its elapsed time may be zero, which would cause catch-up to get stuck. + // To avoid this, use a constant 16ms elapsed time for now. Probably not too correct, but this whole logic isn't too correct anyway. + double elapsedSource = Source.IsRunning ? Source.ElapsedFrameTime : 16; double elapsed = elapsedSource * Rate; CurrentTime += elapsed; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 2a2575e4b2..953d16f6e8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; @@ -195,6 +196,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private void onMasterStateChanged(ValueChangedEvent state) { + Logger.Log($"{nameof(MultiSpectatorScreen)}'s master clock become {state.NewValue}"); + switch (state.NewValue) { case MasterClockState.Synchronised: From ec31f37ff7a1c436c054b6e963c0d4f2fa71b9a4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 14:50:10 +0900 Subject: [PATCH 0642/2686] Accept `MasterGameplayClockContainer` rather than generic clock --- .../Spectate/CatchUpSpectatorPlayerClock.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs index 8d8f6a373a..c0263d6d0f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Bindables; using osu.Framework.Timing; +using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { @@ -17,15 +18,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public const double CATCHUP_RATE = 2; - public readonly IFrameBasedClock Source; + private readonly GameplayClockContainer masterClock; public double CurrentTime { get; private set; } public bool IsRunning { get; private set; } - public CatchUpSpectatorPlayerClock(IFrameBasedClock source) + public CatchUpSpectatorPlayerClock(GameplayClockContainer masterClock) { - Source = source; + this.masterClock = masterClock; } public void Reset() => CurrentTime = 0; @@ -69,16 +70,16 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate ElapsedFrameTime = 0; FramesPerSecond = 0; - Source.ProcessFrame(); + masterClock.ProcessFrame(); if (IsRunning) { - double elapsedSource = Source.ElapsedFrameTime; + double elapsedSource = masterClock.ElapsedFrameTime; double elapsed = elapsedSource * Rate; CurrentTime += elapsed; ElapsedFrameTime = elapsed; - FramesPerSecond = Source.FramesPerSecond; + FramesPerSecond = masterClock.FramesPerSecond; } } From c9f364d6a086c7582040c9b66a94eca09e8ce25e Mon Sep 17 00:00:00 2001 From: Khang Date: Wed, 24 Aug 2022 02:10:19 -0400 Subject: [PATCH 0643/2686] Document why beatLength can be NaN --- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index f064d89e19..75500fbc4e 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -373,6 +373,8 @@ namespace osu.Game.Beatmaps.Formats string[] split = line.Split(','); double time = getOffsetTime(Parsing.ParseDouble(split[0].Trim())); + + // beatLength is allowed to be NaN to handle an edge case in which some beatmaps use NaN slider velocity to disable slider tick generation (see LegacyDifficultyControlPoint). double beatLength = Parsing.ParseDouble(split[1].Trim(), allowNaN: true); // If beatLength is NaN, speedMultiplier should still be 1 because all comparisons against NaN are false. From 22963ab95162fc13770b128c09e7b8c57b061a87 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 13:11:53 +0900 Subject: [PATCH 0644/2686] Fix multiplayer spectator getting stuck --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 3d04ae8f3c..0f0f29e02e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; @@ -198,6 +199,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private void onMasterStateChanged(ValueChangedEvent state) { + Logger.Log($"{nameof(MultiSpectatorScreen)}'s master clock become {state.NewValue}"); + switch (state.NewValue) { case MasterClockState.Synchronised: From 882dd93942356d2122f4c34fe7d41a97bb98c33e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:01:57 +0900 Subject: [PATCH 0645/2686] Remove `ISyncManager` interface Too many levels of redirection. One interface with one implementation is not useful, IMO. --- .../Spectate/CatchUpSyncManager.cs | 18 +++++++- .../Spectate/ISpectatorPlayerClock.cs | 2 +- .../Multiplayer/Spectate/ISyncManager.cs | 42 ------------------- .../Spectate/MultiSpectatorScreen.cs | 2 +- 4 files changed, 18 insertions(+), 46 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs index 4e563ec69a..b9898ad456 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs @@ -11,9 +11,9 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// A which synchronises de-synced player clocks through catchup. + /// Manages the synchronisation between one or more s in relation to a master clock. /// - public class CatchUpSyncManager : Component, ISyncManager + public class CatchUpSyncManager : Component { /// /// The offset from the master clock to which player clocks should remain within to be considered in-sync. @@ -30,6 +30,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public const double MAXIMUM_START_DELAY = 15000; + /// + /// An event which is invoked when gameplay is ready to start. + /// public event Action? ReadyToStart; /// @@ -37,6 +40,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public GameplayClockContainer MasterClock { get; } + /// + /// The catch-up state of the master clock. + /// public IBindable MasterState => masterState; /// @@ -54,6 +60,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate MasterClock = master; } + /// + /// Create a new managed . + /// + /// The newly created . public ISpectatorPlayerClock CreateManagedClock() { var clock = new CatchUpSpectatorPlayerClock(MasterClock); @@ -61,6 +71,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate return clock; } + /// + /// Removes an , stopping it from being managed by this . + /// + /// The to remove. public void RemoveManagedClock(ISpectatorPlayerClock clock) { playerClocks.Remove(clock); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs index a2e6df9282..22f835f79e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs @@ -7,7 +7,7 @@ using osu.Framework.Timing; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// A clock which is used by s and managed by an . + /// A clock which is used by s and managed by an . /// public interface ISpectatorPlayerClock : IFrameBasedClock, IAdjustableClock { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs deleted file mode 100644 index 5615e02336..0000000000 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs +++ /dev/null @@ -1,42 +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 osu.Framework.Bindables; -using osu.Game.Screens.Play; - -namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate -{ - /// - /// Manages the synchronisation between one or more s in relation to a master clock. - /// - public interface ISyncManager - { - /// - /// An event which is invoked when gameplay is ready to start. - /// - event Action? ReadyToStart; - - /// - /// The master clock which player clocks should synchronise to. - /// - GameplayClockContainer MasterClock { get; } - - /// - /// An event which is invoked when the state of is changed. - /// - IBindable MasterState { get; } - - /// - /// Create a new managed . - /// - /// The newly created . - ISpectatorPlayerClock CreateManagedClock(); - - /// - /// Removes an , stopping it from being managed by this . - /// - /// The to remove. - void RemoveManagedClock(ISpectatorPlayerClock clock); - } -} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 0f0f29e02e..0177003bb2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly PlayerArea[] instances; private MasterGameplayClockContainer masterClockContainer = null!; - private ISyncManager syncManager = null!; + private CatchUpSyncManager syncManager = null!; private PlayerGrid grid = null!; private MultiSpectatorLeaderboard leaderboard = null!; private PlayerArea? currentAudioSource; From 31f657fe01f7b7ce53b7ef3fa07fed91bb4502ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:04:52 +0900 Subject: [PATCH 0646/2686] Remove `ISpectatorPlayerClock` interface Too many levels of redirection. One interface with one implementation is not useful, IMO. --- .../OnlinePlay/TestSceneCatchUpSyncManager.cs | 16 ++++---- .../Spectate/CatchUpSpectatorPlayerClock.cs | 19 +++++++++- .../Spectate/CatchUpSyncManager.cs | 16 ++++---- .../Spectate/ISpectatorPlayerClock.cs | 37 ------------------- .../Spectate/MultiSpectatorPlayer.cs | 4 +- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../Multiplayer/Spectate/PlayerArea.cs | 6 +-- 7 files changed, 39 insertions(+), 61 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs diff --git a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs index db14dc95b2..263ce7c9bd 100644 --- a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs +++ b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs @@ -21,9 +21,9 @@ namespace osu.Game.Tests.OnlinePlay private GameplayClockContainer master; private CatchUpSyncManager syncManager; - private Dictionary clocksById; - private ISpectatorPlayerClock player1; - private ISpectatorPlayerClock player2; + private Dictionary clocksById; + private CatchUpSpectatorPlayerClock player1; + private CatchUpSpectatorPlayerClock player2; [SetUp] public void Setup() @@ -32,7 +32,7 @@ namespace osu.Game.Tests.OnlinePlay player1 = syncManager.CreateManagedClock(); player2 = syncManager.CreateManagedClock(); - clocksById = new Dictionary + clocksById = new Dictionary { { player1, 1 }, { player2, 2 } @@ -145,7 +145,7 @@ namespace osu.Game.Tests.OnlinePlay assertPlayerClockState(() => player1, false); } - private void setWaiting(Func playerClock, bool waiting) + private void setWaiting(Func playerClock, bool waiting) => AddStep($"set player clock {clocksById[playerClock()]} waiting = {waiting}", () => playerClock().WaitingOnFrames.Value = waiting); private void setAllWaiting(bool waiting) => AddStep($"set all player clocks waiting = {waiting}", () => @@ -160,13 +160,13 @@ namespace osu.Game.Tests.OnlinePlay /// /// clock.Time = master.Time - offsetFromMaster /// - private void setPlayerClockTime(Func playerClock, double offsetFromMaster) + private void setPlayerClockTime(Func playerClock, double offsetFromMaster) => AddStep($"set player clock {clocksById[playerClock()]} = master - {offsetFromMaster}", () => playerClock().Seek(master.CurrentTime - offsetFromMaster)); - private void assertCatchingUp(Func playerClock, bool catchingUp) => + private void assertCatchingUp(Func playerClock, bool catchingUp) => AddAssert($"player clock {clocksById[playerClock()]} {(catchingUp ? "is" : "is not")} catching up", () => playerClock().IsCatchingUp == catchingUp); - private void assertPlayerClockState(Func playerClock, bool running) + private void assertPlayerClockState(Func playerClock, bool running) => AddAssert($"player clock {clocksById[playerClock()]} {(running ? "is" : "is not")} running", () => playerClock().IsRunning == running); private class TestManualClock : ManualClock, IAdjustableClock diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs index c0263d6d0f..15821fb133 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs @@ -9,9 +9,9 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// A which catches up using rate adjustment. + /// A which catches up using rate adjustment. /// - public class CatchUpSpectatorPlayerClock : ISpectatorPlayerClock + public class CatchUpSpectatorPlayerClock : IFrameBasedClock, IAdjustableClock { /// /// The catch up rate. @@ -31,8 +31,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public void Reset() => CurrentTime = 0; + /// + /// Starts this . + /// public void Start() => IsRunning = true; + /// + /// Stops this . + /// public void Stop() => IsRunning = false; void IAdjustableClock.Start() @@ -89,8 +95,17 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public FrameTimeInfo TimeInfo => new FrameTimeInfo { Elapsed = ElapsedFrameTime, Current = CurrentTime }; + /// + /// Whether this clock is waiting on frames to continue playback. + /// public Bindable WaitingOnFrames { get; } = new Bindable(true); + /// + /// Whether this clock is behind the master clock and running at a higher rate to catch up to it. + /// + /// + /// Of note, this will be false if this clock is *ahead* of the master clock. + /// public bool IsCatchingUp { get; set; } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs index b9898ad456..71fbb8cbee 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// Manages the synchronisation between one or more s in relation to a master clock. + /// Manages the synchronisation between one or more s in relation to a master clock. /// public class CatchUpSyncManager : Component { @@ -48,7 +48,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The player clocks. /// - private readonly List playerClocks = new List(); + private readonly List playerClocks = new List(); private readonly Bindable masterState = new Bindable(); @@ -61,10 +61,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } /// - /// Create a new managed . + /// Create a new managed . /// - /// The newly created . - public ISpectatorPlayerClock CreateManagedClock() + /// The newly created . + public CatchUpSpectatorPlayerClock CreateManagedClock() { var clock = new CatchUpSpectatorPlayerClock(MasterClock); playerClocks.Add(clock); @@ -72,10 +72,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } /// - /// Removes an , stopping it from being managed by this . + /// Removes an , stopping it from being managed by this . /// - /// The to remove. - public void RemoveManagedClock(ISpectatorPlayerClock clock) + /// The to remove. + public void RemoveManagedClock(CatchUpSpectatorPlayerClock clock) { playerClocks.Remove(clock); clock.Stop(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs deleted file mode 100644 index 22f835f79e..0000000000 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs +++ /dev/null @@ -1,37 +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.Framework.Timing; - -namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate -{ - /// - /// A clock which is used by s and managed by an . - /// - public interface ISpectatorPlayerClock : IFrameBasedClock, IAdjustableClock - { - /// - /// Starts this . - /// - new void Start(); - - /// - /// Stops this . - /// - new void Stop(); - - /// - /// Whether this clock is waiting on frames to continue playback. - /// - Bindable WaitingOnFrames { get; } - - /// - /// Whether this clock is behind the master clock and running at a higher rate to catch up to it. - /// - /// - /// Of note, this will be false if this clock is *ahead* of the master clock. - /// - bool IsCatchingUp { get; set; } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 68eae76030..4821eb69c6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -15,14 +15,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public class MultiSpectatorPlayer : SpectatorPlayer { private readonly Bindable waitingOnFrames = new Bindable(true); - private readonly ISpectatorPlayerClock spectatorPlayerClock; + private readonly CatchUpSpectatorPlayerClock spectatorPlayerClock; /// /// Creates a new . /// /// The score containing the player's replay. /// The clock controlling the gameplay running state. - public MultiSpectatorPlayer(Score score, ISpectatorPlayerClock spectatorPlayerClock) + public MultiSpectatorPlayer(Score score, CatchUpSpectatorPlayerClock spectatorPlayerClock) : base(score, new PlayerConfiguration { AllowUserInteraction = false }) { this.spectatorPlayerClock = spectatorPlayerClock; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 0177003bb2..ac66aa160c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -177,7 +177,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } } - private bool isCandidateAudioSource(ISpectatorPlayerClock? clock) + private bool isCandidateAudioSource(CatchUpSpectatorPlayerClock? clock) => clock?.IsRunning == true && !clock.IsCatchingUp && !clock.WaitingOnFrames.Value; private void onReadyToStart() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index 7e679383c4..451f4e0b79 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -38,9 +38,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public readonly int UserId; /// - /// The used to control the gameplay running state of a loaded . + /// The used to control the gameplay running state of a loaded . /// - public readonly ISpectatorPlayerClock GameplayClock; + public readonly CatchUpSpectatorPlayerClock GameplayClock; /// /// The currently-loaded score. @@ -55,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly LoadingLayer loadingLayer; private OsuScreenStack? stack; - public PlayerArea(int userId, ISpectatorPlayerClock clock) + public PlayerArea(int userId, CatchUpSpectatorPlayerClock clock) { UserId = userId; GameplayClock = clock; From 995e6664b612aac7d2c8565b8ab1a839c227bab8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:07:04 +0900 Subject: [PATCH 0647/2686] Rename spectator clock sync classes --- .../OnlinePlay/TestSceneCatchUpSyncManager.cs | 38 +++++++++---------- .../TestSceneMultiSpectatorScreen.cs | 4 +- .../Spectate/MultiSpectatorPlayer.cs | 8 ++-- .../Spectate/MultiSpectatorScreen.cs | 6 +-- .../Multiplayer/Spectate/PlayerArea.cs | 6 +-- ...PlayerClock.cs => SpectatorPlayerClock.cs} | 10 ++--- ...SyncManager.cs => SpectatorSyncManager.cs} | 22 +++++------ 7 files changed, 47 insertions(+), 47 deletions(-) rename osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/{CatchUpSpectatorPlayerClock.cs => SpectatorPlayerClock.cs} (88%) rename osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/{CatchUpSyncManager.cs => SpectatorSyncManager.cs} (86%) diff --git a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs index 263ce7c9bd..5761a89ae8 100644 --- a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs +++ b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs @@ -19,20 +19,20 @@ namespace osu.Game.Tests.OnlinePlay public class TestSceneCatchUpSyncManager : OsuTestScene { private GameplayClockContainer master; - private CatchUpSyncManager syncManager; + private SpectatorSyncManager syncManager; - private Dictionary clocksById; - private CatchUpSpectatorPlayerClock player1; - private CatchUpSpectatorPlayerClock player2; + private Dictionary clocksById; + private SpectatorPlayerClock player1; + private SpectatorPlayerClock player2; [SetUp] public void Setup() { - syncManager = new CatchUpSyncManager(master = new GameplayClockContainer(new TestManualClock())); + syncManager = new SpectatorSyncManager(master = new GameplayClockContainer(new TestManualClock())); player1 = syncManager.CreateManagedClock(); player2 = syncManager.CreateManagedClock(); - clocksById = new Dictionary + clocksById = new Dictionary { { player1, 1 }, { player2, 2 } @@ -64,7 +64,7 @@ namespace osu.Game.Tests.OnlinePlay public void TestReadyPlayersStartWhenReadyForMaximumDelayTime() { setWaiting(() => player1, false); - AddWaitStep($"wait {CatchUpSyncManager.MAXIMUM_START_DELAY} milliseconds", (int)Math.Ceiling(CatchUpSyncManager.MAXIMUM_START_DELAY / TimePerAction)); + AddWaitStep($"wait {SpectatorSyncManager.MAXIMUM_START_DELAY} milliseconds", (int)Math.Ceiling(SpectatorSyncManager.MAXIMUM_START_DELAY / TimePerAction)); assertPlayerClockState(() => player1, true); assertPlayerClockState(() => player2, false); } @@ -74,7 +74,7 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setMasterTime(CatchUpSyncManager.SYNC_TARGET + 1); + setMasterTime(SpectatorSyncManager.SYNC_TARGET + 1); assertCatchingUp(() => player1, false); } @@ -83,7 +83,7 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setMasterTime(CatchUpSyncManager.MAX_SYNC_OFFSET + 1); + setMasterTime(SpectatorSyncManager.MAX_SYNC_OFFSET + 1); assertCatchingUp(() => player1, true); assertCatchingUp(() => player2, true); } @@ -93,8 +93,8 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setMasterTime(CatchUpSyncManager.MAX_SYNC_OFFSET + 1); - setPlayerClockTime(() => player1, CatchUpSyncManager.SYNC_TARGET + 1); + setMasterTime(SpectatorSyncManager.MAX_SYNC_OFFSET + 1); + setPlayerClockTime(() => player1, SpectatorSyncManager.SYNC_TARGET + 1); assertCatchingUp(() => player1, true); } @@ -103,8 +103,8 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setMasterTime(CatchUpSyncManager.MAX_SYNC_OFFSET + 2); - setPlayerClockTime(() => player1, CatchUpSyncManager.SYNC_TARGET); + setMasterTime(SpectatorSyncManager.MAX_SYNC_OFFSET + 2); + setPlayerClockTime(() => player1, SpectatorSyncManager.SYNC_TARGET); assertCatchingUp(() => player1, false); assertCatchingUp(() => player2, true); } @@ -114,7 +114,7 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setPlayerClockTime(() => player1, -CatchUpSyncManager.SYNC_TARGET); + setPlayerClockTime(() => player1, -SpectatorSyncManager.SYNC_TARGET); assertCatchingUp(() => player1, false); assertPlayerClockState(() => player1, true); } @@ -124,7 +124,7 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setPlayerClockTime(() => player1, -CatchUpSyncManager.SYNC_TARGET - 1); + setPlayerClockTime(() => player1, -SpectatorSyncManager.SYNC_TARGET - 1); // This is a silent catchup, where IsCatchingUp = false but IsRunning = false also. assertCatchingUp(() => player1, false); @@ -145,7 +145,7 @@ namespace osu.Game.Tests.OnlinePlay assertPlayerClockState(() => player1, false); } - private void setWaiting(Func playerClock, bool waiting) + private void setWaiting(Func playerClock, bool waiting) => AddStep($"set player clock {clocksById[playerClock()]} waiting = {waiting}", () => playerClock().WaitingOnFrames.Value = waiting); private void setAllWaiting(bool waiting) => AddStep($"set all player clocks waiting = {waiting}", () => @@ -160,13 +160,13 @@ namespace osu.Game.Tests.OnlinePlay /// /// clock.Time = master.Time - offsetFromMaster /// - private void setPlayerClockTime(Func playerClock, double offsetFromMaster) + private void setPlayerClockTime(Func playerClock, double offsetFromMaster) => AddStep($"set player clock {clocksById[playerClock()]} = master - {offsetFromMaster}", () => playerClock().Seek(master.CurrentTime - offsetFromMaster)); - private void assertCatchingUp(Func playerClock, bool catchingUp) => + private void assertCatchingUp(Func playerClock, bool catchingUp) => AddAssert($"player clock {clocksById[playerClock()]} {(catchingUp ? "is" : "is not")} catching up", () => playerClock().IsCatchingUp == catchingUp); - private void assertPlayerClockState(Func playerClock, bool running) + private void assertPlayerClockState(Func playerClock, bool running) => AddAssert($"player clock {clocksById[playerClock()]} {(running ? "is" : "is not")} running", () => playerClock().IsRunning == running); private class TestManualClock : ManualClock, IAdjustableClock diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index a2e3ab7318..bab613bed7 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -202,7 +202,7 @@ namespace osu.Game.Tests.Visual.Multiplayer checkPausedInstant(PLAYER_2_ID, true); // Wait for the start delay seconds... - AddWaitStep("wait maximum start delay seconds", (int)(CatchUpSyncManager.MAXIMUM_START_DELAY / TimePerAction)); + AddWaitStep("wait maximum start delay seconds", (int)(SpectatorSyncManager.MAXIMUM_START_DELAY / TimePerAction)); // Player 1 should start playing by itself, player 2 should remain paused. checkPausedInstant(PLAYER_1_ID, false); @@ -318,7 +318,7 @@ namespace osu.Game.Tests.Visual.Multiplayer loadSpectateScreen(); sendFrames(PLAYER_1_ID, 300); - AddWaitStep("wait maximum start delay seconds", (int)(CatchUpSyncManager.MAXIMUM_START_DELAY / TimePerAction)); + AddWaitStep("wait maximum start delay seconds", (int)(SpectatorSyncManager.MAXIMUM_START_DELAY / TimePerAction)); checkPaused(PLAYER_1_ID, false); sendFrames(PLAYER_2_ID, 300); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 4821eb69c6..8445a6fdf0 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -15,14 +15,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public class MultiSpectatorPlayer : SpectatorPlayer { private readonly Bindable waitingOnFrames = new Bindable(true); - private readonly CatchUpSpectatorPlayerClock spectatorPlayerClock; + private readonly SpectatorPlayerClock spectatorPlayerClock; /// /// Creates a new . /// /// The score containing the player's replay. /// The clock controlling the gameplay running state. - public MultiSpectatorPlayer(Score score, CatchUpSpectatorPlayerClock spectatorPlayerClock) + public MultiSpectatorPlayer(Score score, SpectatorPlayerClock spectatorPlayerClock) : base(score, new PlayerConfiguration { AllowUserInteraction = false }) { this.spectatorPlayerClock = spectatorPlayerClock; @@ -40,9 +40,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate protected override void Update() { // The player clock's running state is controlled externally, but the local pausing state needs to be updated to start/stop gameplay. - CatchUpSpectatorPlayerClock catchUpClock = (CatchUpSpectatorPlayerClock)GameplayClockContainer.SourceClock; + SpectatorPlayerClock clock = (SpectatorPlayerClock)GameplayClockContainer.SourceClock; - if (catchUpClock.IsRunning) + if (clock.IsRunning) GameplayClockContainer.Start(); else GameplayClockContainer.Stop(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index ac66aa160c..8af5a640fa 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly PlayerArea[] instances; private MasterGameplayClockContainer masterClockContainer = null!; - private CatchUpSyncManager syncManager = null!; + private SpectatorSyncManager syncManager = null!; private PlayerGrid grid = null!; private MultiSpectatorLeaderboard leaderboard = null!; private PlayerArea? currentAudioSource; @@ -81,7 +81,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate InternalChildren = new[] { - (Drawable)(syncManager = new CatchUpSyncManager(masterClockContainer)), + (Drawable)(syncManager = new SpectatorSyncManager(masterClockContainer)), masterClockContainer.WithChild(new GridContainer { RelativeSizeAxes = Axes.Both, @@ -177,7 +177,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } } - private bool isCandidateAudioSource(CatchUpSpectatorPlayerClock? clock) + private bool isCandidateAudioSource(SpectatorPlayerClock? clock) => clock?.IsRunning == true && !clock.IsCatchingUp && !clock.WaitingOnFrames.Value; private void onReadyToStart() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index 451f4e0b79..a1fbdc10de 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -38,9 +38,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public readonly int UserId; /// - /// The used to control the gameplay running state of a loaded . + /// The used to control the gameplay running state of a loaded . /// - public readonly CatchUpSpectatorPlayerClock GameplayClock; + public readonly SpectatorPlayerClock GameplayClock; /// /// The currently-loaded score. @@ -55,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly LoadingLayer loadingLayer; private OsuScreenStack? stack; - public PlayerArea(int userId, CatchUpSpectatorPlayerClock clock) + public PlayerArea(int userId, SpectatorPlayerClock clock) { UserId = userId; GameplayClock = clock; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs similarity index 88% rename from osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 15821fb133..729a120dc1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -9,9 +9,9 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// A which catches up using rate adjustment. + /// A clock which catches up using rate adjustment. /// - public class CatchUpSpectatorPlayerClock : IFrameBasedClock, IAdjustableClock + public class SpectatorPlayerClock : IFrameBasedClock, IAdjustableClock { /// /// The catch up rate. @@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public bool IsRunning { get; private set; } - public CatchUpSpectatorPlayerClock(GameplayClockContainer masterClock) + public SpectatorPlayerClock(GameplayClockContainer masterClock) { this.masterClock = masterClock; } @@ -32,12 +32,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public void Reset() => CurrentTime = 0; /// - /// Starts this . + /// Starts this . /// public void Start() => IsRunning = true; /// - /// Stops this . + /// Stops this . /// public void Stop() => IsRunning = false; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs similarity index 86% rename from osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index 71fbb8cbee..d2f2efffc9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -11,9 +11,9 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// Manages the synchronisation between one or more s in relation to a master clock. + /// Manages the synchronisation between one or more s in relation to a master clock. /// - public class CatchUpSyncManager : Component + public class SpectatorSyncManager : Component { /// /// The offset from the master clock to which player clocks should remain within to be considered in-sync. @@ -48,34 +48,34 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The player clocks. /// - private readonly List playerClocks = new List(); + private readonly List playerClocks = new List(); private readonly Bindable masterState = new Bindable(); private bool hasStarted; private double? firstStartAttemptTime; - public CatchUpSyncManager(GameplayClockContainer master) + public SpectatorSyncManager(GameplayClockContainer master) { MasterClock = master; } /// - /// Create a new managed . + /// Create a new managed . /// - /// The newly created . - public CatchUpSpectatorPlayerClock CreateManagedClock() + /// The newly created . + public SpectatorPlayerClock CreateManagedClock() { - var clock = new CatchUpSpectatorPlayerClock(MasterClock); + var clock = new SpectatorPlayerClock(MasterClock); playerClocks.Add(clock); return clock; } /// - /// Removes an , stopping it from being managed by this . + /// Removes an , stopping it from being managed by this . /// - /// The to remove. - public void RemoveManagedClock(CatchUpSpectatorPlayerClock clock) + /// The to remove. + public void RemoveManagedClock(SpectatorPlayerClock clock) { playerClocks.Remove(clock); clock.Stop(); From 0c9a4ec13cab46f49bd04da9b03897a3c523cc16 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:09:00 +0900 Subject: [PATCH 0648/2686] Don't expose `MasterClock` in `SpectatorClockSyncManager` --- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../Spectate/SpectatorSyncManager.cs | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 8af5a640fa..b285d3d7c2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -169,7 +169,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate if (!isCandidateAudioSource(currentAudioSource?.GameplayClock)) { currentAudioSource = instances.Where(i => isCandidateAudioSource(i.GameplayClock)) - .OrderBy(i => Math.Abs(i.GameplayClock.CurrentTime - syncManager.MasterClock.CurrentTime)) + .OrderBy(i => Math.Abs(i.GameplayClock.CurrentTime - syncManager.CurrentMasterTime)) .FirstOrDefault(); foreach (var instance in instances) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index d2f2efffc9..aa6fb878b3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -35,16 +35,18 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public event Action? ReadyToStart; - /// - /// The master clock which is used to control the timing of all player clocks clocks. - /// - public GameplayClockContainer MasterClock { get; } - /// /// The catch-up state of the master clock. /// public IBindable MasterState => masterState; + public double CurrentMasterTime => masterClock.CurrentTime; + + /// + /// The master clock which is used to control the timing of all player clocks clocks. + /// + private GameplayClockContainer masterClock { get; } + /// /// The player clocks. /// @@ -57,7 +59,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public SpectatorSyncManager(GameplayClockContainer master) { - MasterClock = master; + masterClock = master; } /// @@ -66,7 +68,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// The newly created . public SpectatorPlayerClock CreateManagedClock() { - var clock = new SpectatorPlayerClock(MasterClock); + var clock = new SpectatorPlayerClock(masterClock); playerClocks.Add(clock); return clock; } @@ -142,7 +144,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate // How far this player's clock is out of sync, compared to the master clock. // A negative value means the player is running fast (ahead); a positive value means the player is running behind (catching up). - double timeDelta = MasterClock.CurrentTime - clock.CurrentTime; + double timeDelta = masterClock.CurrentTime - clock.CurrentTime; // Check that the player clock isn't too far ahead. // This is a quiet case in which the catchup is done by the master clock, so IsCatchingUp is not set on the player clock. From a86fc6f248b3c4712a9542409de54c8608d973a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:17:56 +0900 Subject: [PATCH 0649/2686] Change running state of `SpectatorPlayerClock` using `IsRunning` --- .../Spectate/SpectatorPlayerClock.cs | 50 ++++++++----------- .../Spectate/SpectatorSyncManager.cs | 11 ++-- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 729a120dc1..4e785ad3b1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -22,7 +22,24 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public double CurrentTime { get; private set; } - public bool IsRunning { get; private set; } + /// + /// Whether this clock is waiting on frames to continue playback. + /// + public Bindable WaitingOnFrames { get; } = new Bindable(true); + + /// + /// Whether this clock is behind the master clock and running at a higher rate to catch up to it. + /// + /// + /// Of note, this will be false if this clock is *ahead* of the master clock. + /// + public bool IsCatchingUp { get; set; } + + /// + /// Whether this spectator clock should be running. + /// Use instead of / to control time. + /// + public bool IsRunning { get; set; } public SpectatorPlayerClock(GameplayClockContainer masterClock) { @@ -31,24 +48,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public void Reset() => CurrentTime = 0; - /// - /// Starts this . - /// - public void Start() => IsRunning = true; - - /// - /// Stops this . - /// - public void Stop() => IsRunning = false; - - void IAdjustableClock.Start() + public void Start() { - // Our running state should only be managed by an ISyncManager, ignore calls from external sources. + // Our running state should only be managed by SpectatorSyncManager via IsRunning. } - void IAdjustableClock.Stop() + public void Stop() { - // Our running state should only be managed by an ISyncManager, ignore calls from external sources. + // Our running state should only be managed by an SpectatorSyncManager via IsRunning. } public bool Seek(double position) @@ -94,18 +101,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public double FramesPerSecond { get; private set; } public FrameTimeInfo TimeInfo => new FrameTimeInfo { Elapsed = ElapsedFrameTime, Current = CurrentTime }; - - /// - /// Whether this clock is waiting on frames to continue playback. - /// - public Bindable WaitingOnFrames { get; } = new Bindable(true); - - /// - /// Whether this clock is behind the master clock and running at a higher rate to catch up to it. - /// - /// - /// Of note, this will be false if this clock is *ahead* of the master clock. - /// - public bool IsCatchingUp { get; set; } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index aa6fb878b3..7ec8f45b1f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -80,7 +80,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public void RemoveManagedClock(SpectatorPlayerClock clock) { playerClocks.Remove(clock); - clock.Stop(); + clock.IsRunning = false; } protected override void Update() @@ -91,7 +91,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { // Ensure all player clocks are stopped until the start succeeds. foreach (var clock in playerClocks) - clock.Stop(); + clock.IsRunning = true; return; } @@ -153,15 +153,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate // Importantly, set the clock to a non-catchup state. if this isn't done, updateMasterState may incorrectly pause the master clock // when it is required to be running (ie. if all players are ahead of the master). clock.IsCatchingUp = false; - clock.Stop(); + clock.IsRunning = false; continue; } // Make sure the player clock is running if it can. - if (!clock.WaitingOnFrames.Value) - clock.Start(); - else - clock.Stop(); + clock.IsRunning = !clock.WaitingOnFrames.Value; if (clock.IsCatchingUp) { From b6254a1f252f55750cb66a9033f8e65719b35291 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:23:31 +0900 Subject: [PATCH 0650/2686] Remove unnecessary casting --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 8445a6fdf0..57af929cb7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -40,9 +40,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate protected override void Update() { // The player clock's running state is controlled externally, but the local pausing state needs to be updated to start/stop gameplay. - SpectatorPlayerClock clock = (SpectatorPlayerClock)GameplayClockContainer.SourceClock; - - if (clock.IsRunning) + if (GameplayClockContainer.SourceClock.IsRunning) GameplayClockContainer.Start(); else GameplayClockContainer.Stop(); From 0b271fe4b3ae9a9e4aa78cb138136a37bcba342c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:27:31 +0900 Subject: [PATCH 0651/2686] Fix incorrect `IsRunning` value --- .../OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index 7ec8f45b1f..c7b70cc6c7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -91,7 +91,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { // Ensure all player clocks are stopped until the start succeeds. foreach (var clock in playerClocks) - clock.IsRunning = true; + clock.IsRunning = false; return; } From b4eede61fb6c1b2dbfd13e262d9c90c1ac42400f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:28:18 +0900 Subject: [PATCH 0652/2686] Use `readonly` instead of `get-only` --- .../OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index c7b70cc6c7..119e82a682 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The master clock which is used to control the timing of all player clocks clocks. /// - private GameplayClockContainer masterClock { get; } + private readonly GameplayClockContainer masterClock; /// /// The player clocks. From c7d4c739aa067825e89a97f11a8d3ae3e4965602 Mon Sep 17 00:00:00 2001 From: Khang Date: Wed, 24 Aug 2022 02:53:55 -0400 Subject: [PATCH 0653/2686] Add a basic NaN control point test for LegacyBeatmapDecoder --- .../Formats/LegacyBeatmapDecoderTest.cs | 27 +++++++++++++++++++ .../Resources/nan-control-points.osu | 15 +++++++++++ 2 files changed, 42 insertions(+) create mode 100644 osu.Game.Tests/Resources/nan-control-points.osu diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 9acd3a6cab..7bd32eb5bd 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -919,5 +919,32 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.That(controlPoints[1].Position, Is.Not.EqualTo(Vector2.Zero)); } } + + [Test] + public void TestNaNControlPoints() + { + var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false }; + + using (var resStream = TestResources.OpenResource("nan-control-points.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + var controlPoints = (LegacyControlPointInfo)decoder.Decode(stream).ControlPointInfo; + + Assert.That(controlPoints.TimingPoints.Count, Is.EqualTo(1)); + Assert.That(controlPoints.DifficultyPoints.Count, Is.EqualTo(3)); + + Assert.That(controlPoints.TimingPointAt(1000).BeatLength, Is.EqualTo(500)); + + Assert.That(controlPoints.DifficultyPointAt(1000).SliderVelocity, Is.EqualTo(1)); + Assert.That(controlPoints.DifficultyPointAt(2000).SliderVelocity, Is.EqualTo(1)); + Assert.That(controlPoints.DifficultyPointAt(3000).SliderVelocity, Is.EqualTo(1)); + +#pragma warning disable 618 + Assert.That(((LegacyBeatmapDecoder.LegacyDifficultyControlPoint)controlPoints.DifficultyPointAt(1000)).GenerateTicks, Is.True); + Assert.That(((LegacyBeatmapDecoder.LegacyDifficultyControlPoint)controlPoints.DifficultyPointAt(2000)).GenerateTicks, Is.False); + Assert.That(((LegacyBeatmapDecoder.LegacyDifficultyControlPoint)controlPoints.DifficultyPointAt(3000)).GenerateTicks, Is.True); +#pragma warning restore 618 + } + } } } diff --git a/osu.Game.Tests/Resources/nan-control-points.osu b/osu.Game.Tests/Resources/nan-control-points.osu new file mode 100644 index 0000000000..dcaa705116 --- /dev/null +++ b/osu.Game.Tests/Resources/nan-control-points.osu @@ -0,0 +1,15 @@ +osu file format v14 + +[TimingPoints] + +// NaN bpm (should be rejected) +0,NaN,4,2,0,100,1,0 + +// 120 bpm +1000,500,4,2,0,100,1,0 + +// NaN slider velocity +2000,NaN,4,3,0,100,0,1 + +// 1.0x slider velocity +3000,-100,4,3,0,100,0,1 \ No newline at end of file From 9c6968e96dfb322cbcc08a17dcd5ed0dbaf6ea00 Mon Sep 17 00:00:00 2001 From: Khang Date: Wed, 24 Aug 2022 02:54:40 -0400 Subject: [PATCH 0654/2686] Remove unused import in Slider --- osu.Game.Rulesets.Osu/Objects/Slider.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index a7495a2809..e3c1b1e168 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -15,7 +15,6 @@ using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Formats; -using osu.Game.Beatmaps.Legacy; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Scoring; From 7e5086c8d79dd1c440a30dfde936ae496b0a1ebf Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 24 Aug 2022 09:50:29 +0300 Subject: [PATCH 0655/2686] Fix spectator client not handling multiple watch calls properly --- osu.Game/Online/Spectator/SpectatorClient.cs | 32 ++++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index 745c968992..f1ce6258d6 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -65,11 +65,12 @@ namespace osu.Game.Online.Spectator public virtual event Action? OnUserFinishedPlaying; /// - /// All users currently being watched. + /// A dictionary containing all users currently being watched, with the number of watching components for each user. /// - private readonly List watchedUsers = new List(); + private readonly Dictionary watchedUsers = new Dictionary(); private readonly BindableDictionary watchedUserStates = new BindableDictionary(); + private readonly BindableList playingUsers = new BindableList(); private readonly SpectatorState currentState = new SpectatorState(); @@ -94,12 +95,15 @@ namespace osu.Game.Online.Spectator if (connected.NewValue) { // get all the users that were previously being watched - int[] users = watchedUsers.ToArray(); + var users = new Dictionary(watchedUsers); watchedUsers.Clear(); // resubscribe to watched users. - foreach (int userId in users) - WatchUser(userId); + foreach ((int user, int watchers) in users) + { + for (int i = 0; i < watchers; i++) + WatchUser(user); + } // re-send state in case it wasn't received if (IsPlaying) @@ -121,7 +125,7 @@ namespace osu.Game.Online.Spectator if (!playingUsers.Contains(userId)) playingUsers.Add(userId); - if (watchedUsers.Contains(userId)) + if (watchedUsers.ContainsKey(userId)) watchedUserStates[userId] = state; OnUserBeganPlaying?.Invoke(userId, state); @@ -136,7 +140,7 @@ namespace osu.Game.Online.Spectator { playingUsers.Remove(userId); - if (watchedUsers.Contains(userId)) + if (watchedUsers.ContainsKey(userId)) watchedUserStates[userId] = state; OnUserFinishedPlaying?.Invoke(userId, state); @@ -232,11 +236,13 @@ namespace osu.Game.Online.Spectator { Debug.Assert(ThreadSafety.IsUpdateThread); - if (watchedUsers.Contains(userId)) + if (watchedUsers.ContainsKey(userId)) + { + watchedUsers[userId]++; return; + } - watchedUsers.Add(userId); - + watchedUsers.Add(userId, 1); WatchUserInternal(userId); } @@ -246,6 +252,12 @@ namespace osu.Game.Online.Spectator // Todo: This should not be a thing, but requires framework changes. Schedule(() => { + if (watchedUsers.TryGetValue(userId, out int watchers) && watchers > 1) + { + watchedUsers[userId]--; + return; + } + watchedUsers.Remove(userId); watchedUserStates.Remove(userId); StopWatchingUserInternal(userId); From 2fa8b61f3c0bb3f5065aa6f3cc2ad7dfb6f43d2e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 6 Aug 2022 05:51:57 +0300 Subject: [PATCH 0656/2686] Handle completion user state updates during spectating --- osu.Game/Screens/Spectate/SpectatorScreen.cs | 46 ++++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/osu.Game/Screens/Spectate/SpectatorScreen.cs b/osu.Game/Screens/Spectate/SpectatorScreen.cs index 0c1fe56eb6..8218ddf641 100644 --- a/osu.Game/Screens/Spectate/SpectatorScreen.cs +++ b/osu.Game/Screens/Spectate/SpectatorScreen.cs @@ -115,13 +115,13 @@ namespace osu.Game.Screens.Spectate { case NotifyDictionaryChangedAction.Add: case NotifyDictionaryChangedAction.Replace: - foreach ((int userId, var state) in e.NewItems.AsNonNull()) + foreach ((int userId, SpectatorState state) in e.NewItems.AsNonNull()) onUserStateChanged(userId, state); break; case NotifyDictionaryChangedAction.Remove: foreach ((int userId, SpectatorState state) in e.OldItems.AsNonNull()) - onUserStateRemoved(userId, state); + onUserStateChanged(userId, state); break; } } @@ -136,33 +136,19 @@ namespace osu.Game.Screens.Spectate switch (newState.State) { - case SpectatedUserState.Passed: - // Make sure that gameplay completes to the end. - if (gameplayStates.TryGetValue(userId, out var gameplayState)) - gameplayState.Score.Replay.HasReceivedAllFrames = true; - break; - case SpectatedUserState.Playing: Schedule(() => OnNewPlayingUserState(userId, newState)); startGameplay(userId); break; + + case SpectatedUserState.Passed: + case SpectatedUserState.Failed: + case SpectatedUserState.Quit: + endGameplay(userId, newState); + break; } } - private void onUserStateRemoved(int userId, SpectatorState state) - { - if (!userMap.ContainsKey(userId)) - return; - - if (!gameplayStates.TryGetValue(userId, out var gameplayState)) - return; - - gameplayState.Score.Replay.HasReceivedAllFrames = true; - - gameplayStates.Remove(userId); - Schedule(() => EndGameplay(userId, state)); - } - private void startGameplay(int userId) { Debug.Assert(userMap.ContainsKey(userId)); @@ -196,6 +182,20 @@ namespace osu.Game.Screens.Spectate Schedule(() => StartGameplay(userId, gameplayState)); } + private void endGameplay(int userId, SpectatorState state) + { + if (!userMap.ContainsKey(userId)) + return; + + if (!gameplayStates.TryGetValue(userId, out var gameplayState)) + return; + + gameplayState.Score.Replay.HasReceivedAllFrames = true; + + gameplayStates.Remove(userId); + Schedule(() => EndGameplay(userId, state)); + } + /// /// Invoked when a spectated user's state has changed to a new state indicating the player is currently playing. /// @@ -226,7 +226,7 @@ namespace osu.Game.Screens.Spectate if (!userStates.TryGetValue(userId, out var state)) return; - onUserStateRemoved(userId, state); + endGameplay(userId, state); users.Remove(userId); userMap.Remove(userId); From b564c34dbc29a9c821da648177e9051a7a5bb431 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:35:30 +0900 Subject: [PATCH 0657/2686] Don't process master clock (is a noop) --- .../OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 4e785ad3b1..764ab60d6b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -83,8 +83,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate ElapsedFrameTime = 0; FramesPerSecond = 0; - masterClock.ProcessFrame(); - if (IsRunning) { double elapsedSource = masterClock.ElapsedFrameTime; From 2f5be6efcaecc48c7e6c87cb8a73c19ce2f224f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:37:14 +0900 Subject: [PATCH 0658/2686] Tidy up `ProcessFrame` and privatise const --- .../Multiplayer/Spectate/SpectatorPlayerClock.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 764ab60d6b..be9f7f2bf0 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The catch up rate. /// - public const double CATCHUP_RATE = 2; + private const double catchup_rate = 2; private readonly GameplayClockContainer masterClock; @@ -68,7 +68,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { } - public double Rate => IsCatchingUp ? CATCHUP_RATE : 1; + public double Rate => IsCatchingUp ? catchup_rate : 1; double IAdjustableClock.Rate { @@ -76,13 +76,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate set => throw new NotSupportedException(); } - double IClock.Rate => Rate; - public void ProcessFrame() { - ElapsedFrameTime = 0; - FramesPerSecond = 0; - if (IsRunning) { double elapsedSource = masterClock.ElapsedFrameTime; @@ -92,6 +87,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate ElapsedFrameTime = elapsed; FramesPerSecond = masterClock.FramesPerSecond; } + else + { + ElapsedFrameTime = 0; + FramesPerSecond = 0; + } } public double ElapsedFrameTime { get; private set; } From d05d8aeb2289e6395f800ea724491081aa25a9d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:38:25 +0900 Subject: [PATCH 0659/2686] Simplify interface implementations --- .../Multiplayer/Spectate/SpectatorPlayerClock.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index be9f7f2bf0..6f2d1701c9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -68,12 +68,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { } - public double Rate => IsCatchingUp ? catchup_rate : 1; - - double IAdjustableClock.Rate + public double Rate { - get => Rate; - set => throw new NotSupportedException(); + get => IsCatchingUp ? catchup_rate : 1; + set => throw new NotImplementedException(); } public void ProcessFrame() From d33d705684512d2c3f3b58fcb2d0b14662f4ee5b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:40:47 +0900 Subject: [PATCH 0660/2686] Make `WaitingOnFrames` non-bindable --- osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs | 6 +++--- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs | 6 +----- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs | 2 +- .../OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs | 3 +-- .../OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs | 4 ++-- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs index 5761a89ae8..6015c92663 100644 --- a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs +++ b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs @@ -146,12 +146,12 @@ namespace osu.Game.Tests.OnlinePlay } private void setWaiting(Func playerClock, bool waiting) - => AddStep($"set player clock {clocksById[playerClock()]} waiting = {waiting}", () => playerClock().WaitingOnFrames.Value = waiting); + => AddStep($"set player clock {clocksById[playerClock()]} waiting = {waiting}", () => playerClock().WaitingOnFrames = waiting); private void setAllWaiting(bool waiting) => AddStep($"set all player clocks waiting = {waiting}", () => { - player1.WaitingOnFrames.Value = waiting; - player2.WaitingOnFrames.Value = waiting; + player1.WaitingOnFrames = waiting; + player2.WaitingOnFrames = waiting; }); private void setMasterTime(double time) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 57af929cb7..d351d121c6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -14,7 +13,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public class MultiSpectatorPlayer : SpectatorPlayer { - private readonly Bindable waitingOnFrames = new Bindable(true); private readonly SpectatorPlayerClock spectatorPlayerClock; /// @@ -31,8 +29,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate [BackgroundDependencyLoader] private void load() { - spectatorPlayerClock.WaitingOnFrames.BindTo(waitingOnFrames); - HUDOverlay.PlayerSettingsOverlay.Expire(); HUDOverlay.HoldToQuit.Expire(); } @@ -53,7 +49,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate base.UpdateAfterChildren(); // This is required because the frame stable clock is set to WaitingOnFrames = false for one frame. - waitingOnFrames.Value = DrawableRuleset.FrameStableClock.WaitingOnFrames.Value || Score.Replay.Frames.Count == 0; + spectatorPlayerClock.WaitingOnFrames = DrawableRuleset.FrameStableClock.WaitingOnFrames.Value || Score.Replay.Frames.Count == 0; } protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index b285d3d7c2..8130620312 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -178,7 +178,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } private bool isCandidateAudioSource(SpectatorPlayerClock? clock) - => clock?.IsRunning == true && !clock.IsCatchingUp && !clock.WaitingOnFrames.Value; + => clock?.IsRunning == true && !clock.IsCatchingUp && !clock.WaitingOnFrames; private void onReadyToStart() { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 6f2d1701c9..7801f22437 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Bindables; using osu.Framework.Timing; using osu.Game.Screens.Play; @@ -25,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// Whether this clock is waiting on frames to continue playback. /// - public Bindable WaitingOnFrames { get; } = new Bindable(true); + public bool WaitingOnFrames { get; set; } = true; /// /// Whether this clock is behind the master clock and running at a higher rate to catch up to it. diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index 119e82a682..dcc034cba6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -111,7 +111,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate if (playerClocks.Count == 0) return false; - int readyCount = playerClocks.Count(s => !s.WaitingOnFrames.Value); + int readyCount = playerClocks.Count(s => !s.WaitingOnFrames); if (readyCount == playerClocks.Count) return performStart(); @@ -158,7 +158,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } // Make sure the player clock is running if it can. - clock.IsRunning = !clock.WaitingOnFrames.Value; + clock.IsRunning = !clock.WaitingOnFrames; if (clock.IsCatchingUp) { From 683d49c6083fbb480fcd9ed12fd48786aed16704 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:51:54 +0900 Subject: [PATCH 0661/2686] Move `MasterClockState` handling in to `SpectatorSyncManager` --- .../Spectate/MultiSpectatorScreen.cs | 25 ----------------- .../Spectate/SpectatorSyncManager.cs | 27 +++++++++++++++---- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 8130620312..32ba73e904 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -4,11 +4,9 @@ using System; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; @@ -52,7 +50,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private PlayerGrid grid = null!; private MultiSpectatorLeaderboard leaderboard = null!; private PlayerArea? currentAudioSource; - private bool canStartMasterClock; private readonly Room room; private readonly MultiplayerRoomUser[] users; @@ -159,7 +156,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate masterClockContainer.Reset(); syncManager.ReadyToStart += onReadyToStart; - syncManager.MasterState.BindValueChanged(onMasterStateChanged, true); } protected override void Update() @@ -192,27 +188,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate masterClockContainer.StartTime = startTime; masterClockContainer.Reset(true); - - // Although the clock has been started, this flag is set to allow for later synchronisation state changes to also be able to start it. - canStartMasterClock = true; - } - - private void onMasterStateChanged(ValueChangedEvent state) - { - Logger.Log($"{nameof(MultiSpectatorScreen)}'s master clock become {state.NewValue}"); - - switch (state.NewValue) - { - case MasterClockState.Synchronised: - if (canStartMasterClock) - masterClockContainer.Start(); - - break; - - case MasterClockState.TooFarAhead: - masterClockContainer.Stop(); - break; - } } protected override void OnNewPlayingUserState(int userId, SpectatorState spectatorState) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index dcc034cba6..57c7c18db9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Logging; using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate @@ -35,11 +36,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public event Action? ReadyToStart; - /// - /// The catch-up state of the master clock. - /// - public IBindable MasterState => masterState; - public double CurrentMasterTime => masterClock.CurrentTime; /// @@ -55,11 +51,32 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly Bindable masterState = new Bindable(); private bool hasStarted; + private double? firstStartAttemptTime; public SpectatorSyncManager(GameplayClockContainer master) { masterClock = master; + + masterState.BindValueChanged(onMasterStateChanged); + } + + private void onMasterStateChanged(ValueChangedEvent state) + { + Logger.Log($"{nameof(SpectatorSyncManager)}'s master clock become {state.NewValue}"); + + switch (state.NewValue) + { + case MasterClockState.Synchronised: + if (hasStarted) + masterClock.Start(); + + break; + + case MasterClockState.TooFarAhead: + masterClock.Stop(); + break; + } } /// From 6c50f618a3989959b3ceab17962802abccf538d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:53:45 +0900 Subject: [PATCH 0662/2686] Don't use bindable flow for `masterState` --- .../Spectate/SpectatorSyncManager.cs | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index 57c7c18db9..af16d4e0ab 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Game.Screens.Play; @@ -48,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// private readonly List playerClocks = new List(); - private readonly Bindable masterState = new Bindable(); + private MasterClockState masterState = MasterClockState.Synchronised; private bool hasStarted; @@ -57,26 +56,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public SpectatorSyncManager(GameplayClockContainer master) { masterClock = master; - - masterState.BindValueChanged(onMasterStateChanged); - } - - private void onMasterStateChanged(ValueChangedEvent state) - { - Logger.Log($"{nameof(SpectatorSyncManager)}'s master clock become {state.NewValue}"); - - switch (state.NewValue) - { - case MasterClockState.Synchronised: - if (hasStarted) - masterClock.Start(); - - break; - - case MasterClockState.TooFarAhead: - masterClock.Stop(); - break; - } } /// @@ -197,8 +176,26 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// private void updateMasterState() { - bool anyInSync = playerClocks.Any(s => !s.IsCatchingUp); - masterState.Value = anyInSync ? MasterClockState.Synchronised : MasterClockState.TooFarAhead; + MasterClockState newState = playerClocks.Any(s => !s.IsCatchingUp) ? MasterClockState.Synchronised : MasterClockState.TooFarAhead; + + if (masterState == newState) + return; + + masterState = newState; + Logger.Log($"{nameof(SpectatorSyncManager)}'s master clock become {masterState}"); + + switch (masterState) + { + case MasterClockState.Synchronised: + if (hasStarted) + masterClock.Start(); + + break; + + case MasterClockState.TooFarAhead: + masterClock.Stop(); + break; + } } } } From 871365bbb01b8301333da9cd7d0b04d61f454fa4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:56:36 +0900 Subject: [PATCH 0663/2686] Inline `ReadyToStart` action binding for added safety --- .../Multiplayer/Spectate/MultiSpectatorScreen.cs | 9 +++++---- .../Multiplayer/Spectate/SpectatorSyncManager.cs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 32ba73e904..3b26fd9962 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -78,7 +78,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate InternalChildren = new[] { - (Drawable)(syncManager = new SpectatorSyncManager(masterClockContainer)), + (Drawable)(syncManager = new SpectatorSyncManager(masterClockContainer) + { + ReadyToStart = performInitialSeek, + }), masterClockContainer.WithChild(new GridContainer { RelativeSizeAxes = Axes.Both, @@ -154,8 +157,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate base.LoadComplete(); masterClockContainer.Reset(); - - syncManager.ReadyToStart += onReadyToStart; } protected override void Update() @@ -176,7 +177,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private bool isCandidateAudioSource(SpectatorPlayerClock? clock) => clock?.IsRunning == true && !clock.IsCatchingUp && !clock.WaitingOnFrames; - private void onReadyToStart() + private void performInitialSeek() { // Seek the master clock to the gameplay time. // This is chosen as the first available frame in the players' replays, which matches the seek by each individual SpectatorPlayer. diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index af16d4e0ab..8d087aa25c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// An event which is invoked when gameplay is ready to start. /// - public event Action? ReadyToStart; + public Action? ReadyToStart; public double CurrentMasterTime => masterClock.CurrentTime; From 7c1fc4814e02ff20a9709fa7e18160907d0104dc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 16:00:20 +0900 Subject: [PATCH 0664/2686] Remove unused `CreateMasterGameplayClockContainer` method --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 3b26fd9962..4cab377239 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; @@ -74,7 +73,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate FillFlowContainer leaderboardFlow; Container scoreDisplayContainer; - masterClockContainer = CreateMasterGameplayClockContainer(Beatmap.Value); + masterClockContainer = new MasterGameplayClockContainer(Beatmap.Value, 0); InternalChildren = new[] { @@ -230,7 +229,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate return base.OnBackButton(); } - - protected virtual MasterGameplayClockContainer CreateMasterGameplayClockContainer(WorkingBeatmap beatmap) => new MasterGameplayClockContainer(beatmap, 0); } } From edd50dc05bd787800609dc1d44f210f3965c2d1a Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Wed, 24 Aug 2022 03:07:03 -0400 Subject: [PATCH 0665/2686] Add profile url context menu to user container --- .../Profile/Header/TopHeaderContainer.cs | 144 +++++++++--------- 1 file changed, 75 insertions(+), 69 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 7e079c8341..67a6df3228 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; @@ -70,85 +71,90 @@ namespace osu.Game.Overlays.Profile.Header Masking = true, CornerRadius = avatar_size * 0.25f, }, - new Container + new OsuContextMenuContainer { RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, - Padding = new MarginPadding { Left = 10 }, - Children = new Drawable[] + Child = new Container { - new FillFlowContainer + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Padding = new MarginPadding { Left = 10 }, + Children = new Drawable[] { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] + new FillFlowContainer { - new FillFlowContainer + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] + new FillFlowContainer { - usernameText = new OsuSpriteText + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new Drawable[] { - Font = OsuFont.GetFont(size: 24, weight: FontWeight.Regular) - }, - openUserExternally = new ExternalLinkButton - { - Margin = new MarginPadding { Left = 5 }, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - } - }, - titleText = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 18, weight: FontWeight.Regular) - }, - } - }, - new FillFlowContainer - { - Origin = Anchor.BottomLeft, - Anchor = Anchor.BottomLeft, - Direction = FillDirection.Vertical, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - supporterTag = new SupporterIcon - { - Height = 20, - Margin = new MarginPadding { Top = 5 } - }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = 1.5f, - Margin = new MarginPadding { Top = 10 }, - Colour = colourProvider.Light1, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = 5 }, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - userFlag = new UpdateableFlag - { - Size = new Vector2(28, 20), - ShowPlaceholderOnUnknown = false, - }, - userCountryText = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 17.5f, weight: FontWeight.Regular), - Margin = new MarginPadding { Left = 10 }, - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - Colour = colourProvider.Light1, + usernameText = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 24, weight: FontWeight.Regular) + }, + openUserExternally = new ExternalLinkButton + { + Margin = new MarginPadding { Left = 5 }, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, } - } - }, + }, + titleText = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 18, weight: FontWeight.Regular) + }, + } + }, + new FillFlowContainer + { + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + Direction = FillDirection.Vertical, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + supporterTag = new SupporterIcon + { + Height = 20, + Margin = new MarginPadding { Top = 5 } + }, + new Box + { + RelativeSizeAxes = Axes.X, + Height = 1.5f, + Margin = new MarginPadding { Top = 10 }, + Colour = colourProvider.Light1, + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Margin = new MarginPadding { Top = 5 }, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + userFlag = new UpdateableFlag + { + Size = new Vector2(28, 20), + ShowPlaceholderOnUnknown = false, + }, + userCountryText = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 17.5f, weight: FontWeight.Regular), + Margin = new MarginPadding { Left = 10 }, + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + Colour = colourProvider.Light1, + } + } + }, + } } } } From 7f9246637a6276a70addae935aac728b1d86c833 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 16:08:48 +0900 Subject: [PATCH 0666/2686] Simplify `MultiSpectatorScreen` hierarchy construction --- .../Spectate/MultiSpectatorScreen.cs | 69 ++++++++++--------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 4cab377239..cb797d7aff 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -73,53 +73,54 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate FillFlowContainer leaderboardFlow; Container scoreDisplayContainer; - masterClockContainer = new MasterGameplayClockContainer(Beatmap.Value, 0); - - InternalChildren = new[] + InternalChildren = new Drawable[] { - (Drawable)(syncManager = new SpectatorSyncManager(masterClockContainer) + masterClockContainer = new MasterGameplayClockContainer(Beatmap.Value, 0) { - ReadyToStart = performInitialSeek, - }), - masterClockContainer.WithChild(new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, - Content = new[] + Child = new GridContainer { - new Drawable[] + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + Content = new[] { - scoreDisplayContainer = new Container + new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - }, - new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, - Content = new[] + scoreDisplayContainer = new Container { - new Drawable[] + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + }, + new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + Content = new[] { - leaderboardFlow = new FillFlowContainer + new Drawable[] { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(5) - }, - grid = new PlayerGrid { RelativeSizeAxes = Axes.Both } + leaderboardFlow = new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5) + }, + grid = new PlayerGrid { RelativeSizeAxes = Axes.Both } + } } } } } } - }) + }, + syncManager = new SpectatorSyncManager(masterClockContainer) + { + ReadyToStart = performInitialSeek, + } }; for (int i = 0; i < Users.Count; i++) From b24513038cd66941e26b304dd8667957850243e8 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Wed, 24 Aug 2022 02:54:24 -0400 Subject: [PATCH 0667/2686] Add popupdialog button to copy url --- osu.Game/Online/Chat/ExternalLinkOpener.cs | 2 +- osu.Game/Overlays/Chat/ExternalLinkDialog.cs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/ExternalLinkOpener.cs b/osu.Game/Online/Chat/ExternalLinkOpener.cs index e557b9933e..4141a6fb60 100644 --- a/osu.Game/Online/Chat/ExternalLinkOpener.cs +++ b/osu.Game/Online/Chat/ExternalLinkOpener.cs @@ -32,7 +32,7 @@ namespace osu.Game.Online.Chat public void OpenUrlExternally(string url, bool bypassWarning = false) { if (!bypassWarning && externalLinkWarning.Value) - dialogOverlay.Push(new ExternalLinkDialog(url, () => host.OpenUrlExternally(url))); + dialogOverlay.Push(new ExternalLinkDialog(url, () => host.OpenUrlExternally(url), () => host.GetClipboard().SetText(url))); else host.OpenUrlExternally(url); } diff --git a/osu.Game/Overlays/Chat/ExternalLinkDialog.cs b/osu.Game/Overlays/Chat/ExternalLinkDialog.cs index f0d39346e0..09650a13bd 100644 --- a/osu.Game/Overlays/Chat/ExternalLinkDialog.cs +++ b/osu.Game/Overlays/Chat/ExternalLinkDialog.cs @@ -11,7 +11,7 @@ namespace osu.Game.Overlays.Chat { public class ExternalLinkDialog : PopupDialog { - public ExternalLinkDialog(string url, Action openExternalLinkAction) + public ExternalLinkDialog(string url, Action openExternalLinkAction, Action copyExternalLinkAction) { HeaderText = "Just checking..."; BodyText = $"You are about to leave osu! and open the following link in a web browser:\n\n{url}"; @@ -25,6 +25,11 @@ namespace osu.Game.Overlays.Chat Text = @"Yes. Go for it.", Action = openExternalLinkAction }, + new PopupDialogOkButton + { + Text = @"No! Copy the URL instead!", + Action = copyExternalLinkAction + }, new PopupDialogCancelButton { Text = @"No! Abort mission!" From 8f4a2b4936636031bd394bd54a0ddd9b3129c86f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 8 Aug 2022 01:37:43 +0300 Subject: [PATCH 0668/2686] Separate passed/failed states from calling `EndGameplay` --- .../Spectate/MultiSpectatorScreen.cs | 13 +------ osu.Game/Screens/Play/SoloSpectator.cs | 2 +- osu.Game/Screens/Spectate/SpectatorScreen.cs | 34 ++++++++++++------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 3d04ae8f3c..9269433ac5 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -219,19 +219,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate protected override void StartGameplay(int userId, SpectatorGameplayState spectatorGameplayState) => instances.Single(i => i.UserId == userId).LoadScore(spectatorGameplayState.Score); - protected override void EndGameplay(int userId, SpectatorState state) + protected override void QuitGameplay(int userId) { - // Allowed passed/failed users to complete their remaining replay frames. - // The failed state isn't really possible in multiplayer (yet?) but is added here just for safety in case it starts being used. - if (state.State == SpectatedUserState.Passed || state.State == SpectatedUserState.Failed) - return; - - // we could also potentially receive EndGameplay with "Playing" state, at which point we can only early-return and hope it's a passing player. - // todo: this shouldn't exist, but it's here as a hotfix for an issue with multi-spectator screen not proceeding to results screen. - // see: https://github.com/ppy/osu/issues/19593 - if (state.State == SpectatedUserState.Playing) - return; - RemoveUser(userId); var instance = instances.Single(i => i.UserId == userId); diff --git a/osu.Game/Screens/Play/SoloSpectator.cs b/osu.Game/Screens/Play/SoloSpectator.cs index 7eaba40640..9ef05c3a05 100644 --- a/osu.Game/Screens/Play/SoloSpectator.cs +++ b/osu.Game/Screens/Play/SoloSpectator.cs @@ -182,7 +182,7 @@ namespace osu.Game.Screens.Play scheduleStart(spectatorGameplayState); } - protected override void EndGameplay(int userId, SpectatorState state) + protected override void QuitGameplay(int userId) { scheduledStart?.Cancel(); immediateSpectatorGameplayState = null; diff --git a/osu.Game/Screens/Spectate/SpectatorScreen.cs b/osu.Game/Screens/Spectate/SpectatorScreen.cs index 8218ddf641..7081db4793 100644 --- a/osu.Game/Screens/Spectate/SpectatorScreen.cs +++ b/osu.Game/Screens/Spectate/SpectatorScreen.cs @@ -142,9 +142,11 @@ namespace osu.Game.Screens.Spectate break; case SpectatedUserState.Passed: - case SpectatedUserState.Failed: + markReceivedAllFrames(userId); + break; + case SpectatedUserState.Quit: - endGameplay(userId, newState); + quitGameplay(userId); break; } } @@ -182,18 +184,27 @@ namespace osu.Game.Screens.Spectate Schedule(() => StartGameplay(userId, gameplayState)); } - private void endGameplay(int userId, SpectatorState state) + /// + /// Marks an existing gameplay session as received all frames. + /// + private void markReceivedAllFrames(int userId) + { + if (gameplayStates.TryGetValue(userId, out var gameplayState)) + gameplayState.Score.Replay.HasReceivedAllFrames = true; + } + + private void quitGameplay(int userId) { if (!userMap.ContainsKey(userId)) return; - if (!gameplayStates.TryGetValue(userId, out var gameplayState)) + if (!gameplayStates.ContainsKey(userId)) return; - gameplayState.Score.Replay.HasReceivedAllFrames = true; + markReceivedAllFrames(userId); gameplayStates.Remove(userId); - Schedule(() => EndGameplay(userId, state)); + Schedule(() => QuitGameplay(userId)); } /// @@ -211,11 +222,10 @@ namespace osu.Game.Screens.Spectate protected abstract void StartGameplay(int userId, [NotNull] SpectatorGameplayState spectatorGameplayState); /// - /// Ends gameplay for a user. + /// Quits gameplay for a user. /// - /// The user to end gameplay for. - /// The final user state. - protected abstract void EndGameplay(int userId, SpectatorState state); + /// The user to quit gameplay for. + protected abstract void QuitGameplay(int userId); /// /// Stops spectating a user. @@ -223,10 +233,10 @@ namespace osu.Game.Screens.Spectate /// The user to stop spectating. protected void RemoveUser(int userId) { - if (!userStates.TryGetValue(userId, out var state)) + if (!userStates.ContainsKey(userId)) return; - endGameplay(userId, state); + quitGameplay(userId); users.Remove(userId); userMap.Remove(userId); From adea29c10604fb50a91d680e751f744c84cfe559 Mon Sep 17 00:00:00 2001 From: Khang Date: Wed, 24 Aug 2022 03:37:33 -0400 Subject: [PATCH 0669/2686] Fix test failures --- osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 4 +--- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 7bd32eb5bd..9fc1eb7650 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -931,16 +931,14 @@ namespace osu.Game.Tests.Beatmaps.Formats var controlPoints = (LegacyControlPointInfo)decoder.Decode(stream).ControlPointInfo; Assert.That(controlPoints.TimingPoints.Count, Is.EqualTo(1)); - Assert.That(controlPoints.DifficultyPoints.Count, Is.EqualTo(3)); + Assert.That(controlPoints.DifficultyPoints.Count, Is.EqualTo(2)); Assert.That(controlPoints.TimingPointAt(1000).BeatLength, Is.EqualTo(500)); - Assert.That(controlPoints.DifficultyPointAt(1000).SliderVelocity, Is.EqualTo(1)); Assert.That(controlPoints.DifficultyPointAt(2000).SliderVelocity, Is.EqualTo(1)); Assert.That(controlPoints.DifficultyPointAt(3000).SliderVelocity, Is.EqualTo(1)); #pragma warning disable 618 - Assert.That(((LegacyBeatmapDecoder.LegacyDifficultyControlPoint)controlPoints.DifficultyPointAt(1000)).GenerateTicks, Is.True); Assert.That(((LegacyBeatmapDecoder.LegacyDifficultyControlPoint)controlPoints.DifficultyPointAt(2000)).GenerateTicks, Is.False); Assert.That(((LegacyBeatmapDecoder.LegacyDifficultyControlPoint)controlPoints.DifficultyPointAt(3000)).GenerateTicks, Is.True); #pragma warning restore 618 diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index c3fd16e86f..3d65ab8e0f 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -188,9 +188,8 @@ namespace osu.Game.Beatmaps.Formats } public override bool IsRedundant(ControlPoint? existing) - => existing is LegacyDifficultyControlPoint existingLegacyDifficulty - && base.IsRedundant(existing) - && GenerateTicks == existingLegacyDifficulty.GenerateTicks; + => base.IsRedundant(existing) + && GenerateTicks == ((existing as LegacyDifficultyControlPoint)?.GenerateTicks ?? true); public override void CopyFrom(ControlPoint other) { From ec5fd7ac1dc0bf84328a64a3b963bf1157ee6685 Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Wed, 24 Aug 2022 03:42:16 -0400 Subject: [PATCH 0670/2686] Remove possible 'System.NullReferenceException' --- osu.Game/Online/Chat/ExternalLinkOpener.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ExternalLinkOpener.cs b/osu.Game/Online/Chat/ExternalLinkOpener.cs index 4141a6fb60..4c5df9c917 100644 --- a/osu.Game/Online/Chat/ExternalLinkOpener.cs +++ b/osu.Game/Online/Chat/ExternalLinkOpener.cs @@ -32,7 +32,7 @@ namespace osu.Game.Online.Chat public void OpenUrlExternally(string url, bool bypassWarning = false) { if (!bypassWarning && externalLinkWarning.Value) - dialogOverlay.Push(new ExternalLinkDialog(url, () => host.OpenUrlExternally(url), () => host.GetClipboard().SetText(url))); + dialogOverlay.Push(new ExternalLinkDialog(url, () => host.OpenUrlExternally(url), () => host.GetClipboard()?.SetText(url))); else host.OpenUrlExternally(url); } From e378c5b866119b48a2b4ff96ed383706935ed60e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 24 Aug 2022 10:50:40 +0300 Subject: [PATCH 0671/2686] Remove no longer necessary switch case --- osu.Game/Screens/Spectate/SpectatorScreen.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game/Screens/Spectate/SpectatorScreen.cs b/osu.Game/Screens/Spectate/SpectatorScreen.cs index 7081db4793..259ac0160d 100644 --- a/osu.Game/Screens/Spectate/SpectatorScreen.cs +++ b/osu.Game/Screens/Spectate/SpectatorScreen.cs @@ -118,11 +118,6 @@ namespace osu.Game.Screens.Spectate foreach ((int userId, SpectatorState state) in e.NewItems.AsNonNull()) onUserStateChanged(userId, state); break; - - case NotifyDictionaryChangedAction.Remove: - foreach ((int userId, SpectatorState state) in e.OldItems.AsNonNull()) - onUserStateChanged(userId, state); - break; } } From af56cd0126b1cc4b5dd5254b02e4ae64e44d77ea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 16:52:36 +0900 Subject: [PATCH 0672/2686] Fix merge breakage --- .../Spectate/CatchUpSpectatorPlayerClock.cs | 98 ------------------- .../Spectate/MultiSpectatorScreen.cs | 3 +- 2 files changed, 1 insertion(+), 100 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs deleted file mode 100644 index 5625a79afa..0000000000 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs +++ /dev/null @@ -1,98 +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 osu.Framework.Bindables; -using osu.Framework.Timing; - -namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate -{ - /// - /// A which catches up using rate adjustment. - /// - public class CatchUpSpectatorPlayerClock : ISpectatorPlayerClock - { - /// - /// The catch up rate. - /// - public const double CATCHUP_RATE = 2; - - public readonly IFrameBasedClock Source; - - public double CurrentTime { get; private set; } - - public bool IsRunning { get; private set; } - - public CatchUpSpectatorPlayerClock(IFrameBasedClock source) - { - Source = source; - } - - public void Reset() => CurrentTime = 0; - - public void Start() => IsRunning = true; - - public void Stop() => IsRunning = false; - - void IAdjustableClock.Start() - { - // Our running state should only be managed by an ISyncManager, ignore calls from external sources. - } - - void IAdjustableClock.Stop() - { - // Our running state should only be managed by an ISyncManager, ignore calls from external sources. - } - - public bool Seek(double position) - { - CurrentTime = position; - return true; - } - - public void ResetSpeedAdjustments() - { - } - - public double Rate => IsCatchingUp ? CATCHUP_RATE : 1; - - double IAdjustableClock.Rate - { - get => Rate; - set => throw new NotSupportedException(); - } - - double IClock.Rate => Rate; - - public void ProcessFrame() - { - ElapsedFrameTime = 0; - FramesPerSecond = 0; - - Source.ProcessFrame(); - - if (IsRunning) - { - // When in catch-up mode, the source is usually not running. - // In such a case, its elapsed time may be zero, which would cause catch-up to get stuck. - // To avoid this, use a constant 16ms elapsed time for now. Probably not too correct, but this whole logic isn't too correct anyway. - double elapsedSource = Source.IsRunning ? Source.ElapsedFrameTime : 16; - double elapsed = elapsedSource * Rate; - - CurrentTime += elapsed; - ElapsedFrameTime = elapsed; - FramesPerSecond = Source.FramesPerSecond; - } - } - - public double ElapsedFrameTime { get; private set; } - - public double FramesPerSecond { get; private set; } - - public FrameTimeInfo TimeInfo => new FrameTimeInfo { Elapsed = ElapsedFrameTime, Current = CurrentTime }; - - public Bindable WaitingOnFrames { get; } = new Bindable(true); - - public bool IsCatchingUp { get; set; } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index cb797d7aff..aa002a7da2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -187,8 +187,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate .DefaultIfEmpty(0) .Min(); - masterClockContainer.StartTime = startTime; - masterClockContainer.Reset(true); + masterClockContainer.Reset(startTime, true); } protected override void OnNewPlayingUserState(int userId, SpectatorState spectatorState) From 9ee26c575d1d68f7c6fc31911653212c220fa8cc Mon Sep 17 00:00:00 2001 From: Andrew Hong Date: Wed, 24 Aug 2022 04:04:44 -0400 Subject: [PATCH 0673/2686] Made button blue --- osu.Game/Overlays/Chat/ExternalLinkDialog.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ExternalLinkDialog.cs b/osu.Game/Overlays/Chat/ExternalLinkDialog.cs index 09650a13bd..b5102de1c5 100644 --- a/osu.Game/Overlays/Chat/ExternalLinkDialog.cs +++ b/osu.Game/Overlays/Chat/ExternalLinkDialog.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Chat Text = @"Yes. Go for it.", Action = openExternalLinkAction }, - new PopupDialogOkButton + new PopupDialogCancelButton { Text = @"No! Copy the URL instead!", Action = copyExternalLinkAction From 5f01f461b375c33e2b90c9813314e0376642d3fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 16:33:07 +0900 Subject: [PATCH 0674/2686] Ensure elapsed time is always non-zero when advancing `SpectatorPlayerClock` --- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 8 +++++++- .../Multiplayer/Spectate/SpectatorPlayerClock.cs | 5 ++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index bab613bed7..dce996696b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -357,12 +357,18 @@ namespace osu.Game.Tests.Visual.Multiplayer /// /// Tests spectating with a beatmap that has a high value. + /// + /// This test is not intended not to check the correct initial time value, but only to guard against + /// gameplay potentially getting stuck in a stopped state due to lead in time being present. /// [Test] public void TestAudioLeadIn() => testLeadIn(b => b.BeatmapInfo.AudioLeadIn = 2000); /// /// Tests spectating with a beatmap that has a storyboard element with a negative start time (i.e. intro storyboard element). + /// + /// This test is not intended not to check the correct initial time value, but only to guard against + /// gameplay potentially getting stuck in a stopped state due to lead in time being present. /// [Test] public void TestIntroStoryboardElement() => testLeadIn(b => @@ -384,7 +390,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for player load", () => spectatorScreen.AllPlayersLoaded); - AddWaitStep("wait for progression", 3); + AddUntilStep($"wait for clock running", () => getInstance(PLAYER_1_ID).SpectatorPlayerClock.IsRunning); assertNotCatchingUp(PLAYER_1_ID); assertRunning(PLAYER_1_ID); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 7801f22437..62731c6903 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -77,7 +77,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { if (IsRunning) { - double elapsedSource = masterClock.ElapsedFrameTime; + // When in catch-up mode, the source is usually not running. + // In such a case, its elapsed time may be zero, which would cause catch-up to get stuck. + // To avoid this, use a constant 16ms elapsed time for now. Probably not too correct, but this whole logic isn't too correct anyway. + double elapsedSource = masterClock.ElapsedFrameTime != 0 ? masterClock.ElapsedFrameTime : 16; double elapsed = elapsedSource * Rate; CurrentTime += elapsed; From 27b57947e4822e1e73757d434b8fa8640327f2eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 16:43:26 +0900 Subject: [PATCH 0675/2686] Rename `PlayerArea.GameplayClock` to `SpectatorPlayerClock` for clarity --- .../Multiplayer/TestSceneMultiSpectatorScreen.cs | 6 +++--- .../Multiplayer/Spectate/MultiSpectatorScreen.cs | 10 +++++----- .../OnlinePlay/Multiplayer/Spectate/PlayerArea.cs | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index dce996696b..54e289055b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -473,13 +473,13 @@ namespace osu.Game.Tests.Visual.Multiplayer => AddAssert($"{userId} {(muted ? "is" : "is not")} muted", () => getInstance(userId).Mute == muted); private void assertRunning(int userId) - => AddAssert($"{userId} clock running", () => getInstance(userId).GameplayClock.IsRunning); + => AddAssert($"{userId} clock running", () => getInstance(userId).SpectatorPlayerClock.IsRunning); private void assertNotCatchingUp(int userId) - => AddAssert($"{userId} in sync", () => !getInstance(userId).GameplayClock.IsCatchingUp); + => AddAssert($"{userId} in sync", () => !getInstance(userId).SpectatorPlayerClock.IsCatchingUp); private void waitForCatchup(int userId) - => AddUntilStep($"{userId} not catching up", () => !getInstance(userId).GameplayClock.IsCatchingUp); + => AddUntilStep($"{userId} not catching up", () => !getInstance(userId).SpectatorPlayerClock.IsCatchingUp); private Player getPlayer(int userId) => getInstance(userId).ChildrenOfType().Single(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index aa002a7da2..a42aa4ba93 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -132,7 +132,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate }, _ => { foreach (var instance in instances) - leaderboard.AddClock(instance.UserId, instance.GameplayClock); + leaderboard.AddClock(instance.UserId, instance.SpectatorPlayerClock); leaderboardFlow.Insert(0, leaderboard); @@ -163,10 +163,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { base.Update(); - if (!isCandidateAudioSource(currentAudioSource?.GameplayClock)) + if (!isCandidateAudioSource(currentAudioSource?.SpectatorPlayerClock)) { - currentAudioSource = instances.Where(i => isCandidateAudioSource(i.GameplayClock)) - .OrderBy(i => Math.Abs(i.GameplayClock.CurrentTime - syncManager.CurrentMasterTime)) + currentAudioSource = instances.Where(i => isCandidateAudioSource(i.SpectatorPlayerClock)) + .OrderBy(i => Math.Abs(i.SpectatorPlayerClock.CurrentTime - syncManager.CurrentMasterTime)) .FirstOrDefault(); foreach (var instance in instances) @@ -215,7 +215,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate var instance = instances.Single(i => i.UserId == userId); instance.FadeColour(colours.Gray4, 400, Easing.OutQuint); - syncManager.RemoveManagedClock(instance.GameplayClock); + syncManager.RemoveManagedClock(instance.SpectatorPlayerClock); } public override bool OnBackButton() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index a1fbdc10de..36f6631ebf 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -38,9 +38,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public readonly int UserId; /// - /// The used to control the gameplay running state of a loaded . + /// The used to control the gameplay running state of a loaded . /// - public readonly SpectatorPlayerClock GameplayClock; + public readonly SpectatorPlayerClock SpectatorPlayerClock; /// /// The currently-loaded score. @@ -58,7 +58,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public PlayerArea(int userId, SpectatorPlayerClock clock) { UserId = userId; - GameplayClock = clock; + SpectatorPlayerClock = clock; RelativeSizeAxes = Axes.Both; Masking = true; @@ -95,7 +95,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate stack.Push(new MultiSpectatorPlayerLoader(Score, () => { - var player = new MultiSpectatorPlayer(Score, GameplayClock); + var player = new MultiSpectatorPlayer(Score, SpectatorPlayerClock); player.OnGameplayStarted += () => OnGameplayStarted?.Invoke(); return player; })); From ddccf4defe293ebd44a59999a27d3bb4e6d9473b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 17:17:59 +0900 Subject: [PATCH 0676/2686] Remove dollar sign --- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 54e289055b..3226eb992d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -390,7 +390,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for player load", () => spectatorScreen.AllPlayersLoaded); - AddUntilStep($"wait for clock running", () => getInstance(PLAYER_1_ID).SpectatorPlayerClock.IsRunning); + AddUntilStep("wait for clock running", () => getInstance(PLAYER_1_ID).SpectatorPlayerClock.IsRunning); assertNotCatchingUp(PLAYER_1_ID); assertRunning(PLAYER_1_ID); From f70af779a4dd9e3215ede924fce791d31461c5f2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 Aug 2022 17:42:41 +0900 Subject: [PATCH 0677/2686] Add maximum statistics to ScoreInfo/SoloScoreInfo --- .../API/Requests/Responses/SoloScoreInfo.cs | 5 +++++ osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 7 ++++--- osu.Game/Scoring/ScoreInfo.cs | 21 +++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index e2e5ea4239..16aa800cb0 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -74,6 +74,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("statistics")] public Dictionary Statistics { get; set; } = new Dictionary(); + [JsonProperty("maximum_statistics")] + public Dictionary MaximumStatistics { get; set; } = new Dictionary(); + #region osu-web API additions (not stored to database). [JsonProperty("id")] @@ -153,6 +156,7 @@ namespace osu.Game.Online.API.Requests.Responses MaxCombo = MaxCombo, Rank = Rank, Statistics = Statistics, + MaximumStatistics = MaximumStatistics, Date = EndedAt, Hash = HasReplay ? "online" : string.Empty, // TODO: temporary? Mods = mods, @@ -174,6 +178,7 @@ namespace osu.Game.Online.API.Requests.Responses Passed = score.Passed, Mods = score.APIMods, Statistics = score.Statistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value), + MaximumStatistics = score.MaximumStatistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value), }; public long OnlineID => ID ?? -1; diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 1deac9f08a..9e7a5e3657 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -405,8 +405,6 @@ namespace osu.Game.Rulesets.Scoring return ScoreRank.D; } - public int GetStatistic(HitResult result) => scoreResultCounts.GetValueOrDefault(result); - /// /// Resets this ScoreProcessor to a default state. /// @@ -449,7 +447,10 @@ namespace osu.Game.Rulesets.Scoring score.HitEvents = hitEvents; foreach (var result in HitResultExtensions.ALL_TYPES) - score.Statistics[result] = GetStatistic(result); + score.Statistics[result] = scoreResultCounts.GetValueOrDefault(result); + + foreach (var result in HitResultExtensions.ALL_TYPES) + score.MaximumStatistics[result] = maximumResultCounts.GetValueOrDefault(result); // Populate total score after everything else. score.TotalScore = (long)Math.Round(ComputeFinalScore(ScoringMode.Standardised, score)); diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index d32d611a27..99e0726da7 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -63,6 +63,9 @@ namespace osu.Game.Scoring [MapTo("Statistics")] public string StatisticsJson { get; set; } = string.Empty; + [MapTo("MaximumStatistics")] + public string MaximumStatisticsJson { get; set; } = string.Empty; + public ScoreInfo(BeatmapInfo? beatmap = null, RulesetInfo? ruleset = null, RealmUser? realmUser = null) { Ruleset = ruleset ?? new RulesetInfo(); @@ -181,6 +184,24 @@ namespace osu.Game.Scoring set => statistics = value; } + private Dictionary? maximumStatistics; + + [Ignored] + public Dictionary MaximumStatistics + { + get + { + if (maximumStatistics != null) + return maximumStatistics; + + if (!string.IsNullOrEmpty(MaximumStatisticsJson)) + maximumStatistics = JsonConvert.DeserializeObject>(MaximumStatisticsJson); + + return maximumStatistics ??= new Dictionary(); + } + set => maximumStatistics = value; + } + private Mod[]? mods; [Ignored] From d947a6cb5947c1a3bf1a1d81fd7701266945ffae Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 Aug 2022 19:45:19 +0900 Subject: [PATCH 0678/2686] Add Realm migration --- osu.Game/Database/RealmAccess.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 0f2e724567..e23fc912df 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -69,8 +69,9 @@ namespace osu.Game.Database /// 21 2022-07-27 Migrate collections to realm (BeatmapCollection). /// 22 2022-07-31 Added ModPreset. /// 23 2022-08-01 Added LastLocalUpdate to BeatmapInfo. + /// 24 2022-08-22 Added MaximumStatistics to ScoreInfo. /// - private const int schema_version = 23; + private const int schema_version = 24; /// /// Lock object which is held during sections, blocking realm retrieval during blocking periods. From cc648a90bc547fdb9c368937b9a9cd618a83191b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 Aug 2022 21:31:10 +0900 Subject: [PATCH 0679/2686] Actually save maximum statistics --- osu.Game/Scoring/ScoreImporter.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Scoring/ScoreImporter.cs b/osu.Game/Scoring/ScoreImporter.cs index 0902f1636b..45f827354e 100644 --- a/osu.Game/Scoring/ScoreImporter.cs +++ b/osu.Game/Scoring/ScoreImporter.cs @@ -73,6 +73,9 @@ namespace osu.Game.Scoring if (string.IsNullOrEmpty(model.StatisticsJson)) model.StatisticsJson = JsonConvert.SerializeObject(model.Statistics); + + if (string.IsNullOrEmpty(model.MaximumStatisticsJson)) + model.MaximumStatisticsJson = JsonConvert.SerializeObject(model.MaximumStatistics); } protected override void PostImport(ScoreInfo model, Realm realm, bool batchImport) From 9f9deef438a557254142acb2cb38ec1a96d503c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 17:37:41 +0900 Subject: [PATCH 0680/2686] Reword slightly --- osu.Game/Overlays/Chat/ExternalLinkDialog.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ExternalLinkDialog.cs b/osu.Game/Overlays/Chat/ExternalLinkDialog.cs index b5102de1c5..657fd35f8a 100644 --- a/osu.Game/Overlays/Chat/ExternalLinkDialog.cs +++ b/osu.Game/Overlays/Chat/ExternalLinkDialog.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Chat }, new PopupDialogCancelButton { - Text = @"No! Copy the URL instead!", + Text = @"Copy URL to the clipboard instead.", Action = copyExternalLinkAction }, new PopupDialogCancelButton From 6a0d23cf96158cad6007c160713e16e4a5ddeb75 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 17:39:22 +0900 Subject: [PATCH 0681/2686] Nest dialog class and apply NRT --- osu.Game/Online/Chat/ExternalLinkOpener.cs | 43 ++++++++++++++++---- osu.Game/Overlays/Chat/ExternalLinkDialog.cs | 40 ------------------ 2 files changed, 36 insertions(+), 47 deletions(-) delete mode 100644 osu.Game/Overlays/Chat/ExternalLinkDialog.cs diff --git a/osu.Game/Online/Chat/ExternalLinkOpener.cs b/osu.Game/Online/Chat/ExternalLinkOpener.cs index 4c5df9c917..587159179f 100644 --- a/osu.Game/Online/Chat/ExternalLinkOpener.cs +++ b/osu.Game/Online/Chat/ExternalLinkOpener.cs @@ -1,27 +1,27 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; using osu.Framework.Platform; using osu.Game.Configuration; using osu.Game.Overlays; -using osu.Game.Overlays.Chat; +using osu.Game.Overlays.Dialog; namespace osu.Game.Online.Chat { public class ExternalLinkOpener : Component { [Resolved] - private GameHost host { get; set; } + private GameHost host { get; set; } = null!; [Resolved(CanBeNull = true)] - private IDialogOverlay dialogOverlay { get; set; } + private IDialogOverlay? dialogOverlay { get; set; } - private Bindable externalLinkWarning; + private Bindable externalLinkWarning = null!; [BackgroundDependencyLoader(true)] private void load(OsuConfigManager config) @@ -31,10 +31,39 @@ namespace osu.Game.Online.Chat public void OpenUrlExternally(string url, bool bypassWarning = false) { - if (!bypassWarning && externalLinkWarning.Value) + if (!bypassWarning && externalLinkWarning.Value && dialogOverlay != null) dialogOverlay.Push(new ExternalLinkDialog(url, () => host.OpenUrlExternally(url), () => host.GetClipboard()?.SetText(url))); else host.OpenUrlExternally(url); } + + public class ExternalLinkDialog : PopupDialog + { + public ExternalLinkDialog(string url, Action openExternalLinkAction, Action copyExternalLinkAction) + { + HeaderText = "Just checking..."; + BodyText = $"You are about to leave osu! and open the following link in a web browser:\n\n{url}"; + + Icon = FontAwesome.Solid.ExclamationTriangle; + + Buttons = new PopupDialogButton[] + { + new PopupDialogOkButton + { + Text = @"Yes. Go for it.", + Action = openExternalLinkAction + }, + new PopupDialogCancelButton + { + Text = @"Copy URL to the clipboard instead.", + Action = copyExternalLinkAction + }, + new PopupDialogCancelButton + { + Text = @"No! Abort mission!" + }, + }; + } + } } } diff --git a/osu.Game/Overlays/Chat/ExternalLinkDialog.cs b/osu.Game/Overlays/Chat/ExternalLinkDialog.cs deleted file mode 100644 index 657fd35f8a..0000000000 --- a/osu.Game/Overlays/Chat/ExternalLinkDialog.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using osu.Framework.Graphics.Sprites; -using osu.Game.Overlays.Dialog; - -namespace osu.Game.Overlays.Chat -{ - public class ExternalLinkDialog : PopupDialog - { - public ExternalLinkDialog(string url, Action openExternalLinkAction, Action copyExternalLinkAction) - { - HeaderText = "Just checking..."; - BodyText = $"You are about to leave osu! and open the following link in a web browser:\n\n{url}"; - - Icon = FontAwesome.Solid.ExclamationTriangle; - - Buttons = new PopupDialogButton[] - { - new PopupDialogOkButton - { - Text = @"Yes. Go for it.", - Action = openExternalLinkAction - }, - new PopupDialogCancelButton - { - Text = @"Copy URL to the clipboard instead.", - Action = copyExternalLinkAction - }, - new PopupDialogCancelButton - { - Text = @"No! Abort mission!" - }, - }; - } - } -} From f3847b90fddaa6418c457a68ddd2912f637b0443 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 19:36:01 +0900 Subject: [PATCH 0682/2686] Tidy up attach logic --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 7 ++++--- osu.Game/Rulesets/UI/RulesetInputManager.cs | 23 +++++++++------------ osu.Game/Screens/Play/HUDOverlay.cs | 7 +++++-- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 02df4d8fb3..73acb1759f 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.UI /// Displays an interactive ruleset gameplay instance. /// /// The type of HitObject contained by this DrawableRuleset. - public abstract class DrawableRuleset : DrawableRuleset, IProvideCursor, ICanAttachKeyCounter + public abstract class DrawableRuleset : DrawableRuleset, IProvideCursor, ICanAttachHUDPieces where TObject : HitObject { public override event Action NewResult; @@ -339,9 +339,10 @@ namespace osu.Game.Rulesets.UI public abstract DrawableHitObject CreateDrawableRepresentation(TObject h); public void Attach(KeyCounterDisplay keyCounter) => - (KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(keyCounter); + (KeyBindingInputManager as ICanAttachHUDPieces)?.Attach(keyCounter); - public void Attach(ClicksPerSecondCalculator calculator) => (KeyBindingInputManager as ICanAttachKeyCounter)?.Attach(calculator); + public void Attach(ClicksPerSecondCalculator calculator) => + (KeyBindingInputManager as ICanAttachHUDPieces)?.Attach(calculator); /// /// Creates a key conversion input manager. An exception will be thrown if a valid is not returned. diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 4b7ce22cfc..401ebbfd74 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -25,7 +25,7 @@ using static osu.Game.Input.Handlers.ReplayInputHandler; namespace osu.Game.Rulesets.UI { - public abstract class RulesetInputManager : PassThroughInputManager, ICanAttachKeyCounter, IHasReplayHandler, IHasRecordingHandler + public abstract class RulesetInputManager : PassThroughInputManager, ICanAttachHUDPieces, IHasReplayHandler, IHasRecordingHandler where T : struct { public readonly KeyBindingContainer KeyBindingContainer; @@ -169,7 +169,7 @@ namespace osu.Game.Rulesets.UI .Select(action => new KeyCounterAction(action))); } - public class ActionReceptor : KeyCounterDisplay.Receptor, IKeyBindingHandler + private class ActionReceptor : KeyCounterDisplay.Receptor, IKeyBindingHandler { public ActionReceptor(KeyCounterDisplay target) : base(target) @@ -191,8 +191,6 @@ namespace osu.Game.Rulesets.UI public void Attach(ClicksPerSecondCalculator calculator) { - if (calculator == null) return; - var listener = new ActionListener(calculator); KeyBindingContainer.Add(listener); @@ -200,23 +198,22 @@ namespace osu.Game.Rulesets.UI calculator.Listener = listener; } - public class ActionListener : ClicksPerSecondCalculator.InputListener, IKeyBindingHandler + private class ActionListener : ClicksPerSecondCalculator.InputListener, IKeyBindingHandler { + public ActionListener(ClicksPerSecondCalculator calculator) + : base(calculator) + { + } + public bool OnPressed(KeyBindingPressEvent e) { Calculator.AddTimestamp(); - return false; } public void OnReleased(KeyBindingReleaseEvent e) { } - - public ActionListener(ClicksPerSecondCalculator calculator) - : base(calculator) - { - } } #endregion @@ -256,10 +253,10 @@ namespace osu.Game.Rulesets.UI } /// - /// Supports attaching a . + /// Supports attaching various HUD pieces. /// Keys will be populated automatically and a receptor will be injected inside. /// - public interface ICanAttachKeyCounter + public interface ICanAttachHUDPieces { void Attach(KeyCounterDisplay keyCounter); void Attach(ClicksPerSecondCalculator calculator); diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index b27efaf13a..f9f3693385 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -264,8 +264,11 @@ namespace osu.Game.Screens.Play protected virtual void BindDrawableRuleset(DrawableRuleset drawableRuleset) { - (drawableRuleset as ICanAttachKeyCounter)?.Attach(KeyCounter); - (drawableRuleset as ICanAttachKeyCounter)?.Attach(clicksPerSecondCalculator); + if (drawableRuleset is ICanAttachHUDPieces attachTarget) + { + attachTarget.Attach(KeyCounter); + attachTarget.Attach(clicksPerSecondCalculator); + } replayLoaded.BindTo(drawableRuleset.HasReplayLoaded); } From 5ec95c92694f47ca376ff6a3e54d4b66fee5410e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 24 Aug 2022 19:46:35 +0900 Subject: [PATCH 0683/2686] Update ScoreProcessor to make use of MaximumStatistics --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 9e7a5e3657..866f285e4f 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -535,6 +535,9 @@ namespace osu.Game.Rulesets.Scoring { extractScoringValues(scoreInfo.Statistics, out current, out maximum); current.MaxCombo = scoreInfo.MaxCombo; + + if (scoreInfo.MaximumStatistics.Count > 0) + extractScoringValues(scoreInfo.MaximumStatistics, out _, out maximum); } /// From c9ff39f8c33d014462db360d6c19d45653ebf32c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 23 Aug 2022 21:00:30 +0900 Subject: [PATCH 0684/2686] Add HitResult.LegacyComboIncrease --- .../Rulesets/Scoring/ScoreProcessorTest.cs | 69 +++++++++++++++++++ osu.Game/Rulesets/Scoring/HitResult.cs | 38 ++++++++-- .../Rulesets/Scoring/JudgementProcessor.cs | 5 ++ osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 3 +- 4 files changed, 110 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs index ff282fff62..63d6e0483b 100644 --- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs +++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -314,6 +315,46 @@ namespace osu.Game.Tests.Rulesets.Scoring }), Is.EqualTo(expectedScore).Within(0.5d)); } +#pragma warning disable CS0618 + [Test] + public void TestLegacyComboIncrease() + { + Assert.That(HitResult.LegacyComboIncrease.IncreasesCombo(), Is.True); + Assert.That(HitResult.LegacyComboIncrease.BreaksCombo(), Is.False); + Assert.That(HitResult.LegacyComboIncrease.AffectsCombo(), Is.True); + Assert.That(HitResult.LegacyComboIncrease.AffectsAccuracy(), Is.False); + Assert.That(HitResult.LegacyComboIncrease.IsBasic(), Is.False); + Assert.That(HitResult.LegacyComboIncrease.IsTick(), Is.False); + Assert.That(HitResult.LegacyComboIncrease.IsBonus(), Is.False); + Assert.That(HitResult.LegacyComboIncrease.IsHit(), Is.True); + Assert.That(HitResult.LegacyComboIncrease.IsScorable(), Is.True); + Assert.That(HitResultExtensions.ALL_TYPES, Does.Not.Contain(HitResult.LegacyComboIncrease)); + + // Cannot be used to apply results. + Assert.Throws(() => scoreProcessor.ApplyBeatmap(new Beatmap + { + HitObjects = { new TestHitObject(HitResult.LegacyComboIncrease) } + })); + + ScoreInfo testScore = new ScoreInfo + { + MaxCombo = 1, + Statistics = new Dictionary + { + { HitResult.Great, 1 } + }, + MaximumStatistics = new Dictionary + { + { HitResult.Great, 1 }, + { HitResult.LegacyComboIncrease, 1 } + } + }; + + double totalScore = new TestScoreProcessor().ComputeFinalScore(ScoringMode.Standardised, testScore); + Assert.That(totalScore, Is.EqualTo(750_000)); // 500K from accuracy (100%), and 250K from combo (50%). + } +#pragma warning restore CS0618 + private class TestRuleset : Ruleset { public override IEnumerable GetModsFor(ModType type) => throw new System.NotImplementedException(); @@ -352,5 +393,33 @@ namespace osu.Game.Tests.Rulesets.Scoring this.maxResult = maxResult; } } + + private class TestScoreProcessor : ScoreProcessor + { + protected override double DefaultAccuracyPortion => 0.5; + protected override double DefaultComboPortion => 0.5; + + public TestScoreProcessor() + : base(new TestRuleset()) + { + } + + // ReSharper disable once MemberHidesStaticFromOuterClass + private class TestRuleset : Ruleset + { + protected override IEnumerable GetValidHitResults() => new[] { HitResult.Great }; + + public override IEnumerable GetModsFor(ModType type) => throw new NotImplementedException(); + + public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => throw new NotImplementedException(); + + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException(); + + public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new NotImplementedException(); + + public override string Description => string.Empty; + public override string ShortName => string.Empty; + } + } } } diff --git a/osu.Game/Rulesets/Scoring/HitResult.cs b/osu.Game/Rulesets/Scoring/HitResult.cs index bfa256fc20..e6aba4a70e 100644 --- a/osu.Game/Rulesets/Scoring/HitResult.cs +++ b/osu.Game/Rulesets/Scoring/HitResult.cs @@ -119,8 +119,20 @@ namespace osu.Game.Rulesets.Scoring [EnumMember(Value = "ignore_hit")] [Order(12)] IgnoreHit, + + /// + /// A special result used as a padding value for legacy rulesets. It is a hit type and affects combo, but does not contribute to score. + /// + /// + /// DO NOT USE. + /// + [EnumMember(Value = "legacy_combo_increase")] + [Order(99)] + [Obsolete("Do not use.")] + LegacyComboIncrease = 99 } +#pragma warning disable CS0618 public static class HitResultExtensions { /// @@ -150,6 +162,7 @@ namespace osu.Game.Rulesets.Scoring case HitResult.Perfect: case HitResult.LargeTickHit: case HitResult.LargeTickMiss: + case HitResult.LegacyComboIncrease: return true; default: @@ -161,13 +174,23 @@ namespace osu.Game.Rulesets.Scoring /// Whether a affects the accuracy portion of the score. /// public static bool AffectsAccuracy(this HitResult result) - => IsScorable(result) && !IsBonus(result); + { + if (result == HitResult.LegacyComboIncrease) + return false; + + return IsScorable(result) && !IsBonus(result); + } /// /// Whether a is a non-tick and non-bonus result. /// public static bool IsBasic(this HitResult result) - => IsScorable(result) && !IsTick(result) && !IsBonus(result); + { + if (result == HitResult.LegacyComboIncrease) + return false; + + return IsScorable(result) && !IsTick(result) && !IsBonus(result); + } /// /// Whether a should be counted as a tick. @@ -225,12 +248,18 @@ namespace osu.Game.Rulesets.Scoring /// /// Whether a is scorable. /// - public static bool IsScorable(this HitResult result) => result >= HitResult.Miss && result < HitResult.IgnoreMiss; + public static bool IsScorable(this HitResult result) + { + if (result == HitResult.LegacyComboIncrease) + return true; + + return result >= HitResult.Miss && result < HitResult.IgnoreMiss; + } /// /// An array of all scorable s. /// - public static readonly HitResult[] ALL_TYPES = ((HitResult[])Enum.GetValues(typeof(HitResult))).ToArray(); + public static readonly HitResult[] ALL_TYPES = ((HitResult[])Enum.GetValues(typeof(HitResult))).Except(new[] { HitResult.LegacyComboIncrease }).ToArray(); /// /// Whether a is valid within a given range. @@ -251,4 +280,5 @@ namespace osu.Game.Rulesets.Scoring return result > minResult && result < maxResult; } } +#pragma warning restore CS0618 } diff --git a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs index 12fe0056bb..bc8f2c22f3 100644 --- a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs +++ b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs @@ -61,6 +61,11 @@ namespace osu.Game.Rulesets.Scoring /// The to apply. public void ApplyResult(JudgementResult result) { +#pragma warning disable CS0618 + if (result.Type == HitResult.LegacyComboIncrease) + throw new ArgumentException(@$"A {nameof(HitResult.LegacyComboIncrease)} hit result cannot be applied."); +#pragma warning restore CS0618 + JudgedHits++; lastAppliedResult = result; diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 866f285e4f..905fda6d8b 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -593,7 +593,8 @@ namespace osu.Game.Rulesets.Scoring if (result.IsBonus()) current.BonusScore += count * Judgement.ToNumericResult(result); - else + + if (result.AffectsAccuracy()) { // The maximum result of this judgement if it wasn't a miss. // E.g. For a GOOD judgement, the max result is either GREAT/PERFECT depending on which one the ruleset uses (osu!: GREAT, osu!mania: PERFECT). From e7cbb6c63d784c0365bf22ae6512edc637a80308 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 24 Aug 2022 19:53:16 +0900 Subject: [PATCH 0685/2686] Fix test failures/nullability --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 9e7a5e3657..76e6fcecca 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -128,8 +128,7 @@ namespace osu.Game.Rulesets.Scoring private bool beatmapApplied; private readonly Dictionary scoreResultCounts = new Dictionary(); - - private Dictionary? maximumResultCounts; + private readonly Dictionary maximumResultCounts = new Dictionary(); private readonly List hitEvents = new List(); private HitObject? lastHitObject; @@ -419,7 +418,9 @@ namespace osu.Game.Rulesets.Scoring if (storeResults) { maximumScoringValues = currentScoringValues; - maximumResultCounts = new Dictionary(scoreResultCounts); + + maximumResultCounts.Clear(); + maximumResultCounts.AddRange(scoreResultCounts); } scoreResultCounts.Clear(); From dc829334a1b6611f8518d5fa6518f9e498d4de66 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 24 Aug 2022 22:19:32 +0900 Subject: [PATCH 0686/2686] Update for framework-side changes. --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 2718465b9c..1be2b09ff8 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -56,6 +56,14 @@ namespace osu.Game.Graphics.UserInterface private bool selectionStarted; private double sampleLastPlaybackTime; + private enum SelectionSampleType + { + Character, + Word, + All, + Deselect + } + public OsuTextBox() { Height = 40; @@ -133,16 +141,19 @@ namespace osu.Game.Graphics.UserInterface { base.OnTextSelectionChanged(selectionType); - if (selectionType == TextSelectionType.Word) + switch (selectionType) { - if (!selectionStarted) - playSelectSample(selectionType); - else - playSelectSample(); - } - else - { - playSelectSample(selectionType); + case TextSelectionType.Character: + playSelectSample(SelectionSampleType.Character); + break; + + case TextSelectionType.Word: + playSelectSample(selectionStarted ? SelectionSampleType.Character : SelectionSampleType.Word); + break; + + case TextSelectionType.All: + playSelectSample(SelectionSampleType.All); + break; } selectionStarted = true; @@ -150,15 +161,16 @@ namespace osu.Game.Graphics.UserInterface protected override void OnTextDeselected() { - if (selectionStarted) - playSelectSample(TextSelectionType.Deselect); + base.OnTextDeselected(); + + if (!selectionStarted) return; + + playSelectSample(SelectionSampleType.Deselect); selectionStarted = false; - - base.OnTextDeselected(); } - private void playSelectSample(TextSelectionType selectionType = TextSelectionType.Character) + private void playSelectSample(SelectionSampleType selectionType) { if (Time.Current < sampleLastPlaybackTime + 15) return; @@ -167,15 +179,15 @@ namespace osu.Game.Graphics.UserInterface switch (selectionType) { - case TextSelectionType.All: + case SelectionSampleType.All: channel = selectAllSample?.GetChannel(); break; - case TextSelectionType.Word: + case SelectionSampleType.Word: channel = selectWordSample?.GetChannel(); break; - case TextSelectionType.Deselect: + case SelectionSampleType.Deselect: channel = deselectSample?.GetChannel(); break; From da7f8270da6af8fe7d09ad24954b88500ad4e309 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 24 Aug 2022 22:31:28 +0900 Subject: [PATCH 0687/2686] Fix incorrect cast --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 1be2b09ff8..60c8dcef21 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -193,7 +193,7 @@ namespace osu.Game.Graphics.UserInterface default: channel = selectCharSample?.GetChannel(); - pitch += (SelectedText.Length / (float)Text.Length) * 0.15f; + pitch += (SelectedText.Length / (double)Text.Length) * 0.15f; break; } From 5cddc7ed1f8fadccedccc4b6efe0a836d1ec3037 Mon Sep 17 00:00:00 2001 From: Ryuki Date: Wed, 24 Aug 2022 17:12:52 +0200 Subject: [PATCH 0688/2686] Code cleanup (CPS) --- .../Gameplay/TestSceneClicksPerSecond.cs | 31 ++---- osu.Game/Rulesets/UI/RulesetInputManager.cs | 10 +- .../ClicksPerSecondCalculator.cs | 96 ++++++------------- .../ClicksPerSecond/ClicksPerSecondCounter.cs | 6 +- 4 files changed, 42 insertions(+), 101 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs index 137ab7acdb..a140460251 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs @@ -29,7 +29,6 @@ namespace osu.Game.Tests.Visual.Gameplay { private DependencyProvidingContainer dependencyContainer = null!; private ClicksPerSecondCalculator calculator = null!; - private ManualInputListener? listener; private GameplayClockContainer gameplayClockContainer = null!; private ManualClock manualClock = null!; private DrawableRuleset? drawableRuleset; @@ -151,7 +150,6 @@ namespace osu.Game.Tests.Visual.Gameplay } } }; - calculator.Listener = listener = new ManualInputListener(calculator); }); } @@ -189,7 +187,7 @@ namespace osu.Game.Tests.Visual.Gameplay foreach (double timestamp in inputs) { seekAllClocks(timestamp); - listener?.AddInput(); + calculator.AddTimestamp(); } seekAllClocks(baseTime); @@ -270,18 +268,6 @@ namespace osu.Game.Tests.Visual.Gameplay public IBindable WaitingOnFrames => new Bindable(); } - private class ManualInputListener : ClicksPerSecondCalculator.InputListener - { - public void AddInput() => Calculator.AddTimestamp(); - - public ManualInputListener(ClicksPerSecondCalculator calculator) - : base(calculator) - { - } - } - -#nullable disable - [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] private class TestDrawableRuleset : DrawableRuleset { @@ -299,24 +285,19 @@ namespace osu.Game.Tests.Visual.Gameplay remove => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); } - public override Playfield Playfield => null; - public override Container Overlays => null; - public override Container FrameStableComponents => null; + public override Playfield Playfield => null!; + public override Container Overlays => null!; + public override Container FrameStableComponents => null!; public override IFrameStableClock FrameStableClock { get; } internal override bool FrameStablePlayback { get; set; } public override IReadOnlyList Mods => Array.Empty(); public override double GameplayStartTime => 0; - public override GameplayCursorContainer Cursor => null; - - public TestDrawableRuleset() - : base(new OsuRuleset()) - { - } + public override GameplayCursorContainer Cursor => null!; public TestDrawableRuleset(IFrameStableClock frameStableClock) - : this() + : base(new OsuRuleset()) { FrameStableClock = frameStableClock; } diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 401ebbfd74..dcd2c4fb5d 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -194,20 +194,20 @@ namespace osu.Game.Rulesets.UI var listener = new ActionListener(calculator); KeyBindingContainer.Add(listener); - - calculator.Listener = listener; } - private class ActionListener : ClicksPerSecondCalculator.InputListener, IKeyBindingHandler + private class ActionListener : Component, IKeyBindingHandler { + private readonly ClicksPerSecondCalculator calculator; + public ActionListener(ClicksPerSecondCalculator calculator) - : base(calculator) { + this.calculator = calculator; } public bool OnPressed(KeyBindingPressEvent e) { - Calculator.AddTimestamp(); + calculator.AddTimestamp(); return false; } diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs index d9c3c6ffec..20ac923b82 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs @@ -1,12 +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; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Timing; using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Play.HUD.ClicksPerSecond @@ -15,89 +13,53 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond { private readonly List timestamps; - private InputListener? listener; + [Resolved] + private IGameplayClock gameplayClock { get; set; } = null!; [Resolved] - private IGameplayClock? gameplayClock { get; set; } + private DrawableRuleset drawableRuleset { get; set; } = null!; - [Resolved(canBeNull: true)] - private DrawableRuleset? drawableRuleset { get; set; } + private double rate; - public InputListener Listener - { - set - { - onResetRequested?.Invoke(); - listener = value; - } - } + // The latest timestamp GC seeked. Does not affect normal gameplay + // but prevents duplicate inputs on replays. + private double latestTime = double.NegativeInfinity; - private event Action? onResetRequested; - - private IClock? workingClock => drawableRuleset?.FrameStableClock; - - private double baseRate; - - private double rate - { - get - { - if (gameplayClock?.TrueGameplayRate > 0) - { - baseRate = gameplayClock.TrueGameplayRate; - } - - return baseRate; - } - } - - private double maxTime = double.NegativeInfinity; - - public bool Ready => workingClock != null && gameplayClock != null && listener != null; - public int Value => timestamps.Count(isTimestampWithinSpan); + public int Value { get; private set; } public ClicksPerSecondCalculator() { RelativeSizeAxes = Axes.Both; timestamps = new List(); - onResetRequested += cleanUp; } - private void cleanUp() + protected override void Update() { - timestamps.Clear(); - maxTime = double.NegativeInfinity; + base.Update(); + + // When pausing in replays (using the space bar) GC.TrueGameplayRate returns 0 + // To prevent CPS value being 0, we store and use the last non-zero TrueGameplayRate + if (gameplayClock.TrueGameplayRate > 0) + { + rate = gameplayClock.TrueGameplayRate; + } + + Value = timestamps.Count(timestamp => + { + double window = 1000 * rate; + double relativeTime = drawableRuleset.FrameStableClock.CurrentTime - timestamp; + return relativeTime > 0 && relativeTime <= window; + }); } public void AddTimestamp() { - if (workingClock == null) return; - - if (workingClock.CurrentTime >= maxTime) + // Discard inputs if current gameplay time is not the latest + // to prevent duplicate inputs + if (drawableRuleset.FrameStableClock.CurrentTime >= latestTime) { - timestamps.Add(workingClock.CurrentTime); - maxTime = workingClock.CurrentTime; - } - } - - private bool isTimestampWithinSpan(double timestamp) - { - if (workingClock == null) return false; - - double span = 1000 * rate; - double relativeTime = workingClock.CurrentTime - timestamp; - return relativeTime > 0 && relativeTime <= span; - } - - public abstract class InputListener : Component - { - protected ClicksPerSecondCalculator Calculator; - - protected InputListener(ClicksPerSecondCalculator calculator) - { - RelativeSizeAxes = Axes.Both; - Depth = float.MinValue; - Calculator = calculator; + timestamps.Add(drawableRuleset.FrameStableClock.CurrentTime); + latestTime = drawableRuleset.FrameStableClock.CurrentTime; } } } diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs index 3ff06d5217..243d8ed1e8 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs @@ -16,9 +16,7 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond { public class ClicksPerSecondCounter : RollingCounter, ISkinnableDrawable { - private const float alpha_when_invalid = 0.3f; - - [Resolved(canBeNull: false)] + [Resolved] private ClicksPerSecondCalculator calculator { get; set; } = null!; protected override double RollingDuration => 350; @@ -40,7 +38,7 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond { base.Update(); - Current.Value = calculator.Ready ? calculator.Value : 0; + Current.Value = calculator.Value; } protected override IHasText CreateText() => new TextComponent(); From 4de6df71c5749f88ca0a0c323a04be6309ec3d7c Mon Sep 17 00:00:00 2001 From: o-dasher Date: Wed, 24 Aug 2022 20:59:32 -0400 Subject: [PATCH 0689/2686] No "gameplayClock" usage with playfield update mods --- osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs | 6 +----- .../Mods/OsuModMagnetised.cs | 17 +++++++--------- osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs | 20 +++++++------------ 3 files changed, 15 insertions(+), 28 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs index f942538ed3..6772cfe0be 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs @@ -31,8 +31,6 @@ namespace osu.Game.Rulesets.Osu.Mods private OsuInputManager inputManager = null!; - private IFrameStableClock gameplayClock = null!; - private List replayFrames = null!; private int currentFrame; @@ -41,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Mods { if (currentFrame == replayFrames.Count - 1) return; - double time = gameplayClock.CurrentTime; + double time = playfield.Clock.CurrentTime; // Very naive implementation of autopilot based on proximity to replay frames. // TODO: this needs to be based on user interactions to better match stable (pausing until judgement is registered). @@ -56,8 +54,6 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - gameplayClock = drawableRuleset.FrameStableClock; - // Grab the input manager to disable the user's cursor, and for future use inputManager = (OsuInputManager)drawableRuleset.KeyBindingInputManager; inputManager.AllowUserCursorMovement = false; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs index 35a34094d1..fbde9e0491 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; @@ -27,8 +28,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 0.5; public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel) }; - private IFrameStableClock gameplayClock = null!; - [SettingSource("Attraction strength", "How strong the pull is.", 0)] public BindableFloat AttractionStrength { get; } = new BindableFloat(0.5f) { @@ -39,8 +38,6 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - gameplayClock = drawableRuleset.FrameStableClock; - // Hide judgment displays and follow points as they won't make any sense. // Judgements can potentially be turned on in a future where they display at a position relative to their drawable counterpart. drawableRuleset.Playfield.DisplayJudgements.Value = false; @@ -56,27 +53,27 @@ namespace osu.Game.Rulesets.Osu.Mods switch (drawable) { case DrawableHitCircle circle: - easeTo(circle, cursorPos); + easeTo(playfield.Clock, circle, cursorPos); break; case DrawableSlider slider: if (!slider.HeadCircle.Result.HasResult) - easeTo(slider, cursorPos); + easeTo(playfield.Clock, slider, cursorPos); else - easeTo(slider, cursorPos - slider.Ball.DrawPosition); + easeTo(playfield.Clock, slider, cursorPos - slider.Ball.DrawPosition); break; } } } - private void easeTo(DrawableHitObject hitObject, Vector2 destination) + private void easeTo(IFrameBasedClock clock, DrawableHitObject hitObject, Vector2 destination) { double dampLength = Interpolation.Lerp(3000, 40, AttractionStrength.Value); - float x = (float)Interpolation.DampContinuously(hitObject.X, destination.X, dampLength, gameplayClock.ElapsedFrameTime); - float y = (float)Interpolation.DampContinuously(hitObject.Y, destination.Y, dampLength, gameplayClock.ElapsedFrameTime); + float x = (float)Interpolation.DampContinuously(hitObject.X, destination.X, dampLength, clock.ElapsedFrameTime); + float y = (float)Interpolation.DampContinuously(hitObject.Y, destination.Y, dampLength, clock.ElapsedFrameTime); hitObject.Position = new Vector2(x, y); } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs index 54b594505c..911363a27e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs @@ -2,9 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using osu.Framework.Bindables; using osu.Framework.Localisation; +using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; @@ -27,8 +27,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModMagnetised) }; - private IFrameStableClock? gameplayClock; - [SettingSource("Repulsion strength", "How strong the repulsion is.", 0)] public BindableFloat RepulsionStrength { get; } = new BindableFloat(0.5f) { @@ -39,8 +37,6 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - gameplayClock = drawableRuleset.FrameStableClock; - // Hide judgment displays and follow points as they won't make any sense. // Judgements can potentially be turned on in a future where they display at a position relative to their drawable counterpart. drawableRuleset.Playfield.DisplayJudgements.Value = false; @@ -69,29 +65,27 @@ namespace osu.Game.Rulesets.Osu.Mods switch (drawable) { case DrawableHitCircle circle: - easeTo(circle, destination, cursorPos); + easeTo(playfield.Clock, circle, destination, cursorPos); break; case DrawableSlider slider: if (!slider.HeadCircle.Result.HasResult) - easeTo(slider, destination, cursorPos); + easeTo(playfield.Clock, slider, destination, cursorPos); else - easeTo(slider, destination - slider.Ball.DrawPosition, cursorPos); + easeTo(playfield.Clock, slider, destination - slider.Ball.DrawPosition, cursorPos); break; } } } - private void easeTo(DrawableHitObject hitObject, Vector2 destination, Vector2 cursorPos) + private void easeTo(IFrameBasedClock clock, DrawableHitObject hitObject, Vector2 destination, Vector2 cursorPos) { - Debug.Assert(gameplayClock != null); - double dampLength = Vector2.Distance(hitObject.Position, cursorPos) / (0.04 * RepulsionStrength.Value + 0.04); - float x = (float)Interpolation.DampContinuously(hitObject.X, destination.X, dampLength, gameplayClock.ElapsedFrameTime); - float y = (float)Interpolation.DampContinuously(hitObject.Y, destination.Y, dampLength, gameplayClock.ElapsedFrameTime); + float x = (float)Interpolation.DampContinuously(hitObject.X, destination.X, dampLength, clock.ElapsedFrameTime); + float y = (float)Interpolation.DampContinuously(hitObject.Y, destination.Y, dampLength, clock.ElapsedFrameTime); hitObject.Position = new Vector2(x, y); } From 73f41439aeffd5036fe54038035b67d8d8819aac Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Aug 2022 13:34:58 +0900 Subject: [PATCH 0690/2686] Remove redundant qualifiers --- osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs index 63d6e0483b..44ebdad2e4 100644 --- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs +++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs @@ -357,13 +357,13 @@ namespace osu.Game.Tests.Rulesets.Scoring private class TestRuleset : Ruleset { - public override IEnumerable GetModsFor(ModType type) => throw new System.NotImplementedException(); + public override IEnumerable GetModsFor(ModType type) => throw new NotImplementedException(); - public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => throw new System.NotImplementedException(); + public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => throw new NotImplementedException(); - public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new System.NotImplementedException(); + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new NotImplementedException(); - public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new System.NotImplementedException(); + public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => throw new NotImplementedException(); public override string Description => string.Empty; public override string ShortName => string.Empty; From 17029f0b927b7ec03cc1e193c7fd0dac751e4e09 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Aug 2022 13:58:57 +0900 Subject: [PATCH 0691/2686] Ensure clones don't reference to MaximumStatistics --- osu.Game/Scoring/ScoreInfo.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 99e0726da7..25a7bad9e8 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -136,6 +136,7 @@ namespace osu.Game.Scoring var clone = (ScoreInfo)this.Detach().MemberwiseClone(); clone.Statistics = new Dictionary(clone.Statistics); + clone.MaximumStatistics = new Dictionary(clone.MaximumStatistics); clone.RealmUser = new RealmUser { OnlineID = RealmUser.OnlineID, From 8eab36f8c9ccb0d14ccdd554a2afb95da2d32789 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Aug 2022 14:02:10 +0900 Subject: [PATCH 0692/2686] Actually fix possible NaN value --- .../Difficulty/TaikoPerformanceCalculator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 6b1ea58129..95a1e8bc66 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -38,7 +38,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000. - effectiveMissCount = Math.Max(1.0, Math.Min(0, 1000.0 / totalSuccessfulHits)) * countMiss; + if (totalSuccessfulHits > 0) + effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; double multiplier = 1.13; From 1032b2a68c8b1d16b98dc7997d81d4c0d2db2baf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 14:03:25 +0900 Subject: [PATCH 0693/2686] Fix some `BeatmapCarousel` tests not correctly reinitialising local data per run Closes https://github.com/ppy/osu/issues/19949. --- .../SongSelect/TestSceneBeatmapCarousel.cs | 125 ++++++++++++------ 1 file changed, 84 insertions(+), 41 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index bb9e83a21c..c3e485d56b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -244,8 +244,12 @@ namespace osu.Game.Tests.Visual.SongSelect const int total_set_count = 200; - for (int i = 0; i < total_set_count; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo()); + AddStep("Populuate beatmap sets", () => + { + sets.Clear(); + for (int i = 0; i < total_set_count; i++) + sets.Add(TestResources.CreateTestBeatmapSetInfo()); + }); loadBeatmaps(sets); @@ -275,8 +279,12 @@ namespace osu.Game.Tests.Visual.SongSelect const int total_set_count = 20; - for (int i = 0; i < total_set_count; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo(3)); + AddStep("Populuate beatmap sets", () => + { + sets.Clear(); + for (int i = 0; i < total_set_count; i++) + sets.Add(TestResources.CreateTestBeatmapSetInfo(3)); + }); loadBeatmaps(sets); @@ -493,18 +501,23 @@ namespace osu.Game.Tests.Visual.SongSelect const string zzz_string = "zzzzz"; - for (int i = 0; i < 20; i++) + AddStep("Populuate beatmap sets", () => { - var set = TestResources.CreateTestBeatmapSetInfo(); + sets.Clear(); - if (i == 4) - set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string); + for (int i = 0; i < 20; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(); - if (i == 16) - set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_string); + if (i == 4) + set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string); - sets.Add(set); - } + if (i == 16) + set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_string); + + sets.Add(set); + } + }); loadBeatmaps(sets); @@ -521,21 +534,27 @@ namespace osu.Game.Tests.Visual.SongSelect public void TestSortingStability() { var sets = new List(); + int idOffset = 0; - for (int i = 0; i < 10; i++) + AddStep("Populuate beatmap sets", () => { - var set = TestResources.CreateTestBeatmapSetInfo(); + sets.Clear(); - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); + for (int i = 0; i < 10; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(); - beatmap.Metadata.Artist = $"artist {i / 2}"; - beatmap.Metadata.Title = $"title {9 - i}"; + // only need to set the first as they are a shared reference. + var beatmap = set.Beatmaps.First(); - sets.Add(set); - } + beatmap.Metadata.Artist = $"artist {i / 2}"; + beatmap.Metadata.Title = $"title {9 - i}"; - int idOffset = sets.First().OnlineID; + sets.Add(set); + } + + idOffset = sets.First().OnlineID; + }); loadBeatmaps(sets); @@ -556,26 +575,32 @@ namespace osu.Game.Tests.Visual.SongSelect public void TestSortingStabilityWithNewItems() { List sets = new List(); + int idOffset = 0; - for (int i = 0; i < 3; i++) + AddStep("Populuate beatmap sets", () => { - var set = TestResources.CreateTestBeatmapSetInfo(3); + sets.Clear(); - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); + for (int i = 0; i < 3; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(3); - beatmap.Metadata.Artist = "same artist"; - beatmap.Metadata.Title = "same title"; + // only need to set the first as they are a shared reference. + var beatmap = set.Beatmaps.First(); - sets.Add(set); - } + beatmap.Metadata.Artist = "same artist"; + beatmap.Metadata.Title = "same title"; - int idOffset = sets.First().OnlineID; + sets.Add(set); + } + + idOffset = sets.First().OnlineID; + }); loadBeatmaps(sets); AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); - AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); + assertOriginalOrderMaintained(); AddStep("Add new item", () => { @@ -590,10 +615,16 @@ namespace osu.Game.Tests.Visual.SongSelect carousel.UpdateBeatmapSet(set); }); - AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); + assertOriginalOrderMaintained(); AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false)); - AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); + assertOriginalOrderMaintained(); + + void assertOriginalOrderMaintained() + { + AddAssert("Items remain in original order", + () => carousel.BeatmapSets.Select(s => s.OnlineID), () => Is.EqualTo(carousel.BeatmapSets.Select((set, index) => idOffset + index))); + } } [Test] @@ -601,13 +632,18 @@ namespace osu.Game.Tests.Visual.SongSelect { List sets = new List(); - for (int i = 0; i < 3; i++) + AddStep("Populuate beatmap sets", () => { - var set = TestResources.CreateTestBeatmapSetInfo(3); - set.Beatmaps[0].StarRating = 3 - i; - set.Beatmaps[2].StarRating = 6 + i; - sets.Add(set); - } + sets.Clear(); + + for (int i = 0; i < 3; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(3); + set.Beatmaps[0].StarRating = 3 - i; + set.Beatmaps[2].StarRating = 6 + i; + sets.Add(set); + } + }); loadBeatmaps(sets); @@ -759,8 +795,13 @@ namespace osu.Game.Tests.Visual.SongSelect { List manySets = new List(); - for (int i = 1; i <= 50; i++) - manySets.Add(TestResources.CreateTestBeatmapSetInfo(3)); + AddStep("Populuate beatmap sets", () => + { + manySets.Clear(); + + for (int i = 1; i <= 50; i++) + manySets.Add(TestResources.CreateTestBeatmapSetInfo(3)); + }); loadBeatmaps(manySets); @@ -791,6 +832,8 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("populate maps", () => { + manySets.Clear(); + for (int i = 0; i < 10; i++) { manySets.Add(TestResources.CreateTestBeatmapSetInfo(3, new[] From 4c45f7d938d90d41c7dd6fb6b6f23e2c51190f4b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 14:26:20 +0900 Subject: [PATCH 0694/2686] Ensure `FailAnimation` can't be `Start`ed after filters are already removed --- osu.Game/Screens/Play/FailAnimation.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index c1223d7262..312e752cc6 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -105,6 +105,7 @@ namespace osu.Game.Screens.Play } private bool started; + private bool filtersRemoved; /// /// Start the fail animation playing. @@ -113,6 +114,7 @@ namespace osu.Game.Screens.Play public void Start() { if (started) throw new InvalidOperationException("Animation cannot be started more than once."); + if (filtersRemoved) throw new InvalidOperationException("Animation cannot be started after filters have been removed."); started = true; @@ -155,6 +157,11 @@ namespace osu.Game.Screens.Play public void RemoveFilters(bool resetTrackFrequency = true) { + if (filtersRemoved) + return; + + filtersRemoved = true; + if (resetTrackFrequency) track?.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq); From 8f4a953d11a4ef3ddf7eaf3d46b75a2e40f570b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 14:26:42 +0900 Subject: [PATCH 0695/2686] Ensure fail animation sequence isn't run after the player exit sequence has started --- osu.Game/Screens/Play/Player.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 6827ff04d3..cd7bf6fe9e 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; @@ -828,9 +829,17 @@ namespace osu.Game.Screens.Play private bool onFail() { + // Failing after the quit sequence has started may cause weird side effects with the fail animation / effects. + if (GameplayState.HasQuit) + return false; + if (!CheckModsAllowFailure()) return false; + Debug.Assert(!GameplayState.HasFailed); + Debug.Assert(!GameplayState.HasPassed); + Debug.Assert(!GameplayState.HasQuit); + GameplayState.HasFailed = true; updateGameplayState(); From ec60e164392acda3e644726e5774be04df6afd7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 14:35:42 +0900 Subject: [PATCH 0696/2686] Apply NRT to `FailAnimation` --- osu.Game/Screens/Play/FailAnimation.cs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index 312e752cc6..4d3b08cbe0 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -1,14 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Game.Rulesets.UI; using System; using System.Collections.Generic; -using JetBrains.Annotations; using ManagedBass.Fx; using osu.Framework.Allocation; using osu.Framework.Audio.Sample; @@ -34,27 +31,27 @@ namespace osu.Game.Screens.Play /// public class FailAnimation : Container { - public Action OnComplete; + public Action? OnComplete; private readonly DrawableRuleset drawableRuleset; private readonly BindableDouble trackFreq = new BindableDouble(1); private readonly BindableDouble volumeAdjustment = new BindableDouble(0.5); - private Container filters; + private Container filters = null!; - private Box redFlashLayer; + private Box redFlashLayer = null!; - private Track track; + private Track? track; - private AudioFilter failLowPassFilter; - private AudioFilter failHighPassFilter; + private AudioFilter failLowPassFilter = null!; + private AudioFilter failHighPassFilter = null!; private const float duration = 2500; - private Sample failSample; + private Sample? failSample; [Resolved] - private OsuConfigManager config { get; set; } + private OsuConfigManager config { get; set; } = null!; protected override Container Content { get; } = new Container { @@ -66,8 +63,7 @@ namespace osu.Game.Screens.Play /// /// The player screen background, used to adjust appearance on failing. /// - [CanBeNull] - public BackgroundScreen Background { private get; set; } + public BackgroundScreen? Background { private get; set; } public FailAnimation(DrawableRuleset drawableRuleset) { @@ -127,7 +123,7 @@ namespace osu.Game.Screens.Play failHighPassFilter.CutoffTo(300); failLowPassFilter.CutoffTo(300, duration, Easing.OutCubic); - failSample.Play(); + failSample?.Play(); track.AddAdjustment(AdjustableProperty.Frequency, trackFreq); track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment); From ad3dd1c700e09b30a64d90e00903ae3dc24f7923 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 14:45:00 +0900 Subject: [PATCH 0697/2686] Fix a couple of oversights regarding `track` nullability --- osu.Game/Beatmaps/WorkingBeatmap.cs | 1 + osu.Game/Screens/Play/FailAnimation.cs | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 301610ee58..eb914e61d4 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -146,6 +146,7 @@ namespace osu.Game.Beatmaps /// Get the loaded audio track instance. must have first been called. /// This generally happens via MusicController when changing the global beatmap. /// + [NotNull] public Track Track { get diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index 4d3b08cbe0..965d3d3454 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Play private Box redFlashLayer = null!; - private Track? track; + private Track track = null!; private AudioFilter failLowPassFilter = null!; private AudioFilter failHighPassFilter = null!; @@ -153,15 +153,17 @@ namespace osu.Game.Screens.Play public void RemoveFilters(bool resetTrackFrequency = true) { - if (filtersRemoved) - return; + if (filtersRemoved) return; filtersRemoved = true; - if (resetTrackFrequency) - track?.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq); + if (!started) + return; - track?.RemoveAdjustment(AdjustableProperty.Volume, volumeAdjustment); + if (resetTrackFrequency) + track.RemoveAdjustment(AdjustableProperty.Frequency, trackFreq); + + track.RemoveAdjustment(AdjustableProperty.Volume, volumeAdjustment); if (filters.Parent == null) return; From a6ed589db4fad90248c56f268c0e94a25c3edd2f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 14:47:32 +0900 Subject: [PATCH 0698/2686] Remove guard against `RemoveFilters` running more than once It turns out this is required to remove some filters immediate, and some later. Weird. --- osu.Game/Screens/Play/FailAnimation.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index 965d3d3454..7275b369c3 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -153,8 +153,6 @@ namespace osu.Game.Screens.Play public void RemoveFilters(bool resetTrackFrequency = true) { - if (filtersRemoved) return; - filtersRemoved = true; if (!started) From 091c51e6646935e0b5616b9b00c11d58462aa3ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 15:00:32 +0900 Subject: [PATCH 0699/2686] Fix `SliderPath.Version` bindings not being correctly cleaned up on path changes --- .../Sliders/Components/PathControlPointVisualiser.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 0506e8ab8a..0febfba5f2 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -142,8 +142,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components case NotifyCollectionChangedAction.Remove: foreach (var point in e.OldItems.Cast()) { - Pieces.RemoveAll(p => p.ControlPoint == point); - Connections.RemoveAll(c => c.ControlPoint == point); + foreach (var piece in Pieces.Where(p => p.ControlPoint == point)) + piece.RemoveAndDisposeImmediately(); + foreach (var connection in Connections.Where(c => c.ControlPoint == point)) + connection.RemoveAndDisposeImmediately(); } // If removing before the end of the path, From 3ca4bdc0878d220c3ba4978c0e5fc2421c037eb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 15:13:38 +0900 Subject: [PATCH 0700/2686] Add `ToArray()` calls to removal iteration for safety --- .../Sliders/Components/PathControlPointVisualiser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 0febfba5f2..c1908ef44c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -142,9 +142,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components case NotifyCollectionChangedAction.Remove: foreach (var point in e.OldItems.Cast()) { - foreach (var piece in Pieces.Where(p => p.ControlPoint == point)) + foreach (var piece in Pieces.Where(p => p.ControlPoint == point).ToArray()) piece.RemoveAndDisposeImmediately(); - foreach (var connection in Connections.Where(c => c.ControlPoint == point)) + foreach (var connection in Connections.Where(c => c.ControlPoint == point).ToArray()) connection.RemoveAndDisposeImmediately(); } From 6840e906e79e8fe22a8820166ddd01e4cbaeba92 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 25 Aug 2022 09:50:52 +0300 Subject: [PATCH 0701/2686] `watchedUsers` -> `watchedUsersRefCounts` --- osu.Game/Online/Spectator/SpectatorClient.cs | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index f1ce6258d6..592bae80ba 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -67,7 +67,7 @@ namespace osu.Game.Online.Spectator /// /// A dictionary containing all users currently being watched, with the number of watching components for each user. /// - private readonly Dictionary watchedUsers = new Dictionary(); + private readonly Dictionary watchedUsersRefCounts = new Dictionary(); private readonly BindableDictionary watchedUserStates = new BindableDictionary(); @@ -95,8 +95,8 @@ namespace osu.Game.Online.Spectator if (connected.NewValue) { // get all the users that were previously being watched - var users = new Dictionary(watchedUsers); - watchedUsers.Clear(); + var users = new Dictionary(watchedUsersRefCounts); + watchedUsersRefCounts.Clear(); // resubscribe to watched users. foreach ((int user, int watchers) in users) @@ -125,7 +125,7 @@ namespace osu.Game.Online.Spectator if (!playingUsers.Contains(userId)) playingUsers.Add(userId); - if (watchedUsers.ContainsKey(userId)) + if (watchedUsersRefCounts.ContainsKey(userId)) watchedUserStates[userId] = state; OnUserBeganPlaying?.Invoke(userId, state); @@ -140,7 +140,7 @@ namespace osu.Game.Online.Spectator { playingUsers.Remove(userId); - if (watchedUsers.ContainsKey(userId)) + if (watchedUsersRefCounts.ContainsKey(userId)) watchedUserStates[userId] = state; OnUserFinishedPlaying?.Invoke(userId, state); @@ -236,13 +236,13 @@ namespace osu.Game.Online.Spectator { Debug.Assert(ThreadSafety.IsUpdateThread); - if (watchedUsers.ContainsKey(userId)) + if (watchedUsersRefCounts.ContainsKey(userId)) { - watchedUsers[userId]++; + watchedUsersRefCounts[userId]++; return; } - watchedUsers.Add(userId, 1); + watchedUsersRefCounts.Add(userId, 1); WatchUserInternal(userId); } @@ -252,13 +252,13 @@ namespace osu.Game.Online.Spectator // Todo: This should not be a thing, but requires framework changes. Schedule(() => { - if (watchedUsers.TryGetValue(userId, out int watchers) && watchers > 1) + if (watchedUsersRefCounts.TryGetValue(userId, out int watchers) && watchers > 1) { - watchedUsers[userId]--; + watchedUsersRefCounts[userId]--; return; } - watchedUsers.Remove(userId); + watchedUsersRefCounts.Remove(userId); watchedUserStates.Remove(userId); StopWatchingUserInternal(userId); }); From a5c61d9a5211fb981ee453df40f534a993fc8880 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 16:44:12 +0900 Subject: [PATCH 0702/2686] Improve understandability of `TestMostInSyncUserIsAudioSource` --- .../TestSceneMultiSpectatorScreen.cs | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 3226eb992d..e9539baf27 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -165,11 +165,11 @@ namespace osu.Game.Tests.Visual.Multiplayer sendFrames(PLAYER_1_ID, 40); sendFrames(PLAYER_2_ID, 20); - checkPaused(PLAYER_2_ID, true); + waitUntilPaused(PLAYER_2_ID, true); checkPausedInstant(PLAYER_1_ID, false); AddAssert("master clock still running", () => this.ChildrenOfType().Single().IsRunning); - checkPaused(PLAYER_1_ID, true); + waitUntilPaused(PLAYER_1_ID, true); AddUntilStep("master clock paused", () => !this.ChildrenOfType().Single().IsRunning); } @@ -222,11 +222,11 @@ namespace osu.Game.Tests.Visual.Multiplayer checkPausedInstant(PLAYER_2_ID, false); // Eventually player 2 will pause, player 1 must remain running. - checkPaused(PLAYER_2_ID, true); + waitUntilPaused(PLAYER_2_ID, true); checkPausedInstant(PLAYER_1_ID, false); // Eventually both players will run out of frames and should pause. - checkPaused(PLAYER_1_ID, true); + waitUntilPaused(PLAYER_1_ID, true); checkPausedInstant(PLAYER_2_ID, true); // Send more frames for the first player only. Player 1 should start playing with player 2 remaining paused. @@ -253,7 +253,7 @@ namespace osu.Game.Tests.Visual.Multiplayer checkPausedInstant(PLAYER_2_ID, false); // Eventually player 2 will run out of frames and should pause. - checkPaused(PLAYER_2_ID, true); + waitUntilPaused(PLAYER_2_ID, true); AddWaitStep("wait a few more frames", 10); // Send more frames for player 2. It should unpause. @@ -271,21 +271,28 @@ namespace osu.Game.Tests.Visual.Multiplayer start(new[] { PLAYER_1_ID, PLAYER_2_ID }); loadSpectateScreen(); + // With no frames, the synchronisation state will be TooFarAhead. + // In this state, all players should be muted. assertMuted(PLAYER_1_ID, true); assertMuted(PLAYER_2_ID, true); - sendFrames(PLAYER_1_ID); - sendFrames(PLAYER_2_ID, 20); - checkPaused(PLAYER_1_ID, false); - assertOneNotMuted(); + // Send frames for both players, with more frames for player 2. + sendFrames(PLAYER_1_ID, 5); + sendFrames(PLAYER_2_ID, 40); - checkPaused(PLAYER_1_ID, true); + // While both players are running, one of them should be un-muted. + waitUntilPaused(PLAYER_1_ID, false); + assertOnePlayerNotMuted(); + + // After player 1 runs out of frames, the un-muted player should always be player 2. + waitUntilPaused(PLAYER_1_ID, true); + waitUntilPaused(PLAYER_2_ID, false); assertMuted(PLAYER_1_ID, true); assertMuted(PLAYER_2_ID, false); sendFrames(PLAYER_1_ID, 100); waitForCatchup(PLAYER_1_ID); - checkPaused(PLAYER_2_ID, true); + waitUntilPaused(PLAYER_2_ID, true); assertMuted(PLAYER_1_ID, false); assertMuted(PLAYER_2_ID, true); @@ -319,7 +326,7 @@ namespace osu.Game.Tests.Visual.Multiplayer sendFrames(PLAYER_1_ID, 300); AddWaitStep("wait maximum start delay seconds", (int)(SpectatorSyncManager.MAXIMUM_START_DELAY / TimePerAction)); - checkPaused(PLAYER_1_ID, false); + waitUntilPaused(PLAYER_1_ID, false); sendFrames(PLAYER_2_ID, 300); AddUntilStep("player 2 playing from correct point in time", () => getPlayer(PLAYER_2_ID).ChildrenOfType().Single().FrameStableClock.CurrentTime > 30000); @@ -456,18 +463,18 @@ namespace osu.Game.Tests.Visual.Multiplayer }); } - private void checkPaused(int userId, bool state) + private void waitUntilPaused(int userId, bool state) => AddUntilStep($"{userId} is {(state ? "paused" : "playing")}", () => getPlayer(userId).ChildrenOfType().First().IsRunning != state); private void checkPausedInstant(int userId, bool state) { - checkPaused(userId, state); + waitUntilPaused(userId, state); // Todo: The following should work, but is broken because SpectatorScreen retrieves the WorkingBeatmap via the BeatmapManager, bypassing the test scene clock and running real-time. // AddAssert($"{userId} is {(state ? "paused" : "playing")}", () => getPlayer(userId).ChildrenOfType().First().GameplayClock.IsRunning != state); } - private void assertOneNotMuted() => AddAssert("one player not muted", () => spectatorScreen.ChildrenOfType().Count(p => !p.Mute) == 1); + private void assertOnePlayerNotMuted() => AddAssert("one player not muted", () => spectatorScreen.ChildrenOfType().Count(p => !p.Mute) == 1); private void assertMuted(int userId, bool muted) => AddAssert($"{userId} {(muted ? "is" : "is not")} muted", () => getInstance(userId).Mute == muted); From e2e10a8f267b82baae1e693dcce9d07b847dd569 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Aug 2022 17:14:35 +0900 Subject: [PATCH 0703/2686] Add some explanatory comments to conditions --- osu.Game/Rulesets/Scoring/HitResult.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Rulesets/Scoring/HitResult.cs b/osu.Game/Rulesets/Scoring/HitResult.cs index e6aba4a70e..0c898e9543 100644 --- a/osu.Game/Rulesets/Scoring/HitResult.cs +++ b/osu.Game/Rulesets/Scoring/HitResult.cs @@ -175,6 +175,7 @@ namespace osu.Game.Rulesets.Scoring /// public static bool AffectsAccuracy(this HitResult result) { + // LegacyComboIncrease is a special type which is neither a basic, tick, bonus, or accuracy-affecting result. if (result == HitResult.LegacyComboIncrease) return false; @@ -186,6 +187,7 @@ namespace osu.Game.Rulesets.Scoring /// public static bool IsBasic(this HitResult result) { + // LegacyComboIncrease is a special type which is neither a basic, tick, bonus, or accuracy-affecting result. if (result == HitResult.LegacyComboIncrease) return false; @@ -250,6 +252,7 @@ namespace osu.Game.Rulesets.Scoring /// public static bool IsScorable(this HitResult result) { + // LegacyComboIncrease is not actually scorable (in terms of usable by rulesets for that purpose), but needs to be defined as such to be correctly included in statistics output. if (result == HitResult.LegacyComboIncrease) return true; From 9bca7223f67e09626a0d1fd927f4328ec35248a8 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Aug 2022 17:16:30 +0900 Subject: [PATCH 0704/2686] Adjust xmldoc to better explain score contribution --- osu.Game/Rulesets/Scoring/HitResult.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/HitResult.cs b/osu.Game/Rulesets/Scoring/HitResult.cs index 0c898e9543..5047fdea82 100644 --- a/osu.Game/Rulesets/Scoring/HitResult.cs +++ b/osu.Game/Rulesets/Scoring/HitResult.cs @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Scoring IgnoreHit, /// - /// A special result used as a padding value for legacy rulesets. It is a hit type and affects combo, but does not contribute to score. + /// A special result used as a padding value for legacy rulesets. It is a hit type and affects combo, but does not affect the base score (does not affect accuracy). /// /// /// DO NOT USE. From ddb434f47a314c38bdb5892c4029c9835d91ac87 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 17:30:13 +0900 Subject: [PATCH 0705/2686] Rename asserts to method names to make it easier to track in logs --- .../TestSceneMultiSpectatorScreen.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index e9539baf27..7235e10642 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -278,7 +278,7 @@ namespace osu.Game.Tests.Visual.Multiplayer // Send frames for both players, with more frames for player 2. sendFrames(PLAYER_1_ID, 5); - sendFrames(PLAYER_2_ID, 40); + sendFrames(PLAYER_2_ID, 20); // While both players are running, one of them should be un-muted. waitUntilPaused(PLAYER_1_ID, false); @@ -452,6 +452,10 @@ namespace osu.Game.Tests.Visual.Multiplayer }); } + /// + /// Send new frames on behalf of a user. + /// Frames will last for count * 100 milliseconds. + /// private void sendFrames(int userId, int count = 10) => sendFrames(new[] { userId }, count); private void sendFrames(int[] userIds, int count = 10) @@ -464,7 +468,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } private void waitUntilPaused(int userId, bool state) - => AddUntilStep($"{userId} is {(state ? "paused" : "playing")}", () => getPlayer(userId).ChildrenOfType().First().IsRunning != state); + => AddUntilStep($"{nameof(waitUntilPaused)}({userId}, {state})", () => getPlayer(userId).ChildrenOfType().First().IsRunning != state); private void checkPausedInstant(int userId, bool state) { @@ -474,19 +478,19 @@ namespace osu.Game.Tests.Visual.Multiplayer // AddAssert($"{userId} is {(state ? "paused" : "playing")}", () => getPlayer(userId).ChildrenOfType().First().GameplayClock.IsRunning != state); } - private void assertOnePlayerNotMuted() => AddAssert("one player not muted", () => spectatorScreen.ChildrenOfType().Count(p => !p.Mute) == 1); + private void assertOnePlayerNotMuted() => AddAssert(nameof(assertOnePlayerNotMuted), () => spectatorScreen.ChildrenOfType().Count(p => !p.Mute) == 1); private void assertMuted(int userId, bool muted) - => AddAssert($"{userId} {(muted ? "is" : "is not")} muted", () => getInstance(userId).Mute == muted); + => AddAssert($"{nameof(assertMuted)}({userId}, {muted})", () => getInstance(userId).Mute == muted); private void assertRunning(int userId) - => AddAssert($"{userId} clock running", () => getInstance(userId).SpectatorPlayerClock.IsRunning); + => AddAssert($"{nameof(assertRunning)}({userId})", () => getInstance(userId).SpectatorPlayerClock.IsRunning); private void assertNotCatchingUp(int userId) - => AddAssert($"{userId} in sync", () => !getInstance(userId).SpectatorPlayerClock.IsCatchingUp); + => AddAssert($"{nameof(assertNotCatchingUp)}({userId})", () => !getInstance(userId).SpectatorPlayerClock.IsCatchingUp); private void waitForCatchup(int userId) - => AddUntilStep($"{userId} not catching up", () => !getInstance(userId).SpectatorPlayerClock.IsCatchingUp); + => AddUntilStep($"{nameof(waitForCatchup)}({userId})", () => !getInstance(userId).SpectatorPlayerClock.IsCatchingUp); private Player getPlayer(int userId) => getInstance(userId).ChildrenOfType().Single(); From a8c699610a2e2544e670eb955f1b45d1c2425407 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 17:58:15 +0900 Subject: [PATCH 0706/2686] Fix lead in tests not waiting for player to start running The tests are only meant to ensure that gameplay eventually starts. The case where failures can occur is where the master clock is behind the player clock (due to being in lead-in time). Because the test is running in real-time, it can take arbitrary amounts of time to catch up. If it took too long, the test would fail. --- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 7235e10642..3498ca5e6d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -400,7 +400,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for clock running", () => getInstance(PLAYER_1_ID).SpectatorPlayerClock.IsRunning); assertNotCatchingUp(PLAYER_1_ID); - assertRunning(PLAYER_1_ID); + waitForRunning(PLAYER_1_ID); } private void loadSpectateScreen(bool waitForPlayerLoad = true, Action? applyToBeatmap = null) @@ -486,6 +486,9 @@ namespace osu.Game.Tests.Visual.Multiplayer private void assertRunning(int userId) => AddAssert($"{nameof(assertRunning)}({userId})", () => getInstance(userId).SpectatorPlayerClock.IsRunning); + private void waitForRunning(int userId) + => AddUntilStep($"{nameof(waitForRunning)}({userId})", () => getInstance(userId).SpectatorPlayerClock.IsRunning); + private void assertNotCatchingUp(int userId) => AddAssert($"{nameof(assertNotCatchingUp)}({userId})", () => !getInstance(userId).SpectatorPlayerClock.IsCatchingUp); From 2d2bfac5e9c955b3047dca66c30635492a9d9e9d Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Thu, 25 Aug 2022 17:49:38 +0800 Subject: [PATCH 0707/2686] used `firstHitObject.Samples` as samples for `mergedHitObject` --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 061c5008c5..2c5bbdb279 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -371,6 +371,7 @@ namespace osu.Game.Rulesets.Osu.Edit Position = firstHitObject.Position, NewCombo = firstHitObject.NewCombo, SampleControlPoint = firstHitObject.SampleControlPoint, + Samples = firstHitObject.Samples, }; if (mergedHitObject.Path.ControlPoints.Count == 0) From ae38c9e58d94a036a33acdafc04c3f620f91400a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 19:18:17 +0900 Subject: [PATCH 0708/2686] 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 17a6178641..bff3627af7 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 0613db891b..5fc69e475f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index bf1e4e350c..f763e411be 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 16fee7ac1c402b751a9b0a57b10ba1892841b4de Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Thu, 25 Aug 2022 19:31:47 +0800 Subject: [PATCH 0709/2686] add visual test --- .../Editor/TestSceneObjectMerging.cs | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs index b68231ce64..7a5b6022b7 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs @@ -168,6 +168,99 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddAssert("spinner not merged", () => EditorBeatmap.HitObjects.Contains(spinner)); } + [Test] + public void TestSimpleMergeHitSound() + { + HitCircle? circle1 = null; + HitCircle? circle2 = null; + double sliderStartTime = 0; + + AddStep("select first two circles", () => + { + circle1 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle); + circle2 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle && h != circle1); + EditorClock.Seek(circle1.StartTime); + EditorBeatmap.SelectedHitObjects.Add(circle1); + EditorBeatmap.SelectedHitObjects.Add(circle2); + sliderStartTime = circle1.StartTime; + }); + + mergeSelection(); + + AddAssert("slider created", () => circle1 is not null && circle2 is not null && sliderCreatedFor( + (pos: circle1.Position, pathType: PathType.Linear), + (pos: circle2.Position, pathType: null))); + + AddStep("start editor clock", () => + { + EditorClock.Seek(sliderStartTime); + EditorClock.Start(); + }); + + AddStep("stop editor clock", () => + { + EditorClock.Stop(); + }); + + AddStep("undo", () => Editor.Undo()); + AddAssert("merged objects restored", () => circle1 is not null && circle2 is not null && objectsRestored(circle1, circle2)); + } + + [Test] + public void TestMergeCircleSliderHitsound() + { + HitCircle? circle1 = null; + Slider? slider = null; + HitCircle? circle2 = null; + double sliderStartTime = 0; + + AddStep("select a circle, slider, circle", () => + { + circle1 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle); + slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider && h.StartTime > circle1.StartTime); + circle2 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle && h.StartTime > slider.StartTime); + EditorClock.Seek(circle1.StartTime); + EditorBeatmap.SelectedHitObjects.Add(circle1); + EditorBeatmap.SelectedHitObjects.Add(slider); + EditorBeatmap.SelectedHitObjects.Add(circle2); + sliderStartTime = circle1.StartTime; + }); + + mergeSelection(); + + AddAssert("slider created", () => + { + if (circle1 is null || circle2 is null || slider is null) + return false; + + var controlPoints = slider.Path.ControlPoints; + (Vector2, PathType?)[] args = new (Vector2, PathType?)[controlPoints.Count + 2]; + args[0] = (circle1.Position, PathType.Linear); + + for (int i = 0; i < controlPoints.Count; i++) + { + args[i + 1] = (controlPoints[i].Position + slider.Position, i == controlPoints.Count - 1 ? PathType.Linear : controlPoints[i].Type); + } + + args[^1] = (circle2.Position, null); + return sliderCreatedFor(args); + }); + + AddStep("start editor clock", () => + { + EditorClock.Seek(sliderStartTime); + EditorClock.Start(); + }); + + AddStep("stop editor clock", () => + { + EditorClock.Stop(); + }); + + AddStep("undo", () => Editor.Undo()); + AddAssert("merged objects restored", () => circle1 is not null && circle2 is not null && objectsRestored(circle1, circle2)); + } + private void mergeSelection() { AddStep("merge selection", () => From a546aa267390b38402d064578e4749f93096ec51 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 21:33:33 +0900 Subject: [PATCH 0710/2686] Clamp `SpectatorPlayerClock`'s elapsed calculation to avoid player clocks getting too far ahead --- .../OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 62731c6903..45615d4e19 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -80,7 +80,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate // When in catch-up mode, the source is usually not running. // In such a case, its elapsed time may be zero, which would cause catch-up to get stuck. // To avoid this, use a constant 16ms elapsed time for now. Probably not too correct, but this whole logic isn't too correct anyway. - double elapsedSource = masterClock.ElapsedFrameTime != 0 ? masterClock.ElapsedFrameTime : 16; + // Clamping is required to ensure that player clocks don't get too far ahead if ProcessFrame is run multiple times. + double elapsedSource = masterClock.ElapsedFrameTime != 0 ? masterClock.ElapsedFrameTime : Math.Clamp(masterClock.CurrentTime - CurrentTime, 0, 16); double elapsed = elapsedSource * Rate; CurrentTime += elapsed; From a260d7872d58dda2249a941f3dd58a96eceb5764 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 21:50:10 +0900 Subject: [PATCH 0711/2686] 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 17a6178641..bff3627af7 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 0613db891b..5fc69e475f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index bf1e4e350c..f763e411be 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 29f3724047ec5e457a89f797f20689ac2e87ef54 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Fri, 26 Aug 2022 01:28:57 +0100 Subject: [PATCH 0712/2686] Changed UprightUnscaledContainer to UprightUnstretchedContainer. --- .../Containers/UprightUnscaledContainer.cs | 66 ++++++++++++++++--- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs index b6c3b56c4a..c64e4ee2b7 100644 --- a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs +++ b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs @@ -12,13 +12,24 @@ namespace osu.Game.Graphics.Containers /// /// A container that prevents itself and its children from getting rotated, scaled or flipped with its Parent. /// - public class UprightUnscaledContainer : Container + public class UprightUnstretchedContainer : Container { protected override Container Content => content; private readonly Container content; - public UprightUnscaledContainer() + /// + /// Controls how much this container scales compared to its parent (default is 1.0f). + /// + public float ScalingFactor { get; set; } + + /// + /// Controls the scaling of this container. + /// + public ScaleMode Scaling { get; set; } + + public UprightUnstretchedContainer() { + Scaling = ScaleMode.NoScaling; InternalChild = content = new GrowToFitContainer(); AddLayout(layout); } @@ -31,7 +42,7 @@ namespace osu.Game.Graphics.Containers if (!layout.IsValid) { - keepUprightAndUnscaled(); + keepUprightAndUnstretched(); layout.Validate(); } } @@ -39,7 +50,7 @@ namespace osu.Game.Graphics.Containers /// /// Keeps the drawable upright and unstretched preventing it from being rotated, sheared, scaled or flipped with its Parent. /// - private void keepUprightAndUnscaled() + private void keepUprightAndUnstretched() { // Decomposes the inverse of the parent FrawInfo.Matrix into rotation, shear and scale. var parentMatrix = Parent.DrawInfo.Matrix; @@ -58,13 +69,32 @@ namespace osu.Game.Graphics.Containers Matrix3 m = Matrix3.CreateRotationZ(-angle); reversedParrent *= m; - // Extract shear and scale. + // Extract shear. + float alpha = reversedParrent.M21 / reversedParrent.M22; + Shear = new Vector2(-alpha, 0); + + // Etract scale. float sx = reversedParrent.M11; float sy = reversedParrent.M22; - float alpha = reversedParrent.M21 / reversedParrent.M22; - Scale = new Vector2(sx, sy); - Shear = new Vector2(-alpha, 0); + Vector3 parentScale = parentMatrix.ExtractScale(); + + float usedScale = 1.0f; + + switch (Scaling) + { + case ScaleMode.Horizontal: + usedScale = parentScale.X; + break; + + case ScaleMode.Vertical: + usedScale = parentScale.Y; + break; + } + + usedScale = 1.0f + (usedScale - 1.0f) * ScalingFactor; + + Scale = new Vector2(sx * usedScale, sy * usedScale); } /// @@ -91,4 +121,24 @@ namespace osu.Game.Graphics.Containers } } } + + public enum ScaleMode + { + /// + /// Prevent this container from scaling. + /// + NoScaling, + + /// + /// Scale This container (vertically and horizontally) with the vertical axis of its parent + /// preserving the aspect ratio of the container. + /// + Vertical, + + /// + /// Scales This container (vertically and horizontally) with the horizontal axis of its parent + /// preserving the aspect ratio of the container. + /// + Horizontal, + } } From d98357aa5748d5a6ee400925684dc45a7bcdaec6 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Fri, 26 Aug 2022 01:30:44 +0100 Subject: [PATCH 0713/2686] Made text inside SongProgressInfo scale. --- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index c4cdc0cb29..83fe8b14c3 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -55,11 +55,13 @@ namespace osu.Game.Screens.Play.HUD Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, - Child = new UprightUnscaledContainer + Child = new UprightUnstretchedContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, + Scaling = ScaleMode.Vertical, + ScalingFactor = 0.5f, Child = timeCurrent = new OsuSpriteText { Origin = Anchor.Centre, @@ -74,11 +76,13 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, - Child = new UprightUnscaledContainer + Child = new UprightUnstretchedContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, + Scaling = ScaleMode.Vertical, + ScalingFactor = 0.5f, Child = progress = new OsuSpriteText { Origin = Anchor.Centre, @@ -93,11 +97,13 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.CentreRight, Anchor = Anchor.CentreRight, AutoSizeAxes = Axes.Both, - Child = new UprightUnscaledContainer + Child = new UprightUnstretchedContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, + Scaling = ScaleMode.Vertical, + ScalingFactor = 0.5f, Child = timeLeft = new OsuSpriteText { Origin = Anchor.Centre, From b0e7f63361aa072841a0614b6454aeb5aa243158 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Fri, 26 Aug 2022 12:34:33 +1000 Subject: [PATCH 0714/2686] Update angle multiplier to nerf repeated angles --- .../Evaluators/FlashlightEvaluator.cs | 28 ++++++++++++------- .../Difficulty/Skills/Flashlight.cs | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 9d2696c978..8cf8190554 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -7,6 +7,7 @@ using System; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; +using osu.Framework.Utils; namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { @@ -18,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators private const double min_velocity = 0.5; private const double slider_multiplier = 1.3; - private const double min_grid_multiplier = 0.35; + private const double min_angle_multiplier = 0.2; /// /// Evaluates the difficulty of memorising and hitting an object, based on: @@ -46,6 +47,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators OsuDifficultyHitObject lastObj = osuCurrent; + int angleRepeatCount = 0; + + // We want to round angles to make abusing the nerf a bit harder. + double initialRoundedAngle = 0.0; + if (osuCurrent.Angle != null) + initialRoundedAngle = Math.Round(MathUtils.RadiansToDegrees(osuCurrent.Angle.Value) / 2.0) * 2.0; + // This is iterating backwards in time from the current object. for (int i = 0; i < Math.Min(current.Index, 10); i++) { @@ -69,6 +77,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double opacityBonus = 1.0 + max_opacity_bonus * (1.0 - osuCurrent.OpacityAt(currentHitObject.StartTime, hidden)); result += stackNerf * opacityBonus * scalingFactor * jumpDistance / cumulativeStrainTime; + + if (currentObj.Angle != null && osuCurrent.Angle != null) { + double roundedAngle = Math.Round(MathUtils.RadiansToDegrees(currentObj.Angle.Value) / 2.0) * 2.0; + + if (roundedAngle == initialRoundedAngle) + angleRepeatCount++; + } } lastObj = currentObj; @@ -80,15 +95,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (hidden) result *= 1.0 + hidden_bonus; - // Nerf patterns with angles that are commonly used in grid maps. - // 0 deg, 60 deg, 120 deg and 180 deg are commonly used in hexgrid maps. - // 0 deg, 45 deg, 90 deg, 135 deg and 180 deg are commonly used in squaregrid maps. - if (osuCurrent.Angle != null) - { - double hexgridMultiplier = 1.0 - Math.Pow(Math.Cos((180 / 60.0) * (double)(osuCurrent.Angle)), 20.0); - double squaregridMultiplier = 1.0 - Math.Pow(Math.Cos((180 / 45.0) * (double)(osuCurrent.Angle)), 20.0); - result *= (1.0 - min_grid_multiplier) * hexgridMultiplier * squaregridMultiplier + min_grid_multiplier; - } + // Nerf patterns with repeated angles. + result *= min_angle_multiplier + (1.0 - min_angle_multiplier) / (angleRepeatCount + 1.0); double sliderBonus = 0.0; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 03130031ea..84ef109598 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills hasHiddenMod = mods.Any(m => m is OsuModHidden); } - private double skillMultiplier => 0.06; + private double skillMultiplier => 0.05; private double strainDecayBase => 0.15; private double currentStrain; From 6651e76e2e9215ebfe700d5fcb4720c2ae265308 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Fri, 26 Aug 2022 12:37:56 +1000 Subject: [PATCH 0715/2686] Remove whitespace --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 8cf8190554..f3953bdb79 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (currentObj.Angle != null && osuCurrent.Angle != null) { double roundedAngle = Math.Round(MathUtils.RadiansToDegrees(currentObj.Angle.Value) / 2.0) * 2.0; - + if (roundedAngle == initialRoundedAngle) angleRepeatCount++; } From d8854413cbbcf0607edd6093c9b0cfea8935a3ed Mon Sep 17 00:00:00 2001 From: MBmasher Date: Fri, 26 Aug 2022 12:38:36 +1000 Subject: [PATCH 0716/2686] Add newline --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index f3953bdb79..86b6170d13 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -78,7 +78,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators result += stackNerf * opacityBonus * scalingFactor * jumpDistance / cumulativeStrainTime; - if (currentObj.Angle != null && osuCurrent.Angle != null) { + if (currentObj.Angle != null && osuCurrent.Angle != null) + { double roundedAngle = Math.Round(MathUtils.RadiansToDegrees(currentObj.Angle.Value) / 2.0) * 2.0; if (roundedAngle == initialRoundedAngle) From 9862b79b47595d383e769f63d8f0dd9a207008c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 15:20:09 +0900 Subject: [PATCH 0717/2686] Fix typo in long comment --- osu.Game/Screens/Play/GameplayClockContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 21fffb2992..21f6814f7c 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -92,7 +92,7 @@ namespace osu.Game.Screens.Play // This accounts for the clock source potentially taking time to enter a completely stopped state Seek(GameplayClock.CurrentTime); - // The case which cause this to be added is FrameStabilityContainer, which manages its own current and elapsed time. + // The case which caused this to be added is FrameStabilityContainer, which manages its own current and elapsed time. // Because we generally update our own current time quicker than children can query it (via Start/Seek/Update), // this means that the first frame ever exposed to children may have a non-zero current time. // From 23efec65054946ca62f6b7f3b1473f9b55258c5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 15:56:47 +0900 Subject: [PATCH 0718/2686] Fix naming and comment typos --- .../Containers/UprightUnscaledContainer.cs | 19 ++++++++----------- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 6 +++--- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs index c64e4ee2b7..4d9630052a 100644 --- a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs +++ b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs @@ -10,9 +10,9 @@ using System; namespace osu.Game.Graphics.Containers { /// - /// A container that prevents itself and its children from getting rotated, scaled or flipped with its Parent. + /// A container that reverts any rotation (and optionally scale) applied by its direct parent. /// - public class UprightUnstretchedContainer : Container + public class UprightAspectMaintainingContainer : Container { protected override Container Content => content; private readonly Container content; @@ -20,16 +20,15 @@ namespace osu.Game.Graphics.Containers /// /// Controls how much this container scales compared to its parent (default is 1.0f). /// - public float ScalingFactor { get; set; } + public float ScalingFactor { get; set; } = 1; /// /// Controls the scaling of this container. /// - public ScaleMode Scaling { get; set; } + public ScaleMode Scaling { get; set; } = ScaleMode.Vertical; - public UprightUnstretchedContainer() + public UprightAspectMaintainingContainer() { - Scaling = ScaleMode.NoScaling; InternalChild = content = new GrowToFitContainer(); AddLayout(layout); } @@ -52,7 +51,7 @@ namespace osu.Game.Graphics.Containers /// private void keepUprightAndUnstretched() { - // Decomposes the inverse of the parent FrawInfo.Matrix into rotation, shear and scale. + // Decomposes the inverse of the parent DrawInfo.Matrix into rotation, shear and scale. var parentMatrix = Parent.DrawInfo.Matrix; // Remove Translation. @@ -130,14 +129,12 @@ namespace osu.Game.Graphics.Containers NoScaling, /// - /// Scale This container (vertically and horizontally) with the vertical axis of its parent - /// preserving the aspect ratio of the container. + /// Scale uniformly (maintaining aspect ratio) based on the vertical scale of the parent. /// Vertical, /// - /// Scales This container (vertically and horizontally) with the horizontal axis of its parent - /// preserving the aspect ratio of the container. + /// Scale uniformly (maintaining aspect ratio) based on the horizontal scale of the parent. /// Horizontal, } diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 83fe8b14c3..36ec16a607 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -55,7 +55,7 @@ namespace osu.Game.Screens.Play.HUD Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, - Child = new UprightUnstretchedContainer + Child = new UprightAspectMaintainingContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, @@ -76,7 +76,7 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, - Child = new UprightUnstretchedContainer + Child = new UprightAspectMaintainingContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, @@ -97,7 +97,7 @@ namespace osu.Game.Screens.Play.HUD Origin = Anchor.CentreRight, Anchor = Anchor.CentreRight, AutoSizeAxes = Axes.Both, - Child = new UprightUnstretchedContainer + Child = new UprightAspectMaintainingContainer { Origin = Anchor.Centre, Anchor = Anchor.Centre, From a40355186a1c8434535a7ccf286ee92e82c2d39d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 16:00:20 +0900 Subject: [PATCH 0719/2686] Tidy up constructor field initialisation --- osu.Game/Graphics/Containers/UprightUnscaledContainer.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs index 4d9630052a..d2cd7d3373 100644 --- a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs +++ b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs @@ -14,8 +14,7 @@ namespace osu.Game.Graphics.Containers /// public class UprightAspectMaintainingContainer : Container { - protected override Container Content => content; - private readonly Container content; + protected override Container Content { get; } /// /// Controls how much this container scales compared to its parent (default is 1.0f). @@ -27,14 +26,14 @@ namespace osu.Game.Graphics.Containers /// public ScaleMode Scaling { get; set; } = ScaleMode.Vertical; + private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawInfo, InvalidationSource.Parent); + public UprightAspectMaintainingContainer() { - InternalChild = content = new GrowToFitContainer(); + AddInternal(Content = new GrowToFitContainer()); AddLayout(layout); } - private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawInfo, InvalidationSource.Parent); - protected override void Update() { base.Update(); From ed0843aa84628501a937b787cbda995a88add486 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 16:46:22 +0900 Subject: [PATCH 0720/2686] Reword xmldoc regarding final clock source to read better --- osu.Game/Screens/Play/GameplayClockContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 21f6814f7c..1ae393d06a 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -52,7 +52,7 @@ namespace osu.Game.Screens.Play /// /// The adjustable source clock used for gameplay. Should be used for seeks and clock control. - /// This is the final clock exposed to gameplay components as an . + /// This is the final source exposed to gameplay components via delegation in this class. /// protected readonly FramedBeatmapClock GameplayClock; From 9050f54681dbf6acca1167c824c9fd30a3344c64 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 16:56:03 +0900 Subject: [PATCH 0721/2686] Split out test assertion methods to read better --- .../TestSceneMultiSpectatorScreen.cs | 84 ++++++++++--------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 3498ca5e6d..a11a67aebd 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -165,11 +165,11 @@ namespace osu.Game.Tests.Visual.Multiplayer sendFrames(PLAYER_1_ID, 40); sendFrames(PLAYER_2_ID, 20); - waitUntilPaused(PLAYER_2_ID, true); - checkPausedInstant(PLAYER_1_ID, false); + waitUntilPaused(PLAYER_2_ID); + checkRunningInstant(PLAYER_1_ID); AddAssert("master clock still running", () => this.ChildrenOfType().Single().IsRunning); - waitUntilPaused(PLAYER_1_ID, true); + waitUntilPaused(PLAYER_1_ID); AddUntilStep("master clock paused", () => !this.ChildrenOfType().Single().IsRunning); } @@ -181,13 +181,13 @@ namespace osu.Game.Tests.Visual.Multiplayer // Send frames for one player only, both should remain paused. sendFrames(PLAYER_1_ID, 20); - checkPausedInstant(PLAYER_1_ID, true); - checkPausedInstant(PLAYER_2_ID, true); + checkPausedInstant(PLAYER_1_ID); + checkPausedInstant(PLAYER_2_ID); // Send frames for the other player, both should now start playing. sendFrames(PLAYER_2_ID, 20); - checkPausedInstant(PLAYER_1_ID, false); - checkPausedInstant(PLAYER_2_ID, false); + checkRunningInstant(PLAYER_1_ID); + checkRunningInstant(PLAYER_2_ID); } [Test] @@ -198,15 +198,15 @@ namespace osu.Game.Tests.Visual.Multiplayer // Send frames for one player only, both should remain paused. sendFrames(PLAYER_1_ID, 1000); - checkPausedInstant(PLAYER_1_ID, true); - checkPausedInstant(PLAYER_2_ID, true); + checkPausedInstant(PLAYER_1_ID); + checkPausedInstant(PLAYER_2_ID); // Wait for the start delay seconds... AddWaitStep("wait maximum start delay seconds", (int)(SpectatorSyncManager.MAXIMUM_START_DELAY / TimePerAction)); // Player 1 should start playing by itself, player 2 should remain paused. - checkPausedInstant(PLAYER_1_ID, false); - checkPausedInstant(PLAYER_2_ID, true); + checkRunningInstant(PLAYER_1_ID); + checkPausedInstant(PLAYER_2_ID); } [Test] @@ -218,26 +218,26 @@ namespace osu.Game.Tests.Visual.Multiplayer // Send initial frames for both players. A few more for player 1. sendFrames(PLAYER_1_ID, 20); sendFrames(PLAYER_2_ID); - checkPausedInstant(PLAYER_1_ID, false); - checkPausedInstant(PLAYER_2_ID, false); + checkRunningInstant(PLAYER_1_ID); + checkRunningInstant(PLAYER_2_ID); // Eventually player 2 will pause, player 1 must remain running. - waitUntilPaused(PLAYER_2_ID, true); - checkPausedInstant(PLAYER_1_ID, false); + waitUntilPaused(PLAYER_2_ID); + checkRunningInstant(PLAYER_1_ID); // Eventually both players will run out of frames and should pause. - waitUntilPaused(PLAYER_1_ID, true); - checkPausedInstant(PLAYER_2_ID, true); + waitUntilPaused(PLAYER_1_ID); + checkPausedInstant(PLAYER_2_ID); // Send more frames for the first player only. Player 1 should start playing with player 2 remaining paused. sendFrames(PLAYER_1_ID, 20); - checkPausedInstant(PLAYER_2_ID, true); - checkPausedInstant(PLAYER_1_ID, false); + checkPausedInstant(PLAYER_2_ID); + checkRunningInstant(PLAYER_1_ID); // Send more frames for the second player. Both should be playing sendFrames(PLAYER_2_ID, 20); - checkPausedInstant(PLAYER_2_ID, false); - checkPausedInstant(PLAYER_1_ID, false); + checkRunningInstant(PLAYER_2_ID); + checkRunningInstant(PLAYER_1_ID); } [Test] @@ -249,16 +249,16 @@ namespace osu.Game.Tests.Visual.Multiplayer // Send initial frames for both players. A few more for player 1. sendFrames(PLAYER_1_ID, 1000); sendFrames(PLAYER_2_ID, 30); - checkPausedInstant(PLAYER_1_ID, false); - checkPausedInstant(PLAYER_2_ID, false); + checkRunningInstant(PLAYER_1_ID); + checkRunningInstant(PLAYER_2_ID); // Eventually player 2 will run out of frames and should pause. - waitUntilPaused(PLAYER_2_ID, true); + waitUntilPaused(PLAYER_2_ID); AddWaitStep("wait a few more frames", 10); // Send more frames for player 2. It should unpause. sendFrames(PLAYER_2_ID, 1000); - checkPausedInstant(PLAYER_2_ID, false); + checkRunningInstant(PLAYER_2_ID); // Player 2 should catch up to player 1 after unpausing. waitForCatchup(PLAYER_2_ID); @@ -281,18 +281,18 @@ namespace osu.Game.Tests.Visual.Multiplayer sendFrames(PLAYER_2_ID, 20); // While both players are running, one of them should be un-muted. - waitUntilPaused(PLAYER_1_ID, false); + waitUntilRunning(PLAYER_1_ID); assertOnePlayerNotMuted(); // After player 1 runs out of frames, the un-muted player should always be player 2. - waitUntilPaused(PLAYER_1_ID, true); - waitUntilPaused(PLAYER_2_ID, false); + waitUntilPaused(PLAYER_1_ID); + waitUntilRunning(PLAYER_2_ID); assertMuted(PLAYER_1_ID, true); assertMuted(PLAYER_2_ID, false); sendFrames(PLAYER_1_ID, 100); waitForCatchup(PLAYER_1_ID); - waitUntilPaused(PLAYER_2_ID, true); + waitUntilPaused(PLAYER_2_ID); assertMuted(PLAYER_1_ID, false); assertMuted(PLAYER_2_ID, true); @@ -326,7 +326,7 @@ namespace osu.Game.Tests.Visual.Multiplayer sendFrames(PLAYER_1_ID, 300); AddWaitStep("wait maximum start delay seconds", (int)(SpectatorSyncManager.MAXIMUM_START_DELAY / TimePerAction)); - waitUntilPaused(PLAYER_1_ID, false); + waitUntilRunning(PLAYER_1_ID); sendFrames(PLAYER_2_ID, 300); AddUntilStep("player 2 playing from correct point in time", () => getPlayer(PLAYER_2_ID).ChildrenOfType().Single().FrameStableClock.CurrentTime > 30000); @@ -400,7 +400,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for clock running", () => getInstance(PLAYER_1_ID).SpectatorPlayerClock.IsRunning); assertNotCatchingUp(PLAYER_1_ID); - waitForRunning(PLAYER_1_ID); + waitUntilRunning(PLAYER_1_ID); } private void loadSpectateScreen(bool waitForPlayerLoad = true, Action? applyToBeatmap = null) @@ -467,12 +467,17 @@ namespace osu.Game.Tests.Visual.Multiplayer }); } - private void waitUntilPaused(int userId, bool state) - => AddUntilStep($"{nameof(waitUntilPaused)}({userId}, {state})", () => getPlayer(userId).ChildrenOfType().First().IsRunning != state); - - private void checkPausedInstant(int userId, bool state) + private void checkRunningInstant(int userId) { - waitUntilPaused(userId, state); + waitUntilRunning(userId); + + // Todo: The following should work, but is broken because SpectatorScreen retrieves the WorkingBeatmap via the BeatmapManager, bypassing the test scene clock and running real-time. + // AddAssert($"{userId} is {(state ? "paused" : "playing")}", () => getPlayer(userId).ChildrenOfType().First().GameplayClock.IsRunning != state); + } + + private void checkPausedInstant(int userId) + { + waitUntilPaused(userId); // Todo: The following should work, but is broken because SpectatorScreen retrieves the WorkingBeatmap via the BeatmapManager, bypassing the test scene clock and running real-time. // AddAssert($"{userId} is {(state ? "paused" : "playing")}", () => getPlayer(userId).ChildrenOfType().First().GameplayClock.IsRunning != state); @@ -486,8 +491,11 @@ namespace osu.Game.Tests.Visual.Multiplayer private void assertRunning(int userId) => AddAssert($"{nameof(assertRunning)}({userId})", () => getInstance(userId).SpectatorPlayerClock.IsRunning); - private void waitForRunning(int userId) - => AddUntilStep($"{nameof(waitForRunning)}({userId})", () => getInstance(userId).SpectatorPlayerClock.IsRunning); + private void waitUntilPaused(int userId) + => AddUntilStep($"{nameof(waitUntilPaused)}({userId})", () => !getPlayer(userId).ChildrenOfType().First().IsRunning); + + private void waitUntilRunning(int userId) + => AddUntilStep($"{nameof(waitUntilRunning)}({userId})", () => getPlayer(userId).ChildrenOfType().First().IsRunning); private void assertNotCatchingUp(int userId) => AddAssert($"{nameof(assertNotCatchingUp)}({userId})", () => !getInstance(userId).SpectatorPlayerClock.IsCatchingUp); From 31e459364bd2eb6a5c6879447fbd596dda0f5b52 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 18 Aug 2022 14:11:42 +0900 Subject: [PATCH 0722/2686] Use `FramedBeatmapClock` in `EditorClock` --- osu.Game/Screens/Edit/EditorClock.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index c3b29afd30..d55f2c0bf6 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -4,10 +4,12 @@ #nullable disable using System; +using System.Diagnostics; using System.Linq; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Transforms; using osu.Framework.Timing; using osu.Framework.Utils; @@ -19,7 +21,7 @@ namespace osu.Game.Screens.Edit /// /// A decoupled clock which adds editor-specific functionality, such as snapping to a user-defined beat divisor. /// - public class EditorClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock + public class EditorClock : CompositeComponent, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock { public IBindable Track => track; @@ -33,7 +35,7 @@ namespace osu.Game.Screens.Edit private readonly BindableBeatDivisor beatDivisor; - private readonly DecoupleableInterpolatingFramedClock underlyingClock; + private readonly FramedBeatmapClock underlyingClock; private bool playbackFinished; @@ -52,7 +54,8 @@ namespace osu.Game.Screens.Edit this.beatDivisor = beatDivisor ?? new BindableBeatDivisor(); - underlyingClock = new DecoupleableInterpolatingFramedClock(); + underlyingClock = new FramedBeatmapClock(applyOffsets: true); + AddInternal(underlyingClock); } /// @@ -219,6 +222,9 @@ namespace osu.Game.Screens.Edit public void ProcessFrame() { + // EditorClock wasn't being added in many places. This gives us more certainty that it is. + Debug.Assert(underlyingClock.LoadState > LoadState.NotLoaded); + underlyingClock.ProcessFrame(); playbackFinished = CurrentTime >= TrackLength; From fec744a7fe5b4d44fdcd801ef63ad14d63ee334f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 17:44:33 +0900 Subject: [PATCH 0723/2686] Add global `FramedBeatmapClock` for `BeatSyncProvider` components --- osu.Game/OsuGameBase.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 8d5c58d5f0..27ea3a76ae 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -185,6 +185,12 @@ namespace osu.Game private RealmAccess realm; + /// + /// For now, this is used as a source specifically for beat synced components. + /// Going forward, it could potentially be used as the single source-of-truth for beatmap timing. + /// + private readonly FramedBeatmapClock beatmapClock = new FramedBeatmapClock(true); + protected override Container Content => content; private Container content; @@ -368,10 +374,15 @@ namespace osu.Game AddInternal(MusicController = new MusicController()); dependencies.CacheAs(MusicController); + MusicController.TrackChanged += onTrackChanged; + AddInternal(beatmapClock); + Ruleset.BindValueChanged(onRulesetChanged); Beatmap.BindValueChanged(onBeatmapChanged); } + private void onTrackChanged(WorkingBeatmap beatmap, TrackChangeDirection direction) => beatmapClock.ChangeSource(beatmap.Track); + protected virtual void InitialiseFonts() { AddFont(Resources, @"Fonts/osuFont"); @@ -587,7 +598,7 @@ namespace osu.Game } ControlPointInfo IBeatSyncProvider.ControlPoints => Beatmap.Value.BeatmapLoaded ? Beatmap.Value.Beatmap.ControlPointInfo : null; - IClock IBeatSyncProvider.Clock => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track : (IClock)null; + IClock IBeatSyncProvider.Clock => beatmapClock; ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; } } From 78717956d536df4ba1bfea7e37f01920fb1a9f81 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Fri, 26 Aug 2022 16:55:18 +0800 Subject: [PATCH 0724/2686] add visual test --- .../Editor/TestSceneObjectMerging.cs | 88 ++++++------------- 1 file changed, 25 insertions(+), 63 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs index 7a5b6022b7..75a2361732 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osuTK; using osuTK.Input; +using System.Collections.Generic; namespace osu.Game.Rulesets.Osu.Tests.Editor { @@ -169,11 +170,11 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor } [Test] - public void TestSimpleMergeHitSound() + public void TestSimpleMergeSample() { HitCircle? circle1 = null; HitCircle? circle2 = null; - double sliderStartTime = 0; + AddStep("select first two circles", () => { @@ -182,83 +183,31 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor EditorClock.Seek(circle1.StartTime); EditorBeatmap.SelectedHitObjects.Add(circle1); EditorBeatmap.SelectedHitObjects.Add(circle2); - sliderStartTime = circle1.StartTime; }); mergeSelection(); - AddAssert("slider created", () => circle1 is not null && circle2 is not null && sliderCreatedFor( - (pos: circle1.Position, pathType: PathType.Linear), - (pos: circle2.Position, pathType: null))); - - AddStep("start editor clock", () => - { - EditorClock.Seek(sliderStartTime); - EditorClock.Start(); - }); - - AddStep("stop editor clock", () => - { - EditorClock.Stop(); - }); - - AddStep("undo", () => Editor.Undo()); - AddAssert("merged objects restored", () => circle1 is not null && circle2 is not null && objectsRestored(circle1, circle2)); + AddAssert("samples exist", () => sliderSampleExist()); } [Test] - public void TestMergeCircleSliderHitsound() + public void TestSliderCircleMergeSample() { - HitCircle? circle1 = null; Slider? slider = null; - HitCircle? circle2 = null; - double sliderStartTime = 0; + HitCircle? circle = null; - AddStep("select a circle, slider, circle", () => + AddStep("select a slider followed by a circle", () => { - circle1 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle); - slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider && h.StartTime > circle1.StartTime); - circle2 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle && h.StartTime > slider.StartTime); - EditorClock.Seek(circle1.StartTime); - EditorBeatmap.SelectedHitObjects.Add(circle1); + slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider); + circle = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle && h.StartTime > slider.StartTime); + EditorClock.Seek(slider.StartTime); EditorBeatmap.SelectedHitObjects.Add(slider); - EditorBeatmap.SelectedHitObjects.Add(circle2); - sliderStartTime = circle1.StartTime; + EditorBeatmap.SelectedHitObjects.Add(circle); }); mergeSelection(); - AddAssert("slider created", () => - { - if (circle1 is null || circle2 is null || slider is null) - return false; - - var controlPoints = slider.Path.ControlPoints; - (Vector2, PathType?)[] args = new (Vector2, PathType?)[controlPoints.Count + 2]; - args[0] = (circle1.Position, PathType.Linear); - - for (int i = 0; i < controlPoints.Count; i++) - { - args[i + 1] = (controlPoints[i].Position + slider.Position, i == controlPoints.Count - 1 ? PathType.Linear : controlPoints[i].Type); - } - - args[^1] = (circle2.Position, null); - return sliderCreatedFor(args); - }); - - AddStep("start editor clock", () => - { - EditorClock.Seek(sliderStartTime); - EditorClock.Start(); - }); - - AddStep("stop editor clock", () => - { - EditorClock.Stop(); - }); - - AddStep("undo", () => Editor.Undo()); - AddAssert("merged objects restored", () => circle1 is not null && circle2 is not null && objectsRestored(circle1, circle2)); + AddAssert("samples exist", () => sliderSampleExist()); } private void mergeSelection() @@ -302,5 +251,18 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor return true; } + + private bool sliderSampleExist() + { + if (EditorBeatmap.SelectedHitObjects.Count != 1) + return false; + + var mergedSlider = (Slider)EditorBeatmap.SelectedHitObjects.First(); + + if (mergedSlider.Samples[0] is null) + return false; + + return true; + } } } From 12d6d6793cd5eba002c0b39a976dc15c8c8955b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 18:08:39 +0900 Subject: [PATCH 0725/2686] Move `EditorClock` processing to `Update` and always decouple --- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Edit/EditorClock.cs | 38 ++++++++++++---------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index a7cbe1f1ad..ad8fda7ad0 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -220,7 +220,7 @@ namespace osu.Game.Screens.Edit } // Todo: should probably be done at a DrawableRuleset level to share logic with Player. - clock = new EditorClock(playableBeatmap, beatDivisor) { IsCoupled = false }; + clock = new EditorClock(playableBeatmap, beatDivisor); clock.ChangeSource(loadableBeatmap.Track); dependencies.CacheAs(clock); diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index d55f2c0bf6..7a00a74530 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Edit this.beatDivisor = beatDivisor ?? new BindableBeatDivisor(); - underlyingClock = new FramedBeatmapClock(applyOffsets: true); + underlyingClock = new FramedBeatmapClock(applyOffsets: true) { IsCoupled = false }; AddInternal(underlyingClock); } @@ -222,21 +222,7 @@ namespace osu.Game.Screens.Edit public void ProcessFrame() { - // EditorClock wasn't being added in many places. This gives us more certainty that it is. - Debug.Assert(underlyingClock.LoadState > LoadState.NotLoaded); - - underlyingClock.ProcessFrame(); - - playbackFinished = CurrentTime >= TrackLength; - - if (playbackFinished) - { - if (IsRunning) - underlyingClock.Stop(); - - if (CurrentTime > TrackLength) - underlyingClock.Seek(TrackLength); - } + // Noop to ensure an external consumer doesn't process the internal clock an extra time. } public double ElapsedFrameTime => underlyingClock.ElapsedFrameTime; @@ -253,18 +239,26 @@ namespace osu.Game.Screens.Edit public IClock Source => underlyingClock.Source; - public bool IsCoupled - { - get => underlyingClock.IsCoupled; - set => underlyingClock.IsCoupled = value; - } - private const double transform_time = 300; protected override void Update() { base.Update(); + // EditorClock wasn't being added in many places. This gives us more certainty that it is. + Debug.Assert(underlyingClock.LoadState > LoadState.NotLoaded); + + playbackFinished = CurrentTime >= TrackLength; + + if (playbackFinished) + { + if (IsRunning) + underlyingClock.Stop(); + + if (CurrentTime > TrackLength) + underlyingClock.Seek(TrackLength); + } + updateSeekingState(); } From 4b72e557701bf8358d771a710950d9126d593b93 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 17 Aug 2022 15:40:01 +0900 Subject: [PATCH 0726/2686] Fix various test scenes not adding `EditorClock` to the draw hierarchy --- .../CatchSelectionBlueprintTestScene.cs | 9 +- .../Editor/TestSceneManiaHitObjectComposer.cs | 8 +- .../Editor/TestSceneOsuDistanceSnapGrid.cs | 3 +- .../Editor/TestSceneTaikoHitObjectComposer.cs | 2 +- ...tSceneHitObjectComposerDistanceSnapping.cs | 18 +- .../Visual/Editing/TestSceneEditorClock.cs | 48 +++--- .../Editing/TestSceneEditorSeekSnapping.cs | 159 +++++++++--------- .../Editing/TestSceneTapTimingControl.cs | 4 +- .../TestSceneTimelineBlueprintContainer.cs | 2 +- .../Visual/Editing/TestSceneTimingScreen.cs | 12 +- .../Visual/Editing/TimelineTestScene.cs | 2 +- osu.Game/Tests/Visual/EditorClockTestScene.cs | 44 ++--- .../Visual/PlacementBlueprintTestScene.cs | 11 +- .../Visual/SelectionBlueprintTestScene.cs | 17 +- 14 files changed, 174 insertions(+), 165 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs index ea17fa400c..60fb31d1e0 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs @@ -70,10 +70,17 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor [Cached] private readonly BindableBeatDivisor beatDivisor; + protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; + public EditorBeatmapDependencyContainer(IBeatmap beatmap, BindableBeatDivisor beatDivisor) { - editorClock = new EditorClock(beatmap, beatDivisor); this.beatDivisor = beatDivisor; + + InternalChildren = new Drawable[] + { + editorClock = new EditorClock(beatmap, beatDivisor), + Content, + }; } } } diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs index 4ad27348fc..fcc9e2e6c3 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor public void Setup() => Schedule(() => { BeatDivisor.Value = 8; - Clock.Seek(0); + EditorClock.Seek(0); Child = composer = new TestComposer { RelativeSizeAxes = Axes.Both }; }); @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor { lastObject = this.ChildrenOfType().Single(d => d.HitObject == composer.EditorBeatmap.HitObjects.Last()); originalTime = lastObject.HitObject.StartTime; - Clock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime); + EditorClock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime); }); AddStep("select all objects", () => composer.EditorBeatmap.SelectedHitObjects.AddRange(composer.EditorBeatmap.HitObjects)); @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor { lastObject = this.ChildrenOfType().Single(d => d.HitObject == composer.EditorBeatmap.HitObjects.Last()); originalTime = lastObject.HitObject.StartTime; - Clock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime); + EditorClock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime); }); AddStep("select all objects", () => composer.EditorBeatmap.SelectedHitObjects.AddRange(composer.EditorBeatmap.HitObjects)); @@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor AddStep("seek to last object", () => { lastObject = this.ChildrenOfType().Single(d => d.HitObject == composer.EditorBeatmap.HitObjects.Last()); - Clock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime); + EditorClock.Seek(composer.EditorBeatmap.HitObjects.Last().StartTime); }); AddStep("select all objects", () => composer.EditorBeatmap.SelectedHitObjects.AddRange(composer.EditorBeatmap.HitObjects)); diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs index e54ce45ccc..c102678e00 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs @@ -59,10 +59,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor } }); - editorClock = new EditorClock(editorBeatmap); - base.Content.Children = new Drawable[] { + editorClock = new EditorClock(editorBeatmap), snapProvider, Content }; diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs index 16f17f4131..8d17918a92 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Editor public void Setup() => Schedule(() => { BeatDivisor.Value = 8; - Clock.Seek(0); + EditorClock.Seek(0); Child = new TestComposer { RelativeSizeAxes = Axes.Both }; }); diff --git a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs index 0e80f8f699..1e87ed27df 100644 --- a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs +++ b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.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. -#nullable disable - using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -23,13 +21,13 @@ namespace osu.Game.Tests.Editing [HeadlessTest] public class TestSceneHitObjectComposerDistanceSnapping : EditorClockTestScene { - private TestHitObjectComposer composer; + private TestHitObjectComposer composer = null!; [Cached(typeof(EditorBeatmap))] [Cached(typeof(IBeatSnapProvider))] private readonly EditorBeatmap editorBeatmap; - protected override Container Content { get; } + protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; public TestSceneHitObjectComposerDistanceSnapping() { @@ -40,15 +38,9 @@ namespace osu.Game.Tests.Editing { editorBeatmap = new EditorBeatmap(new OsuBeatmap { - BeatmapInfo = - { - Ruleset = new OsuRuleset().RulesetInfo, - }, + BeatmapInfo = { Ruleset = new OsuRuleset().RulesetInfo }, }), - Content = new Container - { - RelativeSizeAxes = Axes.Both, - } + Content }, }); } @@ -205,7 +197,7 @@ namespace osu.Game.Tests.Editing assertSnappedDistance(400, 400); } - private void assertSnapDistance(float expectedDistance, HitObject hitObject = null) + private void assertSnapDistance(float expectedDistance, HitObject? hitObject = null) => AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(hitObject ?? new HitObject()), () => Is.EqualTo(expectedDistance)); private void assertDurationToDistance(double duration, float expectedDistance) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs index 3c6820e49b..d598ebafa9 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs @@ -55,51 +55,51 @@ namespace osu.Game.Tests.Visual.Editing [Test] public void TestStopAtTrackEnd() { - AddStep("reset clock", () => Clock.Seek(0)); + AddStep("reset clock", () => EditorClock.Seek(0)); - AddStep("start clock", () => Clock.Start()); - AddAssert("clock running", () => Clock.IsRunning); + AddStep("start clock", () => EditorClock.Start()); + AddAssert("clock running", () => EditorClock.IsRunning); - AddStep("seek near end", () => Clock.Seek(Clock.TrackLength - 250)); - AddUntilStep("clock stops", () => !Clock.IsRunning); + AddStep("seek near end", () => EditorClock.Seek(EditorClock.TrackLength - 250)); + AddUntilStep("clock stops", () => !EditorClock.IsRunning); - AddUntilStep("clock stopped at end", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength)); + AddUntilStep("clock stopped at end", () => EditorClock.CurrentTime, () => Is.EqualTo(EditorClock.TrackLength)); - AddStep("start clock again", () => Clock.Start()); - AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500); + AddStep("start clock again", () => EditorClock.Start()); + AddAssert("clock looped to start", () => EditorClock.IsRunning && EditorClock.CurrentTime < 500); } [Test] public void TestWrapWhenStoppedAtTrackEnd() { - AddStep("reset clock", () => Clock.Seek(0)); + AddStep("reset clock", () => EditorClock.Seek(0)); - AddStep("stop clock", () => Clock.Stop()); - AddAssert("clock stopped", () => !Clock.IsRunning); + AddStep("stop clock", () => EditorClock.Stop()); + AddAssert("clock stopped", () => !EditorClock.IsRunning); - AddStep("seek exactly to end", () => Clock.Seek(Clock.TrackLength)); - AddAssert("clock stopped at end", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength)); + AddStep("seek exactly to end", () => EditorClock.Seek(EditorClock.TrackLength)); + AddAssert("clock stopped at end", () => EditorClock.CurrentTime, () => Is.EqualTo(EditorClock.TrackLength)); - AddStep("start clock again", () => Clock.Start()); - AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500); + AddStep("start clock again", () => EditorClock.Start()); + AddAssert("clock looped to start", () => EditorClock.IsRunning && EditorClock.CurrentTime < 500); } [Test] public void TestClampWhenSeekOutsideBeatmapBounds() { - AddStep("stop clock", () => Clock.Stop()); + AddStep("stop clock", () => EditorClock.Stop()); - AddStep("seek before start time", () => Clock.Seek(-1000)); - AddAssert("time is clamped to 0", () => Clock.CurrentTime, () => Is.EqualTo(0)); + AddStep("seek before start time", () => EditorClock.Seek(-1000)); + AddAssert("time is clamped to 0", () => EditorClock.CurrentTime, () => Is.EqualTo(0)); - AddStep("seek beyond track length", () => Clock.Seek(Clock.TrackLength + 1000)); - AddAssert("time is clamped to track length", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength)); + AddStep("seek beyond track length", () => EditorClock.Seek(EditorClock.TrackLength + 1000)); + AddAssert("time is clamped to track length", () => EditorClock.CurrentTime, () => Is.EqualTo(EditorClock.TrackLength)); - AddStep("seek smoothly before start time", () => Clock.SeekSmoothlyTo(-1000)); - AddUntilStep("time is clamped to 0", () => Clock.CurrentTime, () => Is.EqualTo(0)); + AddStep("seek smoothly before start time", () => EditorClock.SeekSmoothlyTo(-1000)); + AddUntilStep("time is clamped to 0", () => EditorClock.CurrentTime, () => Is.EqualTo(0)); - AddStep("seek smoothly beyond track length", () => Clock.SeekSmoothlyTo(Clock.TrackLength + 1000)); - AddUntilStep("time is clamped to track length", () => Clock.CurrentTime, () => Is.EqualTo(Clock.TrackLength)); + AddStep("seek smoothly beyond track length", () => EditorClock.SeekSmoothlyTo(EditorClock.TrackLength + 1000)); + AddUntilStep("time is clamped to track length", () => EditorClock.CurrentTime, () => Is.EqualTo(EditorClock.TrackLength)); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs index 2465512dae..aa4bccd728 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs @@ -28,6 +28,11 @@ namespace osu.Game.Tests.Visual.Editing { base.LoadComplete(); + Child = new TimingPointVisualiser(Beatmap.Value.Beatmap, 5000) { Clock = EditorClock }; + } + + protected override Beatmap CreateEditorClockBeatmap() + { var testBeatmap = new Beatmap { ControlPointInfo = new ControlPointInfo(), @@ -45,9 +50,7 @@ namespace osu.Game.Tests.Visual.Editing testBeatmap.ControlPointInfo.Add(450, new TimingControlPoint { BeatLength = 100 }); testBeatmap.ControlPointInfo.Add(500, new TimingControlPoint { BeatLength = 307.69230769230802 }); - Beatmap.Value = CreateWorkingBeatmap(testBeatmap); - - Child = new TimingPointVisualiser(testBeatmap, 5000) { Clock = Clock }; + return testBeatmap; } /// @@ -59,17 +62,17 @@ namespace osu.Game.Tests.Visual.Editing reset(); // Forwards - AddStep("Seek(0)", () => Clock.Seek(0)); + AddStep("Seek(0)", () => EditorClock.Seek(0)); checkTime(0); - AddStep("Seek(33)", () => Clock.Seek(33)); + AddStep("Seek(33)", () => EditorClock.Seek(33)); checkTime(33); - AddStep("Seek(89)", () => Clock.Seek(89)); + AddStep("Seek(89)", () => EditorClock.Seek(89)); checkTime(89); // Backwards - AddStep("Seek(25)", () => Clock.Seek(25)); + AddStep("Seek(25)", () => EditorClock.Seek(25)); checkTime(25); - AddStep("Seek(0)", () => Clock.Seek(0)); + AddStep("Seek(0)", () => EditorClock.Seek(0)); checkTime(0); } @@ -82,19 +85,19 @@ namespace osu.Game.Tests.Visual.Editing { reset(); - AddStep("Seek(0), Snap", () => Clock.SeekSnapped(0)); + AddStep("Seek(0), Snap", () => EditorClock.SeekSnapped(0)); checkTime(0); - AddStep("Seek(50), Snap", () => Clock.SeekSnapped(50)); + AddStep("Seek(50), Snap", () => EditorClock.SeekSnapped(50)); checkTime(50); - AddStep("Seek(100), Snap", () => Clock.SeekSnapped(100)); + AddStep("Seek(100), Snap", () => EditorClock.SeekSnapped(100)); checkTime(100); - AddStep("Seek(175), Snap", () => Clock.SeekSnapped(175)); + AddStep("Seek(175), Snap", () => EditorClock.SeekSnapped(175)); checkTime(175); - AddStep("Seek(350), Snap", () => Clock.SeekSnapped(350)); + AddStep("Seek(350), Snap", () => EditorClock.SeekSnapped(350)); checkTime(350); - AddStep("Seek(400), Snap", () => Clock.SeekSnapped(400)); + AddStep("Seek(400), Snap", () => EditorClock.SeekSnapped(400)); checkTime(400); - AddStep("Seek(450), Snap", () => Clock.SeekSnapped(450)); + AddStep("Seek(450), Snap", () => EditorClock.SeekSnapped(450)); checkTime(450); } @@ -107,17 +110,17 @@ namespace osu.Game.Tests.Visual.Editing { reset(); - AddStep("Seek(24), Snap", () => Clock.SeekSnapped(24)); + AddStep("Seek(24), Snap", () => EditorClock.SeekSnapped(24)); checkTime(0); - AddStep("Seek(26), Snap", () => Clock.SeekSnapped(26)); + AddStep("Seek(26), Snap", () => EditorClock.SeekSnapped(26)); checkTime(50); - AddStep("Seek(150), Snap", () => Clock.SeekSnapped(150)); + AddStep("Seek(150), Snap", () => EditorClock.SeekSnapped(150)); checkTime(100); - AddStep("Seek(170), Snap", () => Clock.SeekSnapped(170)); + AddStep("Seek(170), Snap", () => EditorClock.SeekSnapped(170)); checkTime(175); - AddStep("Seek(274), Snap", () => Clock.SeekSnapped(274)); + AddStep("Seek(274), Snap", () => EditorClock.SeekSnapped(274)); checkTime(175); - AddStep("Seek(276), Snap", () => Clock.SeekSnapped(276)); + AddStep("Seek(276), Snap", () => EditorClock.SeekSnapped(276)); checkTime(350); } @@ -129,15 +132,15 @@ namespace osu.Game.Tests.Visual.Editing { reset(); - AddStep("SeekForward", () => Clock.SeekForward()); + AddStep("SeekForward", () => EditorClock.SeekForward()); checkTime(50); - AddStep("SeekForward", () => Clock.SeekForward()); + AddStep("SeekForward", () => EditorClock.SeekForward()); checkTime(100); - AddStep("SeekForward", () => Clock.SeekForward()); + AddStep("SeekForward", () => EditorClock.SeekForward()); checkTime(200); - AddStep("SeekForward", () => Clock.SeekForward()); + AddStep("SeekForward", () => EditorClock.SeekForward()); checkTime(400); - AddStep("SeekForward", () => Clock.SeekForward()); + AddStep("SeekForward", () => EditorClock.SeekForward()); checkTime(450); } @@ -149,17 +152,17 @@ namespace osu.Game.Tests.Visual.Editing { reset(); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(50); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(100); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(175); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(350); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(400); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(450); } @@ -172,30 +175,30 @@ namespace osu.Game.Tests.Visual.Editing { reset(); - AddStep("Seek(49)", () => Clock.Seek(49)); + AddStep("Seek(49)", () => EditorClock.Seek(49)); checkTime(49); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(50); - AddStep("Seek(49.999)", () => Clock.Seek(49.999)); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("Seek(49.999)", () => EditorClock.Seek(49.999)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(100); - AddStep("Seek(99)", () => Clock.Seek(99)); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("Seek(99)", () => EditorClock.Seek(99)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(100); - AddStep("Seek(99.999)", () => Clock.Seek(99.999)); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("Seek(99.999)", () => EditorClock.Seek(99.999)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(150); - AddStep("Seek(174)", () => Clock.Seek(174)); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("Seek(174)", () => EditorClock.Seek(174)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(175); - AddStep("Seek(349)", () => Clock.Seek(349)); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("Seek(349)", () => EditorClock.Seek(349)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(350); - AddStep("Seek(399)", () => Clock.Seek(399)); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("Seek(399)", () => EditorClock.Seek(399)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(400); - AddStep("Seek(449)", () => Clock.Seek(449)); - AddStep("SeekForward, Snap", () => Clock.SeekForward(true)); + AddStep("Seek(449)", () => EditorClock.Seek(449)); + AddStep("SeekForward, Snap", () => EditorClock.SeekForward(true)); checkTime(450); } @@ -207,17 +210,17 @@ namespace osu.Game.Tests.Visual.Editing { reset(); - AddStep("Seek(450)", () => Clock.Seek(450)); + AddStep("Seek(450)", () => EditorClock.Seek(450)); checkTime(450); - AddStep("SeekBackward", () => Clock.SeekBackward()); + AddStep("SeekBackward", () => EditorClock.SeekBackward()); checkTime(400); - AddStep("SeekBackward", () => Clock.SeekBackward()); + AddStep("SeekBackward", () => EditorClock.SeekBackward()); checkTime(350); - AddStep("SeekBackward", () => Clock.SeekBackward()); + AddStep("SeekBackward", () => EditorClock.SeekBackward()); checkTime(150); - AddStep("SeekBackward", () => Clock.SeekBackward()); + AddStep("SeekBackward", () => EditorClock.SeekBackward()); checkTime(50); - AddStep("SeekBackward", () => Clock.SeekBackward()); + AddStep("SeekBackward", () => EditorClock.SeekBackward()); checkTime(0); } @@ -229,19 +232,19 @@ namespace osu.Game.Tests.Visual.Editing { reset(); - AddStep("Seek(450)", () => Clock.Seek(450)); + AddStep("Seek(450)", () => EditorClock.Seek(450)); checkTime(450); - AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); + AddStep("SeekBackward, Snap", () => EditorClock.SeekBackward(true)); checkTime(400); - AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); + AddStep("SeekBackward, Snap", () => EditorClock.SeekBackward(true)); checkTime(350); - AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); + AddStep("SeekBackward, Snap", () => EditorClock.SeekBackward(true)); checkTime(175); - AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); + AddStep("SeekBackward, Snap", () => EditorClock.SeekBackward(true)); checkTime(100); - AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); + AddStep("SeekBackward, Snap", () => EditorClock.SeekBackward(true)); checkTime(50); - AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); + AddStep("SeekBackward, Snap", () => EditorClock.SeekBackward(true)); checkTime(0); } @@ -254,18 +257,18 @@ namespace osu.Game.Tests.Visual.Editing { reset(); - AddStep("Seek(451)", () => Clock.Seek(451)); + AddStep("Seek(451)", () => EditorClock.Seek(451)); checkTime(451); - AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); + AddStep("SeekBackward, Snap", () => EditorClock.SeekBackward(true)); checkTime(450); - AddStep("Seek(450.999)", () => Clock.Seek(450.999)); - AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); + AddStep("Seek(450.999)", () => EditorClock.Seek(450.999)); + AddStep("SeekBackward, Snap", () => EditorClock.SeekBackward(true)); checkTime(450); - AddStep("Seek(401)", () => Clock.Seek(401)); - AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); + AddStep("Seek(401)", () => EditorClock.Seek(401)); + AddStep("SeekBackward, Snap", () => EditorClock.SeekBackward(true)); checkTime(400); - AddStep("Seek(401.999)", () => Clock.Seek(401.999)); - AddStep("SeekBackward, Snap", () => Clock.SeekBackward(true)); + AddStep("Seek(401.999)", () => EditorClock.Seek(401.999)); + AddStep("SeekBackward, Snap", () => EditorClock.SeekBackward(true)); checkTime(400); } @@ -279,37 +282,37 @@ namespace osu.Game.Tests.Visual.Editing double lastTime = 0; - AddStep("Seek(0)", () => Clock.Seek(0)); + AddStep("Seek(0)", () => EditorClock.Seek(0)); checkTime(0); for (int i = 0; i < 9; i++) { AddStep("SeekForward, Snap", () => { - lastTime = Clock.CurrentTime; - Clock.SeekForward(true); + lastTime = EditorClock.CurrentTime; + EditorClock.SeekForward(true); }); - AddAssert("Time > lastTime", () => Clock.CurrentTime > lastTime); + AddAssert("Time > lastTime", () => EditorClock.CurrentTime > lastTime); } for (int i = 0; i < 9; i++) { AddStep("SeekBackward, Snap", () => { - lastTime = Clock.CurrentTime; - Clock.SeekBackward(true); + lastTime = EditorClock.CurrentTime; + EditorClock.SeekBackward(true); }); - AddAssert("Time < lastTime", () => Clock.CurrentTime < lastTime); + AddAssert("Time < lastTime", () => EditorClock.CurrentTime < lastTime); } checkTime(0); } - private void checkTime(double expectedTime) => AddAssert($"Current time is {expectedTime}", () => Clock.CurrentTime, () => Is.EqualTo(expectedTime)); + private void checkTime(double expectedTime) => AddUntilStep($"Current time is {expectedTime}", () => EditorClock.CurrentTime, () => Is.EqualTo(expectedTime)); private void reset() { - AddStep("Reset", () => Clock.Seek(0)); + AddStep("Reset", () => EditorClock.Seek(0)); } private class TimingPointVisualiser : CompositeDrawable diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs index 7d881bc259..10e1206b53 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs @@ -113,7 +113,7 @@ namespace osu.Game.Tests.Visual.Editing .TriggerClick(); }); - AddUntilStep("wait for track playing", () => Clock.IsRunning); + AddUntilStep("wait for track playing", () => EditorClock.IsRunning); AddStep("click reset button", () => { @@ -122,7 +122,7 @@ namespace osu.Game.Tests.Visual.Editing .TriggerClick(); }); - AddUntilStep("wait for track stopped", () => !Clock.IsRunning); + AddUntilStep("wait for track stopped", () => !EditorClock.IsRunning); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineBlueprintContainer.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineBlueprintContainer.cs index d2984728b0..c098b683a6 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineBlueprintContainer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineBlueprintContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tests.Visual.Editing protected override void LoadComplete() { base.LoadComplete(); - Clock.Seek(10000); + EditorClock.Seek(10000); } } } diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs index e262bd756a..03c184c27d 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Editing [SetUpSteps] public void SetUpSteps() { - AddStep("Stop clock", () => Clock.Stop()); + AddStep("Stop clock", () => EditorClock.Stop()); AddUntilStep("wait for rows to load", () => Child.ChildrenOfType().Any()); } @@ -68,10 +68,10 @@ namespace osu.Game.Tests.Visual.Editing }); AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 54670); - AddUntilStep("Ensure seeked to correct time", () => Clock.CurrentTimeAccurate == 54670); + AddUntilStep("Ensure seeked to correct time", () => EditorClock.CurrentTimeAccurate == 54670); - AddStep("Seek to just before next point", () => Clock.Seek(69000)); - AddStep("Start clock", () => Clock.Start()); + AddStep("Seek to just before next point", () => EditorClock.Seek(69000)); + AddStep("Start clock", () => EditorClock.Start()); AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 69670); } @@ -86,9 +86,9 @@ namespace osu.Game.Tests.Visual.Editing }); AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 54670); - AddUntilStep("Ensure seeked to correct time", () => Clock.CurrentTimeAccurate == 54670); + AddUntilStep("Ensure seeked to correct time", () => EditorClock.CurrentTimeAccurate == 54670); - AddStep("Seek to later", () => Clock.Seek(80000)); + AddStep("Seek to later", () => EditorClock.Seek(80000)); AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 69670); } diff --git a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs index 437f06c47f..d830f8d488 100644 --- a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs +++ b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs @@ -72,7 +72,7 @@ namespace osu.Game.Tests.Visual.Editing { base.LoadComplete(); - Clock.Seek(2500); + EditorClock.Seek(2500); } public abstract Drawable CreateTestComponent(); diff --git a/osu.Game/Tests/Visual/EditorClockTestScene.cs b/osu.Game/Tests/Visual/EditorClockTestScene.cs index 91284ae499..8f1e7abd9e 100644 --- a/osu.Game/Tests/Visual/EditorClockTestScene.cs +++ b/osu.Game/Tests/Visual/EditorClockTestScene.cs @@ -6,6 +6,8 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Overlays; @@ -24,30 +26,39 @@ namespace osu.Game.Tests.Visual protected readonly BindableBeatDivisor BeatDivisor = new BindableBeatDivisor(); - [Cached] - protected new readonly EditorClock Clock; + protected EditorClock EditorClock; private readonly Bindable frequencyAdjustment = new BindableDouble(1); + private IBeatmap editorClockBeatmap; protected virtual bool ScrollUsingMouseWheel => true; - protected EditorClockTestScene() - { - Clock = new EditorClock(new Beatmap(), BeatDivisor) { IsCoupled = false }; - } + protected override Container Content => content; + + private readonly Container content = new Container { RelativeSizeAxes = Axes.Both }; protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + editorClockBeatmap = CreateEditorClockBeatmap(); + + base.Content.AddRange(new Drawable[] + { + EditorClock = new EditorClock(editorClockBeatmap, BeatDivisor), + content + }); + dependencies.Cache(BeatDivisor); - dependencies.CacheAs(Clock); + dependencies.CacheAs(EditorClock); return dependencies; } protected override void LoadComplete() { + Beatmap.Value = CreateWorkingBeatmap(editorClockBeatmap); + base.LoadComplete(); Beatmap.BindValueChanged(beatmapChanged, true); @@ -55,22 +66,13 @@ namespace osu.Game.Tests.Visual AddSliderStep("editor clock rate", 0.0, 2.0, 1.0, v => frequencyAdjustment.Value = v); } + protected virtual IBeatmap CreateEditorClockBeatmap() => new Beatmap(); + private void beatmapChanged(ValueChangedEvent e) { e.OldValue?.Track.RemoveAdjustment(AdjustableProperty.Frequency, frequencyAdjustment); - - Clock.Beatmap = e.NewValue.Beatmap; - Clock.ChangeSource(e.NewValue.Track); - Clock.ProcessFrame(); - e.NewValue.Track.AddAdjustment(AdjustableProperty.Frequency, frequencyAdjustment); - } - - protected override void Update() - { - base.Update(); - - Clock.ProcessFrame(); + EditorClock.ChangeSource(e.NewValue.Track); } protected override bool OnScroll(ScrollEvent e) @@ -79,9 +81,9 @@ namespace osu.Game.Tests.Visual return false; if (e.ScrollDelta.Y > 0) - Clock.SeekBackward(true); + EditorClock.SeekBackward(true); else - Clock.SeekForward(true); + EditorClock.SeekForward(true); return true; } diff --git a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs index 797e8363c3..176b181e73 100644 --- a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs @@ -30,10 +30,15 @@ namespace osu.Game.Tests.Visual { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.CacheAs(new EditorClock()); - var playable = GetPlayableBeatmap(); - dependencies.CacheAs(new EditorBeatmap(playable)); + + var editorClock = new EditorClock(); + base.Content.Add(editorClock); + dependencies.CacheAs(editorClock); + + var editorBeatmap = new EditorBeatmap(playable); + // Not adding to hierarchy as we don't satisfy its dependencies. Probably not good. + dependencies.CacheAs(editorBeatmap); return dependencies; } diff --git a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs index 66d79cad1c..ac0d1cd366 100644 --- a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -19,19 +16,23 @@ namespace osu.Game.Tests.Visual [Cached] private readonly EditorClock editorClock = new EditorClock(); - protected override Container Content => content ?? base.Content; + protected override Container Content => content; private readonly Container content; protected SelectionBlueprintTestScene() { - base.Content.Add(content = new Container + base.Content.AddRange(new Drawable[] { - Clock = new FramedClock(new StopwatchClock()), - RelativeSizeAxes = Axes.Both + editorClock, + content = new Container + { + Clock = new FramedClock(new StopwatchClock()), + RelativeSizeAxes = Axes.Both + } }); } - protected void AddBlueprint(HitObjectSelectionBlueprint blueprint, [CanBeNull] DrawableHitObject drawableObject = null) + protected void AddBlueprint(HitObjectSelectionBlueprint blueprint, DrawableHitObject? drawableObject = null) { Add(blueprint.With(d => { From cd90536e4bbb881b1787390d4469a57a5e6299d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 18:25:48 +0900 Subject: [PATCH 0727/2686] Remove `Track` access in `Timeline` --- .../Compose/Components/Timeline/Timeline.cs | 48 ++++++++----------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 54f2d13707..9e96a7386d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -5,7 +5,6 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -64,8 +63,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline /// private bool trackWasPlaying; - private Track track; - /// /// The timeline zoom level at a 1x zoom scale. /// @@ -93,6 +90,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private Bindable waveformOpacity; + private double trackLengthForZoom; + [BackgroundDependencyLoader] private void load(IBindable beatmap, OsuColour colours, OsuConfigManager config) { @@ -144,9 +143,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline Beatmap.BindValueChanged(b => { waveform.Waveform = b.NewValue.Waveform; - track = b.NewValue.Track; - - setupTimelineZoom(); }, true); Zoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom); @@ -185,8 +181,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private void updateWaveformOpacity() => waveform.FadeTo(WaveformVisible.Value ? waveformOpacity.Value : 0, 200, Easing.OutQuint); - private float getZoomLevelForVisibleMilliseconds(double milliseconds) => Math.Max(1, (float)(track.Length / milliseconds)); - protected override void Update() { base.Update(); @@ -197,20 +191,21 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline // This needs to happen after transforms are updated, but before the scroll position is updated in base.UpdateAfterChildren if (editorClock.IsRunning) scrollToTrackTime(); - } - private void setupTimelineZoom() - { - if (!track.IsLoaded) + if (editorClock.TrackLength != trackLengthForZoom) { - Scheduler.AddOnce(setupTimelineZoom); - return; + defaultTimelineZoom = getZoomLevelForVisibleMilliseconds(6000); + + float initialZoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom); + float minimumZoom = getZoomLevelForVisibleMilliseconds(10000); + float maximumZoom = getZoomLevelForVisibleMilliseconds(500); + + SetupZoom(initialZoom, minimumZoom, maximumZoom); + + float getZoomLevelForVisibleMilliseconds(double milliseconds) => Math.Max(1, (float)(editorClock.TrackLength / milliseconds)); + + trackLengthForZoom = editorClock.TrackLength; } - - defaultTimelineZoom = getZoomLevelForVisibleMilliseconds(6000); - - float initialZoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom); - SetupZoom(initialZoom, getZoomLevelForVisibleMilliseconds(10000), getZoomLevelForVisibleMilliseconds(500)); } protected override bool OnScroll(ScrollEvent e) @@ -255,16 +250,13 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private void seekTrackToCurrent() { - if (!track.IsLoaded) - return; - - double target = Current / Content.DrawWidth * track.Length; - editorClock.Seek(Math.Min(track.Length, target)); + double target = Current / Content.DrawWidth * editorClock.TrackLength; + editorClock.Seek(Math.Min(editorClock.TrackLength, target)); } private void scrollToTrackTime() { - if (!track.IsLoaded || track.Length == 0) + if (editorClock.TrackLength == 0) return; // covers the case where the user starts playback after a drag is in progress. @@ -272,7 +264,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline if (handlingDragInput) editorClock.Stop(); - ScrollTo((float)(editorClock.CurrentTime / track.Length) * Content.DrawWidth, false); + ScrollTo((float)(editorClock.CurrentTime / editorClock.TrackLength) * Content.DrawWidth, false); } protected override bool OnMouseDown(MouseDownEvent e) @@ -310,12 +302,12 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline /// /// The total amount of time visible on the timeline. /// - public double VisibleRange => track.Length / Zoom; + public double VisibleRange => editorClock.TrackLength / Zoom; public SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition, SnapType snapType = SnapType.All) => new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(screenSpacePosition)))); private double getTimeFromPosition(Vector2 localPosition) => - (localPosition.X / Content.DrawWidth) * track.Length; + (localPosition.X / Content.DrawWidth) * editorClock.TrackLength; } } From 9c9238d6e8686017d522752c3044156906393674 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 18:38:52 +0900 Subject: [PATCH 0728/2686] Fix `TimelineTestScene`'s beatmap getting overwritten by `EditorClockTestScene` --- .../Visual/Editing/TestSceneTimelineZoom.cs | 4 ---- .../Visual/Editing/TimelineTestScene.cs | 20 ++++++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs index 630d048867..11ac102814 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs @@ -17,8 +17,6 @@ namespace osu.Game.Tests.Visual.Editing { double initialVisibleRange = 0; - AddUntilStep("wait for load", () => MusicController.TrackLoaded); - AddStep("reset zoom", () => TimelineArea.Timeline.Zoom = 100); AddStep("get initial range", () => initialVisibleRange = TimelineArea.Timeline.VisibleRange); @@ -36,8 +34,6 @@ namespace osu.Game.Tests.Visual.Editing { double initialVisibleRange = 0; - AddUntilStep("wait for load", () => MusicController.TrackLoaded); - AddStep("reset timeline size", () => TimelineArea.Timeline.Width = 1); AddStep("get initial range", () => initialVisibleRange = TimelineArea.Timeline.VisibleRange); diff --git a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs index d830f8d488..19e297a08d 100644 --- a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs +++ b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs @@ -9,12 +9,14 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components.Timeline; +using osu.Game.Storyboards; using osuTK; using osuTK.Graphics; @@ -28,10 +30,14 @@ namespace osu.Game.Tests.Visual.Editing protected EditorBeatmap EditorBeatmap { get; private set; } - [BackgroundDependencyLoader] - private void load(AudioManager audio) + [Resolved] + private AudioManager audio { get; set; } + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) => new WaveformTestBeatmap(audio); + + protected override void LoadComplete() { - Beatmap.Value = new WaveformTestBeatmap(audio); + base.LoadComplete(); var playable = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset); EditorBeatmap = new EditorBeatmap(playable); @@ -68,11 +74,11 @@ namespace osu.Game.Tests.Visual.Editing }); } - protected override void LoadComplete() + [SetUpSteps] + public void SetUpSteps() { - base.LoadComplete(); - - EditorClock.Seek(2500); + AddUntilStep("wait for track loaded", () => MusicController.TrackLoaded); + AddStep("seek forward", () => EditorClock.Seek(2500)); } public abstract Drawable CreateTestComponent(); From f54047d17b0ae8d50546909e386aeec2d1c0ea1b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 18:55:20 +0900 Subject: [PATCH 0729/2686] Move selection clearing to top --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 14ed305b25..a955a1cce3 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -260,6 +260,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders if (toSplit.Count == 0) return; + editorBeatmap.SelectedHitObjects.Clear(); + foreach (var c in toSplit) { if (c == controlPoints[0] || c == controlPoints[^1] || c.Type is null) @@ -318,8 +320,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders foreach (var c in controlPoints) c.Position -= first; HitObject.Position += first; - - editorBeatmap.SelectedHitObjects.Clear(); } private void convertToStream() From 47cb163015e9ef4b46e05dbcfc49ec5bbd7bb53e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 19:09:03 +0900 Subject: [PATCH 0730/2686] Refactor splitting logic and comments slightly --- .../Components/PathControlPointVisualiser.cs | 6 ++--- .../Sliders/SliderSelectionBlueprint.cs | 25 ++++++++----------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 48e1d6405d..22cbab8938 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -107,14 +107,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private bool splitSelected() { - List toSplit = Pieces.Where(p => p.IsSelected.Value && isSplittable(p)).Select(p => p.ControlPoint).ToList(); + List controlPointsToSplitAt = Pieces.Where(p => p.IsSelected.Value && isSplittable(p)).Select(p => p.ControlPoint).ToList(); // Ensure that there are any points to be split - if (toSplit.Count == 0) + if (controlPointsToSplitAt.Count == 0) return false; changeHandler?.BeginChange(); - SplitControlPointsRequested?.Invoke(toSplit); + SplitControlPointsRequested?.Invoke(controlPointsToSplitAt); changeHandler?.EndChange(); // Since pieces are re-used, they will not point to the deleted control points while remaining selected diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index a955a1cce3..eb69efd636 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -251,34 +251,31 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders HitObject.Position += first; } - private void splitControlPoints(List toSplit) + private void splitControlPoints(List controlPointsToSplitAt) { // Arbitrary gap in milliseconds to put between split slider pieces const double split_gap = 100; // Ensure that there are any points to be split - if (toSplit.Count == 0) + if (controlPointsToSplitAt.Count == 0) return; editorBeatmap.SelectedHitObjects.Clear(); - foreach (var c in toSplit) + foreach (var splitPoint in controlPointsToSplitAt) { - if (c == controlPoints[0] || c == controlPoints[^1] || c.Type is null) + if (splitPoint == controlPoints[0] || splitPoint == controlPoints[^1] || splitPoint.Type is null) continue; // Split off the section of slider before this control point so the remaining control points to split are in the latter part of the slider. - var splitControlPoints = controlPoints.TakeWhile(current => current != c).ToList(); + int index = controlPoints.IndexOf(splitPoint); - if (splitControlPoints.Count == 0) + if (index <= 0) continue; - foreach (var current in splitControlPoints) - { - controlPoints.Remove(current); - } - - splitControlPoints.Add(c); + // Extract the split portion and remove from the original slider. + var splitControlPoints = controlPoints.Take(index + 1).ToList(); + controlPoints.RemoveRange(0, index); // Turn the control points which were split off into a new slider. var samplePoint = (SampleControlPoint)HitObject.SampleControlPoint.DeepClone(); @@ -314,8 +311,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders } } - // The path will have a non-zero offset if the head is removed, but sliders don't support this behaviour since the head is positioned at the slider's position - // So the slider needs to be offset by this amount instead, and all control points offset backwards such that the path is re-positioned at (0, 0) + // Once all required pieces have been split off, the original slider has the final split. + // As a final step, we must reset its control points to have an origin of (0,0). Vector2 first = controlPoints[0].Position; foreach (var c in controlPoints) c.Position -= first; From cb1c4a1bb106102e0756167ec877fb00d81cc04a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 19:16:12 +0900 Subject: [PATCH 0731/2686] Move sample checks to be inline in other existing tests --- .../Editor/TestSceneObjectMerging.cs | 53 +++---------------- 1 file changed, 7 insertions(+), 46 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs index 75a2361732..cdb2a7fe77 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs @@ -9,7 +9,6 @@ using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osuTK; using osuTK.Input; -using System.Collections.Generic; namespace osu.Game.Rulesets.Osu.Tests.Editor { @@ -78,6 +77,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor return sliderCreatedFor(args); }); + AddAssert("samples exist", sliderSampleExist); + AddStep("undo", () => Editor.Undo()); AddAssert("merged objects restored", () => circle1 is not null && circle2 is not null && slider is not null && objectsRestored(circle1, slider, circle2)); } @@ -123,6 +124,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor return sliderCreatedFor(args); }); + AddAssert("samples exist", sliderSampleExist); + AddAssert("merged slider matches first slider", () => { var mergedSlider = (Slider)EditorBeatmap.SelectedHitObjects.First(); @@ -166,50 +169,11 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor (pos: circle1.Position, pathType: PathType.Linear), (pos: circle2.Position, pathType: null))); + AddAssert("samples exist", sliderSampleExist); + AddAssert("spinner not merged", () => EditorBeatmap.HitObjects.Contains(spinner)); } - [Test] - public void TestSimpleMergeSample() - { - HitCircle? circle1 = null; - HitCircle? circle2 = null; - - - AddStep("select first two circles", () => - { - circle1 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle); - circle2 = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle && h != circle1); - EditorClock.Seek(circle1.StartTime); - EditorBeatmap.SelectedHitObjects.Add(circle1); - EditorBeatmap.SelectedHitObjects.Add(circle2); - }); - - mergeSelection(); - - AddAssert("samples exist", () => sliderSampleExist()); - } - - [Test] - public void TestSliderCircleMergeSample() - { - Slider? slider = null; - HitCircle? circle = null; - - AddStep("select a slider followed by a circle", () => - { - slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider); - circle = (HitCircle)EditorBeatmap.HitObjects.First(h => h is HitCircle && h.StartTime > slider.StartTime); - EditorClock.Seek(slider.StartTime); - EditorBeatmap.SelectedHitObjects.Add(slider); - EditorBeatmap.SelectedHitObjects.Add(circle); - }); - - mergeSelection(); - - AddAssert("samples exist", () => sliderSampleExist()); - } - private void mergeSelection() { AddStep("merge selection", () => @@ -259,10 +223,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor var mergedSlider = (Slider)EditorBeatmap.SelectedHitObjects.First(); - if (mergedSlider.Samples[0] is null) - return false; - - return true; + return mergedSlider.Samples[0] is not null; } } } From d6359b00ad5022062f9469cb2103d4229ce38d88 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 19:20:36 +0900 Subject: [PATCH 0732/2686] Fix filename mismatch --- .../UprightAspectMaintainingContainer.cs | 122 ++++++++++++++++++ .../Containers/UprightUnscaledContainer.cs | 117 ----------------- 2 files changed, 122 insertions(+), 117 deletions(-) create mode 100644 osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs diff --git a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs new file mode 100644 index 0000000000..e556117bc0 --- /dev/null +++ b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs @@ -0,0 +1,122 @@ +// 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; +using osu.Framework.Graphics.Containers; +using osu.Framework.Layout; +using osuTK; + +namespace osu.Game.Graphics.Containers +{ + /// + /// A container that reverts any rotation (and optionally scale) applied by its direct parent. + /// + public class UprightAspectMaintainingContainer : Container + { + protected override Container Content { get; } + + /// + /// Controls how much this container scales compared to its parent (default is 1.0f). + /// + public float ScalingFactor { get; set; } = 1; + + /// + /// Controls the scaling of this container. + /// + public ScaleMode Scaling { get; set; } = ScaleMode.Vertical; + + private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawInfo, InvalidationSource.Parent); + + public UprightAspectMaintainingContainer() + { + AddInternal(Content = new GrowToFitContainer()); + AddLayout(layout); + } + + protected override void Update() + { + base.Update(); + + if (!layout.IsValid) + { + keepUprightAndUnstretched(); + layout.Validate(); + } + } + + /// + /// Keeps the drawable upright and unstretched preventing it from being rotated, sheared, scaled or flipped with its Parent. + /// + private void keepUprightAndUnstretched() + { + // Decomposes the inverse of the parent DrawInfo.Matrix into rotation, shear and scale. + var parentMatrix = Parent.DrawInfo.Matrix; + + // Remove Translation. + parentMatrix.M31 = 0.0f; + parentMatrix.M32 = 0.0f; + + Matrix3 reversedParrent = parentMatrix.Inverted(); + + // Extract the rotation. + float angle = MathF.Atan2(reversedParrent.M12, reversedParrent.M11); + Rotation = MathHelper.RadiansToDegrees(angle); + + // Remove rotation from the C matrix so that it only contains shear and scale. + Matrix3 m = Matrix3.CreateRotationZ(-angle); + reversedParrent *= m; + + // Extract shear. + float alpha = reversedParrent.M21 / reversedParrent.M22; + Shear = new Vector2(-alpha, 0); + + // Etract scale. + float sx = reversedParrent.M11; + float sy = reversedParrent.M22; + + Vector3 parentScale = parentMatrix.ExtractScale(); + + float usedScale = 1.0f; + + switch (Scaling) + { + case ScaleMode.Horizontal: + usedScale = parentScale.X; + break; + + case ScaleMode.Vertical: + usedScale = parentScale.Y; + break; + } + + usedScale = 1.0f + (usedScale - 1.0f) * ScalingFactor; + + Scale = new Vector2(sx * usedScale, sy * usedScale); + } + + /// + /// A container that grows in size to fit its children and retains its size when its children shrink + /// + private class GrowToFitContainer : Container + { + protected override Container Content => content; + private readonly Container content; + + public GrowToFitContainer() + { + InternalChild = content = new Container + { + AutoSizeAxes = Axes.Both, + }; + } + + protected override void Update() + { + base.Update(); + Height = Math.Max(content.Height, Height); + Width = Math.Max(content.Width, Width); + } + } + } +} diff --git a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs index d2cd7d3373..d801f4a215 100644 --- a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs +++ b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs @@ -1,125 +1,8 @@ // 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.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Layout; -using osuTK; -using System; - namespace osu.Game.Graphics.Containers { - /// - /// A container that reverts any rotation (and optionally scale) applied by its direct parent. - /// - public class UprightAspectMaintainingContainer : Container - { - protected override Container Content { get; } - - /// - /// Controls how much this container scales compared to its parent (default is 1.0f). - /// - public float ScalingFactor { get; set; } = 1; - - /// - /// Controls the scaling of this container. - /// - public ScaleMode Scaling { get; set; } = ScaleMode.Vertical; - - private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawInfo, InvalidationSource.Parent); - - public UprightAspectMaintainingContainer() - { - AddInternal(Content = new GrowToFitContainer()); - AddLayout(layout); - } - - protected override void Update() - { - base.Update(); - - if (!layout.IsValid) - { - keepUprightAndUnstretched(); - layout.Validate(); - } - } - - /// - /// Keeps the drawable upright and unstretched preventing it from being rotated, sheared, scaled or flipped with its Parent. - /// - private void keepUprightAndUnstretched() - { - // Decomposes the inverse of the parent DrawInfo.Matrix into rotation, shear and scale. - var parentMatrix = Parent.DrawInfo.Matrix; - - // Remove Translation. - parentMatrix.M31 = 0.0f; - parentMatrix.M32 = 0.0f; - - Matrix3 reversedParrent = parentMatrix.Inverted(); - - // Extract the rotation. - float angle = MathF.Atan2(reversedParrent.M12, reversedParrent.M11); - Rotation = MathHelper.RadiansToDegrees(angle); - - // Remove rotation from the C matrix so that it only contains shear and scale. - Matrix3 m = Matrix3.CreateRotationZ(-angle); - reversedParrent *= m; - - // Extract shear. - float alpha = reversedParrent.M21 / reversedParrent.M22; - Shear = new Vector2(-alpha, 0); - - // Etract scale. - float sx = reversedParrent.M11; - float sy = reversedParrent.M22; - - Vector3 parentScale = parentMatrix.ExtractScale(); - - float usedScale = 1.0f; - - switch (Scaling) - { - case ScaleMode.Horizontal: - usedScale = parentScale.X; - break; - - case ScaleMode.Vertical: - usedScale = parentScale.Y; - break; - } - - usedScale = 1.0f + (usedScale - 1.0f) * ScalingFactor; - - Scale = new Vector2(sx * usedScale, sy * usedScale); - } - - /// - /// A container that grows in size to fit its children and retains its size when its children shrink - /// - private class GrowToFitContainer : Container - { - protected override Container Content => content; - private readonly Container content; - - public GrowToFitContainer() - { - InternalChild = content = new Container - { - AutoSizeAxes = Axes.Both, - }; - } - - protected override void Update() - { - base.Update(); - Height = Math.Max(content.Height, Height); - Width = Math.Max(content.Width, Width); - } - } - } - public enum ScaleMode { /// From 08cb70b0931eac8edcfc3939c0341166dff54ea1 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Fri, 26 Aug 2022 20:27:31 +1000 Subject: [PATCH 0733/2686] Lessen repeated angle nerf for objects further back in time --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 86b6170d13..a6e76db902 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators OsuDifficultyHitObject lastObj = osuCurrent; - int angleRepeatCount = 0; + double angleRepeatCount = 0.0; // We want to round angles to make abusing the nerf a bit harder. double initialRoundedAngle = 0.0; @@ -82,8 +82,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { double roundedAngle = Math.Round(MathUtils.RadiansToDegrees(currentObj.Angle.Value) / 2.0) * 2.0; + // Objects further back in time should count less for the nerf. if (roundedAngle == initialRoundedAngle) - angleRepeatCount++; + angleRepeatCount += 1.0 - 0.1 * i; } } From 5082ee26cfeb62b7ce8560f9253e92f8434f606b Mon Sep 17 00:00:00 2001 From: MBmasher Date: Fri, 26 Aug 2022 20:30:14 +1000 Subject: [PATCH 0734/2686] Ensure a negative value cannot be added to angleRepeatCount --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index a6e76db902..2733217b64 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // Objects further back in time should count less for the nerf. if (roundedAngle == initialRoundedAngle) - angleRepeatCount += 1.0 - 0.1 * i; + angleRepeatCount += Math.Max(1.0 - 0.1 * i, 0.0); } } From 217fa00a72af23ae2971dba4d10beb9a5a185930 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 19:32:49 +0900 Subject: [PATCH 0735/2686] Bring logic up-to-date --- .../SongSelect/TestSceneBeatmapCarousel.cs | 22 +++---------------- .../Carousel/CarouselGroupEagerSelect.cs | 14 ++++++------ 2 files changed, 10 insertions(+), 26 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 8f7d630a19..7623704a4b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -834,16 +834,7 @@ namespace osu.Game.Tests.Visual.SongSelect for (int i = 0; i < makeThisManyGroups; i++) { for (int j = 0; j < haveThisManySetsInGroup; j++) - { - var testBeatmap = createTestBeatmapSet(i * haveThisManySetsInGroup + j + 1); - var rulesetID = i % 3; - testBeatmap.Beatmaps.ForEach(b => - { - b.Ruleset = rulesets.AvailableRulesets.ElementAt(rulesetID); - b.RulesetID = rulesetID; - }); - sets.Add(testBeatmap); - } + sets.Add(TestResources.CreateTestBeatmapSetInfo(i * haveThisManySetsInGroup + j + 1)); } loadBeatmaps(sets); @@ -852,7 +843,7 @@ namespace osu.Game.Tests.Visual.SongSelect for (int i = 1; i < makeThisManyGroups; i++) { - var rulesetID = i % 3; + int rulesetID = i % 3; AddStep($"Toggle filter to ruleset {rulesetID}", () => { carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(rulesetID) }, false); @@ -869,14 +860,7 @@ namespace osu.Game.Tests.Visual.SongSelect for (int i = 1; i <= 40; i++) { - var testBeatmap = createTestBeatmapSet(i); - var rulesetID = (i - 1) / 10; - testBeatmap.Beatmaps.ForEach(b => - { - b.Ruleset = rulesets.AvailableRulesets.ElementAt(rulesetID); - b.RulesetID = rulesetID; - }); - sets.Add(testBeatmap); + sets.Add(TestResources.CreateTestBeatmapSetInfo(i)); } loadBeatmaps(sets); diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs index 432f795f4c..2c1ccebfab 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs @@ -120,16 +120,16 @@ namespace osu.Game.Screens.Select.Carousel while (true) { // check if a direction has been exhausted and an item (or null) from the other direction should be returned - if (forwardsIndex >= Children.Count) - return Children.Reverse().Skip(Children.Count - backwardsIndex - 1).FirstOrDefault(item => !item.Filtered.Value); + if (forwardsIndex >= Items.Count) + return Items.Reverse().Skip(Items.Count - backwardsIndex - 1).FirstOrDefault(item => !item.Filtered.Value); if (backwardsIndex < 0) - return Children.Skip(forwardsIndex).FirstOrDefault(item => !item.Filtered.Value); + return Items.Skip(forwardsIndex).FirstOrDefault(item => !item.Filtered.Value); // check if an unfiltered item has been reached - if (!Children[forwardsIndex].Filtered.Value) - return Children[forwardsIndex]; - if (!Children[backwardsIndex].Filtered.Value) - return Children[backwardsIndex]; + if (!Items[forwardsIndex].Filtered.Value) + return Items[forwardsIndex]; + if (!Items[backwardsIndex].Filtered.Value) + return Items[backwardsIndex]; // increment the indices forwardsIndex++; From 249c3f868f6c426985a3631d2ad4f3773bbffb7d Mon Sep 17 00:00:00 2001 From: MBmasher Date: Fri, 26 Aug 2022 20:40:18 +1000 Subject: [PATCH 0736/2686] Compare raw angle values instead of rounding angles --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 2733217b64..9630da5a01 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -49,11 +49,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double angleRepeatCount = 0.0; - // We want to round angles to make abusing the nerf a bit harder. - double initialRoundedAngle = 0.0; - if (osuCurrent.Angle != null) - initialRoundedAngle = Math.Round(MathUtils.RadiansToDegrees(osuCurrent.Angle.Value) / 2.0) * 2.0; - // This is iterating backwards in time from the current object. for (int i = 0; i < Math.Min(current.Index, 10); i++) { @@ -80,10 +75,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (currentObj.Angle != null && osuCurrent.Angle != null) { - double roundedAngle = Math.Round(MathUtils.RadiansToDegrees(currentObj.Angle.Value) / 2.0) * 2.0; - // Objects further back in time should count less for the nerf. - if (roundedAngle == initialRoundedAngle) + if (Math.Abs(currentObj.Angle.Value - osuCurrent.Angle.Value) < 0.02) angleRepeatCount += Math.Max(1.0 - 0.1 * i, 0.0); } } From 454d868dd598148f7ea141f83de2e9dbdb73a97c Mon Sep 17 00:00:00 2001 From: MBmasher Date: Fri, 26 Aug 2022 20:42:02 +1000 Subject: [PATCH 0737/2686] Remove unnecessary using call --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 9630da5a01..2ba856d014 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -7,7 +7,6 @@ using System; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Objects; -using osu.Framework.Utils; namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { From 5ef8e26ebe894322c8aaba026051c3bba5ab15f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 19:59:25 +0900 Subject: [PATCH 0738/2686] Fix check not accounting for mods not existing in certain rulesets Also check all instances, rather than first. --- .../Visual/Gameplay/TestSceneModValidity.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs index aa8dfaaa7e..0c6b656ab6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -30,17 +29,19 @@ namespace osu.Game.Tests.Visual.Gameplay IEnumerable modInstances = mods.Select(mod => mod.CreateInstance()); - foreach (var mod in modInstances) + foreach (var modToCheck in modInstances) { - var modIncompatibilities = mod.IncompatibleMods; + var incompatibleMods = modToCheck.IncompatibleMods; - foreach (var incompatibleModType in modIncompatibilities) + foreach (var incompatible in incompatibleMods) { - var incompatibleMod = modInstances.First(m => incompatibleModType.IsInstanceOfType(m)); - Assert.That( - incompatibleMod.IncompatibleMods.Any(m => m.IsInstanceOfType(mod)), - $"{mod} has {incompatibleMod} in it's incompatible mods, but {incompatibleMod} does not have {mod} in it's incompatible mods." - ); + foreach (var incompatibleMod in modInstances.Where(m => incompatible.IsInstanceOfType(m))) + { + Assert.That( + incompatibleMod.IncompatibleMods.Any(m => m.IsInstanceOfType(modToCheck)), + $"{modToCheck} has {incompatibleMod} in it's incompatible mods, but {incompatibleMod} does not have {modToCheck} in it's incompatible mods." + ); + } } } }); From 24edffcbc47628e49df7e25159d1dbb437f2ddd5 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Fri, 26 Aug 2022 12:47:12 +0100 Subject: [PATCH 0739/2686] Moved ScaleMode to UprightAspectMaintainingContainer.cs --- .../UprightAspectMaintainingContainer.cs | 18 +++++++++++++++ .../Containers/UprightUnscaledContainer.cs | 23 ------------------- 2 files changed, 18 insertions(+), 23 deletions(-) delete mode 100644 osu.Game/Graphics/Containers/UprightUnscaledContainer.cs diff --git a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs index e556117bc0..9736cba206 100644 --- a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs +++ b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs @@ -119,4 +119,22 @@ namespace osu.Game.Graphics.Containers } } } + + public enum ScaleMode + { + /// + /// Prevent this container from scaling. + /// + NoScaling, + + /// + /// Scale uniformly (maintaining aspect ratio) based on the vertical scale of the parent. + /// + Vertical, + + /// + /// Scale uniformly (maintaining aspect ratio) based on the horizontal scale of the parent. + /// + Horizontal, + } } diff --git a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs b/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs deleted file mode 100644 index d801f4a215..0000000000 --- a/osu.Game/Graphics/Containers/UprightUnscaledContainer.cs +++ /dev/null @@ -1,23 +0,0 @@ -// 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.Graphics.Containers -{ - public enum ScaleMode - { - /// - /// Prevent this container from scaling. - /// - NoScaling, - - /// - /// Scale uniformly (maintaining aspect ratio) based on the vertical scale of the parent. - /// - Vertical, - - /// - /// Scale uniformly (maintaining aspect ratio) based on the horizontal scale of the parent. - /// - Horizontal, - } -} From 81c0a641b4f596ca4c9b0a7d9c19b97c389f2ee1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 26 Aug 2022 14:51:08 +0300 Subject: [PATCH 0740/2686] Fix selection fallback path not updated to check inserted indices --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index e9f676d32f..0cbc17c67a 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -299,7 +299,7 @@ namespace osu.Game.Screens.Select // If a direct selection couldn't be made, it's feasible that the difficulty name (or beatmap metadata) changed. // Let's attempt to follow set-level selection anyway. - SelectBeatmap(sender[changes.NewModifiedIndices.First()].Beatmaps.First()); + SelectBeatmap(sender[modifiedAndInserted.First()].Beatmaps.First()); } } } From a3e595a9aac215987a6cb5ee5cad82cfad615a5c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 26 Aug 2022 14:51:19 +0300 Subject: [PATCH 0741/2686] Update comment to include inserted indices --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 0cbc17c67a..0f130714f1 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -277,7 +277,7 @@ namespace osu.Game.Screens.Select if (selectedSetMarkedDeleted && modifiedAndInserted.Any()) { - // If it is no longer valid, make the bold assumption that an updated version will be available in the modified indices. + // If it is no longer valid, make the bold assumption that an updated version will be available in the modified/inserted indices. // This relies on the full update operation being in a single transaction, so please don't change that. foreach (int i in modifiedAndInserted) { From 470bec79490b28e8eabe10f1f706d2806ddfaa64 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 23:29:03 +0900 Subject: [PATCH 0742/2686] Move private method down --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 60c8dcef21..1984840553 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -170,41 +170,6 @@ namespace osu.Game.Graphics.UserInterface selectionStarted = false; } - private void playSelectSample(SelectionSampleType selectionType) - { - if (Time.Current < sampleLastPlaybackTime + 15) return; - - SampleChannel? channel; - double pitch = 0.98 + RNG.NextDouble(0.04); - - switch (selectionType) - { - case SelectionSampleType.All: - channel = selectAllSample?.GetChannel(); - break; - - case SelectionSampleType.Word: - channel = selectWordSample?.GetChannel(); - break; - - case SelectionSampleType.Deselect: - channel = deselectSample?.GetChannel(); - break; - - default: - channel = selectCharSample?.GetChannel(); - pitch += (SelectedText.Length / (double)Text.Length) * 0.15f; - break; - } - - if (channel == null) return; - - channel.Frequency.Value = pitch; - channel.Play(); - - sampleLastPlaybackTime = Time.Current; - } - protected override void OnImeComposition(string newComposition, int removedTextLength, int addedTextLength, bool caretMoved) { base.OnImeComposition(newComposition, removedTextLength, addedTextLength, caretMoved); @@ -294,6 +259,41 @@ namespace osu.Game.Graphics.UserInterface SelectionColour = SelectionColour, }; + private void playSelectSample(SelectionSampleType selectionType) + { + if (Time.Current < sampleLastPlaybackTime + 15) return; + + SampleChannel? channel; + double pitch = 0.98 + RNG.NextDouble(0.04); + + switch (selectionType) + { + case SelectionSampleType.All: + channel = selectAllSample?.GetChannel(); + break; + + case SelectionSampleType.Word: + channel = selectWordSample?.GetChannel(); + break; + + case SelectionSampleType.Deselect: + channel = deselectSample?.GetChannel(); + break; + + default: + channel = selectCharSample?.GetChannel(); + pitch += (SelectedText.Length / (double)Text.Length) * 0.15f; + break; + } + + if (channel == null) return; + + channel.Frequency.Value = pitch; + channel.Play(); + + sampleLastPlaybackTime = Time.Current; + } + private void playTextAddedSample() => textAddedSamples[RNG.Next(0, textAddedSamples.Length)]?.Play(); private class OsuCaret : Caret From b082dc1fe47f30662d7f2f81a3ac5766371a1bf9 Mon Sep 17 00:00:00 2001 From: MBmasher Date: Sat, 27 Aug 2022 18:31:07 +1000 Subject: [PATCH 0743/2686] Slightly buff flashlight multiplier --- osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs index 84ef109598..40448c444c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Flashlight.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills hasHiddenMod = mods.Any(m => m is OsuModHidden); } - private double skillMultiplier => 0.05; + private double skillMultiplier => 0.052; private double strainDecayBase => 0.15; private double currentStrain; From 16e0ec2f88f7924c4a9f965a735c5a635981c300 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Sat, 27 Aug 2022 13:53:50 +0200 Subject: [PATCH 0744/2686] Fixed 0 length merge being allowed --- .../Editor/TestSceneObjectMerging.cs | 43 +++++++++++++++++++ .../Edit/OsuSelectionHandler.cs | 7 ++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs index cdb2a7fe77..4673c3d1d9 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs @@ -3,9 +3,11 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Objects; using osuTK; using osuTK.Input; @@ -14,6 +16,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor { public class TestSceneObjectMerging : TestSceneOsuEditor { + private OsuSelectionHandler selectionHandler => Editor.ChildrenOfType().First(); + [Test] public void TestSimpleMerge() { @@ -29,6 +33,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor EditorBeatmap.SelectedHitObjects.Add(circle2); }); + moveMouseToHitObject(1); + AddAssert("merge option available", () => selectionHandler.ContextMenuItems.Any(o => o.Text.Value == "Merge selection")); + mergeSelection(); AddAssert("slider created", () => circle1 is not null && circle2 is not null && sliderCreatedFor( @@ -174,6 +181,30 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddAssert("spinner not merged", () => EditorBeatmap.HitObjects.Contains(spinner)); } + [Test] + public void TestIllegalMerge() + { + HitCircle? circle1 = null; + HitCircle? circle2 = null; + + AddStep("add two circles on the same position", () => + { + circle1 = new HitCircle(); + circle2 = new HitCircle { Position = circle1.Position + Vector2.UnitX, StartTime = 1 }; + EditorClock.Seek(0); + EditorBeatmap.Add(circle1); + EditorBeatmap.Add(circle2); + EditorBeatmap.SelectedHitObjects.Add(circle1); + EditorBeatmap.SelectedHitObjects.Add(circle2); + }); + + moveMouseToHitObject(1); + AddAssert("merge option not available", () => selectionHandler.ContextMenuItems.Length > 0 && selectionHandler.ContextMenuItems.All(o => o.Text.Value != "Merge selection")); + mergeSelection(); + AddAssert("circles not merged", () => circle1 is not null && circle2 is not null + && EditorBeatmap.HitObjects.Contains(circle1) && EditorBeatmap.HitObjects.Contains(circle2)); + } + private void mergeSelection() { AddStep("merge selection", () => @@ -225,5 +256,17 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor return mergedSlider.Samples[0] is not null; } + + private void moveMouseToHitObject(int index) + { + AddStep($"hover mouse over hit object {index}", () => + { + if (EditorBeatmap.HitObjects.Count <= index) + return; + + Vector2 position = ((OsuHitObject)EditorBeatmap.HitObjects[index]).Position; + InputManager.MoveMouseTo(selectionHandler.ToScreenSpace(position)); + }); + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 2c5bbdb279..8b67c0dcc9 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -358,7 +358,8 @@ namespace osu.Game.Rulesets.Osu.Edit { var mergeableObjects = selectedMergeableObjects; - if (mergeableObjects.Length < 2) + if (mergeableObjects.Length < 2 || (mergeableObjects.All(h => h is not Slider) + && Precision.AlmostBigger(1, Vector2.DistanceSquared(mergeableObjects[0].Position, mergeableObjects[1].Position)))) return; ChangeHandler?.BeginChange(); @@ -445,7 +446,9 @@ namespace osu.Game.Rulesets.Osu.Edit foreach (var item in base.GetContextMenuItemsForSelection(selection)) yield return item; - if (selectedMergeableObjects.Length > 1) + var mergeableObjects = selectedMergeableObjects; + if (mergeableObjects.Length > 1 && (mergeableObjects.Any(h => h is Slider) + || Precision.DefinitelyBigger(Vector2.DistanceSquared(mergeableObjects[0].Position, mergeableObjects[1].Position), 1))) yield return new OsuMenuItem("Merge selection", MenuItemType.Destructive, mergeSelection); } } From ff2eac79d14934b5d6e179d38792d196484b77bd Mon Sep 17 00:00:00 2001 From: OliBomby Date: Sat, 27 Aug 2022 17:43:32 +0200 Subject: [PATCH 0745/2686] fix same time merge causing crash --- .../Editor/TestSceneObjectMerging.cs | 29 ++++++++++++++++++- .../Edit/OsuSelectionHandler.cs | 2 ++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs index 4673c3d1d9..5c5384e0b7 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs @@ -190,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddStep("add two circles on the same position", () => { circle1 = new HitCircle(); - circle2 = new HitCircle { Position = circle1.Position + Vector2.UnitX, StartTime = 1 }; + circle2 = new HitCircle { Position = circle1.Position + Vector2.UnitX }; EditorClock.Seek(0); EditorBeatmap.Add(circle1); EditorBeatmap.Add(circle2); @@ -205,6 +205,33 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor && EditorBeatmap.HitObjects.Contains(circle1) && EditorBeatmap.HitObjects.Contains(circle2)); } + [Test] + public void TestSameStartTimeMerge() + { + HitCircle? circle1 = null; + HitCircle? circle2 = null; + + AddStep("add two circles at the same time", () => + { + circle1 = new HitCircle(); + circle2 = new HitCircle { Position = circle1.Position + 100 * Vector2.UnitX }; + EditorClock.Seek(0); + EditorBeatmap.Add(circle1); + EditorBeatmap.Add(circle2); + EditorBeatmap.SelectedHitObjects.Add(circle1); + EditorBeatmap.SelectedHitObjects.Add(circle2); + }); + + moveMouseToHitObject(1); + AddAssert("merge option available", () => selectionHandler.ContextMenuItems.Any(o => o.Text.Value == "Merge selection")); + + mergeSelection(); + + AddAssert("slider created", () => circle1 is not null && circle2 is not null && sliderCreatedFor( + (pos: circle1.Position, pathType: PathType.Linear), + (pos: circle2.Position, pathType: null))); + } + private void mergeSelection() { AddStep("merge selection", () => diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 8b67c0dcc9..3d425afe9e 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -363,6 +363,7 @@ namespace osu.Game.Rulesets.Osu.Edit return; ChangeHandler?.BeginChange(); + EditorBeatmap.BeginChange(); // Have an initial slider object. var firstHitObject = mergeableObjects[0]; @@ -438,6 +439,7 @@ namespace osu.Game.Rulesets.Osu.Edit SelectedItems.Clear(); SelectedItems.Add(mergedHitObject); + EditorBeatmap.EndChange(); ChangeHandler?.EndChange(); } From 3e828c3416bd6d4f4701a5916be185eff71ab0f5 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 27 Aug 2022 20:11:38 +0300 Subject: [PATCH 0746/2686] Move base layout from DifficultyMultiplierDisplay to another class --- osu.Game/Overlays/Mods/ModsEffectDisplay.cs | 144 ++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 osu.Game/Overlays/Mods/ModsEffectDisplay.cs diff --git a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs new file mode 100644 index 0000000000..a7c5ec9ef9 --- /dev/null +++ b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs @@ -0,0 +1,144 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Mods; +using osuTK; + +namespace osu.Game.Overlays.Mods +{ + /// + /// + /// Base class for displays of mods effects. + /// + public abstract class ModsEffectDisplay : Container + { + public const float HEIGHT = 42; + private const float value_area_width = 56; + private const float transition_duration = 200; + + private readonly Box contentBackground; + private readonly Box labelBackground; + private readonly Container content; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + /// + /// Text to display in the left area of the display. + /// + protected abstract LocalisableString Label { get; } + + protected override Container Content => content; + + protected ModsEffectDisplay() + { + Height = HEIGHT; + AutoSizeAxes = Axes.X; + + InternalChild = new InputBlockingContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Masking = true, + CornerRadius = ModSelectPanel.CORNER_RADIUS, + Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0), + Children = new Drawable[] + { + contentBackground = new Box + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Y, + Width = value_area_width + ModSelectPanel.CORNER_RADIUS + }, + new GridContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, value_area_width) + }, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Masking = true, + CornerRadius = ModSelectPanel.CORNER_RADIUS, + Children = new Drawable[] + { + labelBackground = new Box + { + RelativeSizeAxes = Axes.Both + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Horizontal = 18 }, + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), + Text = Label, + Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) + } + } + }, + content = new Container + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0) + } + } + } + } + } + }; + } + + [BackgroundDependencyLoader] + private void load() + { + labelBackground.Colour = colourProvider.Background4; + } + + /// + /// Fades colours of text and its background according to displayed value. + /// + /// Difference between actual value and default value. + /// Negative leads to green color, positive to red. Can be obtained via CompareTo(defaultValue). + protected void SetColours(int difference) + { + if (difference == 0) + { + contentBackground.FadeColour(colourProvider.Background3, transition_duration, Easing.OutQuint); + content.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); + } + else if (difference < 0) + { + contentBackground.FadeColour(colours.ForModType(ModType.DifficultyReduction), transition_duration, Easing.OutQuint); + content.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint); + } + else + { + contentBackground.FadeColour(colours.ForModType(ModType.DifficultyIncrease), transition_duration, Easing.OutQuint); + content.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint); + } + } + } +} From 90334a2b91888698e449797f8c29d6f71c526885 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 27 Aug 2022 20:12:45 +0300 Subject: [PATCH 0747/2686] Add test scene --- .../TestSceneModsEffectDisplay.cs | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs new file mode 100644 index 0000000000..36267b0e2a --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs @@ -0,0 +1,60 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osu.Game.Overlays.Mods; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneModsEffectDisplay : OsuTestScene + { + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + + [Test] + public void TestEffectDisplay() + { + TestDisplay dsp; + Add(dsp = new TestDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }); + AddSliderStep("value", 40, 60, 50, i => dsp.Value = i); + } + + private class TestDisplay : ModsEffectDisplay + { + private readonly OsuSpriteText text; + + protected override LocalisableString Label => "Test display"; + + public int Value + { + set + { + text.Text = value.ToString(); + SetColours(value.CompareTo(50)); + } + } + + public TestDisplay() + { + Add(text = new OsuSpriteText + { + Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold), + Text = "50" + }); + } + + [BackgroundDependencyLoader] + private void load() => SetColours(0); + } + } +} From 039f00956225ef2459da64469206a6a168c18687 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 27 Aug 2022 20:26:05 +0300 Subject: [PATCH 0748/2686] Inherit difficulty multiplier display from `ModsEffectDiplay` --- .../Mods/DifficultyMultiplierDisplay.cs | 140 +++--------------- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 4 +- 2 files changed, 21 insertions(+), 123 deletions(-) diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index 835883fb93..e5daa2de63 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -3,27 +3,24 @@ #nullable disable -using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Rulesets.Mods; using osuTK; using osu.Game.Localisation; namespace osu.Game.Overlays.Mods { - public class DifficultyMultiplierDisplay : CompositeDrawable, IHasCurrentValue + public sealed class DifficultyMultiplierDisplay : ModsEffectDisplay, IHasCurrentValue { - public const float HEIGHT = 42; + protected override LocalisableString Label => DifficultyMultiplierDisplayStrings.DifficultyMultiplier; public Bindable Current { @@ -33,143 +30,44 @@ namespace osu.Game.Overlays.Mods private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(1); - private readonly Box underlayBackground; - private readonly Box contentBackground; - private readonly FillFlowContainer multiplierFlow; private readonly MultiplierCounter multiplierCounter; - [Resolved] - private OsuColour colours { get; set; } - - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - - private const float multiplier_value_area_width = 56; - private const float transition_duration = 200; - public DifficultyMultiplierDisplay() { - Height = HEIGHT; - AutoSizeAxes = Axes.X; - - InternalChild = new InputBlockingContainer + Add(new FillFlowContainer { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Masking = true, - CornerRadius = ModSelectPanel.CORNER_RADIUS, - Shear = new Vector2(ShearedOverlayContainer.SHEAR, 0), + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(2, 0), Children = new Drawable[] { - underlayBackground = new Box + multiplierCounter = new MultiplierCounter { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Y, - Width = multiplier_value_area_width + ModSelectPanel.CORNER_RADIUS + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = { BindTarget = Current } }, - new GridContainer + new SpriteIcon { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Absolute, multiplier_value_area_width) - }, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Masking = true, - CornerRadius = ModSelectPanel.CORNER_RADIUS, - Children = new Drawable[] - { - contentBackground = new Box - { - RelativeSizeAxes = Axes.Both - }, - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Margin = new MarginPadding { Horizontal = 18 }, - Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), - Text = DifficultyMultiplierDisplayStrings.DifficultyMultiplier, - Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) - } - } - }, - multiplierFlow = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), - Direction = FillDirection.Horizontal, - Spacing = new Vector2(2, 0), - Children = new Drawable[] - { - multiplierCounter = new MultiplierCounter - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Current = { BindTarget = Current } - }, - new SpriteIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Icon = FontAwesome.Solid.Times, - Size = new Vector2(7), - Margin = new MarginPadding { Top = 1 } - } - } - } - } - } + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Solid.Times, + Size = new Vector2(7), + Margin = new MarginPadding { Top = 1 } } } - }; - } - - [BackgroundDependencyLoader] - private void load() - { - contentBackground.Colour = colourProvider.Background4; + }); } protected override void LoadComplete() { base.LoadComplete(); - current.BindValueChanged(_ => updateState(), true); + current.BindValueChanged(e => SetColours(e.NewValue.CompareTo(current.Default)), true); // required to prevent the counter initially rolling up from 0 to 1 // due to `Current.Value` having a nonstandard default value of 1. - multiplierCounter.SetCountWithoutRolling(Current.Value); - } - - private void updateState() - { - if (Current.IsDefault) - { - underlayBackground.FadeColour(colourProvider.Background3, transition_duration, Easing.OutQuint); - multiplierFlow.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); - } - else - { - var backgroundColour = Current.Value < 1 - ? colours.ForModType(ModType.DifficultyReduction) - : colours.ForModType(ModType.DifficultyIncrease); - - underlayBackground.FadeColour(backgroundColour, transition_duration, Easing.OutQuint); - multiplierFlow.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint); - } + multiplierCounter.SetCountWithoutRolling(current.Value); } private class MultiplierCounter : RollingCounter diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index b993aca0ca..ccc075b190 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -153,7 +153,7 @@ namespace osu.Game.Overlays.Mods { Padding = new MarginPadding { - Top = (ShowTotalMultiplier ? DifficultyMultiplierDisplay.HEIGHT : 0) + PADDING, + Top = (ShowTotalMultiplier ? ModsEffectDisplay.HEIGHT : 0) + PADDING, Bottom = PADDING }, RelativeSizeAxes = Axes.Both, @@ -191,7 +191,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopRight, Origin = Anchor.TopRight, AutoSizeAxes = Axes.X, - Height = DifficultyMultiplierDisplay.HEIGHT, + Height = ModsEffectDisplay.HEIGHT, Margin = new MarginPadding { Horizontal = 100 }, Child = multiplierDisplay = new DifficultyMultiplierDisplay { From 2a12194ff9243e44dc8b29ff6e25dfd456ff4767 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 28 Aug 2022 02:59:38 +0300 Subject: [PATCH 0749/2686] Test colours --- .../TestSceneModsEffectDisplay.cs | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs index 36267b0e2a..dd663ad59d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs @@ -1,38 +1,65 @@ // 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 NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; +using osu.Framework.Testing; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osu.Game.Overlays.Mods; +using osu.Game.Rulesets.Mods; +using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { + [TestFixture] public class TestSceneModsEffectDisplay : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + [Resolved] + private OsuColour colours { get; set; } = null!; + [Test] - public void TestEffectDisplay() + public void TestModsEffectDisplay() { - TestDisplay dsp; - Add(dsp = new TestDisplay + TestDisplay testDisplay = null!; + Box background = null!; + + AddStep("add display", () => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre + Add(testDisplay = new TestDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }); + var boxes = testDisplay.ChildrenOfType(); + background = boxes.First(); }); - AddSliderStep("value", 40, 60, 50, i => dsp.Value = i); + + AddStep("set value to default", () => testDisplay.Value = 50); + AddUntilStep("colours are correct", () => testDisplay.Container.Colour == Color4.White && background.Colour == colourProvider.Background3); + + AddStep("set value to less", () => testDisplay.Value = 40); + AddUntilStep("colours are correct", () => testDisplay.Container.Colour == colourProvider.Background5 && background.Colour == colours.ForModType(ModType.DifficultyReduction)); + + AddStep("set value to bigger", () => testDisplay.Value = 60); + AddUntilStep("colours are correct", () => testDisplay.Container.Colour == colourProvider.Background5 && background.Colour == colours.ForModType(ModType.DifficultyIncrease)); } private class TestDisplay : ModsEffectDisplay { private readonly OsuSpriteText text; + public Container Container => Content; + protected override LocalisableString Label => "Test display"; public int Value From 0cc6a76c17f6f5e9c0b36a747bfa349369f4e82c Mon Sep 17 00:00:00 2001 From: its5Q Date: Sun, 28 Aug 2022 14:13:38 +1000 Subject: [PATCH 0750/2686] Fix crash with legacy import from incomplete installs --- osu.Game/Database/LegacyBeatmapImporter.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Database/LegacyBeatmapImporter.cs b/osu.Game/Database/LegacyBeatmapImporter.cs index 6805cb36b8..0955461609 100644 --- a/osu.Game/Database/LegacyBeatmapImporter.cs +++ b/osu.Game/Database/LegacyBeatmapImporter.cs @@ -20,6 +20,10 @@ namespace osu.Game.Database protected override IEnumerable GetStableImportPaths(Storage storage) { + // make sure the directory exists + if (!storage.ExistsDirectory(string.Empty)) + yield break; + foreach (string directory in storage.GetDirectories(string.Empty)) { var directoryStorage = storage.GetStorageForDirectory(directory); From d4a52baa56f0eee37c6a50ba65c29d57dc8bc3f9 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Mon, 29 Aug 2022 00:07:42 +0100 Subject: [PATCH 0751/2686] Added visual test for UprightAspectMaintainingContainer --- ...tSceneUprightAspectMaintainingContainer.cs | 245 ++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs new file mode 100644 index 0000000000..8b87e4030e --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs @@ -0,0 +1,245 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics; +using osuTK.Graphics; +using osuTK; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneUprightAspectMaintainingContainer : OsuGridTestScene + { + private const int rows = 3; + private const int columns = 4; + + private readonly ScaleMode[] scaleModeValues = { ScaleMode.NoScaling, ScaleMode.Horizontal, ScaleMode.Vertical }; + private readonly float[] scalingFactorValues = { 1.0f / 3, 1.0f / 2, 1.0f, 1.5f }; + + private readonly List> parentContainers = new List>(rows); + private readonly List> childContainers = new List>(rows); + + // Preferably should be set to (4 * 2^n) + private const int rotation_step_count = 8; + + private readonly List flipStates = new List(); + private readonly List rotationSteps = new List(); + private readonly List scaleSteps = new List(); + + public TestSceneUprightAspectMaintainingContainer() + : base(rows, columns) + { + for (int i = 0; i < rows; i++) + { + parentContainers.Add(new List()); + childContainers.Add(new List()); + + for (int j = 0; j < columns; j++) + { + UprightAspectMaintainingContainer child; + Container parent = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Height = 80, + Width = 80, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = new Color4(255, 0, 0, 160), + }, + new OsuSpriteText + { + Text = "Parent", + }, + child = new UprightAspectMaintainingContainer + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + AutoSizeAxes = Axes.Both, + + // These are the parameters being Tested + Scaling = scaleModeValues[i], + ScalingFactor = scalingFactorValues[j], + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = new Color4(0, 0, 255, 160), + }, + new OsuSpriteText + { + Text = "Text", + Font = OsuFont.Numeric, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Padding = new MarginPadding + { + Horizontal = 4, + Vertical = 4, + } + }, + } + } + } + }; + + Container cellInfo = new Container + { + Children = new Drawable[] + { + new OsuSpriteText + { + Text = "Scaling: " + scaleModeValues[i].ToString(), + }, + new OsuSpriteText + { + Text = "ScalingFactor: " + scalingFactorValues[j].ToString("0.00"), + Margin = new MarginPadding + { + Top = 15, + }, + }, + }, + }; + + Cell(i * columns + j).Add(cellInfo); + Cell(i * columns + j).Add(parent); + parentContainers[i].Add(parent); + childContainers[i].Add(child); + } + } + + flipStates.AddRange(new[] { 1, -1 }); + rotationSteps.AddRange(Enumerable.Range(0, rotation_step_count).Select(x => 360f * ((float)x / rotation_step_count))); + scaleSteps.AddRange(new[] { 1, 0.5f, 0.3f, 1.5f, 2.0f }); + } + + [Test] + public void ExplicitlySizedParent() + { + var parentStates = from xFlip in flipStates + from yFlip in flipStates + from xScale in scaleSteps + from yScale in scaleSteps + from rotation in rotationSteps + select new { xFlip, yFlip, xScale, yScale, rotation }; + + foreach (var state in parentStates) + { + Vector2 parentScale = new Vector2(state.xFlip * state.xScale, state.yFlip * state.yScale); + float parentRotation = state.rotation; + + AddStep("S: (" + parentScale.X.ToString("0.00") + ", " + parentScale.Y.ToString("0.00") + "), R: " + parentRotation.ToString("0.00"), () => + { + foreach (List list in parentContainers) + { + foreach (Container container in list) + { + container.Scale = parentScale; + container.Rotation = parentRotation; + } + } + }); + + AddAssert("Check if state is valid", () => + { + foreach (int i in Enumerable.Range(0, parentContainers.Count)) + { + foreach (int j in Enumerable.Range(0, parentContainers[i].Count)) + { + if (!uprightAspectMaintainingContainerStateIsValid(parentContainers[i][j], childContainers[i][j])) + return false; + } + } + + return true; + }); + } + } + + private bool uprightAspectMaintainingContainerStateIsValid(Container parent, UprightAspectMaintainingContainer child) + { + Matrix3 parentMatrix = parent.DrawInfo.Matrix; + Matrix3 childMatrix = child.DrawInfo.Matrix; + Vector3 childScale = childMatrix.ExtractScale(); + Vector3 parentScale = parentMatrix.ExtractScale(); + + // Orientation check + if (!(isNearlyZero(MathF.Abs(childMatrix.M21)) && isNearlyZero(MathF.Abs(childMatrix.M12)))) + return false; + + // flip check + if (!(childMatrix.M11 * childMatrix.M22 > 0)) + return false; + + // Aspect ratio check + if (!isNearlyZero(childScale.X - childScale.Y, 0.0001f)) + return false; + + // ScalingMode check + switch (child.Scaling) + { + case ScaleMode.NoScaling: + if (!(isNearlyZero(childMatrix.M11 - 1.0f) && isNearlyZero(childMatrix.M22 - 1.0f))) + return false; + + break; + + case ScaleMode.Vertical: + if (!(checkScaling(child.ScalingFactor, parentScale.Y, childScale.Y))) + return false; + + break; + + case ScaleMode.Horizontal: + if (!(checkScaling(child.ScalingFactor, parentScale.X, childScale.X))) + return false; + + break; + } + + return true; + } + + private bool checkScaling(float scalingFactor, float parentScale, float childScale) + { + if (scalingFactor <= 1.0f) + { + if (!isNearlyZero(1.0f + (parentScale - 1.0f) * scalingFactor - childScale)) + return false; + } + else if (scalingFactor > 1.0f) + { + if (parentScale < 1.0f) + { + if (!isNearlyZero((parentScale * (1.0f / scalingFactor)) - childScale)) + return false; + } + else if (!isNearlyZero(parentScale * scalingFactor - childScale)) + return false; + } + + return true; + } + + private bool isNearlyZero(float f, float epsilon = 0.00001f) + { + return f < epsilon; + } + } +} From 62210bce4ee3c97c212e9f064ec6631ab271dd10 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Mon, 29 Aug 2022 00:08:19 +0100 Subject: [PATCH 0752/2686] Fixed issues found in UprightAspectMaintainingContainer --- .../UprightAspectMaintainingContainer.cs | 59 ++++++++++--------- 1 file changed, 31 insertions(+), 28 deletions(-) diff --git a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs index 9736cba206..64b9eb409b 100644 --- a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs +++ b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs @@ -14,8 +14,6 @@ namespace osu.Game.Graphics.Containers /// public class UprightAspectMaintainingContainer : Container { - protected override Container Content { get; } - /// /// Controls how much this container scales compared to its parent (default is 1.0f). /// @@ -30,7 +28,6 @@ namespace osu.Game.Graphics.Containers public UprightAspectMaintainingContainer() { - AddInternal(Content = new GrowToFitContainer()); AddLayout(layout); } @@ -45,6 +42,14 @@ namespace osu.Game.Graphics.Containers } } + public override void Add(Drawable drawable) + { + base.Add(new GrowToFitContainer + { + Child = drawable + }); + } + /// /// Keeps the drawable upright and unstretched preventing it from being rotated, sheared, scaled or flipped with its Parent. /// @@ -57,23 +62,23 @@ namespace osu.Game.Graphics.Containers parentMatrix.M31 = 0.0f; parentMatrix.M32 = 0.0f; - Matrix3 reversedParrent = parentMatrix.Inverted(); + Matrix3 reversedParent = parentMatrix.Inverted(); // Extract the rotation. - float angle = MathF.Atan2(reversedParrent.M12, reversedParrent.M11); + float angle = MathF.Atan2(reversedParent.M12, reversedParent.M11); Rotation = MathHelper.RadiansToDegrees(angle); // Remove rotation from the C matrix so that it only contains shear and scale. Matrix3 m = Matrix3.CreateRotationZ(-angle); - reversedParrent *= m; + reversedParent *= m; // Extract shear. - float alpha = reversedParrent.M21 / reversedParrent.M22; + float alpha = reversedParent.M21 / reversedParent.M22; Shear = new Vector2(-alpha, 0); // Etract scale. - float sx = reversedParrent.M11; - float sy = reversedParrent.M22; + float sx = reversedParent.M11; + float sy = reversedParent.M22; Vector3 parentScale = parentMatrix.ExtractScale(); @@ -90,32 +95,30 @@ namespace osu.Game.Graphics.Containers break; } - usedScale = 1.0f + (usedScale - 1.0f) * ScalingFactor; + if (Scaling != ScaleMode.NoScaling) + { + if (ScalingFactor < 1.0f) + usedScale = 1.0f + (usedScale - 1.0f) * ScalingFactor; + if (ScalingFactor > 1.0f) + usedScale = (usedScale < 1.0f) ? usedScale * (1.0f / ScalingFactor) : usedScale * ScalingFactor; + } Scale = new Vector2(sx * usedScale, sy * usedScale); } - /// - /// A container that grows in size to fit its children and retains its size when its children shrink - /// - private class GrowToFitContainer : Container + public class GrowToFitContainer : Container { - protected override Container Content => content; - private readonly Container content; - - public GrowToFitContainer() - { - InternalChild = content = new Container - { - AutoSizeAxes = Axes.Both, - }; - } - protected override void Update() { - base.Update(); - Height = Math.Max(content.Height, Height); - Width = Math.Max(content.Width, Width); + if ((Child.RelativeSizeAxes & Axes.X) != 0) + RelativeSizeAxes |= Axes.X; + else + Width = Math.Max(Child.Width, Width); + + if ((Child.RelativeSizeAxes & Axes.Y) != 0) + RelativeSizeAxes |= Axes.Y; + else + Height = Math.Max(Child.Height, Height); } } } From c0b13c7e1fa33da7681957dd62326632cba564e1 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 Aug 2022 19:39:12 +0900 Subject: [PATCH 0753/2686] Refactor ScoreProcessor ComputeScore() methods --- .../Rulesets/Scoring/ScoreProcessorTest.cs | 4 +- .../PerformanceBreakdownCalculator.cs | 2 +- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 60 +------------------ osu.Game/Scoring/ScoreManager.cs | 2 +- .../OnlinePlay/Playlists/PlaylistsPlayer.cs | 2 +- 5 files changed, 8 insertions(+), 62 deletions(-) diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs index 44ebdad2e4..7a45d1e7cf 100644 --- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs +++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs @@ -307,7 +307,7 @@ namespace osu.Game.Tests.Rulesets.Scoring HitObjects = { new TestHitObject(result) } }); - Assert.That(scoreProcessor.ComputeFinalScore(ScoringMode.Standardised, new ScoreInfo + Assert.That(scoreProcessor.ComputeScore(ScoringMode.Standardised, new ScoreInfo { Ruleset = new TestRuleset().RulesetInfo, MaxCombo = result.AffectsCombo() ? 1 : 0, @@ -350,7 +350,7 @@ namespace osu.Game.Tests.Rulesets.Scoring } }; - double totalScore = new TestScoreProcessor().ComputeFinalScore(ScoringMode.Standardised, testScore); + double totalScore = new TestScoreProcessor().ComputeScore(ScoringMode.Standardised, testScore); Assert.That(totalScore, Is.EqualTo(750_000)); // 500K from accuracy (100%), and 250K from combo (50%). } #pragma warning restore CS0618 diff --git a/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs b/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs index 4465f1a328..3fb12041d1 100644 --- a/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs @@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Difficulty // calculate total score ScoreProcessor scoreProcessor = ruleset.CreateScoreProcessor(); scoreProcessor.Mods.Value = perfectPlay.Mods; - perfectPlay.TotalScore = (long)scoreProcessor.ComputeFinalScore(ScoringMode.Standardised, perfectPlay); + perfectPlay.TotalScore = (long)scoreProcessor.ComputeScore(ScoringMode.Standardised, perfectPlay); // compute rank achieved // default to SS, then adjust the rank with mods diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 5b21caee84..f13e3e6de6 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.Scoring /// /// The maximum of a basic (non-tick and non-bonus) hitobject. - /// Only populated via or . + /// Only populated via or . /// private HitResult? maxBasicResult; @@ -281,7 +281,7 @@ namespace osu.Game.Rulesets.Scoring /// The to compute the total score of. /// The total score in the given . [Pure] - public double ComputeFinalScore(ScoringMode mode, ScoreInfo scoreInfo) + public double ComputeScore(ScoringMode mode, ScoreInfo scoreInfo) { if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset)) throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\"."); @@ -291,60 +291,6 @@ namespace osu.Game.Rulesets.Scoring return ComputeScore(mode, current, maximum); } - /// - /// Computes the total score of a partially-completed . This should be used when it is unknown whether a score is complete. - /// - /// - /// Requires to have been called before use. - /// - /// The to represent the score as. - /// The to compute the total score of. - /// The total score in the given . - [Pure] - public double ComputePartialScore(ScoringMode mode, ScoreInfo scoreInfo) - { - if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset)) - throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\"."); - - if (!beatmapApplied) - throw new InvalidOperationException($"Cannot compute partial score without calling {nameof(ApplyBeatmap)}."); - - ExtractScoringValues(scoreInfo, out var current, out _); - - return ComputeScore(mode, current, MaximumScoringValues); - } - - /// - /// Computes the total score of a given with a given custom max achievable combo. - /// - /// - /// This is useful for processing legacy scores in which the maximum achievable combo can be more accurately determined via external means (e.g. database values or difficulty calculation). - ///

Does not require to have been called before use.

- ///
- /// The to represent the score as. - /// The to compute the total score of. - /// The maximum achievable combo for the provided beatmap. - /// The total score in the given . - [Pure] - public double ComputeFinalLegacyScore(ScoringMode mode, ScoreInfo scoreInfo, int maxAchievableCombo) - { - if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset)) - throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\"."); - - double accuracyRatio = scoreInfo.Accuracy; - double comboRatio = maxAchievableCombo > 0 ? (double)scoreInfo.MaxCombo / maxAchievableCombo : 1; - - ExtractScoringValues(scoreInfo, out var current, out var maximum); - - // For legacy osu!mania scores, a full-GREAT score has 100% accuracy. If combined with a full-combo, the score becomes indistinguishable from a full-PERFECT score. - // To get around this, the accuracy ratio is always recalculated based on the hit statistics rather than trusting the score. - // Note: This cannot be applied universally to all legacy scores, as some rulesets (e.g. catch) group multiple judgements together. - if (scoreInfo.IsLegacyScore && scoreInfo.Ruleset.OnlineID == 3 && maximum.BaseScore > 0) - accuracyRatio = current.BaseScore / maximum.BaseScore; - - return ComputeScore(mode, accuracyRatio, comboRatio, current.BonusScore, maximum.CountBasicHitObjects); - } - /// /// Computes the total score from scoring values. /// @@ -454,7 +400,7 @@ namespace osu.Game.Rulesets.Scoring score.MaximumStatistics[result] = maximumResultCounts.GetValueOrDefault(result); // Populate total score after everything else. - score.TotalScore = (long)Math.Round(ComputeFinalScore(ScoringMode.Standardised, score)); + score.TotalScore = (long)Math.Round(ComputeScore(ScoringMode.Standardised, score)); } /// diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 7367a1ef77..ecd37c761c 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -148,7 +148,7 @@ namespace osu.Game.Scoring var scoreProcessor = ruleset.CreateScoreProcessor(); scoreProcessor.Mods.Value = score.Mods; - return (long)Math.Round(scoreProcessor.ComputeFinalLegacyScore(mode, score, beatmapMaxCombo.Value)); + return (long)Math.Round(scoreProcessor.ComputeScore(mode, score)); } /// diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs index 282c1db585..1c4d02bb11 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs @@ -67,7 +67,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { await base.PrepareScoreForResultsAsync(score).ConfigureAwait(false); - Score.ScoreInfo.TotalScore = (int)Math.Round(ScoreProcessor.ComputeFinalScore(ScoringMode.Standardised, Score.ScoreInfo)); + Score.ScoreInfo.TotalScore = (int)Math.Round(ScoreProcessor.ComputeScore(ScoringMode.Standardised, Score.ScoreInfo)); } protected override void Dispose(bool isDisposing) From 90b9c02ac64ca410fd8440d8d30c4a607aaeffeb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 14:01:04 +0900 Subject: [PATCH 0754/2686] Remove `"internal"` identifier as unnecessary --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 30 +++++++++---------- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 20 ++++++------- osu.Game.Rulesets.Osu/OsuRuleset.cs | 40 ++++++++++++------------- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 32 ++++++++++---------- osu.Game/Rulesets/RealmRulesetStore.cs | 2 -- osu.Game/Rulesets/Ruleset.cs | 37 ++++++++++++----------- 6 files changed, 80 insertions(+), 81 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index f94bf276a0..321399c597 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -3,30 +3,30 @@ #nullable disable -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Rulesets.Catch.Mods; -using osu.Game.Rulesets.Catch.UI; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.UI; +using System; using System.Collections.Generic; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets.Catch.Replays; -using osu.Game.Rulesets.Replays.Types; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; +using osu.Game.Graphics; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Catch.Difficulty; -using osu.Game.Rulesets.Catch.Scoring; -using osu.Game.Rulesets.Difficulty; -using osu.Game.Rulesets.Scoring; -using System; -using osu.Framework.Extensions.EnumExtensions; -using osu.Framework.Localisation; using osu.Game.Rulesets.Catch.Edit; +using osu.Game.Rulesets.Catch.Mods; +using osu.Game.Rulesets.Catch.Replays; +using osu.Game.Rulesets.Catch.Scoring; using osu.Game.Rulesets.Catch.Skinning.Legacy; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Replays.Types; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Catch public const string SHORT_NAME = "fruits"; - public override string RulesetAPIVersionSupported => "internal"; + public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION; public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index b1fe4b30c4..813e2c461a 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -4,11 +4,6 @@ #nullable disable using System; -using osu.Game.Beatmaps; -using osu.Game.Rulesets.Mania.Mods; -using osu.Game.Rulesets.Mania.UI; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.UI; using System.Collections.Generic; using System.Linq; using osu.Framework.Extensions.EnumExtensions; @@ -16,11 +11,10 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; using osu.Framework.Localisation; -using osu.Game.Graphics; -using osu.Game.Rulesets.Mania.Replays; -using osu.Game.Rulesets.Replays.Types; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; using osu.Game.Configuration; +using osu.Game.Graphics; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; @@ -31,13 +25,19 @@ using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Difficulty; using osu.Game.Rulesets.Mania.Edit; using osu.Game.Rulesets.Mania.Edit.Setup; +using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Skinning.Legacy; +using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; +using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Ranking.Statistics; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania { @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Mania public const string SHORT_NAME = "mania"; - public override string RulesetAPIVersionSupported => "internal"; + public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION; public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this); diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 4400dfbb65..226299d168 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -3,42 +3,42 @@ #nullable disable -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Rulesets.Osu.UI; -using osu.Game.Rulesets.UI; +using System; using System.Collections.Generic; +using System.Linq; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; -using osu.Game.Overlays.Settings; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets.Osu.Edit; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu.Replays; -using osu.Game.Rulesets.Replays.Types; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Difficulty; -using osu.Game.Rulesets.Osu.Scoring; -using osu.Game.Rulesets.Scoring; -using osu.Game.Scoring; -using osu.Game.Skinning; -using System; -using System.Linq; -using osu.Framework.Extensions.EnumExtensions; -using osu.Framework.Localisation; +using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Edit.Setup; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Replays; +using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.Osu.Statistics; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.Replays.Types; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Ranking.Statistics; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu { @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Osu public const string SHORT_NAME = "osu"; - public override string RulesetAPIVersionSupported => "internal"; + public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION; public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 275c7144a7..f4eb1c68b3 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -3,33 +3,33 @@ #nullable disable -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Taiko.Mods; -using osu.Game.Rulesets.Taiko.UI; -using osu.Game.Rulesets.UI; +using System; using System.Collections.Generic; +using System.Linq; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets.Replays.Types; -using osu.Game.Rulesets.Taiko.Replays; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Legacy; +using osu.Game.Graphics; using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Beatmaps; using osu.Game.Rulesets.Taiko.Difficulty; -using osu.Game.Rulesets.Taiko.Scoring; -using osu.Game.Scoring; -using System; -using System.Linq; -using osu.Framework.Extensions.EnumExtensions; -using osu.Framework.Localisation; -using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Taiko.Edit; +using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Replays; +using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Rulesets.Taiko.Skinning.Legacy; +using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Screens.Ranking.Statistics; using osu.Game.Skinning; @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Taiko public const string SHORT_NAME = "taiko"; - public override string RulesetAPIVersionSupported => "internal"; + public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION; public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[] { diff --git a/osu.Game/Rulesets/RealmRulesetStore.cs b/osu.Game/Rulesets/RealmRulesetStore.cs index 590f118b68..456f6e399b 100644 --- a/osu.Game/Rulesets/RealmRulesetStore.cs +++ b/osu.Game/Rulesets/RealmRulesetStore.cs @@ -119,8 +119,6 @@ namespace osu.Game.Rulesets // Consider rulesets which haven't override the version as up-to-date for now. // At some point (once ruleset devs add versioning), we'll probably want to disallow this for deployed builds. case @"": - // Rulesets which are bundled with the game. Saves having to update their versions each bump. - case @"internal": // Ruleset is up-to-date, all good. case Ruleset.CURRENT_RULESET_API_VERSION: return true; diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 63f5906f46..cb72a1f20f 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -7,33 +7,33 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; +using osu.Framework.Extensions; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; using osu.Framework.IO.Stores; -using osu.Game.Beatmaps; -using osu.Game.Overlays.Settings; -using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Replays.Types; -using osu.Game.Rulesets.UI; -using osu.Game.Beatmaps.Legacy; -using osu.Game.Configuration; -using osu.Game.Rulesets.Configuration; -using osu.Game.Rulesets.Difficulty; -using osu.Game.Rulesets.Scoring; -using osu.Game.Scoring; -using osu.Game.Skinning; -using osu.Game.Users; -using JetBrains.Annotations; -using osu.Framework.Extensions; -using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Localisation; using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Legacy; +using osu.Game.Configuration; using osu.Game.Extensions; +using osu.Game.Overlays.Settings; +using osu.Game.Rulesets.Configuration; +using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Filter; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Replays.Types; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Ranking.Statistics; +using osu.Game.Skinning; +using osu.Game.Users; namespace osu.Game.Rulesets { @@ -56,7 +56,8 @@ namespace osu.Game.Rulesets /// Ruleset implementations should be updated to support the latest version to ensure they can still be loaded. /// /// - /// When updating a ruleset to support the latest API, you should set this to . + /// Generally, all ruleset implementations should point this directly to . + /// This will ensure that each time you compile a new release, it will pull in the most recent version. /// See https://github.com/ppy/osu/wiki/Breaking-Changes for full details on required ongoing changes. /// public virtual string RulesetAPIVersionSupported => string.Empty; From 5ff4e6a4fe657b6c2f420bc1df3eddb028401638 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 14:26:09 +0900 Subject: [PATCH 0755/2686] Add test coverage for outdated ruleset --- osu.Game.Tests/Database/RulesetStoreTests.cs | 87 +++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Database/RulesetStoreTests.cs b/osu.Game.Tests/Database/RulesetStoreTests.cs index 795e90f543..dedec6dc83 100644 --- a/osu.Game.Tests/Database/RulesetStoreTests.cs +++ b/osu.Game.Tests/Database/RulesetStoreTests.cs @@ -1,11 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; +using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Game.Beatmaps; using osu.Game.Rulesets; +using osu.Game.Rulesets.Difficulty; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Difficulty; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.UI; namespace osu.Game.Tests.Database { @@ -51,5 +59,80 @@ namespace osu.Game.Tests.Database Assert.IsFalse(rulesets.GetRuleset("mania")?.IsManaged); }); } + + [Test] + public void TestOutdatedRulesetNotAvailable() + { + RunTestWithRealm((realm, storage) => + { + OutdatedRuleset.Version = "2021.101.0"; + OutdatedRuleset.HasImplementations = true; + + var ruleset = new OutdatedRuleset(); + string rulesetShortName = ruleset.RulesetInfo.ShortName; + + realm.Write(r => r.Add(new RulesetInfo(rulesetShortName, ruleset.RulesetInfo.Name, ruleset.RulesetInfo.InstantiationInfo, ruleset.RulesetInfo.OnlineID) + { + Available = true, + })); + + Assert.That(realm.Run(r => r.Find(rulesetShortName).Available), Is.True); + + // Availability is updated on construction of a RealmRulesetStore + var _ = new RealmRulesetStore(realm, storage); + + Assert.That(realm.Run(r => r.Find(rulesetShortName).Available), Is.False); + + // Simulate the ruleset getting updated + OutdatedRuleset.Version = Ruleset.CURRENT_RULESET_API_VERSION; + var __ = new RealmRulesetStore(realm, storage); + + Assert.That(realm.Run(r => r.Find(rulesetShortName).Available), Is.True); + }); + } + + private class OutdatedRuleset : Ruleset + { + public override string RulesetAPIVersionSupported => Version; + + public static bool HasImplementations = true; + + public static string Version { get; set; } = CURRENT_RULESET_API_VERSION; + + public override IEnumerable GetModsFor(ModType type) + { + if (!HasImplementations) + throw new NotImplementedException(); + + return Array.Empty(); + } + + public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList? mods = null) + { + if (!HasImplementations) + throw new NotImplementedException(); + + return new DrawableOsuRuleset(new OsuRuleset(), beatmap, mods); + } + + public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) + { + if (!HasImplementations) + throw new NotImplementedException(); + + return new OsuBeatmapConverter(beatmap, new OsuRuleset()); + } + + public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) + { + if (!HasImplementations) + throw new NotImplementedException(); + + return new OsuDifficultyCalculator(new OsuRuleset().RulesetInfo, beatmap); + } + + public override string Description => "outdated ruleset"; + public override string ShortName => "ruleset-outdated"; + } } } From 892f43da433a96d408f8b8d723d03c677d1d3653 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 14:28:55 +0900 Subject: [PATCH 0756/2686] Add test coverage of ruleset being marked unavailable if methods are throwing --- osu.Game.Tests/Database/RulesetStoreTests.cs | 35 +++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Database/RulesetStoreTests.cs b/osu.Game.Tests/Database/RulesetStoreTests.cs index dedec6dc83..a5662fa121 100644 --- a/osu.Game.Tests/Database/RulesetStoreTests.cs +++ b/osu.Game.Tests/Database/RulesetStoreTests.cs @@ -60,15 +60,40 @@ namespace osu.Game.Tests.Database }); } + [Test] + public void TestRulesetThrowingOnMethods() + { + RunTestWithRealm((realm, storage) => + { + LoadTestRuleset.Version = Ruleset.CURRENT_RULESET_API_VERSION; + LoadTestRuleset.HasImplementations = false; + + var ruleset = new LoadTestRuleset(); + string rulesetShortName = ruleset.RulesetInfo.ShortName; + + realm.Write(r => r.Add(new RulesetInfo(rulesetShortName, ruleset.RulesetInfo.Name, ruleset.RulesetInfo.InstantiationInfo, ruleset.RulesetInfo.OnlineID) + { + Available = true, + })); + + Assert.That(realm.Run(r => r.Find(rulesetShortName).Available), Is.True); + + // Availability is updated on construction of a RealmRulesetStore + var _ = new RealmRulesetStore(realm, storage); + + Assert.That(realm.Run(r => r.Find(rulesetShortName).Available), Is.False); + }); + } + [Test] public void TestOutdatedRulesetNotAvailable() { RunTestWithRealm((realm, storage) => { - OutdatedRuleset.Version = "2021.101.0"; - OutdatedRuleset.HasImplementations = true; + LoadTestRuleset.Version = "2021.101.0"; + LoadTestRuleset.HasImplementations = true; - var ruleset = new OutdatedRuleset(); + var ruleset = new LoadTestRuleset(); string rulesetShortName = ruleset.RulesetInfo.ShortName; realm.Write(r => r.Add(new RulesetInfo(rulesetShortName, ruleset.RulesetInfo.Name, ruleset.RulesetInfo.InstantiationInfo, ruleset.RulesetInfo.OnlineID) @@ -84,14 +109,14 @@ namespace osu.Game.Tests.Database Assert.That(realm.Run(r => r.Find(rulesetShortName).Available), Is.False); // Simulate the ruleset getting updated - OutdatedRuleset.Version = Ruleset.CURRENT_RULESET_API_VERSION; + LoadTestRuleset.Version = Ruleset.CURRENT_RULESET_API_VERSION; var __ = new RealmRulesetStore(realm, storage); Assert.That(realm.Run(r => r.Find(rulesetShortName).Available), Is.True); }); } - private class OutdatedRuleset : Ruleset + private class LoadTestRuleset : Ruleset { public override string RulesetAPIVersionSupported => Version; From e8ae6840ea6da67cb206e55955c1040951378769 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 15:23:34 +0900 Subject: [PATCH 0757/2686] Add test coverage of selection being retained --- .../SongSelect/TestScenePlaySongSelect.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 3d8f496c9a..5db46e3097 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -6,15 +6,18 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; +using osu.Framework.Extensions; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics.Containers; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; @@ -24,6 +27,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays; using osu.Game.Overlays.Mods; +using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -413,6 +417,55 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmapInfo == null); } + [Test] + public void TestSelectionRetainedOnBeatmapUpdate() + { + createSongSelect(); + changeRuleset(0); + + Live original = null!; + int originalOnlineSetID = 0; + + AddStep(@"Sort by artist", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Artist)); + + AddStep("import original", () => + { + original = manager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).GetResultSafely(); + originalOnlineSetID = original!.Value.OnlineID; + }); + + // This will move the beatmap set to a different location in the carousel. + AddStep("Update original with bogus info", () => + { + original.PerformWrite(set => + { + foreach (var beatmap in set.Beatmaps) + { + beatmap.Metadata.Artist = "ZZZZZ"; + beatmap.OnlineID = 12804; + } + }); + }); + + AddRepeatStep("import other beatmaps", () => + { + var testBeatmapSetInfo = TestResources.CreateTestBeatmapSetInfo(); + + foreach (var beatmap in testBeatmapSetInfo.Beatmaps) + beatmap.Metadata.Artist = ((char)RNG.Next('A', 'Z')).ToString(); + + manager.Import(testBeatmapSetInfo); + }, 10); + + AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo?.BeatmapSet?.OnlineID == originalOnlineSetID); + + Task> updateTask = null!; + AddStep("update beatmap", () => updateTask = manager.ImportAsUpdate(new ProgressNotification(), new ImportTask(TestResources.GetQuickTestBeatmapForImport()), original.Value)); + AddUntilStep("wait for update completion", () => updateTask.IsCompleted); + + AddUntilStep("retained selection", () => songSelect.Carousel.SelectedBeatmapInfo?.BeatmapSet?.OnlineID == originalOnlineSetID); + } + [Test] public void TestPresentNewRulesetNewBeatmap() { From 3ff2058975a72aa69b2d2a7d39fa0ec4be2fe7d0 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 29 Aug 2022 09:23:53 +0300 Subject: [PATCH 0758/2686] Fix back-to-front fallback comparison in `HitObjectOrderedSelectionContainer` --- .../Compose/Components/HitObjectOrderedSelectionContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs b/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs index 06af232111..e3934025e2 100644 --- a/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Edit.Compose.Components if (result != 0) return result; } - return CompareReverseChildID(y, x); + return CompareReverseChildID(x, y); } protected override void Dispose(bool isDisposing) From b2e80ca7f0314f7478b340309632a900f5119ace Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Aug 2022 15:27:19 +0900 Subject: [PATCH 0759/2686] Don't include misses in failed score statistics --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 5b21caee84..547b132345 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -468,22 +468,6 @@ namespace osu.Game.Rulesets.Scoring score.Passed = false; Rank.Value = ScoreRank.F; - Debug.Assert(maximumResultCounts != null); - - if (maximumResultCounts.TryGetValue(HitResult.LargeTickHit, out int maximumLargeTick)) - scoreResultCounts[HitResult.LargeTickMiss] = maximumLargeTick - scoreResultCounts.GetValueOrDefault(HitResult.LargeTickHit); - - if (maximumResultCounts.TryGetValue(HitResult.SmallTickHit, out int maximumSmallTick)) - scoreResultCounts[HitResult.SmallTickMiss] = maximumSmallTick - scoreResultCounts.GetValueOrDefault(HitResult.SmallTickHit); - - int maximumBonusOrIgnore = maximumResultCounts.Where(kvp => kvp.Key.IsBonus() || kvp.Key == HitResult.IgnoreHit).Sum(kvp => kvp.Value); - int currentBonusOrIgnore = scoreResultCounts.Where(kvp => kvp.Key.IsBonus() || kvp.Key == HitResult.IgnoreHit).Sum(kvp => kvp.Value); - scoreResultCounts[HitResult.IgnoreMiss] = maximumBonusOrIgnore - currentBonusOrIgnore; - - int maximumBasic = maximumResultCounts.SingleOrDefault(kvp => kvp.Key.IsBasic()).Value; - int currentBasic = scoreResultCounts.Where(kvp => kvp.Key.IsBasic() && kvp.Key != HitResult.Miss).Sum(kvp => kvp.Value); - scoreResultCounts[HitResult.Miss] = maximumBasic - currentBasic; - PopulateScore(score); } From 423f6f90f2d28bf81ff5096b4b3a8156e7ad9caa Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 22 Aug 2022 21:31:30 +0900 Subject: [PATCH 0760/2686] Remove async calls from ScoreManager --- .../TestScenePlayerLocalScoreImport.cs | 2 +- .../SongSelect/TestSceneBeatmapLeaderboard.cs | 2 +- .../SongSelect/TestSceneTopLocalRank.cs | 2 +- .../TestSceneDeleteLocalScore.cs | 2 +- osu.Game/OsuGameBase.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 28 ++--- osu.Game/Scoring/ScoreManager.cs | 101 ++---------------- .../Playlists/PlaylistsResultsScreen.cs | 33 +++--- .../Expanded/ExpandedPanelMiddleContent.cs | 4 +- osu.Game/Screens/Ranking/ScorePanelList.cs | 45 ++++---- .../Select/Leaderboards/BeatmapLeaderboard.cs | 28 ++--- 11 files changed, 62 insertions(+), 187 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs index ddb585a73c..f3e436e31f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Gameplay { Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); - Dependencies.Cache(new ScoreManager(rulesets, () => beatmaps, LocalStorage, Realm, Scheduler, API)); + Dependencies.Cache(new ScoreManager(rulesets, () => beatmaps, LocalStorage, Realm, API)); Dependencies.Cache(Realm); } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index aeb30c94e1..07da1790c8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.SongSelect dependencies.Cache(rulesetStore = new RealmRulesetStore(Realm)); dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); - dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, Realm, Scheduler, API)); + dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, Realm, API)); Dependencies.Cache(Realm); return dependencies; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs index 72d78ededb..086af3084d 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.SongSelect { Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); - Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, Scheduler, API)); + Dependencies.Cache(scoreManager = new ScoreManager(rulesets, () => beatmapManager, LocalStorage, Realm, API)); Dependencies.Cache(Realm); beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely(); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index 3beade9d4f..db380cfdb7 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.UserInterface dependencies.Cache(new RealmRulesetStore(Realm)); dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); - dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get(), () => beatmapManager, LocalStorage, Realm, Scheduler, API)); + dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get(), () => beatmapManager, LocalStorage, Realm, API)); Dependencies.Cache(Realm); return dependencies; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 8d5c58d5f0..f87f95efd5 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -273,7 +273,7 @@ namespace osu.Game dependencies.Cache(difficultyCache = new BeatmapDifficultyCache()); // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() - dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, Scheduler, API, difficultyCache, LocalConfig)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, API, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, realm, API, Audio, Resources, Host, defaultBeatmap, difficultyCache, performOnlineLookups: true)); diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index e50fc356eb..53818bbee3 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -6,10 +6,8 @@ using System.Diagnostics; using System.Linq; using System.Threading; -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -87,27 +85,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores MD5Hash = apiBeatmap.MD5Hash }; - scoreManager.OrderByTotalScoreAsync(value.Scores.Select(s => s.ToScoreInfo(rulesets, beatmapInfo)).ToArray(), loadCancellationSource.Token) - .ContinueWith(task => Schedule(() => - { - if (loadCancellationSource.IsCancellationRequested) - return; + var scores = scoreManager.OrderByTotalScore(value.Scores.Select(s => s.ToScoreInfo(rulesets, beatmapInfo))).ToArray(); + var topScore = scores.First(); - var scores = task.GetResultSafely(); + scoreTable.DisplayScores(scores, apiBeatmap.Status.GrantsPerformancePoints()); + scoreTable.Show(); - var topScore = scores.First(); + var userScore = value.UserScore; + var userScoreInfo = userScore?.Score.ToScoreInfo(rulesets, beatmapInfo); - scoreTable.DisplayScores(scores, apiBeatmap.Status.GrantsPerformancePoints()); - scoreTable.Show(); + topScoresContainer.Add(new DrawableTopScore(topScore)); - var userScore = value.UserScore; - var userScoreInfo = userScore?.Score.ToScoreInfo(rulesets, beatmapInfo); - - topScoresContainer.Add(new DrawableTopScore(topScore)); - - if (userScoreInfo != null && userScoreInfo.OnlineID != topScore.OnlineID) - topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position)); - }), TaskContinuationOptions.OnlyOnRanToCompletion); + if (userScoreInfo != null && userScoreInfo.OnlineID != topScore.OnlineID) + topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position)); }); } diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index ecd37c761c..7204b5a281 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -11,10 +11,7 @@ using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using osu.Framework.Bindables; -using osu.Framework.Extensions; -using osu.Framework.Logging; using osu.Framework.Platform; -using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; @@ -28,17 +25,12 @@ namespace osu.Game.Scoring { public class ScoreManager : ModelManager, IModelImporter { - private readonly Scheduler scheduler; - private readonly BeatmapDifficultyCache difficultyCache; private readonly OsuConfigManager configManager; private readonly ScoreImporter scoreImporter; - public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, Scheduler scheduler, IAPIProvider api, - BeatmapDifficultyCache difficultyCache = null, OsuConfigManager configManager = null) + public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, IAPIProvider api, OsuConfigManager configManager = null) : base(storage, realm) { - this.scheduler = scheduler; - this.difficultyCache = difficultyCache; this.configManager = configManager; scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm, api) @@ -63,27 +55,13 @@ namespace osu.Game.Scoring /// Orders an array of s by total score. /// /// The array of s to reorder. - /// A to cancel the process. /// The given ordered by decreasing total score. - public async Task OrderByTotalScoreAsync(ScoreInfo[] scores, CancellationToken cancellationToken = default) + public IEnumerable OrderByTotalScore(IEnumerable scores) { - if (difficultyCache != null) - { - // Compute difficulties asynchronously first to prevent blocking via the GetTotalScore() call below. - foreach (var s in scores) - { - await difficultyCache.GetDifficultyAsync(s.BeatmapInfo, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false); - cancellationToken.ThrowIfCancellationRequested(); - } - } - - long[] totalScores = await Task.WhenAll(scores.Select(s => GetTotalScoreAsync(s, cancellationToken: cancellationToken))).ConfigureAwait(false); - - return scores.Select((score, index) => (score, totalScore: totalScores[index])) + return scores.Select((score, index) => (score, totalScore: GetTotalScore(score))) .OrderByDescending(g => g.totalScore) .ThenBy(g => g.score.OnlineID) - .Select(g => g.score) - .ToArray(); + .Select(g => g.score); } /// @@ -106,44 +84,18 @@ namespace osu.Game.Scoring /// The bindable containing the formatted total score string. public Bindable GetBindableTotalScoreString([NotNull] ScoreInfo score) => new TotalScoreStringBindable(GetBindableTotalScore(score)); - /// - /// Retrieves the total score of a in the given . - /// The score is returned in a callback that is run on the update thread. - /// - /// The to calculate the total score of. - /// The callback to be invoked with the total score. - /// The to return the total score as. - /// A to cancel the process. - public void GetTotalScore([NotNull] ScoreInfo score, [NotNull] Action callback, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default) - { - GetTotalScoreAsync(score, mode, cancellationToken) - .ContinueWith(task => scheduler.Add(() => - { - if (!cancellationToken.IsCancellationRequested) - callback(task.GetResultSafely()); - }), TaskContinuationOptions.OnlyOnRanToCompletion); - } - /// /// Retrieves the total score of a in the given . /// /// The to calculate the total score of. /// The to return the total score as. - /// A to cancel the process. /// The total score. - public async Task GetTotalScoreAsync([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default) + public long GetTotalScore([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised) { // TODO: This is required for playlist aggregate scores. They should likely not be getting here in the first place. if (string.IsNullOrEmpty(score.BeatmapInfo.MD5Hash)) return score.TotalScore; - int? beatmapMaxCombo = await GetMaximumAchievableComboAsync(score, cancellationToken).ConfigureAwait(false); - if (beatmapMaxCombo == null) - return score.TotalScore; - - if (beatmapMaxCombo == 0) - return 0; - var ruleset = score.Ruleset.CreateInstance(); var scoreProcessor = ruleset.CreateScoreProcessor(); scoreProcessor.Mods.Value = score.Mods; @@ -155,33 +107,9 @@ namespace osu.Game.Scoring /// Retrieves the maximum achievable combo for the provided score. /// /// The to compute the maximum achievable combo for. - /// A to cancel the process. /// The maximum achievable combo. A return value indicates the difficulty cache has failed to retrieve the combo. - public async Task GetMaximumAchievableComboAsync([NotNull] ScoreInfo score, CancellationToken cancellationToken = default) + public int GetMaximumAchievableCombo([NotNull] ScoreInfo score) { - if (score.IsLegacyScore) - { - // This score is guaranteed to be an osu!stable score. - // The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used. -#pragma warning disable CS0618 - if (score.BeatmapInfo.MaxCombo != null) - return score.BeatmapInfo.MaxCombo.Value; -#pragma warning restore CS0618 - - if (difficultyCache == null) - return null; - - // We can compute the max combo locally after the async beatmap difficulty computation. - var difficulty = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo, score.Ruleset, score.Mods, cancellationToken).ConfigureAwait(false); - - if (difficulty == null) - Logger.Log($"Couldn't get beatmap difficulty for beatmap {score.BeatmapInfo.OnlineID}"); - - return difficulty?.MaxCombo; - } - - // This is guaranteed to be a non-legacy score. - // The combo must be determined through the score's statistics, as both the beatmap's max combo and the difficulty calculator will provide osu!stable combo values. return Enum.GetValues(typeof(HitResult)).OfType().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum(); } @@ -191,10 +119,6 @@ namespace osu.Game.Scoring private class TotalScoreBindable : Bindable { private readonly Bindable scoringMode = new Bindable(); - private readonly ScoreInfo score; - private readonly ScoreManager scoreManager; - - private CancellationTokenSource difficultyCalculationCancellationSource; /// /// Creates a new . @@ -204,19 +128,8 @@ namespace osu.Game.Scoring /// The config. public TotalScoreBindable(ScoreInfo score, ScoreManager scoreManager, OsuConfigManager configManager) { - this.score = score; - this.scoreManager = scoreManager; - configManager?.BindWith(OsuSetting.ScoreDisplayMode, scoringMode); - scoringMode.BindValueChanged(onScoringModeChanged, true); - } - - private void onScoringModeChanged(ValueChangedEvent mode) - { - difficultyCalculationCancellationSource?.Cancel(); - difficultyCalculationCancellationSource = new CancellationTokenSource(); - - scoreManager.GetTotalScore(score, s => Value = s, mode.NewValue, difficultyCalculationCancellationSource.Token); + scoringMode.BindValueChanged(mode => Value = scoreManager.GetTotalScore(score, mode.NewValue), true); } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs index 53b38962ac..41633c34ce 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs @@ -180,31 +180,26 @@ namespace osu.Game.Screens.OnlinePlay.Playlists /// The callback to invoke with the final s. /// The s that were retrieved from s. /// An optional pivot around which the scores were retrieved. - private void performSuccessCallback([NotNull] Action> callback, [NotNull] List scores, [CanBeNull] MultiplayerScores pivot = null) + private void performSuccessCallback([NotNull] Action> callback, [NotNull] List scores, [CanBeNull] MultiplayerScores pivot = null) => Schedule(() => { - var scoreInfos = scores.Select(s => s.CreateScoreInfo(rulesets, playlistItem, Beatmap.Value.BeatmapInfo)).ToArray(); + var scoreInfos = scoreManager.OrderByTotalScore(scores.Select(s => s.CreateScoreInfo(rulesets, playlistItem, Beatmap.Value.BeatmapInfo))).ToArray(); - // Score panels calculate total score before displaying, which can take some time. In order to count that calculation as part of the loading spinner display duration, - // calculate the total scores locally before invoking the success callback. - scoreManager.OrderByTotalScoreAsync(scoreInfos).ContinueWith(_ => Schedule(() => + // Select a score if we don't already have one selected. + // Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll). + if (SelectedScore.Value == null) { - // Select a score if we don't already have one selected. - // Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll). - if (SelectedScore.Value == null) + Schedule(() => { - Schedule(() => - { - // Prefer selecting the local user's score, or otherwise default to the first visible score. - SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.OnlineID == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault(); - }); - } + // Prefer selecting the local user's score, or otherwise default to the first visible score. + SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.OnlineID == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault(); + }); + } - // Invoke callback to add the scores. Exclude the user's current score which was added previously. - callback.Invoke(scoreInfos.Where(s => s.OnlineID != Score?.OnlineID)); + // Invoke callback to add the scores. Exclude the user's current score which was added previously. + callback.Invoke(scoreInfos.Where(s => s.OnlineID != Score?.OnlineID)); - hideLoadingSpinners(pivot); - })); - } + hideLoadingSpinners(pivot); + }); private void hideLoadingSpinners([CanBeNull] MultiplayerScores pivot = null) { diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 0f202e5e08..b496f4242d 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -67,12 +67,10 @@ namespace osu.Game.Screens.Ranking.Expanded var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata; string creator = metadata.Author.Username; - int? beatmapMaxCombo = scoreManager.GetMaximumAchievableComboAsync(score).GetResultSafely(); - var topStatistics = new List { new AccuracyStatistic(score.Accuracy), - new ComboStatistic(score.MaxCombo, beatmapMaxCombo), + new ComboStatistic(score.MaxCombo, scoreManager.GetMaximumAchievableCombo(score)), new PerformanceStatistic(score), }; diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index 4f9e61a4a1..46f9efd126 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -8,11 +8,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; -using System.Threading.Tasks; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; @@ -151,32 +149,27 @@ namespace osu.Game.Screens.Ranking var score = trackingContainer.Panel.Score; - // Calculating score can take a while in extreme scenarios, so only display scores after the process completes. - scoreManager.GetTotalScoreAsync(score) - .ContinueWith(task => Schedule(() => - { - flow.SetLayoutPosition(trackingContainer, task.GetResultSafely()); + flow.SetLayoutPosition(trackingContainer, scoreManager.GetTotalScore(score)); - trackingContainer.Show(); + trackingContainer.Show(); - if (SelectedScore.Value?.Equals(score) == true) - { - SelectedScore.TriggerChange(); - } - else - { - // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. - // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel. - if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score)) - { - // A somewhat hacky property is used here because we need to: - // 1) Scroll after the scroll container's visible range is updated. - // 2) Scroll before the scroll container's scroll position is updated. - // Without this, we would have a 1-frame positioning error which looks very jarring. - scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing; - } - } - }), TaskContinuationOptions.OnlyOnRanToCompletion); + if (SelectedScore.Value?.Equals(score) == true) + { + SelectedScore.TriggerChange(); + } + else + { + // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. + // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel. + if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score)) + { + // A somewhat hacky property is used here because we need to: + // 1) Scroll after the scroll container's visible range is updated. + // 2) Scroll before the scroll container's scroll position is updated. + // Without this, we would have a 1-frame positioning error which looks very jarring. + scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing; + } + } } /// diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index b497943dfa..343b815e9f 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -8,10 +8,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Extensions; @@ -150,17 +148,12 @@ namespace osu.Game.Screens.Select.Leaderboards var req = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods); - req.Success += r => + req.Success += r => Schedule(() => { - scoreManager.OrderByTotalScoreAsync(r.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo)).ToArray(), cancellationToken) - .ContinueWith(task => Schedule(() => - { - if (cancellationToken.IsCancellationRequested) - return; - - SetScores(task.GetResultSafely(), r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo)); - }), TaskContinuationOptions.OnlyOnRanToCompletion); - }; + SetScores( + scoreManager.OrderByTotalScore(r.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))), + r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo)); + }); return req; } @@ -213,16 +206,9 @@ namespace osu.Game.Screens.Select.Leaderboards scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym))); } - scores = scores.Detach(); + scores = scoreManager.OrderByTotalScore(scores.Detach()); - scoreManager.OrderByTotalScoreAsync(scores.ToArray(), cancellationToken) - .ContinueWith(ordered => Schedule(() => - { - if (cancellationToken.IsCancellationRequested) - return; - - SetScores(ordered.GetResultSafely()); - }), TaskContinuationOptions.OnlyOnRanToCompletion); + Schedule(() => SetScores(scores)); } } From d75543ad68acc74546d9e4ab4d1c2066efb52d44 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Aug 2022 15:36:10 +0900 Subject: [PATCH 0761/2686] Simplify GetMaximumAchievableCombo further --- osu.Game/Scoring/ScoreManager.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 7204b5a281..fd600f4864 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -107,11 +107,8 @@ namespace osu.Game.Scoring /// Retrieves the maximum achievable combo for the provided score. /// /// The to compute the maximum achievable combo for. - /// The maximum achievable combo. A return value indicates the difficulty cache has failed to retrieve the combo. - public int GetMaximumAchievableCombo([NotNull] ScoreInfo score) - { - return Enum.GetValues(typeof(HitResult)).OfType().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum(); - } + /// The maximum achievable combo. + public int GetMaximumAchievableCombo([NotNull] ScoreInfo score) => score.MaximumStatistics.Where(kvp => kvp.Key.AffectsCombo()).Sum(kvp => kvp.Value); /// /// Provides the total score of a . Responds to changes in the currently-selected . From 81ac0daba8cd9574fd08821cbf8fe767d0969a1b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Aug 2022 15:51:12 +0900 Subject: [PATCH 0762/2686] Update xmldoc --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 547b132345..cd01ae7eff 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -458,7 +458,7 @@ namespace osu.Game.Rulesets.Scoring } /// - /// Populates the given score with remaining statistics as "missed" and marks it with rank. + /// Populates a failed score, marking it with the rank. /// public void FailScore(ScoreInfo score) { From a215d009fed8bae6f3566e08f19f3de753c098e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 26 Aug 2022 15:19:05 +0900 Subject: [PATCH 0763/2686] Update `Remove`/`RemoveRange`/`RemoveAll` calls in line with framework changes --- osu.Game.Rulesets.Catch/UI/Catcher.cs | 6 +++--- osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs | 6 +++--- osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs | 2 +- osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs | 2 +- osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs | 4 ++-- .../Objects/Drawables/DrawableOsuHitObject.cs | 2 +- .../Objects/Drawables/DrawableTaikoHitObject.cs | 6 +++--- .../Visual/Background/TestSceneSeasonalBackgroundLoader.cs | 2 +- .../Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 2 +- osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs | 2 +- osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs | 4 ++-- osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs | 4 ++-- osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs | 2 +- .../Visual/Online/TestSceneLeaderboardModSelector.cs | 2 +- .../Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs | 2 +- .../Visual/UserInterface/TestSceneLogoTrackingContainer.cs | 2 +- .../Screens/TestSceneGameplayScreen.cs | 2 +- osu.Game.Tournament/Screens/Drawings/Components/Group.cs | 2 +- .../Screens/Drawings/Components/ScrollingTeamContainer.cs | 4 ++-- .../Screens/Drawings/Components/VisualiserContainer.cs | 2 +- .../Screens/Editors/TournamentEditorScreen.cs | 2 +- osu.Game/Graphics/Containers/SectionsContainer.cs | 2 +- .../Graphics/Containers/SelectionCycleFillFlowContainer.cs | 2 +- osu.Game/Graphics/UserInterface/BarGraph.cs | 2 +- osu.Game/Graphics/UserInterface/TwoLayerButton.cs | 4 ++-- osu.Game/Overlays/Chat/ChannelList/ChannelList.cs | 2 +- osu.Game/Overlays/Chat/DrawableChannel.cs | 2 +- osu.Game/Rulesets/UI/JudgementContainer.cs | 2 +- .../Screens/Edit/Compose/Components/BlueprintContainer.cs | 2 +- .../Components/HitObjectOrderedSelectionContainer.cs | 4 ++-- .../Components/Timeline/TimelineBlueprintContainer.cs | 2 +- osu.Game/Screens/Menu/IntroTriangles.cs | 3 +-- .../Lounge/Components/DrawableRoomParticipantsList.cs | 4 ++-- .../Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs | 2 +- osu.Game/Screens/Ranking/ResultsScreen.cs | 2 +- osu.Game/Skinning/SkinnableSound.cs | 2 +- osu.Game/Skinning/SkinnableTargetContainer.cs | 2 +- osu.Game/Tests/Visual/OsuGameTestScene.cs | 5 +---- osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs | 2 +- 39 files changed, 52 insertions(+), 56 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index efc841dfac..61fefcfd99 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -271,8 +271,8 @@ namespace osu.Game.Rulesets.Catch.UI SetHyperDashState(); } - caughtObjectContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject); - droppedObjectTarget.RemoveAll(d => d.HitObject == drawableObject.HitObject); + caughtObjectContainer.RemoveAll(d => d.HitObject == drawableObject.HitObject, false); + droppedObjectTarget.RemoveAll(d => d.HitObject == drawableObject.HitObject, false); } /// @@ -430,7 +430,7 @@ namespace osu.Game.Rulesets.Catch.UI { var droppedObject = getDroppedObject(caughtObject); - caughtObjectContainer.Remove(caughtObject); + caughtObjectContainer.Remove(caughtObject, false); droppedObjectTarget.Add(droppedObject); diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index 6ab6a59293..d255937fed 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -93,15 +93,15 @@ namespace osu.Game.Rulesets.Catch.UI switch (entry.Animation) { case CatcherTrailAnimation.Dashing: - dashTrails.Remove(drawable); + dashTrails.Remove(drawable, false); break; case CatcherTrailAnimation.HyperDashing: - hyperDashTrails.Remove(drawable); + hyperDashTrails.Remove(drawable, false); break; case CatcherTrailAnimation.HyperDashAfterImage: - hyperDashAfterImages.Remove(drawable); + hyperDashAfterImages.Remove(drawable, false); break; } } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs index 3c24e91d54..6a94e5d371 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModPlayfieldCover.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Mania.Mods HitObjectContainer hoc = column.HitObjectArea.HitObjectContainer; Container hocParent = (Container)hoc.Parent; - hocParent.Remove(hoc); + hocParent.Remove(hoc, false); hocParent.Add(new PlayfieldCoveringWrapper(hoc).With(c => { c.RelativeSizeAxes = Axes.Both; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index 4b6f364831..49ba503cb5 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -155,7 +155,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy else { lightContainer.FadeOut(120) - .OnComplete(d => Column.TopLevelContainer.Remove(d)); + .OnComplete(d => Column.TopLevelContainer.Remove(d, false)); } } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs index 305678bb62..1e625cd4e6 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs @@ -195,7 +195,7 @@ namespace osu.Game.Rulesets.Osu.Tests { var drawableObject = getFunc.Invoke(); - hitObjectContainer.Remove(drawableObject); + hitObjectContainer.Remove(drawableObject, false); followPointRenderer.RemoveFollowPoints(drawableObject.HitObject); }); } @@ -212,7 +212,7 @@ namespace osu.Game.Rulesets.Osu.Tests else targetTime = getObject(hitObjectContainer.Count - 1).HitObject.StartTime + 1; - hitObjectContainer.Remove(toReorder); + hitObjectContainer.Remove(toReorder, false); toReorder.HitObject.StartTime = targetTime; hitObjectContainer.Add(toReorder); }); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 360b28f69f..aedb62dd24 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables // This is a bit ugly but we don't have the concept of InternalContent so it'll have to do for now. (https://github.com/ppy/osu-framework/issues/1690) protected override void AddInternal(Drawable drawable) => shakeContainer.Add(drawable); protected override void ClearInternal(bool disposeChildren = true) => shakeContainer.Clear(disposeChildren); - protected override bool RemoveInternal(Drawable drawable) => shakeContainer.Remove(drawable); + protected override bool RemoveInternal(Drawable drawable) => shakeContainer.Remove(drawable, true); protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 9bbd3670fa..c0c80eaa4a 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables isProxied = true; - nonProxiedContent.Remove(Content); + nonProxiedContent.Remove(Content, false); proxiedContent.Add(Content); } @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables isProxied = false; - proxiedContent.Remove(Content); + proxiedContent.Remove(Content, false); nonProxiedContent.Add(Content); } @@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Size = BaseSize = new Vector2(TaikoHitObject.DEFAULT_SIZE); if (MainPiece != null) - Content.Remove(MainPiece); + Content.Remove(MainPiece, true); Content.Add(MainPiece = CreateMainPiece()); } diff --git a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs index cce7ae1922..c9920cd01f 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs @@ -171,7 +171,7 @@ namespace osu.Game.Tests.Visual.Background => AddStep("create loader", () => { if (backgroundLoader != null) - Remove(backgroundLoader); + Remove(backgroundLoader, true); Add(backgroundLoader = new SeasonalBackgroundLoader()); }); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index d6c49b026e..5c7321fb24 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual.Gameplay Add(expectedComponentsAdjustmentContainer); expectedComponentsAdjustmentContainer.UpdateSubTree(); var expectedInfo = expectedComponentsContainer.CreateSkinnableInfo(); - Remove(expectedComponentsAdjustmentContainer); + Remove(expectedComponentsAdjustmentContainer, true); return almostEqual(actualInfo, expectedInfo); } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs index 9ad8ac086c..083be3539d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual.Gameplay { base.TearDownSteps(); AddStep("stop watching user", () => spectatorClient.StopWatchingUser(dummy_user_id)); - AddStep("remove test spectator client", () => Remove(spectatorClient)); + AddStep("remove test spectator client", () => Remove(spectatorClient, false)); } } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs index 30c2790fb4..2ec675874b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs @@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void loadStoryboard(IWorkingBeatmap working) { if (storyboard != null) - storyboardContainer.Remove(storyboard); + storyboardContainer.Remove(storyboard, true); var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true }; storyboardContainer.Clock = decoupledClock; @@ -106,7 +106,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void loadStoryboardNoVideo() { if (storyboard != null) - storyboardContainer.Remove(storyboard); + storyboardContainer.Remove(storyboard, true); var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true }; storyboardContainer.Clock = decoupledClock; diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs index 90e218675c..4473f315b9 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs @@ -62,8 +62,8 @@ namespace osu.Game.Tests.Visual.Menus [SetUp] public void SetUp() => Schedule(() => { - Remove(nowPlayingOverlay); - Remove(volumeOverlay); + Remove(nowPlayingOverlay, false); + Remove(volumeOverlay, false); Children = new Drawable[] { diff --git a/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs b/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs index f5c7ee2f19..2879536034 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("force save config", () => Game.LocalConfig.Save()); - AddStep("remove game", () => Remove(Game)); + AddStep("remove game", () => Remove(Game, true)); AddStep("create game again", CreateGame); diff --git a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs index 10d9a5664e..5579ecedbd 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs @@ -60,7 +60,7 @@ namespace osu.Game.Tests.Visual.Online { if (selected.Text == mod.Acronym) { - selectedMods.Remove(selected); + selectedMods.Remove(selected, true); break; } } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs index 27b485156c..c42b51c1a6 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.SongSelect OsuLogo logo = new OsuLogo { Scale = new Vector2(0.15f) }; - Remove(testDifficultyCache); + Remove(testDifficultyCache, false); Children = new Drawable[] { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs index 558ea01a49..d069e742dd 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs @@ -259,7 +259,7 @@ namespace osu.Game.Tests.Visual.UserInterface private void removeFacade() { - trackingContainer.Remove(logoFacade); + trackingContainer.Remove(logoFacade, false); visualBox.Colour = Color4.White; moveLogoFacade(); } diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs index 842324d03d..4fc15c365f 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs @@ -53,7 +53,7 @@ namespace osu.Game.Tournament.Tests.Screens { AddStep("setup screen", () => { - Remove(chat); + Remove(chat, false); Children = new Drawable[] { diff --git a/osu.Game.Tournament/Screens/Drawings/Components/Group.cs b/osu.Game.Tournament/Screens/Drawings/Components/Group.cs index f50abd6e58..0b1a5328ab 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/Group.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/Group.cs @@ -93,7 +93,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components { allTeams.RemoveAll(gt => gt.Team == team); - if (teams.RemoveAll(gt => gt.Team == team) > 0) + if (teams.RemoveAll(gt => gt.Team == team, true) > 0) { TeamsCount--; return true; diff --git a/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs b/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs index 52c611d323..55555adb80 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs @@ -170,7 +170,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components availableTeams.Add(team); - RemoveAll(c => c is ScrollingTeam); + RemoveAll(c => c is ScrollingTeam, false); setScrollState(ScrollState.Idle); } @@ -186,7 +186,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components public void ClearTeams() { availableTeams.Clear(); - RemoveAll(c => c is ScrollingTeam); + RemoveAll(c => c is ScrollingTeam, true); setScrollState(ScrollState.Idle); } diff --git a/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs b/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs index 15edbb76c1..663162d1ca 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs @@ -57,7 +57,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components if (allLines.Count == 0) return; - Remove(allLines.First()); + Remove(allLines.First(), true); allLines.Remove(allLines.First()); } diff --git a/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs index 0fefe6f780..8c55026c67 100644 --- a/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs @@ -106,7 +106,7 @@ namespace osu.Game.Tournament.Screens.Editors break; case NotifyCollectionChangedAction.Remove: - args.OldItems.Cast().ForEach(i => flow.RemoveAll(d => d.Model == i)); + args.OldItems.Cast().ForEach(i => flow.RemoveAll(d => d.Model == i, true)); break; } }; diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index c04a5add89..448ecc6b3d 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -70,7 +70,7 @@ namespace osu.Game.Graphics.Containers if (value == footer) return; if (footer != null) - scrollContainer.Remove(footer); + scrollContainer.Remove(footer, true); footer = value; if (value == null) return; diff --git a/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs b/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs index 94505d2310..2667b8b8e0 100644 --- a/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs +++ b/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs @@ -59,7 +59,7 @@ namespace osu.Game.Graphics.Containers drawable.StateChanged += state => selectionChanged(drawable, state); } - public override bool Remove(T drawable) + public override bool Remove(T drawable, bool disposeImmediately) => throw new NotSupportedException($"Cannot remove drawables from {nameof(SelectionCycleFillFlowContainer)}"); private void setSelected(int? value) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index f55875ac58..2e9fd6734f 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -74,7 +74,7 @@ namespace osu.Game.Graphics.UserInterface } //I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards - RemoveRange(Children.Where((_, index) => index >= value.Count()).ToList()); + RemoveRange(Children.Where((_, index) => index >= value.Count()).ToList(), true); } } } diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs index 144b51d3e8..1b8848f3d5 100644 --- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs +++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs @@ -64,8 +64,8 @@ namespace osu.Game.Graphics.UserInterface X = value.HasFlagFast(Anchor.x2) ? SIZE_RETRACTED.X * shear.X * 0.5f : 0; - Remove(c1); - Remove(c2); + Remove(c1, false); + Remove(c2, false); c1.Depth = value.HasFlagFast(Anchor.x2) ? 0 : 1; c2.Depth = value.HasFlagFast(Anchor.x2) ? 1 : 0; Add(c1); diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index b3814ca90c..d9f962ca97 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -99,7 +99,7 @@ namespace osu.Game.Overlays.Chat.ChannelList FillFlowContainer flow = getFlowForChannel(channel); channelMap.Remove(channel); - flow.Remove(item); + flow.Remove(item, true); updateVisibility(); } diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index c05f456a96..544daf7d2c 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -181,7 +181,7 @@ namespace osu.Game.Overlays.Chat { Trace.Assert(updated.Id.HasValue, "An updated message was returned with no ID."); - ChatLineFlow.Remove(found); + ChatLineFlow.Remove(found, false); found.Message = updated; ChatLineFlow.Add(found); } diff --git a/osu.Game/Rulesets/UI/JudgementContainer.cs b/osu.Game/Rulesets/UI/JudgementContainer.cs index 4336977aa8..471a62cab3 100644 --- a/osu.Game/Rulesets/UI/JudgementContainer.cs +++ b/osu.Game/Rulesets/UI/JudgementContainer.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.UI // remove any existing judgements for the judged object. // this can be the case when rewinding. - RemoveAll(c => c.JudgedObject == judgement.JudgedObject); + RemoveAll(c => c.JudgedObject == judgement.JudgedObject, false); base.Add(judgement); } diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 540fbf9a72..8b38d9c612 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -292,7 +292,7 @@ namespace osu.Game.Screens.Edit.Compose.Components blueprint.Selected -= OnBlueprintSelected; blueprint.Deselected -= OnBlueprintDeselected; - SelectionBlueprints.Remove(blueprint); + SelectionBlueprints.Remove(blueprint, true); if (movementBlueprints?.Contains(blueprint) == true) finishSelectionMovement(); diff --git a/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs b/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs index 06af232111..3be1c27129 100644 --- a/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs @@ -35,10 +35,10 @@ namespace osu.Game.Screens.Edit.Compose.Components base.Add(drawable); } - public override bool Remove(SelectionBlueprint drawable) + public override bool Remove(SelectionBlueprint drawable, bool disposeImmediately) { SortInternal(); - return base.Remove(drawable); + return base.Remove(drawable, disposeImmediately); } protected override int Compare(Drawable x, Drawable y) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 742e16d5a9..590f92d281 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { if (placementBlueprint != null) { - SelectionBlueprints.Remove(placementBlueprint); + SelectionBlueprints.Remove(placementBlueprint, true); placementBlueprint = null; } } diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index d777f78df2..05a6d25303 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -255,8 +255,7 @@ namespace osu.Game.Screens.Menu { lazerLogo.FadeOut().OnComplete(_ => { - logoContainerSecondary.Remove(lazerLogo); - lazerLogo.Dispose(); // explicit disposal as we are pushing a new screen and the expire may not get run. + logoContainerSecondary.Remove(lazerLogo, true); logo.FadeIn(); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs index 995a0d3397..9e2bd41fd0 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs @@ -232,7 +232,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private void removeUser(APIUser user) { - avatarFlow.RemoveAll(a => a.User == user); + avatarFlow.RemoveAll(a => a.User == user, true); } private void clearUsers() @@ -250,7 +250,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components hiddenUsers.Count = hiddenCount; if (displayedCircles > NumberOfCircles) - avatarFlow.Remove(avatarFlow.Last()); + avatarFlow.Remove(avatarFlow.Last(), true); else if (displayedCircles < NumberOfCircles) { var nextUser = RecentParticipants.FirstOrDefault(u => avatarFlow.All(a => a.User != u)); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index 6142fc78a8..e6b1942506 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -138,7 +138,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { foreach (var r in rooms) { - roomFlow.RemoveAll(d => d.Room == r); + roomFlow.RemoveAll(d => d.Room == r, true); // selection may have a lease due to being in a sub screen. if (!SelectedRoom.Disabled) diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 226216b0f0..486df8653f 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -317,7 +317,7 @@ namespace osu.Game.Screens.Ranking var screenSpacePos = detachedPanel.ScreenSpaceDrawQuad.TopLeft; // Remove from the local container and re-attach. - detachedPanelContainer.Remove(detachedPanel); + detachedPanelContainer.Remove(detachedPanel, false); ScorePanelList.Attach(detachedPanel); // Move into its original location in the attached container first, then to the final location. diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index c2696c56f3..8f71b40801 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -151,7 +151,7 @@ namespace osu.Game.Skinning bool wasPlaying = IsPlaying; // Remove all pooled samples (return them to the pool), and dispose the rest. - samplesContainer.RemoveAll(s => s.IsInPool); + samplesContainer.RemoveAll(s => s.IsInPool, false); samplesContainer.Clear(); foreach (var s in samples) diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index 341a881789..2faaa9a905 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -85,7 +85,7 @@ namespace osu.Game.Skinning if (!(component is Drawable drawable)) throw new ArgumentException($"Provided argument must be of type {nameof(Drawable)}.", nameof(component)); - content.Remove(drawable); + content.Remove(drawable, true); components.Remove(component); } diff --git a/osu.Game/Tests/Visual/OsuGameTestScene.cs b/osu.Game/Tests/Visual/OsuGameTestScene.cs index 69a945db34..e47d19fba6 100644 --- a/osu.Game/Tests/Visual/OsuGameTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGameTestScene.cs @@ -58,10 +58,7 @@ namespace osu.Game.Tests.Visual AddStep("Create new game instance", () => { if (Game?.Parent != null) - { - Remove(Game); - Game.Dispose(); - } + Remove(Game, true); RecycleLocalStorage(false); diff --git a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs index 797e8363c3..a12459bc4e 100644 --- a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs @@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual protected void ResetPlacement() { if (CurrentBlueprint != null) - Remove(CurrentBlueprint); + Remove(CurrentBlueprint, true); Add(CurrentBlueprint = CreateBlueprint()); } From 105aa01e7d414d5e1837d00fd7eb4990895d98c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 15:49:28 +0900 Subject: [PATCH 0764/2686] Update usages of `RemoveInternal` --- .../Edit/Blueprints/Components/EditablePath.cs | 2 +- .../Edit/Blueprints/Components/NestedOutlineContainer.cs | 2 +- .../Objects/Drawables/DrawableOsuHitObject.cs | 2 +- osu.Game/Graphics/Backgrounds/Background.cs | 2 +- osu.Game/Graphics/Containers/SectionsContainer.cs | 2 +- osu.Game/Rulesets/Judgements/DrawableJudgement.cs | 2 +- .../Objects/Pooling/PooledDrawableWithLifetimeContainer.cs | 2 +- osu.Game/Rulesets/UI/HitObjectContainer.cs | 2 +- osu.Game/Screens/Play/FailAnimation.cs | 3 +-- osu.Game/Screens/Ranking/ScorePanelTrackingContainer.cs | 2 +- 10 files changed, 10 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs index 44d14ec330..8473eda663 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components public void UpdateFrom(ScrollingHitObjectContainer hitObjectContainer, JuiceStream hitObject) { while (path.Vertices.Count < InternalChildren.Count) - RemoveInternal(InternalChildren[^1]); + RemoveInternal(InternalChildren[^1], true); while (InternalChildren.Count < path.Vertices.Count) AddInternal(new VertexPiece()); diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs index 431ba331ac..a6f1732bc1 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components .Where(h => !(h is TinyDroplet))); while (nestedHitObjects.Count < InternalChildren.Count) - RemoveInternal(InternalChildren[^1]); + RemoveInternal(InternalChildren[^1], true); while (InternalChildren.Count < nestedHitObjects.Count) AddInternal(new FruitOutline()); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index aedb62dd24..6e525071ca 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables // This is a bit ugly but we don't have the concept of InternalContent so it'll have to do for now. (https://github.com/ppy/osu-framework/issues/1690) protected override void AddInternal(Drawable drawable) => shakeContainer.Add(drawable); protected override void ClearInternal(bool disposeChildren = true) => shakeContainer.Clear(disposeChildren); - protected override bool RemoveInternal(Drawable drawable) => shakeContainer.Remove(drawable, true); + protected override bool RemoveInternal(Drawable drawable, bool disposeImmediately) => shakeContainer.Remove(drawable, disposeImmediately); protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; diff --git a/osu.Game/Graphics/Backgrounds/Background.cs b/osu.Game/Graphics/Backgrounds/Background.cs index 2dd96bcb09..0899c0706d 100644 --- a/osu.Game/Graphics/Backgrounds/Background.cs +++ b/osu.Game/Graphics/Backgrounds/Background.cs @@ -57,7 +57,7 @@ namespace osu.Game.Graphics.Backgrounds { if (bufferedContainer == null && newBlurSigma != Vector2.Zero) { - RemoveInternal(Sprite); + RemoveInternal(Sprite, false); AddInternal(bufferedContainer = new BufferedContainer(cachedFrameBuffer: true) { diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 448ecc6b3d..b8a8ea79cc 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -35,7 +35,7 @@ namespace osu.Game.Graphics.Containers if (value == expandableHeader) return; if (expandableHeader != null) - RemoveInternal(expandableHeader); + RemoveInternal(expandableHeader, false); expandableHeader = value; diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 0d8b8429d8..7e1196d4ca 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -165,7 +165,7 @@ namespace osu.Game.Rulesets.Judgements // sub-classes might have added their own children that would be removed here if .InternalChild was used. if (JudgementBody != null) - RemoveInternal(JudgementBody); + RemoveInternal(JudgementBody, true); AddInternal(JudgementBody = new SkinnableDrawable(new GameplaySkinComponent(type), _ => CreateDefaultJudgement(type), confineMode: ConfineMode.NoScaling) diff --git a/osu.Game/Rulesets/Objects/Pooling/PooledDrawableWithLifetimeContainer.cs b/osu.Game/Rulesets/Objects/Pooling/PooledDrawableWithLifetimeContainer.cs index 07a80895e6..d5b4390ce8 100644 --- a/osu.Game/Rulesets/Objects/Pooling/PooledDrawableWithLifetimeContainer.cs +++ b/osu.Game/Rulesets/Objects/Pooling/PooledDrawableWithLifetimeContainer.cs @@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.Objects.Pooling /// /// Invoked when the entry became dead. /// - protected virtual void RemoveDrawable(TEntry entry, TDrawable drawable) => RemoveInternal(drawable); + protected virtual void RemoveDrawable(TEntry entry, TDrawable drawable) => RemoveInternal(drawable, false); private void entryCrossedBoundary(LifetimeEntry lifetimeEntry, LifetimeBoundaryKind kind, LifetimeBoundaryCrossingDirection direction) { diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index 589b585643..bbced9e58c 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -124,7 +124,7 @@ namespace osu.Game.Rulesets.UI unbindStartTime(drawable); - RemoveInternal(drawable); + RemoveInternal(drawable, false); } #endregion diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index 7275b369c3..a4b4bf4d2b 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -166,8 +166,7 @@ namespace osu.Game.Screens.Play if (filters.Parent == null) return; - RemoveInternal(filters); - filters.Dispose(); + RemoveInternal(filters, true); } protected override void Update() diff --git a/osu.Game/Screens/Ranking/ScorePanelTrackingContainer.cs b/osu.Game/Screens/Ranking/ScorePanelTrackingContainer.cs index e55c4530b4..b4d6d481ef 100644 --- a/osu.Game/Screens/Ranking/ScorePanelTrackingContainer.cs +++ b/osu.Game/Screens/Ranking/ScorePanelTrackingContainer.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.Ranking if (InternalChildren.Count == 0) throw new InvalidOperationException("Score panel container is not attached."); - RemoveInternal(Panel); + RemoveInternal(Panel, false); } /// From d4a37725c43d6582b89c2eba96d5732ee265785a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Aug 2022 15:59:57 +0900 Subject: [PATCH 0765/2686] Adjust test --- .../Gameplay/TestSceneScoreProcessor.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs index 4123412ab6..fb9d841d99 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs @@ -124,14 +124,19 @@ namespace osu.Game.Tests.Gameplay Assert.That(score.Rank, Is.EqualTo(ScoreRank.F)); Assert.That(score.Passed, Is.False); - Assert.That(score.Statistics.Count(kvp => kvp.Value > 0), Is.EqualTo(7)); + Assert.That(score.Statistics.Sum(kvp => kvp.Value), Is.EqualTo(4)); + Assert.That(score.MaximumStatistics.Sum(kvp => kvp.Value), Is.EqualTo(8)); + Assert.That(score.Statistics[HitResult.Ok], Is.EqualTo(1)); - Assert.That(score.Statistics[HitResult.Miss], Is.EqualTo(1)); Assert.That(score.Statistics[HitResult.LargeTickHit], Is.EqualTo(1)); - Assert.That(score.Statistics[HitResult.LargeTickMiss], Is.EqualTo(1)); - Assert.That(score.Statistics[HitResult.SmallTickMiss], Is.EqualTo(2)); + Assert.That(score.Statistics[HitResult.SmallTickMiss], Is.EqualTo(1)); Assert.That(score.Statistics[HitResult.SmallBonus], Is.EqualTo(1)); - Assert.That(score.Statistics[HitResult.IgnoreMiss], Is.EqualTo(1)); + + Assert.That(score.MaximumStatistics[HitResult.Perfect], Is.EqualTo(2)); + Assert.That(score.MaximumStatistics[HitResult.LargeTickHit], Is.EqualTo(2)); + Assert.That(score.MaximumStatistics[HitResult.SmallTickHit], Is.EqualTo(2)); + Assert.That(score.MaximumStatistics[HitResult.SmallBonus], Is.EqualTo(1)); + Assert.That(score.MaximumStatistics[HitResult.LargeBonus], Is.EqualTo(1)); } private class TestJudgement : Judgement From be5c6232e82ea1fa9115fda102a6259ec5bb2444 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 16:29:19 +0900 Subject: [PATCH 0766/2686] Encapsulate `Track` inside a `FramedClock` to avoid mutating operations --- osu.Game/OsuGameBase.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 27ea3a76ae..0b158d5e08 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -381,7 +381,16 @@ namespace osu.Game Beatmap.BindValueChanged(onBeatmapChanged); } - private void onTrackChanged(WorkingBeatmap beatmap, TrackChangeDirection direction) => beatmapClock.ChangeSource(beatmap.Track); + private void onTrackChanged(WorkingBeatmap beatmap, TrackChangeDirection direction) + { + // FramedBeatmapClock uses a decoupled clock internally which will mutate the source if it is an `IAdjustableClock`. + // We don't want this for now, as the intention of beatmapClock is to be a read-only source for beat sync components. + // + // Encapsulating in a FramedClock will avoid any mutations. + var framedClock = new FramedClock(beatmap.Track); + + beatmapClock.ChangeSource(framedClock); + } protected virtual void InitialiseFonts() { From cf8fad045d94a010d96c7764fc66879ae2f22561 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 16:32:41 +0900 Subject: [PATCH 0767/2686] Update template rulesets to include baked value --- .../osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs | 3 +++ .../osu.Game.Rulesets.Pippidon/PippidonRuleset.cs | 3 +++ .../osu.Game.Rulesets.EmptyScrolling/EmptyScrollingRuleset.cs | 3 +++ .../osu.Game.Rulesets.Pippidon/PippidonRuleset.cs | 3 +++ 4 files changed, 12 insertions(+) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs index 00754c6346..1e88f87f09 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs @@ -77,5 +77,8 @@ namespace osu.Game.Rulesets.EmptyFreeform }; } } + + // Leave this line intact. It will bake the correct version into the ruleset on each build/release. + public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION; } } diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs index 0522840e9e..2f6ba0dda6 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs @@ -49,5 +49,8 @@ namespace osu.Game.Rulesets.Pippidon }; public override Drawable CreateIcon() => new PippidonRulesetIcon(this); + + // Leave this line intact. It will bake the correct version into the ruleset on each build/release. + public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION; } } diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingRuleset.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingRuleset.cs index c8f0c07724..a32586c414 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingRuleset.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingRuleset.cs @@ -54,5 +54,8 @@ namespace osu.Game.Rulesets.EmptyScrolling Text = ShortName[0].ToString(), Font = OsuFont.Default.With(size: 18), }; + + // Leave this line intact. It will bake the correct version into the ruleset on each build/release. + public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION; } } diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs index 89246373ee..bde530feb8 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRuleset.cs @@ -46,5 +46,8 @@ namespace osu.Game.Rulesets.Pippidon }; public override Drawable CreateIcon() => new PippidonRulesetIcon(this); + + // Leave this line intact. It will bake the correct version into the ruleset on each build/release. + public override string RulesetAPIVersionSupported => CURRENT_RULESET_API_VERSION; } } From 2dafa041a7e0a732159691f2107977555378e836 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 16:42:50 +0900 Subject: [PATCH 0768/2686] Account for offset being applied to editor clock time in `TestSceneEditorClock` --- osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs | 2 +- osu.Game/Beatmaps/FramedBeatmapClock.cs | 4 ++-- osu.Game/Screens/Edit/EditorClock.cs | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs index d598ebafa9..319f8ab9dc 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("seek near end", () => EditorClock.Seek(EditorClock.TrackLength - 250)); AddUntilStep("clock stops", () => !EditorClock.IsRunning); - AddUntilStep("clock stopped at end", () => EditorClock.CurrentTime, () => Is.EqualTo(EditorClock.TrackLength)); + AddUntilStep("clock stopped at end", () => EditorClock.CurrentTime - EditorClock.TotalAppliedOffset, () => Is.EqualTo(EditorClock.TrackLength)); AddStep("start clock again", () => EditorClock.Start()); AddAssert("clock looped to start", () => EditorClock.IsRunning && EditorClock.CurrentTime < 500); diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index c86f25640f..a4787a34e8 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -124,7 +124,7 @@ namespace osu.Game.Beatmaps finalClockSource.ProcessFrame(); } - private double totalAppliedOffset + public double TotalAppliedOffset { get { @@ -169,7 +169,7 @@ namespace osu.Game.Beatmaps public bool Seek(double position) { - bool success = decoupledClock.Seek(position - totalAppliedOffset); + bool success = decoupledClock.Seek(position - TotalAppliedOffset); finalClockSource.ProcessFrame(); return success; diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index 7a00a74530..6485f683ad 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -158,6 +158,8 @@ namespace osu.Game.Screens.Edit public double CurrentTime => underlyingClock.CurrentTime; + public double TotalAppliedOffset => underlyingClock.TotalAppliedOffset; + public void Reset() { ClearTransforms(); From 780121eeee359a433aba22dba057fcc2a55ef8d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 17:12:09 +0900 Subject: [PATCH 0769/2686] Add setting to toggle metronome in "Target" mod As mentioned in https://github.com/ppy/osu/discussions/20006#discussioncomment-3496732. --- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 82260db818..b48f0b4ccd 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -59,6 +59,9 @@ namespace osu.Game.Rulesets.Osu.Mods Value = null }; + [SettingSource("Metronome ticks", "Whether a metronome beat should play in the background")] + public BindableBool Metronome { get; } = new BindableBool(true); + #region Constants /// @@ -337,7 +340,8 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableRuleset.Overlays.Add(new MetronomeBeat(drawableRuleset.Beatmap.HitObjects.First().StartTime)); + if (Metronome.Value) + drawableRuleset.Overlays.Add(new MetronomeBeat(drawableRuleset.Beatmap.HitObjects.First().StartTime)); } #endregion From 07b502f69af5bc73b84ac0df689fec121edc39f7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 29 Aug 2022 17:58:57 +0900 Subject: [PATCH 0770/2686] Simplify OrderByTotalScore implementation --- osu.Game/Scoring/ScoreManager.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index fd600f4864..782590114f 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -57,12 +57,7 @@ namespace osu.Game.Scoring /// The array of s to reorder. /// The given ordered by decreasing total score. public IEnumerable OrderByTotalScore(IEnumerable scores) - { - return scores.Select((score, index) => (score, totalScore: GetTotalScore(score))) - .OrderByDescending(g => g.totalScore) - .ThenBy(g => g.score.OnlineID) - .Select(g => g.score); - } + => scores.OrderByDescending(s => GetTotalScore(s)).ThenBy(s => s.OnlineID); /// /// Retrieves a bindable that represents the total score of a . From 3eda284b03b5abcabe78b03d743078313f8f52a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 18:17:41 +0900 Subject: [PATCH 0771/2686] Always reprocess beatmaps after a user update request This covers the rare case where metadata may have changed server-side but not the beatmap itself. Tested with the provided user database to resolve the issue. Closes #19976. --- osu.Game/Beatmaps/BeatmapImporter.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index 0fa30cf5e7..292caa4397 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -55,7 +55,14 @@ namespace osu.Game.Beatmaps // If there were no changes, ensure we don't accidentally nuke ourselves. if (first.ID == original.ID) + { + first.PerformRead(s => + { + // Re-run processing even in this case. We might have outdated metadata. + ProcessBeatmap?.Invoke((s, false)); + }); return first; + } first.PerformWrite(updated => { From ad5ef529227d3687e8dd94573ea62b9e45b24f5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 19:02:01 +0900 Subject: [PATCH 0772/2686] Add test coverage of resuming after pause not skipping forward in time --- .../Visual/Gameplay/TestScenePause.cs | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index cad8c62233..61b59747ea 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -90,6 +90,9 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("player not playing", () => !Player.LocalUserPlaying.Value); resumeAndConfirm(); + + AddAssert("Resumed without seeking forward", () => Player.LastResumeTime, () => Is.LessThanOrEqualTo(Player.LastPauseTime)); + AddUntilStep("player playing", () => Player.LocalUserPlaying.Value); } @@ -378,7 +381,16 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("pause overlay " + (isShown ? "shown" : "hidden"), () => Player.PauseOverlayVisible == isShown); private void confirmClockRunning(bool isRunning) => - AddUntilStep("clock " + (isRunning ? "running" : "stopped"), () => Player.GameplayClockContainer.IsRunning == isRunning); + AddUntilStep("clock " + (isRunning ? "running" : "stopped"), () => + { + bool completed = Player.GameplayClockContainer.IsRunning == isRunning; + + if (completed) + { + } + + return completed; + }); protected override bool AllowFail => true; @@ -386,6 +398,9 @@ namespace osu.Game.Tests.Visual.Gameplay protected class PausePlayer : TestPlayer { + public double LastPauseTime { get; private set; } + public double LastResumeTime { get; private set; } + public bool FailOverlayVisible => FailOverlay.State.Value == Visibility.Visible; public bool PauseOverlayVisible => PauseOverlay.State.Value == Visibility.Visible; @@ -399,6 +414,23 @@ namespace osu.Game.Tests.Visual.Gameplay base.OnEntering(e); GameplayClockContainer.Stop(); } + + private bool? isRunning; + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + if (GameplayClockContainer.IsRunning != isRunning) + { + isRunning = GameplayClockContainer.IsRunning; + + if (isRunning.Value) + LastResumeTime = GameplayClockContainer.CurrentTime; + else + LastPauseTime = GameplayClockContainer.CurrentTime; + } + } } } } From 75531d2d62d3f7e9f7c2fd04dd5ba53d884bcefc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 19:51:16 +0900 Subject: [PATCH 0773/2686] Fix gameplay skipping forward during resume operation --- .../Screens/Play/GameplayClockContainer.cs | 17 +++++-- .../Play/MasterGameplayClockContainer.cs | 45 ++++++++++++++++++- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 1ae393d06a..ff82fb96ec 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -88,9 +88,7 @@ namespace osu.Game.Screens.Play ensureSourceClockSet(); - // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time - // This accounts for the clock source potentially taking time to enter a completely stopped state - Seek(GameplayClock.CurrentTime); + PrepareStart(); // The case which caused this to be added is FrameStabilityContainer, which manages its own current and elapsed time. // Because we generally update our own current time quicker than children can query it (via Start/Seek/Update), @@ -111,11 +109,22 @@ namespace osu.Game.Screens.Play }); } + /// + /// When is called, this will be run to give an opportunity to prepare the clock at the correct + /// start location. + /// + protected virtual void PrepareStart() + { + // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time + // This accounts for the clock source potentially taking time to enter a completely stopped state + Seek(GameplayClock.CurrentTime); + } + /// /// Seek to a specific time in gameplay. /// /// The destination time to seek to. - public void Seek(double time) + public virtual void Seek(double time) { Logger.Log($"{nameof(GameplayClockContainer)} seeking to {time}"); diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 238817ad05..f0f5daf64d 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -8,6 +8,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Logging; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -45,6 +46,17 @@ namespace osu.Game.Screens.Play private readonly List> nonGameplayAdjustments = new List>(); + /// + /// Stores the time at which the last call was triggered. + /// This is used to ensure we resume from that precise point in time, ignoring the proceeding frequency ramp. + /// + /// Optimally, we'd have gameplay ramp down with the frequency, but I believe this was intentionally disabled + /// to avoid fails occurring after the pause screen has been shown. + /// + /// In the future I want to change this. + /// + private double? actualStopTime; + public override IEnumerable NonGameplayAdjustments => nonGameplayAdjustments.Select(b => b.Value); /// @@ -86,10 +98,12 @@ namespace osu.Game.Screens.Play protected override void StopGameplayClock() { + actualStopTime = GameplayClock.CurrentTime; + if (IsLoaded) { // During normal operation, the source is stopped after performing a frequency ramp. - this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 0, 200, Easing.Out).OnComplete(_ => + this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 0, 2000, Easing.Out).OnComplete(_ => { if (IsPaused.Value) base.StopGameplayClock(); @@ -108,6 +122,25 @@ namespace osu.Game.Screens.Play } } + public override void Seek(double time) + { + // Safety in case the clock is seeked while stopped. + actualStopTime = null; + + base.Seek(time); + } + + protected override void PrepareStart() + { + if (actualStopTime != null) + { + Seek(actualStopTime.Value); + actualStopTime = null; + } + else + base.PrepareStart(); + } + protected override void StartGameplayClock() { addSourceClockAdjustments(); @@ -116,7 +149,7 @@ namespace osu.Game.Screens.Play if (IsLoaded) { - this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 1, 200, Easing.In); + this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 1, 2000, Easing.In); } else { @@ -158,6 +191,14 @@ namespace osu.Game.Screens.Play private bool speedAdjustmentsApplied; + protected override void Update() + { + base.Update(); + + if (GameplayClock.ExternalPauseFrequencyAdjust.Value < 1) + Logger.Log($"{GameplayClock.CurrentTime}"); + } + private void addSourceClockAdjustments() { if (speedAdjustmentsApplied) From 1bff540381f8c7aaea4d4be68fab8bc69ffafa03 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 29 Aug 2022 22:04:37 +0900 Subject: [PATCH 0774/2686] Remove debug changes --- .../Screens/Play/MasterGameplayClockContainer.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index f0f5daf64d..2f1ffa126f 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -8,7 +8,6 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Logging; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -103,7 +102,7 @@ namespace osu.Game.Screens.Play if (IsLoaded) { // During normal operation, the source is stopped after performing a frequency ramp. - this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 0, 2000, Easing.Out).OnComplete(_ => + this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 0, 200, Easing.Out).OnComplete(_ => { if (IsPaused.Value) base.StopGameplayClock(); @@ -149,7 +148,7 @@ namespace osu.Game.Screens.Play if (IsLoaded) { - this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 1, 2000, Easing.In); + this.TransformBindableTo(GameplayClock.ExternalPauseFrequencyAdjust, 1, 200, Easing.In); } else { @@ -191,14 +190,6 @@ namespace osu.Game.Screens.Play private bool speedAdjustmentsApplied; - protected override void Update() - { - base.Update(); - - if (GameplayClock.ExternalPauseFrequencyAdjust.Value < 1) - Logger.Log($"{GameplayClock.CurrentTime}"); - } - private void addSourceClockAdjustments() { if (speedAdjustmentsApplied) From a296c1ec81e6980927d8d8dc9338001758ae40e0 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 29 Aug 2022 16:05:35 +0200 Subject: [PATCH 0775/2686] remove call to changeHandler BeginChange --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 3d425afe9e..09f28b5b14 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -362,7 +362,6 @@ namespace osu.Game.Rulesets.Osu.Edit && Precision.AlmostBigger(1, Vector2.DistanceSquared(mergeableObjects[0].Position, mergeableObjects[1].Position)))) return; - ChangeHandler?.BeginChange(); EditorBeatmap.BeginChange(); // Have an initial slider object. @@ -440,7 +439,6 @@ namespace osu.Game.Rulesets.Osu.Edit SelectedItems.Add(mergedHitObject); EditorBeatmap.EndChange(); - ChangeHandler?.EndChange(); } protected override IEnumerable GetContextMenuItemsForSelection(IEnumerable> selection) From 27ad224f13591fb35309d4612b074dd47b22f6cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 01:21:44 +0900 Subject: [PATCH 0776/2686] Remove probably unnecessary `Seek` on start --- osu.Game/Screens/Play/GameplayClockContainer.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index ff82fb96ec..6de88d7ad0 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -115,9 +115,6 @@ namespace osu.Game.Screens.Play /// protected virtual void PrepareStart() { - // Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time - // This accounts for the clock source potentially taking time to enter a completely stopped state - Seek(GameplayClock.CurrentTime); } /// From 062a6fcc181da7e3ca597a9d6201491b16fc7898 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 01:21:53 +0900 Subject: [PATCH 0777/2686] Fix failing large offset test If we are going to continue to let the underlying clock process frames, there needs to be a bit of lenience to allow the backwards seek on resume (to play back over the freq ramp period). The test is meant to be ensuring we don't skip the full offset amount, so div10 seems pretty safe. --- osu.Game.Tests/Visual/Gameplay/TestScenePause.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index 61b59747ea..a6abdd7ee1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Gameplay Player.OnUpdate += _ => { double currentTime = Player.GameplayClockContainer.CurrentTime; - alwaysGoingForward &= currentTime >= lastTime; + alwaysGoingForward &= currentTime >= lastTime - 500; lastTime = currentTime; }; }); @@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.Gameplay resumeAndConfirm(); - AddAssert("time didn't go backwards", () => alwaysGoingForward); + AddAssert("time didn't go too far backwards", () => alwaysGoingForward); AddStep("reset offset", () => LocalConfig.SetValue(OsuSetting.AudioOffset, 0.0)); } From d50e9caa11a5930d49b39aa4ce18e11827730f7f Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 29 Aug 2022 18:58:29 +0200 Subject: [PATCH 0778/2686] Moved guards to separate canMerge method --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 8b67c0dcc9..dd9d1614b8 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -354,12 +354,14 @@ namespace osu.Game.Rulesets.Osu.Edit .OrderBy(h => h.StartTime) .ToArray(); + private bool canMerge(IReadOnlyList objects) => + objects.Count > 1 && (objects.Any(h => h is Slider) || Precision.DefinitelyBigger(Vector2.DistanceSquared(objects[0].Position, objects[1].Position), 1)); + private void mergeSelection() { var mergeableObjects = selectedMergeableObjects; - if (mergeableObjects.Length < 2 || (mergeableObjects.All(h => h is not Slider) - && Precision.AlmostBigger(1, Vector2.DistanceSquared(mergeableObjects[0].Position, mergeableObjects[1].Position)))) + if (!canMerge(mergeableObjects)) return; ChangeHandler?.BeginChange(); @@ -446,9 +448,7 @@ namespace osu.Game.Rulesets.Osu.Edit foreach (var item in base.GetContextMenuItemsForSelection(selection)) yield return item; - var mergeableObjects = selectedMergeableObjects; - if (mergeableObjects.Length > 1 && (mergeableObjects.Any(h => h is Slider) - || Precision.DefinitelyBigger(Vector2.DistanceSquared(mergeableObjects[0].Position, mergeableObjects[1].Position), 1))) + if (canMerge(selectedMergeableObjects)) yield return new OsuMenuItem("Merge selection", MenuItemType.Destructive, mergeSelection); } } From 2e5770be4e14623f61327063f62019112d15e316 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 02:51:42 +0900 Subject: [PATCH 0779/2686] Move helper method to bottom of class --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index dd9d1614b8..048fd4ed7e 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -354,9 +354,6 @@ namespace osu.Game.Rulesets.Osu.Edit .OrderBy(h => h.StartTime) .ToArray(); - private bool canMerge(IReadOnlyList objects) => - objects.Count > 1 && (objects.Any(h => h is Slider) || Precision.DefinitelyBigger(Vector2.DistanceSquared(objects[0].Position, objects[1].Position), 1)); - private void mergeSelection() { var mergeableObjects = selectedMergeableObjects; @@ -451,5 +448,10 @@ namespace osu.Game.Rulesets.Osu.Edit if (canMerge(selectedMergeableObjects)) yield return new OsuMenuItem("Merge selection", MenuItemType.Destructive, mergeSelection); } + + private bool canMerge(IReadOnlyList objects) => + objects.Count > 1 + && (objects.Any(h => h is Slider) + || Precision.DefinitelyBigger(Vector2.DistanceSquared(objects[0].Position, objects[1].Position), 1)); } } From 7faeed88b053e6b06f3de90fdb74b89ca1793215 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 29 Aug 2022 22:08:43 +0300 Subject: [PATCH 0780/2686] Add ability to override width of value area --- osu.Game/Overlays/Mods/ModsEffectDisplay.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs index a7c5ec9ef9..4b97614ade 100644 --- a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs +++ b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs @@ -20,7 +20,6 @@ namespace osu.Game.Overlays.Mods public abstract class ModsEffectDisplay : Container { public const float HEIGHT = 42; - private const float value_area_width = 56; private const float transition_duration = 200; private readonly Box contentBackground; @@ -38,6 +37,8 @@ namespace osu.Game.Overlays.Mods /// protected abstract LocalisableString Label { get; } + protected virtual float ValueAreaWidth => 56; + protected override Container Content => content; protected ModsEffectDisplay() @@ -59,7 +60,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.Y, - Width = value_area_width + ModSelectPanel.CORNER_RADIUS + Width = ValueAreaWidth + ModSelectPanel.CORNER_RADIUS }, new GridContainer { @@ -68,7 +69,7 @@ namespace osu.Game.Overlays.Mods ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Absolute, value_area_width) + new Dimension(GridSizeMode.Absolute, ValueAreaWidth) }, Content = new[] { From 5343c2645253407a218ee7916dfe11cd347ed4e5 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 29 Aug 2022 22:48:27 +0300 Subject: [PATCH 0781/2686] Control colour via `Current` bindable --- osu.Game/Overlays/Mods/ModsEffectDisplay.cs | 92 +++++++++++++++++---- 1 file changed, 74 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs index 4b97614ade..2ff6bf043b 100644 --- a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs +++ b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs @@ -1,10 +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.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -13,11 +16,10 @@ using osuTK; namespace osu.Game.Overlays.Mods { - /// /// /// Base class for displays of mods effects. /// - public abstract class ModsEffectDisplay : Container + public abstract class ModsEffectDisplay : Container, IHasCurrentValue { public const float HEIGHT = 42; private const float transition_duration = 200; @@ -26,6 +28,14 @@ namespace osu.Game.Overlays.Mods private readonly Box labelBackground; private readonly Container content; + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } + + private readonly BindableWithCurrent current = new BindableWithCurrent(); + [Resolved] private OsuColour colours { get; set; } = null!; @@ -37,6 +47,13 @@ namespace osu.Game.Overlays.Mods /// protected abstract LocalisableString Label { get; } + /// + /// Calculates, does current value increase difficulty or decrease it. + /// + /// Value to calculate for. Will arrive from bindable once it changes. + /// Effect of the value. + protected abstract ModEffect CalculateEffect(TValue value); + protected virtual float ValueAreaWidth => 56; protected override Container Content => content; @@ -118,28 +135,67 @@ namespace osu.Game.Overlays.Mods labelBackground.Colour = colourProvider.Background4; } + protected override void LoadComplete() + { + Current.BindValueChanged(e => + { + var effect = CalculateEffect(e.NewValue); + setColours(effect); + }, true); + } + /// /// Fades colours of text and its background according to displayed value. /// - /// Difference between actual value and default value. - /// Negative leads to green color, positive to red. Can be obtained via CompareTo(defaultValue). - protected void SetColours(int difference) + /// Effect of the value. + private void setColours(ModEffect effect) { - if (difference == 0) + switch (effect) { - contentBackground.FadeColour(colourProvider.Background3, transition_duration, Easing.OutQuint); - content.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); - } - else if (difference < 0) - { - contentBackground.FadeColour(colours.ForModType(ModType.DifficultyReduction), transition_duration, Easing.OutQuint); - content.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint); - } - else - { - contentBackground.FadeColour(colours.ForModType(ModType.DifficultyIncrease), transition_duration, Easing.OutQuint); - content.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint); + case ModEffect.NotChanged: + contentBackground.FadeColour(colourProvider.Background3, transition_duration, Easing.OutQuint); + content.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); + break; + + case ModEffect.DifficultyReduction: + contentBackground.FadeColour(colours.ForModType(ModType.DifficultyReduction), transition_duration, Easing.OutQuint); + content.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint); + break; + + case ModEffect.DifficultyIncrease: + contentBackground.FadeColour(colours.ForModType(ModType.DifficultyIncrease), transition_duration, Easing.OutQuint); + content.FadeColour(colourProvider.Background5, transition_duration, Easing.OutQuint); + break; + + default: + throw new ArgumentOutOfRangeException(nameof(effect)); } } + + #region Quick implementations for CalculateEffect + + /// + /// Converts signed integer into . Negative values are counted as difficulty reduction, positive as increase. + /// + /// Value to convert. Can be obtained from CompareTo. + /// Effect. + protected ModEffect CalculateForSign(int comparison) + { + if (comparison == 0) + return ModEffect.NotChanged; + if (comparison < 0) + return ModEffect.DifficultyReduction; + + return ModEffect.DifficultyIncrease; + } + + #endregion + + protected enum ModEffect + { + NotChanged, + DifficultyReduction, + DifficultyIncrease + } } } From 545e0bbcef580ab282235ba69585996a16bd6020 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 29 Aug 2022 22:48:45 +0300 Subject: [PATCH 0782/2686] Adjust inheritors and test --- .../TestSceneModsEffectDisplay.cs | 25 ++++++++----------- .../Mods/DifficultyMultiplierDisplay.cs | 19 ++++---------- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 4 +-- 3 files changed, 17 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs index dd663ad59d..ec50a07998 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs @@ -44,32 +44,24 @@ namespace osu.Game.Tests.Visual.UserInterface background = boxes.First(); }); - AddStep("set value to default", () => testDisplay.Value = 50); + AddStep("set value to default", () => testDisplay.Current.Value = 50); AddUntilStep("colours are correct", () => testDisplay.Container.Colour == Color4.White && background.Colour == colourProvider.Background3); - AddStep("set value to less", () => testDisplay.Value = 40); + AddStep("set value to less", () => testDisplay.Current.Value = 40); AddUntilStep("colours are correct", () => testDisplay.Container.Colour == colourProvider.Background5 && background.Colour == colours.ForModType(ModType.DifficultyReduction)); - AddStep("set value to bigger", () => testDisplay.Value = 60); + AddStep("set value to bigger", () => testDisplay.Current.Value = 60); AddUntilStep("colours are correct", () => testDisplay.Container.Colour == colourProvider.Background5 && background.Colour == colours.ForModType(ModType.DifficultyIncrease)); } - private class TestDisplay : ModsEffectDisplay + private class TestDisplay : ModsEffectDisplay { private readonly OsuSpriteText text; public Container Container => Content; protected override LocalisableString Label => "Test display"; - - public int Value - { - set - { - text.Text = value.ToString(); - SetColours(value.CompareTo(50)); - } - } + protected override ModEffect CalculateEffect(int value) => CalculateForSign(value.CompareTo(50)); public TestDisplay() { @@ -80,8 +72,11 @@ namespace osu.Game.Tests.Visual.UserInterface }); } - [BackgroundDependencyLoader] - private void load() => SetColours(0); + protected override void LoadComplete() + { + base.LoadComplete(); + Current.BindValueChanged(e => text.Text = e.NewValue.ToString(), true); + } } } } diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index e5daa2de63..843310249e 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -3,12 +3,10 @@ #nullable disable -using osu.Framework.Bindables; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -18,22 +16,17 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Mods { - public sealed class DifficultyMultiplierDisplay : ModsEffectDisplay, IHasCurrentValue + public sealed class DifficultyMultiplierDisplay : ModsEffectDisplay { protected override LocalisableString Label => DifficultyMultiplierDisplayStrings.DifficultyMultiplier; - - public Bindable Current - { - get => current.Current; - set => current.Current = value; - } - - private readonly BindableNumberWithCurrent current = new BindableNumberWithCurrent(1); + protected override ModEffect CalculateEffect(double value) => CalculateForSign(value.CompareTo(1d)); private readonly MultiplierCounter multiplierCounter; public DifficultyMultiplierDisplay() { + Current.Default = 1d; + Current.Value = 1d; Add(new FillFlowContainer { AutoSizeAxes = Axes.Both, @@ -63,11 +56,9 @@ namespace osu.Game.Overlays.Mods { base.LoadComplete(); - current.BindValueChanged(e => SetColours(e.NewValue.CompareTo(current.Default)), true); - // required to prevent the counter initially rolling up from 0 to 1 // due to `Current.Value` having a nonstandard default value of 1. - multiplierCounter.SetCountWithoutRolling(current.Value); + multiplierCounter.SetCountWithoutRolling(Current.Value); } private class MultiplierCounter : RollingCounter diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index ccc075b190..80f18eafeb 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -153,7 +153,7 @@ namespace osu.Game.Overlays.Mods { Padding = new MarginPadding { - Top = (ShowTotalMultiplier ? ModsEffectDisplay.HEIGHT : 0) + PADDING, + Top = (ShowTotalMultiplier ? ModsEffectDisplay.HEIGHT : 0) + PADDING, Bottom = PADDING }, RelativeSizeAxes = Axes.Both, @@ -191,7 +191,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopRight, Origin = Anchor.TopRight, AutoSizeAxes = Axes.X, - Height = ModsEffectDisplay.HEIGHT, + Height = ModsEffectDisplay.HEIGHT, Margin = new MarginPadding { Horizontal = 100 }, Child = multiplierDisplay = new DifficultyMultiplierDisplay { From d20e7da2d98365e6e2e75fc239132069964d5344 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Mon, 29 Aug 2022 21:03:22 +0100 Subject: [PATCH 0783/2686] Changed epsilon --- .../TestSceneUprightAspectMaintainingContainer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs index 8b87e4030e..f81f8e8d85 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs @@ -10,6 +10,7 @@ using NUnit.Framework; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics; +using osu.Framework.Utils; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics; @@ -188,7 +189,7 @@ namespace osu.Game.Tests.Visual.UserInterface return false; // Aspect ratio check - if (!isNearlyZero(childScale.X - childScale.Y, 0.0001f)) + if (!isNearlyZero(childScale.X - childScale.Y)) return false; // ScalingMode check @@ -237,7 +238,7 @@ namespace osu.Game.Tests.Visual.UserInterface return true; } - private bool isNearlyZero(float f, float epsilon = 0.00001f) + private bool isNearlyZero(float f, float epsilon = Precision.FLOAT_EPSILON) { return f < epsilon; } From 43f2ba659697370d5e885d2adf784852447f1535 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Mon, 29 Aug 2022 22:00:33 +0100 Subject: [PATCH 0784/2686] Added test scene --- .../TestSceneGrowToFitContent.cs | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneGrowToFitContent.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneGrowToFitContent.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneGrowToFitContent.cs new file mode 100644 index 0000000000..bcff992f9d --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneGrowToFitContent.cs @@ -0,0 +1,175 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics; +using System.Linq; +using osuTK; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneGrowToFitContent : OsuGridTestScene + { + private readonly List parentContainers = new List(); + private readonly List childContainers = new List(); + private readonly List texts = new List(); + + public TestSceneGrowToFitContent() + : base(1, 2) + { + for (int i = 0; i < 2; i++) + { + OsuSpriteText text; + UprightAspectMaintainingContainer childContainer; + Container parentContainer = new Container + { + Origin = Anchor.BottomRight, + Anchor = Anchor.BottomCentre, + AutoSizeAxes = Axes.Both, + Rotation = 45, + Y = -200, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Colour4.Red, + }, + childContainer = new UprightAspectMaintainingContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Colour4.Blue, + }, + text = new OsuSpriteText + { + Text = "Text", + Font = OsuFont.GetFont(Typeface.Venera, weight: FontWeight.Bold, size: 40), + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + }, + } + }, + } + }; + + Container cellInfo = new Container + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Margin = new MarginPadding + { + Top = 100, + }, + Child = new OsuSpriteText + { + Text = (i == 0) ? "GrowToFitContent == true" : "GrowToFitContent == false", + Font = OsuFont.GetFont(Typeface.Inter, weight: FontWeight.Bold, size: 40), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + }, + }; + + parentContainers.Add(parentContainer); + childContainers.Add(childContainer); + texts.Add(text); + Cell(i).Add(cellInfo); + Cell(i).Add(parentContainer); + } + } + + [Test] + public void TestResizeText() + { + AddStep("reset...", () => + { + childContainers[0].GrowToFitContent = false; + childContainers[1].GrowToFitContent = false; + }); + + AddStep("setup...", () => + { + childContainers[0].GrowToFitContent = true; + childContainers[1].GrowToFitContent = false; + }); + + for (int i = 0; i < 10; i++) + { + AddStep("Add Character", () => + { + foreach (int j in Enumerable.Range(0, parentContainers.Count)) + { + texts[j].Text += "."; + } + }); + } + + for (int i = 0; i < 10; i++) + { + AddStep("Remove Character", () => + { + foreach (int j in Enumerable.Range(0, parentContainers.Count)) + { + string text = texts[j].Text.ToString(); + texts[j].Text = text.Remove(text.Length - 1, 1); + } + }); + } + } + + [Test] + public void TestScaleText() + { + AddStep("reset...", () => + { + childContainers[0].GrowToFitContent = false; + childContainers[1].GrowToFitContent = false; + }); + + AddStep("setup...", () => + { + childContainers[0].GrowToFitContent = true; + childContainers[1].GrowToFitContent = false; + }); + + for (int i = 0; i < 1; i++) + { + AddStep("Big text", scaleUp); + + AddWaitStep("wait...", 5); + + AddStep("Small text", scaleDown); + } + } + + private void scaleUp() + { + foreach (int j in Enumerable.Range(0, parentContainers.Count)) + { + texts[j].ScaleTo(new Vector2(2, 2), 1000); + } + } + + private void scaleDown() + { + foreach (int j in Enumerable.Range(0, parentContainers.Count)) + { + texts[j].ScaleTo(new Vector2(1, 1), 1000); + } + } + } +} From cda7faecf798e9ad9242c44b0edcf544fb5d1801 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Mon, 29 Aug 2022 22:01:24 +0100 Subject: [PATCH 0785/2686] Added GrowToFitContent Parameter. --- .../UprightAspectMaintainingContainer.cs | 86 ++++++++++++++++--- 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs index 64b9eb409b..8efc29c83c 100644 --- a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs +++ b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs @@ -24,6 +24,27 @@ namespace osu.Game.Graphics.Containers /// public ScaleMode Scaling { get; set; } = ScaleMode.Vertical; + /// + /// If this is true, all wrapper containers will be set to grow with their content + /// and not shrink back, this is used to fix the position of children that change + /// in size when using AutoSizeAxes. + /// + public bool GrowToFitContent + { + get => growToFitContent; + set + { + if (growToFitContent != value) + { + foreach (GrowToFitContainer c in Children) + c.GrowToFitContentUpdated = true; + growToFitContent = value; + } + } + } + + private bool growToFitContent = true; + private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawInfo, InvalidationSource.Parent); public UprightAspectMaintainingContainer() @@ -44,10 +65,11 @@ namespace osu.Game.Graphics.Containers public override void Add(Drawable drawable) { - base.Add(new GrowToFitContainer - { - Child = drawable - }); + var wrapper = new GrowToFitContainer(); + wrapper.Wrap(drawable); + wrapper.AutoSizeAxes = Axes.None; + drawable.Origin = drawable.Anchor = Anchor.Centre; + base.Add(wrapper); } /// @@ -58,7 +80,7 @@ namespace osu.Game.Graphics.Containers // Decomposes the inverse of the parent DrawInfo.Matrix into rotation, shear and scale. var parentMatrix = Parent.DrawInfo.Matrix; - // Remove Translation. + // Remove Translation.> parentMatrix.M31 = 0.0f; parentMatrix.M32 = 0.0f; @@ -108,17 +130,55 @@ namespace osu.Game.Graphics.Containers public class GrowToFitContainer : Container { + private readonly LayoutValue layout = new LayoutValue(Invalidation.RequiredParentSizeToFit, InvalidationSource.Child); + + private Vector2 maxChildSize; + + public bool GrowToFitContentUpdated { get; set; } + + public GrowToFitContainer() + { + AddLayout(layout); + } + protected override void Update() { - if ((Child.RelativeSizeAxes & Axes.X) != 0) - RelativeSizeAxes |= Axes.X; - else - Width = Math.Max(Child.Width, Width); + UprightAspectMaintainingContainer parent = (UprightAspectMaintainingContainer)Parent; - if ((Child.RelativeSizeAxes & Axes.Y) != 0) - RelativeSizeAxes |= Axes.Y; - else - Height = Math.Max(Child.Height, Height); + if (!layout.IsValid || GrowToFitContentUpdated) + { + if ((Child.RelativeSizeAxes & Axes.X) != 0) + RelativeSizeAxes |= Axes.X; + else + { + if (parent.GrowToFitContent) + Width = Math.Max(Child.Width * Child.Scale.X, maxChildSize.X); + else + Width = Child.Width * Child.Scale.X; + } + + if ((Child.RelativeSizeAxes & Axes.Y) != 0) + RelativeSizeAxes |= Axes.Y; + else + { + if (parent.GrowToFitContent) + Height = Math.Max(Child.Height * Child.Scale.Y, maxChildSize.Y); + else + Height = Child.Height * Child.Scale.Y; + } + + // reset max_child_size or update it + if (!parent.GrowToFitContent) + maxChildSize = Child.Size; + else + { + maxChildSize.X = MathF.Max(maxChildSize.X, Child.Size.X); + maxChildSize.Y = MathF.Max(maxChildSize.Y, Child.Size.Y); + } + + GrowToFitContentUpdated = false; + layout.Validate(); + } } } } From 44916c51d73580ab42c5a18f33705da9ffae9a16 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 30 Aug 2022 00:18:55 +0200 Subject: [PATCH 0786/2686] Updated canMerge check to be totally accurate --- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 048fd4ed7e..ac5fad54a4 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -452,6 +452,6 @@ namespace osu.Game.Rulesets.Osu.Edit private bool canMerge(IReadOnlyList objects) => objects.Count > 1 && (objects.Any(h => h is Slider) - || Precision.DefinitelyBigger(Vector2.DistanceSquared(objects[0].Position, objects[1].Position), 1)); + || objects.Zip(objects.Skip(1), (h1, h2) => Precision.DefinitelyBigger(Vector2.DistanceSquared(h1.Position, h2.Position), 1)).Any(x => x)); } } From 5d41fdfc890acd4d9dc1d45e3e96f890ec12f1b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 15:05:21 +0900 Subject: [PATCH 0787/2686] Remove unnecessary usage of `DrawableAudioMixer` in `ScorePanel` --- osu.Game/Screens/Ranking/ScorePanel.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Ranking/ScorePanel.cs b/osu.Game/Screens/Ranking/ScorePanel.cs index 0bcfa0da1f..cb777de144 100644 --- a/osu.Game/Screens/Ranking/ScorePanel.cs +++ b/osu.Game/Screens/Ranking/ScorePanel.cs @@ -99,7 +99,7 @@ namespace osu.Game.Screens.Ranking [Resolved] private OsuGameBase game { get; set; } - private DrawableAudioMixer mixer; + private AudioContainer audioContent; private bool displayWithFlair; @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Ranking // Adding a manual offset here allows the expanded version to take on an "acceptable" vertical centre when at 100% UI scale. const float vertical_fudge = 20; - InternalChild = mixer = new DrawableAudioMixer + InternalChild = audioContent = new AudioContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -225,7 +225,7 @@ namespace osu.Game.Screens.Ranking protected override void Update() { base.Update(); - mixer.Balance.Value = (ScreenSpaceDrawQuad.Centre.X / game.ScreenSpaceDrawQuad.Width) * 2 - 1; + audioContent.Balance.Value = (ScreenSpaceDrawQuad.Centre.X / game.ScreenSpaceDrawQuad.Width) * 2 - 1; } private void playAppearSample() @@ -274,7 +274,7 @@ namespace osu.Game.Screens.Ranking break; } - mixer.ResizeTo(Size, RESIZE_DURATION, Easing.OutQuint); + audioContent.ResizeTo(Size, RESIZE_DURATION, Easing.OutQuint); bool topLayerExpanded = topLayerContainer.Y < 0; From 5202c15a0e3edc10e3667805c0db15fe059e441b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 30 Aug 2022 15:11:39 +0900 Subject: [PATCH 0788/2686] Populate MaximumStatistics for test scores --- osu.Game.Tests/Resources/TestResources.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index 6bce03869d..9c85f61330 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -194,8 +194,16 @@ namespace osu.Game.Tests.Resources [HitResult.LargeTickHit] = 100, [HitResult.LargeTickMiss] = 50, [HitResult.SmallBonus] = 10, - [HitResult.SmallBonus] = 50 + [HitResult.LargeBonus] = 50 }, + MaximumStatistics = new Dictionary + { + [HitResult.Perfect] = 971, + [HitResult.SmallTickHit] = 75, + [HitResult.LargeTickHit] = 150, + [HitResult.SmallBonus] = 10, + [HitResult.LargeBonus] = 50, + } }; private class TestModHardRock : ModHardRock From 8b3742188fcb9c4c80c7515546091b2ec714ec3e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 30 Aug 2022 15:42:33 +0900 Subject: [PATCH 0789/2686] Fix test by also clearing out maximum statistics --- .../Visual/Playlists/TestScenePlaylistsResultsScreen.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index 8a04cd96fe..26fa740159 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -61,6 +61,7 @@ namespace osu.Game.Tests.Visual.Playlists userScore = TestResources.CreateTestScoreInfo(); userScore.TotalScore = 0; userScore.Statistics = new Dictionary(); + userScore.MaximumStatistics = new Dictionary(); bindHandler(); From 799c015bff82460ffb1c1392610d47984281a443 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 30 Aug 2022 15:50:19 +0900 Subject: [PATCH 0790/2686] Add LegacyTotalScore to SoloScoreInfo --- osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 16aa800cb0..a8cedabd48 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -77,6 +77,12 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("maximum_statistics")] public Dictionary MaximumStatistics { get; set; } = new Dictionary(); + /// + /// Used to preserve the total score for legacy scores. + /// + [JsonProperty("legacy_total_score")] + public int? LegacyTotalScore { get; set; } + #region osu-web API additions (not stored to database). [JsonProperty("id")] From b8fda1a16f3668e244086ba5958f9b818c95c02b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 15:51:46 +0900 Subject: [PATCH 0791/2686] Apply NRT to notification classes and tidy things up a bit. --- .../TestSceneNotificationOverlay.cs | 10 +++--- .../Database/ImportProgressNotification.cs | 2 -- osu.Game/Overlays/NotificationOverlay.cs | 12 ++----- .../Overlays/Notifications/Notification.cs | 8 ++--- .../Notifications/NotificationSection.cs | 14 ++++---- .../Notifications/ProgressNotification.cs | 32 +++++++++---------- .../Notifications/SimpleNotification.cs | 2 -- 7 files changed, 32 insertions(+), 48 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index cf069a9e34..c196b204b9 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -19,11 +17,11 @@ namespace osu.Game.Tests.Visual.UserInterface [TestFixture] public class TestSceneNotificationOverlay : OsuTestScene { - private NotificationOverlay notificationOverlay; + private NotificationOverlay notificationOverlay = null!; private readonly List progressingNotifications = new List(); - private SpriteText displayedCount; + private SpriteText displayedCount = null!; [SetUp] public void SetUp() => Schedule(() => @@ -46,7 +44,7 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestCompleteProgress() { - ProgressNotification notification = null; + ProgressNotification notification = null!; AddStep("add progress notification", () => { notification = new ProgressNotification @@ -64,7 +62,7 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestCancelProgress() { - ProgressNotification notification = null; + ProgressNotification notification = null!; AddStep("add progress notification", () => { notification = new ProgressNotification diff --git a/osu.Game/Database/ImportProgressNotification.cs b/osu.Game/Database/ImportProgressNotification.cs index 46f9936bc2..aaee3e117f 100644 --- a/osu.Game/Database/ImportProgressNotification.cs +++ b/osu.Game/Database/ImportProgressNotification.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. -#nullable disable - using osu.Game.Overlays.Notifications; namespace osu.Game.Database diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 281077bcf6..cbcc7b6886 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -64,14 +64,8 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.X, Children = new[] { - new NotificationSection(AccountsStrings.NotificationsTitle, "Clear All") - { - AcceptTypes = new[] { typeof(SimpleNotification) } - }, - new NotificationSection(@"Running Tasks", @"Cancel All") - { - AcceptTypes = new[] { typeof(ProgressNotification) } - } + new NotificationSection(AccountsStrings.NotificationsTitle, new[] { typeof(SimpleNotification) }, "Clear All"), + new NotificationSection(@"Running Tasks", new[] { typeof(ProgressNotification) }, @"Cancel All"), } } } @@ -133,7 +127,7 @@ namespace osu.Game.Overlays var ourType = notification.GetType(); - var section = sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => accept.IsAssignableFrom(ourType))); + var section = sections.Children.FirstOrDefault(s => s.AcceptedNotificationTypes.Any(accept => accept.IsAssignableFrom(ourType))); section?.Add(notification, notification.DisplayOnTop ? -runningDepth : runningDepth); if (notification.IsImportant) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 64bf3693c8..fbb906e637 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -26,7 +24,7 @@ namespace osu.Game.Overlays.Notifications /// /// User requested close. /// - public event Action Closed; + public event Action? Closed; public abstract LocalisableString Text { get; set; } @@ -38,7 +36,7 @@ namespace osu.Game.Overlays.Notifications /// /// Run on user activating the notification. Return true to close. /// - public Func Activated; + public Func? Activated; /// /// Should we show at the top of our section on display? @@ -212,7 +210,7 @@ namespace osu.Game.Overlays.Notifications public class NotificationLight : Container { private bool pulsate; - private Container pulsateLayer; + private Container pulsateLayer = null!; public bool Pulsate { diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index b7e21822fa..d2e18a0cee 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -21,9 +19,9 @@ namespace osu.Game.Overlays.Notifications { public class NotificationSection : AlwaysUpdateFillFlowContainer { - private OsuSpriteText countDrawable; + private OsuSpriteText countDrawable = null!; - private FlowContainer notifications; + private FlowContainer notifications = null!; public int DisplayedCount => notifications.Count(n => !n.WasClosed); public int UnreadCount => notifications.Count(n => !n.WasClosed && !n.Read); @@ -33,14 +31,16 @@ namespace osu.Game.Overlays.Notifications notifications.Insert((int)position, notification); } - public IEnumerable AcceptTypes; + public IEnumerable AcceptedNotificationTypes { get; } private readonly string clearButtonText; private readonly LocalisableString titleText; - public NotificationSection(LocalisableString title, string clearButtonText) + public NotificationSection(LocalisableString title, IEnumerable acceptedNotificationTypes, string clearButtonText) { + AcceptedNotificationTypes = acceptedNotificationTypes.ToArray(); + this.clearButtonText = clearButtonText.ToUpperInvariant(); titleText = title; } @@ -159,7 +159,7 @@ namespace osu.Game.Overlays.Notifications public void MarkAllRead() { - notifications?.Children.ForEach(n => n.Read = true); + notifications.Children.ForEach(n => n.Read = true); } } diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 719e77db83..15346930a3 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.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. -#nullable disable - using System; using System.Threading; using osu.Framework.Allocation; @@ -25,6 +23,18 @@ namespace osu.Game.Overlays.Notifications { private const float loading_spinner_size = 22; + public Func? CancelRequested { get; set; } + + /// + /// The function to post completion notifications back to. + /// + public Action? CompletionTarget { get; set; } + + /// + /// An action to complete when the completion notification is clicked. Return true to close. + /// + public Func? CompletionClickAction { get; set; } + private LocalisableString text; public override LocalisableString Text @@ -142,7 +152,7 @@ namespace osu.Game.Overlays.Notifications Text = CompletionText }; - protected virtual void Completed() + protected void Completed() { CompletionTarget?.Invoke(CreateCompletionNotification()); base.Close(); @@ -155,8 +165,8 @@ namespace osu.Game.Overlays.Notifications private Color4 colourActive; private Color4 colourCancelled; - private Box iconBackground; - private LoadingSpinner loadingSpinner; + private Box iconBackground = null!; + private LoadingSpinner loadingSpinner = null!; private readonly TextFlowContainer textDrawable; @@ -222,18 +232,6 @@ namespace osu.Game.Overlays.Notifications } } - public Func CancelRequested { get; set; } - - /// - /// The function to post completion notifications back to. - /// - public Action CompletionTarget { get; set; } - - /// - /// An action to complete when the completion notification is clicked. Return true to close. - /// - public Func CompletionClickAction; - private class ProgressBar : Container { private readonly Box box; diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index fc594902cf..b9a1cc6d90 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; From 1484ae19f0a7a3f4a069bf8628dd5c8805d923db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 17:33:08 +0900 Subject: [PATCH 0792/2686] Initial design update pass --- osu.Game/Overlays/NotificationOverlay.cs | 6 +- .../Overlays/Notifications/Notification.cs | 147 ++++++++++-------- .../Notifications/ProgressNotification.cs | 3 +- .../Notifications/SimpleNotification.cs | 32 ++-- 4 files changed, 100 insertions(+), 88 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index cbcc7b6886..bd483e073c 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Threading; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Overlays.Notifications; using osu.Game.Resources.Localisation.Web; @@ -35,6 +34,9 @@ namespace osu.Game.Overlays [Resolved] private AudioManager audio { get; set; } = null!; + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + private readonly IBindable firstRunSetupVisibility = new Bindable(); [BackgroundDependencyLoader] @@ -49,7 +51,7 @@ namespace osu.Game.Overlays new Box { RelativeSizeAxes = Axes.Both, - Colour = OsuColour.Gray(0.05f), + Colour = colourProvider.Background4, }, new OsuScrollContainer { diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index fbb906e637..5cd0db628d 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osuTK; using osuTK.Graphics; @@ -46,8 +45,9 @@ namespace osu.Game.Overlays.Notifications public virtual string PopInSampleName => "UI/notification-pop-in"; protected NotificationLight Light; - private readonly CloseButton closeButton; + protected Container IconContent; + private readonly Container content; protected override Container Content => content; @@ -61,7 +61,7 @@ namespace osu.Game.Overlays.Notifications RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - AddRangeInternal(new Drawable[] + InternalChildren = new Drawable[] { Light = new NotificationLight { @@ -79,64 +79,68 @@ namespace osu.Game.Overlays.Notifications AutoSizeEasing = Easing.OutQuint, Children = new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - }, - new Container + new GridContainer { RelativeSizeAxes = Axes.X, - Padding = new MarginPadding(5), AutoSizeAxes = Axes.Y, - Children = new Drawable[] + RowDimensions = new[] { - IconContent = new Container - { - Size = new Vector2(40), - Masking = true, - CornerRadius = 5, - }, - content = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding - { - Left = 45, - Right = 30 - }, - } - } - }, - closeButton = new CloseButton - { - Alpha = 0, - Action = Close, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Margin = new MarginPadding - { - Right = 5 + new Dimension(GridSizeMode.AutoSize, minSize: 60) }, - } + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] + { + IconContent = new Container + { + Width = 40, + RelativeSizeAxes = Axes.Y, + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(10), + Children = new Drawable[] + { + content = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, + } + }, + new CloseButton + { + Action = Close, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + } + } + }, + }, } } + }; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + NotificationContent.Add(new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background3, + Depth = float.MaxValue }); } - protected override bool OnHover(HoverEvent e) - { - closeButton.FadeIn(75); - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - closeButton.FadeOut(75); - base.OnHoverLost(e); - } - protected override bool OnClick(ClickEvent e) { if (Activated?.Invoke() ?? true) @@ -150,6 +154,7 @@ namespace osu.Game.Overlays.Notifications base.LoadComplete(); this.FadeInFromZero(200); + NotificationContent.MoveToX(DrawSize.X); NotificationContent.MoveToX(0, 500, Easing.OutQuint); } @@ -169,40 +174,48 @@ namespace osu.Game.Overlays.Notifications private class CloseButton : OsuClickableContainer { - private Color4 hoverColour; + private SpriteIcon icon = null!; + private Box background = null!; - public CloseButton() + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load() { - Colour = OsuColour.Gray(0.2f); - AutoSizeAxes = Axes.Both; + RelativeSizeAxes = Axes.Y; + Width = 24; - Children = new[] + Children = new Drawable[] { - new SpriteIcon + background = new Box + { + Colour = colourProvider.Background4, + Alpha = 0, + RelativeSizeAxes = Axes.Both, + }, + icon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Icon = FontAwesome.Solid.TimesCircle, - Size = new Vector2(20), + Icon = FontAwesome.Solid.Check, + Size = new Vector2(12), + Colour = colourProvider.Foreground1, } }; } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - hoverColour = colours.Yellow; - } - protected override bool OnHover(HoverEvent e) { - this.FadeColour(hoverColour, 200); + background.FadeIn(200); + icon.FadeColour(colourProvider.Content1, 200); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - this.FadeColour(OsuColour.Gray(0.2f), 200); + background.FadeOut(200); + icon.FadeColour(colourProvider.Foreground1, 200); base.OnHoverLost(e); } } diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 15346930a3..6390d9a54f 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -57,7 +57,7 @@ namespace osu.Game.Overlays.Notifications set { progress = value; - Scheduler.AddOnce(updateProgress, progress); + Scheduler.AddOnce(p => progressBar.Progress = p, progress); } } @@ -174,7 +174,6 @@ namespace osu.Game.Overlays.Notifications { Content.Add(textDrawable = new OsuTextFlowContainer { - Colour = OsuColour.Gray(128), AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, }); diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index b9a1cc6d90..ae4d183258 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; @@ -24,7 +23,8 @@ namespace osu.Game.Overlays.Notifications set { text = value; - textDrawable.Text = text; + if (textDrawable != null) + textDrawable.Text = text; } } @@ -36,48 +36,46 @@ namespace osu.Game.Overlays.Notifications set { icon = value; - iconDrawable.Icon = icon; + if (iconDrawable != null) + iconDrawable.Icon = icon; } } - private readonly TextFlowContainer textDrawable; - private readonly SpriteIcon iconDrawable; + protected Box IconBackground = null!; - protected Box IconBackground; + private TextFlowContainer? textDrawable; - public SimpleNotification() + private SpriteIcon? iconDrawable; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, OverlayColourProvider colourProvider) { + Light.Colour = colours.Green; + IconContent.AddRange(new Drawable[] { IconBackground = new Box { RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.6f)) + Colour = colourProvider.Background5, }, iconDrawable = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = icon, - Size = new Vector2(20), + Size = new Vector2(16), } }); - Content.Add(textDrawable = new OsuTextFlowContainer(t => t.Font = t.Font.With(size: 14)) + Content.Add(textDrawable = new OsuTextFlowContainer(t => t.Font = t.Font.With(size: 14, weight: FontWeight.Medium)) { - Colour = OsuColour.Gray(128), AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, Text = text }); } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Light.Colour = colours.Green; - } - public override bool Read { get => base.Read; From 0f203531d938fc39e0b8c99274cf35ccf844b5a3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 17:37:43 +0900 Subject: [PATCH 0793/2686] Allow customising the "close" button icon --- osu.Game/Overlays/Notifications/Notification.cs | 13 +++++++++++-- .../Overlays/Notifications/ProgressNotification.cs | 5 ++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 5cd0db628d..2b57423305 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -56,6 +56,8 @@ namespace osu.Game.Overlays.Notifications public virtual bool Read { get; set; } + protected virtual IconUsage CloseButtonIcon => FontAwesome.Solid.Check; + protected Notification() { RelativeSizeAxes = Axes.X; @@ -116,7 +118,7 @@ namespace osu.Game.Overlays.Notifications }, } }, - new CloseButton + new CloseButton(CloseButtonIcon) { Action = Close, Anchor = Anchor.TopRight, @@ -177,9 +179,16 @@ namespace osu.Game.Overlays.Notifications private SpriteIcon icon = null!; private Box background = null!; + private readonly IconUsage iconUsage; + [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + public CloseButton(IconUsage iconUsage) + { + this.iconUsage = iconUsage; + } + [BackgroundDependencyLoader] private void load() { @@ -198,7 +207,7 @@ namespace osu.Game.Overlays.Notifications { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Icon = FontAwesome.Solid.Check, + Icon = iconUsage, Size = new Vector2(12), Colour = colourProvider.Foreground1, } diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 6390d9a54f..594537bce7 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -61,7 +61,10 @@ namespace osu.Game.Overlays.Notifications } } - private void updateProgress(float progress) => progressBar.Progress = progress; + protected override IconUsage CloseButtonIcon => FontAwesome.Solid.Times; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; protected override void LoadComplete() { From 09aa3e065d790ad2f1cb44024dc7b06bd9cc8b73 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 17:40:35 +0900 Subject: [PATCH 0794/2686] Move colouring to full icon content rather than background --- osu.Desktop/Security/ElevatedPrivilegesChecker.cs | 2 +- osu.Game/Database/TooManyDownloadsNotification.cs | 2 +- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- .../Notifications/ProgressCompletionNotification.cs | 2 +- .../Overlays/Notifications/ProgressNotification.cs | 11 +++++------ osu.Game/Overlays/Notifications/SimpleNotification.cs | 4 +--- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- osu.Game/Updater/UpdateManager.cs | 2 +- 8 files changed, 13 insertions(+), 16 deletions(-) diff --git a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs index 9959b24b35..cc4337fb02 100644 --- a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs +++ b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs @@ -76,7 +76,7 @@ namespace osu.Desktop.Security private void load(OsuColour colours) { Icon = FontAwesome.Solid.ShieldAlt; - IconBackground.Colour = colours.YellowDark; + IconContent.Colour = colours.YellowDark; } } } diff --git a/osu.Game/Database/TooManyDownloadsNotification.cs b/osu.Game/Database/TooManyDownloadsNotification.cs index aa88fed43c..14012e1d34 100644 --- a/osu.Game/Database/TooManyDownloadsNotification.cs +++ b/osu.Game/Database/TooManyDownloadsNotification.cs @@ -20,7 +20,7 @@ namespace osu.Game.Database [BackgroundDependencyLoader] private void load(OsuColour colours) { - IconBackground.Colour = colours.RedDark; + IconContent.Colour = colours.RedDark; } } } diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 3fc6a008e8..22c2b4690e 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -174,7 +174,7 @@ namespace osu.Game.Online.Chat [BackgroundDependencyLoader] private void load(OsuColour colours, ChatOverlay chatOverlay, INotificationOverlay notificationOverlay) { - IconBackground.Colour = colours.PurpleDark; + IconContent.Colour = colours.PurpleDark; Activated = delegate { diff --git a/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs index cb9d54c14c..49d558285c 100644 --- a/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Notifications [BackgroundDependencyLoader] private void load(OsuColour colours) { - IconBackground.Colour = ColourInfo.GradientVertical(colours.GreenDark, colours.GreenLight); + IconContent.Colour = ColourInfo.GradientVertical(colours.GreenDark, colours.GreenLight); } } } diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 594537bce7..c0342f1c2a 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -103,7 +103,7 @@ namespace osu.Game.Overlays.Notifications Light.Pulsate = false; progressBar.Active = false; - iconBackground.FadeColour(ColourInfo.GradientVertical(colourQueued, colourQueued.Lighten(0.5f)), colour_fade_duration); + IconContent.FadeColour(ColourInfo.GradientVertical(colourQueued, colourQueued.Lighten(0.5f)), colour_fade_duration); loadingSpinner.Show(); break; @@ -112,14 +112,14 @@ namespace osu.Game.Overlays.Notifications Light.Pulsate = true; progressBar.Active = true; - iconBackground.FadeColour(ColourInfo.GradientVertical(colourActive, colourActive.Lighten(0.5f)), colour_fade_duration); + IconContent.FadeColour(ColourInfo.GradientVertical(colourActive, colourActive.Lighten(0.5f)), colour_fade_duration); loadingSpinner.Show(); break; case ProgressNotificationState.Cancelled: cancellationTokenSource.Cancel(); - iconBackground.FadeColour(ColourInfo.GradientVertical(Color4.Gray, Color4.Gray.Lighten(0.5f)), colour_fade_duration); + IconContent.FadeColour(ColourInfo.GradientVertical(Color4.Gray, Color4.Gray.Lighten(0.5f)), colour_fade_duration); loadingSpinner.Hide(); var icon = new SpriteIcon @@ -168,7 +168,6 @@ namespace osu.Game.Overlays.Notifications private Color4 colourActive; private Color4 colourCancelled; - private Box iconBackground = null!; private LoadingSpinner loadingSpinner = null!; private readonly TextFlowContainer textDrawable; @@ -206,10 +205,10 @@ namespace osu.Game.Overlays.Notifications IconContent.AddRange(new Drawable[] { - iconBackground = new Box + new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4.White, + Colour = colourProvider.Background5, }, loadingSpinner = new LoadingSpinner { diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index ae4d183258..1dba60fb5f 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -41,8 +41,6 @@ namespace osu.Game.Overlays.Notifications } } - protected Box IconBackground = null!; - private TextFlowContainer? textDrawable; private SpriteIcon? iconDrawable; @@ -54,7 +52,7 @@ namespace osu.Game.Overlays.Notifications IconContent.AddRange(new Drawable[] { - IconBackground = new Box + new Box { RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index e6bd1367ef..a9fcab063c 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -530,7 +530,7 @@ namespace osu.Game.Screens.Play private void load(OsuColour colours, AudioManager audioManager, INotificationOverlay notificationOverlay, VolumeOverlay volumeOverlay) { Icon = FontAwesome.Solid.VolumeMute; - IconBackground.Colour = colours.RedDark; + IconContent.Colour = colours.RedDark; Activated = delegate { @@ -584,7 +584,7 @@ namespace osu.Game.Screens.Play private void load(OsuColour colours, INotificationOverlay notificationOverlay) { Icon = FontAwesome.Solid.BatteryQuarter; - IconBackground.Colour = colours.RedDark; + IconContent.Colour = colours.RedDark; Activated = delegate { diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index d60f2e4a4b..4790055cd1 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -99,7 +99,7 @@ namespace osu.Game.Updater private void load(OsuColour colours, ChangelogOverlay changelog, INotificationOverlay notificationOverlay) { Icon = FontAwesome.Solid.CheckSquare; - IconBackground.Colour = colours.BlueDark; + IconContent.Colour = colours.BlueDark; Activated = delegate { From bea12ab3c262bb777dbba82b4fbc74ce1dd38c60 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 17:49:29 +0900 Subject: [PATCH 0795/2686] Rename `NotificationContent` to `MainContent` --- osu.Game/Overlays/Notifications/Notification.cs | 10 +++++----- .../Overlays/Notifications/ProgressNotification.cs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 2b57423305..b04e732f92 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Notifications protected override Container Content => content; - protected Container NotificationContent; + protected Container MainContent; public virtual bool Read { get; set; } @@ -71,7 +71,7 @@ namespace osu.Game.Overlays.Notifications Anchor = Anchor.CentreLeft, Origin = Anchor.CentreRight, }, - NotificationContent = new Container + MainContent = new Container { CornerRadius = 8, Masking = true, @@ -135,7 +135,7 @@ namespace osu.Game.Overlays.Notifications [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { - NotificationContent.Add(new Box + MainContent.Add(new Box { RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background3, @@ -157,8 +157,8 @@ namespace osu.Game.Overlays.Notifications this.FadeInFromZero(200); - NotificationContent.MoveToX(DrawSize.X); - NotificationContent.MoveToX(0, 500, Easing.OutQuint); + MainContent.MoveToX(DrawSize.X); + MainContent.MoveToX(0, 500, Easing.OutQuint); } public bool WasClosed; diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index c0342f1c2a..2f813b4ad5 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -141,7 +141,7 @@ namespace osu.Game.Overlays.Notifications case ProgressNotificationState.Completed: loadingSpinner.Hide(); - NotificationContent.MoveToY(-DrawSize.Y / 2, 200, Easing.OutQuint); + MainContent.MoveToY(-DrawSize.Y / 2, 200, Easing.OutQuint); this.FadeOut(200).Finally(_ => Completed()); break; } @@ -180,7 +180,7 @@ namespace osu.Game.Overlays.Notifications RelativeSizeAxes = Axes.X, }); - NotificationContent.Add(progressBar = new ProgressBar + MainContent.Add(progressBar = new ProgressBar { Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, From c846bf20a76ffb9adf5c698f64f3c668b04f90aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 17:58:32 +0900 Subject: [PATCH 0796/2686] Add background hover and adjust remaining metrics --- .../Overlays/Notifications/Notification.cs | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index b04e732f92..a759e2efd1 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -58,6 +58,11 @@ namespace osu.Game.Overlays.Notifications protected virtual IconUsage CloseButtonIcon => FontAwesome.Solid.Check; + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + private Box background = null!; + protected Notification() { RelativeSizeAxes = Axes.X; @@ -73,7 +78,7 @@ namespace osu.Game.Overlays.Notifications }, MainContent = new Container { - CornerRadius = 8, + CornerRadius = 6, Masking = true, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -133,9 +138,9 @@ namespace osu.Game.Overlays.Notifications } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load() { - MainContent.Add(new Box + MainContent.Add(background = new Box { RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background3, @@ -143,6 +148,18 @@ namespace osu.Game.Overlays.Notifications }); } + protected override bool OnHover(HoverEvent e) + { + background.FadeColour(colourProvider.Background2, 200, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + background.FadeColour(colourProvider.Background3, 200, Easing.OutQuint); + base.OnHoverLost(e); + } + protected override bool OnClick(ClickEvent e) { if (Activated?.Invoke() ?? true) @@ -193,7 +210,7 @@ namespace osu.Game.Overlays.Notifications private void load() { RelativeSizeAxes = Axes.Y; - Width = 24; + Width = 28; Children = new Drawable[] { @@ -216,15 +233,15 @@ namespace osu.Game.Overlays.Notifications protected override bool OnHover(HoverEvent e) { - background.FadeIn(200); - icon.FadeColour(colourProvider.Content1, 200); + background.FadeIn(200, Easing.OutQuint); + icon.FadeColour(colourProvider.Content1, 200, Easing.OutQuint); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - background.FadeOut(200); - icon.FadeColour(colourProvider.Foreground1, 200); + background.FadeOut(200, Easing.OutQuint); + icon.FadeColour(colourProvider.Foreground1, 200, Easing.OutQuint); base.OnHoverLost(e); } } From d600058c98419657c7f4b9d630b34ff8b5d2a613 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 18:09:10 +0900 Subject: [PATCH 0797/2686] Assert non-null in `ProfileHeader` to appease r# --- osu.Game/Overlays/Profile/ProfileHeader.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index f84f829f7a..1eca6a81cf 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -3,6 +3,7 @@ #nullable disable +using System.Diagnostics; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -37,6 +38,10 @@ namespace osu.Game.Overlays.Profile // todo: pending implementation. // TabControl.AddItem(LayoutStrings.HeaderUsersModding); + // Haphazardly guaranteed by OverlayHeader constructor (see CreateBackground / CreateContent). + Debug.Assert(centreHeaderContainer != null); + Debug.Assert(detailHeaderContainer != null); + centreHeaderContainer.DetailsVisible.BindValueChanged(visible => detailHeaderContainer.Expanded = visible.NewValue, true); } From 928bce8fcdee3daf785539cd068b48274eae30e0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 18:18:46 +0900 Subject: [PATCH 0798/2686] Fix crash when attempting to watch a replay when the storage file doesn't exist --- osu.Game/Scoring/LegacyDatabasedScore.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Scoring/LegacyDatabasedScore.cs b/osu.Game/Scoring/LegacyDatabasedScore.cs index de35cb5faf..a7641c7999 100644 --- a/osu.Game/Scoring/LegacyDatabasedScore.cs +++ b/osu.Game/Scoring/LegacyDatabasedScore.cs @@ -25,7 +25,12 @@ namespace osu.Game.Scoring return; using (var stream = store.GetStream(replayFilename)) + { + if (stream == null) + return; + Replay = new DatabasedLegacyScoreDecoder(rulesets, beatmaps).Parse(stream).Replay; + } } } } From 6b71b4656d6a10e085d9ab9119110293c7250cbd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 19:16:59 +0900 Subject: [PATCH 0799/2686] Remove `ProgressNotification` vertical movement and delay --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 2f813b4ad5..36b8bac873 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -141,8 +141,7 @@ namespace osu.Game.Overlays.Notifications case ProgressNotificationState.Completed: loadingSpinner.Hide(); - MainContent.MoveToY(-DrawSize.Y / 2, 200, Easing.OutQuint); - this.FadeOut(200).Finally(_ => Completed()); + Completed(); break; } } From 60413e3e7bac003d6d7ceab82b704d4efd236bb5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 19:17:40 +0900 Subject: [PATCH 0800/2686] Enable masking for main content to avoid underlap with close button on word wrap failure. --- osu.Game/Overlays/Notifications/Notification.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index a759e2efd1..90d9b88b79 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -118,6 +118,7 @@ namespace osu.Game.Overlays.Notifications { content = new Container { + Masking = true, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }, From 7b006f1f2249278d67a073bbd747e0957aede85a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 20:34:27 +0900 Subject: [PATCH 0801/2686] Add flash when a new notification is displayed to draw attention --- osu.Game/Overlays/Notifications/Notification.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 90d9b88b79..3407995502 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -61,6 +61,8 @@ namespace osu.Game.Overlays.Notifications [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + private readonly Box initialFlash; + private Box background = null!; protected Notification() @@ -133,6 +135,12 @@ namespace osu.Game.Overlays.Notifications } }, }, + initialFlash = new Box + { + Colour = Color4.White.Opacity(0.8f), + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive, + }, } } }; @@ -177,6 +185,8 @@ namespace osu.Game.Overlays.Notifications MainContent.MoveToX(DrawSize.X); MainContent.MoveToX(0, 500, Easing.OutQuint); + + initialFlash.FadeOutFromOne(2000, Easing.OutQuart); } public bool WasClosed; From b8300ae60a29216e63790857e486614f3c295eac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 20:57:12 +0900 Subject: [PATCH 0802/2686] Add toast notification tray --- osu.Game/Overlays/NotificationOverlay.cs | 81 +++++++++--- .../Overlays/NotificationOverlayToastTray.cs | 124 ++++++++++++++++++ 2 files changed, 184 insertions(+), 21 deletions(-) create mode 100644 osu.Game/Overlays/NotificationOverlayToastTray.cs diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index bd483e073c..096de558dd 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -15,6 +15,7 @@ using osu.Framework.Threading; using osu.Game.Graphics.Containers; using osu.Game.Overlays.Notifications; using osu.Game.Resources.Localisation.Web; +using osuTK; using NotificationsStrings = osu.Game.Localisation.NotificationsStrings; namespace osu.Game.Overlays @@ -39,6 +40,23 @@ namespace osu.Game.Overlays private readonly IBindable firstRunSetupVisibility = new Bindable(); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) + { + if (State.Value == Visibility.Visible) + return base.ReceivePositionalInputAt(screenSpacePos); + + if (toastTray.IsDisplayingToasts) + return toastTray.ReceivePositionalInputAt(screenSpacePos); + + return false; + } + + public override bool PropagatePositionalInputSubTree => base.PropagatePositionalInputSubTree || toastTray.IsDisplayingToasts; + + private NotificationOverlayToastTray toastTray = null!; + + private Container mainContent = null!; + [BackgroundDependencyLoader] private void load(FirstRunSetupOverlay? firstRunSetup) { @@ -48,30 +66,41 @@ namespace osu.Game.Overlays Children = new Drawable[] { - new Box + toastTray = new NotificationOverlayToastTray { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background4, + Origin = Anchor.TopRight, }, - new OsuScrollContainer + mainContent = new Container { - Masking = true, RelativeSizeAxes = Axes.Both, - Children = new[] + Children = new Drawable[] { - sections = new FillFlowContainer + new Box { - Direction = FillDirection.Vertical, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4, + }, + new OsuScrollContainer + { + Masking = true, + RelativeSizeAxes = Axes.Both, Children = new[] { - new NotificationSection(AccountsStrings.NotificationsTitle, new[] { typeof(SimpleNotification) }, "Clear All"), - new NotificationSection(@"Running Tasks", new[] { typeof(ProgressNotification) }, @"Cancel All"), + sections = new FillFlowContainer + { + Direction = FillDirection.Vertical, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Children = new[] + { + new NotificationSection(AccountsStrings.NotificationsTitle, new[] { typeof(SimpleNotification) }, "Clear All"), + new NotificationSection(@"Running Tasks", new[] { typeof(ProgressNotification) }, @"Cancel All"), + } + } } } } - } + }, }; if (firstRunSetup != null) @@ -129,14 +158,22 @@ namespace osu.Game.Overlays var ourType = notification.GetType(); - var section = sections.Children.FirstOrDefault(s => s.AcceptedNotificationTypes.Any(accept => accept.IsAssignableFrom(ourType))); - section?.Add(notification, notification.DisplayOnTop ? -runningDepth : runningDepth); + int depth = notification.DisplayOnTop ? -runningDepth : runningDepth; - if (notification.IsImportant) - Show(); + if (State.Value == Visibility.Hidden) + toastTray.Post(notification, addPermanently); + else + addPermanently(); - updateCounts(); - playDebouncedSample(notification.PopInSampleName); + void addPermanently() + { + var section = sections.Children.First(s => s.AcceptedNotificationTypes.Any(accept => accept.IsAssignableFrom(ourType))); + + section.Add(notification, depth); + + updateCounts(); + playDebouncedSample(notification.PopInSampleName); + } }); protected override void Update() @@ -152,7 +189,9 @@ namespace osu.Game.Overlays base.PopIn(); this.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint); - this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint); + mainContent.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint); + + toastTray.FlushAllToasts(); } protected override void PopOut() @@ -162,7 +201,7 @@ namespace osu.Game.Overlays markAllRead(); this.MoveToX(WIDTH, TRANSITION_LENGTH, Easing.OutQuint); - this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); + mainContent.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); } private void notificationClosed() diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs new file mode 100644 index 0000000000..338e84c472 --- /dev/null +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -0,0 +1,124 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Threading; +using osu.Framework.Utils; +using osu.Game.Overlays.Notifications; +using osuTK; + +namespace osu.Game.Overlays +{ + /// + /// A tray which attaches to the left of to show temporary toasts. + /// + public class NotificationOverlayToastTray : CompositeDrawable + { + public bool IsDisplayingToasts => toastFlow.Count > 0; + + private FillFlowContainer toastFlow = null!; + private BufferedContainer toastContentBackground = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + private readonly List pendingToastOperations = new List(); + + private int runningDepth; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding(20); + + InternalChildren = new Drawable[] + { + toastContentBackground = (new Box + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Colour = ColourInfo.GradientVertical( + colourProvider.Background6.Opacity(0.7f), + colourProvider.Background6.Opacity(0.5f)), + RelativeSizeAxes = Axes.Both, + }.WithEffect(new BlurEffect + { + PadExtent = true, + Sigma = new Vector2(20), + }).With(postEffectDrawable => + { + postEffectDrawable.Scale = new Vector2(1.5f, 1); + postEffectDrawable.Position += new Vector2(70, -50); + postEffectDrawable.AutoSizeAxes = Axes.None; + postEffectDrawable.RelativeSizeAxes = Axes.X; + })), + toastFlow = new FillFlowContainer + { + LayoutDuration = 150, + LayoutEasing = Easing.OutQuart, + Spacing = new Vector2(3), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, + }; + } + + public void FlushAllToasts() + { + foreach (var d in pendingToastOperations.Where(d => !d.Completed)) + d.RunTask(); + + pendingToastOperations.Clear(); + } + + public void Post(Notification notification, Action addPermanently) + { + ++runningDepth; + + int depth = notification.DisplayOnTop ? -runningDepth : runningDepth; + + toastFlow.Insert(depth, notification); + + pendingToastOperations.Add(Scheduler.AddDelayed(() => + { + // add notification to permanent overlay unless it was already dismissed by the user. + if (notification.WasClosed) + return; + + toastFlow.Remove(notification); + AddInternal(notification); + + notification.MoveToOffset(new Vector2(400, 0), NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint); + notification.FadeOut(NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint).OnComplete(_ => + { + RemoveInternal(notification); + addPermanently(); + + notification.FadeIn(300, Easing.OutQuint); + }); + }, notification.IsImportant ? 15000 : 3000)); + } + + protected override void Update() + { + base.Update(); + + float height = toastFlow.DrawHeight + 120; + float alpha = IsDisplayingToasts ? MathHelper.Clamp(toastFlow.DrawHeight / 40, 0, 1) * toastFlow.Children.Max(n => n.Alpha) : 0; + + toastContentBackground.Height = (float)Interpolation.DampContinuously(toastContentBackground.Height, height, 10, Clock.ElapsedFrameTime); + toastContentBackground.Alpha = (float)Interpolation.DampContinuously(toastContentBackground.Alpha, alpha, 10, Clock.ElapsedFrameTime); + } + } +} From e9cfaa76c954bf2375f3f0c44b24354a2ead697d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 21:04:28 +0900 Subject: [PATCH 0803/2686] Change global overlay ordering so notification toasts display above settings --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f7747c5d64..108153fd9d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -804,8 +804,8 @@ namespace osu.Game Children = new Drawable[] { overlayContent = new Container { RelativeSizeAxes = Axes.Both }, - rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, + rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, } }, topMostOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, From 95ce78a50c72df36eaaa2c63101ea9939f930a28 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 21:04:38 +0900 Subject: [PATCH 0804/2686] Reduce notification post delay now that it's less important --- osu.Game/Overlays/NotificationOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 096de558dd..b6354179e0 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -117,7 +117,7 @@ namespace osu.Game.Overlays if (enabled) // we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed. - notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State.Value == Visibility.Visible ? 0 : 1000); + notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State.Value == Visibility.Visible ? 0 : 100); else processingPosts = false; } From a7110666a0c43b214b3f83d48587eadc3067d0ad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 21:13:27 +0900 Subject: [PATCH 0805/2686] Play notification appear sample immediately --- osu.Game/Overlays/NotificationOverlay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index b6354179e0..b0ebf7e666 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -160,6 +160,8 @@ namespace osu.Game.Overlays int depth = notification.DisplayOnTop ? -runningDepth : runningDepth; + playDebouncedSample(notification.PopInSampleName); + if (State.Value == Visibility.Hidden) toastTray.Post(notification, addPermanently); else @@ -172,7 +174,6 @@ namespace osu.Game.Overlays section.Add(notification, depth); updateCounts(); - playDebouncedSample(notification.PopInSampleName); } }); From 403fc18976e8593e93e7724a9069604fd70a242d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 21:13:37 +0900 Subject: [PATCH 0806/2686] Fix notification completion events not being run when overlay not visible --- osu.Game/Overlays/NotificationOverlay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index b0ebf7e666..80071db37f 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -72,6 +72,7 @@ namespace osu.Game.Overlays }, mainContent = new Container { + AlwaysPresent = true, RelativeSizeAxes = Axes.Both, Children = new Drawable[] { From 224ab29ef405428d9ee4634879fbd6f10658d507 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 21:19:51 +0900 Subject: [PATCH 0807/2686] Don't dismiss toasts while hovered (and adjust timings slightly) --- osu.Game/Overlays/NotificationOverlayToastTray.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index 338e84c472..38f790e88e 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -90,12 +90,20 @@ namespace osu.Game.Overlays toastFlow.Insert(depth, notification); - pendingToastOperations.Add(Scheduler.AddDelayed(() => + pendingToastOperations.Add(scheduleDismissal()); + + ScheduledDelegate scheduleDismissal() => Scheduler.AddDelayed(() => { // add notification to permanent overlay unless it was already dismissed by the user. if (notification.WasClosed) return; + if (notification.IsHovered) + { + pendingToastOperations.Add(scheduleDismissal()); + return; + } + toastFlow.Remove(notification); AddInternal(notification); @@ -107,7 +115,7 @@ namespace osu.Game.Overlays notification.FadeIn(300, Easing.OutQuint); }); - }, notification.IsImportant ? 15000 : 3000)); + }, notification.IsImportant ? 12000 : 2500); } protected override void Update() From b185194d07f0ff1e6ebe7eafb796a85491fab118 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Tue, 30 Aug 2022 14:44:44 +0200 Subject: [PATCH 0808/2686] Apply comments by smoogi --- .../Skinning/TestSceneDrawableTaikoMascot.cs | 1 - .../TestSceneDrumRollJudgements.cs | 38 ------------------- .../Judgements/TaikoDrumRollJudgement.cs | 16 -------- .../Objects/Drawables/DrawableDrumRoll.cs | 2 +- .../Objects/Drawables/DrawableSwell.cs | 3 +- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 2 +- 6 files changed, 3 insertions(+), 59 deletions(-) delete mode 100644 osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs delete mode 100644 osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs index ef95358d34..637e355d97 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs @@ -118,7 +118,6 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Fail); - assertStateAfterResult(new JudgementResult(new DrumRoll(), new TaikoDrumRollJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle); assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Ok }, TaikoMascotAnimationState.Idle); } diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs deleted file mode 100644 index 82dfaecaa4..0000000000 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Linq; -using NUnit.Framework; -using osu.Game.Beatmaps; -using osu.Game.Rulesets.Taiko.Objects; - -namespace osu.Game.Rulesets.Taiko.Tests -{ - public class TestSceneDrumRollJudgements : TestSceneTaikoPlayer - { - [Test] - public void TestStrongDrumRollFullyJudgedOnKilled() - { - AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted.Value); - AddAssert("all judgements are misses", () => Player.Results.All(r => r.Type == r.Judgement.MinResult)); - } - - protected override bool Autoplay => false; - - protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap - { - BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo }, - HitObjects = - { - new DrumRoll - { - StartTime = 1000, - Duration = 1000, - IsStrong = true - } - } - }; - } -} diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs deleted file mode 100644 index f7f923e76e..0000000000 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using osu.Game.Rulesets.Scoring; - -namespace osu.Game.Rulesets.Taiko.Judgements -{ - public class TaikoDrumRollJudgement : TaikoJudgement - { - public override HitResult MaxResult => HitResult.IgnoreHit; - - protected override double HealthIncreaseFor(HitResult result) => 0; - } -} diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 418c4673e2..259add81e0 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -140,7 +140,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables if (timeOffset < 0) return; - ApplyResult(r => r.Type = r.Judgement.MinResult); + ApplyResult(r => r.Type = r.Judgement.MaxResult); } protected override void UpdateHitStateTransforms(ArmedState state) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 84edb30890..a6f6edba09 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -16,7 +16,6 @@ using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; @@ -224,7 +223,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables tick.TriggerResult(false); } - ApplyResult(r => r.Type = numHits > HitObject.RequiredHits / 2 ? HitResult.SmallBonus : r.Judgement.MinResult); + ApplyResult(r => r.Type = numHits == HitObject.RequiredHits ? r.Judgement.MaxResult : r.Judgement.MinResult); } } diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index db752c6691..bd6f10b1a4 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Objects } } - public override Judgement CreateJudgement() => new TaikoDrumRollJudgement(); + public override Judgement CreateJudgement() => new IgnoreJudgement(); protected override HitWindows CreateHitWindows() => HitWindows.Empty; From a9aa928ce6b50162b17ca8bf0b889e4e4e0a0586 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Tue, 30 Aug 2022 15:00:46 +0200 Subject: [PATCH 0809/2686] Fix test, make strong hits have LargeBonus judgement --- osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs | 2 +- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs index f2397aba22..bafe7dfbaf 100644 --- a/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs +++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoStrongJudgement.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Judgements { public class TaikoStrongJudgement : TaikoJudgement { - public override HitResult MaxResult => HitResult.SmallBonus; + public override HitResult MaxResult => HitResult.LargeBonus; // MainObject already changes the HP protected override double HealthIncreaseFor(HitResult result) => 0; diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index bd6f10b1a4..3dab8d2e13 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -11,7 +11,6 @@ using osu.Game.Beatmaps.Formats; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Judgements; using osuTK; namespace osu.Game.Rulesets.Taiko.Objects From ed11b1ba6f57063527ec2fb96965c64671365b8e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 30 Aug 2022 21:31:06 +0900 Subject: [PATCH 0810/2686] Improve forwarding flow to not use piling delegates --- osu.Game/Overlays/NotificationOverlay.cs | 30 ++++----- .../Overlays/NotificationOverlayToastTray.cs | 62 +++++++++++-------- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 80071db37f..593618ab51 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -68,6 +68,7 @@ namespace osu.Game.Overlays { toastTray = new NotificationOverlayToastTray { + ForwardNotificationToPermanentStore = addPermanently, Origin = Anchor.TopRight, }, mainContent = new Container @@ -157,27 +158,26 @@ namespace osu.Game.Overlays if (notification is IHasCompletionTarget hasCompletionTarget) hasCompletionTarget.CompletionTarget = Post; - var ourType = notification.GetType(); - - int depth = notification.DisplayOnTop ? -runningDepth : runningDepth; - playDebouncedSample(notification.PopInSampleName); if (State.Value == Visibility.Hidden) - toastTray.Post(notification, addPermanently); + toastTray.Post(notification); else - addPermanently(); - - void addPermanently() - { - var section = sections.Children.First(s => s.AcceptedNotificationTypes.Any(accept => accept.IsAssignableFrom(ourType))); - - section.Add(notification, depth); - - updateCounts(); - } + addPermanently(notification); }); + private void addPermanently(Notification notification) + { + var ourType = notification.GetType(); + int depth = notification.DisplayOnTop ? -runningDepth : runningDepth; + + var section = sections.Children.First(s => s.AcceptedNotificationTypes.Any(accept => accept.IsAssignableFrom(ourType))); + + section.Add(notification, depth); + + updateCounts(); + } + protected override void Update() { base.Update(); diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index 38f790e88e..7017365dbd 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -11,7 +11,6 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; -using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Overlays.Notifications; using osuTK; @@ -25,13 +24,13 @@ namespace osu.Game.Overlays { public bool IsDisplayingToasts => toastFlow.Count > 0; - private FillFlowContainer toastFlow = null!; + private FillFlowContainer toastFlow = null!; private BufferedContainer toastContentBackground = null!; [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; - private readonly List pendingToastOperations = new List(); + public Action? ForwardNotificationToPermanentStore { get; set; } private int runningDepth; @@ -63,7 +62,7 @@ namespace osu.Game.Overlays postEffectDrawable.AutoSizeAxes = Axes.None; postEffectDrawable.RelativeSizeAxes = Axes.X; })), - toastFlow = new FillFlowContainer + toastFlow = new FillFlowContainer { LayoutDuration = 150, LayoutEasing = Easing.OutQuart, @@ -76,13 +75,13 @@ namespace osu.Game.Overlays public void FlushAllToasts() { - foreach (var d in pendingToastOperations.Where(d => !d.Completed)) - d.RunTask(); - - pendingToastOperations.Clear(); + foreach (var notification in toastFlow.ToArray()) + { + forwardNotification(notification); + } } - public void Post(Notification notification, Action addPermanently) + public void Post(Notification notification) { ++runningDepth; @@ -90,34 +89,47 @@ namespace osu.Game.Overlays toastFlow.Insert(depth, notification); - pendingToastOperations.Add(scheduleDismissal()); + scheduleDismissal(); - ScheduledDelegate scheduleDismissal() => Scheduler.AddDelayed(() => + void scheduleDismissal() => Scheduler.AddDelayed(() => { - // add notification to permanent overlay unless it was already dismissed by the user. + // Notification dismissed by user. if (notification.WasClosed) return; + // Notification forwarded away. + if (notification.Parent != toastFlow) + return; + + // Notification hovered; delay dismissal. if (notification.IsHovered) { - pendingToastOperations.Add(scheduleDismissal()); + scheduleDismissal(); return; } - toastFlow.Remove(notification); - AddInternal(notification); - - notification.MoveToOffset(new Vector2(400, 0), NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint); - notification.FadeOut(NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint).OnComplete(_ => - { - RemoveInternal(notification); - addPermanently(); - - notification.FadeIn(300, Easing.OutQuint); - }); + // All looks good, forward away! + forwardNotification(notification); }, notification.IsImportant ? 12000 : 2500); } + private void forwardNotification(Notification notification) + { + Debug.Assert(notification.Parent == toastFlow); + + toastFlow.Remove(notification); + AddInternal(notification); + + notification.MoveToOffset(new Vector2(400, 0), NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint); + notification.FadeOut(NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint).OnComplete(_ => + { + RemoveInternal(notification); + ForwardNotificationToPermanentStore?.Invoke(notification); + + notification.FadeIn(300, Easing.OutQuint); + }); + } + protected override void Update() { base.Update(); From a62ba9e0d9bda715dabc408df5b0b1f85ed76cd2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 00:57:18 +0900 Subject: [PATCH 0811/2686] Remove notification blocking behaviour of first run setup --- .../Visual/Navigation/TestSceneFirstRunGame.cs | 9 --------- osu.Game/Overlays/NotificationOverlay.cs | 10 ++-------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunGame.cs index f4078676c9..fe26d59812 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunGame.cs @@ -26,16 +26,7 @@ namespace osu.Game.Tests.Visual.Navigation public void TestImportantNotificationDoesntInterruptSetup() { AddStep("post important notification", () => Game.Notifications.Post(new SimpleNotification { Text = "Important notification" })); - AddAssert("no notification posted", () => Game.Notifications.UnreadCount.Value == 0); AddAssert("first-run setup still visible", () => Game.FirstRunOverlay.State.Value == Visibility.Visible); - - AddUntilStep("finish first-run setup", () => - { - Game.FirstRunOverlay.NextButton.TriggerClick(); - return Game.FirstRunOverlay.State.Value == Visibility.Hidden; - }); - AddWaitStep("wait for post delay", 5); - AddAssert("notifications shown", () => Game.Notifications.State.Value == Visibility.Visible); AddAssert("notification posted", () => Game.Notifications.UnreadCount.Value == 1); } diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 593618ab51..bb0beeef41 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -38,8 +38,6 @@ namespace osu.Game.Overlays [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - private readonly IBindable firstRunSetupVisibility = new Bindable(); - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) { if (State.Value == Visibility.Visible) @@ -58,7 +56,7 @@ namespace osu.Game.Overlays private Container mainContent = null!; [BackgroundDependencyLoader] - private void load(FirstRunSetupOverlay? firstRunSetup) + private void load() { X = WIDTH; Width = WIDTH; @@ -104,16 +102,13 @@ namespace osu.Game.Overlays } }, }; - - if (firstRunSetup != null) - firstRunSetupVisibility.BindTo(firstRunSetup.State); } private ScheduledDelegate? notificationsEnabler; private void updateProcessingMode() { - bool enabled = (OverlayActivationMode.Value == OverlayActivation.All && firstRunSetupVisibility.Value != Visibility.Visible) || State.Value == Visibility.Visible; + bool enabled = OverlayActivationMode.Value == OverlayActivation.All || State.Value == Visibility.Visible; notificationsEnabler?.Cancel(); @@ -129,7 +124,6 @@ namespace osu.Game.Overlays base.LoadComplete(); State.BindValueChanged(_ => updateProcessingMode()); - firstRunSetupVisibility.BindValueChanged(_ => updateProcessingMode()); OverlayActivationMode.BindValueChanged(_ => updateProcessingMode(), true); } From 31a9980686a620c5e434a0ea55851e112fe183a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 00:57:30 +0900 Subject: [PATCH 0812/2686] Update remaining test expectations with new behaviour --- .../Visual/UserInterface/TestSceneNotificationOverlay.cs | 5 +++-- osu.Game/Overlays/NotificationOverlay.cs | 7 ++++++- osu.Game/Overlays/NotificationOverlayToastTray.cs | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index c196b204b9..38eecaa052 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -110,7 +110,8 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep(@"simple #1", sendHelloNotification); - AddAssert("Is visible", () => notificationOverlay.State.Value == Visibility.Visible); + AddAssert("toast displayed", () => notificationOverlay.ToastCount == 1); + AddAssert("is not visible", () => notificationOverlay.State.Value == Visibility.Hidden); checkDisplayedCount(1); @@ -183,7 +184,7 @@ namespace osu.Game.Tests.Visual.UserInterface } private void checkDisplayedCount(int expected) => - AddAssert($"Displayed count is {expected}", () => notificationOverlay.UnreadCount.Value == expected); + AddUntilStep($"Displayed count is {expected}", () => notificationOverlay.UnreadCount.Value == expected); private void sendDownloadProgress() { diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index bb0beeef41..3769a7080f 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -129,6 +129,8 @@ namespace osu.Game.Overlays public IBindable UnreadCount => unreadCount; + public int ToastCount => toastTray.UnreadCount; + private readonly BindableInt unreadCount = new BindableInt(); private int runningDepth; @@ -155,7 +157,10 @@ namespace osu.Game.Overlays playDebouncedSample(notification.PopInSampleName); if (State.Value == Visibility.Hidden) + { toastTray.Post(notification); + updateCounts(); + } else addPermanently(notification); }); @@ -220,7 +225,7 @@ namespace osu.Game.Overlays private void updateCounts() { - unreadCount.Value = sections.Select(c => c.UnreadCount).Sum(); + unreadCount.Value = sections.Select(c => c.UnreadCount).Sum() + toastTray.UnreadCount; } private void markAllRead() diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index 7017365dbd..368996f395 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -32,6 +32,8 @@ namespace osu.Game.Overlays public Action? ForwardNotificationToPermanentStore { get; set; } + public int UnreadCount => toastFlow.Count(n => !n.WasClosed && !n.Read); + private int runningDepth; [BackgroundDependencyLoader] From 9eb615f9421202ebec908f97c5a1524005e0f3dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 01:40:27 +0900 Subject: [PATCH 0813/2686] Fix remaining test failures by strengthening `PlayerLoader` tests - Click using `TriggerClick` as notifications move around quite a bit. - Ensure any notifications from a previous test method are cleaned up. --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 44 ++++++++++--------- osu.Game/Overlays/NotificationOverlay.cs | 6 +-- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 922529cf19..b6c17fbaca 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -14,11 +14,10 @@ using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; -using osu.Framework.Utils; using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Configuration; -using osu.Game.Graphics.Containers; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; @@ -30,7 +29,6 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Utils; using osuTK.Input; -using SkipOverlay = osu.Game.Screens.Play.SkipOverlay; namespace osu.Game.Tests.Visual.Gameplay { @@ -83,6 +81,20 @@ namespace osu.Game.Tests.Visual.Gameplay [SetUp] public void Setup() => Schedule(() => player = null); + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("read all notifications", () => + { + notificationOverlay.Show(); + notificationOverlay.Hide(); + }); + + AddUntilStep("wait for no notifications", () => notificationOverlay.UnreadCount.Value, () => Is.EqualTo(0)); + } + /// /// Sets the input manager child to a new test player loader container instance. /// @@ -287,16 +299,9 @@ namespace osu.Game.Tests.Visual.Gameplay saveVolumes(); - AddAssert("check for notification", () => notificationOverlay.UnreadCount.Value == 1); - AddStep("click notification", () => - { - var scrollContainer = (OsuScrollContainer)notificationOverlay.Children.Last(); - var flowContainer = scrollContainer.Children.OfType>().First(); - var notification = flowContainer.First(); + AddAssert("check for notification", () => notificationOverlay.UnreadCount.Value, () => Is.EqualTo(1)); - InputManager.MoveMouseTo(notification); - InputManager.Click(MouseButton.Left); - }); + clickNotificationIfAny(); AddAssert("check " + volumeName, assert); @@ -366,15 +371,7 @@ namespace osu.Game.Tests.Visual.Gameplay })); AddUntilStep("wait for player", () => player?.LoadState == LoadState.Ready); AddAssert($"notification {(shouldWarn ? "triggered" : "not triggered")}", () => notificationOverlay.UnreadCount.Value == (shouldWarn ? 1 : 0)); - AddStep("click notification", () => - { - var scrollContainer = (OsuScrollContainer)notificationOverlay.Children.Last(); - var flowContainer = scrollContainer.Children.OfType>().First(); - var notification = flowContainer.First(); - - InputManager.MoveMouseTo(notification); - InputManager.Click(MouseButton.Left); - }); + clickNotificationIfAny(); AddUntilStep("wait for player load", () => player.IsLoaded); } @@ -439,6 +436,11 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("skip button not visible", () => !checkSkipButtonVisible()); } + private void clickNotificationIfAny() + { + AddStep("click notification", () => notificationOverlay.ChildrenOfType().FirstOrDefault()?.TriggerClick()); + } + private EpilepsyWarning getWarning() => loader.ChildrenOfType().SingleOrDefault(); private class TestPlayerLoader : PlayerLoader diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 3769a7080f..488f3eab0d 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -157,12 +157,11 @@ namespace osu.Game.Overlays playDebouncedSample(notification.PopInSampleName); if (State.Value == Visibility.Hidden) - { toastTray.Post(notification); - updateCounts(); - } else addPermanently(notification); + + updateCounts(); }); private void addPermanently(Notification notification) @@ -231,7 +230,6 @@ namespace osu.Game.Overlays private void markAllRead() { sections.Children.ForEach(s => s.MarkAllRead()); - updateCounts(); } } From ad650adab0b9ea2b226b10523193f96439265c6c Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Tue, 30 Aug 2022 18:03:44 +0100 Subject: [PATCH 0814/2686] Fix speed note count sum --- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index a156726f94..c39d61020c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills if (maxStrain == 0) return 0; - return objectStrains.Aggregate((total, next) => total + (1.0 / (1.0 + Math.Exp(-(next / maxStrain * 12.0 - 6.0))))); + return objectStrains.Sum(strain => 1.0 / (1.0 + Math.Exp(-(strain / maxStrain * 12.0 - 6.0)))); } } } From 0558dae917899a7cafb5dd14adaf016ff7701ce0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 12:46:03 +0900 Subject: [PATCH 0815/2686] Mark toasts as read when closing the overlay for added safety I'm not sure how the read status will play out going forward so I'm just adding this to keep things conforming for now. --- osu.Game/Overlays/NotificationOverlay.cs | 1 + osu.Game/Overlays/NotificationOverlayToastTray.cs | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 488f3eab0d..6eb327cbce 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -230,6 +230,7 @@ namespace osu.Game.Overlays private void markAllRead() { sections.Children.ForEach(s => s.MarkAllRead()); + toastTray.MarkAllRead(); updateCounts(); } } diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index 368996f395..800751072c 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -75,6 +75,12 @@ namespace osu.Game.Overlays }; } + public void MarkAllRead() + { + toastFlow.Children.ForEach(n => n.Read = true); + InternalChildren.OfType().ForEach(n => n.Read = true); + } + public void FlushAllToasts() { foreach (var notification in toastFlow.ToArray()) From 7c72c6b43faef9a78400a8b0f5807fc8f927885f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 12:46:43 +0900 Subject: [PATCH 0816/2686] Fix unread count potentially missing notifications in a transforming state --- osu.Game/Overlays/NotificationOverlay.cs | 10 +++++----- osu.Game/Overlays/NotificationOverlayToastTray.cs | 9 +++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 6eb327cbce..2c39ebcc87 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -222,16 +222,16 @@ namespace osu.Game.Overlays } } - private void updateCounts() - { - unreadCount.Value = sections.Select(c => c.UnreadCount).Sum() + toastTray.UnreadCount; - } - private void markAllRead() { sections.Children.ForEach(s => s.MarkAllRead()); toastTray.MarkAllRead(); updateCounts(); } + + private void updateCounts() + { + unreadCount.Value = sections.Select(c => c.UnreadCount).Sum() + toastTray.UnreadCount; + } } } diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index 800751072c..4417b5e0d0 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; @@ -32,7 +33,8 @@ namespace osu.Game.Overlays public Action? ForwardNotificationToPermanentStore { get; set; } - public int UnreadCount => toastFlow.Count(n => !n.WasClosed && !n.Read); + public int UnreadCount => toastFlow.Count(n => !n.WasClosed && !n.Read) + + InternalChildren.OfType().Count(n => !n.WasClosed && !n.Read); private int runningDepth; @@ -64,7 +66,7 @@ namespace osu.Game.Overlays postEffectDrawable.AutoSizeAxes = Axes.None; postEffectDrawable.RelativeSizeAxes = Axes.X; })), - toastFlow = new FillFlowContainer + toastFlow = new AlwaysUpdateFillFlowContainer { LayoutDuration = 150, LayoutEasing = Easing.OutQuart, @@ -84,9 +86,7 @@ namespace osu.Game.Overlays public void FlushAllToasts() { foreach (var notification in toastFlow.ToArray()) - { forwardNotification(notification); - } } public void Post(Notification notification) @@ -125,6 +125,7 @@ namespace osu.Game.Overlays { Debug.Assert(notification.Parent == toastFlow); + // Temporarily remove from flow so we can animate the position off to the right. toastFlow.Remove(notification); AddInternal(notification); From c573396ab6f5c1ff4d66d89cc3e73eaaa0aefdc4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 12:46:54 +0900 Subject: [PATCH 0817/2686] Fix `IntroTestScene` not clearing previous notifications hard enough --- osu.Game.Tests/Visual/Menus/IntroTestScene.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs index 66e3612113..e0f0df0554 100644 --- a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs +++ b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs @@ -52,6 +52,7 @@ namespace osu.Game.Tests.Visual.Menus }, notifications = new NotificationOverlay { + Depth = float.MinValue, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, } @@ -82,7 +83,14 @@ namespace osu.Game.Tests.Visual.Menus [Test] public virtual void TestPlayIntroWithFailingAudioDevice() { - AddStep("hide notifications", () => notifications.Hide()); + AddStep("reset notifications", () => + { + notifications.Show(); + notifications.Hide(); + }); + + AddUntilStep("wait for no notifications", () => notifications.UnreadCount.Value, () => Is.EqualTo(0)); + AddStep("restart sequence", () => { logo.FinishTransforms(); From 85442fe0328395bb76209b7478bbf69f0a85a5cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 12:48:30 +0900 Subject: [PATCH 0818/2686] Adjust dismiss button background colour to avoid conflict with background --- osu.Game/Overlays/Notifications/Notification.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 90d9b88b79..a2ffdbe208 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osuTK; using osuTK.Graphics; @@ -217,7 +218,7 @@ namespace osu.Game.Overlays.Notifications { background = new Box { - Colour = colourProvider.Background4, + Colour = OsuColour.Gray(0).Opacity(0.15f), Alpha = 0, RelativeSizeAxes = Axes.Both, }, From 8b9ccc66b7b9bd8c01385083b9b55fd9943f5e68 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 12:49:28 +0900 Subject: [PATCH 0819/2686] Update `ProgressNotification` font spec to match other notifications --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 36b8bac873..14cf6b3013 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -173,7 +173,7 @@ namespace osu.Game.Overlays.Notifications public ProgressNotification() { - Content.Add(textDrawable = new OsuTextFlowContainer + Content.Add(textDrawable = new OsuTextFlowContainer(t => t.Font = t.Font.With(size: 14, weight: FontWeight.Medium)) { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, From 7ce1cf7560d00b9c92df6a6b18eda8a5999470d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 13:19:58 +0900 Subject: [PATCH 0820/2686] Add test coverage of skip button failure with equal time --- .../Visual/Gameplay/TestSceneSkipOverlay.cs | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs index b6b3650c83..6b02449aa3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs @@ -27,8 +27,7 @@ namespace osu.Game.Tests.Visual.Gameplay private const double skip_time = 6000; - [SetUp] - public void SetUp() => Schedule(() => + private void createTest(double skipTime = skip_time) => AddStep("create test", () => { requestCount = 0; increment = skip_time; @@ -40,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - skip = new TestSkipOverlay(skip_time) + skip = new TestSkipOverlay(skipTime) { RequestSkip = () => { @@ -55,9 +54,25 @@ namespace osu.Game.Tests.Visual.Gameplay gameplayClock = gameplayClockContainer; }); + [Test] + public void TestSkipTimeZero() + { + createTest(0); + AddUntilStep("wait for skip overlay expired", () => !skip.IsAlive); + } + + [Test] + public void TestSkipTimeEqualToSkip() + { + createTest(MasterGameplayClockContainer.MINIMUM_SKIP_TIME); + AddUntilStep("wait for skip overlay expired", () => !skip.IsAlive); + } + [Test] public void TestFadeOnIdle() { + createTest(); + AddStep("move mouse", () => InputManager.MoveMouseTo(Vector2.Zero)); AddUntilStep("fully visible", () => skip.FadingContent.Alpha == 1); AddUntilStep("wait for fade", () => skip.FadingContent.Alpha < 1); @@ -70,6 +85,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestClickableAfterFade() { + createTest(); + AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre)); AddUntilStep("wait for fade", () => skip.FadingContent.Alpha == 0); AddStep("click", () => InputManager.Click(MouseButton.Left)); @@ -79,6 +96,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestClickOnlyActuatesOnce() { + createTest(); + AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre)); AddStep("click", () => { @@ -94,6 +113,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestClickOnlyActuatesMultipleTimes() { + createTest(); + AddStep("set increment lower", () => increment = 3000); AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre)); AddStep("click", () => InputManager.Click(MouseButton.Left)); @@ -106,6 +127,8 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestDoesntFadeOnMouseDown() { + createTest(); + AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre)); AddStep("button down", () => InputManager.PressButton(MouseButton.Left)); AddUntilStep("wait for overlay disappear", () => !skip.OverlayContent.IsPresent); From 51346e015417f634928c169d641a332f9bae0590 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 13:05:57 +0900 Subject: [PATCH 0821/2686] Fix skip button getting stuck on screen for certain beatmaps Closes #20034. --- osu.Game/Screens/Play/SkipOverlay.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 5c9a706549..974d40b538 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -114,16 +114,17 @@ namespace osu.Game.Screens.Play { base.LoadComplete(); + displayTime = gameplayClock.CurrentTime; + // skip is not required if there is no extra "empty" time to skip. // we may need to remove this if rewinding before the initial player load position becomes a thing. - if (fadeOutBeginTime < gameplayClock.CurrentTime) + if (fadeOutBeginTime <= displayTime) { Expire(); return; } button.Action = () => RequestSkip?.Invoke(); - displayTime = gameplayClock.CurrentTime; fadeContainer.TriggerShow(); @@ -146,7 +147,12 @@ namespace osu.Game.Screens.Play { base.Update(); - double progress = fadeOutBeginTime <= displayTime ? 1 : Math.Max(0, 1 - (gameplayClock.CurrentTime - displayTime) / (fadeOutBeginTime - displayTime)); + // This case causes an immediate expire in `LoadComplete`, but `Update` may run once after that. + // Avoid div-by-zero below. + if (fadeOutBeginTime <= displayTime) + return; + + double progress = Math.Max(0, 1 - (gameplayClock.CurrentTime - displayTime) / (fadeOutBeginTime - displayTime)); remainingTimeBox.Width = (float)Interpolation.Lerp(remainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1)); From 93bc4b9294cf08d32d6ba6af00ccf72200a79cc3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 13:44:06 +0900 Subject: [PATCH 0822/2686] Add toggle for tournament client "auto progression" behaviour Addresses https://github.com/ppy/osu/discussions/20038. --- osu.Game.Tournament/Models/LadderInfo.cs | 2 ++ .../Screens/Gameplay/GameplayScreen.cs | 21 +++++++++++-------- .../Screens/MapPool/MapPoolScreen.cs | 9 +++++--- .../Screens/Setup/SetupScreen.cs | 6 ++++++ 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tournament/Models/LadderInfo.cs b/osu.Game.Tournament/Models/LadderInfo.cs index 0f73b60774..6b64a1156e 100644 --- a/osu.Game.Tournament/Models/LadderInfo.cs +++ b/osu.Game.Tournament/Models/LadderInfo.cs @@ -40,5 +40,7 @@ namespace osu.Game.Tournament.Models MinValue = 3, MaxValue = 4, }; + + public Bindable AutoProgressScreens = new BindableBool(true); } } diff --git a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs index 54ae4c0366..8a23ee65da 100644 --- a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs +++ b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs @@ -199,16 +199,19 @@ namespace osu.Game.Tournament.Screens.Gameplay case TourneyState.Idle: contract(); - const float delay_before_progression = 4000; - - // if we've returned to idle and the last screen was ranking - // we should automatically proceed after a short delay - if (lastState == TourneyState.Ranking && !warmup.Value) + if (LadderInfo.AutoProgressScreens.Value) { - if (CurrentMatch.Value?.Completed.Value == true) - scheduledOperation = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(TeamWinScreen)); }, delay_before_progression); - else if (CurrentMatch.Value?.Completed.Value == false) - scheduledOperation = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(MapPoolScreen)); }, delay_before_progression); + const float delay_before_progression = 4000; + + // if we've returned to idle and the last screen was ranking + // we should automatically proceed after a short delay + if (lastState == TourneyState.Ranking && !warmup.Value) + { + if (CurrentMatch.Value?.Completed.Value == true) + scheduledOperation = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(TeamWinScreen)); }, delay_before_progression); + else if (CurrentMatch.Value?.Completed.Value == false) + scheduledOperation = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(MapPoolScreen)); }, delay_before_progression); + } } break; diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs index 5eb2142fae..4d36515316 100644 --- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs +++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs @@ -197,10 +197,13 @@ namespace osu.Game.Tournament.Screens.MapPool setNextMode(); - if (pickType == ChoiceType.Pick && CurrentMatch.Value.PicksBans.Any(i => i.Type == ChoiceType.Pick)) + if (LadderInfo.AutoProgressScreens.Value) { - scheduledChange?.Cancel(); - scheduledChange = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(GameplayScreen)); }, 10000); + if (pickType == ChoiceType.Pick && CurrentMatch.Value.PicksBans.Any(i => i.Type == ChoiceType.Pick)) + { + scheduledChange?.Cancel(); + scheduledChange = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(GameplayScreen)); }, 10000); + } } } diff --git a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs index 2b2dce3664..ff781dec80 100644 --- a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs @@ -131,6 +131,12 @@ namespace osu.Game.Tournament.Screens.Setup windowSize.Value = new Size((int)(height * aspect_ratio / TournamentSceneManager.STREAM_AREA_WIDTH * TournamentSceneManager.REQUIRED_WIDTH), height); } }, + new LabelledSwitchButton + { + Label = "Auto advance screens", + Description = "Screens will progress automatically from gameplay -> results -> map pool", + Current = LadderInfo.AutoProgressScreens, + }, }; } From e9463f3c192aa635dc73c891e61ceb58206572e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 14:07:55 +0900 Subject: [PATCH 0823/2686] Test editor `ComposeScreen` tests not adding beatmap to hierarchy Makes it hard to test anything because `EditorBeatmap`'s `Update` method updates whether a beatmap has timing or not (enabling the placement controls). Also adds a basic timing point to allow for better testing. --- .../Editor/TestSceneManiaComposeScreen.cs | 15 ++++++++++++--- .../Visual/Editing/TestSceneComposeScreen.cs | 11 +++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs index 15b38b39ba..0354228cca 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Database; using osu.Game.Overlays; using osu.Game.Rulesets.Edit; @@ -34,10 +35,14 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor { AddStep("setup compose screen", () => { - var editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 }) + var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 4 }) { BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo }, - }); + }; + + beatmap.ControlPointInfo.Add(0, new TimingControlPoint()); + + var editorBeatmap = new EditorBeatmap(beatmap, new LegacyBeatmapSkin(beatmap.BeatmapInfo, null)); Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); @@ -50,7 +55,11 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor (typeof(IBeatSnapProvider), editorBeatmap), (typeof(OverlayColourProvider), new OverlayColourProvider(OverlayColourScheme.Green)), }, - Child = new ComposeScreen { State = { Value = Visibility.Visible } }, + Children = new Drawable[] + { + editorBeatmap, + new ComposeScreen { State = { Value = Visibility.Visible } }, + } }; }); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs index 291630fa3a..0df44b9ac4 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs @@ -9,6 +9,7 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Overlays; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu; @@ -34,9 +35,11 @@ namespace osu.Game.Tests.Visual.Editing { var beatmap = new OsuBeatmap { - BeatmapInfo = { Ruleset = new OsuRuleset().RulesetInfo } + BeatmapInfo = { Ruleset = new OsuRuleset().RulesetInfo }, }; + beatmap.ControlPointInfo.Add(0, new TimingControlPoint()); + editorBeatmap = new EditorBeatmap(beatmap, new LegacyBeatmapSkin(beatmap.BeatmapInfo, null)); Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); @@ -50,7 +53,11 @@ namespace osu.Game.Tests.Visual.Editing (typeof(IBeatSnapProvider), editorBeatmap), (typeof(OverlayColourProvider), new OverlayColourProvider(OverlayColourScheme.Green)), }, - Child = new ComposeScreen { State = { Value = Visibility.Visible } }, + Children = new Drawable[] + { + editorBeatmap, + new ComposeScreen { State = { Value = Visibility.Visible } }, + } }; }); From cc9dc604a069506f443aa8d3f77bcc35d9d4025a Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 31 Aug 2022 17:21:58 +0900 Subject: [PATCH 0824/2686] Refactor feedback sample playback logic --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 124 +++++++++--------- 1 file changed, 59 insertions(+), 65 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 1984840553..a5f133506e 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -1,6 +1,8 @@ // 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 osu.Framework.Allocation; using osu.Framework.Audio; @@ -40,30 +42,26 @@ namespace osu.Game.Graphics.UserInterface Margin = new MarginPadding { Left = 2 }, }; - private readonly Sample?[] textAddedSamples = new Sample[4]; - private Sample? capsTextAddedSample; - private Sample? textRemovedSample; - private Sample? textCommittedSample; - private Sample? caretMovedSample; - - private Sample? selectCharSample; - private Sample? selectWordSample; - private Sample? selectAllSample; - private Sample? deselectSample; - private OsuCaret? caret; private bool selectionStarted; private double sampleLastPlaybackTime; - private enum SelectionSampleType + private enum FeedbackSampleType { - Character, - Word, - All, + TextAdd, + TextAddCaps, + TextRemove, + TextConfirm, + CaretMove, + SelectCharacter, + SelectWord, + SelectAll, Deselect } + private Dictionary sampleMap = new Dictionary(); + public OsuTextBox() { Height = 40; @@ -87,18 +85,22 @@ namespace osu.Game.Graphics.UserInterface Placeholder.Colour = colourProvider?.Foreground1 ?? new Color4(180, 180, 180, 255); + var textAddedSamples = new Sample?[4]; for (int i = 0; i < textAddedSamples.Length; i++) textAddedSamples[i] = audio.Samples.Get($@"Keyboard/key-press-{1 + i}"); - capsTextAddedSample = audio.Samples.Get(@"Keyboard/key-caps"); - textRemovedSample = audio.Samples.Get(@"Keyboard/key-delete"); - textCommittedSample = audio.Samples.Get(@"Keyboard/key-confirm"); - caretMovedSample = audio.Samples.Get(@"Keyboard/key-movement"); - - selectCharSample = audio.Samples.Get(@"Keyboard/select-char"); - selectWordSample = audio.Samples.Get(@"Keyboard/select-word"); - selectAllSample = audio.Samples.Get(@"Keyboard/select-all"); - deselectSample = audio.Samples.Get(@"Keyboard/deselect"); + sampleMap = new Dictionary + { + { FeedbackSampleType.TextAdd, textAddedSamples }, + { FeedbackSampleType.TextAddCaps, new[] { audio.Samples.Get(@"Keyboard/key-caps") } }, + { FeedbackSampleType.TextRemove, new[] { audio.Samples.Get(@"Keyboard/key-delete") } }, + { FeedbackSampleType.TextConfirm, new[] { audio.Samples.Get(@"Keyboard/key-confirm") } }, + { FeedbackSampleType.CaretMove, new[] { audio.Samples.Get(@"Keyboard/key-movement") } }, + { FeedbackSampleType.SelectCharacter, new[] { audio.Samples.Get(@"Keyboard/select-char") } }, + { FeedbackSampleType.SelectWord, new[] { audio.Samples.Get(@"Keyboard/select-word") } }, + { FeedbackSampleType.SelectAll, new[] { audio.Samples.Get(@"Keyboard/select-all") } }, + { FeedbackSampleType.Deselect, new[] { audio.Samples.Get(@"Keyboard/deselect") } } + }; } private Color4 selectionColour; @@ -110,23 +112,23 @@ namespace osu.Game.Graphics.UserInterface base.OnUserTextAdded(added); if (added.Any(char.IsUpper) && AllowUniqueCharacterSamples) - capsTextAddedSample?.Play(); + playSample(FeedbackSampleType.TextAddCaps); else - playTextAddedSample(); + playSample(FeedbackSampleType.TextAdd); } protected override void OnUserTextRemoved(string removed) { base.OnUserTextRemoved(removed); - textRemovedSample?.Play(); + playSample(FeedbackSampleType.TextRemove); } protected override void OnTextCommitted(bool textChanged) { base.OnTextCommitted(textChanged); - textCommittedSample?.Play(); + playSample(FeedbackSampleType.TextConfirm); } protected override void OnCaretMoved(bool selecting) @@ -134,7 +136,7 @@ namespace osu.Game.Graphics.UserInterface base.OnCaretMoved(selecting); if (!selecting) - caretMovedSample?.Play(); + playSample(FeedbackSampleType.CaretMove); } protected override void OnTextSelectionChanged(TextSelectionType selectionType) @@ -144,15 +146,15 @@ namespace osu.Game.Graphics.UserInterface switch (selectionType) { case TextSelectionType.Character: - playSelectSample(SelectionSampleType.Character); + playSample(FeedbackSampleType.SelectCharacter); break; case TextSelectionType.Word: - playSelectSample(selectionStarted ? SelectionSampleType.Character : SelectionSampleType.Word); + playSample(selectionStarted ? FeedbackSampleType.SelectCharacter : FeedbackSampleType.SelectWord); break; case TextSelectionType.All: - playSelectSample(SelectionSampleType.All); + playSample(FeedbackSampleType.SelectAll); break; } @@ -165,7 +167,7 @@ namespace osu.Game.Graphics.UserInterface if (!selectionStarted) return; - playSelectSample(SelectionSampleType.Deselect); + playSample(FeedbackSampleType.Deselect); selectionStarted = false; } @@ -184,13 +186,13 @@ namespace osu.Game.Graphics.UserInterface case 1: // composition probably ended by pressing backspace, or was cancelled. - textRemovedSample?.Play(); + playSample(FeedbackSampleType.TextRemove); return; default: // longer text removed, composition ended because it was cancelled. // could be a different sample if desired. - textRemovedSample?.Play(); + playSample(FeedbackSampleType.TextRemove); return; } } @@ -198,7 +200,7 @@ namespace osu.Game.Graphics.UserInterface if (addedTextLength > 0) { // some text was added, probably due to typing new text or by changing the candidate. - playTextAddedSample(); + playSample(FeedbackSampleType.TextAdd); return; } @@ -206,14 +208,14 @@ namespace osu.Game.Graphics.UserInterface { // text was probably removed by backspacing. // it's also possible that a candidate that only removed text was changed to. - textRemovedSample?.Play(); + playSample(FeedbackSampleType.TextRemove); return; } if (caretMoved) { // only the caret/selection was moved. - caretMovedSample?.Play(); + playSample(FeedbackSampleType.CaretMove); } } @@ -224,13 +226,13 @@ namespace osu.Game.Graphics.UserInterface if (successful) { // composition was successfully completed, usually by pressing the enter key. - textCommittedSample?.Play(); + playSample(FeedbackSampleType.TextConfirm); } else { // composition was prematurely ended, eg. by clicking inside the textbox. // could be a different sample if desired. - textCommittedSample?.Play(); + playSample(FeedbackSampleType.TextConfirm); } } @@ -259,43 +261,35 @@ namespace osu.Game.Graphics.UserInterface SelectionColour = SelectionColour, }; - private void playSelectSample(SelectionSampleType selectionType) + private SampleChannel? getSampleChannel(FeedbackSampleType feedbackSampleType) + { + var samples = sampleMap[feedbackSampleType]; + + if (samples == null || samples.Length == 0) + return null; + + return samples[RNG.Next(0, samples.Length)]?.GetChannel(); + } + + private void playSample(FeedbackSampleType feedbackSample) { if (Time.Current < sampleLastPlaybackTime + 15) return; - SampleChannel? channel; - double pitch = 0.98 + RNG.NextDouble(0.04); - - switch (selectionType) - { - case SelectionSampleType.All: - channel = selectAllSample?.GetChannel(); - break; - - case SelectionSampleType.Word: - channel = selectWordSample?.GetChannel(); - break; - - case SelectionSampleType.Deselect: - channel = deselectSample?.GetChannel(); - break; - - default: - channel = selectCharSample?.GetChannel(); - pitch += (SelectedText.Length / (double)Text.Length) * 0.15f; - break; - } + SampleChannel? channel = getSampleChannel(feedbackSample); if (channel == null) return; + double pitch = 0.98 + RNG.NextDouble(0.04); + + if (feedbackSample == FeedbackSampleType.SelectCharacter) + pitch += ((double)SelectedText.Length / Math.Max(1, Text.Length)) * 0.15f; + channel.Frequency.Value = pitch; channel.Play(); sampleLastPlaybackTime = Time.Current; } - private void playTextAddedSample() => textAddedSamples[RNG.Next(0, textAddedSamples.Length)]?.Play(); - private class OsuCaret : Caret { private const float caret_move_time = 60; From 212d76a11f3b3bbb6e8bafdcc9c935076a34c61c Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 31 Aug 2022 17:23:22 +0900 Subject: [PATCH 0825/2686] Add audio feedback for invalid textbox input --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index a5f133506e..e5341cfd4b 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -53,6 +53,7 @@ namespace osu.Game.Graphics.UserInterface TextAddCaps, TextRemove, TextConfirm, + TextInvalid, CaretMove, SelectCharacter, SelectWord, @@ -95,6 +96,7 @@ namespace osu.Game.Graphics.UserInterface { FeedbackSampleType.TextAddCaps, new[] { audio.Samples.Get(@"Keyboard/key-caps") } }, { FeedbackSampleType.TextRemove, new[] { audio.Samples.Get(@"Keyboard/key-delete") } }, { FeedbackSampleType.TextConfirm, new[] { audio.Samples.Get(@"Keyboard/key-confirm") } }, + { FeedbackSampleType.TextInvalid, new[] { audio.Samples.Get(@"Keyboard/key-invalid") } }, { FeedbackSampleType.CaretMove, new[] { audio.Samples.Get(@"Keyboard/key-movement") } }, { FeedbackSampleType.SelectCharacter, new[] { audio.Samples.Get(@"Keyboard/select-char") } }, { FeedbackSampleType.SelectWord, new[] { audio.Samples.Get(@"Keyboard/select-word") } }, @@ -111,6 +113,9 @@ namespace osu.Game.Graphics.UserInterface { base.OnUserTextAdded(added); + if (!added.Any(CanAddCharacter)) + return; + if (added.Any(char.IsUpper) && AllowUniqueCharacterSamples) playSample(FeedbackSampleType.TextAddCaps); else @@ -124,6 +129,13 @@ namespace osu.Game.Graphics.UserInterface playSample(FeedbackSampleType.TextRemove); } + protected override void NotifyInputError() + { + base.NotifyInputError(); + + playSample(FeedbackSampleType.TextInvalid); + } + protected override void OnTextCommitted(bool textChanged) { base.OnTextCommitted(textChanged); From b5ec7d06dda29ec8463d9aac8cbe3987c7e9e93b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 31 Aug 2022 19:49:04 +0900 Subject: [PATCH 0826/2686] Add auto-skip setting Default to auto skip --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 5 ++++- .../Online/Multiplayer/MultiplayerRoomSettings.cs | 9 +++++++-- osu.Game/Online/Rooms/Room.cs | 5 +++++ .../Match/MultiplayerMatchSettingsOverlay.cs | 13 ++++++++++++- osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs | 3 +++ 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 04b87c19da..364309ffe4 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -265,8 +265,9 @@ namespace osu.Game.Online.Multiplayer /// The type of the match, if any. /// The new queue mode, if any. /// The new auto-start countdown duration, if any. + /// The new auto-skip setting. public Task ChangeSettings(Optional name = default, Optional password = default, Optional matchType = default, Optional queueMode = default, - Optional autoStartDuration = default) + Optional autoStartDuration = default, Optional autoSkip = default) { if (Room == null) throw new InvalidOperationException("Must be joined to a match to change settings."); @@ -278,6 +279,7 @@ namespace osu.Game.Online.Multiplayer MatchType = matchType.GetOr(Room.Settings.MatchType), QueueMode = queueMode.GetOr(Room.Settings.QueueMode), AutoStartDuration = autoStartDuration.GetOr(Room.Settings.AutoStartDuration), + AutoSkip = autoSkip.GetOr(Room.Settings.AutoSkip) }); } @@ -739,6 +741,7 @@ namespace osu.Game.Online.Multiplayer APIRoom.QueueMode.Value = Room.Settings.QueueMode; APIRoom.AutoStartDuration.Value = Room.Settings.AutoStartDuration; APIRoom.CurrentPlaylistItem.Value = APIRoom.Playlist.Single(item => item.ID == settings.PlaylistItemId); + APIRoom.AutoSkip.Value = Room.Settings.AutoSkip; RoomUpdated?.Invoke(); } diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs index 356acb427c..c73b02874e 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs @@ -29,6 +29,9 @@ namespace osu.Game.Online.Multiplayer [Key(5)] public TimeSpan AutoStartDuration { get; set; } + [Key(6)] + public bool AutoSkip { get; set; } + [IgnoreMember] public bool AutoStartEnabled => AutoStartDuration != TimeSpan.Zero; @@ -42,7 +45,8 @@ namespace osu.Game.Online.Multiplayer && PlaylistItemId == other.PlaylistItemId && MatchType == other.MatchType && QueueMode == other.QueueMode - && AutoStartDuration == other.AutoStartDuration; + && AutoStartDuration == other.AutoStartDuration + && AutoSkip == other.AutoSkip; } public override string ToString() => $"Name:{Name}" @@ -50,6 +54,7 @@ namespace osu.Game.Online.Multiplayer + $" Type:{MatchType}" + $" Item:{PlaylistItemId}" + $" Queue:{QueueMode}" - + $" Start:{AutoStartDuration}"; + + $" Start:{AutoStartDuration}" + + $" AutoSkip:{AutoSkip}"; } } diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 3a24fa02a8..33397a237f 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -159,6 +159,10 @@ namespace osu.Game.Online.Rooms set => MaxAttempts.Value = value; } + [Cached] + [JsonProperty("auto_skip")] + public readonly Bindable AutoSkip = new Bindable(true); + public Room() { Password.BindValueChanged(p => HasPassword.Value = !string.IsNullOrEmpty(p.NewValue)); @@ -195,6 +199,7 @@ namespace osu.Game.Online.Rooms DifficultyRange.Value = other.DifficultyRange.Value; PlaylistItemStats.Value = other.PlaylistItemStats.Value; CurrentPlaylistItem.Value = other.CurrentPlaylistItem.Value; + AutoSkip.Value = other.AutoSkip.Value; if (EndDate.Value != null && DateTimeOffset.Now >= EndDate.Value) Status.Value = new RoomStatusEnded(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 3aa879dde0..3d6127e8e7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -63,6 +63,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match public MatchTypePicker TypePicker; public OsuEnumDropdown QueueModeDropdown; public OsuTextBox PasswordTextBox; + public OsuCheckbox AutoSkipCheckbox; public TriangleButton ApplyButton; public OsuSpriteText ErrorText; @@ -249,6 +250,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match LengthLimit = 255, }, }, + new Section("Other") + { + Child = AutoSkipCheckbox = new OsuCheckbox + { + LabelText = "Automatically skip the beatmap intro" + } + } } } }, @@ -343,6 +351,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match Password.BindValueChanged(password => PasswordTextBox.Text = password.NewValue ?? string.Empty, true); QueueMode.BindValueChanged(mode => QueueModeDropdown.Current.Value = mode.NewValue, true); AutoStartDuration.BindValueChanged(duration => startModeDropdown.Current.Value = (StartMode)(int)duration.NewValue.TotalSeconds, true); + AutoSkip.BindValueChanged(autoSkip => AutoSkipCheckbox.Current.Value = autoSkip.NewValue, true); operationInProgress.BindTo(ongoingOperationTracker.InProgress); operationInProgress.BindValueChanged(v => @@ -390,7 +399,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match password: PasswordTextBox.Text, matchType: TypePicker.Current.Value, queueMode: QueueModeDropdown.Current.Value, - autoStartDuration: autoStartDuration) + autoStartDuration: autoStartDuration, + autoSkip: AutoSkipCheckbox.Current.Value) .ContinueWith(t => Schedule(() => { if (t.IsCompletedSuccessfully) @@ -406,6 +416,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match room.Password.Value = PasswordTextBox.Current.Value; room.QueueMode.Value = QueueModeDropdown.Current.Value; room.AutoStartDuration.Value = autoStartDuration; + room.AutoSkip.Value = AutoSkipCheckbox.Current.Value; if (int.TryParse(MaxParticipantsField.Text, out int max)) room.MaxParticipants.Value = max; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index 0bf5f2604c..50ad3228e5 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -86,6 +86,9 @@ namespace osu.Game.Screens.OnlinePlay [Resolved(typeof(Room))] protected Bindable AutoStartDuration { get; private set; } + [Resolved(typeof(Room))] + protected Bindable AutoSkip { get; private set; } + [Resolved(CanBeNull = true)] private IBindable subScreenSelectedItem { get; set; } From c852c54055c17537cf91242f0ab970f41ba76f71 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 31 Aug 2022 19:50:16 +0900 Subject: [PATCH 0827/2686] Consume auto skip setting during play --- osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 3 ++- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index a82da7b185..773e68162e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -61,7 +61,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { AllowPause = false, AllowRestart = false, - AllowSkipping = false, + AllowSkipping = room.AutoSkip.Value, + AutomaticallySkipIntro = room.AutoSkip.Value }) { this.users = users; diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index a9fcab063c..6373633b5a 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -363,7 +363,7 @@ namespace osu.Game.Screens.Play return; CurrentPlayer = createPlayer(); - CurrentPlayer.Configuration.AutomaticallySkipIntro = quickRestart; + CurrentPlayer.Configuration.AutomaticallySkipIntro |= quickRestart; CurrentPlayer.RestartCount = restartCount++; CurrentPlayer.RestartRequested = restartRequested; From 50e8052f0706d00cb9cb8fae11d140566acb1e92 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 22:08:20 +0900 Subject: [PATCH 0828/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index bff3627af7..85857771a5 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5fc69e475f..f757fd77b9 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index f763e411be..9fcc3753eb 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + From 6af8143c8caed96fbfb18fcd02c226cb311a18bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 22:34:07 +0900 Subject: [PATCH 0829/2686] Fix typing of new setting to allow it to be visible to tools export --- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index b48f0b4ccd..5e2a92e5e9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Mods }; [SettingSource("Metronome ticks", "Whether a metronome beat should play in the background")] - public BindableBool Metronome { get; } = new BindableBool(true); + public Bindable Metronome { get; } = new BindableBool(true); #region Constants From ba20044af499ea5555e1cfc61e91ab64630a0cad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 31 Aug 2022 23:24:39 +0900 Subject: [PATCH 0830/2686] Fix missing nullability consideraition --- .../Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index b845b85e1f..16d564f0ee 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -194,7 +194,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("notification arrived", () => notificationOverlay.Verify(n => n.Post(It.IsAny()), Times.Once)); - AddStep("run notification action", () => lastNotification.Activated()); + AddStep("run notification action", () => lastNotification.Activated?.Invoke()); AddAssert("overlay shown", () => overlay.State.Value == Visibility.Visible); AddAssert("is resumed", () => overlay.CurrentScreen is ScreenUIScale); From eb02a9a14442d970b2b710b69e749abaa7cd93eb Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Wed, 31 Aug 2022 22:04:28 +0100 Subject: [PATCH 0831/2686] Removed GrowToFItContainer --- .../UprightAspectMaintainingContainer.cs | 84 ------------------- 1 file changed, 84 deletions(-) diff --git a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs index 8efc29c83c..300b5bd4b4 100644 --- a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs +++ b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs @@ -24,27 +24,6 @@ namespace osu.Game.Graphics.Containers /// public ScaleMode Scaling { get; set; } = ScaleMode.Vertical; - /// - /// If this is true, all wrapper containers will be set to grow with their content - /// and not shrink back, this is used to fix the position of children that change - /// in size when using AutoSizeAxes. - /// - public bool GrowToFitContent - { - get => growToFitContent; - set - { - if (growToFitContent != value) - { - foreach (GrowToFitContainer c in Children) - c.GrowToFitContentUpdated = true; - growToFitContent = value; - } - } - } - - private bool growToFitContent = true; - private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawInfo, InvalidationSource.Parent); public UprightAspectMaintainingContainer() @@ -63,15 +42,6 @@ namespace osu.Game.Graphics.Containers } } - public override void Add(Drawable drawable) - { - var wrapper = new GrowToFitContainer(); - wrapper.Wrap(drawable); - wrapper.AutoSizeAxes = Axes.None; - drawable.Origin = drawable.Anchor = Anchor.Centre; - base.Add(wrapper); - } - /// /// Keeps the drawable upright and unstretched preventing it from being rotated, sheared, scaled or flipped with its Parent. /// @@ -127,60 +97,6 @@ namespace osu.Game.Graphics.Containers Scale = new Vector2(sx * usedScale, sy * usedScale); } - - public class GrowToFitContainer : Container - { - private readonly LayoutValue layout = new LayoutValue(Invalidation.RequiredParentSizeToFit, InvalidationSource.Child); - - private Vector2 maxChildSize; - - public bool GrowToFitContentUpdated { get; set; } - - public GrowToFitContainer() - { - AddLayout(layout); - } - - protected override void Update() - { - UprightAspectMaintainingContainer parent = (UprightAspectMaintainingContainer)Parent; - - if (!layout.IsValid || GrowToFitContentUpdated) - { - if ((Child.RelativeSizeAxes & Axes.X) != 0) - RelativeSizeAxes |= Axes.X; - else - { - if (parent.GrowToFitContent) - Width = Math.Max(Child.Width * Child.Scale.X, maxChildSize.X); - else - Width = Child.Width * Child.Scale.X; - } - - if ((Child.RelativeSizeAxes & Axes.Y) != 0) - RelativeSizeAxes |= Axes.Y; - else - { - if (parent.GrowToFitContent) - Height = Math.Max(Child.Height * Child.Scale.Y, maxChildSize.Y); - else - Height = Child.Height * Child.Scale.Y; - } - - // reset max_child_size or update it - if (!parent.GrowToFitContent) - maxChildSize = Child.Size; - else - { - maxChildSize.X = MathF.Max(maxChildSize.X, Child.Size.X); - maxChildSize.Y = MathF.Max(maxChildSize.Y, Child.Size.Y); - } - - GrowToFitContentUpdated = false; - layout.Validate(); - } - } - } } public enum ScaleMode From 4a630b53846f64d1f1d5fd96569991fdd316b246 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Wed, 31 Aug 2022 22:05:06 +0100 Subject: [PATCH 0832/2686] Implemented SizePreservingSpriteText --- .../Sprites/SizePreservingTextSprite.cs | 107 ++++++++++++++++++ osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 12 +- 2 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Graphics/Sprites/SizePreservingTextSprite.cs diff --git a/osu.Game/Graphics/Sprites/SizePreservingTextSprite.cs b/osu.Game/Graphics/Sprites/SizePreservingTextSprite.cs new file mode 100644 index 0000000000..11b81b26fd --- /dev/null +++ b/osu.Game/Graphics/Sprites/SizePreservingTextSprite.cs @@ -0,0 +1,107 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Graphics.Sprites +{ + public class SizePreservingSpriteText : CompositeDrawable + { + private readonly OsuSpriteText text = new OsuSpriteText(); + + private Vector2 maximumSize; + + public SizePreservingSpriteText(Vector2? minimumSize = null) + { + text.Origin = Anchor.Centre; + text.Anchor = Anchor.Centre; + + AddInternal(text); + maximumSize = minimumSize ?? Vector2.Zero; + } + + protected override void Update() + { + Width = maximumSize.X = MathF.Max(maximumSize.X, text.Width); + Height = maximumSize.Y = MathF.Max(maximumSize.Y, text.Height); + } + + public new Axes AutoSizeAxes + { + get => Axes.None; + set => throw new InvalidOperationException("You can't set AutoSizeAxes of this container"); + } + + /// + /// Gets or sets the text to be displayed. + /// + public LocalisableString Text + { + get => text.Text; + set => text.Text = value; + } + + /// + /// Contains information on the font used to display the text. + /// + public FontUsage Font + { + get => text.Font; + set => text.Font = value; + } + + /// + /// True if a shadow should be displayed around the text. + /// + public bool Shadow + { + get => text.Shadow; + set => text.Shadow = value; + } + + /// + /// The colour of the shadow displayed around the text. A shadow will only be displayed if the property is set to true. + /// + public Color4 ShadowColour + { + get => text.ShadowColour; + set => text.ShadowColour = value; + } + + /// + /// The offset of the shadow displayed around the text. A shadow will only be displayed if the property is set to true. + /// + public Vector2 ShadowOffset + { + get => text.ShadowOffset; + set => text.ShadowOffset = value; + } + + /// + /// True if the 's vertical size should be equal to (the full height) or precisely the size of used characters. + /// Set to false to allow better centering of individual characters/numerals/etc. + /// + public bool UseFullGlyphHeight + { + get => text.UseFullGlyphHeight; + set => text.UseFullGlyphHeight = value; + } + + public override bool IsPresent => text.IsPresent; + + public override string ToString() => text.ToString(); + + public float LineBaseHeight => text.LineBaseHeight; + + public IEnumerable FilterTerms => text.FilterTerms; + } +} diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index 81abfce0c7..d0eb8f8ca1 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -15,9 +15,9 @@ namespace osu.Game.Screens.Play.HUD { public class SongProgressInfo : Container { - private OsuSpriteText timeCurrent; - private OsuSpriteText timeLeft; - private OsuSpriteText progress; + private SizePreservingSpriteText timeCurrent; + private SizePreservingSpriteText timeLeft; + private SizePreservingSpriteText progress; private double startTime; private double endTime; @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Play.HUD AutoSizeAxes = Axes.Both, Scaling = ScaleMode.Vertical, ScalingFactor = 0.5f, - Child = timeCurrent = new OsuSpriteText + Child = timeCurrent = new SizePreservingSpriteText { Origin = Anchor.Centre, Anchor = Anchor.Centre, @@ -83,7 +83,7 @@ namespace osu.Game.Screens.Play.HUD AutoSizeAxes = Axes.Both, Scaling = ScaleMode.Vertical, ScalingFactor = 0.5f, - Child = progress = new OsuSpriteText + Child = progress = new SizePreservingSpriteText { Origin = Anchor.Centre, Anchor = Anchor.Centre, @@ -104,7 +104,7 @@ namespace osu.Game.Screens.Play.HUD AutoSizeAxes = Axes.Both, Scaling = ScaleMode.Vertical, ScalingFactor = 0.5f, - Child = timeLeft = new OsuSpriteText + Child = timeLeft = new SizePreservingSpriteText { Origin = Anchor.Centre, Anchor = Anchor.Centre, From a548b28158c018d738d29fd2a2e94b70c00673f7 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Wed, 31 Aug 2022 22:05:46 +0100 Subject: [PATCH 0833/2686] Added test scene for SizePreservingSpriteText --- .../TestSceneGrowToFitContent.cs | 175 ------------------ .../TestSceneSizePreservingTextSprite.cs | 96 ++++++++++ 2 files changed, 96 insertions(+), 175 deletions(-) delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneGrowToFitContent.cs create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingTextSprite.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneGrowToFitContent.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneGrowToFitContent.cs deleted file mode 100644 index bcff992f9d..0000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneGrowToFitContent.cs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Collections.Generic; -using NUnit.Framework; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics; -using System.Linq; -using osuTK; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public class TestSceneGrowToFitContent : OsuGridTestScene - { - private readonly List parentContainers = new List(); - private readonly List childContainers = new List(); - private readonly List texts = new List(); - - public TestSceneGrowToFitContent() - : base(1, 2) - { - for (int i = 0; i < 2; i++) - { - OsuSpriteText text; - UprightAspectMaintainingContainer childContainer; - Container parentContainer = new Container - { - Origin = Anchor.BottomRight, - Anchor = Anchor.BottomCentre, - AutoSizeAxes = Axes.Both, - Rotation = 45, - Y = -200, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Colour4.Red, - }, - childContainer = new UprightAspectMaintainingContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Colour4.Blue, - }, - text = new OsuSpriteText - { - Text = "Text", - Font = OsuFont.GetFont(Typeface.Venera, weight: FontWeight.Bold, size: 40), - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - }, - } - }, - } - }; - - Container cellInfo = new Container - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Margin = new MarginPadding - { - Top = 100, - }, - Child = new OsuSpriteText - { - Text = (i == 0) ? "GrowToFitContent == true" : "GrowToFitContent == false", - Font = OsuFont.GetFont(Typeface.Inter, weight: FontWeight.Bold, size: 40), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - }, - }; - - parentContainers.Add(parentContainer); - childContainers.Add(childContainer); - texts.Add(text); - Cell(i).Add(cellInfo); - Cell(i).Add(parentContainer); - } - } - - [Test] - public void TestResizeText() - { - AddStep("reset...", () => - { - childContainers[0].GrowToFitContent = false; - childContainers[1].GrowToFitContent = false; - }); - - AddStep("setup...", () => - { - childContainers[0].GrowToFitContent = true; - childContainers[1].GrowToFitContent = false; - }); - - for (int i = 0; i < 10; i++) - { - AddStep("Add Character", () => - { - foreach (int j in Enumerable.Range(0, parentContainers.Count)) - { - texts[j].Text += "."; - } - }); - } - - for (int i = 0; i < 10; i++) - { - AddStep("Remove Character", () => - { - foreach (int j in Enumerable.Range(0, parentContainers.Count)) - { - string text = texts[j].Text.ToString(); - texts[j].Text = text.Remove(text.Length - 1, 1); - } - }); - } - } - - [Test] - public void TestScaleText() - { - AddStep("reset...", () => - { - childContainers[0].GrowToFitContent = false; - childContainers[1].GrowToFitContent = false; - }); - - AddStep("setup...", () => - { - childContainers[0].GrowToFitContent = true; - childContainers[1].GrowToFitContent = false; - }); - - for (int i = 0; i < 1; i++) - { - AddStep("Big text", scaleUp); - - AddWaitStep("wait...", 5); - - AddStep("Small text", scaleDown); - } - } - - private void scaleUp() - { - foreach (int j in Enumerable.Range(0, parentContainers.Count)) - { - texts[j].ScaleTo(new Vector2(2, 2), 1000); - } - } - - private void scaleDown() - { - foreach (int j in Enumerable.Range(0, parentContainers.Count)) - { - texts[j].ScaleTo(new Vector2(1, 1), 1000); - } - } - } -} diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingTextSprite.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingTextSprite.cs new file mode 100644 index 0000000000..a5e70a54f8 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingTextSprite.cs @@ -0,0 +1,96 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System; +using System.Collections.Generic; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneSizePreservingSpriteText : OsuGridTestScene + { + private readonly List parentContainers = new List(); + private readonly List childContainers = new List(); + private readonly OsuSpriteText osuSpriteText = new OsuSpriteText(); + private readonly SizePreservingSpriteText sizePreservingSpriteText = new SizePreservingSpriteText(); + + + public TestSceneSizePreservingSpriteText() + : base(1, 2) + { + for (int i = 0; i < 2; i++) + { + UprightAspectMaintainingContainer childContainer; + Container parentContainer = new Container + { + Origin = Anchor.BottomRight, + Anchor = Anchor.BottomCentre, + AutoSizeAxes = Axes.Both, + Rotation = 45, + Y = -200, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Colour4.Red, + }, + childContainer = new UprightAspectMaintainingContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Colour4.Blue, + }, + } + }, + } + }; + + Container cellInfo = new Container + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Margin = new MarginPadding + { + Top = 100, + }, + Child = new OsuSpriteText + { + Text = (i == 0) ? "OsuSpriteText" : "SizePreservingSpriteText", + Font = OsuFont.GetFont(Typeface.Inter, weight: FontWeight.Bold, size: 40), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + }, + }; + + parentContainers.Add(parentContainer); + childContainers.Add(childContainer); + Cell(i).Add(cellInfo); + Cell(i).Add(parentContainer); + } + + childContainers[0].Add(osuSpriteText); + childContainers[1].Add(sizePreservingSpriteText); + osuSpriteText.Font = sizePreservingSpriteText.Font = OsuFont.GetFont(Typeface.Venera, weight: FontWeight.Bold, size: 20); + } + + protected override void Update() + { + base.Update(); + osuSpriteText.Text = sizePreservingSpriteText.Text = DateTime.Now.ToString(); + } + } +} From 921a9ef895f4e23f81775bb3f252c85916d9e670 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Wed, 31 Aug 2022 22:18:52 +0100 Subject: [PATCH 0834/2686] clean up --- .../Visual/UserInterface/TestSceneSizePreservingTextSprite.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingTextSprite.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingTextSprite.cs index a5e70a54f8..69f5015af6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingTextSprite.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingTextSprite.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics; @@ -21,7 +22,6 @@ namespace osu.Game.Tests.Visual.UserInterface private readonly OsuSpriteText osuSpriteText = new OsuSpriteText(); private readonly SizePreservingSpriteText sizePreservingSpriteText = new SizePreservingSpriteText(); - public TestSceneSizePreservingSpriteText() : base(1, 2) { @@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual.UserInterface protected override void Update() { base.Update(); - osuSpriteText.Text = sizePreservingSpriteText.Text = DateTime.Now.ToString(); + osuSpriteText.Text = sizePreservingSpriteText.Text = DateTime.Now.ToString(CultureInfo.InvariantCulture); } } } From d70208fcf189506ccefcce7617e9534cfc5b9e5c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 1 Sep 2022 14:14:22 +0900 Subject: [PATCH 0835/2686] Default to off --- osu.Game/Online/Rooms/Room.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 33397a237f..adfd4c226a 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -161,7 +161,7 @@ namespace osu.Game.Online.Rooms [Cached] [JsonProperty("auto_skip")] - public readonly Bindable AutoSkip = new Bindable(true); + public readonly Bindable AutoSkip = new Bindable(); public Room() { From 148e487c025421ea8596fd6e817519ddc6f90b58 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Sep 2022 19:59:20 +0900 Subject: [PATCH 0836/2686] Add failing test of date submitted search failing --- .../SongSelect/TestSceneBeatmapCarousel.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index c3e485d56b..c9e63fa621 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -494,6 +494,43 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Something is selected", () => carousel.SelectedBeatmapInfo != null); } + [Test] + public void TestSortingDateSubmitted() + { + var sets = new List(); + const string zzz_string = "zzzzz"; + + AddStep("Populuate beatmap sets", () => + { + sets.Clear(); + + for (int i = 0; i < 20; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(5); + + if (i >= 2 && i < 10) + set.DateSubmitted = DateTimeOffset.Now.AddMinutes(i); + if (i < 5) + set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string); + + sets.Add(set); + } + }); + + loadBeatmaps(sets); + + AddStep("Sort by date submitted", () => carousel.Filter(new FilterCriteria { Sort = SortMode.DateSubmitted }, false)); + checkVisibleItemCount(diff: false, count: 8); + checkVisibleItemCount(diff: true, count: 5); + AddStep("Sort by date submitted and string", () => carousel.Filter(new FilterCriteria + { + Sort = SortMode.DateSubmitted, + SearchText = zzz_string + }, false)); + checkVisibleItemCount(diff: false, count: 3); + checkVisibleItemCount(diff: true, count: 5); + } + [Test] public void TestSorting() { From 15246236242e14304a6ae6df5a84f36403b67e81 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Sep 2022 19:27:33 +0900 Subject: [PATCH 0837/2686] Fix back-to-front filter logic Was copied across from a place which was checking for `match` and applied verbatim to a place that was `filter`. Which are polar opposites. --- osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs index 6c134a4ab8..9a4319c6b2 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmapSet.cs @@ -129,12 +129,13 @@ namespace osu.Game.Screens.Select.Carousel public override void Filter(FilterCriteria criteria) { base.Filter(criteria); - bool match = Items.All(i => i.Filtered.Value); - match &= criteria.Sort != SortMode.DateRanked || BeatmapSet?.DateRanked != null; - match &= criteria.Sort != SortMode.DateSubmitted || BeatmapSet?.DateSubmitted != null; + bool filtered = Items.All(i => i.Filtered.Value); - Filtered.Value = match; + filtered |= criteria.Sort == SortMode.DateRanked && BeatmapSet?.DateRanked == null; + filtered |= criteria.Sort == SortMode.DateSubmitted && BeatmapSet?.DateSubmitted == null; + + Filtered.Value = filtered; } public override string ToString() => BeatmapSet.ToString(); From a27743126639d51619c29b68654e5f50ab053a03 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 1 Sep 2022 21:10:36 +0900 Subject: [PATCH 0838/2686] Add has_replay and legacy_score_id to SoloScoreInfo --- osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index a8cedabd48..659b661ef0 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -18,7 +18,7 @@ namespace osu.Game.Online.API.Requests.Responses [Serializable] public class SoloScoreInfo : IHasOnlineID { - [JsonProperty("replay")] + [JsonProperty("has_replay")] public bool HasReplay { get; set; } [JsonProperty("beatmap_id")] @@ -83,6 +83,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("legacy_total_score")] public int? LegacyTotalScore { get; set; } + [JsonProperty("legacy_score_id")] + public uint? LegacyScoreId { get; set; } + #region osu-web API additions (not stored to database). [JsonProperty("id")] @@ -117,7 +120,6 @@ namespace osu.Game.Online.API.Requests.Responses public bool ShouldSerializeBeatmapSet() => false; public bool ShouldSerializePP() => false; public bool ShouldSerializeOnlineID() => false; - public bool ShouldSerializeHasReplay() => false; #endregion From 8866250cff5742c2604ab7b3532044ae3b6adcef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Sep 2022 21:42:38 +0900 Subject: [PATCH 0839/2686] Fix seasonal background not being unloaded when changing setting to "Never" Closes #20065. --- .../Backgrounds/SeasonalBackgroundLoader.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index 99af95b5fe..5c98e22818 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -38,21 +38,19 @@ namespace osu.Game.Graphics.Backgrounds private void load(OsuConfigManager config, SessionStatics sessionStatics) { seasonalBackgroundMode = config.GetBindable(OsuSetting.SeasonalBackgroundMode); - seasonalBackgroundMode.BindValueChanged(_ => triggerSeasonalBackgroundChanged()); + seasonalBackgroundMode.BindValueChanged(_ => SeasonalBackgroundChanged?.Invoke()); seasonalBackgrounds = sessionStatics.GetBindable(Static.SeasonalBackgrounds); - seasonalBackgrounds.BindValueChanged(_ => triggerSeasonalBackgroundChanged()); + seasonalBackgrounds.BindValueChanged(_ => + { + if (shouldShowSeasonal) + SeasonalBackgroundChanged?.Invoke(); + }); apiState.BindTo(api.State); apiState.BindValueChanged(fetchSeasonalBackgrounds, true); } - private void triggerSeasonalBackgroundChanged() - { - if (shouldShowSeasonal) - SeasonalBackgroundChanged?.Invoke(); - } - private void fetchSeasonalBackgrounds(ValueChangedEvent stateChanged) { if (seasonalBackgrounds.Value != null || stateChanged.NewValue != APIState.Online) From d3ae60ec6d38ce3dd55d588833a4edbfc8a7e274 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Sep 2022 22:02:58 +0900 Subject: [PATCH 0840/2686] Fix tournament population failure when beatmap is not found on server --- osu.Game.Tournament/Models/TournamentBeatmap.cs | 3 +-- osu.Game/Beatmaps/BeatmapSetOnlineCovers.cs | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game.Tournament/Models/TournamentBeatmap.cs b/osu.Game.Tournament/Models/TournamentBeatmap.cs index 274fddc490..7f57b6a151 100644 --- a/osu.Game.Tournament/Models/TournamentBeatmap.cs +++ b/osu.Game.Tournament/Models/TournamentBeatmap.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Extensions.ObjectExtensions; using osu.Game.Beatmaps; using osu.Game.Extensions; using osu.Game.Online.API.Requests.Responses; @@ -41,7 +40,7 @@ namespace osu.Game.Tournament.Models StarRating = beatmap.StarRating; Metadata = beatmap.Metadata; Difficulty = beatmap.Difficulty; - Covers = beatmap.BeatmapSet.AsNonNull().Covers; + Covers = beatmap.BeatmapSet?.Covers ?? new BeatmapSetOnlineCovers(); } public bool Equals(IBeatmapInfo? other) => other is TournamentBeatmap b && this.MatchesOnlineID(b); diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineCovers.cs b/osu.Game/Beatmaps/BeatmapSetOnlineCovers.cs index b76496b145..aad31befa8 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineCovers.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineCovers.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. -#nullable disable - using Newtonsoft.Json; namespace osu.Game.Beatmaps From 22c18d9a81cfdb1e777b09ff4bfb6fa42170be67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Sep 2022 23:03:28 +0900 Subject: [PATCH 0841/2686] 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 85857771a5..219912425f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f757fd77b9..43e3076f5c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 9fcc3753eb..0f0bf2848c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From c9dec473d3e4ef96d093da510b2b4f666512ed05 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Sep 2022 23:05:07 +0900 Subject: [PATCH 0842/2686] Update virtual track logic to match framework changes --- osu.Game/Tests/Visual/OsuTestScene.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 5a297fd109..5055153691 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -404,9 +404,9 @@ namespace osu.Game.Tests.Visual public IEnumerable GetAvailableResources() => throw new NotImplementedException(); - public Track GetVirtual(double length = double.PositiveInfinity) + public Track GetVirtual(double length = double.PositiveInfinity, string name = "virtual") { - var track = new TrackVirtualManual(referenceClock) { Length = length }; + var track = new TrackVirtualManual(referenceClock, name) { Length = length }; AddItem(track); return track; } @@ -421,7 +421,8 @@ namespace osu.Game.Tests.Visual private bool running; - public TrackVirtualManual(IFrameBasedClock referenceClock) + public TrackVirtualManual(IFrameBasedClock referenceClock, string name = "virtual") + : base(name) { this.referenceClock = referenceClock; Length = double.PositiveInfinity; From 7eaa4c5ccd89ff88c691f9bddf7cc30eea8a64f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Sep 2022 23:05:34 +0900 Subject: [PATCH 0843/2686] Update new usages of `Remove` / `RemoveInternal` --- osu.Game/Overlays/NotificationOverlayToastTray.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index 4417b5e0d0..c47a61eac1 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -126,13 +126,13 @@ namespace osu.Game.Overlays Debug.Assert(notification.Parent == toastFlow); // Temporarily remove from flow so we can animate the position off to the right. - toastFlow.Remove(notification); + toastFlow.Remove(notification, false); AddInternal(notification); notification.MoveToOffset(new Vector2(400, 0), NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint); notification.FadeOut(NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint).OnComplete(_ => { - RemoveInternal(notification); + RemoveInternal(notification, false); ForwardNotificationToPermanentStore?.Invoke(notification); notification.FadeIn(300, Easing.OutQuint); From 23d5e8b286af37ec6dd4c79e4b837a9df5d2c136 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Sep 2022 23:45:59 +0900 Subject: [PATCH 0844/2686] Fix beat sync components stopping after beatmap change Not an amazing fix, but it seems to work and would rather get this in ASAP rather than trying to fix at a framework level. Closes #20059. --- osu.Game/OsuGameBase.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 97142d5472..c95a281f09 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -390,6 +390,11 @@ namespace osu.Game var framedClock = new FramedClock(beatmap.Track); beatmapClock.ChangeSource(framedClock); + + // Normally the internal decoupled clock will seek the *track* to the decoupled time, but we blocked this. + // It won't behave nicely unless we also set it to the track's time. + // Probably another thing which should be fixed in the decoupled mess (or just replaced). + beatmapClock.Seek(beatmap.Track.CurrentTime); } protected virtual void InitialiseFonts() From d13e353a534a8ee93493f019d9640da8e2bb7183 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 03:02:27 +0900 Subject: [PATCH 0845/2686] Fix double colour application in update progress notification I'd like to restore it to yellow, but let's clean the slate first. --- osu.Desktop/Updater/SquirrelUpdateManager.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index d53db6c516..6f45237522 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -6,8 +6,6 @@ using System.Runtime.Versioning; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Logging; using osu.Game; @@ -15,7 +13,6 @@ using osu.Game.Graphics; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osuTK; -using osuTK.Graphics; using Squirrel; using Squirrel.SimpleSplat; @@ -177,17 +174,11 @@ namespace osu.Desktop.Updater { IconContent.AddRange(new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow) - }, new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = FontAwesome.Solid.Upload, - Colour = Color4.White, Size = new Vector2(20), } }); From 9645bfe7085fccfd6c79156bf1e9378576545f82 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 2 Sep 2022 16:27:25 +0900 Subject: [PATCH 0846/2686] Bump difficulty calculator versions --- osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 5d30d33190..63e61f17e3 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty private readonly bool isForCurrentRuleset; private readonly double originalOverallDifficulty; - public override int Version => 20220701; + public override int Version => 20220902; public ManiaDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 0ebfb9a283..6ef17d47c0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private const double difficulty_multiplier = 0.0675; private double hitWindowGreat; - public override int Version => 20220701; + public override int Version => 20220902; public OsuDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index ea2f04a3d9..2b0b563323 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { private const double difficulty_multiplier = 1.35; - public override int Version => 20220701; + public override int Version => 20220902; public TaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) From a70fc10d06ffb1f03ee0aaf895a5eeb978da5333 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 16:30:04 +0900 Subject: [PATCH 0847/2686] Fix mock track construction failure --- osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs index 9fdd49823e..50e6087526 100644 --- a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs @@ -7,10 +7,12 @@ using System.Linq; using Moq; using NUnit.Framework; using osu.Framework.Audio.Track; +using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Checks; using osu.Game.Rulesets.Objects; +using osu.Game.Tests.Visual; namespace osu.Game.Tests.Editing.Checks { @@ -109,7 +111,7 @@ namespace osu.Game.Tests.Editing.Checks /// The bitrate of the audio file the beatmap uses. private Mock getMockWorkingBeatmap(int? audioBitrate) { - var mockTrack = new Mock(); + var mockTrack = new Mock(new FramedClock(), "virtual"); mockTrack.SetupGet(t => t.Bitrate).Returns(audioBitrate); var mockWorkingBeatmap = new Mock(); From 8c50ccc48e973e86c2a3381d7fae69ae5e8c401a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 16:37:39 +0900 Subject: [PATCH 0848/2686] Fix incorrect specification in `SectionsContainer` --- osu.Game/Graphics/Containers/SectionsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index b8a8ea79cc..583f1385c1 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -35,7 +35,7 @@ namespace osu.Game.Graphics.Containers if (value == expandableHeader) return; if (expandableHeader != null) - RemoveInternal(expandableHeader, false); + RemoveInternal(expandableHeader, true); expandableHeader = value; From b10026993ab4a9f2b55db30fc479a63c1a2f760d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 2 Sep 2022 16:40:32 +0900 Subject: [PATCH 0849/2686] Don't serialise has_replay --- osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 659b661ef0..d7b97cdddf 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -18,9 +18,6 @@ namespace osu.Game.Online.API.Requests.Responses [Serializable] public class SoloScoreInfo : IHasOnlineID { - [JsonProperty("has_replay")] - public bool HasReplay { get; set; } - [JsonProperty("beatmap_id")] public int BeatmapID { get; set; } @@ -114,12 +111,16 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("pp")] public double? PP { get; set; } + [JsonProperty("has_replay")] + public bool HasReplay { get; set; } + public bool ShouldSerializeID() => false; public bool ShouldSerializeUser() => false; public bool ShouldSerializeBeatmap() => false; public bool ShouldSerializeBeatmapSet() => false; public bool ShouldSerializePP() => false; public bool ShouldSerializeOnlineID() => false; + public bool ShouldSerializeHasReplay() => false; #endregion From 65baf73d97b3e4b4bfcc22ffb5a1971054c306f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 16:50:28 +0900 Subject: [PATCH 0850/2686] Add test scene --- .../Editing/TestSceneDifficultyDelete.cs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs new file mode 100644 index 0000000000..ef0c91cd90 --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs @@ -0,0 +1,67 @@ +// 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.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Storyboards; +using osu.Game.Tests.Beatmaps.IO; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Editing +{ + public class TestSceneDifficultyDelete : EditorTestScene + { + protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); + protected override bool IsolateSavingFromDatabase => false; + + [Resolved] + private OsuGameBase game { get; set; } = null!; + + [Resolved] + private BeatmapManager beatmaps { get; set; } = null!; + + private BeatmapSetInfo importedBeatmapSet = null!; + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null!) + => beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First()); + + public override void SetUpSteps() + { + AddStep("import test beatmap", () => importedBeatmapSet = BeatmapImportHelper.LoadOszIntoOsu(game, virtualTrack: true).GetResultSafely()); + base.SetUpSteps(); + } + + [Test] + public void TestDifficultyDelete() + { + string lastDiff = null!; + AddStep("remember selected difficulty", () => lastDiff = EditorBeatmap.BeatmapInfo.DifficultyName); + + AddStep("click File", () => this.ChildrenOfType().First().TriggerClick()); + AddStep("click Delete", () => this.ChildrenOfType().Single(deleteMenuItemPredicate).TriggerClick()); + AddStep("confirm", () => InputManager.Key(Key.Number2)); + + AddAssert("difficulty is deleted", () => + { + if (lastDiff == null!) throw new NullReferenceException(); + + var newSet = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First(), true).BeatmapSetInfo; + return newSet.Beatmaps.All(x => x.DifficultyName != lastDiff); + }); + } + + private bool deleteMenuItemPredicate(DrawableOsuMenuItem item) + { + return item.ChildrenOfType().Any(text => text.Text.ToString().StartsWith("Delete", StringComparison.Ordinal)); + } + } +} From 605108c938486b276a6b4c6806ccda2140771b81 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 16:58:46 +0900 Subject: [PATCH 0851/2686] Refactor/rename deletion method to read better --- osu.Game/Beatmaps/BeatmapManager.cs | 31 ++++++++++++++--------------- osu.Game/Screens/Edit/Editor.cs | 2 +- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 2baac05d8b..d784f1e627 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -364,27 +364,26 @@ namespace osu.Game.Beatmaps } /// - /// Hard-Delete a beatmap difficulty locally. + /// Delete a beatmap difficulty immediately. /// - /// is generally preferred as it keeps the local beatmap set in sync with the server. - /// The beatmap difficulty to hide. - public void DeleteLocal(BeatmapInfo beatmapInfo) + /// + /// There's no undoing this operation, as we don't have a soft-deletion flag on . + /// This may be a future consideration if there's a user requirement for undeleting support. + /// + public void DeleteDifficultyImmediately(BeatmapInfo beatmapInfo) { - Realm.Run(r => + Realm.Write(r => { - using (var transaction = r.BeginWrite()) - { - if (!beatmapInfo.IsManaged) - beatmapInfo = r.Find(beatmapInfo.ID); + if (!beatmapInfo.IsManaged) + beatmapInfo = r.Find(beatmapInfo.ID); - var setInfo = beatmapInfo.BeatmapSet!; - DeleteFile(setInfo, beatmapInfo.File!); - setInfo.Beatmaps.Remove(beatmapInfo); + Debug.Assert(beatmapInfo.BeatmapSet != null); + Debug.Assert(beatmapInfo.File != null); - var liveSetInfo = r.Find(setInfo.ID); - setInfo.CopyChangesToRealm(liveSetInfo); - transaction.Commit(); - } + var setInfo = beatmapInfo.BeatmapSet; + + DeleteFile(setInfo, beatmapInfo.File); + setInfo.Beatmaps.Remove(beatmapInfo); }); } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 10a86cdca3..24a89d124d 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -904,7 +904,7 @@ namespace osu.Game.Screens.Edit var current = playableBeatmap.BeatmapInfo; if (current is null) return; - beatmapManager.DeleteLocal(current); + beatmapManager.DeleteDifficultyImmediately(current); switchBeatmapOrExit(current.BeatmapSet); } From 9fd8067e11d4d21d39dc9e33b1e3b9df39647519 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 17:07:09 +0900 Subject: [PATCH 0852/2686] Tidy up dialog and deletion flow --- .../DeleteDifficultyConfirmationDialog.cs | 18 +++++++ osu.Game/Screens/Edit/Editor.cs | 52 ++++++++----------- .../Edit/PromptForDifficultyDeleteDialog.cs | 38 -------------- 3 files changed, 41 insertions(+), 67 deletions(-) create mode 100644 osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs delete mode 100644 osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs diff --git a/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs b/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs new file mode 100644 index 0000000000..594042b426 --- /dev/null +++ b/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs @@ -0,0 +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; +using osu.Game.Beatmaps; +using osu.Game.Overlays.Dialog; + +namespace osu.Game.Screens.Edit +{ + public class DeleteDifficultyConfirmationDialog : DeleteConfirmationDialog + { + public DeleteDifficultyConfirmationDialog(BeatmapInfo beatmapInfo, Action deleteAction) + { + BodyText = $"\"{beatmapInfo.DifficultyName}\" difficulty"; + DeleteAction = deleteAction; + } + } +} diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 24a89d124d..2e09b9a865 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -879,35 +879,6 @@ namespace osu.Game.Screens.Edit clock.SeekForward(!trackPlaying, amount); } - private void exportBeatmap() - { - Save(); - new LegacyBeatmapExporter(storage).Export(Beatmap.Value.BeatmapSetInfo); - } - - private void deleteDifficulty() - { - dialogOverlay?.Push(new PromptForDifficultyDeleteDialog(confirmDifficultyHide, confirmDifficultyDelete, () => { })); - } - - private void confirmDifficultyHide() - { - var current = playableBeatmap.BeatmapInfo; - if (current is null) return; - - beatmapManager.Hide(current); - switchBeatmapOrExit(current.BeatmapSet); - } - - private void confirmDifficultyDelete() - { - var current = playableBeatmap.BeatmapInfo; - if (current is null) return; - - beatmapManager.DeleteDifficultyImmediately(current); - switchBeatmapOrExit(current.BeatmapSet); - } - private void switchBeatmapOrExit([CanBeNull] BeatmapSetInfo setInfo) { if (setInfo is null || setInfo.Beatmaps.Count() <= 1) @@ -948,6 +919,29 @@ namespace osu.Game.Screens.Edit return fileMenuItems; } + private void exportBeatmap() + { + Save(); + new LegacyBeatmapExporter(storage).Export(Beatmap.Value.BeatmapSetInfo); + } + + private void deleteDifficulty() + { + if (dialogOverlay == null) + delete(); + else + dialogOverlay.Push(new DeleteDifficultyConfirmationDialog(Beatmap.Value.BeatmapInfo, delete)); + + void delete() + { + var current = playableBeatmap.BeatmapInfo; + if (current is null) return; + + beatmapManager.DeleteDifficultyImmediately(current); + switchBeatmapOrExit(current.BeatmapSet); + } + } + private EditorMenuItem createDifficultyCreationMenu() { var rulesetItems = new List(); diff --git a/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs b/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs deleted file mode 100644 index dcea9f1210..0000000000 --- a/osu.Game/Screens/Edit/PromptForDifficultyDeleteDialog.cs +++ /dev/null @@ -1,38 +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 osu.Framework.Graphics.Sprites; -using osu.Game.Overlays.Dialog; - -namespace osu.Game.Screens.Edit -{ - public class PromptForDifficultyDeleteDialog : PopupDialog - { - public PromptForDifficultyDeleteDialog(Action hide, Action delete, Action cancel) - { - HeaderText = "Are you sure you want to delete this difficulty?"; - - Icon = FontAwesome.Regular.TrashAlt; - - Buttons = new PopupDialogButton[] - { - new PopupDialogOkButton - { - Text = @"Hide this difficulty instead (recommended)", - Action = hide - }, - new PopupDialogDangerousButton - { - Text = @"Yes, DELETE this difficulty!", - Action = delete - }, - new PopupDialogCancelButton - { - Text = @"Oops, continue editing", - Action = cancel - }, - }; - } - } -} From 840d1c4cd59aefa26e0d3cb8e6aa8b0961e0aa51 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 17:14:48 +0900 Subject: [PATCH 0853/2686] Disable delete difficulty menu item when only one difficulty is present --- osu.Game/Screens/Edit/Editor.cs | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 2e09b9a865..5df403e643 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -895,29 +895,18 @@ namespace osu.Game.Screens.Edit lastSavedHash = changeHandler?.CurrentStateHash; } - private List createFileMenuItems() + private List createFileMenuItems() => new List { - var fileMenuItems = new List - { - new EditorMenuItem("Save", MenuItemType.Standard, () => Save()) - }; - - if (RuntimeInfo.IsDesktop) - fileMenuItems.Add(new EditorMenuItem("Export package", MenuItemType.Standard, exportBeatmap)); - - fileMenuItems.Add(new EditorMenuItemSpacer()); - - fileMenuItems.Add(createDifficultyCreationMenu()); - fileMenuItems.Add(createDifficultySwitchMenu()); - - fileMenuItems.Add(new EditorMenuItemSpacer()); - - fileMenuItems.Add(new EditorMenuItem("Delete difficulty", MenuItemType.Standard, deleteDifficulty)); - - fileMenuItems.Add(new EditorMenuItemSpacer()); - fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit)); - return fileMenuItems; - } + new EditorMenuItem("Save", MenuItemType.Standard, () => Save()), + new EditorMenuItem("Export package", MenuItemType.Standard, exportBeatmap) { Action = { Disabled = !RuntimeInfo.IsDesktop } }, + new EditorMenuItemSpacer(), + createDifficultyCreationMenu(), + createDifficultySwitchMenu(), + new EditorMenuItemSpacer(), + new EditorMenuItem("Delete difficulty", MenuItemType.Standard, deleteDifficulty) { Action = { Disabled = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count < 2 } }, + new EditorMenuItemSpacer(), + new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit) + }; private void exportBeatmap() { From 7a8fa5c2e4364f3c50523f155674119c98ad6394 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Fri, 2 Sep 2022 09:56:00 +0100 Subject: [PATCH 0854/2686] Fix filenames mismatch --- ...eservingTextSprite.cs => TestSceneSizePreservingSpriteText.cs} | 0 .../{SizePreservingTextSprite.cs => SizePreservingSpriteText.cs} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename osu.Game.Tests/Visual/UserInterface/{TestSceneSizePreservingTextSprite.cs => TestSceneSizePreservingSpriteText.cs} (100%) rename osu.Game/Graphics/Sprites/{SizePreservingTextSprite.cs => SizePreservingSpriteText.cs} (100%) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingTextSprite.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingSpriteText.cs similarity index 100% rename from osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingTextSprite.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingSpriteText.cs diff --git a/osu.Game/Graphics/Sprites/SizePreservingTextSprite.cs b/osu.Game/Graphics/Sprites/SizePreservingSpriteText.cs similarity index 100% rename from osu.Game/Graphics/Sprites/SizePreservingTextSprite.cs rename to osu.Game/Graphics/Sprites/SizePreservingSpriteText.cs From 4f18105e9d9045a1cd1c4ae98d30997de73b4588 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 17:39:14 +0900 Subject: [PATCH 0855/2686] Ensure next beatmap selected matches the menu ordering --- osu.Game/Screens/Edit/Editor.cs | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 5df403e643..6e06683e38 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using JetBrains.Annotations; using osu.Framework; @@ -879,17 +878,6 @@ namespace osu.Game.Screens.Edit clock.SeekForward(!trackPlaying, amount); } - private void switchBeatmapOrExit([CanBeNull] BeatmapSetInfo setInfo) - { - if (setInfo is null || setInfo.Beatmaps.Count() <= 1) - this.Exit(); - var nextBeatmap = setInfo!.Beatmaps.First(); - - // Force a refresh of the beatmap (and beatmap set) so the `Change difficulty` list is also updated. - Beatmap.Value = beatmapManager.GetWorkingBeatmap(nextBeatmap, true); - SwitchToDifficulty(Beatmap.Value.BeatmapInfo); - } - private void updateLastSavedHash() { lastSavedHash = changeHandler?.CurrentStateHash; @@ -914,6 +902,14 @@ namespace osu.Game.Screens.Edit new LegacyBeatmapExporter(storage).Export(Beatmap.Value.BeatmapSetInfo); } + /// + /// Beatmaps of the currently edited set, grouped by ruleset and ordered by difficulty. + /// + private IOrderedEnumerable> groupedOrderedBeatmaps => Beatmap.Value.BeatmapSetInfo.Beatmaps + .OrderBy(b => b.StarRating) + .GroupBy(b => b.Ruleset) + .OrderBy(group => group.Key); + private void deleteDifficulty() { if (dialogOverlay == null) @@ -923,11 +919,19 @@ namespace osu.Game.Screens.Edit void delete() { - var current = playableBeatmap.BeatmapInfo; - if (current is null) return; + BeatmapInfo difficultyToDelete = playableBeatmap.BeatmapInfo; - beatmapManager.DeleteDifficultyImmediately(current); - switchBeatmapOrExit(current.BeatmapSet); + var difficultiesBeforeDeletion = groupedOrderedBeatmaps.SelectMany(g => g).ToList(); + + beatmapManager.DeleteDifficultyImmediately(difficultyToDelete); + + int deletedIndex = difficultiesBeforeDeletion.IndexOf(difficultyToDelete); + // of note, we're still working with the cloned version, so indices are all prior to deletion. + BeatmapInfo nextToShow = difficultiesBeforeDeletion[deletedIndex == 0 ? 1 : deletedIndex - 1]; + + Beatmap.Value = beatmapManager.GetWorkingBeatmap(nextToShow, true); + + SwitchToDifficulty(nextToShow); } } @@ -960,18 +964,14 @@ namespace osu.Game.Screens.Edit private EditorMenuItem createDifficultySwitchMenu() { - var beatmapSet = playableBeatmap.BeatmapInfo.BeatmapSet; - - Debug.Assert(beatmapSet != null); - var difficultyItems = new List(); - foreach (var rulesetBeatmaps in beatmapSet.Beatmaps.GroupBy(b => b.Ruleset).OrderBy(group => group.Key)) + foreach (var rulesetBeatmaps in groupedOrderedBeatmaps) { if (difficultyItems.Count > 0) difficultyItems.Add(new EditorMenuItemSpacer()); - foreach (var beatmap in rulesetBeatmaps.OrderBy(b => b.StarRating)) + foreach (var beatmap in rulesetBeatmaps) { bool isCurrentDifficulty = playableBeatmap.BeatmapInfo.Equals(beatmap); difficultyItems.Add(new DifficultyMenuItem(beatmap, isCurrentDifficulty, SwitchToDifficulty)); From dc02b59a05cd76f224bc9c96535741c72a3342a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 17:57:19 +0900 Subject: [PATCH 0856/2686] Add extra coverage to tests Also fixes a potential failure due to test beatmap having two difficulties with same name. --- .../Editing/TestSceneDifficultyDelete.cs | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs index ef0c91cd90..1520f64ec0 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs @@ -41,27 +41,42 @@ namespace osu.Game.Tests.Visual.Editing } [Test] - public void TestDifficultyDelete() + public void TestDeleteDifficulties() { - string lastDiff = null!; - AddStep("remember selected difficulty", () => lastDiff = EditorBeatmap.BeatmapInfo.DifficultyName); + Guid deletedDifficultyID = Guid.Empty; + int countBeforeDeletion = 0; - AddStep("click File", () => this.ChildrenOfType().First().TriggerClick()); - AddStep("click Delete", () => this.ChildrenOfType().Single(deleteMenuItemPredicate).TriggerClick()); - AddStep("confirm", () => InputManager.Key(Key.Number2)); - - AddAssert("difficulty is deleted", () => + for (int i = 0; i < 12; i++) { - if (lastDiff == null!) throw new NullReferenceException(); + // Will be reloaded after each deletion. + AddUntilStep("wait for editor to load", () => Editor?.ReadyForUse == true); - var newSet = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First(), true).BeatmapSetInfo; - return newSet.Beatmaps.All(x => x.DifficultyName != lastDiff); - }); + AddStep("store selected difficulty", () => + { + deletedDifficultyID = EditorBeatmap.BeatmapInfo.ID; + countBeforeDeletion = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count; + }); + + AddStep("click File", () => this.ChildrenOfType().First().TriggerClick()); + + if (i == 11) + { + // last difficulty shouldn't be able to be deleted. + AddAssert("Delete menu item disabled", () => getDeleteMenuItem().Item.Action.Disabled); + } + else + { + AddStep("click delete", () => getDeleteMenuItem().TriggerClick()); + AddUntilStep("wait for dialog", () => DialogOverlay.CurrentDialog != null); + AddStep("confirm", () => InputManager.Key(Key.Number1)); + + AddAssert($"difficulty {i} is deleted", () => Beatmap.Value.BeatmapSetInfo.Beatmaps.Select(b => b.ID), () => Does.Not.Contain(deletedDifficultyID)); + AddAssert("count decreased by one", () => Beatmap.Value.BeatmapSetInfo.Beatmaps.Count, () => Is.EqualTo(countBeforeDeletion - 1)); + } + } } - private bool deleteMenuItemPredicate(DrawableOsuMenuItem item) - { - return item.ChildrenOfType().Any(text => text.Text.ToString().StartsWith("Delete", StringComparison.Ordinal)); - } + private DrawableOsuMenuItem getDeleteMenuItem() => this.ChildrenOfType() + .Single(item => item.ChildrenOfType().Any(text => text.Text.ToString().StartsWith("Delete", StringComparison.Ordinal))); } } From 8bfaa2a51f09e21a64db332b5de1716aa12e9dd0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 18:14:47 +0900 Subject: [PATCH 0857/2686] Fix tournament match handling right click to select itself, dismissing the context menu --- .../Screens/Ladder/Components/DrawableTournamentMatch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentMatch.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentMatch.cs index 5204edf3be..ed8b789387 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentMatch.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentMatch.cs @@ -280,7 +280,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components protected override bool OnClick(ClickEvent e) { - if (editorInfo == null || Match is ConditionalTournamentMatch) + if (editorInfo == null || Match is ConditionalTournamentMatch || e.Button != MouseButton.Left) return false; Selected = true; From 8d6739ae73b5eb13b07ee29c02a11a7a20547267 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 18:20:23 +0900 Subject: [PATCH 0858/2686] Show team scores at the tournament map pool screen --- .../Screens/Gameplay/Components/TeamScoreDisplay.cs | 5 +++++ osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs index 5ee57e9271..0fa5884603 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs @@ -25,6 +25,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components public bool ShowScore { + get => teamDisplay.ShowScore; set => teamDisplay.ShowScore = value; } @@ -92,10 +93,14 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components private void teamChanged(ValueChangedEvent team) { + bool wasShowingScores = teamDisplay?.ShowScore ?? false; + InternalChildren = new Drawable[] { teamDisplay = new TeamDisplay(team.NewValue, teamColour, currentTeamScore, currentMatch.Value?.PointsToWin ?? 0), }; + + teamDisplay.ShowScore = wasShowingScores; } } } diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs index 4d36515316..decd723814 100644 --- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs +++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs @@ -46,7 +46,10 @@ namespace osu.Game.Tournament.Screens.MapPool Loop = true, RelativeSizeAxes = Axes.Both, }, - new MatchHeader(), + new MatchHeader + { + ShowScores = true, + }, mapFlows = new FillFlowContainer> { Y = 160, From 40ff2d50dd6e51feefc17fb1a7bfbce0e18c2be1 Mon Sep 17 00:00:00 2001 From: Josh <43808099+josh-codes@users.noreply.github.com> Date: Sat, 3 Sep 2022 02:31:58 +0800 Subject: [PATCH 0859/2686] Refactor UI and add drag support --- .../TestSceneCatchTouchInput.cs | 2 - osu.Game.Rulesets.Catch/UI/TouchInputField.cs | 58 ++++++++++++++----- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs index 03d031a0a8..24afda4cfa 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.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. -#nullable disable - using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Testing; diff --git a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs index 771902df65..dbc8a51d9c 100644 --- a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs +++ b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics; using osuTK.Graphics; using osuTK; using System.Collections.Generic; +using osu.Framework.Logging; namespace osu.Game.Rulesets.Catch.UI { @@ -39,10 +40,13 @@ namespace osu.Game.Rulesets.Catch.UI private ArrowHitbox leftDashBox = null!; private ArrowHitbox rightDashBox = null!; + // Force input to be prossed even when hidden. + public override bool PropagatePositionalInputSubTree => true; + public override bool PropagateNonPositionalInputSubTree => true; + [BackgroundDependencyLoader] private void load(CatchInputManager catchInputManager, OsuColour colours) { - Show(); Debug.Assert(catchInputManager.KeyBindingContainer != null); keyBindingContainer = catchInputManager.KeyBindingContainer; @@ -121,7 +125,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool OnKeyDown(KeyDownEvent e) { // Hide whenever the keyboard is used. - PopOut(); + Hide(); return false; } @@ -143,19 +147,39 @@ namespace osu.Game.Rulesets.Catch.UI base.OnMouseUp(e); } - /* I plan to come back to this code to add touch support - * protected override void OnTouchMove(TouchMoveEvent e) + protected override bool OnDragStart(DragStartEvent e) + { + return true; + } + + protected override void OnDragEnd(DragEndEvent e) + { + base.OnDragEnd(e); + } + + protected override void OnDrag(DragEvent e) + { + // I'm not sure if this is posible but let's be safe + if (!trackedActions.ContainsKey(e.Button)) + trackedActions.Add(e.Button, TouchCatchAction.None); + + trackedActions[e.Button] = getTouchCatchActionFromInput(e.ScreenSpaceMousePosition); + calculateActiveKeys(); + + base.OnDrag(e); + } + protected override void OnTouchMove(TouchMoveEvent e) { // I'm not sure if this is posible but let's be safe if (!trackedActions.ContainsKey(e.Touch.Source)) trackedActions.Add(e.Touch.Source, TouchCatchAction.None); - trackedActions[e.Touch.Source] = getTouchCatchActionFromInput(e.MousePosition); + trackedActions[e.Touch.Source] = getTouchCatchActionFromInput(e.ScreenSpaceTouchDownPosition); calculateActiveKeys(); base.OnTouchMove(e); - }*/ + } protected override bool OnTouchDown(TouchDownEvent e) { @@ -189,7 +213,7 @@ namespace osu.Game.Rulesets.Catch.UI private void handleDown(object source, Vector2 position) { - PopIn(); + Show(); TouchCatchAction catchAction = getTouchCatchActionFromInput(position); @@ -217,8 +241,10 @@ namespace osu.Game.Rulesets.Catch.UI if (leftBox.Contains(inputPosition)) return TouchCatchAction.MoveLeft; if (rightBox.Contains(inputPosition)) + { + Logger.Log(inputPosition.ToString()); return TouchCatchAction.MoveRight; - + } return TouchCatchAction.None; } @@ -255,20 +281,20 @@ namespace osu.Game.Rulesets.Catch.UI RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - overlay = new Box - { - Alpha = 0, - Colour = colour.Multiply(1.4f).Darken(2.8f), - Blending = BlendingParameters.Additive, - Width = 1, - RelativeSizeAxes = Axes.Both, - }, new Box { Alpha = 0.8f, Colour = colour, Width = 1, RelativeSizeAxes = Axes.Both, + }, + overlay = new Box + { + Alpha = 0, + Colour = colour.Multiply(1.4f), + Blending = BlendingParameters.Additive, + Width = 1, + RelativeSizeAxes = Axes.Both, } } } From 534c40e18eb2911f449f1aa3016b4f3809057330 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Fri, 2 Sep 2022 23:07:30 +0200 Subject: [PATCH 0860/2686] Initial version --- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 335d956e39..4332532df7 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -5,9 +5,11 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Configuration; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osuTK; @@ -17,18 +19,39 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public class ColourHitErrorMeter : HitErrorMeter { - internal const int MAX_DISPLAYED_JUDGEMENTS = 20; - private const int animation_duration = 200; private const int drawable_judgement_size = 8; private const int spacing = 2; - private readonly JudgementFlow judgementsFlow; + [SettingSource("Colour hit number", "number of coloured hits")] + public BindableNumber HitCircleAmount { get; } = new BindableNumber(20) + { + MinValue = 1, + MaxValue = 30, + Precision = 1 + }; + + [SettingSource("Opacity", "Visibility of object")] + public BindableNumber HitOpacity { get; } = new BindableNumber(1) + { + MinValue = 0, + MaxValue = 1, + Precision = .01f + }; + + [SettingSource("Spacing", "space between hit colour circles")] + public BindableNumber HitSpacing { get; } = new BindableNumber(1) + { + MinValue = 0, + MaxValue = 1, + Precision = .01f + }; + public ColourHitErrorMeter() { AutoSizeAxes = Axes.Both; - InternalChild = judgementsFlow = new JudgementFlow(); + InternalChild = judgementsFlow = new JudgementFlow(HitCircleAmount.Value, HitOpacity.Value); } protected override void OnNewJudgement(JudgementResult judgement) @@ -36,7 +59,15 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters if (!judgement.Type.IsScorable() || judgement.Type.IsBonus()) return; - judgementsFlow.Push(GetColourForHitResult(judgement.Type)); + judgementsFlow.Push(GetColourForHitResult(judgement.Type), HitCircleAmount.Value); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + judgementsFlow.Height = HitCircleAmount.Value * (drawable_judgement_size + spacing) - spacing; + judgementsFlow.Alpha = HitOpacity.Value; + judgementsFlow.Spacing = new Vector2(0, HitSpacing.Value); } public override void Clear() => judgementsFlow.Clear(); @@ -45,21 +76,20 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); - public JudgementFlow() + public JudgementFlow(int hitCircleAmount, float opacity) { AutoSizeAxes = Axes.X; - Height = MAX_DISPLAYED_JUDGEMENTS * (drawable_judgement_size + spacing) - spacing; Spacing = new Vector2(0, spacing); Direction = FillDirection.Vertical; LayoutDuration = animation_duration; LayoutEasing = Easing.OutQuint; } - public void Push(Color4 colour) + public void Push(Color4 colour, int amount) { Add(new HitErrorCircle(colour, drawable_judgement_size)); - if (Children.Count > MAX_DISPLAYED_JUDGEMENTS) + if (Children.Count > amount) Children.FirstOrDefault(c => !c.IsRemoved)?.Remove(); } } From 51061c3a12af4711314c6a945f96a5ec220844be Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Sat, 3 Sep 2022 01:27:22 +0200 Subject: [PATCH 0861/2686] Bug fixing and parameter adjustments --- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 4332532df7..f3d2c84177 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -21,7 +21,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { private const int animation_duration = 200; private const int drawable_judgement_size = 8; - private const int spacing = 2; private readonly JudgementFlow judgementsFlow; [SettingSource("Colour hit number", "number of coloured hits")] @@ -35,23 +34,23 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [SettingSource("Opacity", "Visibility of object")] public BindableNumber HitOpacity { get; } = new BindableNumber(1) { - MinValue = 0, + MinValue = 0.01f, MaxValue = 1, Precision = .01f }; [SettingSource("Spacing", "space between hit colour circles")] - public BindableNumber HitSpacing { get; } = new BindableNumber(1) + public BindableNumber HitSpacing { get; } = new BindableNumber(2) { MinValue = 0, - MaxValue = 1, - Precision = .01f + MaxValue = 10, + Precision = .1f }; public ColourHitErrorMeter() { AutoSizeAxes = Axes.Both; - InternalChild = judgementsFlow = new JudgementFlow(HitCircleAmount.Value, HitOpacity.Value); + InternalChild = judgementsFlow = new JudgementFlow(); } protected override void OnNewJudgement(JudgementResult judgement) @@ -65,9 +64,11 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters protected override void LoadComplete() { base.LoadComplete(); - judgementsFlow.Height = HitCircleAmount.Value * (drawable_judgement_size + spacing) - spacing; - judgementsFlow.Alpha = HitOpacity.Value; - judgementsFlow.Spacing = new Vector2(0, HitSpacing.Value); + HitOpacity.BindValueChanged(_ => judgementsFlow.Alpha = HitOpacity.Value, true); + HitSpacing.BindValueChanged(_ => judgementsFlow.Spacing = new Vector2(0, HitSpacing.Value), true); + HitSpacing.BindValueChanged(_ => judgementsFlow.Height = HitCircleAmount.Value * (drawable_judgement_size + HitSpacing.Value) - HitSpacing.Value, true); + HitCircleAmount.BindValueChanged(_ => judgementsFlow.Height = HitCircleAmount.Value * (drawable_judgement_size + HitSpacing.Value) - HitSpacing.Value, true); + HitCircleAmount.BindValueChanged(_ => judgementsFlow.Clear(), true); } public override void Clear() => judgementsFlow.Clear(); @@ -76,10 +77,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); - public JudgementFlow(int hitCircleAmount, float opacity) + public JudgementFlow() { - AutoSizeAxes = Axes.X; - Spacing = new Vector2(0, spacing); + Width = drawable_judgement_size; Direction = FillDirection.Vertical; LayoutDuration = animation_duration; LayoutEasing = Easing.OutQuint; @@ -97,7 +97,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters internal class HitErrorCircle : Container { public bool IsRemoved { get; private set; } - private readonly Circle circle; public HitErrorCircle(Color4 colour, int size) From 161c54df1cf981fe000a35e8412153de0d9cc95a Mon Sep 17 00:00:00 2001 From: Josh <43808099+josh-codes@users.noreply.github.com> Date: Sat, 3 Sep 2022 14:14:34 +0800 Subject: [PATCH 0862/2686] Refactor UI and add drag support --- osu.Game.Rulesets.Catch/UI/TouchInputField.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs index dbc8a51d9c..80453d6aa3 100644 --- a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs +++ b/osu.Game.Rulesets.Catch/UI/TouchInputField.cs @@ -13,7 +13,6 @@ using osu.Game.Graphics; using osuTK.Graphics; using osuTK; using System.Collections.Generic; -using osu.Framework.Logging; namespace osu.Game.Rulesets.Catch.UI { @@ -174,8 +173,7 @@ namespace osu.Game.Rulesets.Catch.UI if (!trackedActions.ContainsKey(e.Touch.Source)) trackedActions.Add(e.Touch.Source, TouchCatchAction.None); - trackedActions[e.Touch.Source] = getTouchCatchActionFromInput(e.ScreenSpaceTouchDownPosition); - + trackedActions[e.Touch.Source] = getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position); calculateActiveKeys(); base.OnTouchMove(e); @@ -183,7 +181,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool OnTouchDown(TouchDownEvent e) { - handleDown(e.Touch.Source, e.ScreenSpaceTouchDownPosition); + handleDown(e.Touch.Source, e.ScreenSpaceTouch.Position); return true; } @@ -241,10 +239,7 @@ namespace osu.Game.Rulesets.Catch.UI if (leftBox.Contains(inputPosition)) return TouchCatchAction.MoveLeft; if (rightBox.Contains(inputPosition)) - { - Logger.Log(inputPosition.ToString()); return TouchCatchAction.MoveRight; - } return TouchCatchAction.None; } From 778d767a1288fe8daaa1c814f9b42bad62283dae Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 3 Sep 2022 15:02:56 +0300 Subject: [PATCH 0863/2686] Revert disposal on `SectionsContainer` properties --- osu.Game/Graphics/Containers/SectionsContainer.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 583f1385c1..97e9ff88b5 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -35,7 +35,7 @@ namespace osu.Game.Graphics.Containers if (value == expandableHeader) return; if (expandableHeader != null) - RemoveInternal(expandableHeader, true); + RemoveInternal(expandableHeader, false); expandableHeader = value; @@ -55,6 +55,7 @@ namespace osu.Game.Graphics.Containers fixedHeader?.Expire(); fixedHeader = value; + if (value == null) return; AddInternal(fixedHeader); @@ -70,8 +71,10 @@ namespace osu.Game.Graphics.Containers if (value == footer) return; if (footer != null) - scrollContainer.Remove(footer, true); + scrollContainer.Remove(footer, false); + footer = value; + if (value == null) return; footer.Anchor |= Anchor.y2; From b43995269ad724ecf2ee352bb147fa3b363872d8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 3 Sep 2022 15:17:46 +0300 Subject: [PATCH 0864/2686] Dispose `ScrollingTeam`s on removal --- .../Screens/Drawings/Components/ScrollingTeamContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs b/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs index 55555adb80..8092c24ccb 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs @@ -170,7 +170,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components availableTeams.Add(team); - RemoveAll(c => c is ScrollingTeam, false); + RemoveAll(c => c is ScrollingTeam, true); setScrollState(ScrollState.Idle); } From e8fa872f61e08ddd88488a3bd7efd1e0b3fab6bb Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 3 Sep 2022 16:14:21 +0300 Subject: [PATCH 0865/2686] Fix room status dropdown position inconsistent on online-play screens --- .../OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index 37b977cff7..8206d4b64d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer roomAccessTypeDropdown.Current.BindValueChanged(_ => UpdateFilter()); - return base.CreateFilterControls().Prepend(roomAccessTypeDropdown); + return base.CreateFilterControls().Append(roomAccessTypeDropdown); } protected override FilterCriteria CreateFilterCriteria() From 0c6d8efa28ae40f6f5301c9e455baa34dde6b7d3 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Sun, 4 Sep 2022 17:24:12 +0200 Subject: [PATCH 0866/2686] Large code refactor, Implementation of shapes option drop down --- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 111 +++++++++++++----- 1 file changed, 81 insertions(+), 30 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index f3d2c84177..9bc6cdbb9b 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -1,8 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Bindables; @@ -19,12 +18,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public class ColourHitErrorMeter : HitErrorMeter { + private const int default_shape_alpha = 0; private const int animation_duration = 200; private const int drawable_judgement_size = 8; - private readonly JudgementFlow judgementsFlow; - [SettingSource("Colour hit number", "number of coloured hits")] - public BindableNumber HitCircleAmount { get; } = new BindableNumber(20) + [SettingSource("Hit error amount", "Number of hit error shapes")] + public BindableNumber HitShapeCount { get; } = new BindableNumber(20) { MinValue = 1, MaxValue = 30, @@ -32,21 +31,26 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }; [SettingSource("Opacity", "Visibility of object")] - public BindableNumber HitOpacity { get; } = new BindableNumber(1) + public BindableNumber HitShapeOpacity { get; } = new BindableNumber(1) { MinValue = 0.01f, MaxValue = 1, - Precision = .01f + Precision = .01f, }; - [SettingSource("Spacing", "space between hit colour circles")] - public BindableNumber HitSpacing { get; } = new BindableNumber(2) + [SettingSource("Spacing", "Space between hit error shapes")] + public BindableNumber HitShapeSpacing { get; } = new BindableNumber(2) { MinValue = 0, MaxValue = 10, Precision = .1f }; + [SettingSource("Shape", "What shape to use for hit errors")] + public Bindable HitShape { get; } = new Bindable(); + + private readonly JudgementFlow judgementsFlow; + public ColourHitErrorMeter() { AutoSizeAxes = Axes.Both; @@ -58,24 +62,36 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters if (!judgement.Type.IsScorable() || judgement.Type.IsBonus()) return; - judgementsFlow.Push(GetColourForHitResult(judgement.Type), HitCircleAmount.Value); + judgementsFlow.Push(GetColourForHitResult(judgement.Type), HitShapeCount.Value); } protected override void LoadComplete() { base.LoadComplete(); - HitOpacity.BindValueChanged(_ => judgementsFlow.Alpha = HitOpacity.Value, true); - HitSpacing.BindValueChanged(_ => judgementsFlow.Spacing = new Vector2(0, HitSpacing.Value), true); - HitSpacing.BindValueChanged(_ => judgementsFlow.Height = HitCircleAmount.Value * (drawable_judgement_size + HitSpacing.Value) - HitSpacing.Value, true); - HitCircleAmount.BindValueChanged(_ => judgementsFlow.Height = HitCircleAmount.Value * (drawable_judgement_size + HitSpacing.Value) - HitSpacing.Value, true); - HitCircleAmount.BindValueChanged(_ => judgementsFlow.Clear(), true); + HitShapeOpacity.BindValueChanged(_ => judgementsFlow.Alpha = HitShapeOpacity.Value, true); + HitShapeSpacing.BindValueChanged(_ => + { + judgementsFlow.Height = HitShapeCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; + judgementsFlow.Spacing = new Vector2(0, HitShapeSpacing.Value); + }, true); + HitShapeCount.BindValueChanged(_ => + { + judgementsFlow.Clear(); + judgementsFlow.Height = HitShapeCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; + }, true); + HitShape.BindValueChanged(_ => + { + judgementsFlow.ValueParser = getShapeStyle(HitShape.Value); + judgementsFlow.Clear(); + }, true); } public override void Clear() => judgementsFlow.Clear(); - private class JudgementFlow : FillFlowContainer + private class JudgementFlow : FillFlowContainer { public override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); + internal string ValueParser = null!; public JudgementFlow() { @@ -85,38 +101,52 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters LayoutEasing = Easing.OutQuint; } - public void Push(Color4 colour, int amount) + public void Push(Color4 colour, int maxErrorShapeCount) { - Add(new HitErrorCircle(colour, drawable_judgement_size)); + Add(new HitErrorShape(colour, drawable_judgement_size, ValueParser)); - if (Children.Count > amount) + if (Children.Count > maxErrorShapeCount) Children.FirstOrDefault(c => !c.IsRemoved)?.Remove(); } } - internal class HitErrorCircle : Container + private class HitErrorShape : Container { public bool IsRemoved { get; private set; } - private readonly Circle circle; - public HitErrorCircle(Color4 colour, int size) + public HitErrorShape(Color4 colour, int size, string shape) { Size = new Vector2(size); - Child = circle = new Circle + + switch (shape) { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Colour = colour - }; + case "circle": + Child = new Circle + { + RelativeSizeAxes = Axes.Both, + Alpha = default_shape_alpha, + Colour = colour + }; + break; + + case "square": + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = default_shape_alpha, + Colour = colour + }; + break; + } } protected override void LoadComplete() { base.LoadComplete(); - circle.FadeInFromZero(animation_duration, Easing.OutQuint); - circle.MoveToY(-DrawSize.Y); - circle.MoveToY(0, animation_duration, Easing.OutQuint); + Child.FadeInFromZero(animation_duration, Easing.OutQuint); + Child.MoveToY(-DrawSize.Y); + Child.MoveToY(0, animation_duration, Easing.OutQuint); } public void Remove() @@ -126,5 +156,26 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters this.FadeOut(animation_duration, Easing.OutQuint).Expire(); } } + + private string getShapeStyle(ShapeStyle shape) + { + switch (shape) + { + case ShapeStyle.Circle: + return "circle"; + + case ShapeStyle.Square: + return "square"; + + default: + throw new ArgumentOutOfRangeException(nameof(shape), shape, @"Unsupported animation style"); + } + } + + public enum ShapeStyle + { + Circle, + Square + } } } From 5f0832ead72c9964cdc40fa00b01f260ffa5a1ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Sep 2022 01:58:57 +0900 Subject: [PATCH 0867/2686] refactor(osu.Game): separate `OsuColour.ForHitResult` by usage --- osu.Game/Graphics/OsuColour.cs | 30 ++++++++++++++++++- .../Leaderboards/LeaderboardScoreTooltip.cs | 2 +- .../Judgements/DefaultJudgementPiece.cs | 2 +- .../Play/HUD/HitErrorMeters/HitErrorMeter.cs | 25 +--------------- .../Expanded/Statistics/HitResultStatistic.cs | 2 +- 5 files changed, 33 insertions(+), 28 deletions(-) diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index 6e2f460930..022b1a363f 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -102,7 +102,7 @@ namespace osu.Game.Graphics /// /// Retrieves the colour for a . /// - public Color4 ForHitResult(HitResult judgement) + public Color4 TextForHitResult(HitResult judgement) { switch (judgement) { @@ -125,6 +125,34 @@ namespace osu.Game.Graphics } } + public Color4 DrawForHitResult(HitResult result) + { + switch (result) + { + case HitResult.SmallTickMiss: + case HitResult.LargeTickMiss: + case HitResult.Miss: + return Red; + + case HitResult.Meh: + return Yellow; + + case HitResult.Ok: + return Green; + + case HitResult.Good: + return GreenLight; + + case HitResult.SmallTickHit: + case HitResult.LargeTickHit: + case HitResult.Great: + return Blue; + + default: + return BlueLight; + } + } + /// /// Retrieves a colour for the given . /// A value indicates that a "background" shade from the local diff --git a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs index 2f3ece0e3b..23d4e64191 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs @@ -156,7 +156,7 @@ namespace osu.Game.Online.Leaderboards { Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), Text = displayName.ToUpper(), - Colour = colours.ForHitResult(result), + Colour = colours.TextForHitResult(result), }, new OsuSpriteText { diff --git a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs index c2b27d4ce8..a854bf37f5 100644 --- a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs +++ b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Judgements Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = Result.GetDescription().ToUpperInvariant(), - Colour = colours.ForHitResult(Result), + Colour = colours.TextForHitResult(Result), Font = OsuFont.Numeric.With(size: 20), Scale = new Vector2(0.85f, 1), } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index 26befd659c..35d28b8e98 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs @@ -59,30 +59,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters protected Color4 GetColourForHitResult(HitResult result) { - switch (result) - { - case HitResult.SmallTickMiss: - case HitResult.LargeTickMiss: - case HitResult.Miss: - return colours.Red; - - case HitResult.Meh: - return colours.Yellow; - - case HitResult.Ok: - return colours.Green; - - case HitResult.Good: - return colours.GreenLight; - - case HitResult.SmallTickHit: - case HitResult.LargeTickHit: - case HitResult.Great: - return colours.Blue; - - default: - return colours.BlueLight; - } + return colours.DrawForHitResult(result); } /// diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs index c23a5e668d..429b72c07c 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics [BackgroundDependencyLoader] private void load(OsuColour colours) { - HeaderText.Colour = colours.ForHitResult(Result); + HeaderText.Colour = colours.TextForHitResult(Result); } } } From 074d2a7a3a64cb09b566e51399450da57bbc455e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Sep 2022 02:01:44 +0900 Subject: [PATCH 0868/2686] chore(osu.Game): provide ordering index for `HitResult` --- osu.Game/Rulesets/Scoring/HitResult.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game/Rulesets/Scoring/HitResult.cs b/osu.Game/Rulesets/Scoring/HitResult.cs index 5047fdea82..8078363212 100644 --- a/osu.Game/Rulesets/Scoring/HitResult.cs +++ b/osu.Game/Rulesets/Scoring/HitResult.cs @@ -4,10 +4,12 @@ #nullable disable using System; +using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Runtime.Serialization; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Utils; namespace osu.Game.Rulesets.Scoring @@ -135,6 +137,8 @@ namespace osu.Game.Rulesets.Scoring #pragma warning disable CS0618 public static class HitResultExtensions { + private static readonly IList order = EnumExtensions.GetValuesInOrder().ToList(); + /// /// Whether a increases the combo. /// @@ -282,6 +286,16 @@ namespace osu.Game.Rulesets.Scoring Debug.Assert(minResult <= maxResult); return result > minResult && result < maxResult; } + + /// + /// Ordered index of a . Used for sorting. + /// + /// The to get the index of. + /// The index of . + public static int OrderingIndex(this HitResult result) + { + return order.IndexOf(result); + } } #pragma warning restore CS0618 } From 0af6b3dc0fa41e65480c670c7a8dbc53f11f6de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Sep 2022 02:02:38 +0900 Subject: [PATCH 0869/2686] chore(osu.Game): colorize bars by OD on `HitEventTimingDistributionGraph` --- .../HitEventTimingDistributionGraph.cs | 109 ++++++++++++++---- 1 file changed, 84 insertions(+), 25 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index db69e270f6..3a696290b9 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -48,6 +47,9 @@ namespace osu.Game.Screens.Ranking.Statistics /// private readonly IReadOnlyList hitEvents; + [Resolved] + private OsuColour colours { get; set; } + /// /// Creates a new . /// @@ -57,7 +59,7 @@ namespace osu.Game.Screens.Ranking.Statistics this.hitEvents = hitEvents.Where(e => !(e.HitObject.HitWindows is HitWindows.EmptyHitWindows) && e.Result.IsHit()).ToList(); } - private int[] bins; + private IDictionary[] bins; private double binSize; private double hitOffset; @@ -69,7 +71,7 @@ namespace osu.Game.Screens.Ranking.Statistics if (hitEvents == null || hitEvents.Count == 0) return; - bins = new int[total_timing_distribution_bins]; + bins = Enumerable.Range(0, total_timing_distribution_bins).Select(_ => new Dictionary()).ToArray>(); binSize = Math.Ceiling(hitEvents.Max(e => Math.Abs(e.TimeOffset)) / timing_distribution_bins); @@ -89,7 +91,8 @@ namespace osu.Game.Screens.Ranking.Statistics { bool roundUp = true; - Array.Clear(bins, 0, bins.Length); + foreach (var bin in bins) + bin.Clear(); foreach (var e in hitEvents) { @@ -110,23 +113,29 @@ namespace osu.Game.Screens.Ranking.Statistics // may be out of range when applying an offset. for such cases we can just drop the results. if (index >= 0 && index < bins.Length) - bins[index]++; + { + bins[index].TryGetValue(e.Result, out int value); + bins[index][e.Result] = ++value; + } } if (barDrawables != null) { for (int i = 0; i < barDrawables.Length; i++) { - barDrawables[i].UpdateOffset(bins[i]); + barDrawables[i].UpdateOffset(bins[i].Sum(b => b.Value)); } } else { - int maxCount = bins.Max(); + int maxCount = bins.Max(b => b.Values.Sum()); barDrawables = new Bar[total_timing_distribution_bins]; for (int i = 0; i < barDrawables.Length; i++) - barDrawables[i] = new Bar(bins[i], maxCount, i == timing_distribution_centre_bin_index); + { + IReadOnlyList values = bins[i].Select(b => new BarValue(b.Key.OrderingIndex(), b.Value, colours.DrawForHitResult(b.Key))).OrderBy(b => b.Index).ToList(); + barDrawables[i] = new Bar(values, maxCount, i == timing_distribution_centre_bin_index); + } Container axisFlow; @@ -207,52 +216,102 @@ namespace osu.Game.Screens.Ranking.Statistics } } + private readonly struct BarValue + { + public readonly int Index; + public readonly float Value; + public readonly Color4 Colour; + + public BarValue(int index, float value, Color4 colour) + { + Index = index; + Value = value; + Colour = colour; + } + } + private class Bar : CompositeDrawable { - private readonly float value; + private float totalValue => values.Sum(v => v.Value); + private float basalHeight => BoundingBox.Width / BoundingBox.Height; + private float availableHeight => 1 - basalHeight; + + private readonly IReadOnlyList values; private readonly float maxValue; - private readonly Circle boxOriginal; + private readonly Circle[] boxOriginals; private Circle boxAdjustment; - private const float minimum_height = 0.05f; - - public Bar(float value, float maxValue, bool isCentre) + public Bar(IReadOnlyList values, float maxValue, bool isCentre) { - this.value = value; + this.values = values; this.maxValue = maxValue; RelativeSizeAxes = Axes.Both; Masking = true; - InternalChildren = new Drawable[] + if (values.Any()) { - boxOriginal = new Circle + boxOriginals = values.Select(v => new Circle { RelativeSizeAxes = Axes.Both, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - Colour = isCentre ? Color4.White : Color4Extensions.FromHex("#66FFCC"), - Height = minimum_height, - }, - }; + Colour = isCentre ? Color4.White : v.Colour, + Height = 0, + }).ToArray(); + InternalChildren = boxOriginals.Reverse().ToArray(); + } + else + { + InternalChildren = boxOriginals = new[] + { + new Circle + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Colour = isCentre ? Color4.White : Color4.Gray, + Height = 0, + }, + }; + } } private const double duration = 300; + private float offsetForValue(float value) + { + return availableHeight * value / maxValue; + } + + private float heightForValue(float value) + { + return basalHeight + offsetForValue(value); + } + protected override void LoadComplete() { base.LoadComplete(); - float height = Math.Clamp(value / maxValue, minimum_height, 1); + float offsetValue = 0; - if (height > minimum_height) - boxOriginal.ResizeHeightTo(height, duration, Easing.OutQuint); + if (values.Any()) + { + for (int i = 0; i < values.Count; i++) + { + boxOriginals[i].Y = BoundingBox.Height * offsetForValue(offsetValue); + boxOriginals[i].Delay(duration * i).ResizeHeightTo(heightForValue(values[i].Value), duration, Easing.OutQuint); + offsetValue -= values[i].Value; + } + } + else + boxOriginals.Single().ResizeHeightTo(basalHeight, duration, Easing.OutQuint); } public void UpdateOffset(float adjustment) { - bool hasAdjustment = adjustment != value && adjustment / maxValue >= minimum_height; + bool hasAdjustment = adjustment != totalValue; if (boxAdjustment == null) { @@ -271,7 +330,7 @@ namespace osu.Game.Screens.Ranking.Statistics }); } - boxAdjustment.ResizeHeightTo(Math.Clamp(adjustment / maxValue, minimum_height, 1), duration, Easing.OutQuint); + boxAdjustment.ResizeHeightTo(heightForValue(adjustment), duration, Easing.OutQuint); boxAdjustment.FadeTo(!hasAdjustment ? 0 : 1, duration, Easing.OutQuint); } } From b67fd3d8804a6461943057fc0cf6fb0adf5fbcbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Sep 2022 03:45:51 +0900 Subject: [PATCH 0870/2686] chore(osu.Game): split transform duration of bars on `HitTimingDistributionGraph` --- .../Ranking/Statistics/HitEventTimingDistributionGraph.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 3a696290b9..900fd2c907 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -278,7 +278,9 @@ namespace osu.Game.Screens.Ranking.Statistics } } - private const double duration = 300; + private const double total_duration = 300; + + private double duration => total_duration / Math.Max(values.Count, 1); private float offsetForValue(float value) { From 19ab1433c67b06b1a9f08bf5b64c14abcee5647d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Sep 2022 03:46:23 +0900 Subject: [PATCH 0871/2686] test(osu.Game): add more test cases for `HitTimingDistributionGraph` --- ...estSceneHitEventTimingDistributionGraph.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs index 44cb438a6b..9264ed7030 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs @@ -43,6 +43,50 @@ namespace osu.Game.Tests.Visual.Ranking createTest(Enumerable.Range(-150, 300).Select(i => new HitEvent(i / 50f, HitResult.Perfect, placeholder_object, placeholder_object, null)).ToList()); } + [Test] + public void TestSparse() + { + createTest(new List + { + new HitEvent(-7, HitResult.Perfect, placeholder_object, placeholder_object, null), + new HitEvent(-6, HitResult.Perfect, placeholder_object, placeholder_object, null), + new HitEvent(-5, HitResult.Perfect, placeholder_object, placeholder_object, null), + new HitEvent(5, HitResult.Perfect, placeholder_object, placeholder_object, null), + new HitEvent(6, HitResult.Perfect, placeholder_object, placeholder_object, null), + new HitEvent(7, HitResult.Perfect, placeholder_object, placeholder_object, null), + }); + } + + [Test] + public void TestVariousTypesOfHitResult() + { + createTest(CreateDistributedHitEvents(0, 50).Select(h => + { + var offset = Math.Abs(h.TimeOffset); + var result = offset > 36 ? HitResult.Miss : offset > 32 ? HitResult.Meh : offset > 24 ? HitResult.Ok : offset > 16 ? HitResult.Good : offset > 8 ? HitResult.Great : HitResult.Perfect; + return new HitEvent(h.TimeOffset, result, placeholder_object, placeholder_object, null); + }).ToList()); + } + + [Test] + public void TestMultipleWindowsOfHitResult() + { + var wide = CreateDistributedHitEvents(0, 50).Select(h => + { + var offset = Math.Abs(h.TimeOffset); + var result = offset > 36 ? HitResult.Miss : offset > 32 ? HitResult.Meh : offset > 24 ? HitResult.Ok : offset > 16 ? HitResult.Good : offset > 8 ? HitResult.Great : HitResult.Perfect; + return new HitEvent(h.TimeOffset, result, placeholder_object, placeholder_object, null); + }); + var narrow = CreateDistributedHitEvents(0, 50).Select(h => + { + var offset = Math.Abs(h.TimeOffset); + var result = offset > 25 ? HitResult.Miss : offset > 20 ? HitResult.Meh : offset > 15 ? HitResult.Ok : offset > 10 ? HitResult.Good : offset > 5 ? HitResult.Great : HitResult.Perfect; + return new HitEvent(h.TimeOffset, result, placeholder_object, placeholder_object, null); + }); + createTest(wide.Concat(narrow).ToList()); + } + + [Test] public void TestZeroTimeOffset() { From 7e77c9e8b47e87fa181db6912bfbc9a541f278d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Sep 2022 04:44:27 +0900 Subject: [PATCH 0872/2686] chore(osu.Game): only the first result should be white at zero position on `HitEventTimingDistributionGraph` --- .../Ranking/Statistics/HitEventTimingDistributionGraph.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 900fd2c907..1be32a94af 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -252,12 +252,12 @@ namespace osu.Game.Screens.Ranking.Statistics if (values.Any()) { - boxOriginals = values.Select(v => new Circle + boxOriginals = values.Select((v, i) => new Circle { RelativeSizeAxes = Axes.Both, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - Colour = isCentre ? Color4.White : v.Colour, + Colour = isCentre && i == 0 ? Color4.White : v.Colour, Height = 0, }).ToArray(); InternalChildren = boxOriginals.Reverse().ToArray(); From 4ea7ca4c0748f1cead8465b6448510136255c289 Mon Sep 17 00:00:00 2001 From: Exanc <43091560+Exanc@users.noreply.github.com> Date: Mon, 5 Sep 2022 00:09:20 +0200 Subject: [PATCH 0873/2686] Slight tweak to the StarsSlider - MinimumStarsSlider now shows "0" when at it's minimum - Modified and NoResultsPlaceholder the tooltip to stay consistent with the changes --- .../Select/DifficultyRangeFilterControl.cs | 15 ++++++++++++++- osu.Game/Screens/Select/NoResultsPlaceholder.cs | 4 ++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs b/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs index a82c969805..eb5a797ac0 100644 --- a/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs +++ b/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs @@ -65,6 +65,10 @@ namespace osu.Game.Screens.Select private class MinimumStarsSlider : StarsSlider { + public MinimumStarsSlider() : base("0") { } + + public override LocalisableString TooltipText => Current.Value.ToString(@"0.## stars"); + protected override void LoadComplete() { base.LoadComplete(); @@ -82,6 +86,8 @@ namespace osu.Game.Screens.Select private class MaximumStarsSlider : StarsSlider { + public MaximumStarsSlider() : base("∞") { } + protected override void LoadComplete() { base.LoadComplete(); @@ -100,6 +106,13 @@ namespace osu.Game.Screens.Select ? UserInterfaceStrings.NoLimit : Current.Value.ToString(@"0.## stars"); + protected readonly string DefaultValue; + + public StarsSlider(string defaultValue) + { + DefaultValue = defaultValue; + } + protected override bool OnHover(HoverEvent e) { base.OnHover(e); @@ -125,7 +138,7 @@ namespace osu.Game.Screens.Select Current.BindValueChanged(current => { - currentDisplay.Text = current.NewValue != Current.Default ? current.NewValue.ToString("N1") : "∞"; + currentDisplay.Text = current.NewValue != Current.Default ? current.NewValue.ToString("N1") : DefaultValue; }, true); } } diff --git a/osu.Game/Screens/Select/NoResultsPlaceholder.cs b/osu.Game/Screens/Select/NoResultsPlaceholder.cs index f3c3fb4d87..f44aa01588 100644 --- a/osu.Game/Screens/Select/NoResultsPlaceholder.cs +++ b/osu.Game/Screens/Select/NoResultsPlaceholder.cs @@ -127,10 +127,10 @@ namespace osu.Game.Screens.Select config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1); }); - string lowerStar = filter.UserStarDifficulty.Min == null ? "∞" : $"{filter.UserStarDifficulty.Min:N1}"; + string lowerStar = filter.UserStarDifficulty.Min == null ? "0,0" : $"{filter.UserStarDifficulty.Min:N1}"; string upperStar = filter.UserStarDifficulty.Max == null ? "∞" : $"{filter.UserStarDifficulty.Max:N1}"; - textFlow.AddText($" the {lowerStar}-{upperStar} star difficulty filter."); + textFlow.AddText($" the {lowerStar} - {upperStar} star difficulty filter."); } // TODO: Add realm queries to hint at which ruleset results are available in (and allow clicking to switch). From 8cbd3443308f08941e7b670516ed25355665e948 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Sep 2022 11:28:12 +0900 Subject: [PATCH 0874/2686] Improve performance when cancelling import with debugger attached --- .../Database/RealmArchiveModelImporter.cs | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index b340d0ee4b..f1bc0bfe0e 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -108,47 +108,42 @@ namespace osu.Game.Database bool isBatchImport = tasks.Length >= minimum_items_considered_batch_import; - try + await Task.WhenAll(tasks.Select(async task => { - await Task.WhenAll(tasks.Select(async task => + if (notification.CancellationToken.IsCancellationRequested) + return; + + try { - notification.CancellationToken.ThrowIfCancellationRequested(); + var model = await Import(task, isBatchImport, notification.CancellationToken).ConfigureAwait(false); - try + lock (imported) { - var model = await Import(task, isBatchImport, notification.CancellationToken).ConfigureAwait(false); + if (model != null) + imported.Add(model); + current++; - lock (imported) - { - if (model != null) - imported.Add(model); - current++; + notification.Text = $"Imported {current} of {tasks.Length} {HumanisedModelName}s"; + notification.Progress = (float)current / tasks.Length; + } + } + catch (OperationCanceledException) + { + } + catch (Exception e) + { + Logger.Error(e, $@"Could not import ({task})", LoggingTarget.Database); + } + })).ConfigureAwait(false); - notification.Text = $"Imported {current} of {tasks.Length} {HumanisedModelName}s"; - notification.Progress = (float)current / tasks.Length; - } - } - catch (TaskCanceledException) - { - throw; - } - catch (Exception e) - { - Logger.Error(e, $@"Could not import ({task})", LoggingTarget.Database); - } - })).ConfigureAwait(false); - } - catch (OperationCanceledException) + if (imported.Count == 0) { - if (imported.Count == 0) + if (notification.CancellationToken.IsCancellationRequested) { notification.State = ProgressNotificationState.Cancelled; return imported; } - } - if (imported.Count == 0) - { notification.Text = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import failed!"; notification.State = ProgressNotificationState.Cancelled; } From aace334fb365485ed41e809d19d34961b57d6920 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Mon, 5 Sep 2022 04:49:48 +0200 Subject: [PATCH 0875/2686] Fix some test issues --- .../Visual/Gameplay/TestSceneHitErrorMeter.cs | 22 +++++++++---------- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index 707f807e64..74387e1d8e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -107,13 +107,13 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("no bars added", () => !this.ChildrenOfType().Any()); AddAssert("circle added", () => this.ChildrenOfType().All( - meter => meter.ChildrenOfType().Count() == 1)); + meter => meter.ChildrenOfType().Count() == 1)); AddStep("miss", () => newJudgement(50, HitResult.Miss)); AddAssert("no bars added", () => !this.ChildrenOfType().Any()); AddAssert("circle added", () => this.ChildrenOfType().All( - meter => meter.ChildrenOfType().Count() == 2)); + meter => meter.ChildrenOfType().Count() == 2)); } [Test] @@ -123,11 +123,11 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("small bonus", () => newJudgement(result: HitResult.SmallBonus)); AddAssert("no bars added", () => !this.ChildrenOfType().Any()); - AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); AddStep("large bonus", () => newJudgement(result: HitResult.LargeBonus)); AddAssert("no bars added", () => !this.ChildrenOfType().Any()); - AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); } [Test] @@ -137,11 +137,11 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("ignore hit", () => newJudgement(result: HitResult.IgnoreHit)); AddAssert("no bars added", () => !this.ChildrenOfType().Any()); - AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); AddStep("ignore miss", () => newJudgement(result: HitResult.IgnoreMiss)); AddAssert("no bars added", () => !this.ChildrenOfType().Any()); - AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); } [Test] @@ -155,16 +155,16 @@ namespace osu.Game.Tests.Visual.Gameplay hitErrorMeter.Hide(); }); - AddRepeatStep("hit", () => newJudgement(), ColourHitErrorMeter.MAX_DISPLAYED_JUDGEMENTS * 2); + AddRepeatStep("hit", () => newJudgement(), ColourHitErrorMeter.HitErrorShape. *2); AddAssert("bars added", () => this.ChildrenOfType().Any()); - AddAssert("circle added", () => this.ChildrenOfType().Any()); + AddAssert("circle added", () => this.ChildrenOfType().Any()); AddUntilStep("wait for bars to disappear", () => !this.ChildrenOfType().Any()); AddUntilStep("ensure max circles not exceeded", () => { return this.ChildrenOfType() - .All(m => m.ChildrenOfType().Count() <= ColourHitErrorMeter.MAX_DISPLAYED_JUDGEMENTS); + .All(m => m.ChildrenOfType().Count() <= ColourHitErrorMeter.HitShapeCount.Default); }); AddStep("show displays", () => @@ -183,12 +183,12 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("bar added", () => this.ChildrenOfType().All( meter => meter.ChildrenOfType().Count() == 1)); AddAssert("circle added", () => this.ChildrenOfType().All( - meter => meter.ChildrenOfType().Count() == 1)); + meter => meter.ChildrenOfType().Count() == 1)); AddStep("clear", () => this.ChildrenOfType().ForEach(meter => meter.Clear())); AddAssert("bar cleared", () => !this.ChildrenOfType().Any()); - AddAssert("colour cleared", () => !this.ChildrenOfType().Any()); + AddAssert("colour cleared", () => !this.ChildrenOfType().Any()); } private void recreateDisplay(HitWindows hitWindows, float overallDifficulty) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 9bc6cdbb9b..8901612b9b 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -1,4 +1,4 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; @@ -110,7 +110,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - private class HitErrorShape : Container + public class HitErrorShape : Container { public bool IsRemoved { get; private set; } From 57954bb8f51382476d7d1dfbbcb0943431a5ec63 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 14:50:43 +0900 Subject: [PATCH 0876/2686] Enable nullability on `TimelineHitObjectBlueprint` --- .../Timeline/TimelineHitObjectBlueprint.cs | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs index 32ebc9c3c1..974e240552 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.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. -#nullable disable - using System; using JetBrains.Annotations; using osu.Framework.Allocation; @@ -33,19 +31,19 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { private const float circle_size = 38; - private Container repeatsContainer; + private Container? repeatsContainer; - public Action OnDragHandled; + public Action? OnDragHandled = null!; [UsedImplicitly] private readonly Bindable startTime; - private Bindable indexInCurrentComboBindable; + private Bindable? indexInCurrentComboBindable; - private Bindable comboIndexBindable; - private Bindable comboIndexWithOffsetsBindable; + private Bindable? comboIndexBindable; + private Bindable? comboIndexWithOffsetsBindable; - private Bindable displayColourBindable; + private Bindable displayColourBindable = null!; private readonly ExtendableCircle circle; private readonly Border border; @@ -54,7 +52,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private readonly OsuSpriteText comboIndexText; [Resolved] - private ISkinSource skin { get; set; } + private ISkinSource skin { get; set; } = null!; public TimelineHitObjectBlueprint(HitObject item) : base(item) @@ -124,7 +122,10 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline case IHasComboInformation comboInfo: indexInCurrentComboBindable = comboInfo.IndexInCurrentComboBindable.GetBoundCopy(); - indexInCurrentComboBindable.BindValueChanged(_ => updateComboIndex(), true); + indexInCurrentComboBindable.BindValueChanged(_ => + { + comboIndexText.Text = (indexInCurrentComboBindable.Value + 1).ToString(); + }, true); comboIndexBindable = comboInfo.ComboIndexBindable.GetBoundCopy(); comboIndexWithOffsetsBindable = comboInfo.ComboIndexWithOffsetsBindable.GetBoundCopy(); @@ -149,8 +150,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline updateColour(); } - private void updateComboIndex() => comboIndexText.Text = (indexInCurrentComboBindable.Value + 1).ToString(); - private void updateColour() { Color4 colour; @@ -183,11 +182,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline colouredComponents.Colour = OsuColour.ForegroundTextColourFor(averageColour); } - private SamplePointPiece sampleOverrideDisplay; - private DifficultyPointPiece difficultyOverrideDisplay; + private SamplePointPiece? sampleOverrideDisplay; + private DifficultyPointPiece? difficultyOverrideDisplay; - private DifficultyControlPoint difficultyControlPoint; - private SampleControlPoint sampleControlPoint; + private DifficultyControlPoint difficultyControlPoint = null!; + private SampleControlPoint sampleControlPoint = null!; protected override void Update() { @@ -276,16 +275,27 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public class DragArea : Circle { - private readonly HitObject hitObject; + private readonly HitObject? hitObject; [Resolved] - private Timeline timeline { get; set; } + private EditorBeatmap beatmap { get; set; } = null!; - public Action OnDragHandled; + [Resolved] + private IBeatSnapProvider beatSnapProvider { get; set; } = null!; + + [Resolved] + private Timeline timeline { get; set; } = null!; + + [Resolved(CanBeNull = true)] + private IEditorChangeHandler? changeHandler { get; set; } + + private ScheduledDelegate? dragOperation; + + public Action? OnDragHandled; public override bool HandlePositionalInput => hitObject != null; - public DragArea(HitObject hitObject) + public DragArea(HitObject? hitObject) { this.hitObject = hitObject; @@ -356,23 +366,12 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline this.FadeTo(IsHovered || hasMouseDown ? 1f : 0.9f, 200, Easing.OutQuint); } - [Resolved] - private EditorBeatmap beatmap { get; set; } - - [Resolved] - private IBeatSnapProvider beatSnapProvider { get; set; } - - [Resolved(CanBeNull = true)] - private IEditorChangeHandler changeHandler { get; set; } - protected override bool OnDragStart(DragStartEvent e) { changeHandler?.BeginChange(); return true; } - private ScheduledDelegate dragOperation; - protected override void OnDrag(DragEvent e) { base.OnDrag(e); From 8af8adf22d1359673e4992d81cef7604e518685c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 16:17:26 +0900 Subject: [PATCH 0877/2686] Fix incorrect slider length in timeline when non-default velocity is inherited from previous object --- .../Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index 59be93530c..4857f13a64 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -89,6 +89,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders HitObject.DifficultyControlPoint = nearestDifficultyPoint ?? new DifficultyControlPoint(); HitObject.Position = ToLocalSpace(result.ScreenSpacePosition); + + // Replacing the DifficultyControlPoint above doesn't trigger any kind of invalidation. + // Without re-applying defaults, velocity won't be updated. + // If this causes further issues, it may be better to copy the velocity p + ApplyDefaultsToHitObject(); break; case SliderPlacementState.Body: From 2bec8b82b355ac78be961b235e620d341a63bdc9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 16:26:41 +0900 Subject: [PATCH 0878/2686] Fix textbox sample playback potentially crashing if called before load --- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index e5341cfd4b..4c2e00d6e0 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -283,7 +283,7 @@ namespace osu.Game.Graphics.UserInterface return samples[RNG.Next(0, samples.Length)]?.GetChannel(); } - private void playSample(FeedbackSampleType feedbackSample) + private void playSample(FeedbackSampleType feedbackSample) => Schedule(() => { if (Time.Current < sampleLastPlaybackTime + 15) return; @@ -300,7 +300,7 @@ namespace osu.Game.Graphics.UserInterface channel.Play(); sampleLastPlaybackTime = Time.Current; - } + }); private class OsuCaret : Caret { From f1d9b225a7ddc43427ecf825910e2e24e18a5f79 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 16:40:10 +0900 Subject: [PATCH 0879/2686] Remove probably pointless comment --- .../Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index 4857f13a64..e2f98c273e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -92,7 +92,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders // Replacing the DifficultyControlPoint above doesn't trigger any kind of invalidation. // Without re-applying defaults, velocity won't be updated. - // If this causes further issues, it may be better to copy the velocity p ApplyDefaultsToHitObject(); break; From 6946015d17fe0f6feddcc5e5e3a974cc39bc54d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Sep 2022 07:49:29 +0000 Subject: [PATCH 0880/2686] style(osu.Game): fix multiple blank lines --- .../Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs index 9264ed7030..fe4aba1317 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs @@ -86,7 +86,6 @@ namespace osu.Game.Tests.Visual.Ranking createTest(wide.Concat(narrow).ToList()); } - [Test] public void TestZeroTimeOffset() { From 4fa6707bf08c6f347c732c1de9b322e1fd0e0020 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 00:58:10 +0900 Subject: [PATCH 0881/2686] Set all progress notifications to non-important --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 14cf6b3013..6821c25ac0 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -162,6 +162,8 @@ namespace osu.Game.Overlays.Notifications public override bool DisplayOnTop => false; + public override bool IsImportant => false; + private readonly ProgressBar progressBar; private Color4 colourQueued; private Color4 colourActive; From 56886fed09f87ad71c7c4bbd9b110d8cfed97e7a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 00:58:27 +0900 Subject: [PATCH 0882/2686] Add test coverage of progress notification completions showing --- .../TestSceneNotificationOverlay.cs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 38eecaa052..288f1f78bc 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -23,9 +23,12 @@ namespace osu.Game.Tests.Visual.UserInterface private SpriteText displayedCount = null!; + public double TimeToCompleteProgress { get; set; } = 2000; + [SetUp] public void SetUp() => Schedule(() => { + TimeToCompleteProgress = 2000; progressingNotifications.Clear(); Content.Children = new Drawable[] @@ -45,6 +48,7 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestCompleteProgress() { ProgressNotification notification = null!; + AddStep("add progress notification", () => { notification = new ProgressNotification @@ -57,6 +61,30 @@ namespace osu.Game.Tests.Visual.UserInterface }); AddUntilStep("wait completion", () => notification.State == ProgressNotificationState.Completed); + + AddAssert("Completion toast shown", () => notificationOverlay.ToastCount == 1); + } + + [Test] + public void TestCompleteProgressSlow() + { + ProgressNotification notification = null!; + + AddStep("Set progress slow", () => TimeToCompleteProgress *= 2); + AddStep("add progress notification", () => + { + notification = new ProgressNotification + { + Text = @"Uploading to BSS...", + CompletionText = "Uploaded to BSS!", + }; + notificationOverlay.Post(notification); + progressingNotifications.Add(notification); + }); + + AddUntilStep("wait completion", () => notification.State == ProgressNotificationState.Completed); + + AddAssert("Completion toast shown", () => notificationOverlay.ToastCount == 1); } [Test] @@ -177,7 +205,7 @@ namespace osu.Game.Tests.Visual.UserInterface foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active)) { if (n.Progress < 1) - n.Progress += (float)(Time.Elapsed / 2000); + n.Progress += (float)(Time.Elapsed / TimeToCompleteProgress); else n.State = ProgressNotificationState.Completed; } From eca7b8f9884284d53d506c28b1ceadfedbffdfd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Sep 2022 00:51:59 +0900 Subject: [PATCH 0883/2686] Fix completion notifications not always showing as toasts --- osu.Game/Overlays/NotificationOverlay.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 2c39ebcc87..fca43e65a5 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -137,7 +137,9 @@ namespace osu.Game.Overlays private readonly Scheduler postScheduler = new Scheduler(); - public override bool IsPresent => base.IsPresent || postScheduler.HasPendingTasks; + public override bool IsPresent => base.IsPresent + || postScheduler.HasPendingTasks + || toastTray.IsDisplayingToasts; private bool processingPosts = true; From 0d4ee6bd80ca8e8004de73f26b56f5695297b906 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 18:35:02 +0900 Subject: [PATCH 0884/2686] Centralise ability to fetch all toast tray notifications (including animating ones) --- osu.Game/Overlays/NotificationOverlayToastTray.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index c47a61eac1..aa61e20a02 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; @@ -23,7 +24,7 @@ namespace osu.Game.Overlays /// public class NotificationOverlayToastTray : CompositeDrawable { - public bool IsDisplayingToasts => toastFlow.Count > 0; + public bool IsDisplayingToasts => displayedCount > 0; private FillFlowContainer toastFlow = null!; private BufferedContainer toastContentBackground = null!; @@ -33,11 +34,14 @@ namespace osu.Game.Overlays public Action? ForwardNotificationToPermanentStore { get; set; } - public int UnreadCount => toastFlow.Count(n => !n.WasClosed && !n.Read) - + InternalChildren.OfType().Count(n => !n.WasClosed && !n.Read); + public int UnreadCount => allNotifications.Count(n => !n.WasClosed && !n.Read); + + private IEnumerable allNotifications => toastFlow.Concat(InternalChildren.OfType()); private int runningDepth; + private int displayedCount; + [BackgroundDependencyLoader] private void load() { @@ -92,6 +96,7 @@ namespace osu.Game.Overlays public void Post(Notification notification) { ++runningDepth; + displayedCount++; int depth = notification.DisplayOnTop ? -runningDepth : runningDepth; @@ -133,6 +138,7 @@ namespace osu.Game.Overlays notification.FadeOut(NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint).OnComplete(_ => { RemoveInternal(notification, false); + displayedCount--; ForwardNotificationToPermanentStore?.Invoke(notification); notification.FadeIn(300, Easing.OutQuint); @@ -144,7 +150,7 @@ namespace osu.Game.Overlays base.Update(); float height = toastFlow.DrawHeight + 120; - float alpha = IsDisplayingToasts ? MathHelper.Clamp(toastFlow.DrawHeight / 40, 0, 1) * toastFlow.Children.Max(n => n.Alpha) : 0; + float alpha = toastFlow.Count > 0 ? MathHelper.Clamp(toastFlow.DrawHeight / 41, 0, 1) * toastFlow.Children.Max(n => n.Alpha) : 0; toastContentBackground.Height = (float)Interpolation.DampContinuously(toastContentBackground.Height, height, 10, Clock.ElapsedFrameTime); toastContentBackground.Alpha = (float)Interpolation.DampContinuously(toastContentBackground.Alpha, alpha, 10, Clock.ElapsedFrameTime); From 2923c10cd808f555375c081b008a4558460ec4e9 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 1 Sep 2022 18:53:35 +0900 Subject: [PATCH 0885/2686] Rewrite rooms to store multiple active countdowns Update test to the new structure --- .../Multiplayer/TestSceneMatchStartControl.cs | 15 ++++++---- .../Countdown/CountdownChangedEvent.cs | 20 ------------- .../Countdown/CountdownStartedEvent.cs | 28 +++++++++++++++++++ .../Countdown/CountdownStoppedEvent.cs | 28 +++++++++++++++++++ .../Countdown/StopCountdownRequest.cs | 10 +++++++ .../Online/Multiplayer/MatchServerEvent.cs | 3 +- .../Online/Multiplayer/MultiplayerClient.cs | 10 +++++-- .../Multiplayer/MultiplayerCountdown.cs | 10 +++++-- .../Online/Multiplayer/MultiplayerRoom.cs | 4 +-- osu.Game/Online/SignalRWorkaroundTypes.cs | 3 +- .../Multiplayer/Match/MatchStartControl.cs | 10 +++++-- .../Match/MultiplayerCountdownButton.cs | 5 ++-- .../Match/MultiplayerReadyButton.cs | 25 ++++++----------- 13 files changed, 117 insertions(+), 54 deletions(-) delete mode 100644 osu.Game/Online/Multiplayer/Countdown/CountdownChangedEvent.cs create mode 100644 osu.Game/Online/Multiplayer/Countdown/CountdownStartedEvent.cs create mode 100644 osu.Game/Online/Multiplayer/Countdown/CountdownStoppedEvent.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs index a800b21bc9..12e7394c93 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs @@ -91,8 +91,7 @@ namespace osu.Game.Tests.Visual.Multiplayer break; case StopCountdownRequest: - multiplayerRoom.Countdown = null; - raiseRoomUpdated(); + clearRoomCountdown(); break; } }); @@ -244,14 +243,14 @@ namespace osu.Game.Tests.Visual.Multiplayer }); AddStep("start countdown", () => multiplayerClient.Object.SendMatchRequest(new StartMatchCountdownRequest { Duration = TimeSpan.FromMinutes(1) }).WaitSafely()); - AddUntilStep("countdown started", () => multiplayerRoom.Countdown != null); + AddUntilStep("countdown started", () => multiplayerRoom.ActiveCountdowns.Any()); AddStep("transfer host to local user", () => transferHost(localUser)); AddUntilStep("local user is host", () => multiplayerRoom.Host?.Equals(multiplayerClient.Object.LocalUser) == true); ClickButtonWhenEnabled(); checkLocalUserState(MultiplayerUserState.Ready); - AddAssert("countdown still active", () => multiplayerRoom.Countdown != null); + AddAssert("countdown still active", () => multiplayerRoom.ActiveCountdowns.Any()); } [Test] @@ -392,7 +391,13 @@ namespace osu.Game.Tests.Visual.Multiplayer private void setRoomCountdown(TimeSpan duration) { - multiplayerRoom.Countdown = new MatchStartCountdown { TimeRemaining = duration }; + multiplayerRoom.ActiveCountdowns.Add(new MatchStartCountdown { TimeRemaining = duration }); + raiseRoomUpdated(); + } + + private void clearRoomCountdown() + { + multiplayerRoom.ActiveCountdowns.Clear(); raiseRoomUpdated(); } diff --git a/osu.Game/Online/Multiplayer/Countdown/CountdownChangedEvent.cs b/osu.Game/Online/Multiplayer/Countdown/CountdownChangedEvent.cs deleted file mode 100644 index 649e3c8389..0000000000 --- a/osu.Game/Online/Multiplayer/Countdown/CountdownChangedEvent.cs +++ /dev/null @@ -1,20 +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 MessagePack; - -namespace osu.Game.Online.Multiplayer.Countdown -{ - /// - /// Indicates a change to the 's countdown. - /// - [MessagePackObject] - public class CountdownChangedEvent : MatchServerEvent - { - /// - /// The new countdown. - /// - [Key(0)] - public MultiplayerCountdown? Countdown { get; set; } - } -} diff --git a/osu.Game/Online/Multiplayer/Countdown/CountdownStartedEvent.cs b/osu.Game/Online/Multiplayer/Countdown/CountdownStartedEvent.cs new file mode 100644 index 0000000000..1dbb27bce6 --- /dev/null +++ b/osu.Game/Online/Multiplayer/Countdown/CountdownStartedEvent.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using MessagePack; +using Newtonsoft.Json; + +namespace osu.Game.Online.Multiplayer.Countdown +{ + /// + /// Indicates that a countdown started in the . + /// + [MessagePackObject] + public class CountdownStartedEvent : MatchServerEvent + { + /// + /// The countdown that was started. + /// + [Key(0)] + public readonly MultiplayerCountdown Countdown; + + [JsonConstructor] + [SerializationConstructor] + public CountdownStartedEvent(MultiplayerCountdown countdown) + { + Countdown = countdown; + } + } +} diff --git a/osu.Game/Online/Multiplayer/Countdown/CountdownStoppedEvent.cs b/osu.Game/Online/Multiplayer/Countdown/CountdownStoppedEvent.cs new file mode 100644 index 0000000000..b46ed0e5e0 --- /dev/null +++ b/osu.Game/Online/Multiplayer/Countdown/CountdownStoppedEvent.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using MessagePack; +using Newtonsoft.Json; + +namespace osu.Game.Online.Multiplayer.Countdown +{ + /// + /// Indicates that a countdown was stopped in the . + /// + [MessagePackObject] + public class CountdownStoppedEvent : MatchServerEvent + { + /// + /// The identifier of the countdown that was stopped. + /// + [Key(0)] + public readonly int ID; + + [JsonConstructor] + [SerializationConstructor] + public CountdownStoppedEvent(int id) + { + ID = id; + } + } +} diff --git a/osu.Game/Online/Multiplayer/Countdown/StopCountdownRequest.cs b/osu.Game/Online/Multiplayer/Countdown/StopCountdownRequest.cs index bd0c381c0b..495252c044 100644 --- a/osu.Game/Online/Multiplayer/Countdown/StopCountdownRequest.cs +++ b/osu.Game/Online/Multiplayer/Countdown/StopCountdownRequest.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using MessagePack; +using Newtonsoft.Json; namespace osu.Game.Online.Multiplayer.Countdown { @@ -11,5 +12,14 @@ namespace osu.Game.Online.Multiplayer.Countdown [MessagePackObject] public class StopCountdownRequest : MatchUserRequest { + [Key(0)] + public readonly int ID; + + [JsonConstructor] + [SerializationConstructor] + public StopCountdownRequest(int id) + { + ID = id; + } } } diff --git a/osu.Game/Online/Multiplayer/MatchServerEvent.cs b/osu.Game/Online/Multiplayer/MatchServerEvent.cs index 20bf9e5141..376ff4d261 100644 --- a/osu.Game/Online/Multiplayer/MatchServerEvent.cs +++ b/osu.Game/Online/Multiplayer/MatchServerEvent.cs @@ -13,7 +13,8 @@ namespace osu.Game.Online.Multiplayer [Serializable] [MessagePackObject] // IMPORTANT: Add rules to SignalRUnionWorkaroundResolver for new derived types. - [Union(0, typeof(CountdownChangedEvent))] + [Union(0, typeof(CountdownStartedEvent))] + [Union(1, typeof(CountdownStoppedEvent))] public abstract class MatchServerEvent { } diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 04b87c19da..5575113a87 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -550,8 +550,14 @@ namespace osu.Game.Online.Multiplayer switch (e) { - case CountdownChangedEvent countdownChangedEvent: - Room.Countdown = countdownChangedEvent.Countdown; + case CountdownStartedEvent countdownStartedEvent: + Room.ActiveCountdowns.Add(countdownStartedEvent.Countdown); + break; + + case CountdownStoppedEvent countdownStoppedEvent: + MultiplayerCountdown? countdown = Room.ActiveCountdowns.FirstOrDefault(countdown => countdown.ID == countdownStoppedEvent.ID); + if (countdown != null) + Room.ActiveCountdowns.Remove(countdown); break; } diff --git a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs index 621f9236fd..00bfa8919a 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs @@ -15,13 +15,19 @@ namespace osu.Game.Online.Multiplayer [Union(1, typeof(ForceGameplayStartCountdown))] public abstract class MultiplayerCountdown { + /// + /// A unique identifier for this countdown. + /// + [Key(0)] + public int ID { get; set; } + /// /// The amount of time remaining in the countdown. /// /// - /// This is only sent once from the server upon initial retrieval of the or via a . + /// This is only sent once from the server upon initial retrieval of the or via a . /// - [Key(0)] + [Key(1)] public TimeSpan TimeRemaining { get; set; } } } diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs index fb05c03256..00048fa931 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs @@ -53,10 +53,10 @@ namespace osu.Game.Online.Multiplayer public IList Playlist { get; set; } = new List(); /// - /// The currently-running countdown. + /// The currently running countdowns. /// [Key(7)] - public MultiplayerCountdown? Countdown { get; set; } + public IList ActiveCountdowns { get; set; } = new List(); [JsonConstructor] [SerializationConstructor] diff --git a/osu.Game/Online/SignalRWorkaroundTypes.cs b/osu.Game/Online/SignalRWorkaroundTypes.cs index 29e01e13ae..3518fbb4fe 100644 --- a/osu.Game/Online/SignalRWorkaroundTypes.cs +++ b/osu.Game/Online/SignalRWorkaroundTypes.cs @@ -23,7 +23,8 @@ namespace osu.Game.Online (typeof(ChangeTeamRequest), typeof(MatchUserRequest)), (typeof(StartMatchCountdownRequest), typeof(MatchUserRequest)), (typeof(StopCountdownRequest), typeof(MatchUserRequest)), - (typeof(CountdownChangedEvent), typeof(MatchServerEvent)), + (typeof(CountdownStartedEvent), typeof(MatchServerEvent)), + (typeof(CountdownStoppedEvent), typeof(MatchServerEvent)), (typeof(TeamVersusRoomState), typeof(MatchRoomState)), (typeof(TeamVersusUserState), typeof(MatchUserState)), (typeof(MatchStartCountdown), typeof(MultiplayerCountdown)), diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs index 501c76f65b..f048ae59cd 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs @@ -109,7 +109,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match Debug.Assert(clickOperation == null); clickOperation = ongoingOperationTracker.BeginOperation(); - if (isReady() && Client.IsHost && Room.Countdown == null) + if (isReady() && Client.IsHost && !Room.ActiveCountdowns.Any(c => c is MatchStartCountdown)) startMatch(); else toggleReady(); @@ -140,10 +140,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private void cancelCountdown() { + if (Client.Room == null) + return; + Debug.Assert(clickOperation == null); clickOperation = ongoingOperationTracker.BeginOperation(); - Client.SendMatchRequest(new StopCountdownRequest()).ContinueWith(_ => endOperation()); + MultiplayerCountdown countdown = Client.Room.ActiveCountdowns.Single(c => c is MatchStartCountdown); + Client.SendMatchRequest(new StopCountdownRequest(countdown.ID)).ContinueWith(_ => endOperation()); } private void endOperation() @@ -192,7 +196,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match // When the local user is the host and spectating the match, the ready button should be enabled only if any users are ready. if (localUser?.State == MultiplayerUserState.Spectating) - readyButton.Enabled.Value &= Client.IsHost && newCountReady > 0 && Room.Countdown == null; + readyButton.Enabled.Value &= Client.IsHost && newCountReady > 0 && !Room.ActiveCountdowns.Any(c => c is MatchStartCountdown); if (newCountReady == countReady) return; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs index 14bf1a8375..cd94b47d9e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Extensions; @@ -79,7 +80,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private void onRoomUpdated() => Scheduler.AddOnce(() => { - bool countdownActive = multiplayerClient.Room?.Countdown is MatchStartCountdown; + bool countdownActive = multiplayerClient.Room?.ActiveCountdowns.Any(c => c is MatchStartCountdown) == true; if (countdownActive) { @@ -121,7 +122,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match }); } - if (multiplayerClient.Room?.Countdown != null && multiplayerClient.IsHost) + if (multiplayerClient.Room?.ActiveCountdowns.Any(c => c is MatchStartCountdown) == true && multiplayerClient.IsHost) { flow.Add(new OsuButton { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs index c5d6da1ebc..b4ff34cbc2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs @@ -57,23 +57,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private void onRoomUpdated() => Scheduler.AddOnce(() => { - MultiplayerCountdown newCountdown; - - switch (room?.Countdown) - { - case MatchStartCountdown: - newCountdown = room.Countdown; - break; - - // Clear the countdown with any other (including non-null) countdown values. - default: - newCountdown = null; - break; - } + MultiplayerCountdown newCountdown = room?.ActiveCountdowns.SingleOrDefault(c => c is MatchStartCountdown); if (newCountdown != countdown) { - countdown = room?.Countdown; + countdown = newCountdown; countdownChangeTime = Time.Current; } @@ -213,7 +201,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match case MultiplayerUserState.Spectating: case MultiplayerUserState.Ready: - if (room?.Host?.Equals(localUser) == true && room.Countdown == null) + if (room?.Host?.Equals(localUser) == true && !room.ActiveCountdowns.Any(c => c is MatchStartCountdown)) setGreen(); else setYellow(); @@ -248,8 +236,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { get { - if (room?.Countdown != null && multiplayerClient.IsHost && multiplayerClient.LocalUser?.State == MultiplayerUserState.Ready && !room.Settings.AutoStartEnabled) + if (room?.ActiveCountdowns.Any(c => c is MatchStartCountdown) == true + && multiplayerClient.IsHost + && multiplayerClient.LocalUser?.State == MultiplayerUserState.Ready + && !room.Settings.AutoStartEnabled) + { return "Cancel countdown"; + } return base.TooltipText; } From f754686521f4262c7194e2503857b351b796fb64 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 18:57:33 +0900 Subject: [PATCH 0886/2686] Remove necessity of `AlwaysPresent` for `ProgressUpdate` completion posting --- osu.Game/Overlays/NotificationOverlay.cs | 7 +++---- osu.Game/Overlays/NotificationOverlayToastTray.cs | 2 +- .../Overlays/Notifications/ProgressNotification.cs | 13 ++++++------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index fca43e65a5..b170ea5dfa 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -71,7 +71,6 @@ namespace osu.Game.Overlays }, mainContent = new Container { - AlwaysPresent = true, RelativeSizeAxes = Axes.Both, Children = new Drawable[] { @@ -137,9 +136,9 @@ namespace osu.Game.Overlays private readonly Scheduler postScheduler = new Scheduler(); - public override bool IsPresent => base.IsPresent - || postScheduler.HasPendingTasks - || toastTray.IsDisplayingToasts; + public override bool IsPresent => + // Delegate presence as we need to consider the toast tray in addition to the main overlay. + State.Value == Visibility.Visible || mainContent.IsPresent || toastTray.IsPresent || postScheduler.HasPendingTasks; private bool processingPosts = true; diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index aa61e20a02..ebf8fb32a9 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -70,7 +70,7 @@ namespace osu.Game.Overlays postEffectDrawable.AutoSizeAxes = Axes.None; postEffectDrawable.RelativeSizeAxes = Axes.X; })), - toastFlow = new AlwaysUpdateFillFlowContainer + toastFlow = new FillFlowContainer { LayoutDuration = 150, LayoutEasing = Easing.OutQuart, diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 6821c25ac0..b5af3a56a1 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -88,7 +88,12 @@ namespace osu.Game.Overlays.Notifications state = value; if (IsLoaded) + { Schedule(updateState); + + if (state == ProgressNotificationState.Completed) + CompletionTarget?.Invoke(CreateCompletionNotification()); + } } } @@ -141,7 +146,7 @@ namespace osu.Game.Overlays.Notifications case ProgressNotificationState.Completed: loadingSpinner.Hide(); - Completed(); + base.Close(); break; } } @@ -154,12 +159,6 @@ namespace osu.Game.Overlays.Notifications Text = CompletionText }; - protected void Completed() - { - CompletionTarget?.Invoke(CreateCompletionNotification()); - base.Close(); - } - public override bool DisplayOnTop => false; public override bool IsImportant => false; From 229e1a8ef7a97639dd328c90ca96afaf6f5ee424 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 18:42:37 +0900 Subject: [PATCH 0887/2686] Fix notification overlay being present when it doesn't need to --- .../UserInterface/TestSceneNotificationOverlay.cs | 14 ++++++++++++++ osu.Game/Overlays/NotificationOverlayToastTray.cs | 2 ++ 2 files changed, 16 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 288f1f78bc..8c7ad5f061 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; @@ -44,6 +45,18 @@ namespace osu.Game.Tests.Visual.UserInterface notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count.NewValue}"; }; }); + [Test] + public void TestPresence() + { + AddAssert("tray not present", () => !notificationOverlay.ChildrenOfType().Single().IsPresent); + AddAssert("overlay not present", () => !notificationOverlay.IsPresent); + + AddStep(@"post notification", sendBackgroundNotification); + + AddUntilStep("wait tray not present", () => !notificationOverlay.ChildrenOfType().Single().IsPresent); + AddUntilStep("wait overlay not present", () => !notificationOverlay.IsPresent); + } + [Test] public void TestCompleteProgress() { @@ -63,6 +76,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait completion", () => notification.State == ProgressNotificationState.Completed); AddAssert("Completion toast shown", () => notificationOverlay.ToastCount == 1); + AddUntilStep("wait forwarded", () => notificationOverlay.ToastCount == 0); } [Test] diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index ebf8fb32a9..df9bbac887 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -24,6 +24,8 @@ namespace osu.Game.Overlays /// public class NotificationOverlayToastTray : CompositeDrawable { + public override bool IsPresent => IsDisplayingToasts; + public bool IsDisplayingToasts => displayedCount > 0; private FillFlowContainer toastFlow = null!; From 0514c961915a250c22a32bf3d466ee5d8239b072 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 19:20:01 +0900 Subject: [PATCH 0888/2686] Fix incorrect count tracking when notification is manually disposed --- .../UserInterface/TestSceneNotificationOverlay.cs | 13 +++++++++++++ osu.Game/Overlays/NotificationOverlayToastTray.cs | 13 ++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 8c7ad5f061..699b8f7d89 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -57,6 +57,19 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait overlay not present", () => !notificationOverlay.IsPresent); } + [Test] + public void TestPresenceWithManualDismiss() + { + AddAssert("tray not present", () => !notificationOverlay.ChildrenOfType().Single().IsPresent); + AddAssert("overlay not present", () => !notificationOverlay.IsPresent); + + AddStep(@"post notification", sendBackgroundNotification); + AddStep("click notification", () => notificationOverlay.ChildrenOfType().Single().TriggerClick()); + + AddUntilStep("wait tray not present", () => !notificationOverlay.ChildrenOfType().Single().IsPresent); + AddUntilStep("wait overlay not present", () => !notificationOverlay.IsPresent); + } + [Test] public void TestCompleteProgress() { diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index df9bbac887..4f98b9f40c 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -97,6 +97,8 @@ namespace osu.Game.Overlays public void Post(Notification notification) { + notification.Closed += stopTrackingNotification; + ++runningDepth; displayedCount++; @@ -139,14 +141,23 @@ namespace osu.Game.Overlays notification.MoveToOffset(new Vector2(400, 0), NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint); notification.FadeOut(NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint).OnComplete(_ => { + notification.Closed -= stopTrackingNotification; + if (!notification.WasClosed) + stopTrackingNotification(); + RemoveInternal(notification, false); - displayedCount--; ForwardNotificationToPermanentStore?.Invoke(notification); notification.FadeIn(300, Easing.OutQuint); }); } + private void stopTrackingNotification() + { + Debug.Assert(displayedCount > 0); + displayedCount--; + } + protected override void Update() { base.Update(); From 510972e3add24d7aebe619d68a56017a70fcbf67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 19:35:15 +0900 Subject: [PATCH 0889/2686] Avoid reference counting by using height calculation for `IsPresent` instead The reference counting was to guarantee performance (zero allocations) when the notification overlay was not required, but adds extra complexity. Instead, the toast tray now uses its ongoing height calculation as a metric for presence. --- .../Overlays/NotificationOverlayToastTray.cs | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index 4f98b9f40c..f9c4f657eb 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -24,9 +24,9 @@ namespace osu.Game.Overlays /// public class NotificationOverlayToastTray : CompositeDrawable { - public override bool IsPresent => IsDisplayingToasts; + public override bool IsPresent => toastContentBackground.Height > 0 || toastFlow.Count > 0; - public bool IsDisplayingToasts => displayedCount > 0; + public bool IsDisplayingToasts => allNotifications.Any(); private FillFlowContainer toastFlow = null!; private BufferedContainer toastContentBackground = null!; @@ -42,8 +42,6 @@ namespace osu.Game.Overlays private int runningDepth; - private int displayedCount; - [BackgroundDependencyLoader] private void load() { @@ -61,6 +59,7 @@ namespace osu.Game.Overlays colourProvider.Background6.Opacity(0.7f), colourProvider.Background6.Opacity(0.5f)), RelativeSizeAxes = Axes.Both, + Height = 0, }.WithEffect(new BlurEffect { PadExtent = true, @@ -97,10 +96,7 @@ namespace osu.Game.Overlays public void Post(Notification notification) { - notification.Closed += stopTrackingNotification; - ++runningDepth; - displayedCount++; int depth = notification.DisplayOnTop ? -runningDepth : runningDepth; @@ -141,10 +137,6 @@ namespace osu.Game.Overlays notification.MoveToOffset(new Vector2(400, 0), NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint); notification.FadeOut(NotificationOverlay.TRANSITION_LENGTH, Easing.OutQuint).OnComplete(_ => { - notification.Closed -= stopTrackingNotification; - if (!notification.WasClosed) - stopTrackingNotification(); - RemoveInternal(notification, false); ForwardNotificationToPermanentStore?.Invoke(notification); @@ -152,17 +144,11 @@ namespace osu.Game.Overlays }); } - private void stopTrackingNotification() - { - Debug.Assert(displayedCount > 0); - displayedCount--; - } - protected override void Update() { base.Update(); - float height = toastFlow.DrawHeight + 120; + float height = toastFlow.Count > 0 ? toastFlow.DrawHeight + 120 : 0; float alpha = toastFlow.Count > 0 ? MathHelper.Clamp(toastFlow.DrawHeight / 41, 0, 1) * toastFlow.Children.Max(n => n.Alpha) : 0; toastContentBackground.Height = (float)Interpolation.DampContinuously(toastContentBackground.Height, height, 10, Clock.ElapsedFrameTime); From b2f30fbf8cb7e76d02d8cb957d6a2eb1328f2b1e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Sep 2022 20:13:23 +0900 Subject: [PATCH 0890/2686] Add countdown exclusivity --- osu.Game/Online/Multiplayer/ForceGameplayStartCountdown.cs | 3 ++- osu.Game/Online/Multiplayer/MatchStartCountdown.cs | 3 ++- osu.Game/Online/Multiplayer/MultiplayerCountdown.cs | 5 +++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Multiplayer/ForceGameplayStartCountdown.cs b/osu.Game/Online/Multiplayer/ForceGameplayStartCountdown.cs index 7f5c0f0a05..81ba56f35c 100644 --- a/osu.Game/Online/Multiplayer/ForceGameplayStartCountdown.cs +++ b/osu.Game/Online/Multiplayer/ForceGameplayStartCountdown.cs @@ -13,7 +13,8 @@ namespace osu.Game.Online.Multiplayer /// and forcing progression of any clients that are blocking load due to user interaction. /// [MessagePackObject] - public class ForceGameplayStartCountdown : MultiplayerCountdown + public sealed class ForceGameplayStartCountdown : MultiplayerCountdown { + public override bool IsExclusive => true; } } diff --git a/osu.Game/Online/Multiplayer/MatchStartCountdown.cs b/osu.Game/Online/Multiplayer/MatchStartCountdown.cs index 5d3365c947..b4c66e6f5b 100644 --- a/osu.Game/Online/Multiplayer/MatchStartCountdown.cs +++ b/osu.Game/Online/Multiplayer/MatchStartCountdown.cs @@ -9,7 +9,8 @@ namespace osu.Game.Online.Multiplayer /// A which will start the match after ending. /// [MessagePackObject] - public class MatchStartCountdown : MultiplayerCountdown + public sealed class MatchStartCountdown : MultiplayerCountdown { + public override bool IsExclusive => true; } } diff --git a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs index 00bfa8919a..e8e2365f7b 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs @@ -29,5 +29,10 @@ namespace osu.Game.Online.Multiplayer /// [Key(1)] public TimeSpan TimeRemaining { get; set; } + + /// + /// Whether only a single instance of this type may be active at any one time. + /// + public virtual bool IsExclusive => false; } } From e33486a766044c17c2f254f5e8df6d72b29c341e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 23:20:02 +0900 Subject: [PATCH 0891/2686] Implement `IAdjustableAudioComponent` in `MasterGameplayClockContainer` --- .../Play/MasterGameplayClockContainer.cs | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 2f1ffa126f..57e67e6e26 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Play /// /// This is intended to be used as a single controller for gameplay, or as a reference source for other s. /// - public class MasterGameplayClockContainer : GameplayClockContainer, IBeatSyncProvider + public class MasterGameplayClockContainer : GameplayClockContainer, IBeatSyncProvider, IAdjustableAudioComponent { /// /// Duration before gameplay start time required before skip button displays. @@ -41,6 +41,8 @@ namespace osu.Game.Screens.Play private readonly WorkingBeatmap beatmap; + private readonly Track track; + private readonly double skipTargetTime; private readonly List> nonGameplayAdjustments = new List>(); @@ -66,6 +68,7 @@ namespace osu.Game.Screens.Play public MasterGameplayClockContainer(WorkingBeatmap beatmap, double skipTargetTime) : base(beatmap.Track, true) { + track = beatmap.Track; this.beatmap = beatmap; this.skipTargetTime = skipTargetTime; @@ -195,9 +198,6 @@ namespace osu.Game.Screens.Play if (speedAdjustmentsApplied) return; - if (SourceClock is not Track track) - return; - track.AddAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); @@ -212,9 +212,6 @@ namespace osu.Game.Screens.Play if (!speedAdjustmentsApplied) return; - if (SourceClock is not Track track) - return; - track.RemoveAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); @@ -234,5 +231,29 @@ namespace osu.Game.Screens.Play IClock IBeatSyncProvider.Clock => this; ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; + + void IAdjustableAudioComponent.AddAdjustment(AdjustableProperty type, IBindable adjustBindable) => + track.AddAdjustment(type, adjustBindable); + + void IAdjustableAudioComponent.RemoveAdjustment(AdjustableProperty type, IBindable adjustBindable) => + track.RemoveAdjustment(type, adjustBindable); + + public void RemoveAllAdjustments(AdjustableProperty type) + { + throw new NotImplementedException(); + } + + public void BindAdjustments(IAggregateAudioAdjustment component) => throw new NotImplementedException(); + public void UnbindAdjustments(IAggregateAudioAdjustment component) => throw new NotImplementedException(); + + public BindableNumber Volume => throw new NotImplementedException(); + public BindableNumber Balance => throw new NotImplementedException(); + public BindableNumber Frequency => throw new NotImplementedException(); + public BindableNumber Tempo => throw new NotImplementedException(); + + public IBindable AggregateVolume => throw new NotImplementedException(); + public IBindable AggregateBalance => throw new NotImplementedException(); + public IBindable AggregateFrequency => throw new NotImplementedException(); + public IBindable AggregateTempo => throw new NotImplementedException(); } } From 7084aeee0523af04c380ef1ee2cee143d18f2fcc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 23:22:38 +0900 Subject: [PATCH 0892/2686] Add method flow to reset applied adjustments --- osu.Game/Screens/Play/GameplayClockContainer.cs | 4 +++- osu.Game/Screens/Play/MasterGameplayClockContainer.cs | 7 +++++-- osu.Game/Screens/Play/Player.cs | 9 ++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 6de88d7ad0..490c2329ca 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -196,7 +196,9 @@ namespace osu.Game.Screens.Play void IAdjustableClock.Reset() => Reset(); - public void ResetSpeedAdjustments() => throw new NotImplementedException(); + public virtual void ResetSpeedAdjustments() + { + } double IAdjustableClock.Rate { diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 57e67e6e26..15e9a40fd3 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -238,11 +238,14 @@ namespace osu.Game.Screens.Play void IAdjustableAudioComponent.RemoveAdjustment(AdjustableProperty type, IBindable adjustBindable) => track.RemoveAdjustment(type, adjustBindable); - public void RemoveAllAdjustments(AdjustableProperty type) + public override void ResetSpeedAdjustments() { - throw new NotImplementedException(); + track.RemoveAllAdjustments(AdjustableProperty.Frequency); + track.RemoveAllAdjustments(AdjustableProperty.Tempo); } + public void RemoveAllAdjustments(AdjustableProperty type) => throw new NotImplementedException(); + public void BindAdjustments(IAggregateAudioAdjustment component) => throw new NotImplementedException(); public void UnbindAdjustments(IAggregateAudioAdjustment component) => throw new NotImplementedException(); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 4afd04c335..21a02fbe0b 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -999,9 +999,12 @@ namespace osu.Game.Screens.Play // Our mods are local copies of the global mods so they need to be re-applied to the track. // This is done through the music controller (for now), because resetting speed adjustments on the beatmap track also removes adjustments provided by DrawableTrack. // Todo: In the future, player will receive in a track and will probably not have to worry about this... - musicController.ResetTrackAdjustments(); - foreach (var mod in GameplayState.Mods.OfType()) - mod.ApplyToTrack(musicController.CurrentTrack); + if (GameplayClockContainer is IAdjustableAudioComponent adjustableClock) + { + GameplayClockContainer.ResetSpeedAdjustments(); + foreach (var mod in GameplayState.Mods.OfType()) + mod.ApplyToTrack(adjustableClock); + } updateGameplayState(); From 266eb758aa2471d1cdb54253ab564e02a27764a3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 23:37:41 +0900 Subject: [PATCH 0893/2686] Use new flow to calcaulate `TrueGameplayRate` --- .../Screens/Play/GameplayClockContainer.cs | 19 +--------- .../Play/MasterGameplayClockContainer.cs | 35 ++++++++++++------- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 490c2329ca..4d48675f94 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Framework.Timing; -using osu.Framework.Utils; using osu.Game.Beatmaps; namespace osu.Game.Screens.Play @@ -225,22 +224,6 @@ namespace osu.Game.Screens.Play public FrameTimeInfo TimeInfo => GameplayClock.TimeInfo; - public double TrueGameplayRate - { - get - { - double baseRate = Rate; - - foreach (double adjustment in NonGameplayAdjustments) - { - if (Precision.AlmostEquals(adjustment, 0)) - return 0; - - baseRate /= adjustment; - } - - return baseRate; - } - } + public virtual double TrueGameplayRate => Rate; } } diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 15e9a40fd3..bda8718dc6 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -45,8 +45,6 @@ namespace osu.Game.Screens.Play private readonly double skipTargetTime; - private readonly List> nonGameplayAdjustments = new List>(); - /// /// Stores the time at which the last call was triggered. /// This is used to ensure we resume from that precise point in time, ignoring the proceeding frequency ramp. @@ -58,8 +56,6 @@ namespace osu.Game.Screens.Play /// private double? actualStopTime; - public override IEnumerable NonGameplayAdjustments => nonGameplayAdjustments.Select(b => b.Value); - /// /// Create a new master gameplay clock container. /// @@ -201,9 +197,6 @@ namespace osu.Game.Screens.Play track.AddAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); - nonGameplayAdjustments.Add(GameplayClock.ExternalPauseFrequencyAdjust); - nonGameplayAdjustments.Add(UserPlaybackRate); - speedAdjustmentsApplied = true; } @@ -215,9 +208,6 @@ namespace osu.Game.Screens.Play track.RemoveAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); - nonGameplayAdjustments.Remove(GameplayClock.ExternalPauseFrequencyAdjust); - nonGameplayAdjustments.Remove(UserPlaybackRate); - speedAdjustmentsApplied = false; } @@ -232,11 +222,30 @@ namespace osu.Game.Screens.Play ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; - void IAdjustableAudioComponent.AddAdjustment(AdjustableProperty type, IBindable adjustBindable) => - track.AddAdjustment(type, adjustBindable); + private readonly List> speedAdjustments = new List>(); - void IAdjustableAudioComponent.RemoveAdjustment(AdjustableProperty type, IBindable adjustBindable) => + public override double TrueGameplayRate + { + get + { + double rate = Rate; + foreach (var a in speedAdjustments) + rate *= a.Value; + return rate; + } + } + + void IAdjustableAudioComponent.AddAdjustment(AdjustableProperty type, IBindable adjustBindable) + { + speedAdjustments.Add(adjustBindable); + track.AddAdjustment(type, adjustBindable); + } + + void IAdjustableAudioComponent.RemoveAdjustment(AdjustableProperty type, IBindable adjustBindable) + { + speedAdjustments.Remove(adjustBindable); track.RemoveAdjustment(type, adjustBindable); + } public override void ResetSpeedAdjustments() { From 44b456e216741a814bc61018aa08c2642465ea74 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 5 Sep 2022 23:38:22 +0900 Subject: [PATCH 0894/2686] Use gameplay clock's `TrueGameplayRate` in `FrameStabilityContainer`? --- .../Rulesets/UI/FrameStabilityContainer.cs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 18d0ff0bed..4d817cd973 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -263,23 +263,7 @@ namespace osu.Game.Rulesets.UI public FrameTimeInfo TimeInfo => framedClock.TimeInfo; - public double TrueGameplayRate - { - get - { - double baseRate = Rate; - - foreach (double adjustment in NonGameplayAdjustments) - { - if (Precision.AlmostEquals(adjustment, 0)) - return 0; - - baseRate /= adjustment; - } - - return baseRate; - } - } + public double TrueGameplayRate => parentGameplayClock?.TrueGameplayRate ?? Rate; public double StartTime => parentGameplayClock?.StartTime ?? 0; From b109e5de6ce537916252487ccd183ef870012afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Tue, 6 Sep 2022 00:04:10 +0900 Subject: [PATCH 0895/2686] chore(osu.Game): align height of bars on timing distribution graph to `basalHeight` first and combine their transitions into each one --- .../Statistics/HitEventTimingDistributionGraph.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 1be32a94af..5fbc07921a 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -278,9 +278,7 @@ namespace osu.Game.Screens.Ranking.Statistics } } - private const double total_duration = 300; - - private double duration => total_duration / Math.Max(values.Count, 1); + private const double duration = 300; private float offsetForValue(float value) { @@ -296,19 +294,20 @@ namespace osu.Game.Screens.Ranking.Statistics { base.LoadComplete(); + foreach (var boxOriginal in boxOriginals) + boxOriginal.Height = basalHeight; + float offsetValue = 0; if (values.Any()) { for (int i = 0; i < values.Count; i++) { - boxOriginals[i].Y = BoundingBox.Height * offsetForValue(offsetValue); - boxOriginals[i].Delay(duration * i).ResizeHeightTo(heightForValue(values[i].Value), duration, Easing.OutQuint); + boxOriginals[i].MoveToY(offsetForValue(offsetValue) * BoundingBox.Height, duration, Easing.OutQuint); + boxOriginals[i].ResizeHeightTo(heightForValue(values[i].Value), duration, Easing.OutQuint); offsetValue -= values[i].Value; } } - else - boxOriginals.Single().ResizeHeightTo(basalHeight, duration, Easing.OutQuint); } public void UpdateOffset(float adjustment) From 9e3228aa651181b5a531ccf8fc6b5da15962d7ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 04:07:49 +0900 Subject: [PATCH 0896/2686] Fix completion notification not being posted if completion occurs during `NotificationOverlay` load --- .../Navigation/TestSceneStartupImport.cs | 4 +-- .../ProgressCompletionNotification.cs | 2 -- .../Notifications/ProgressNotification.cs | 33 ++++++++++++++----- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneStartupImport.cs b/osu.Game.Tests/Visual/Navigation/TestSceneStartupImport.cs index cd53bf3af5..552eb82419 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneStartupImport.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneStartupImport.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. -#nullable disable - using System.Linq; using NUnit.Framework; using osu.Framework.Testing; @@ -13,7 +11,7 @@ namespace osu.Game.Tests.Visual.Navigation { public class TestSceneStartupImport : OsuGameTestScene { - private string importFilename; + private string? importFilename; protected override TestOsuGame CreateTestGame() => new TestOsuGame(LocalStorage, API, new[] { importFilename }); diff --git a/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs index 49d558285c..3cbdf7edf7 100644 --- a/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.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. -#nullable disable - using osu.Framework.Allocation; using osu.Game.Graphics; using osu.Framework.Graphics.Colour; diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index b5af3a56a1..64ad69adf3 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -71,7 +71,7 @@ namespace osu.Game.Overlays.Notifications base.LoadComplete(); // we may have received changes before we were displayed. - updateState(); + Scheduler.AddOnce(updateState); } private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); @@ -87,13 +87,8 @@ namespace osu.Game.Overlays.Notifications state = value; - if (IsLoaded) - { - Schedule(updateState); - - if (state == ProgressNotificationState.Completed) - CompletionTarget?.Invoke(CreateCompletionNotification()); - } + Scheduler.AddOnce(updateState); + attemptPostCompletion(); } } @@ -146,11 +141,33 @@ namespace osu.Game.Overlays.Notifications case ProgressNotificationState.Completed: loadingSpinner.Hide(); + attemptPostCompletion(); base.Close(); break; } } + private bool completionSent; + + /// + /// Attempt to post a completion notification. + /// + private void attemptPostCompletion() + { + if (state != ProgressNotificationState.Completed) return; + + // This notification may not have been posted yet (and thus may not have a target to post the completion to). + // Completion posting will be re-attempted in a scheduled invocation. + if (CompletionTarget == null) + return; + + if (completionSent) + return; + + CompletionTarget.Invoke(CreateCompletionNotification()); + completionSent = true; + } + private ProgressNotificationState state; protected virtual Notification CreateCompletionNotification() => new ProgressCompletionNotification From cfa1ebd0cb632cfba79e1c535952f282880ccc84 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Tue, 6 Sep 2022 03:00:13 +0200 Subject: [PATCH 0897/2686] Test fix --- osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index 74387e1d8e..e3603ee90c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -155,7 +155,7 @@ namespace osu.Game.Tests.Visual.Gameplay hitErrorMeter.Hide(); }); - AddRepeatStep("hit", () => newJudgement(), ColourHitErrorMeter.HitErrorShape. *2); + AddRepeatStep("hit", () => newJudgement(), 10); AddAssert("bars added", () => this.ChildrenOfType().Any()); AddAssert("circle added", () => this.ChildrenOfType().Any()); @@ -164,7 +164,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("ensure max circles not exceeded", () => { return this.ChildrenOfType() - .All(m => m.ChildrenOfType().Count() <= ColourHitErrorMeter.HitShapeCount.Default); + .All(m => m.ChildrenOfType().Count() <= 10); }); AddStep("show displays", () => From abf02426862da854f93a257b9d2cd520f601ab4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 16:16:54 +0900 Subject: [PATCH 0898/2686] Add failing test for incorrect start time of storyboard elements --- .../Formats/LegacyStoryboardDecoderTest.cs | 17 +++++++++++++++++ .../loop-containing-earlier-non-zero-fade.osb | 8 ++++++++ 2 files changed, 25 insertions(+) create mode 100644 osu.Game.Tests/Resources/loop-containing-earlier-non-zero-fade.osb diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index 57dded8ee4..8dcbdb8435 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -117,6 +117,23 @@ namespace osu.Game.Tests.Beatmaps.Formats } } + [Test] + public void TestEarliestStartTimeWithLoopAlphas() + { + var decoder = new LegacyStoryboardDecoder(); + + using (var resStream = TestResources.OpenResource("loop-containing-earlier-non-zero-fade.osb")) + using (var stream = new LineBufferedReader(resStream)) + { + var storyboard = decoder.Decode(stream); + + StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); + Assert.AreEqual(1, background.Elements.Count); + Assert.AreEqual(1000, background.Elements[0].StartTime); + Assert.AreEqual(1000, storyboard.EarliestEventTime); + } + } + [Test] public void TestDecodeVariableWithSuffix() { diff --git a/osu.Game.Tests/Resources/loop-containing-earlier-non-zero-fade.osb b/osu.Game.Tests/Resources/loop-containing-earlier-non-zero-fade.osb new file mode 100644 index 0000000000..5c80bc620c --- /dev/null +++ b/osu.Game.Tests/Resources/loop-containing-earlier-non-zero-fade.osb @@ -0,0 +1,8 @@ +osu file format v14 + +[Events] +//Storyboard Layer 0 (Background) +Sprite,Background,TopCentre,"img.jpg",320,240 + L,1000,1 + F,0,0,,1 // fade inside a loop with non-zero alpha and an earlier start time should be the true start time.. + F,0,2000,,0 // ..not a zero alpha fade with a later start time From a5e57b083c09a136a0248c07266b9838bd147bf7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 15:48:54 +0900 Subject: [PATCH 0899/2686] Remove `EarliestDisplayTime`'s input to `CommandStartTime` --- osu.Game/Storyboards/CommandTimelineGroup.cs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/osu.Game/Storyboards/CommandTimelineGroup.cs b/osu.Game/Storyboards/CommandTimelineGroup.cs index 6fc9f60177..de5da3118a 100644 --- a/osu.Game/Storyboards/CommandTimelineGroup.cs +++ b/osu.Game/Storyboards/CommandTimelineGroup.cs @@ -47,30 +47,11 @@ namespace osu.Game.Storyboards }; } - /// - /// Returns the earliest visible time. Will be null unless this group's first command has a start value of zero. - /// - public double? EarliestDisplayedTime - { - get - { - var first = Alpha.Commands.FirstOrDefault(); - - return first?.StartValue == 0 ? first.StartTime : null; - } - } - [JsonIgnore] public double CommandsStartTime { get { - // if the first alpha command starts at zero it should be given priority over anything else. - // this is due to it creating a state where the target is not present before that time, causing any other events to not be visible. - double? earliestDisplay = EarliestDisplayedTime; - if (earliestDisplay != null) - return earliestDisplay.Value; - double min = double.MaxValue; for (int i = 0; i < timelines.Length; i++) From bea42d286264e4d866dae8b9d58e0771b519f222 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 16:09:16 +0900 Subject: [PATCH 0900/2686] Handle earliest-alpha-start-time logic in `StoryboardSprite` itself --- osu.Game/Storyboards/StoryboardSprite.cs | 50 ++++++++++++++++++------ 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index a759482b5d..249be39b65 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -30,24 +30,52 @@ namespace osu.Game.Storyboards { get { - // check for presence affecting commands as an initial pass. - double earliestStartTime = TimelineGroup.EarliestDisplayedTime ?? double.MaxValue; + // To get the initial start time, we need to check whether the first alpha command to exist has an initial value of zero. + // A start value of zero on an alpha governs, above all else, the first valid display time of a sprite. + // + // To make this valid, we need to aggregate all alpha commands across all loops before checking for the first, time-wise, else we could run into a scenario where: + // L,1000,1 + // F,0,0,,1 # this NEEDS TO BE considered the StartTime... but has a StartValue greater than zero so won't in the initial pass. + // F,0,2000,,0 # ..this will be treated as earliest start due to a StartValue of zero. - foreach (var l in loops) + double zeroAlphaStartTimeOverride = double.MaxValue; + + var topLevelFirstAlphaCommand = TimelineGroup.Alpha.Commands.FirstOrDefault(); + if (topLevelFirstAlphaCommand?.StartValue == 0) + zeroAlphaStartTimeOverride = topLevelFirstAlphaCommand.StartTime; + + foreach (var loop in loops) { - if (l.EarliestDisplayedTime is double loopEarliestDisplayTime) - earliestStartTime = Math.Min(earliestStartTime, l.LoopStartTime + loopEarliestDisplayTime); + var loopFirstAlphaCommand = loop.Alpha.Commands.FirstOrDefault(); + + if (loopFirstAlphaCommand == null) + continue; + + double loopFirstAlphaStartTime = loopFirstAlphaCommand.StartTime + loop.LoopStartTime; + + if (loopFirstAlphaCommand.StartValue == 0) + { + // Found a loop containing a zero StartValue earlier than previous. + zeroAlphaStartTimeOverride = loopFirstAlphaStartTime; + } + else if (loopFirstAlphaStartTime < zeroAlphaStartTimeOverride) + { + // If a loop's first alpha command's StartValue is non-zero, we need to check whether the command's StartTime is less than any previously found zero alpha command. + // If this is the case, we want to abort zero alpha override logic and use the earliest command time instead. + // This is because if the first alpha command is non-zero, the sprite will be shown at that alpha from the time of the first command (of any type, not just alpha). + zeroAlphaStartTimeOverride = double.MaxValue; + break; + } } - if (earliestStartTime < double.MaxValue) - return earliestStartTime; - - // if an alpha-affecting command was not found, use the earliest of any command. - earliestStartTime = TimelineGroup.StartTime; + if (zeroAlphaStartTimeOverride < double.MaxValue) + return zeroAlphaStartTimeOverride; + // if we got to this point, either no alpha commands were present, or the earliest had a non-zero start value. + // the sprite's StartTime will be determined by the earliest command, of any type. + double earliestStartTime = TimelineGroup.StartTime; foreach (var l in loops) earliestStartTime = Math.Min(earliestStartTime, l.StartTime); - return earliestStartTime; } } From fa0a4614f8d90f18604349aef659ee521ad72ef0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 16:40:59 +0900 Subject: [PATCH 0901/2686] Add failing test for second incorrect case of start time handling --- .../Beatmaps/Formats/LegacyStoryboardDecoderTest.cs | 5 ++++- .../Resources/loop-containing-earlier-non-zero-fade.osb | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index 8dcbdb8435..6e41043b0b 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -128,8 +128,11 @@ namespace osu.Game.Tests.Beatmaps.Formats var storyboard = decoder.Decode(stream); StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); - Assert.AreEqual(1, background.Elements.Count); + Assert.AreEqual(2, background.Elements.Count); + Assert.AreEqual(1000, background.Elements[0].StartTime); + Assert.AreEqual(1000, background.Elements[1].StartTime); + Assert.AreEqual(1000, storyboard.EarliestEventTime); } } diff --git a/osu.Game.Tests/Resources/loop-containing-earlier-non-zero-fade.osb b/osu.Game.Tests/Resources/loop-containing-earlier-non-zero-fade.osb index 5c80bc620c..2ff7f9f56f 100644 --- a/osu.Game.Tests/Resources/loop-containing-earlier-non-zero-fade.osb +++ b/osu.Game.Tests/Resources/loop-containing-earlier-non-zero-fade.osb @@ -6,3 +6,9 @@ Sprite,Background,TopCentre,"img.jpg",320,240 L,1000,1 F,0,0,,1 // fade inside a loop with non-zero alpha and an earlier start time should be the true start time.. F,0,2000,,0 // ..not a zero alpha fade with a later start time + +Sprite,Background,TopCentre,"img.jpg",320,240 + L,2000,1 + F,0,0,24,0 // fade inside a loop with zero alpha but later start time than the top-level zero alpha start time. + F,0,24,48,1 + F,0,1000,,1 // ..so this should be the true start time From d667f4683050c7e2bcebf6488f887c2ff421462a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 16:41:32 +0900 Subject: [PATCH 0902/2686] Refactor alpha check to not overwrite sourced overrides with values from later commands --- osu.Game/Storyboards/StoryboardSprite.cs | 45 ++++++++++++++---------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index 249be39b65..0764969d02 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -32,17 +32,18 @@ namespace osu.Game.Storyboards { // To get the initial start time, we need to check whether the first alpha command to exist has an initial value of zero. // A start value of zero on an alpha governs, above all else, the first valid display time of a sprite. - // - // To make this valid, we need to aggregate all alpha commands across all loops before checking for the first, time-wise, else we could run into a scenario where: - // L,1000,1 - // F,0,0,,1 # this NEEDS TO BE considered the StartTime... but has a StartValue greater than zero so won't in the initial pass. - // F,0,2000,,0 # ..this will be treated as earliest start due to a StartValue of zero. - double zeroAlphaStartTimeOverride = double.MaxValue; + double earliestAlphaTime = double.MaxValue; var topLevelFirstAlphaCommand = TimelineGroup.Alpha.Commands.FirstOrDefault(); - if (topLevelFirstAlphaCommand?.StartValue == 0) - zeroAlphaStartTimeOverride = topLevelFirstAlphaCommand.StartTime; + + if (topLevelFirstAlphaCommand != null) + { + earliestAlphaTime = topLevelFirstAlphaCommand.StartTime; + if (topLevelFirstAlphaCommand.StartValue == 0) + // The found alpha command has a zero StartValue, so should be used as the new override. + zeroAlphaStartTimeOverride = topLevelFirstAlphaCommand.StartTime; + } foreach (var loop in loops) { @@ -53,18 +54,24 @@ namespace osu.Game.Storyboards double loopFirstAlphaStartTime = loopFirstAlphaCommand.StartTime + loop.LoopStartTime; - if (loopFirstAlphaCommand.StartValue == 0) + // Found an alpha command with an earlier start time than an override. + if (loopFirstAlphaStartTime < earliestAlphaTime) { - // Found a loop containing a zero StartValue earlier than previous. - zeroAlphaStartTimeOverride = loopFirstAlphaStartTime; - } - else if (loopFirstAlphaStartTime < zeroAlphaStartTimeOverride) - { - // If a loop's first alpha command's StartValue is non-zero, we need to check whether the command's StartTime is less than any previously found zero alpha command. - // If this is the case, we want to abort zero alpha override logic and use the earliest command time instead. - // This is because if the first alpha command is non-zero, the sprite will be shown at that alpha from the time of the first command (of any type, not just alpha). - zeroAlphaStartTimeOverride = double.MaxValue; - break; + earliestAlphaTime = loopFirstAlphaStartTime; + + if (loopFirstAlphaCommand.StartValue == 0) + { + // The found alpha command has a zero StartValue, so should be used as the new override. + zeroAlphaStartTimeOverride = loopFirstAlphaStartTime; + } + else if (loopFirstAlphaStartTime < zeroAlphaStartTimeOverride) + { + // The found alpha command's StartValue is non-zero. + // In this case, we want to reset any found alpha override (so if this is the new earliest alpha, + // we will fall through to the earlier command time logic below). + zeroAlphaStartTimeOverride = double.MaxValue; + break; + } } } From 677708c5e4b0bad1b112ed6402cfa9be05d5ab73 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 16:58:51 +0900 Subject: [PATCH 0903/2686] Rewrite logic using a list --- osu.Game/Storyboards/StoryboardSprite.cs | 62 ++++++++---------------- 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index 0764969d02..f77b3a812e 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -30,56 +30,32 @@ namespace osu.Game.Storyboards { get { - // To get the initial start time, we need to check whether the first alpha command to exist has an initial value of zero. - // A start value of zero on an alpha governs, above all else, the first valid display time of a sprite. - double zeroAlphaStartTimeOverride = double.MaxValue; - double earliestAlphaTime = double.MaxValue; + // To get the initial start time, we need to check whether the first alpha command to exist (across all loops) has a StartValue of zero. + // A StartValue of zero governs, above all else, the first valid display time of a sprite. + // + // You can imagine that the first command of each type decides that type's start value, so if the initial alpha is zero, + // anything before that point can be ignored (the sprite is not visible after all). + var alphaCommands = new List<(double startTime, bool isZeroStartValue)>(); - var topLevelFirstAlphaCommand = TimelineGroup.Alpha.Commands.FirstOrDefault(); - - if (topLevelFirstAlphaCommand != null) - { - earliestAlphaTime = topLevelFirstAlphaCommand.StartTime; - if (topLevelFirstAlphaCommand.StartValue == 0) - // The found alpha command has a zero StartValue, so should be used as the new override. - zeroAlphaStartTimeOverride = topLevelFirstAlphaCommand.StartTime; - } + var command = TimelineGroup.Alpha.Commands.FirstOrDefault(); + if (command != null) alphaCommands.Add((command.StartTime, command.StartValue == 0)); foreach (var loop in loops) { - var loopFirstAlphaCommand = loop.Alpha.Commands.FirstOrDefault(); - - if (loopFirstAlphaCommand == null) - continue; - - double loopFirstAlphaStartTime = loopFirstAlphaCommand.StartTime + loop.LoopStartTime; - - // Found an alpha command with an earlier start time than an override. - if (loopFirstAlphaStartTime < earliestAlphaTime) - { - earliestAlphaTime = loopFirstAlphaStartTime; - - if (loopFirstAlphaCommand.StartValue == 0) - { - // The found alpha command has a zero StartValue, so should be used as the new override. - zeroAlphaStartTimeOverride = loopFirstAlphaStartTime; - } - else if (loopFirstAlphaStartTime < zeroAlphaStartTimeOverride) - { - // The found alpha command's StartValue is non-zero. - // In this case, we want to reset any found alpha override (so if this is the new earliest alpha, - // we will fall through to the earlier command time logic below). - zeroAlphaStartTimeOverride = double.MaxValue; - break; - } - } + command = loop.Alpha.Commands.FirstOrDefault(); + if (command != null) alphaCommands.Add((command.StartTime + loop.StartTime, command.StartValue == 0)); } - if (zeroAlphaStartTimeOverride < double.MaxValue) - return zeroAlphaStartTimeOverride; + if (alphaCommands.Count > 0) + { + var firstAlpha = alphaCommands.OrderBy(t => t.startTime).First(); - // if we got to this point, either no alpha commands were present, or the earliest had a non-zero start value. - // the sprite's StartTime will be determined by the earliest command, of any type. + if (firstAlpha.isZeroStartValue) + return firstAlpha.startTime; + } + + // If we got to this point, either no alpha commands were present, or the earliest had a non-zero start value. + // The sprite's StartTime will be determined by the earliest command, regardless of type. double earliestStartTime = TimelineGroup.StartTime; foreach (var l in loops) earliestStartTime = Math.Min(earliestStartTime, l.StartTime); From 6e52dbb2668768eb8654251a8a4bd3d13190443a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 17:30:24 +0900 Subject: [PATCH 0904/2686] Update `IsDisplayingToasts` to check the flow count directly --- osu.Game/Overlays/NotificationOverlayToastTray.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index f9c4f657eb..40324963fc 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays { public override bool IsPresent => toastContentBackground.Height > 0 || toastFlow.Count > 0; - public bool IsDisplayingToasts => allNotifications.Any(); + public bool IsDisplayingToasts => toastFlow.Count > 0; private FillFlowContainer toastFlow = null!; private BufferedContainer toastContentBackground = null!; @@ -36,9 +36,12 @@ namespace osu.Game.Overlays public Action? ForwardNotificationToPermanentStore { get; set; } - public int UnreadCount => allNotifications.Count(n => !n.WasClosed && !n.Read); + public int UnreadCount => allDisplayedNotifications.Count(n => !n.WasClosed && !n.Read); - private IEnumerable allNotifications => toastFlow.Concat(InternalChildren.OfType()); + /// + /// Notifications contained in the toast flow, or in a detached state while they animate during forwarding to the main overlay. + /// + private IEnumerable allDisplayedNotifications => toastFlow.Concat(InternalChildren.OfType()); private int runningDepth; From 9f2ea54e40c993a9b5091228f455a88bbb33d4fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 17:45:53 +0900 Subject: [PATCH 0905/2686] Tidy up `TestSceneLeadIn` constant for loop offset to read better --- osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs index c066f1417c..c18a78fe3c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs @@ -66,18 +66,20 @@ namespace osu.Game.Tests.Visual.Gameplay [TestCase(-10000, -10000, true)] public void TestStoryboardProducesCorrectStartTimeFadeInAfterOtherEvents(double firstStoryboardEvent, double expectedStartTime, bool addEventToLoop) { + const double loop_start_time = -20000; + var storyboard = new Storyboard(); var sprite = new StoryboardSprite("unknown", Anchor.TopLeft, Vector2.Zero); // these should be ignored as we have an alpha visibility blocker proceeding this command. - sprite.TimelineGroup.Scale.Add(Easing.None, -20000, -18000, 0, 1); - var loopGroup = sprite.AddLoop(-20000, 50); - loopGroup.Scale.Add(Easing.None, -20000, -18000, 0, 1); + sprite.TimelineGroup.Scale.Add(Easing.None, loop_start_time, -18000, 0, 1); + var loopGroup = sprite.AddLoop(loop_start_time, 50); + loopGroup.Scale.Add(Easing.None, loop_start_time, -18000, 0, 1); var target = addEventToLoop ? loopGroup : sprite.TimelineGroup; - double targetTime = addEventToLoop ? 20000 : 0; - target.Alpha.Add(Easing.None, targetTime + firstStoryboardEvent, targetTime + firstStoryboardEvent + 500, 0, 1); + double loopRelativeOffset = addEventToLoop ? -loop_start_time : 0; + target.Alpha.Add(Easing.None, loopRelativeOffset + firstStoryboardEvent, loopRelativeOffset + firstStoryboardEvent + 500, 0, 1); // these should be ignored due to being in the future. sprite.TimelineGroup.Alpha.Add(Easing.None, 18000, 20000, 0, 1); From a3de5f808e39885505e061bdcab0716f226d8e22 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 17:46:03 +0900 Subject: [PATCH 0906/2686] Fix typo in `LoopStartTime` addition --- osu.Game/Storyboards/StoryboardSprite.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index f77b3a812e..1eeaa0f084 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -43,7 +43,7 @@ namespace osu.Game.Storyboards foreach (var loop in loops) { command = loop.Alpha.Commands.FirstOrDefault(); - if (command != null) alphaCommands.Add((command.StartTime + loop.StartTime, command.StartValue == 0)); + if (command != null) alphaCommands.Add((command.StartTime + loop.LoopStartTime, command.StartValue == 0)); } if (alphaCommands.Count > 0) From 579e7e1f174a6db56827b80bbfffb1baaf7cd727 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 18:08:51 +0900 Subject: [PATCH 0907/2686] Fix deleting a difficulty not updating the beatmap set hash --- .../Visual/Editing/TestSceneDifficultyDelete.cs | 3 +++ osu.Game/Beatmaps/BeatmapManager.cs | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs index 1520f64ec0..4366b1c0bb 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs @@ -45,6 +45,7 @@ namespace osu.Game.Tests.Visual.Editing { Guid deletedDifficultyID = Guid.Empty; int countBeforeDeletion = 0; + string beatmapSetHashBefore = string.Empty; for (int i = 0; i < 12; i++) { @@ -55,6 +56,7 @@ namespace osu.Game.Tests.Visual.Editing { deletedDifficultyID = EditorBeatmap.BeatmapInfo.ID; countBeforeDeletion = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count; + beatmapSetHashBefore = Beatmap.Value.BeatmapSetInfo.Hash; }); AddStep("click File", () => this.ChildrenOfType().First().TriggerClick()); @@ -72,6 +74,7 @@ namespace osu.Game.Tests.Visual.Editing AddAssert($"difficulty {i} is deleted", () => Beatmap.Value.BeatmapSetInfo.Beatmaps.Select(b => b.ID), () => Does.Not.Contain(deletedDifficultyID)); AddAssert("count decreased by one", () => Beatmap.Value.BeatmapSetInfo.Beatmaps.Count, () => Is.EqualTo(countBeforeDeletion - 1)); + AddAssert("set hash changed", () => Beatmap.Value.BeatmapSetInfo.Hash, () => Is.Not.EqualTo(beatmapSetHashBefore)); } } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d784f1e627..d55ccb4b41 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -319,8 +319,7 @@ namespace osu.Game.Beatmaps AddFile(setInfo, stream, createBeatmapFilenameFromMetadata(beatmapInfo)); - setInfo.Hash = beatmapImporter.ComputeHash(setInfo); - setInfo.Status = BeatmapOnlineStatus.LocallyModified; + updateHashAndMarkDirty(setInfo); Realm.Write(r => { @@ -384,6 +383,8 @@ namespace osu.Game.Beatmaps DeleteFile(setInfo, beatmapInfo.File); setInfo.Beatmaps.Remove(beatmapInfo); + + updateHashAndMarkDirty(setInfo); }); } @@ -440,6 +441,12 @@ namespace osu.Game.Beatmaps public Task?> ImportAsUpdate(ProgressNotification notification, ImportTask importTask, BeatmapSetInfo original) => beatmapImporter.ImportAsUpdate(notification, importTask, original); + private void updateHashAndMarkDirty(BeatmapSetInfo setInfo) + { + setInfo.Hash = beatmapImporter.ComputeHash(setInfo); + setInfo.Status = BeatmapOnlineStatus.LocallyModified; + } + #region Implementation of ICanAcceptFiles public Task Import(params string[] paths) => beatmapImporter.Import(paths); From db15bd56e87630d0a6bce7e3f31422b82e81b933 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 18:10:59 +0900 Subject: [PATCH 0908/2686] Invalidate working beatmap cache when calling `DeleteDifficultyImmediately` rather than in editor code --- osu.Game/Beatmaps/BeatmapManager.cs | 1 + osu.Game/Screens/Edit/Editor.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index d55ccb4b41..2c6edb64f8 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -385,6 +385,7 @@ namespace osu.Game.Beatmaps setInfo.Beatmaps.Remove(beatmapInfo); updateHashAndMarkDirty(setInfo); + workingBeatmapCache.Invalidate(setInfo); }); } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 6e06683e38..3dfc7010f3 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -929,7 +929,7 @@ namespace osu.Game.Screens.Edit // of note, we're still working with the cloned version, so indices are all prior to deletion. BeatmapInfo nextToShow = difficultiesBeforeDeletion[deletedIndex == 0 ? 1 : deletedIndex - 1]; - Beatmap.Value = beatmapManager.GetWorkingBeatmap(nextToShow, true); + Beatmap.Value = beatmapManager.GetWorkingBeatmap(nextToShow); SwitchToDifficulty(nextToShow); } From bc1212f4e6785670a9249aaf1fa5ccf501fd6f5b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 20:06:30 +0900 Subject: [PATCH 0909/2686] Change `NonGameplayAdjustments` to `GameplayAdjustments` and convert `TrueGameplayRate` to extension method --- .../Default/SpinnerRotationTracker.cs | 2 +- .../NonVisual/GameplayClockContainerTest.cs | 6 ++--- .../Visual/Gameplay/TestScenePause.cs | 2 +- .../Rulesets/UI/FrameStabilityContainer.cs | 5 +---- .../Screens/Play/GameplayClockContainer.cs | 4 +--- .../Screens/Play/GameplayClockExtensions.cs | 22 +++++++++++++++++++ osu.Game/Screens/Play/IGameplayClock.cs | 8 +------ .../Play/MasterGameplayClockContainer.cs | 11 +--------- 8 files changed, 31 insertions(+), 29 deletions(-) create mode 100644 osu.Game/Screens/Play/GameplayClockExtensions.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs index 554ea3ac90..97cebc3123 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs @@ -110,7 +110,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default currentRotation += angle; // rate has to be applied each frame, because it's not guaranteed to be constant throughout playback // (see: ModTimeRamp) - drawableSpinner.Result.RateAdjustedRotation += (float)(Math.Abs(angle) * (gameplayClock?.TrueGameplayRate ?? Clock.Rate)); + drawableSpinner.Result.RateAdjustedRotation += (float)(Math.Abs(angle) * (gameplayClock?.GetTrueGameplayRate() ?? Clock.Rate)); } private void resetState(DrawableHitObject obj) diff --git a/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs b/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs index f9f4ead644..95bf1ab354 100644 --- a/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs +++ b/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs @@ -13,17 +13,17 @@ namespace osu.Game.Tests.NonVisual { [TestCase(0)] [TestCase(1)] - public void TestTrueGameplayRateWithZeroAdjustment(double underlyingClockRate) + public void TestTrueGameplayRateWithGameplayAdjustment(double underlyingClockRate) { var framedClock = new FramedClock(new ManualClock { Rate = underlyingClockRate }); var gameplayClock = new TestGameplayClockContainer(framedClock); - Assert.That(gameplayClock.TrueGameplayRate, Is.EqualTo(0)); + Assert.That(gameplayClock.GetTrueGameplayRate(), Is.EqualTo(2)); } private class TestGameplayClockContainer : GameplayClockContainer { - public override IEnumerable NonGameplayAdjustments => new[] { 0.0 }; + public override IEnumerable GameplayAdjustments => new[] { 2.0 }; public TestGameplayClockContainer(IFrameBasedClock underlyingClock) : base(underlyingClock) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index a6abdd7ee1..d0371acce7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -370,7 +370,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void confirmNoTrackAdjustments() { - AddAssert("track has no adjustments", () => Beatmap.Value.Track.AggregateFrequency.Value == 1); + AddUntilStep("track has no adjustments", () => Beatmap.Value.Track.AggregateFrequency.Value, () => Is.EqualTo(1)); } private void restart() => AddStep("restart", () => Player.Restart()); diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 4d817cd973..4f4a2d908d 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -10,7 +10,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; -using osu.Framework.Utils; using osu.Game.Input.Handlers; using osu.Game.Screens.Play; @@ -263,11 +262,9 @@ namespace osu.Game.Rulesets.UI public FrameTimeInfo TimeInfo => framedClock.TimeInfo; - public double TrueGameplayRate => parentGameplayClock?.TrueGameplayRate ?? Rate; - public double StartTime => parentGameplayClock?.StartTime ?? 0; - public IEnumerable NonGameplayAdjustments => parentGameplayClock?.NonGameplayAdjustments ?? Enumerable.Empty(); + public IEnumerable GameplayAdjustments => parentGameplayClock?.GameplayAdjustments ?? Enumerable.Empty(); #endregion diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 4d48675f94..5dfaf2d584 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.Play /// public double StartTime { get; protected set; } - public virtual IEnumerable NonGameplayAdjustments => Enumerable.Empty(); + public virtual IEnumerable GameplayAdjustments => Enumerable.Empty(); private readonly BindableBool isPaused = new BindableBool(true); @@ -223,7 +223,5 @@ namespace osu.Game.Screens.Play public double FramesPerSecond => GameplayClock.FramesPerSecond; public FrameTimeInfo TimeInfo => GameplayClock.TimeInfo; - - public virtual double TrueGameplayRate => Rate; } } diff --git a/osu.Game/Screens/Play/GameplayClockExtensions.cs b/osu.Game/Screens/Play/GameplayClockExtensions.cs new file mode 100644 index 0000000000..b683c61f63 --- /dev/null +++ b/osu.Game/Screens/Play/GameplayClockExtensions.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 System; + +namespace osu.Game.Screens.Play +{ + public static class GameplayClockExtensions + { + /// + /// The rate of gameplay when playback is at 100%. + /// This excludes any seeking / user adjustments. + /// + public static double GetTrueGameplayRate(this IGameplayClock clock) + { + double rate = Math.Sign(clock.Rate); + foreach (double a in clock.GameplayAdjustments) + rate *= a; + return rate; + } + } +} diff --git a/osu.Game/Screens/Play/IGameplayClock.cs b/osu.Game/Screens/Play/IGameplayClock.cs index ea567090ad..7c50b9d407 100644 --- a/osu.Game/Screens/Play/IGameplayClock.cs +++ b/osu.Game/Screens/Play/IGameplayClock.cs @@ -9,12 +9,6 @@ namespace osu.Game.Screens.Play { public interface IGameplayClock : IFrameBasedClock { - /// - /// The rate of gameplay when playback is at 100%. - /// This excludes any seeking / user adjustments. - /// - double TrueGameplayRate { get; } - /// /// The time from which the clock should start. Will be seeked to on calling . /// @@ -27,7 +21,7 @@ namespace osu.Game.Screens.Play /// /// All adjustments applied to this clock which don't come from gameplay or mods. /// - IEnumerable NonGameplayAdjustments { get; } + IEnumerable GameplayAdjustments { get; } IBindable IsPaused { get; } } diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index bda8718dc6..f1ee65dcd3 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -224,16 +224,7 @@ namespace osu.Game.Screens.Play private readonly List> speedAdjustments = new List>(); - public override double TrueGameplayRate - { - get - { - double rate = Rate; - foreach (var a in speedAdjustments) - rate *= a.Value; - return rate; - } - } + public override IEnumerable GameplayAdjustments => speedAdjustments.Select(bindable => bindable.Value); void IAdjustableAudioComponent.AddAdjustment(AdjustableProperty type, IBindable adjustBindable) { From 66c44f5913d24c95116d1a4605ed4f6e3d3522d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 21:40:04 +0900 Subject: [PATCH 0910/2686] Delegate interface to valid target --- .../Play/MasterGameplayClockContainer.cs | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index f1ee65dcd3..7c30f86125 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -8,6 +8,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -56,6 +57,11 @@ namespace osu.Game.Screens.Play /// private double? actualStopTime; + /// + /// Maintained solely to delegate pieces to (to maintain parent lookups). + /// + private readonly AudioContainer audioContainer; + /// /// Create a new master gameplay clock container. /// @@ -69,6 +75,8 @@ namespace osu.Game.Screens.Play this.skipTargetTime = skipTargetTime; StartTime = findEarliestStartTime(); + + AddInternal(audioContainer = new AudioContainer()); } private double findEarliestStartTime() @@ -238,25 +246,32 @@ namespace osu.Game.Screens.Play track.RemoveAdjustment(type, adjustBindable); } + void IAdjustableAudioComponent.RemoveAllAdjustments(AdjustableProperty type) => audioContainer.RemoveAllAdjustments(type); + + void IAdjustableAudioComponent.BindAdjustments(IAggregateAudioAdjustment component) => audioContainer.BindAdjustments(component); + + void IAdjustableAudioComponent.UnbindAdjustments(IAggregateAudioAdjustment component) => audioContainer.UnbindAdjustments(component); + + BindableNumber IAdjustableAudioComponent.Volume => audioContainer.Volume; + + BindableNumber IAdjustableAudioComponent.Balance => audioContainer.Balance; + + BindableNumber IAdjustableAudioComponent.Frequency => audioContainer.Frequency; + + BindableNumber IAdjustableAudioComponent.Tempo => audioContainer.Tempo; + public override void ResetSpeedAdjustments() { track.RemoveAllAdjustments(AdjustableProperty.Frequency); track.RemoveAllAdjustments(AdjustableProperty.Tempo); } - public void RemoveAllAdjustments(AdjustableProperty type) => throw new NotImplementedException(); + IBindable IAggregateAudioAdjustment.AggregateVolume => audioContainer.AggregateVolume; - public void BindAdjustments(IAggregateAudioAdjustment component) => throw new NotImplementedException(); - public void UnbindAdjustments(IAggregateAudioAdjustment component) => throw new NotImplementedException(); + IBindable IAggregateAudioAdjustment.AggregateBalance => audioContainer.AggregateBalance; - public BindableNumber Volume => throw new NotImplementedException(); - public BindableNumber Balance => throw new NotImplementedException(); - public BindableNumber Frequency => throw new NotImplementedException(); - public BindableNumber Tempo => throw new NotImplementedException(); + IBindable IAggregateAudioAdjustment.AggregateFrequency => audioContainer.AggregateFrequency; - public IBindable AggregateVolume => throw new NotImplementedException(); - public IBindable AggregateBalance => throw new NotImplementedException(); - public IBindable AggregateFrequency => throw new NotImplementedException(); - public IBindable AggregateTempo => throw new NotImplementedException(); + IBindable IAggregateAudioAdjustment.AggregateTempo => audioContainer.AggregateTempo; } } From a2f8ff825e88bc02c3a2e257d5d0f78a1af71a13 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 6 Sep 2022 17:27:29 +0900 Subject: [PATCH 0911/2686] Also ignore drum roll strong judgement --- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 2 ++ osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index 3dab8d2e13..3325eda7cf 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -96,6 +96,8 @@ namespace osu.Game.Rulesets.Taiko.Objects public class StrongNestedHit : StrongNestedHitObject { + // The strong hit of the drum roll doesn't actually provide any score. + public override Judgement CreateJudgement() => new IgnoreJudgement(); } #region LegacyBeatmapEncoder diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index ccca5587b7..cc71ba5401 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -317,6 +317,9 @@ namespace osu.Game.Rulesets.Taiko.UI break; default: + if (!result.Type.IsScorable()) + break; + judgementContainer.Add(judgementPools[result.Type].Get(j => { j.Apply(result, judgedObject); From 2ca63b50309b8d839dffaced3bb9d59ab51766fc Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 6 Sep 2022 18:02:17 +0900 Subject: [PATCH 0912/2686] Add tests for all taiko judgements --- .../Judgements/JudgementTest.cs | 96 +++++++++ .../Judgements/TestSceneDrumRollJudgements.cs | 201 ++++++++++++++++++ .../Judgements/TestSceneHitJudgements.cs | 133 ++++++++++++ .../Judgements/TestSceneSwellJudgements.cs | 118 ++++++++++ .../TestSceneSwellJudgements.cs | 42 ---- 5 files changed, 548 insertions(+), 42 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs create mode 100644 osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneDrumRollJudgements.cs create mode 100644 osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs create mode 100644 osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneSwellJudgements.cs delete mode 100644 osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs b/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs new file mode 100644 index 0000000000..c9e8fefead --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs @@ -0,0 +1,96 @@ +// 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.Extensions.TypeExtensions; +using osu.Framework.Screens; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Replays; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Replays; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Scoring; +using osu.Game.Screens.Play; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public class JudgementTest : RateAdjustedBeatmapTestScene + { + private ScoreAccessibleReplayPlayer currentPlayer = null!; + protected List JudgementResults { get; private set; } = null!; + + protected void AssertJudgementCount(int count) + { + AddAssert($"{count} judgement{(count > 0 ? "s" : "")}", () => JudgementResults, () => Has.Count.EqualTo(count)); + } + + protected void AssertResult(int index, HitResult expectedResult) + { + AddAssert($"{typeof(T).ReadableName()} ({index}) judged as {expectedResult}", + () => JudgementResults.Where(j => j.HitObject is T).OrderBy(j => j.HitObject.StartTime).ElementAt(index).Type, + () => Is.EqualTo(expectedResult)); + } + + protected void PerformTest(List frames, Beatmap? beatmap = null) + { + AddStep("load player", () => + { + Beatmap.Value = CreateWorkingBeatmap(beatmap); + + var p = new ScoreAccessibleReplayPlayer(new Score { Replay = new Replay { Frames = frames } }); + + p.OnLoadComplete += _ => + { + p.ScoreProcessor.NewJudgement += result => + { + if (currentPlayer == p) JudgementResults.Add(result); + }; + }; + + LoadScreen(currentPlayer = p); + JudgementResults = new List(); + }); + + AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0); + AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen()); + AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value); + } + + protected Beatmap CreateBeatmap(params TaikoHitObject[] hitObjects) + { + var beatmap = new Beatmap + { + HitObjects = hitObjects.ToList(), + BeatmapInfo = + { + Difficulty = new BeatmapDifficulty { SliderTickRate = 4 }, + Ruleset = new TaikoRuleset().RulesetInfo + }, + }; + + beatmap.ControlPointInfo.Add(0, new EffectControlPoint { ScrollSpeed = 0.1f }); + return beatmap; + } + + private class ScoreAccessibleReplayPlayer : ReplayPlayer + { + public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; + + protected override bool PauseOnFocusLost => false; + + public ScoreAccessibleReplayPlayer(Score score) + : base(score, new PlayerConfiguration + { + AllowPause = false, + ShowResults = false, + }) + { + } + } + } +} diff --git a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneDrumRollJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneDrumRollJudgements.cs new file mode 100644 index 0000000000..2c28c3dad5 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneDrumRollJudgements.cs @@ -0,0 +1,201 @@ +// 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 NUnit.Framework; +using osu.Game.Rulesets.Replays; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Replays; + +namespace osu.Game.Rulesets.Taiko.Tests.Judgements +{ + public class TestSceneDrumRollJudgements : JudgementTest + { + [Test] + public void TestHitAllDrumRoll() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(1000, TaikoAction.LeftCentre), + new TaikoReplayFrame(1001), + new TaikoReplayFrame(2000, TaikoAction.LeftCentre), + new TaikoReplayFrame(2001), + }, CreateBeatmap(new DrumRoll + { + StartTime = hit_time, + Duration = 1000 + })); + + AssertJudgementCount(3); + AssertResult(0, HitResult.SmallBonus); + AssertResult(1, HitResult.SmallBonus); + AssertResult(0, HitResult.IgnoreHit); + } + + [Test] + public void TestHitSomeDrumRoll() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(2000, TaikoAction.LeftCentre), + new TaikoReplayFrame(2001), + }, CreateBeatmap(new DrumRoll + { + StartTime = hit_time, + Duration = 1000 + })); + + AssertJudgementCount(3); + AssertResult(0, HitResult.IgnoreMiss); + AssertResult(1, HitResult.SmallBonus); + AssertResult(0, HitResult.IgnoreHit); + } + + [Test] + public void TestHitNoneDrumRoll() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + }, CreateBeatmap(new DrumRoll + { + StartTime = hit_time, + Duration = 1000 + })); + + AssertJudgementCount(3); + AssertResult(0, HitResult.IgnoreMiss); + AssertResult(1, HitResult.IgnoreMiss); + AssertResult(0, HitResult.IgnoreHit); + } + + [Test] + public void TestHitAllStrongDrumRollWithOneKey() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(1000, TaikoAction.LeftCentre), + new TaikoReplayFrame(1001), + new TaikoReplayFrame(2000, TaikoAction.LeftCentre), + new TaikoReplayFrame(2001), + }, CreateBeatmap(new DrumRoll + { + StartTime = hit_time, + Duration = 1000, + IsStrong = true + })); + + AssertJudgementCount(6); + + AssertResult(0, HitResult.SmallBonus); + AssertResult(0, HitResult.LargeBonus); + + AssertResult(1, HitResult.SmallBonus); + AssertResult(1, HitResult.LargeBonus); + + AssertResult(0, HitResult.IgnoreHit); + AssertResult(2, HitResult.IgnoreHit); + } + + [Test] + public void TestHitSomeStrongDrumRollWithOneKey() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(2000, TaikoAction.LeftCentre), + new TaikoReplayFrame(2001), + }, CreateBeatmap(new DrumRoll + { + StartTime = hit_time, + Duration = 1000, + IsStrong = true + })); + + AssertJudgementCount(6); + + AssertResult(0, HitResult.IgnoreMiss); + AssertResult(0, HitResult.IgnoreMiss); + + AssertResult(1, HitResult.SmallBonus); + AssertResult(1, HitResult.LargeBonus); + + AssertResult(0, HitResult.IgnoreHit); + AssertResult(2, HitResult.IgnoreHit); + } + + [Test] + public void TestHitAllStrongDrumRollWithBothKeys() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(1000, TaikoAction.LeftCentre, TaikoAction.RightCentre), + new TaikoReplayFrame(1001), + new TaikoReplayFrame(2000, TaikoAction.LeftCentre, TaikoAction.RightCentre), + new TaikoReplayFrame(2001), + }, CreateBeatmap(new DrumRoll + { + StartTime = hit_time, + Duration = 1000, + IsStrong = true + })); + + AssertJudgementCount(6); + + AssertResult(0, HitResult.SmallBonus); + AssertResult(0, HitResult.LargeBonus); + + AssertResult(1, HitResult.SmallBonus); + AssertResult(1, HitResult.LargeBonus); + + AssertResult(0, HitResult.IgnoreHit); + AssertResult(2, HitResult.IgnoreHit); + } + + [Test] + public void TestHitSomeStrongDrumRollWithBothKeys() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(2000, TaikoAction.LeftCentre, TaikoAction.RightCentre), + new TaikoReplayFrame(2001), + }, CreateBeatmap(new DrumRoll + { + StartTime = hit_time, + Duration = 1000, + IsStrong = true + })); + + AssertJudgementCount(6); + + AssertResult(0, HitResult.IgnoreMiss); + AssertResult(0, HitResult.IgnoreMiss); + + AssertResult(1, HitResult.SmallBonus); + AssertResult(1, HitResult.LargeBonus); + + AssertResult(0, HitResult.IgnoreHit); + AssertResult(2, HitResult.IgnoreHit); + } + } +} diff --git a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs new file mode 100644 index 0000000000..a405f0e8ba --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs @@ -0,0 +1,133 @@ +// 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 NUnit.Framework; +using osu.Game.Rulesets.Replays; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Replays; + +namespace osu.Game.Rulesets.Taiko.Tests.Judgements +{ + public class TestSceneHitJudgements : JudgementTest + { + [Test] + public void TestHitCentreHit() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(hit_time, TaikoAction.LeftCentre), + }, CreateBeatmap(new Hit + { + Type = HitType.Centre, + StartTime = hit_time + })); + + AssertJudgementCount(1); + AssertResult(0, HitResult.Great); + } + + [Test] + public void TestHitRimHit() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(hit_time, TaikoAction.LeftRim), + }, CreateBeatmap(new Hit + { + Type = HitType.Rim, + StartTime = hit_time + })); + + AssertJudgementCount(1); + AssertResult(0, HitResult.Great); + } + + [Test] + public void TestMissHit() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0) + }, CreateBeatmap(new Hit + { + Type = HitType.Centre, + StartTime = hit_time + })); + + AssertJudgementCount(1); + AssertResult(0, HitResult.Miss); + } + + [Test] + public void TestHitStrongHitWithOneKey() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(hit_time, TaikoAction.LeftCentre), + }, CreateBeatmap(new Hit + { + Type = HitType.Centre, + StartTime = hit_time, + IsStrong = true + })); + + AssertJudgementCount(2); + AssertResult(0, HitResult.Great); + AssertResult(0, HitResult.IgnoreMiss); + } + + [Test] + public void TestHitStrongHitWithBothKeys() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(hit_time, TaikoAction.LeftCentre, TaikoAction.RightCentre), + }, CreateBeatmap(new Hit + { + Type = HitType.Centre, + StartTime = hit_time, + IsStrong = true + })); + + AssertJudgementCount(2); + AssertResult(0, HitResult.Great); + AssertResult(0, HitResult.LargeBonus); + } + + [Test] + public void TestMissStrongHit() + { + const double hit_time = 1000; + + PerformTest(new List + { + new TaikoReplayFrame(0), + }, CreateBeatmap(new Hit + { + Type = HitType.Centre, + StartTime = hit_time, + IsStrong = true + })); + + AssertJudgementCount(2); + AssertResult(0, HitResult.Miss); + AssertResult(0, HitResult.IgnoreMiss); + } + } +} diff --git a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneSwellJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneSwellJudgements.cs new file mode 100644 index 0000000000..7bdfcf0b07 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneSwellJudgements.cs @@ -0,0 +1,118 @@ +// 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.Game.Rulesets.Replays; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Replays; + +namespace osu.Game.Rulesets.Taiko.Tests.Judgements +{ + public class TestSceneSwellJudgements : JudgementTest + { + [Test] + public void TestHitAllSwell() + { + const double hit_time = 1000; + + Swell swell = new Swell + { + StartTime = hit_time, + Duration = 1000, + RequiredHits = 10 + }; + + List frames = new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(2001), + }; + + for (int i = 0; i < swell.RequiredHits; i++) + { + double frameTime = 1000 + i * 50; + frames.Add(new TaikoReplayFrame(frameTime, i % 2 == 0 ? TaikoAction.LeftCentre : TaikoAction.LeftRim)); + frames.Add(new TaikoReplayFrame(frameTime + 10)); + } + + PerformTest(frames, CreateBeatmap(swell)); + + AssertJudgementCount(11); + + for (int i = 0; i < swell.RequiredHits; i++) + AssertResult(i, HitResult.IgnoreHit); + + AssertResult(0, HitResult.LargeBonus); + } + + [Test] + public void TestHitSomeSwell() + { + const double hit_time = 1000; + + Swell swell = new Swell + { + StartTime = hit_time, + Duration = 1000, + RequiredHits = 10 + }; + + List frames = new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(2001), + }; + + for (int i = 0; i < swell.RequiredHits / 2; i++) + { + double frameTime = 1000 + i * 50; + frames.Add(new TaikoReplayFrame(frameTime, i % 2 == 0 ? TaikoAction.LeftCentre : TaikoAction.LeftRim)); + frames.Add(new TaikoReplayFrame(frameTime + 10)); + } + + PerformTest(frames, CreateBeatmap(swell)); + + AssertJudgementCount(11); + + for (int i = 0; i < swell.RequiredHits / 2; i++) + AssertResult(i, HitResult.IgnoreHit); + for (int i = swell.RequiredHits / 2; i < swell.RequiredHits; i++) + AssertResult(i, HitResult.IgnoreMiss); + + AssertResult(0, HitResult.IgnoreMiss); + } + + [Test] + public void TestHitNoneSwell() + { + const double hit_time = 1000; + + Swell swell = new Swell + { + StartTime = hit_time, + Duration = 1000, + RequiredHits = 10 + }; + + List frames = new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(2001), + }; + + PerformTest(frames, CreateBeatmap(swell)); + + AssertJudgementCount(11); + + for (int i = 0; i < swell.RequiredHits; i++) + AssertResult(i, HitResult.IgnoreMiss); + + AssertResult(0, HitResult.IgnoreMiss); + + AddAssert("all tick offsets are 0", () => JudgementResults.Where(r => r.HitObject is SwellTick).All(r => r.TimeOffset == 0)); + } + } +} diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs deleted file mode 100644 index bd546b16f2..0000000000 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Linq; -using NUnit.Framework; -using osu.Game.Beatmaps; -using osu.Game.Rulesets.Taiko.Objects; - -namespace osu.Game.Rulesets.Taiko.Tests -{ - public class TestSceneSwellJudgements : TestSceneTaikoPlayer - { - [Test] - public void TestZeroTickTimeOffsets() - { - AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted.Value); - AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.HitObject is SwellTick).All(r => r.TimeOffset == 0)); - } - - protected override bool Autoplay => true; - - protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) - { - var beatmap = new Beatmap - { - BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo }, - HitObjects = - { - new Swell - { - StartTime = 1000, - Duration = 1000, - } - } - }; - - return beatmap; - } - } -} From c2107bd32277ae7c40e5cf3bb513a44f189be80f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 6 Sep 2022 23:36:27 +0900 Subject: [PATCH 0913/2686] Fix test failures due to notifications being forwarded before player finishes loading --- .../Visual/Gameplay/TestScenePlayerLoader.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index b6c17fbaca..1d101383cc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -301,7 +301,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("check for notification", () => notificationOverlay.UnreadCount.Value, () => Is.EqualTo(1)); - clickNotificationIfAny(); + clickNotification(); AddAssert("check " + volumeName, assert); @@ -370,8 +370,12 @@ namespace osu.Game.Tests.Visual.Gameplay batteryInfo.SetChargeLevel(chargeLevel); })); AddUntilStep("wait for player", () => player?.LoadState == LoadState.Ready); - AddAssert($"notification {(shouldWarn ? "triggered" : "not triggered")}", () => notificationOverlay.UnreadCount.Value == (shouldWarn ? 1 : 0)); - clickNotificationIfAny(); + + if (shouldWarn) + clickNotification(); + else + AddAssert("notification not triggered", () => notificationOverlay.UnreadCount.Value == 0); + AddUntilStep("wait for player load", () => player.IsLoaded); } @@ -436,9 +440,13 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("skip button not visible", () => !checkSkipButtonVisible()); } - private void clickNotificationIfAny() + private void clickNotification() { - AddStep("click notification", () => notificationOverlay.ChildrenOfType().FirstOrDefault()?.TriggerClick()); + Notification notification = null; + + AddUntilStep("wait for notification", () => (notification = notificationOverlay.ChildrenOfType().FirstOrDefault()) != null); + AddStep("open notification overlay", () => notificationOverlay.Show()); + AddStep("click notification", () => notification.TriggerClick()); } private EpilepsyWarning getWarning() => loader.ChildrenOfType().SingleOrDefault(); From 6a371eba5fcc910b627ca299ba09475198c34b04 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 7 Sep 2022 00:12:25 +0900 Subject: [PATCH 0914/2686] Fix namespace --- osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs b/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs index c9e8fefead..7f2f27b2b8 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs @@ -17,7 +17,7 @@ using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Tests.Visual; -namespace osu.Game.Rulesets.Taiko.Tests +namespace osu.Game.Rulesets.Taiko.Tests.Judgements { public class JudgementTest : RateAdjustedBeatmapTestScene { From 7c0e99c5a86c0c28e1399e36c8cdf5a32271c143 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 7 Sep 2022 00:11:51 +0900 Subject: [PATCH 0915/2686] Decode Geki/Katu from legacy taiko scores into LargeBonus --- .../Formats/LegacyScoreDecoderTest.cs | 18 +++++++++++ .../Resources/Replays/taiko-replay.osr | Bin 0 -> 237 bytes .../Scoring/Legacy/ScoreInfoExtensions.cs | 28 +++++++++++++++--- 3 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Tests/Resources/Replays/taiko-replay.osr diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs index aa6fc1f309..cd6e5e7919 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs @@ -67,6 +67,24 @@ namespace osu.Game.Tests.Beatmaps.Formats } } + [Test] + public void TestDecodeTaikoReplay() + { + var decoder = new TestLegacyScoreDecoder(); + + using (var resourceStream = TestResources.OpenResource("Replays/taiko-replay.osr")) + { + var score = decoder.Parse(resourceStream); + + Assert.AreEqual(1, score.ScoreInfo.Ruleset.OnlineID); + Assert.AreEqual(4, score.ScoreInfo.Statistics[HitResult.Great]); + Assert.AreEqual(2, score.ScoreInfo.Statistics[HitResult.LargeBonus]); + Assert.AreEqual(4, score.ScoreInfo.MaxCombo); + + Assert.That(score.Replay.Frames, Is.Not.Empty); + } + } + [TestCase(3, true)] [TestCase(6, false)] [TestCase(LegacyBeatmapDecoder.LATEST_VERSION, false)] diff --git a/osu.Game.Tests/Resources/Replays/taiko-replay.osr b/osu.Game.Tests/Resources/Replays/taiko-replay.osr new file mode 100644 index 0000000000000000000000000000000000000000..986b3116ab25f62dcb67514b8f52941cddab9b75 GIT binary patch literal 237 zcmZSN=rUpCRxmU*PqQ>jN;EJ_HcqxoN;FS4NKLXxNl8jJvox|WwB+W>P0h|uOvx`U zRpeGMNi{Y$H#9XgPc=7Av^2LcO*A!6v@}XiG&3+yPE9gmVE_RpF!@23fdRzlU|`@D zG%_?ct})OvHr6pUG%%?#)JZt7C`od{EsiLlidY5)1qLgKE(Qj%9;dkG`r7Op-o=T* z*CL8GF^jI?N!zpE@#WrB&!a^VpByr7JWzVO{9Crhvo#`$>L1#cZ&WQ%Oui9fe{Qpf Vr?FkmyS Date: Tue, 6 Sep 2022 17:10:32 +0100 Subject: [PATCH 0916/2686] Retrieve great hit window from the hit object --- .../Difficulty/Evaluators/RhythmEvaluator.cs | 4 ++-- .../Difficulty/Evaluators/SpeedEvaluator.cs | 7 +++---- .../Difficulty/OsuDifficultyCalculator.cs | 13 ++++++------- .../Preprocessing/OsuDifficultyHitObject.cs | 15 +++++++++++++++ osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 8 +++----- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index 3ffd45b588..ca57c87af9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators /// /// Calculates a rhythm multiplier for the difficulty of the tap associated with historic data of the current . /// - public static double EvaluateDifficultyOf(DifficultyHitObject current, double greatWindow) + public static double EvaluateDifficultyOf(DifficultyHitObject current) { if (current.BaseObject is Spinner) return 0; @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double lastDelta = lastObj.StrainTime; double currRatio = 1.0 + 6.0 * Math.Min(0.5, Math.Pow(Math.Sin(Math.PI / (Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta))), 2)); // fancy function to calculate rhythmbonuses. - double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - greatWindow * 0.6) / (greatWindow * 0.6)); + double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - currObj.HitWindowGreat * 0.6) / (currObj.HitWindowGreat * 0.6)); windowPenalty = Math.Min(1, windowPenalty); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index 5187717639..c98f875eb5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators /// and how easily they can be cheesed. /// /// - public static double EvaluateDifficultyOf(DifficultyHitObject current, double greatWindow) + public static double EvaluateDifficultyOf(DifficultyHitObject current) { if (current.BaseObject is Spinner) return 0; @@ -35,7 +35,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators var osuNextObj = (OsuDifficultyHitObject)current.Next(0); double strainTime = osuCurrObj.StrainTime; - double greatWindowFull = greatWindow * 2; double doubletapness = 1; // Nerf doubletappable doubles. @@ -45,13 +44,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double nextDeltaTime = Math.Max(1, osuNextObj.DeltaTime); double deltaDifference = Math.Abs(nextDeltaTime - currDeltaTime); double speedRatio = currDeltaTime / Math.Max(currDeltaTime, deltaDifference); - double windowRatio = Math.Pow(Math.Min(1, currDeltaTime / greatWindowFull), 2); + double windowRatio = Math.Pow(Math.Min(1, currDeltaTime / osuCurrObj.HitWindowGreat), 2); doubletapness = Math.Pow(speedRatio, 1 - windowRatio); } // Cap deltatime to the OD 300 hitwindow. // 0.93 is derived from making sure 260bpm OD8 streams aren't nerfed harshly, whilst 0.92 limits the effect of the cap. - strainTime /= Math.Clamp((strainTime / greatWindowFull) / 0.93, 0.92, 1); + strainTime /= Math.Clamp((strainTime / osuCurrObj.HitWindowGreat) / 0.93, 0.92, 1); // derive speedBonus for calculation double speedBonus = 1.0; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 6ef17d47c0..33787da8f6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -23,7 +23,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty public class OsuDifficultyCalculator : DifficultyCalculator { private const double difficulty_multiplier = 0.0675; - private double hitWindowGreat; public override int Version => 20220902; @@ -76,6 +75,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty int sliderCount = beatmap.HitObjects.Count(h => h is Slider); int spinnerCount = beatmap.HitObjects.Count(h => h is Spinner); + HitWindows hitWindows = new OsuHitWindows(); + hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); + + double hitWindowGreat = hitWindows.WindowFor(HitResult.Great) / clockRate; + return new OsuDifficultyAttributes { StarRating = starRating, @@ -112,16 +116,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty protected override Skill[] CreateSkills(IBeatmap beatmap, Mod[] mods, double clockRate) { - HitWindows hitWindows = new OsuHitWindows(); - hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); - - hitWindowGreat = hitWindows.WindowFor(HitResult.Great) / clockRate; - return new Skill[] { new Aim(mods, true), new Aim(mods, false), - new Speed(mods, hitWindowGreat), + new Speed(mods), new Flashlight(mods) }; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index c7c5650184..6aea00fd35 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -9,6 +9,7 @@ using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; using osuTK; namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing @@ -78,6 +79,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing ///
public double? Angle { get; private set; } + /// + /// Retrieves the full hit window for a Great . + /// + public double HitWindowGreat { get; private set; } + private readonly OsuHitObject lastLastObject; private readonly OsuHitObject lastObject; @@ -90,6 +96,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // Capped to 25ms to prevent difficulty calculation breaking from simultaneous objects. StrainTime = Math.Max(DeltaTime, min_delta_time); + if (BaseObject is Slider sliderObject) + { + HitWindowGreat = 2 * sliderObject.HeadCircle.HitWindows.WindowFor(HitResult.Great) / clockRate; + } + else + { + HitWindowGreat = 2 * BaseObject.HitWindows.WindowFor(HitResult.Great) / clockRate; + } + setDistances(clockRate); } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index c39d61020c..efe0e136bf 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -26,14 +26,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override int ReducedSectionCount => 5; protected override double DifficultyMultiplier => 1.04; - private readonly double greatWindow; private readonly List objectStrains = new List(); - public Speed(Mod[] mods, double hitWindowGreat) + public Speed(Mod[] mods) : base(mods) { - greatWindow = hitWindowGreat; } private double strainDecay(double ms) => Math.Pow(strainDecayBase, ms / 1000); @@ -43,9 +41,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double StrainValueAt(DifficultyHitObject current) { currentStrain *= strainDecay(((OsuDifficultyHitObject)current).StrainTime); - currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current, greatWindow) * skillMultiplier; + currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current) * skillMultiplier; - currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current, greatWindow); + currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current); double totalStrain = currentStrain * currentRhythm; From 3003fc1061f63b147a7e9bf0bc7eb03d0a42e7fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Wed, 7 Sep 2022 02:29:15 +0900 Subject: [PATCH 0917/2686] refactor(osu.Game): improve code quality --- .../TestSceneHitEventTimingDistributionGraph.cs | 6 +++--- .../Statistics/HitEventTimingDistributionGraph.cs | 11 ++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs index fe4aba1317..4825cb7f80 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs @@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.Ranking { createTest(CreateDistributedHitEvents(0, 50).Select(h => { - var offset = Math.Abs(h.TimeOffset); + double offset = Math.Abs(h.TimeOffset); var result = offset > 36 ? HitResult.Miss : offset > 32 ? HitResult.Meh : offset > 24 ? HitResult.Ok : offset > 16 ? HitResult.Good : offset > 8 ? HitResult.Great : HitResult.Perfect; return new HitEvent(h.TimeOffset, result, placeholder_object, placeholder_object, null); }).ToList()); @@ -73,13 +73,13 @@ namespace osu.Game.Tests.Visual.Ranking { var wide = CreateDistributedHitEvents(0, 50).Select(h => { - var offset = Math.Abs(h.TimeOffset); + double offset = Math.Abs(h.TimeOffset); var result = offset > 36 ? HitResult.Miss : offset > 32 ? HitResult.Meh : offset > 24 ? HitResult.Ok : offset > 16 ? HitResult.Good : offset > 8 ? HitResult.Great : HitResult.Perfect; return new HitEvent(h.TimeOffset, result, placeholder_object, placeholder_object, null); }); var narrow = CreateDistributedHitEvents(0, 50).Select(h => { - var offset = Math.Abs(h.TimeOffset); + double offset = Math.Abs(h.TimeOffset); var result = offset > 25 ? HitResult.Miss : offset > 20 ? HitResult.Meh : offset > 15 ? HitResult.Ok : offset > 10 ? HitResult.Good : offset > 5 ? HitResult.Great : HitResult.Perfect; return new HitEvent(h.TimeOffset, result, placeholder_object, placeholder_object, null); }); diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 5fbc07921a..d3c2716f8b 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -299,14 +299,11 @@ namespace osu.Game.Screens.Ranking.Statistics float offsetValue = 0; - if (values.Any()) + for (int i = 0; i < values.Count; i++) { - for (int i = 0; i < values.Count; i++) - { - boxOriginals[i].MoveToY(offsetForValue(offsetValue) * BoundingBox.Height, duration, Easing.OutQuint); - boxOriginals[i].ResizeHeightTo(heightForValue(values[i].Value), duration, Easing.OutQuint); - offsetValue -= values[i].Value; - } + boxOriginals[i].MoveToY(offsetForValue(offsetValue) * BoundingBox.Height, duration, Easing.OutQuint); + boxOriginals[i].ResizeHeightTo(heightForValue(values[i].Value), duration, Easing.OutQuint); + offsetValue -= values[i].Value; } } From cb1d886c9cdbe05b7e47ed11cff15f999023f09c Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 7 Sep 2022 13:17:04 +0900 Subject: [PATCH 0918/2686] Add audio feedback for Esc/Back clearing text from a FocusedTextBox --- .../Graphics/UserInterface/FocusedTextBox.cs | 1 + osu.Game/Graphics/UserInterface/OsuTextBox.cs | 38 +++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index 230d921c68..0c18fd36fc 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -88,6 +88,7 @@ namespace osu.Game.Graphics.UserInterface if (Text.Length > 0) { Text = string.Empty; + PlayFeedbackSample(FeedbackSampleType.TextRemove); return true; } } diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 4c2e00d6e0..18977638f3 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -47,7 +47,7 @@ namespace osu.Game.Graphics.UserInterface private bool selectionStarted; private double sampleLastPlaybackTime; - private enum FeedbackSampleType + protected enum FeedbackSampleType { TextAdd, TextAddCaps, @@ -117,30 +117,30 @@ namespace osu.Game.Graphics.UserInterface return; if (added.Any(char.IsUpper) && AllowUniqueCharacterSamples) - playSample(FeedbackSampleType.TextAddCaps); + PlayFeedbackSample(FeedbackSampleType.TextAddCaps); else - playSample(FeedbackSampleType.TextAdd); + PlayFeedbackSample(FeedbackSampleType.TextAdd); } protected override void OnUserTextRemoved(string removed) { base.OnUserTextRemoved(removed); - playSample(FeedbackSampleType.TextRemove); + PlayFeedbackSample(FeedbackSampleType.TextRemove); } protected override void NotifyInputError() { base.NotifyInputError(); - playSample(FeedbackSampleType.TextInvalid); + PlayFeedbackSample(FeedbackSampleType.TextInvalid); } protected override void OnTextCommitted(bool textChanged) { base.OnTextCommitted(textChanged); - playSample(FeedbackSampleType.TextConfirm); + PlayFeedbackSample(FeedbackSampleType.TextConfirm); } protected override void OnCaretMoved(bool selecting) @@ -148,7 +148,7 @@ namespace osu.Game.Graphics.UserInterface base.OnCaretMoved(selecting); if (!selecting) - playSample(FeedbackSampleType.CaretMove); + PlayFeedbackSample(FeedbackSampleType.CaretMove); } protected override void OnTextSelectionChanged(TextSelectionType selectionType) @@ -158,15 +158,15 @@ namespace osu.Game.Graphics.UserInterface switch (selectionType) { case TextSelectionType.Character: - playSample(FeedbackSampleType.SelectCharacter); + PlayFeedbackSample(FeedbackSampleType.SelectCharacter); break; case TextSelectionType.Word: - playSample(selectionStarted ? FeedbackSampleType.SelectCharacter : FeedbackSampleType.SelectWord); + PlayFeedbackSample(selectionStarted ? FeedbackSampleType.SelectCharacter : FeedbackSampleType.SelectWord); break; case TextSelectionType.All: - playSample(FeedbackSampleType.SelectAll); + PlayFeedbackSample(FeedbackSampleType.SelectAll); break; } @@ -179,7 +179,7 @@ namespace osu.Game.Graphics.UserInterface if (!selectionStarted) return; - playSample(FeedbackSampleType.Deselect); + PlayFeedbackSample(FeedbackSampleType.Deselect); selectionStarted = false; } @@ -198,13 +198,13 @@ namespace osu.Game.Graphics.UserInterface case 1: // composition probably ended by pressing backspace, or was cancelled. - playSample(FeedbackSampleType.TextRemove); + PlayFeedbackSample(FeedbackSampleType.TextRemove); return; default: // longer text removed, composition ended because it was cancelled. // could be a different sample if desired. - playSample(FeedbackSampleType.TextRemove); + PlayFeedbackSample(FeedbackSampleType.TextRemove); return; } } @@ -212,7 +212,7 @@ namespace osu.Game.Graphics.UserInterface if (addedTextLength > 0) { // some text was added, probably due to typing new text or by changing the candidate. - playSample(FeedbackSampleType.TextAdd); + PlayFeedbackSample(FeedbackSampleType.TextAdd); return; } @@ -220,14 +220,14 @@ namespace osu.Game.Graphics.UserInterface { // text was probably removed by backspacing. // it's also possible that a candidate that only removed text was changed to. - playSample(FeedbackSampleType.TextRemove); + PlayFeedbackSample(FeedbackSampleType.TextRemove); return; } if (caretMoved) { // only the caret/selection was moved. - playSample(FeedbackSampleType.CaretMove); + PlayFeedbackSample(FeedbackSampleType.CaretMove); } } @@ -238,13 +238,13 @@ namespace osu.Game.Graphics.UserInterface if (successful) { // composition was successfully completed, usually by pressing the enter key. - playSample(FeedbackSampleType.TextConfirm); + PlayFeedbackSample(FeedbackSampleType.TextConfirm); } else { // composition was prematurely ended, eg. by clicking inside the textbox. // could be a different sample if desired. - playSample(FeedbackSampleType.TextConfirm); + PlayFeedbackSample(FeedbackSampleType.TextConfirm); } } @@ -283,7 +283,7 @@ namespace osu.Game.Graphics.UserInterface return samples[RNG.Next(0, samples.Length)]?.GetChannel(); } - private void playSample(FeedbackSampleType feedbackSample) => Schedule(() => + protected void PlayFeedbackSample(FeedbackSampleType feedbackSample) => Schedule(() => { if (Time.Current < sampleLastPlaybackTime + 15) return; From 241d33d415df0bae374889080a3ba0318937ec2f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 14:04:51 +0900 Subject: [PATCH 0919/2686] Apply NRT to `BeatmapCarousel` --- osu.Game/Screens/Select/BeatmapCarousel.cs | 57 ++++++++++------------ 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 0f130714f1..3370dfbb4e 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.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. -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics; @@ -49,31 +47,31 @@ namespace osu.Game.Screens.Select /// /// Triggered when the loaded change and are completely loaded. /// - public Action BeatmapSetsChanged; + public Action? BeatmapSetsChanged; /// /// The currently selected beatmap. /// - public BeatmapInfo SelectedBeatmapInfo => selectedBeatmap?.BeatmapInfo; + public BeatmapInfo? SelectedBeatmapInfo => selectedBeatmap?.BeatmapInfo; - private CarouselBeatmap selectedBeatmap => selectedBeatmapSet?.Beatmaps.FirstOrDefault(s => s.State.Value == CarouselItemState.Selected); + private CarouselBeatmap? selectedBeatmap => selectedBeatmapSet?.Beatmaps.FirstOrDefault(s => s.State.Value == CarouselItemState.Selected); /// /// The currently selected beatmap set. /// - public BeatmapSetInfo SelectedBeatmapSet => selectedBeatmapSet?.BeatmapSet; + public BeatmapSetInfo? SelectedBeatmapSet => selectedBeatmapSet?.BeatmapSet; /// /// A function to optionally decide on a recommended difficulty from a beatmap set. /// - public Func, BeatmapInfo> GetRecommendedBeatmap; + public Func, BeatmapInfo>? GetRecommendedBeatmap; - private CarouselBeatmapSet selectedBeatmapSet; + private CarouselBeatmapSet? selectedBeatmapSet; /// /// Raised when the is changed. /// - public Action SelectionChanged; + public Action? SelectionChanged; public override bool HandleNonPositionalInput => AllowSelection; public override bool HandlePositionalInput => AllowSelection; @@ -151,15 +149,15 @@ namespace osu.Game.Screens.Select private CarouselRoot root; - private IDisposable subscriptionSets; - private IDisposable subscriptionDeletedSets; - private IDisposable subscriptionBeatmaps; - private IDisposable subscriptionHiddenBeatmaps; + private IDisposable? subscriptionSets; + private IDisposable? subscriptionDeletedSets; + private IDisposable? subscriptionBeatmaps; + private IDisposable? subscriptionHiddenBeatmaps; private readonly DrawablePool setPool = new DrawablePool(100); - private Sample spinSample; - private Sample randomSelectSample; + private Sample? spinSample; + private Sample? randomSelectSample; private int visibleSetsCount; @@ -200,7 +198,7 @@ namespace osu.Game.Screens.Select } [Resolved] - private RealmAccess realm { get; set; } + private RealmAccess realm { get; set; } = null!; protected override void LoadComplete() { @@ -215,7 +213,7 @@ namespace osu.Game.Screens.Select subscriptionHiddenBeatmaps = realm.RegisterForNotifications(r => r.All().Where(b => b.Hidden), beatmapsChanged); } - private void deletedBeatmapSetsChanged(IRealmCollection sender, ChangeSet changes, Exception error) + private void deletedBeatmapSetsChanged(IRealmCollection sender, ChangeSet? changes, Exception? error) { // If loading test beatmaps, avoid overwriting with realm subscription callbacks. if (loadedTestBeatmaps) @@ -228,7 +226,7 @@ namespace osu.Game.Screens.Select removeBeatmapSet(sender[i].ID); } - private void beatmapSetsChanged(IRealmCollection sender, ChangeSet changes, Exception error) + private void beatmapSetsChanged(IRealmCollection sender, ChangeSet? changes, Exception? error) { // If loading test beatmaps, avoid overwriting with realm subscription callbacks. if (loadedTestBeatmaps) @@ -304,7 +302,7 @@ namespace osu.Game.Screens.Select } } - private void beatmapsChanged(IRealmCollection sender, ChangeSet changes, Exception error) + private void beatmapsChanged(IRealmCollection sender, ChangeSet? changes, Exception? error) { // we only care about actual changes in hidden status. if (changes == null) @@ -367,7 +365,7 @@ namespace osu.Game.Screens.Select // check if we can/need to maintain our current selection. if (previouslySelectedID != null) - select((CarouselItem)newSet.Beatmaps.FirstOrDefault(b => b.BeatmapInfo.ID == previouslySelectedID) ?? newSet); + select((CarouselItem?)newSet.Beatmaps.FirstOrDefault(b => b.BeatmapInfo.ID == previouslySelectedID) ?? newSet); } itemsCache.Invalidate(); @@ -384,7 +382,7 @@ namespace osu.Game.Screens.Select /// The beatmap to select. /// Whether to select the beatmap even if it is filtered (i.e., not visible on carousel). /// True if a selection was made, False if it wasn't. - public bool SelectBeatmap(BeatmapInfo beatmapInfo, bool bypassFilters = true) + public bool SelectBeatmap(BeatmapInfo? beatmapInfo, bool bypassFilters = true) { // ensure that any pending events from BeatmapManager have been run before attempting a selection. Scheduler.Update(); @@ -549,7 +547,7 @@ namespace osu.Game.Screens.Select randomSelectSample?.Play(); } - private void select(CarouselItem item) + private void select(CarouselItem? item) { if (!AllowSelection) return; @@ -561,7 +559,7 @@ namespace osu.Game.Screens.Select private FilterCriteria activeCriteria = new FilterCriteria(); - protected ScheduledDelegate PendingFilter; + protected ScheduledDelegate? PendingFilter; public bool AllowSelection = true; @@ -593,7 +591,7 @@ namespace osu.Game.Screens.Select } } - public void Filter(FilterCriteria newCriteria, bool debounce = true) + public void Filter(FilterCriteria? newCriteria, bool debounce = true) { if (newCriteria != null) activeCriteria = newCriteria; @@ -796,7 +794,7 @@ namespace osu.Game.Screens.Select return (firstIndex, lastIndex); } - private CarouselBeatmapSet createCarouselSet(BeatmapSetInfo beatmapSet) + private CarouselBeatmapSet? createCarouselSet(BeatmapSetInfo beatmapSet) { // This can be moved to the realm query if required using: // .Filter("DeletePending == false && Protected == false && ANY Beatmaps.Hidden == false") @@ -962,7 +960,7 @@ namespace osu.Game.Screens.Select ///
/// The item to be updated. /// For nested items, the parent of the item to be updated. - private void updateItem(DrawableCarouselItem item, DrawableCarouselItem parent = null) + private void updateItem(DrawableCarouselItem item, DrawableCarouselItem? parent = null) { Vector2 posInScroll = Scroll.ScrollContent.ToLocalSpace(item.Header.ScreenSpaceDrawQuad.Centre); float itemDrawY = posInScroll.Y - visibleUpperBound; @@ -990,8 +988,7 @@ namespace osu.Game.Screens.Select ///
private class CarouselBoundsItem : CarouselItem { - public override DrawableCarouselItem CreateDrawableRepresentation() => - throw new NotImplementedException(); + public override DrawableCarouselItem CreateDrawableRepresentation() => throw new NotImplementedException(); } private class CarouselRoot : CarouselGroupEagerSelect @@ -1017,7 +1014,7 @@ namespace osu.Game.Screens.Select base.AddItem(i); } - public CarouselBeatmapSet RemoveChild(Guid beatmapSetID) + public CarouselBeatmapSet? RemoveChild(Guid beatmapSetID) { if (BeatmapSetsByID.TryGetValue(beatmapSetID, out var carouselBeatmapSet)) { @@ -1039,7 +1036,7 @@ namespace osu.Game.Screens.Select protected override void PerformSelection() { if (LastSelected == null || LastSelected.Filtered.Value) - carousel?.SelectNextRandom(); + carousel.SelectNextRandom(); else base.PerformSelection(); } From e18b524f8e8cd89e94d99d39d324cb0a4d556263 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 14:08:07 +0900 Subject: [PATCH 0920/2686] Fix missing null checks on `selectedBeatmap` fields in `BeatmapCarousel` --- osu.Game/Screens/Select/BeatmapCarousel.cs | 30 +++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 3370dfbb4e..e0dfbe2a1c 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -264,8 +264,11 @@ namespace osu.Game.Screens.Select foreach (int i in changes.InsertedIndices) UpdateBeatmapSet(sender[i].Detach()); - if (changes.DeletedIndices.Length > 0) + if (changes.DeletedIndices.Length > 0 && SelectedBeatmapInfo != null) { + // If SelectedBeatmapInfo is non-null, the set should also be non-null. + Debug.Assert(SelectedBeatmapSet != null); + // To handle the beatmap update flow, attempt to track selection changes across delete-insert transactions. // When an update occurs, the previous beatmap set is either soft or hard deleted. // Check if the current selection was potentially deleted by re-querying its validity. @@ -440,6 +443,9 @@ namespace osu.Game.Screens.Select private void selectNextSet(int direction, bool skipDifficulties) { + if (selectedBeatmap == null || selectedBeatmapSet == null) + return; + var unfilteredSets = beatmapSets.Where(s => !s.Filtered.Value).ToList(); var nextSet = unfilteredSets[(unfilteredSets.IndexOf(selectedBeatmapSet) + direction + unfilteredSets.Count) % unfilteredSets.Count]; @@ -452,7 +458,7 @@ namespace osu.Game.Screens.Select private void selectNextDifficulty(int direction) { - if (selectedBeatmap == null) + if (selectedBeatmap == null || selectedBeatmapSet == null) return; var unfilteredDifficulties = selectedBeatmapSet.Items.Where(s => !s.Filtered.Value).ToList(); @@ -481,7 +487,7 @@ namespace osu.Game.Screens.Select if (!visibleSets.Any()) return false; - if (selectedBeatmap != null) + if (selectedBeatmap != null && selectedBeatmapSet != null) { randomSelectedBeatmaps.Push(selectedBeatmap); @@ -524,11 +530,13 @@ namespace osu.Game.Screens.Select if (!beatmap.Filtered.Value) { - if (RandomAlgorithm.Value == RandomSelectAlgorithm.RandomPermutation) - previouslyVisitedRandomSets.Remove(selectedBeatmapSet); - if (selectedBeatmapSet != null) + { + if (RandomAlgorithm.Value == RandomSelectAlgorithm.RandomPermutation) + previouslyVisitedRandomSets.Remove(selectedBeatmapSet); + playSpinSample(distanceBetween(beatmap, selectedBeatmapSet)); + } select(beatmap); break; @@ -540,9 +548,13 @@ namespace osu.Game.Screens.Select private void playSpinSample(double distance) { - var chan = spinSample.GetChannel(); - chan.Frequency.Value = 1f + Math.Min(1f, distance / visibleSetsCount); - chan.Play(); + var chan = spinSample?.GetChannel(); + + if (chan != null) + { + chan.Frequency.Value = 1f + Math.Min(1f, distance / visibleSetsCount); + chan.Play(); + } randomSelectSample?.Play(); } From f3bda4e040196f38763001768922f3c2553b6dd8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 14:27:24 +0900 Subject: [PATCH 0921/2686] Fix weird edge case of nullability in `CarouselRoot` A bit unfortunately, but it's what we get for having ctor level bindings.. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index e0dfbe2a1c..a8cb06b888 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -1005,7 +1005,8 @@ namespace osu.Game.Screens.Select private class CarouselRoot : CarouselGroupEagerSelect { - private readonly BeatmapCarousel carousel; + // May only be null during construction (State.Value set causes PerformSelection to be triggered). + private readonly BeatmapCarousel? carousel; public readonly Dictionary BeatmapSetsByID = new Dictionary(); @@ -1048,7 +1049,7 @@ namespace osu.Game.Screens.Select protected override void PerformSelection() { if (LastSelected == null || LastSelected.Filtered.Value) - carousel.SelectNextRandom(); + carousel?.SelectNextRandom(); else base.PerformSelection(); } From 866bc553fe65a8720c82c804f36a7f97c6a3f30c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 15:30:48 +0900 Subject: [PATCH 0922/2686] Tidy up `TestSceneStoryboard` --- .../Visual/Gameplay/TestSceneStoryboard.cs | 54 ++++++++----------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs index 2ec675874b..eaf22ba9cc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.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. -#nullable disable - using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -24,8 +22,9 @@ namespace osu.Game.Tests.Visual.Gameplay [TestFixture] public class TestSceneStoryboard : OsuTestScene { - private Container storyboardContainer; - private DrawableStoryboard storyboard; + private Container storyboardContainer = null!; + + private DrawableStoryboard? storyboard; [Test] public void TestStoryboard() @@ -40,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestStoryboardMissingVideo() { - AddStep("Load storyboard with missing video", loadStoryboardNoVideo); + AddStep("Load storyboard with missing video", () => loadStoryboard("storyboard_no_video.osu")); } [BackgroundDependencyLoader] @@ -77,18 +76,18 @@ namespace osu.Game.Tests.Visual.Gameplay Beatmap.BindValueChanged(beatmapChanged, true); } - private void beatmapChanged(ValueChangedEvent e) => loadStoryboard(e.NewValue); + private void beatmapChanged(ValueChangedEvent e) => loadStoryboard(e.NewValue.Storyboard); private void restart() { var track = Beatmap.Value.Track; track.Reset(); - loadStoryboard(Beatmap.Value); + loadStoryboard(Beatmap.Value.Storyboard); track.Start(); } - private void loadStoryboard(IWorkingBeatmap working) + private void loadStoryboard(Storyboard toLoad) { if (storyboard != null) storyboardContainer.Remove(storyboard, true); @@ -96,34 +95,25 @@ namespace osu.Game.Tests.Visual.Gameplay var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true }; storyboardContainer.Clock = decoupledClock; - storyboard = working.Storyboard.CreateDrawable(SelectedMods.Value); + storyboard = toLoad.CreateDrawable(SelectedMods.Value); storyboard.Passing = false; - storyboardContainer.Add(storyboard); - decoupledClock.ChangeSource(working.Track); - } - - private void loadStoryboardNoVideo() - { - if (storyboard != null) - storyboardContainer.Remove(storyboard, true); - - var decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = true }; - storyboardContainer.Clock = decoupledClock; - - Storyboard sb; - - using (var str = TestResources.OpenResource("storyboard_no_video.osu")) - using (var bfr = new LineBufferedReader(str)) - { - var decoder = new LegacyStoryboardDecoder(); - sb = decoder.Decode(bfr); - } - - storyboard = sb.CreateDrawable(SelectedMods.Value); - storyboardContainer.Add(storyboard); decoupledClock.ChangeSource(Beatmap.Value.Track); } + + private void loadStoryboard(string filename) + { + Storyboard loaded; + + using (var str = TestResources.OpenResource(filename)) + using (var bfr = new LineBufferedReader(str)) + { + var decoder = new LegacyStoryboardDecoder(); + loaded = decoder.Decode(bfr); + } + + loadStoryboard(loaded); + } } } From 258b8f015c9dfda22b7d1720c61347c7ba449411 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 15:37:22 +0900 Subject: [PATCH 0923/2686] Add test coverage of storyboard using zero `VectorScale` --- .../Gameplay/TestSceneDrawableStoryboardSprite.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs index ca7d7b42d8..34723e3329 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -73,6 +71,17 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("origin flipped", () => sprites.All(s => s.Origin == Anchor.BottomRight)); } + [Test] + public void TestZeroScale() + { + const string lookup_name = "hitcircleoverlay"; + + AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true); + AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); + AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(0, 1))); + AddAssert("zero width", () => sprites.All(s => s.ScreenSpaceDrawQuad.Width == 0)); + } + [Test] public void TestNegativeScale() { From 824e68dab35f114c1960c5a5c30dacbbe3c99896 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 15:16:20 +0900 Subject: [PATCH 0924/2686] Fix `VectorScale` set to 0 still showing some sprites in storyboard This implementation was matching the [framework side implementation of scale](https://github.com/ppy/osu-framework/blob/16d1c2d3356b0f59271fb49cff5fe8373ae9cdf3/osu.Framework/Graphics/Drawable.cs#L973-L976) but I don't think it's required here. I'm still not sure if the framework implementation is correct, but removing it locally does seem to fix broken storyboard cases. Closes https://github.com/ppy/osu/issues/20155. --- .../Storyboards/Drawables/DrawableStoryboardAnimation.cs | 5 ----- osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs | 5 ----- 2 files changed, 10 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index 9822f36620..f3187d77b7 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -56,11 +56,6 @@ namespace osu.Game.Storyboards.Drawables get => vectorScale; set { - if (Math.Abs(value.X) < Precision.FLOAT_EPSILON) - value.X = Precision.FLOAT_EPSILON; - if (Math.Abs(value.Y) < Precision.FLOAT_EPSILON) - value.Y = Precision.FLOAT_EPSILON; - if (vectorScale == value) return; diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index 28ed2e65e3..b86b021d51 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -55,11 +55,6 @@ namespace osu.Game.Storyboards.Drawables get => vectorScale; set { - if (Math.Abs(value.X) < Precision.FLOAT_EPSILON) - value.X = Precision.FLOAT_EPSILON; - if (Math.Abs(value.Y) < Precision.FLOAT_EPSILON) - value.Y = Precision.FLOAT_EPSILON; - if (vectorScale == value) return; From b50116e9e4c29b33130712783e2625ee7a391d4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 14:40:51 +0900 Subject: [PATCH 0925/2686] Add missing null check in `BeatmapCarousel` tests --- .../Visual/SongSelect/TestSceneBeatmapCarousel.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index c9e63fa621..0e72463d1e 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -173,7 +173,7 @@ namespace osu.Game.Tests.Visual.SongSelect if (isIterating) AddUntilStep("selection changed", () => !carousel.SelectedBeatmapInfo?.Equals(selection) == true); else - AddUntilStep("selection not changed", () => carousel.SelectedBeatmapInfo.Equals(selection)); + AddUntilStep("selection not changed", () => carousel.SelectedBeatmapInfo?.Equals(selection) == true); } } } @@ -382,7 +382,7 @@ namespace osu.Game.Tests.Visual.SongSelect // buffer the selection setSelected(3, 2); - AddStep("get search text", () => searchText = carousel.SelectedBeatmapSet.Metadata.Title); + AddStep("get search text", () => searchText = carousel.SelectedBeatmapSet!.Metadata.Title); setSelected(1, 3); @@ -701,7 +701,7 @@ namespace osu.Game.Tests.Visual.SongSelect setSelected(2, 1); AddAssert("Selection is non-null", () => currentSelection != null); - AddStep("Remove selected", () => carousel.RemoveBeatmapSet(carousel.SelectedBeatmapSet)); + AddStep("Remove selected", () => carousel.RemoveBeatmapSet(carousel.SelectedBeatmapSet!)); waitForSelection(2); AddStep("Remove first", () => carousel.RemoveBeatmapSet(carousel.BeatmapSets.First())); @@ -804,7 +804,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("filter to ruleset 0", () => carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(0) }, false)); AddStep("select filtered map skipping filtered", () => carousel.SelectBeatmap(testMixed.Beatmaps[1], false)); - AddAssert("unfiltered beatmap not selected", () => carousel.SelectedBeatmapInfo.Ruleset.OnlineID == 0); + AddAssert("unfiltered beatmap not selected", () => carousel.SelectedBeatmapInfo?.Ruleset.OnlineID == 0); AddStep("remove mixed set", () => { @@ -854,7 +854,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("Restore no filter", () => { carousel.Filter(new FilterCriteria(), false); - eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID); + eagerSelectedIDs.Add(carousel.SelectedBeatmapSet!.ID); }); } @@ -899,10 +899,10 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("Restore different ruleset filter", () => { carousel.Filter(new FilterCriteria { Ruleset = rulesets.GetRuleset(1) }, false); - eagerSelectedIDs.Add(carousel.SelectedBeatmapSet.ID); + eagerSelectedIDs.Add(carousel.SelectedBeatmapSet!.ID); }); - AddAssert("selection changed", () => !carousel.SelectedBeatmapInfo.Equals(manySets.First().Beatmaps.First())); + AddAssert("selection changed", () => !carousel.SelectedBeatmapInfo!.Equals(manySets.First().Beatmaps.First())); } AddAssert("Selection was random", () => eagerSelectedIDs.Count > 2); From cb1bb99208d24c7d15f6adb64e289f87ae0116b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 16:43:48 +0900 Subject: [PATCH 0926/2686] Tidy up test logic --- ...estSceneHitEventTimingDistributionGraph.cs | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs index 4825cb7f80..198be4035b 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -20,7 +18,7 @@ namespace osu.Game.Tests.Visual.Ranking { public class TestSceneHitEventTimingDistributionGraph : OsuTestScene { - private HitEventTimingDistributionGraph graph; + private HitEventTimingDistributionGraph graph = null!; private static readonly HitObject placeholder_object = new HitCircle(); @@ -63,7 +61,12 @@ namespace osu.Game.Tests.Visual.Ranking createTest(CreateDistributedHitEvents(0, 50).Select(h => { double offset = Math.Abs(h.TimeOffset); - var result = offset > 36 ? HitResult.Miss : offset > 32 ? HitResult.Meh : offset > 24 ? HitResult.Ok : offset > 16 ? HitResult.Good : offset > 8 ? HitResult.Great : HitResult.Perfect; + HitResult result = offset > 36 ? HitResult.Miss + : offset > 32 ? HitResult.Meh + : offset > 24 ? HitResult.Ok + : offset > 16 ? HitResult.Good + : offset > 8 ? HitResult.Great + : HitResult.Perfect; return new HitEvent(h.TimeOffset, result, placeholder_object, placeholder_object, null); }).ToList()); } @@ -74,13 +77,24 @@ namespace osu.Game.Tests.Visual.Ranking var wide = CreateDistributedHitEvents(0, 50).Select(h => { double offset = Math.Abs(h.TimeOffset); - var result = offset > 36 ? HitResult.Miss : offset > 32 ? HitResult.Meh : offset > 24 ? HitResult.Ok : offset > 16 ? HitResult.Good : offset > 8 ? HitResult.Great : HitResult.Perfect; + HitResult result = offset > 36 ? HitResult.Miss + : offset > 32 ? HitResult.Meh + : offset > 24 ? HitResult.Ok + : offset > 16 ? HitResult.Good + : offset > 8 ? HitResult.Great + : HitResult.Perfect; + return new HitEvent(h.TimeOffset, result, placeholder_object, placeholder_object, null); }); var narrow = CreateDistributedHitEvents(0, 50).Select(h => { double offset = Math.Abs(h.TimeOffset); - var result = offset > 25 ? HitResult.Miss : offset > 20 ? HitResult.Meh : offset > 15 ? HitResult.Ok : offset > 10 ? HitResult.Good : offset > 5 ? HitResult.Great : HitResult.Perfect; + HitResult result = offset > 25 ? HitResult.Miss + : offset > 20 ? HitResult.Meh + : offset > 15 ? HitResult.Ok + : offset > 10 ? HitResult.Good + : offset > 5 ? HitResult.Great + : HitResult.Perfect; return new HitEvent(h.TimeOffset, result, placeholder_object, placeholder_object, null); }); createTest(wide.Concat(narrow).ToList()); From 99ef0c95fec70b164c745f589fc8940726faf454 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 16:51:51 +0900 Subject: [PATCH 0927/2686] Simplify children assignment --- .../Ranking/Statistics/HitEventTimingDistributionGraph.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index d3c2716f8b..37765fe962 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -252,7 +252,7 @@ namespace osu.Game.Screens.Ranking.Statistics if (values.Any()) { - boxOriginals = values.Select((v, i) => new Circle + InternalChildren = boxOriginals = values.Select((v, i) => new Circle { RelativeSizeAxes = Axes.Both, Anchor = Anchor.BottomCentre, @@ -260,7 +260,6 @@ namespace osu.Game.Screens.Ranking.Statistics Colour = isCentre && i == 0 ? Color4.White : v.Colour, Height = 0, }).ToArray(); - InternalChildren = boxOriginals.Reverse().ToArray(); } else { From b5b66de3c9c8a3a99b6e9ffd6d4994a3fa6e6b61 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 17:45:15 +0900 Subject: [PATCH 0928/2686] Fix target mod crashing if beatmap is played with a break after all hitobjects Closes https://github.com/ppy/osu/issues/20161. --- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 5e2a92e5e9..861ad80b7f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -362,10 +362,12 @@ namespace osu.Game.Rulesets.Osu.Mods { return breaks.Any(breakPeriod => { - var firstObjAfterBreak = originalHitObjects.First(obj => almostBigger(obj.StartTime, breakPeriod.EndTime)); + OsuHitObject? firstObjAfterBreak = originalHitObjects.FirstOrDefault(obj => almostBigger(obj.StartTime, breakPeriod.EndTime)); return almostBigger(time, breakPeriod.StartTime) - && definitelyBigger(firstObjAfterBreak.StartTime, time); + // There should never really be a break section with no objects after it, but we've seen crashes from users with malformed beatmaps, + // so it's best to guard against this. + && (firstObjAfterBreak == null || definitelyBigger(firstObjAfterBreak.StartTime, time)); }); } From 75d0deef72ab44b075345f6f4aeddde4d1a52492 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 17:38:00 +0900 Subject: [PATCH 0929/2686] Apply proposed changes to remove inheritance from `MasterGameplayClockContainer` --- .../NonVisual/GameplayClockContainerTest.cs | 6 +- .../Rulesets/UI/FrameStabilityContainer.cs | 7 ++- .../Screens/Play/GameplayClockContainer.cs | 5 +- .../Screens/Play/GameplayClockExtensions.cs | 8 ++- osu.Game/Screens/Play/IGameplayClock.cs | 6 +- .../Play/MasterGameplayClockContainer.cs | 57 +------------------ osu.Game/Screens/Play/Player.cs | 7 ++- 7 files changed, 24 insertions(+), 72 deletions(-) diff --git a/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs b/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs index 95bf1ab354..80f0aaeb55 100644 --- a/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs +++ b/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs @@ -1,8 +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.Collections.Generic; using NUnit.Framework; +using osu.Framework.Audio; +using osu.Framework.Bindables; using osu.Framework.Timing; using osu.Game.Screens.Play; @@ -23,11 +24,10 @@ namespace osu.Game.Tests.NonVisual private class TestGameplayClockContainer : GameplayClockContainer { - public override IEnumerable GameplayAdjustments => new[] { 2.0 }; - public TestGameplayClockContainer(IFrameBasedClock underlyingClock) : base(underlyingClock) { + GameplayAdjustments.AddAdjustment(AdjustableProperty.Frequency, new BindableDouble(2.0)); } } } diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 4f4a2d908d..f0c7a398eb 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -2,10 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -264,7 +263,9 @@ namespace osu.Game.Rulesets.UI public double StartTime => parentGameplayClock?.StartTime ?? 0; - public IEnumerable GameplayAdjustments => parentGameplayClock?.GameplayAdjustments ?? Enumerable.Empty(); + private readonly AudioAdjustments gameplayAdjustments = new AudioAdjustments(); + + public IAdjustableAudioComponent GameplayAdjustments => parentGameplayClock?.GameplayAdjustments ?? gameplayAdjustments; #endregion diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 5dfaf2d584..e64c628fa0 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -2,9 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -45,7 +44,7 @@ namespace osu.Game.Screens.Play /// public double StartTime { get; protected set; } - public virtual IEnumerable GameplayAdjustments => Enumerable.Empty(); + public IAdjustableAudioComponent GameplayAdjustments { get; } = new AudioAdjustments(); private readonly BindableBool isPaused = new BindableBool(true); diff --git a/osu.Game/Screens/Play/GameplayClockExtensions.cs b/osu.Game/Screens/Play/GameplayClockExtensions.cs index b683c61f63..3cc12f7afe 100644 --- a/osu.Game/Screens/Play/GameplayClockExtensions.cs +++ b/osu.Game/Screens/Play/GameplayClockExtensions.cs @@ -13,10 +13,12 @@ namespace osu.Game.Screens.Play ///
public static double GetTrueGameplayRate(this IGameplayClock clock) { + // To handle rewind, we still want to maintain the same direction as the underlying clock. double rate = Math.Sign(clock.Rate); - foreach (double a in clock.GameplayAdjustments) - rate *= a; - return rate; + + return rate + * clock.GameplayAdjustments.AggregateFrequency.Value + * clock.GameplayAdjustments.AggregateTempo.Value; } } } diff --git a/osu.Game/Screens/Play/IGameplayClock.cs b/osu.Game/Screens/Play/IGameplayClock.cs index 7c50b9d407..c58d2dbcac 100644 --- a/osu.Game/Screens/Play/IGameplayClock.cs +++ b/osu.Game/Screens/Play/IGameplayClock.cs @@ -1,7 +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.Collections.Generic; +using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Timing; @@ -19,9 +19,9 @@ namespace osu.Game.Screens.Play double StartTime { get; } /// - /// All adjustments applied to this clock which don't come from gameplay or mods. + /// All adjustments applied to this clock which come from gameplay or mods. /// - IEnumerable GameplayAdjustments { get; } + IAdjustableAudioComponent GameplayAdjustments { get; } IBindable IsPaused { get; } } diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 7c30f86125..226ce8b0d8 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -2,13 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Linq; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -25,7 +23,7 @@ namespace osu.Game.Screens.Play /// /// This is intended to be used as a single controller for gameplay, or as a reference source for other s. /// - public class MasterGameplayClockContainer : GameplayClockContainer, IBeatSyncProvider, IAdjustableAudioComponent + public class MasterGameplayClockContainer : GameplayClockContainer, IBeatSyncProvider { /// /// Duration before gameplay start time required before skip button displays. @@ -57,11 +55,6 @@ namespace osu.Game.Screens.Play /// private double? actualStopTime; - /// - /// Maintained solely to delegate pieces to (to maintain parent lookups). - /// - private readonly AudioContainer audioContainer; - /// /// Create a new master gameplay clock container. /// @@ -75,8 +68,6 @@ namespace osu.Game.Screens.Play this.skipTargetTime = skipTargetTime; StartTime = findEarliestStartTime(); - - AddInternal(audioContainer = new AudioContainer()); } private double findEarliestStartTime() @@ -202,6 +193,7 @@ namespace osu.Game.Screens.Play if (speedAdjustmentsApplied) return; + track.BindAdjustments(GameplayAdjustments); track.AddAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); @@ -213,6 +205,7 @@ namespace osu.Game.Screens.Play if (!speedAdjustmentsApplied) return; + track.UnbindAdjustments(GameplayAdjustments); track.RemoveAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); @@ -229,49 +222,5 @@ namespace osu.Game.Screens.Play IClock IBeatSyncProvider.Clock => this; ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => beatmap.TrackLoaded ? beatmap.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; - - private readonly List> speedAdjustments = new List>(); - - public override IEnumerable GameplayAdjustments => speedAdjustments.Select(bindable => bindable.Value); - - void IAdjustableAudioComponent.AddAdjustment(AdjustableProperty type, IBindable adjustBindable) - { - speedAdjustments.Add(adjustBindable); - track.AddAdjustment(type, adjustBindable); - } - - void IAdjustableAudioComponent.RemoveAdjustment(AdjustableProperty type, IBindable adjustBindable) - { - speedAdjustments.Remove(adjustBindable); - track.RemoveAdjustment(type, adjustBindable); - } - - void IAdjustableAudioComponent.RemoveAllAdjustments(AdjustableProperty type) => audioContainer.RemoveAllAdjustments(type); - - void IAdjustableAudioComponent.BindAdjustments(IAggregateAudioAdjustment component) => audioContainer.BindAdjustments(component); - - void IAdjustableAudioComponent.UnbindAdjustments(IAggregateAudioAdjustment component) => audioContainer.UnbindAdjustments(component); - - BindableNumber IAdjustableAudioComponent.Volume => audioContainer.Volume; - - BindableNumber IAdjustableAudioComponent.Balance => audioContainer.Balance; - - BindableNumber IAdjustableAudioComponent.Frequency => audioContainer.Frequency; - - BindableNumber IAdjustableAudioComponent.Tempo => audioContainer.Tempo; - - public override void ResetSpeedAdjustments() - { - track.RemoveAllAdjustments(AdjustableProperty.Frequency); - track.RemoveAllAdjustments(AdjustableProperty.Tempo); - } - - IBindable IAggregateAudioAdjustment.AggregateVolume => audioContainer.AggregateVolume; - - IBindable IAggregateAudioAdjustment.AggregateBalance => audioContainer.AggregateBalance; - - IBindable IAggregateAudioAdjustment.AggregateFrequency => audioContainer.AggregateFrequency; - - IBindable IAggregateAudioAdjustment.AggregateTempo => audioContainer.AggregateTempo; } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 21a02fbe0b..17cae05862 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -999,11 +999,12 @@ namespace osu.Game.Screens.Play // Our mods are local copies of the global mods so they need to be re-applied to the track. // This is done through the music controller (for now), because resetting speed adjustments on the beatmap track also removes adjustments provided by DrawableTrack. // Todo: In the future, player will receive in a track and will probably not have to worry about this... - if (GameplayClockContainer is IAdjustableAudioComponent adjustableClock) + if (GameplayClockContainer is MasterGameplayClockContainer masterClock) { - GameplayClockContainer.ResetSpeedAdjustments(); + musicController.ResetTrackAdjustments(); + foreach (var mod in GameplayState.Mods.OfType()) - mod.ApplyToTrack(adjustableClock); + mod.ApplyToTrack(masterClock.GameplayAdjustments); } updateGameplayState(); From fa15502384f86d6a323cf999eb6692497beb8a7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 19:12:16 +0900 Subject: [PATCH 0930/2686] Move full track adjustment flow inside `MasterGameplayClockContainer` --- .../Screens/Play/MasterGameplayClockContainer.cs | 7 +++++++ osu.Game/Screens/Play/Player.cs | 12 ++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 226ce8b0d8..26fb127e83 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; using osu.Framework.Bindables; @@ -10,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Overlays; namespace osu.Game.Screens.Play { @@ -55,6 +57,9 @@ namespace osu.Game.Screens.Play ///
private double? actualStopTime; + [Resolved] + private MusicController musicController { get; set; } = null!; + /// /// Create a new master gameplay clock container. /// @@ -193,6 +198,8 @@ namespace osu.Game.Screens.Play if (speedAdjustmentsApplied) return; + musicController.ResetTrackAdjustments(); + track.BindAdjustments(GameplayAdjustments); track.AddAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 17cae05862..e93502da13 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -996,16 +996,8 @@ namespace osu.Game.Screens.Play foreach (var mod in GameplayState.Mods.OfType()) mod.ApplyToHUD(HUDOverlay); - // Our mods are local copies of the global mods so they need to be re-applied to the track. - // This is done through the music controller (for now), because resetting speed adjustments on the beatmap track also removes adjustments provided by DrawableTrack. - // Todo: In the future, player will receive in a track and will probably not have to worry about this... - if (GameplayClockContainer is MasterGameplayClockContainer masterClock) - { - musicController.ResetTrackAdjustments(); - - foreach (var mod in GameplayState.Mods.OfType()) - mod.ApplyToTrack(masterClock.GameplayAdjustments); - } + foreach (var mod in GameplayState.Mods.OfType()) + mod.ApplyToTrack(GameplayClockContainer.GameplayAdjustments); updateGameplayState(); From 1be3b74ff33367af48d34c7e42fb0bd7b530c94c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 19:12:34 +0900 Subject: [PATCH 0931/2686] Fix multiplayer spectator not getting gameplay adjustments applied --- .../Spectate/MultiSpectatorPlayer.cs | 11 ++++++++++- .../Spectate/MultiSpectatorScreen.cs | 19 +++++++++++++++++++ .../Spectate/SpectatorPlayerClock.cs | 3 +++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index d351d121c6..7e910b7946 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -53,6 +53,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) - => new GameplayClockContainer(spectatorPlayerClock); + { + var gameplayClockContainer = new GameplayClockContainer(spectatorPlayerClock); + + // Directionality is important, as BindAdjustments is... not actually a bidirectional bind... + // We want to ensure that any adjustments applied by the Player instance are applied to the SpectatorPlayerClock + // so they can be consumed by the spectator screen (and applied to the master clock / track). + spectatorPlayerClock.GameplayAdjustments.BindAdjustments(gameplayClockContainer.GameplayAdjustments); + + return gameplayClockContainer; + } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index c2ece90472..b7c07372dc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -43,6 +44,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate [Resolved] private MultiplayerClient multiplayerClient { get; set; } = null!; + private AudioAdjustments? boundAdjustments; + private readonly PlayerArea[] instances; private MasterGameplayClockContainer masterClockContainer = null!; private SpectatorSyncManager syncManager = null!; @@ -157,6 +160,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate base.LoadComplete(); masterClockContainer.Reset(); + + // Start with adjustments from the first player to keep a sane state. + bindAudioAdjustments(instances.First()); } protected override void Update() @@ -169,11 +175,24 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate .OrderBy(i => Math.Abs(i.SpectatorPlayerClock.CurrentTime - syncManager.CurrentMasterTime)) .FirstOrDefault(); + // Only bind adjustments if there's actually a valid source, else just use the previous ones to ensure no sudden changes to audio. + if (currentAudioSource != null) + bindAudioAdjustments(currentAudioSource); + foreach (var instance in instances) instance.Mute = instance != currentAudioSource; } } + private void bindAudioAdjustments(PlayerArea first) + { + if (boundAdjustments != null) + masterClockContainer.GameplayAdjustments.UnbindAdjustments(boundAdjustments); + + boundAdjustments = first.SpectatorPlayerClock.GameplayAdjustments; + masterClockContainer.GameplayAdjustments.BindAdjustments(boundAdjustments); + } + private bool isCandidateAudioSource(SpectatorPlayerClock? clock) => clock?.IsRunning == true && !clock.IsCatchingUp && !clock.WaitingOnFrames; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 45615d4e19..5667be1f4b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Audio; using osu.Framework.Timing; using osu.Game.Screens.Play; @@ -19,6 +20,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly GameplayClockContainer masterClock; + public readonly AudioAdjustments GameplayAdjustments = new AudioAdjustments(); + public double CurrentTime { get; private set; } /// From e6b449fe0b602a76a7d61efb5bff0a609fb241cd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 19:23:44 +0900 Subject: [PATCH 0932/2686] Fix case of zero rate calculating a zero true gameplay rate --- osu.Game/Screens/Play/GameplayClockExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayClockExtensions.cs b/osu.Game/Screens/Play/GameplayClockExtensions.cs index 3cc12f7afe..ec77a94ce9 100644 --- a/osu.Game/Screens/Play/GameplayClockExtensions.cs +++ b/osu.Game/Screens/Play/GameplayClockExtensions.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Play public static double GetTrueGameplayRate(this IGameplayClock clock) { // To handle rewind, we still want to maintain the same direction as the underlying clock. - double rate = Math.Sign(clock.Rate); + double rate = clock.Rate == 0 ? 1 : Math.Sign(clock.Rate); return rate * clock.GameplayAdjustments.AggregateFrequency.Value From cb9bae1f5c87ac68fa621a7652db9a9e3dea11df Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 7 Sep 2022 19:05:53 +0900 Subject: [PATCH 0933/2686] Enable NRT --- .../Match/MultiplayerMatchSettingsOverlay.cs | 56 +++++++++---------- .../Playlists/PlaylistsSongSelect.cs | 2 - 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 3d6127e8e7..c2dafda592 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -1,12 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.ComponentModel; using System.Diagnostics; -using JetBrains.Annotations; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -15,6 +13,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -30,12 +29,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public class MultiplayerMatchSettingsOverlay : RoomSettingsOverlay { - private MatchSettings settings; + private MatchSettings settings = null!; protected override OsuButton SubmitButton => settings.ApplyButton; [Resolved] - private OngoingOperationTracker ongoingOperationTracker { get; set; } + private OngoingOperationTracker ongoingOperationTracker { get; set; } = null!; protected override bool IsLoading => ongoingOperationTracker.InProgress.Value; @@ -57,20 +56,24 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { private const float disabled_alpha = 0.2f; - public Action SettingsApplied; + public Action? SettingsApplied; - public OsuTextBox NameField, MaxParticipantsField; - public MatchTypePicker TypePicker; - public OsuEnumDropdown QueueModeDropdown; - public OsuTextBox PasswordTextBox; - public OsuCheckbox AutoSkipCheckbox; - public TriangleButton ApplyButton; + public OsuTextBox NameField = null!; + public OsuTextBox MaxParticipantsField = null!; + public MatchTypePicker TypePicker = null!; + public OsuEnumDropdown QueueModeDropdown = null!; + public OsuTextBox PasswordTextBox = null!; + public OsuCheckbox AutoSkipCheckbox = null!; + public TriangleButton ApplyButton = null!; - public OsuSpriteText ErrorText; + public OsuSpriteText ErrorText = null!; - private OsuEnumDropdown startModeDropdown; - private OsuSpriteText typeLabel; - private LoadingLayer loadingLayer; + private OsuEnumDropdown startModeDropdown = null!; + private OsuSpriteText typeLabel = null!; + private LoadingLayer loadingLayer = null!; + + [Resolved] + private BeatmapManager beatmapManager { get; set; } = null!; public void SelectBeatmap() { @@ -79,26 +82,23 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match } [Resolved] - private MultiplayerMatchSubScreen matchSubScreen { get; set; } + private MultiplayerMatchSubScreen matchSubScreen { get; set; } = null!; [Resolved] - private IRoomManager manager { get; set; } + private IRoomManager manager { get; set; } = null!; [Resolved] - private MultiplayerClient client { get; set; } + private MultiplayerClient client { get; set; } = null!; [Resolved] - private OngoingOperationTracker ongoingOperationTracker { get; set; } + private OngoingOperationTracker ongoingOperationTracker { get; set; } = null!; private readonly IBindable operationInProgress = new BindableBool(); - - [CanBeNull] - private IDisposable applyingSettingsOperation; - private readonly Room room; - private Drawable playlistContainer; - private DrawableRoomPlaylist drawablePlaylist; + private IDisposable? applyingSettingsOperation; + private Drawable playlistContainer = null!; + private DrawableRoomPlaylist drawablePlaylist = null!; public MatchSettings(Room room) { @@ -423,7 +423,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match else room.MaxParticipants.Value = null; - manager?.CreateRoom(room, onSuccess, onError); + manager.CreateRoom(room, onSuccess, onError); } } @@ -466,7 +466,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match public class CreateOrUpdateButton : TriangleButton { [Resolved(typeof(Room), nameof(Room.RoomID))] - private Bindable roomId { get; set; } + private Bindable roomId { get; set; } = null!; protected override void LoadComplete() { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs index 73765fc661..e3f7b5dfc4 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.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. -#nullable disable - using System.Linq; using osu.Framework.Screens; using osu.Game.Online.API; From 770c1ade2fee41abc436f38dc24685c5c8560a25 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 20:00:24 +0900 Subject: [PATCH 0934/2686] Add test coverage of track rate adjusting during multi spectator --- .../TestSceneMultiSpectatorScreen.cs | 21 ++++++++++++++++--- .../Multiplayer/TestMultiplayerClient.cs | 7 ++++--- .../Visual/Spectator/TestSpectatorClient.cs | 8 ++++++- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index a11a67aebd..70f498e7f2 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -13,9 +13,11 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.UI; using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate; using osu.Game.Screens.Play; @@ -332,6 +334,18 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("player 2 playing from correct point in time", () => getPlayer(PLAYER_2_ID).ChildrenOfType().Single().FrameStableClock.CurrentTime > 30000); } + [Test] + public void TestGameplayRateAdjust() + { + start(getPlayerIds(4), mods: new[] { new APIMod(new OsuModDoubleTime()) }); + + loadSpectateScreen(); + + sendFrames(getPlayerIds(4), 300); + + AddUntilStep("wait for correct track speed", () => Beatmap.Value.Track.Rate, () => Is.EqualTo(1.5)); + } + [Test] public void TestPlayersLeaveWhileSpectating() { @@ -420,7 +434,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void start(int userId, int? beatmapId = null) => start(new[] { userId }, beatmapId); - private void start(int[] userIds, int? beatmapId = null) + private void start(int[] userIds, int? beatmapId = null, APIMod[]? mods = null) { AddStep("start play", () => { @@ -429,10 +443,11 @@ namespace osu.Game.Tests.Visual.Multiplayer var user = new MultiplayerRoomUser(id) { User = new APIUser { Id = id }, + Mods = mods ?? Array.Empty(), }; - OnlinePlayDependencies.MultiplayerClient.AddUser(user.User, true); - SpectatorClient.SendStartPlay(id, beatmapId ?? importedBeatmapId); + OnlinePlayDependencies.MultiplayerClient.AddUser(user, true); + SpectatorClient.SendStartPlay(id, beatmapId ?? importedBeatmapId, mods); playingUsers.Add(user); } diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 19b887eea5..84737bce3f 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -81,13 +81,14 @@ namespace osu.Game.Tests.Visual.Multiplayer public void Disconnect() => isConnected.Value = false; public MultiplayerRoomUser AddUser(APIUser user, bool markAsPlaying = false) - { - var roomUser = new MultiplayerRoomUser(user.Id) { User = user }; + => AddUser(new MultiplayerRoomUser(user.Id) { User = user }, markAsPlaying); + public MultiplayerRoomUser AddUser(MultiplayerRoomUser roomUser, bool markAsPlaying = false) + { addUser(roomUser); if (markAsPlaying) - PlayingUserIds.Add(user.Id); + PlayingUserIds.Add(roomUser.UserID); return roomUser; } diff --git a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs index 2531f3c485..cb3711ebb5 100644 --- a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs +++ b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs @@ -37,6 +37,7 @@ namespace osu.Game.Tests.Visual.Spectator private readonly Dictionary lastReceivedUserFrames = new Dictionary(); private readonly Dictionary userBeatmapDictionary = new Dictionary(); + private readonly Dictionary userModsDictionary = new Dictionary(); private readonly Dictionary userNextFrameDictionary = new Dictionary(); [Resolved] @@ -52,9 +53,11 @@ namespace osu.Game.Tests.Visual.Spectator /// /// The user to start play for. /// The playing beatmap id. - public void SendStartPlay(int userId, int beatmapId) + /// The mods the user has applied. + public void SendStartPlay(int userId, int beatmapId, APIMod[]? mods = null) { userBeatmapDictionary[userId] = beatmapId; + userModsDictionary[userId] = mods ?? Array.Empty(); userNextFrameDictionary[userId] = 0; sendPlayingState(userId); } @@ -73,10 +76,12 @@ namespace osu.Game.Tests.Visual.Spectator { BeatmapID = userBeatmapDictionary[userId], RulesetID = 0, + Mods = userModsDictionary[userId], State = state }); userBeatmapDictionary.Remove(userId); + userModsDictionary.Remove(userId); } /// @@ -158,6 +163,7 @@ namespace osu.Game.Tests.Visual.Spectator { BeatmapID = userBeatmapDictionary[userId], RulesetID = 0, + Mods = userModsDictionary[userId], State = SpectatedUserState.Playing }); } From 1997519364810b178ddda6b7a21b6110737c4c39 Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Wed, 7 Sep 2022 13:24:54 +0100 Subject: [PATCH 0935/2686] Don't use full hit window in rhythm --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index ca57c87af9..3bec2346ce 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double lastDelta = lastObj.StrainTime; double currRatio = 1.0 + 6.0 * Math.Min(0.5, Math.Pow(Math.Sin(Math.PI / (Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta))), 2)); // fancy function to calculate rhythmbonuses. - double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - currObj.HitWindowGreat * 0.6) / (currObj.HitWindowGreat * 0.6)); + double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - currObj.HitWindowGreat * 0.3) / (currObj.HitWindowGreat * 0.3)); windowPenalty = Math.Min(1, windowPenalty); From 208bd0f3914d77847fa49ed8815f67490d80b05c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 7 Sep 2022 20:01:17 +0900 Subject: [PATCH 0936/2686] Give OnlinePlaySongSelect a reference PlaylistItem --- .../TestSceneMultiplayerMatchSongSelect.cs | 4 +- .../Match/MultiplayerMatchSettingsOverlay.cs | 5 -- .../Multiplayer/MultiplayerMatchSongSelect.cs | 23 ++---- .../Multiplayer/MultiplayerMatchSubScreen.cs | 14 +--- .../OnlinePlay/OnlinePlaySongSelect.cs | 72 +++++++++++++------ 5 files changed, 58 insertions(+), 60 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs index 2281235f25..0ecfc059e4 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs @@ -152,8 +152,8 @@ namespace osu.Game.Tests.Visual.Multiplayer public new BeatmapCarousel Carousel => base.Carousel; - public TestMultiplayerMatchSongSelect(Room room, WorkingBeatmap beatmap = null, RulesetInfo ruleset = null) - : base(room, null, beatmap, ruleset) + public TestMultiplayerMatchSongSelect(Room room) + : base(room) { } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index c2dafda592..75bd6eb04d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -4,7 +4,6 @@ using System; using System.ComponentModel; using System.Diagnostics; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -13,7 +12,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; -using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -72,9 +70,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private OsuSpriteText typeLabel = null!; private LoadingLayer loadingLayer = null!; - [Resolved] - private BeatmapManager beatmapManager { get; set; } = null!; - public void SelectBeatmap() { if (matchSubScreen.IsCurrentScreen()) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index dbd679104e..3fe236bd7a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -8,11 +8,9 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Framework.Screens; -using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; -using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; @@ -27,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private OngoingOperationTracker operationTracker { get; set; } = null!; private readonly IBindable operationInProgress = new Bindable(); - private readonly long? itemToEdit; + private readonly PlaylistItem? itemToEdit; private LoadingLayer loadingLayer = null!; private IDisposable? selectionOperation; @@ -37,21 +35,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer /// /// The room. /// The item to be edited. May be null, in which case a new item will be added to the playlist. - /// An optional initial beatmap selection to perform. - /// An optional initial ruleset selection to perform. - public MultiplayerMatchSongSelect(Room room, long? itemToEdit = null, WorkingBeatmap? beatmap = null, RulesetInfo? ruleset = null) - : base(room) + public MultiplayerMatchSongSelect(Room room, PlaylistItem? itemToEdit = null) + : base(room, itemToEdit) { this.itemToEdit = itemToEdit; - - if (beatmap != null || ruleset != null) - { - Schedule(() => - { - if (beatmap != null) Beatmap.Value = beatmap; - if (ruleset != null) Ruleset.Value = ruleset; - }); - } } [BackgroundDependencyLoader] @@ -80,7 +67,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { if (operationInProgress.Value) { - Logger.Log($"{nameof(SelectedItem)} aborted due to {nameof(operationInProgress)}"); + Logger.Log($"{nameof(SelectItem)} aborted due to {nameof(operationInProgress)}"); return false; } @@ -92,7 +79,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer var multiplayerItem = new MultiplayerPlaylistItem { - ID = itemToEdit ?? 0, + ID = itemToEdit?.ID ?? 0, BeatmapID = item.Beatmap.OnlineID, BeatmapChecksum = item.Beatmap.MD5Hash, RulesetID = item.RulesetID, diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index ceadfa1527..db752f2b42 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -49,11 +49,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private MultiplayerClient client { get; set; } - [Resolved] - private BeatmapManager beatmapManager { get; set; } - - private readonly IBindable isConnected = new Bindable(); - private AddItemButton addItemButton; public MultiplayerMatchSubScreen(Room room) @@ -227,12 +222,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer if (!this.IsCurrentScreen()) return; - int id = itemToEdit?.Beatmap.OnlineID ?? Room.Playlist.Last().Beatmap.OnlineID; - var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineID == id); - - var workingBeatmap = localBeatmap == null ? null : beatmapManager.GetWorkingBeatmap(localBeatmap); - - this.Push(new MultiplayerMatchSongSelect(Room, itemToEdit?.ID, workingBeatmap)); + this.Push(new MultiplayerMatchSongSelect(Room, itemToEdit)); } protected override Drawable CreateFooter() => new MultiplayerMatchFooter(); @@ -424,7 +414,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer return; } - this.Push(new MultiplayerMatchSongSelect(Room, client.Room.Settings.PlaylistItemId, beatmap, ruleset)); + this.Push(new MultiplayerMatchSongSelect(Room, Room.Playlist.Single(item => item.ID == client.Room.Settings.PlaylistItemId))); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index f26480909e..e841d9c41e 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -1,13 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Humanizer; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -35,32 +33,39 @@ namespace osu.Game.Screens.OnlinePlay public override bool AllowEditing => false; [Resolved(typeof(Room), nameof(Room.Playlist))] - protected BindableList Playlist { get; private set; } - - [CanBeNull] - [Resolved(CanBeNull = true)] - protected IBindable SelectedItem { get; private set; } + protected BindableList Playlist { get; private set; } = null!; [Resolved] - private RulesetStore rulesets { get; set; } + private RulesetStore rulesets { get; set; } = null!; + + [Resolved] + private BeatmapManager beatmapManager { get; set; } = null!; protected override UserActivity InitialActivity => new UserActivity.InLobby(room); protected readonly Bindable> FreeMods = new Bindable>(Array.Empty()); private readonly Room room; + private readonly PlaylistItem? initialItem; + private readonly FreeModSelectOverlay freeModSelectOverlay; - private WorkingBeatmap initialBeatmap; - private RulesetInfo initialRuleset; - private IReadOnlyList initialMods; + private WorkingBeatmap initialBeatmap = null!; + private RulesetInfo initialRuleset = null!; + private IReadOnlyList initialMods = null!; private bool itemSelected; - private readonly FreeModSelectOverlay freeModSelectOverlay; - private IDisposable freeModSelectOverlayRegistration; + private IDisposable? freeModSelectOverlayRegistration; - protected OnlinePlaySongSelect(Room room) + /// + /// Creates a new . + /// + /// The room. + /// An optional initial to use for the initial beatmap/ruleset/mods. + /// If null, the last in the room will be used. + protected OnlinePlaySongSelect(Room room, PlaylistItem? initialItem = null) { this.room = room; + this.initialItem = initialItem ?? room.Playlist.LastOrDefault(); Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; @@ -76,6 +81,7 @@ namespace osu.Game.Screens.OnlinePlay { LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT }; + // Store the initial beatmap/ruleset/mods at the point of entering song select, so they can be reverted to upon exit. initialBeatmap = Beatmap.Value; initialRuleset = Ruleset.Value; initialMods = Mods.Value.ToList(); @@ -87,14 +93,35 @@ namespace osu.Game.Screens.OnlinePlay { base.LoadComplete(); - var rulesetInstance = SelectedItem?.Value?.RulesetID == null ? null : rulesets.GetRuleset(SelectedItem.Value.RulesetID)?.CreateInstance(); - - if (rulesetInstance != null) + if (initialItem != null) { - // At this point, Mods contains both the required and allowed mods. For selection purposes, it should only contain the required mods. - // Similarly, freeMods is currently empty but should only contain the allowed mods. - Mods.Value = SelectedItem.Value.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); - FreeMods.Value = SelectedItem.Value.AllowedMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); + // Prefer using a local databased beatmap lookup since OnlineId may be -1 for an invalid beatmap selection. + BeatmapInfo? beatmapInfo = initialItem.Beatmap as BeatmapInfo; + + // And in the case that this isn't a local databased beatmap, query by online ID. + if (beatmapInfo == null) + { + int onlineId = initialItem.Beatmap.OnlineID; + beatmapInfo = beatmapManager.QueryBeatmap(b => b.OnlineID == onlineId); + } + + if (beatmapInfo != null) + Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); + + RulesetInfo? ruleset = rulesets.GetRuleset(initialItem.RulesetID); + + if (ruleset != null) + { + Ruleset.Value = ruleset; + + var rulesetInstance = ruleset.CreateInstance(); + Debug.Assert(rulesetInstance != null); + + // At this point, Mods contains both the required and allowed mods. For selection purposes, it should only contain the required mods. + // Similarly, freeMods is currently empty but should only contain the allowed mods. + Mods.Value = initialItem.RequiredMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); + FreeMods.Value = initialItem.AllowedMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); + } } Mods.BindValueChanged(onModsChanged); @@ -199,7 +226,6 @@ namespace osu.Game.Screens.OnlinePlay protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - freeModSelectOverlayRegistration?.Dispose(); } } From fcea244537db30790f77c758cce7717d44ef7d11 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 7 Sep 2022 21:21:19 +0900 Subject: [PATCH 0937/2686] Remove initial selection from OnlinePlaySongSelect This stuff never really worked anyway - every case except with an already created multiplayer room was broken anyway. --- .../OnlinePlay/OnlinePlaySongSelect.cs | 27 +------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index e841d9c41e..ea20270c1e 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -49,11 +49,6 @@ namespace osu.Game.Screens.OnlinePlay private readonly PlaylistItem? initialItem; private readonly FreeModSelectOverlay freeModSelectOverlay; - private WorkingBeatmap initialBeatmap = null!; - private RulesetInfo initialRuleset = null!; - private IReadOnlyList initialMods = null!; - private bool itemSelected; - private IDisposable? freeModSelectOverlayRegistration; /// @@ -80,12 +75,6 @@ namespace osu.Game.Screens.OnlinePlay private void load() { LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT }; - - // Store the initial beatmap/ruleset/mods at the point of entering song select, so they can be reverted to upon exit. - initialBeatmap = Beatmap.Value; - initialRuleset = Ruleset.Value; - initialMods = Mods.Value.ToList(); - LoadComponent(freeModSelectOverlay); } @@ -152,13 +141,7 @@ namespace osu.Game.Screens.OnlinePlay AllowedMods = FreeMods.Value.Select(m => new APIMod(m)).ToArray() }; - if (SelectItem(item)) - { - itemSelected = true; - return true; - } - - return false; + return SelectItem(item); } /// @@ -181,15 +164,7 @@ namespace osu.Game.Screens.OnlinePlay public override bool OnExiting(ScreenExitEvent e) { - if (!itemSelected) - { - Beatmap.Value = initialBeatmap; - Ruleset.Value = initialRuleset; - Mods.Value = initialMods; - } - freeModSelectOverlay.Hide(); - return base.OnExiting(e); } From 83c0cb1acce2fe9e6c27080651e82b413add1c5e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 7 Sep 2022 21:22:26 +0900 Subject: [PATCH 0938/2686] Fix beatmap set to null after exiting song select --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 03216180fb..00c819e5e4 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -433,6 +433,9 @@ namespace osu.Game.Screens.OnlinePlay.Match private void updateWorkingBeatmap() { + if (SelectedItem.Value == null || !this.IsCurrentScreen()) + return; + var beatmap = SelectedItem.Value?.Beatmap; // Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info From b560b6f7454983bf2275a76974a6c4c38e828ba9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Wed, 7 Sep 2022 23:29:10 +0900 Subject: [PATCH 0939/2686] refactor(osu.Game): arrange the code for the timing distribution graph --- .../HitEventTimingDistributionGraph.cs | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 37765fe962..ad2f979138 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -47,9 +47,6 @@ namespace osu.Game.Screens.Ranking.Statistics /// private readonly IReadOnlyList hitEvents; - [Resolved] - private OsuColour colours { get; set; } - /// /// Creates a new . /// @@ -129,13 +126,7 @@ namespace osu.Game.Screens.Ranking.Statistics else { int maxCount = bins.Max(b => b.Values.Sum()); - barDrawables = new Bar[total_timing_distribution_bins]; - - for (int i = 0; i < barDrawables.Length; i++) - { - IReadOnlyList values = bins[i].Select(b => new BarValue(b.Key.OrderingIndex(), b.Value, colours.DrawForHitResult(b.Key))).OrderBy(b => b.Index).ToList(); - barDrawables[i] = new Bar(values, maxCount, i == timing_distribution_centre_bin_index); - } + barDrawables = bins.Select((bin, i) => new Bar(bins[i], maxCount, i == timing_distribution_centre_bin_index)).ToArray(); Container axisFlow; @@ -216,53 +207,53 @@ namespace osu.Game.Screens.Ranking.Statistics } } - private readonly struct BarValue - { - public readonly int Index; - public readonly float Value; - public readonly Color4 Colour; - - public BarValue(int index, float value, Color4 colour) - { - Index = index; - Value = value; - Colour = colour; - } - } - private class Bar : CompositeDrawable { private float totalValue => values.Sum(v => v.Value); private float basalHeight => BoundingBox.Width / BoundingBox.Height; private float availableHeight => 1 - basalHeight; - private readonly IReadOnlyList values; + private readonly IReadOnlyList> values; private readonly float maxValue; + private readonly bool isCentre; - private readonly Circle[] boxOriginals; + private Circle[] boxOriginals; private Circle boxAdjustment; - public Bar(IReadOnlyList values, float maxValue, bool isCentre) + [Resolved] + private OsuColour colours { get; set; } + + public Bar(IDictionary values, float maxValue, bool isCentre) { - this.values = values; + this.values = values.OrderBy(v => v.Key.OrderingIndex()).ToList(); this.maxValue = maxValue; + this.isCentre = isCentre; RelativeSizeAxes = Axes.Both; Masking = true; + } + [BackgroundDependencyLoader] + private void load() + { if (values.Any()) { - InternalChildren = boxOriginals = values.Select((v, i) => new Circle + boxOriginals = values.Select((v, i) => new Circle { RelativeSizeAxes = Axes.Both, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - Colour = isCentre && i == 0 ? Color4.White : v.Colour, + Colour = isCentre && i == 0 ? Color4.White : colours.DrawForHitResult(v.Key), Height = 0, }).ToArray(); + // The bars of the stacked bar graph will be processed (stacked) from the bottom, which is the base position, + // to the top, and the bottom bar should be drawn more toward the front by design, + // while the drawing order is from the back to the front, so the order passed to `InternalChildren` is the opposite. + InternalChildren = boxOriginals.Reverse().ToArray(); } else { + // A bin with no value draws a grey dot instead. InternalChildren = boxOriginals = new[] { new Circle From 54f0bb797e46bb581017482876bea3ca4aec83a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Wed, 7 Sep 2022 23:32:45 +0900 Subject: [PATCH 0940/2686] refactor(osu.Game): remove nullable optouts in HitResult.cs --- osu.Game/Rulesets/Scoring/HitResult.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/HitResult.cs b/osu.Game/Rulesets/Scoring/HitResult.cs index 8078363212..3349bcf245 100644 --- a/osu.Game/Rulesets/Scoring/HitResult.cs +++ b/osu.Game/Rulesets/Scoring/HitResult.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. -#nullable disable - using System; using System.Collections.Generic; using System.ComponentModel; From 267465df182b67e783d13b015c646c4d501ad7b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Wed, 7 Sep 2022 23:34:46 +0900 Subject: [PATCH 0941/2686] chore(osu.Game): combine `Osu.Colour.{Draw,Text}ForHitResult` into `OsuColour.ForHitResult` --- osu.Game/Graphics/OsuColour.cs | 25 +------------------ .../Leaderboards/LeaderboardScoreTooltip.cs | 2 +- .../Judgements/DefaultJudgementPiece.cs | 2 +- .../Play/HUD/HitErrorMeters/HitErrorMeter.cs | 2 +- .../Expanded/Statistics/HitResultStatistic.cs | 2 +- .../HitEventTimingDistributionGraph.cs | 2 +- 6 files changed, 6 insertions(+), 29 deletions(-) diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index 022b1a363f..91161d5c71 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -102,30 +102,7 @@ namespace osu.Game.Graphics /// /// Retrieves the colour for a . /// - public Color4 TextForHitResult(HitResult judgement) - { - switch (judgement) - { - case HitResult.Perfect: - case HitResult.Great: - return Blue; - - case HitResult.Ok: - case HitResult.Good: - return Green; - - case HitResult.Meh: - return Yellow; - - case HitResult.Miss: - return Red; - - default: - return Color4.White; - } - } - - public Color4 DrawForHitResult(HitResult result) + public Color4 ForHitResult(HitResult result) { switch (result) { diff --git a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs index 23d4e64191..2f3ece0e3b 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs @@ -156,7 +156,7 @@ namespace osu.Game.Online.Leaderboards { Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), Text = displayName.ToUpper(), - Colour = colours.TextForHitResult(result), + Colour = colours.ForHitResult(result), }, new OsuSpriteText { diff --git a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs index a854bf37f5..c2b27d4ce8 100644 --- a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs +++ b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Judgements Anchor = Anchor.Centre, Origin = Anchor.Centre, Text = Result.GetDescription().ToUpperInvariant(), - Colour = colours.TextForHitResult(Result), + Colour = colours.ForHitResult(Result), Font = OsuFont.Numeric.With(size: 20), Scale = new Vector2(0.85f, 1), } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index 35d28b8e98..dda17c25e6 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters protected Color4 GetColourForHitResult(HitResult result) { - return colours.DrawForHitResult(result); + return colours.ForHitResult(result); } /// diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs index 429b72c07c..c23a5e668d 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics [BackgroundDependencyLoader] private void load(OsuColour colours) { - HeaderText.Colour = colours.TextForHitResult(Result); + HeaderText.Colour = colours.ForHitResult(Result); } } } diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index ad2f979138..52682c35a0 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -243,7 +243,7 @@ namespace osu.Game.Screens.Ranking.Statistics RelativeSizeAxes = Axes.Both, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - Colour = isCentre && i == 0 ? Color4.White : colours.DrawForHitResult(v.Key), + Colour = isCentre && i == 0 ? Color4.White : colours.ForHitResult(v.Key), Height = 0, }).ToArray(); // The bars of the stacked bar graph will be processed (stacked) from the bottom, which is the base position, From 68ea5a765f25f8d6a0df05d95076d9ff21ee8598 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Sep 2022 23:56:45 +0900 Subject: [PATCH 0942/2686] 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 219912425f..cd4dfec3d7 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 43e3076f5c..6d0827a107 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 0f0bf2848c..3316bf5a49 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From 50923b6e5b5722f59e4bbaaa8ef3f218117bd414 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 8 Sep 2022 00:25:55 +0300 Subject: [PATCH 0943/2686] Move track assignment below --- osu.Game/Screens/Play/MasterGameplayClockContainer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 26fb127e83..20a5c95605 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -68,10 +68,11 @@ namespace osu.Game.Screens.Play public MasterGameplayClockContainer(WorkingBeatmap beatmap, double skipTargetTime) : base(beatmap.Track, true) { - track = beatmap.Track; this.beatmap = beatmap; this.skipTargetTime = skipTargetTime; + track = beatmap.Track; + StartTime = findEarliestStartTime(); } From 5a1b2f9a77b62f0ef01e010bfef942ff68385b9f Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Thu, 8 Sep 2022 00:05:48 +0200 Subject: [PATCH 0944/2686] Freeze frame testing --- osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs | 85 ++++++++++++++--------- osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 +- 2 files changed, 56 insertions(+), 32 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs index e291e92901..b50de12465 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs @@ -1,61 +1,84 @@ -// 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.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.UI; +using osuTK; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModFlash : ModWithVisibilityAdjustment, IApplicableAfterBeatmapConversion + public class OsuModFlash : ModWithVisibilityAdjustment, IHidesApproachCircles, IApplicableToDrawableRuleset { - public override string Name => "Var AR Test"; - public override string Acronym => "TP"; + public override string Name => "Freeze frame"; + + public override string Acronym => "FF"; + + public override double ScoreMultiplier => 1; + + public override string Description => "Burn the notes into your memory"; + public override ModType Type => ModType.Fun; - public override IconUsage? Icon => FontAwesome.Regular.Sun; - public override string Description => @"how far will your reading stretch"; - public override double ScoreMultiplier => 1.03; + + public override IconUsage? Icon => FontAwesome.Solid.Fire; + + public override Type[] IncompatibleMods => new[] { typeof(OsuModTarget), typeof(OsuModStrictTracking) }; + + [SettingSource("Beat divisor")] + public BindableFloat BeatDivisor { get; } = new BindableFloat(2) + { + MinValue = .25f, + MaxValue = 2, + Precision = .25F + }; public override void ApplyToBeatmap(IBeatmap beatmap) { base.ApplyToBeatmap(beatmap); - double lastObjectEnd = beatmap.HitObjects.LastOrDefault()?.GetEndTime() ?? 0; - foreach (var obj in beatmap.HitObjects.OfType()) - applyVariableAr(obj); - - void applyVariableAr(OsuHitObject osuObject) + foreach (var hitObject in beatmap.HitObjects.OfType()) { - double percentageofmap = osuObject.StartTime / lastObjectEnd; - osuObject.TimePreempt = (percentageofmap * osuObject.TimePreempt) * ARadded.Value + osuObject.TimePreempt; - foreach (var nested in osuObject.NestedHitObjects.OfType()) - applyVariableAr(nested); + hitObject.TimeFadeIn = hitObject.TimePreempt; + var point = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime); + hitObject.TimePreempt += hitObject.StartTime % (point.BeatLength / BeatDivisor.Value); } } + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) + { + (drawableRuleset.Playfield as OsuPlayfield)?.FollowPoints.Hide(); + } + protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) { } - protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) + protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyFrozenState(hitObject, state); + + private void applyFrozenState(DrawableHitObject drawable, ArmedState state) { + if (drawable is DrawableSpinner) + return; + + var h = (OsuHitObject)drawable.HitObject; + + switch (drawable) + { + case DrawableHitCircle circle: + using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt)) + { + circle.ApproachCircle.Hide(); + } + + break; + } } - - [SettingSource("Additional AR", "how much AR change to add")] - public BindableDouble ARadded { get; } = new BindableDouble(1) - { - Precision = 0.1f, - MinValue = 0, - MaxValue = 10, - }; - - /*[SettingSource("Additional Ar", "how much ar change to add")] - public BindableBool scaledown { get; } = new BindableBool();*/ } } + diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 302194e91a..466b770399 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -198,7 +198,8 @@ namespace osu.Game.Rulesets.Osu new OsuModMuted(), new OsuModNoScope(), new MultiMod(new OsuModMagnetised(), new OsuModRepel()), - new ModAdaptiveSpeed() + new ModAdaptiveSpeed(), + new OsuModFlash() }; case ModType.System: From 7f08de522d68efd5d79e7b08d1d64e1ed81454f3 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Thu, 8 Sep 2022 01:21:03 +0200 Subject: [PATCH 0945/2686] Fixed --- osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs | 25 +++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs index b50de12465..e1ce43d875 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; @@ -10,7 +11,6 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; -using osuTK; namespace osu.Game.Rulesets.Osu.Mods { @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; - public override string Description => "Burn the notes into your memory"; + public override LocalisableString Description => "Burn the notes into your memory"; public override ModType Type => ModType.Fun; @@ -31,22 +31,29 @@ namespace osu.Game.Rulesets.Osu.Mods public override Type[] IncompatibleMods => new[] { typeof(OsuModTarget), typeof(OsuModStrictTracking) }; [SettingSource("Beat divisor")] - public BindableFloat BeatDivisor { get; } = new BindableFloat(2) + public BindableFloat BeatDivisor { get; } = new BindableFloat(1) { MinValue = .25f, - MaxValue = 2, - Precision = .25F + MaxValue = 5, + Precision = .25f }; public override void ApplyToBeatmap(IBeatmap beatmap) { base.ApplyToBeatmap(beatmap); - foreach (var hitObject in beatmap.HitObjects.OfType()) + foreach (var obj in beatmap.HitObjects.OfType()) { - hitObject.TimeFadeIn = hitObject.TimePreempt; - var point = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime); - hitObject.TimePreempt += hitObject.StartTime % (point.BeatLength / BeatDivisor.Value); + applyFadeInAdjustment(obj); + var point = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime); + obj.TimePreempt += obj.StartTime % (point.BeatLength * BeatDivisor.Value); + } + + static void applyFadeInAdjustment(OsuHitObject osuObject) + { + osuObject.TimeFadeIn = osuObject.TimePreempt; + foreach (var nested in osuObject.NestedHitObjects.OfType()) + applyFadeInAdjustment(nested); } } From 3b116a1a474c786eb7beba91317dc43f31a9b93d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 13:17:27 +0900 Subject: [PATCH 0946/2686] Fix mods not being set on `BeginPlayingInternal` --- osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs index cb3711ebb5..e6d8e473bb 100644 --- a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs +++ b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -130,6 +131,7 @@ namespace osu.Game.Tests.Visual.Spectator // Track the local user's playing beatmap ID. Debug.Assert(state.BeatmapID != null); userBeatmapDictionary[api.LocalUser.Value.Id] = state.BeatmapID.Value; + userModsDictionary[api.LocalUser.Value.Id] = state.Mods.ToArray(); return ((ISpectatorClient)this).UserBeganPlaying(api.LocalUser.Value.Id, state); } From 6aac0bd4e96e9da903c22a86162b596108847335 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 13:43:37 +0900 Subject: [PATCH 0947/2686] Update test to account for the fact that SSDQ is not zero anymore --- .../Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs index 34723e3329..5c9e9043a7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs @@ -78,8 +78,9 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("allow skin lookup", () => storyboard.UseSkinSprites = true); AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); + AddAssert("sprites present", () => sprites.All(s => s.IsPresent)); AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(0, 1))); - AddAssert("zero width", () => sprites.All(s => s.ScreenSpaceDrawQuad.Width == 0)); + AddAssert("sprites not present", () => sprites.All(s => s.IsPresent)); } [Test] From 3d9bf25c8afde4a8225035175f1ac4109955d757 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 14:49:43 +0900 Subject: [PATCH 0948/2686] Apply NRT to `TestScenePlaySongSelect` Very mess. --- .../SongSelect/TestScenePlaySongSelect.cs | 309 ++++++++++-------- 1 file changed, 172 insertions(+), 137 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 5db46e3097..cc8746959b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.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. -#nullable disable - using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using NUnit.Framework; @@ -13,6 +12,7 @@ using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Containers; using osu.Framework.Platform; using osu.Framework.Screens; @@ -46,11 +46,12 @@ namespace osu.Game.Tests.Visual.SongSelect [TestFixture] public class TestScenePlaySongSelect : ScreenTestScene { - private BeatmapManager manager; - private RulesetStore rulesets; - private MusicController music; - private WorkingBeatmap defaultBeatmap; - private TestSongSelect songSelect; + private BeatmapManager manager = null!; + private RulesetStore rulesets = null!; + private MusicController music = null!; + private WorkingBeatmap defaultBeatmap = null!; + private OsuConfigManager config = null!; + private TestSongSelect? songSelect; [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) @@ -69,8 +70,6 @@ namespace osu.Game.Tests.Visual.SongSelect Dependencies.Cache(config = new OsuConfigManager(LocalStorage)); } - private OsuConfigManager config; - public override void SetUpSteps() { base.SetUpSteps(); @@ -85,7 +84,7 @@ namespace osu.Game.Tests.Visual.SongSelect songSelect = null; }); - AddStep("delete all beatmaps", () => manager?.Delete()); + AddStep("delete all beatmaps", () => manager.Delete()); } [Test] @@ -98,7 +97,7 @@ namespace osu.Game.Tests.Visual.SongSelect addRulesetImportStep(0); AddUntilStep("wait for placeholder hidden", () => getPlaceholder()?.State.Value == Visibility.Hidden); - AddStep("delete all beatmaps", () => manager?.Delete()); + AddStep("delete all beatmaps", () => manager.Delete()); AddUntilStep("wait for placeholder visible", () => getPlaceholder()?.State.Value == Visibility.Visible); } @@ -144,7 +143,7 @@ namespace osu.Game.Tests.Visual.SongSelect createSongSelect(); - AddAssert("filter count is 1", () => songSelect.FilterCount == 1); + AddAssert("filter count is 1", () => songSelect?.FilterCount == 1); } [Test] @@ -156,7 +155,7 @@ namespace osu.Game.Tests.Visual.SongSelect waitForInitialSelection(); - WorkingBeatmap selected = null; + WorkingBeatmap? selected = null; AddStep("store selected beatmap", () => selected = Beatmap.Value); @@ -166,7 +165,7 @@ namespace osu.Game.Tests.Visual.SongSelect InputManager.Key(Key.Enter); }); - AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen()); + AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen()); AddAssert("ensure selection changed", () => selected != Beatmap.Value); } @@ -179,7 +178,7 @@ namespace osu.Game.Tests.Visual.SongSelect waitForInitialSelection(); - WorkingBeatmap selected = null; + WorkingBeatmap? selected = null; AddStep("store selected beatmap", () => selected = Beatmap.Value); @@ -189,7 +188,7 @@ namespace osu.Game.Tests.Visual.SongSelect InputManager.Key(Key.Down); }); - AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen()); + AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen()); AddAssert("ensure selection didn't change", () => selected == Beatmap.Value); } @@ -202,23 +201,23 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault); - WorkingBeatmap selected = null; + WorkingBeatmap? selected = null; AddStep("store selected beatmap", () => selected = Beatmap.Value); - AddUntilStep("wait for beatmaps to load", () => songSelect.Carousel.ChildrenOfType().Any()); + AddUntilStep("wait for beatmaps to load", () => songSelect!.Carousel.ChildrenOfType().Any()); AddStep("select next and enter", () => { - InputManager.MoveMouseTo(songSelect.Carousel.ChildrenOfType() - .First(b => !((CarouselBeatmap)b.Item).BeatmapInfo.Equals(songSelect.Carousel.SelectedBeatmapInfo))); + InputManager.MoveMouseTo(songSelect!.Carousel.ChildrenOfType() + .First(b => !((CarouselBeatmap)b.Item).BeatmapInfo.Equals(songSelect!.Carousel.SelectedBeatmapInfo))); InputManager.Click(MouseButton.Left); InputManager.Key(Key.Enter); }); - AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen()); + AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen()); AddAssert("ensure selection changed", () => selected != Beatmap.Value); } @@ -231,14 +230,14 @@ namespace osu.Game.Tests.Visual.SongSelect waitForInitialSelection(); - WorkingBeatmap selected = null; + WorkingBeatmap? selected = null; AddStep("store selected beatmap", () => selected = Beatmap.Value); AddStep("select next and enter", () => { - InputManager.MoveMouseTo(songSelect.Carousel.ChildrenOfType() - .First(b => !((CarouselBeatmap)b.Item).BeatmapInfo.Equals(songSelect.Carousel.SelectedBeatmapInfo))); + InputManager.MoveMouseTo(songSelect!.Carousel.ChildrenOfType() + .First(b => !((CarouselBeatmap)b.Item).BeatmapInfo.Equals(songSelect!.Carousel.SelectedBeatmapInfo))); InputManager.PressButton(MouseButton.Left); @@ -247,7 +246,7 @@ namespace osu.Game.Tests.Visual.SongSelect InputManager.ReleaseButton(MouseButton.Left); }); - AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen()); + AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen()); AddAssert("ensure selection didn't change", () => selected == Beatmap.Value); } @@ -260,11 +259,11 @@ namespace osu.Game.Tests.Visual.SongSelect createSongSelect(); AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child"))); - AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen()); + AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen()); - AddStep("return", () => songSelect.MakeCurrent()); - AddUntilStep("wait for current", () => songSelect.IsCurrentScreen()); - AddAssert("filter count is 1", () => songSelect.FilterCount == 1); + AddStep("return", () => songSelect!.MakeCurrent()); + AddUntilStep("wait for current", () => songSelect!.IsCurrentScreen()); + AddAssert("filter count is 1", () => songSelect!.FilterCount == 1); } [Test] @@ -278,13 +277,13 @@ namespace osu.Game.Tests.Visual.SongSelect createSongSelect(); AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child"))); - AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen()); + AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen()); AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true)); - AddStep("return", () => songSelect.MakeCurrent()); - AddUntilStep("wait for current", () => songSelect.IsCurrentScreen()); - AddAssert("filter count is 2", () => songSelect.FilterCount == 2); + AddStep("return", () => songSelect!.MakeCurrent()); + AddUntilStep("wait for current", () => songSelect!.IsCurrentScreen()); + AddAssert("filter count is 2", () => songSelect!.FilterCount == 2); } [Test] @@ -295,7 +294,7 @@ namespace osu.Game.Tests.Visual.SongSelect createSongSelect(); AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child"))); - AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen()); + AddUntilStep("wait for not current", () => !songSelect!.IsCurrentScreen()); AddStep("update beatmap", () => { @@ -304,9 +303,9 @@ namespace osu.Game.Tests.Visual.SongSelect Beatmap.Value = manager.GetWorkingBeatmap(anotherBeatmap); }); - AddStep("return", () => songSelect.MakeCurrent()); - AddUntilStep("wait for current", () => songSelect.IsCurrentScreen()); - AddAssert("carousel updated", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(Beatmap.Value.BeatmapInfo)); + AddStep("return", () => songSelect!.MakeCurrent()); + AddUntilStep("wait for current", () => songSelect!.IsCurrentScreen()); + AddAssert("carousel updated", () => songSelect!.Carousel.SelectedBeatmapInfo?.Equals(Beatmap.Value.BeatmapInfo) == true); } [Test] @@ -318,15 +317,15 @@ namespace osu.Game.Tests.Visual.SongSelect addRulesetImportStep(0); checkMusicPlaying(true); - AddStep("select first", () => songSelect.Carousel.SelectBeatmap(songSelect.Carousel.BeatmapSets.First().Beatmaps.First())); + AddStep("select first", () => songSelect!.Carousel.SelectBeatmap(songSelect!.Carousel.BeatmapSets.First().Beatmaps.First())); checkMusicPlaying(true); AddStep("manual pause", () => music.TogglePause()); checkMusicPlaying(false); - AddStep("select next difficulty", () => songSelect.Carousel.SelectNext(skipDifficulties: false)); + AddStep("select next difficulty", () => songSelect!.Carousel.SelectNext(skipDifficulties: false)); checkMusicPlaying(false); - AddStep("select next set", () => songSelect.Carousel.SelectNext()); + AddStep("select next set", () => songSelect!.Carousel.SelectNext()); checkMusicPlaying(true); } @@ -366,13 +365,13 @@ namespace osu.Game.Tests.Visual.SongSelect public void TestDummy() { createSongSelect(); - AddUntilStep("dummy selected", () => songSelect.CurrentBeatmap == defaultBeatmap); + AddUntilStep("dummy selected", () => songSelect!.CurrentBeatmap == defaultBeatmap); - AddUntilStep("dummy shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap == defaultBeatmap); + AddUntilStep("dummy shown on wedge", () => songSelect!.CurrentBeatmapDetailsBeatmap == defaultBeatmap); addManyTestMaps(); - AddUntilStep("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); + AddUntilStep("random map selected", () => songSelect!.CurrentBeatmap != defaultBeatmap); } [Test] @@ -381,7 +380,7 @@ namespace osu.Game.Tests.Visual.SongSelect createSongSelect(); addManyTestMaps(); - AddUntilStep("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap); + AddUntilStep("random map selected", () => songSelect!.CurrentBeatmap != defaultBeatmap); AddStep(@"Sort by Artist", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Artist)); AddStep(@"Sort by Title", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Title)); @@ -398,7 +397,7 @@ namespace osu.Game.Tests.Visual.SongSelect { createSongSelect(); addRulesetImportStep(2); - AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmapInfo == null); + AddUntilStep("no selection", () => songSelect!.Carousel.SelectedBeatmapInfo == null); } [Test] @@ -408,13 +407,13 @@ namespace osu.Game.Tests.Visual.SongSelect changeRuleset(2); addRulesetImportStep(2); addRulesetImportStep(1); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Ruleset.OnlineID == 2); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo?.Ruleset.OnlineID == 2); changeRuleset(1); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Ruleset.OnlineID == 1); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo?.Ruleset.OnlineID == 1); changeRuleset(0); - AddUntilStep("no selection", () => songSelect.Carousel.SelectedBeatmapInfo == null); + AddUntilStep("no selection", () => songSelect!.Carousel.SelectedBeatmapInfo == null); } [Test] @@ -423,7 +422,7 @@ namespace osu.Game.Tests.Visual.SongSelect createSongSelect(); changeRuleset(0); - Live original = null!; + Live? original = null; int originalOnlineSetID = 0; AddStep(@"Sort by artist", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Artist)); @@ -431,12 +430,17 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("import original", () => { original = manager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).GetResultSafely(); - originalOnlineSetID = original!.Value.OnlineID; + + Debug.Assert(original != null); + + originalOnlineSetID = original.Value.OnlineID; }); // This will move the beatmap set to a different location in the carousel. AddStep("Update original with bogus info", () => { + Debug.Assert(original != null); + original.PerformWrite(set => { foreach (var beatmap in set.Beatmaps) @@ -457,13 +461,19 @@ namespace osu.Game.Tests.Visual.SongSelect manager.Import(testBeatmapSetInfo); }, 10); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo?.BeatmapSet?.OnlineID == originalOnlineSetID); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo?.BeatmapSet?.OnlineID == originalOnlineSetID); - Task> updateTask = null!; - AddStep("update beatmap", () => updateTask = manager.ImportAsUpdate(new ProgressNotification(), new ImportTask(TestResources.GetQuickTestBeatmapForImport()), original.Value)); + Task?> updateTask = null!; + + AddStep("update beatmap", () => + { + Debug.Assert(original != null); + + updateTask = manager.ImportAsUpdate(new ProgressNotification(), new ImportTask(TestResources.GetQuickTestBeatmapForImport()), original.Value); + }); AddUntilStep("wait for update completion", () => updateTask.IsCompleted); - AddUntilStep("retained selection", () => songSelect.Carousel.SelectedBeatmapInfo?.BeatmapSet?.OnlineID == originalOnlineSetID); + AddUntilStep("retained selection", () => songSelect!.Carousel.SelectedBeatmapInfo?.BeatmapSet?.OnlineID == originalOnlineSetID); } [Test] @@ -473,13 +483,13 @@ namespace osu.Game.Tests.Visual.SongSelect changeRuleset(2); addRulesetImportStep(2); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Ruleset.OnlineID == 2); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo?.Ruleset.OnlineID == 2); addRulesetImportStep(0); addRulesetImportStep(0); addRulesetImportStep(0); - BeatmapInfo target = null; + BeatmapInfo? target = null; AddStep("select beatmap/ruleset externally", () => { @@ -490,10 +500,10 @@ namespace osu.Game.Tests.Visual.SongSelect Beatmap.Value = manager.GetWorkingBeatmap(target); }); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(target)); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo?.Equals(target) == true); // this is an important check, to make sure updateComponentFromBeatmap() was actually run - AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target)); + AddUntilStep("selection shown on wedge", () => songSelect!.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target)); } [Test] @@ -503,13 +513,13 @@ namespace osu.Game.Tests.Visual.SongSelect changeRuleset(2); addRulesetImportStep(2); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Ruleset.OnlineID == 2); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo?.Ruleset.OnlineID == 2); addRulesetImportStep(0); addRulesetImportStep(0); addRulesetImportStep(0); - BeatmapInfo target = null; + BeatmapInfo? target = null; AddStep("select beatmap/ruleset externally", () => { @@ -520,12 +530,12 @@ namespace osu.Game.Tests.Visual.SongSelect Ruleset.Value = rulesets.AvailableRulesets.First(r => r.OnlineID == 0); }); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(target)); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo?.Equals(target) == true); AddUntilStep("has correct ruleset", () => Ruleset.Value.OnlineID == 0); // this is an important check, to make sure updateComponentFromBeatmap() was actually run - AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target)); + AddUntilStep("selection shown on wedge", () => songSelect!.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target)); } [Test] @@ -543,12 +553,12 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("change ruleset", () => { SelectedMods.ValueChanged += onModChange; - songSelect.Ruleset.ValueChanged += onRulesetChange; + songSelect!.Ruleset.ValueChanged += onRulesetChange; Ruleset.Value = new TaikoRuleset().RulesetInfo; SelectedMods.ValueChanged -= onModChange; - songSelect.Ruleset.ValueChanged -= onRulesetChange; + songSelect!.Ruleset.ValueChanged -= onRulesetChange; }); AddAssert("mods changed before ruleset", () => modChangeIndex < rulesetChangeIndex); @@ -579,18 +589,18 @@ namespace osu.Game.Tests.Visual.SongSelect { createSongSelect(); addManyTestMaps(); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo != null); bool startRequested = false; AddStep("set filter and finalize", () => { - songSelect.StartRequested = () => startRequested = true; + songSelect!.StartRequested = () => startRequested = true; - songSelect.Carousel.Filter(new FilterCriteria { SearchText = "somestringthatshouldn'tbematchable" }); - songSelect.FinaliseSelection(); + songSelect!.Carousel.Filter(new FilterCriteria { SearchText = "somestringthatshouldn'tbematchable" }); + songSelect!.FinaliseSelection(); - songSelect.StartRequested = null; + songSelect!.StartRequested = null; }); AddAssert("start not requested", () => !startRequested); @@ -610,15 +620,15 @@ namespace osu.Game.Tests.Visual.SongSelect // used for filter check below AddStep("allow convert display", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true)); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo != null); - AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = "nonono"); + AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType().First().Text = "nonono"); AddUntilStep("dummy selected", () => Beatmap.Value is DummyWorkingBeatmap); - AddUntilStep("has no selection", () => songSelect.Carousel.SelectedBeatmapInfo == null); + AddUntilStep("has no selection", () => songSelect!.Carousel.SelectedBeatmapInfo == null); - BeatmapInfo target = null; + BeatmapInfo? target = null; int targetRuleset = differentRuleset ? 1 : 0; @@ -632,24 +642,24 @@ namespace osu.Game.Tests.Visual.SongSelect Beatmap.Value = manager.GetWorkingBeatmap(target); }); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo != null); AddAssert("selected only shows expected ruleset (plus converts)", () => { - var selectedPanel = songSelect.Carousel.ChildrenOfType().First(s => s.Item.State.Value == CarouselItemState.Selected); + var selectedPanel = songSelect!.Carousel.ChildrenOfType().First(s => s.Item.State.Value == CarouselItemState.Selected); // special case for converts checked here. return selectedPanel.ChildrenOfType().All(i => i.IsFiltered || i.Item.BeatmapInfo.Ruleset.OnlineID == targetRuleset || i.Item.BeatmapInfo.Ruleset.OnlineID == 0); }); - AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true); + AddUntilStep("carousel has correct", () => songSelect!.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true); AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(target)); - AddStep("reset filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = string.Empty); + AddStep("reset filter text", () => songSelect!.FilterControl.ChildrenOfType().First().Text = string.Empty); AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.MatchesOnlineID(target) == true); - AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmapInfo.MatchesOnlineID(target)); + AddAssert("carousel still correct", () => songSelect!.Carousel.SelectedBeatmapInfo.MatchesOnlineID(target)); } [Test] @@ -662,15 +672,15 @@ namespace osu.Game.Tests.Visual.SongSelect changeRuleset(0); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo != null); - AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = "nonono"); + AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType().First().Text = "nonono"); AddUntilStep("dummy selected", () => Beatmap.Value is DummyWorkingBeatmap); - AddUntilStep("has no selection", () => songSelect.Carousel.SelectedBeatmapInfo == null); + AddUntilStep("has no selection", () => songSelect!.Carousel.SelectedBeatmapInfo == null); - BeatmapInfo target = null; + BeatmapInfo? target = null; AddStep("select beatmap externally", () => { @@ -682,15 +692,15 @@ namespace osu.Game.Tests.Visual.SongSelect Beatmap.Value = manager.GetWorkingBeatmap(target); }); - AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmapInfo != null); + AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo != null); - AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true); + AddUntilStep("carousel has correct", () => songSelect!.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true); AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(target)); - AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = "nononoo"); + AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType().First().Text = "nononoo"); AddUntilStep("game lost selection", () => Beatmap.Value is DummyWorkingBeatmap); - AddAssert("carousel lost selection", () => songSelect.Carousel.SelectedBeatmapInfo == null); + AddAssert("carousel lost selection", () => songSelect!.Carousel.SelectedBeatmapInfo == null); } [Test] @@ -711,11 +721,11 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("wait for player", () => Stack.CurrentScreen is PlayerLoader); - AddAssert("autoplay selected", () => songSelect.Mods.Value.Single() is ModAutoplay); + AddAssert("autoplay selected", () => songSelect!.Mods.Value.Single() is ModAutoplay); - AddUntilStep("wait for return to ss", () => songSelect.IsCurrentScreen()); + AddUntilStep("wait for return to ss", () => songSelect!.IsCurrentScreen()); - AddAssert("no mods selected", () => songSelect.Mods.Value.Count == 0); + AddAssert("no mods selected", () => songSelect!.Mods.Value.Count == 0); } [Test] @@ -738,11 +748,11 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("wait for player", () => Stack.CurrentScreen is PlayerLoader); - AddAssert("autoplay selected", () => songSelect.Mods.Value.Single() is ModAutoplay); + AddAssert("autoplay selected", () => songSelect!.Mods.Value.Single() is ModAutoplay); - AddUntilStep("wait for return to ss", () => songSelect.IsCurrentScreen()); + AddUntilStep("wait for return to ss", () => songSelect!.IsCurrentScreen()); - AddAssert("autoplay still selected", () => songSelect.Mods.Value.Single() is ModAutoplay); + AddAssert("autoplay still selected", () => songSelect!.Mods.Value.Single() is ModAutoplay); } [Test] @@ -765,11 +775,11 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("wait for player", () => Stack.CurrentScreen is PlayerLoader); - AddAssert("only autoplay selected", () => songSelect.Mods.Value.Single() is ModAutoplay); + AddAssert("only autoplay selected", () => songSelect!.Mods.Value.Single() is ModAutoplay); - AddUntilStep("wait for return to ss", () => songSelect.IsCurrentScreen()); + AddUntilStep("wait for return to ss", () => songSelect!.IsCurrentScreen()); - AddAssert("relax returned", () => songSelect.Mods.Value.Single() is ModRelax); + AddAssert("relax returned", () => songSelect!.Mods.Value.Single() is ModRelax); } [Test] @@ -778,10 +788,10 @@ namespace osu.Game.Tests.Visual.SongSelect Guid? previousID = null; createSongSelect(); addRulesetImportStep(0); - AddStep("Move to last difficulty", () => songSelect.Carousel.SelectBeatmap(songSelect.Carousel.BeatmapSets.First().Beatmaps.Last())); - AddStep("Store current ID", () => previousID = songSelect.Carousel.SelectedBeatmapInfo.ID); - AddStep("Hide first beatmap", () => manager.Hide(songSelect.Carousel.SelectedBeatmapSet.Beatmaps.First())); - AddAssert("Selected beatmap has not changed", () => songSelect.Carousel.SelectedBeatmapInfo.ID == previousID); + AddStep("Move to last difficulty", () => songSelect!.Carousel.SelectBeatmap(songSelect!.Carousel.BeatmapSets.First().Beatmaps.Last())); + AddStep("Store current ID", () => previousID = songSelect!.Carousel.SelectedBeatmapInfo!.ID); + AddStep("Hide first beatmap", () => manager.Hide(songSelect!.Carousel.SelectedBeatmapSet!.Beatmaps.First())); + AddAssert("Selected beatmap has not changed", () => songSelect!.Carousel.SelectedBeatmapInfo?.ID == previousID); } [Test] @@ -792,17 +802,24 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("wait for selection", () => !Beatmap.IsDefault); - DrawableCarouselBeatmapSet set = null; + DrawableCarouselBeatmapSet set = null!; AddStep("Find the DrawableCarouselBeatmapSet", () => { - set = songSelect.Carousel.ChildrenOfType().First(); + set = songSelect!.Carousel.ChildrenOfType().First(); }); - FilterableDifficultyIcon difficultyIcon = null; + FilterableDifficultyIcon difficultyIcon = null!; + AddUntilStep("Find an icon", () => { - return (difficultyIcon = set.ChildrenOfType() - .FirstOrDefault(icon => getDifficultyIconIndex(set, icon) != getCurrentBeatmapIndex())) != null; + var foundIcon = set.ChildrenOfType() + .FirstOrDefault(icon => getDifficultyIconIndex(set, icon) != getCurrentBeatmapIndex()); + + if (foundIcon == null) + return false; + + difficultyIcon = foundIcon; + return true; }); AddStep("Click on a difficulty", () => @@ -815,21 +832,24 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Selected beatmap correct", () => getCurrentBeatmapIndex() == getDifficultyIconIndex(set, difficultyIcon)); double? maxBPM = null; - AddStep("Filter some difficulties", () => songSelect.Carousel.Filter(new FilterCriteria + AddStep("Filter some difficulties", () => songSelect!.Carousel.Filter(new FilterCriteria { BPM = new FilterCriteria.OptionalRange { - Min = maxBPM = songSelect.Carousel.SelectedBeatmapSet.MaxBPM, + Min = maxBPM = songSelect!.Carousel.SelectedBeatmapSet!.MaxBPM, IsLowerInclusive = true } })); - BeatmapInfo filteredBeatmap = null; - FilterableDifficultyIcon filteredIcon = null; + BeatmapInfo? filteredBeatmap = null; + FilterableDifficultyIcon? filteredIcon = null; AddStep("Get filtered icon", () => { - var selectedSet = songSelect.Carousel.SelectedBeatmapSet; + var selectedSet = songSelect!.Carousel.SelectedBeatmapSet; + + Debug.Assert(selectedSet != null); + filteredBeatmap = selectedSet.Beatmaps.First(b => b.BPM < maxBPM); int filteredBeatmapIndex = getBeatmapIndex(selectedSet, filteredBeatmap); filteredIcon = set.ChildrenOfType().ElementAt(filteredBeatmapIndex); @@ -842,7 +862,7 @@ namespace osu.Game.Tests.Visual.SongSelect InputManager.Click(MouseButton.Left); }); - AddAssert("Selected beatmap correct", () => songSelect.Carousel.SelectedBeatmapInfo.Equals(filteredBeatmap)); + AddAssert("Selected beatmap correct", () => songSelect!.Carousel.SelectedBeatmapInfo?.Equals(filteredBeatmap) == true); } [Test] @@ -907,14 +927,14 @@ namespace osu.Game.Tests.Visual.SongSelect manager.Import(TestResources.CreateTestBeatmapSetInfo(3, usableRulesets)); }); - DrawableCarouselBeatmapSet set = null; + DrawableCarouselBeatmapSet? set = null; AddUntilStep("Find the DrawableCarouselBeatmapSet", () => { - set = songSelect.Carousel.ChildrenOfType().FirstOrDefault(); + set = songSelect!.Carousel.ChildrenOfType().FirstOrDefault(); return set != null; }); - FilterableDifficultyIcon difficultyIcon = null; + FilterableDifficultyIcon? difficultyIcon = null; AddUntilStep("Find an icon for different ruleset", () => { difficultyIcon = set.ChildrenOfType() @@ -937,7 +957,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.OnlineID == 3); - AddAssert("Selected beatmap still same set", () => songSelect.Carousel.SelectedBeatmapInfo.BeatmapSet?.OnlineID == previousSetID); + AddAssert("Selected beatmap still same set", () => songSelect!.Carousel.SelectedBeatmapInfo?.BeatmapSet?.OnlineID == previousSetID); AddAssert("Selected beatmap is mania", () => Beatmap.Value.BeatmapInfo.Ruleset.OnlineID == 3); } @@ -948,7 +968,7 @@ namespace osu.Game.Tests.Visual.SongSelect createSongSelect(); - BeatmapSetInfo imported = null; + BeatmapSetInfo? imported = null; AddStep("import huge difficulty count map", () => { @@ -956,20 +976,27 @@ namespace osu.Game.Tests.Visual.SongSelect imported = manager.Import(TestResources.CreateTestBeatmapSetInfo(50, usableRulesets))?.Value; }); - AddStep("select the first beatmap of import", () => Beatmap.Value = manager.GetWorkingBeatmap(imported.Beatmaps.First())); + AddStep("select the first beatmap of import", () => Beatmap.Value = manager.GetWorkingBeatmap(imported?.Beatmaps.First())); - DrawableCarouselBeatmapSet set = null; + DrawableCarouselBeatmapSet? set = null; AddUntilStep("Find the DrawableCarouselBeatmapSet", () => { - set = songSelect.Carousel.ChildrenOfType().FirstOrDefault(); + set = songSelect!.Carousel.ChildrenOfType().FirstOrDefault(); return set != null; }); - GroupedDifficultyIcon groupIcon = null; + GroupedDifficultyIcon groupIcon = null!; + AddUntilStep("Find group icon for different ruleset", () => { - return (groupIcon = set.ChildrenOfType() - .FirstOrDefault(icon => icon.Items.First().BeatmapInfo.Ruleset.OnlineID == 3)) != null; + var foundIcon = set.ChildrenOfType() + .FirstOrDefault(icon => icon.Items.First().BeatmapInfo.Ruleset.OnlineID == 3); + + if (foundIcon == null) + return false; + + groupIcon = foundIcon; + return true; }); AddAssert("Check ruleset is osu!", () => Ruleset.Value.OnlineID == 0); @@ -1004,7 +1031,7 @@ namespace osu.Game.Tests.Visual.SongSelect // this ruleset change should be overridden by the present. Ruleset.Value = getSwitchBeatmap().Ruleset; - songSelect.PresentScore(new ScoreInfo + songSelect!.PresentScore(new ScoreInfo { User = new APIUser { Username = "woo" }, BeatmapInfo = getPresentBeatmap(), @@ -1012,7 +1039,7 @@ namespace osu.Game.Tests.Visual.SongSelect }); }); - AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen()); + AddUntilStep("wait for results screen presented", () => !songSelect!.IsCurrentScreen()); AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap())); AddAssert("check ruleset is correct for score", () => Ruleset.Value.OnlineID == 0); @@ -1038,10 +1065,10 @@ namespace osu.Game.Tests.Visual.SongSelect // this beatmap change should be overridden by the present. Beatmap.Value = manager.GetWorkingBeatmap(getSwitchBeatmap()); - songSelect.PresentScore(TestResources.CreateTestScoreInfo(getPresentBeatmap())); + songSelect!.PresentScore(TestResources.CreateTestScoreInfo(getPresentBeatmap())); }); - AddUntilStep("wait for results screen presented", () => !songSelect.IsCurrentScreen()); + AddUntilStep("wait for results screen presented", () => !songSelect!.IsCurrentScreen()); AddAssert("check beatmap is correct for score", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(getPresentBeatmap())); AddAssert("check ruleset is correct for score", () => Ruleset.Value.OnlineID == 0); @@ -1054,23 +1081,29 @@ namespace osu.Game.Tests.Visual.SongSelect createSongSelect(); AddStep("toggle mod overlay on", () => InputManager.Key(Key.F1)); - AddUntilStep("mod overlay shown", () => songSelect.ModSelect.State.Value == Visibility.Visible); + AddUntilStep("mod overlay shown", () => songSelect!.ModSelect.State.Value == Visibility.Visible); AddStep("toggle mod overlay off", () => InputManager.Key(Key.F1)); - AddUntilStep("mod overlay hidden", () => songSelect.ModSelect.State.Value == Visibility.Hidden); + AddUntilStep("mod overlay hidden", () => songSelect!.ModSelect.State.Value == Visibility.Hidden); } private void waitForInitialSelection() { AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault); - AddUntilStep("wait for difficulty panels visible", () => songSelect.Carousel.ChildrenOfType().Any()); + AddUntilStep("wait for difficulty panels visible", () => songSelect!.Carousel.ChildrenOfType().Any()); } private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.IndexOf(info); - private NoResultsPlaceholder getPlaceholder() => songSelect.ChildrenOfType().FirstOrDefault(); + private NoResultsPlaceholder? getPlaceholder() => songSelect!.ChildrenOfType().FirstOrDefault(); - private int getCurrentBeatmapIndex() => getBeatmapIndex(songSelect.Carousel.SelectedBeatmapSet, songSelect.Carousel.SelectedBeatmapInfo); + private int getCurrentBeatmapIndex() + { + Debug.Assert(songSelect!.Carousel.SelectedBeatmapSet != null); + Debug.Assert(songSelect!.Carousel.SelectedBeatmapInfo != null); + + return getBeatmapIndex(songSelect!.Carousel.SelectedBeatmapSet, songSelect!.Carousel.SelectedBeatmapInfo); + } private int getDifficultyIconIndex(DrawableCarouselBeatmapSet set, FilterableDifficultyIcon icon) { @@ -1079,14 +1112,14 @@ namespace osu.Game.Tests.Visual.SongSelect private void addRulesetImportStep(int id) { - Live imported = null; + Live? imported = null; AddStep($"import test map for ruleset {id}", () => imported = importForRuleset(id)); // This is specifically for cases where the add is happening post song select load. // For cases where song select is null, the assertions are provided by the load checks. - AddUntilStep("wait for imported to arrive in carousel", () => songSelect == null || songSelect.Carousel.BeatmapSets.Any(s => s.ID == imported?.ID)); + AddUntilStep("wait for imported to arrive in carousel", () => songSelect == null || songSelect!.Carousel.BeatmapSets.Any(s => s.ID == imported?.ID)); } - private Live importForRuleset(int id) => manager.Import(TestResources.CreateTestBeatmapSetInfo(3, rulesets.AvailableRulesets.Where(r => r.OnlineID == id).ToArray())); + private Live? importForRuleset(int id) => manager.Import(TestResources.CreateTestBeatmapSetInfo(3, rulesets.AvailableRulesets.Where(r => r.OnlineID == id).ToArray())); private void checkMusicPlaying(bool playing) => AddUntilStep($"music {(playing ? "" : "not ")}playing", () => music.IsPlaying == playing); @@ -1098,8 +1131,8 @@ namespace osu.Game.Tests.Visual.SongSelect private void createSongSelect() { AddStep("create song select", () => LoadScreen(songSelect = new TestSongSelect())); - AddUntilStep("wait for present", () => songSelect.IsCurrentScreen()); - AddUntilStep("wait for carousel loaded", () => songSelect.Carousel.IsAlive); + AddUntilStep("wait for present", () => songSelect!.IsCurrentScreen()); + AddUntilStep("wait for carousel loaded", () => songSelect!.Carousel.IsAlive); } /// @@ -1123,12 +1156,14 @@ namespace osu.Game.Tests.Visual.SongSelect protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - rulesets?.Dispose(); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); } private class TestSongSelect : PlaySongSelect { - public Action StartRequested; + public Action? StartRequested; public new Bindable Ruleset => base.Ruleset; From 7b079c134edae38793d3c98cd14ff2f205888525 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 15:48:04 +0900 Subject: [PATCH 0949/2686] Update test to actually test what was intended --- .../Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs index 5c9e9043a7..54b0bc2080 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); AddAssert("sprites present", () => sprites.All(s => s.IsPresent)); AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(0, 1))); - AddAssert("sprites not present", () => sprites.All(s => s.IsPresent)); + AddAssert("sprites not present", () => !sprites.All(s => s.IsPresent)); } [Test] From 9ead5e59d3262d1e18ec9ba5dce893f275385d0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 15:51:15 +0900 Subject: [PATCH 0950/2686] Fix incorrectly displaying minimum value in placeholder messaging --- osu.Game/Screens/Select/NoResultsPlaceholder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/NoResultsPlaceholder.cs b/osu.Game/Screens/Select/NoResultsPlaceholder.cs index f44aa01588..73b53defe0 100644 --- a/osu.Game/Screens/Select/NoResultsPlaceholder.cs +++ b/osu.Game/Screens/Select/NoResultsPlaceholder.cs @@ -127,7 +127,7 @@ namespace osu.Game.Screens.Select config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1); }); - string lowerStar = filter.UserStarDifficulty.Min == null ? "0,0" : $"{filter.UserStarDifficulty.Min:N1}"; + string lowerStar = $"{filter.UserStarDifficulty.Min ?? 0:N1}"; string upperStar = filter.UserStarDifficulty.Max == null ? "∞" : $"{filter.UserStarDifficulty.Max:N1}"; textFlow.AddText($" the {lowerStar} - {upperStar} star difficulty filter."); From d523a2ac339c88ade0176df1d9dbe26b678cbc7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 15:53:08 +0900 Subject: [PATCH 0951/2686] Rename default value field and make `private` --- .../Select/DifficultyRangeFilterControl.cs | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs b/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs index eb5a797ac0..45e7ff4caa 100644 --- a/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs +++ b/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs @@ -65,7 +65,10 @@ namespace osu.Game.Screens.Select private class MinimumStarsSlider : StarsSlider { - public MinimumStarsSlider() : base("0") { } + public MinimumStarsSlider() + : base("0") + { + } public override LocalisableString TooltipText => Current.Value.ToString(@"0.## stars"); @@ -86,7 +89,10 @@ namespace osu.Game.Screens.Select private class MaximumStarsSlider : StarsSlider { - public MaximumStarsSlider() : base("∞") { } + public MaximumStarsSlider() + : base("∞") + { + } protected override void LoadComplete() { @@ -102,15 +108,15 @@ namespace osu.Game.Screens.Select private class StarsSlider : OsuSliderBar { + private readonly string defaultString; + public override LocalisableString TooltipText => Current.IsDefault ? UserInterfaceStrings.NoLimit : Current.Value.ToString(@"0.## stars"); - protected readonly string DefaultValue; - - public StarsSlider(string defaultValue) + protected StarsSlider(string defaultString) { - DefaultValue = defaultValue; + this.defaultString = defaultString; } protected override bool OnHover(HoverEvent e) @@ -138,7 +144,7 @@ namespace osu.Game.Screens.Select Current.BindValueChanged(current => { - currentDisplay.Text = current.NewValue != Current.Default ? current.NewValue.ToString("N1") : DefaultValue; + currentDisplay.Text = current.NewValue != Current.Default ? current.NewValue.ToString("N1") : defaultString; }, true); } } From 9e42d6167fdd630c360ec6706a6cc5f20f9ce836 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 16:07:21 +0900 Subject: [PATCH 0952/2686] Fix tournament match scores resetting if `StartMatch` is called on an in-progress match --- osu.Game.Tournament/Models/TournamentMatch.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Models/TournamentMatch.cs b/osu.Game.Tournament/Models/TournamentMatch.cs index 2f72dc9257..97c2060f2c 100644 --- a/osu.Game.Tournament/Models/TournamentMatch.cs +++ b/osu.Game.Tournament/Models/TournamentMatch.cs @@ -106,13 +106,16 @@ namespace osu.Game.Tournament.Models } /// - /// Initialise this match with zeroed scores. Will be a noop if either team is not present. + /// Initialise this match with zeroed scores. Will be a noop if either team is not present or if either of the scores are non-zero. /// public void StartMatch() { if (Team1.Value == null || Team2.Value == null) return; + if (Team1Score.Value > 0 || Team2Score.Value > 0) + return; + Team1Score.Value = 0; Team2Score.Value = 0; } From b0b4da533a399327da175f01da06668f821b95e9 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 8 Sep 2022 16:59:20 +0900 Subject: [PATCH 0953/2686] Expose gameplay adjustments via MultiSpectatorPlayer instead --- .../Multiplayer/Spectate/MultiSpectatorPlayer.cs | 14 ++++---------- .../Multiplayer/Spectate/MultiSpectatorScreen.cs | 2 +- .../OnlinePlay/Multiplayer/Spectate/PlayerArea.cs | 8 ++++++++ .../Multiplayer/Spectate/SpectatorPlayerClock.cs | 3 --- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 7e910b7946..32d0e66d90 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Game.Beatmaps; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -13,6 +14,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public class MultiSpectatorPlayer : SpectatorPlayer { + public IAdjustableAudioComponent GameplayAdjustments => GameplayClockContainer.GameplayAdjustments; + private readonly SpectatorPlayerClock spectatorPlayerClock; /// @@ -53,15 +56,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) - { - var gameplayClockContainer = new GameplayClockContainer(spectatorPlayerClock); - - // Directionality is important, as BindAdjustments is... not actually a bidirectional bind... - // We want to ensure that any adjustments applied by the Player instance are applied to the SpectatorPlayerClock - // so they can be consumed by the spectator screen (and applied to the master clock / track). - spectatorPlayerClock.GameplayAdjustments.BindAdjustments(gameplayClockContainer.GameplayAdjustments); - - return gameplayClockContainer; - } + => new GameplayClockContainer(spectatorPlayerClock); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index b7c07372dc..617977bdde 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -189,7 +189,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate if (boundAdjustments != null) masterClockContainer.GameplayAdjustments.UnbindAdjustments(boundAdjustments); - boundAdjustments = first.SpectatorPlayerClock.GameplayAdjustments; + boundAdjustments = first.GameplayAdjustments; masterClockContainer.GameplayAdjustments.BindAdjustments(boundAdjustments); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index 36f6631ebf..8ecb5adb76 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -42,6 +42,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public readonly SpectatorPlayerClock SpectatorPlayerClock; + /// + /// The gameplay adjustments applied by the loaded in this area. + /// + public readonly AudioAdjustments GameplayAdjustments = new AudioAdjustments(); + /// /// The currently-loaded score. /// @@ -97,6 +102,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { var player = new MultiSpectatorPlayer(Score, SpectatorPlayerClock); player.OnGameplayStarted += () => OnGameplayStarted?.Invoke(); + + GameplayAdjustments.BindAdjustments(player.GameplayAdjustments); + return player; })); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 5667be1f4b..45615d4e19 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Audio; using osu.Framework.Timing; using osu.Game.Screens.Play; @@ -20,8 +19,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly GameplayClockContainer masterClock; - public readonly AudioAdjustments GameplayAdjustments = new AudioAdjustments(); - public double CurrentTime { get; private set; } /// From ed81297611bbe18d3df0beba6b6e07448df0b282 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 16:48:43 +0900 Subject: [PATCH 0954/2686] Fix playlist items showing download button briefly during initial local presence checks --- .../Beatmaps/TestSceneBeatmapCardDownloadButton.cs | 2 ++ .../Gameplay/TestScenePlayerLocalScoreImport.cs | 4 +++- .../Visual/Gameplay/TestSceneReplayDownloadButton.cs | 2 +- .../Drawables/Cards/Buttons/DownloadButton.cs | 12 ++++++++---- osu.Game/Online/DownloadState.cs | 1 + .../Rooms/OnlinePlayBeatmapAvailabilityTracker.cs | 1 + .../Screens/OnlinePlay/DrawableRoomPlaylistItem.cs | 4 ++++ osu.Game/Screens/Play/SaveFailedScoreButton.cs | 3 +-- 8 files changed, 21 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs index 3308ffe714..10515fd95f 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables.Cards.Buttons; using osu.Game.Configuration; +using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Resources.Localisation.Web; @@ -58,6 +59,7 @@ namespace osu.Game.Tests.Visual.Beatmaps { Anchor = Anchor.Centre, Origin = Anchor.Centre, + State = { Value = DownloadState.NotDownloaded }, Scale = new Vector2(2) }; }); diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs index f3e436e31f..247b822dc3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs @@ -81,9 +81,11 @@ namespace osu.Game.Tests.Visual.Gameplay CreateTest(); AddUntilStep("fail screen displayed", () => Player.ChildrenOfType().First().State.Value == Visibility.Visible); + AddUntilStep("wait for button clickable", () => Player.ChildrenOfType().First().ChildrenOfType().First().Enabled.Value); + AddUntilStep("score not in database", () => Realm.Run(r => r.Find(Player.Score.ScoreInfo.ID) == null)); AddStep("click save button", () => Player.ChildrenOfType().First().ChildrenOfType().First().TriggerClick()); - AddUntilStep("score not in database", () => Realm.Run(r => r.Find(Player.Score.ScoreInfo.ID) != null)); + AddUntilStep("score in database", () => Realm.Run(r => r.Find(Player.Score.ScoreInfo.ID) != null)); } [Test] diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs index 9d70d1ef33..cd227630c1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs @@ -202,7 +202,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for load", () => downloadButton.IsLoaded); - AddAssert("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded); + AddAssert("state is unknown", () => downloadButton.State.Value == DownloadState.Unknown); AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType().First().Enabled.Value); } diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs index fdb43cb47e..1b15b2498c 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs @@ -17,8 +17,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { public class DownloadButton : BeatmapCardIconButton { - public IBindable State => state; - private readonly Bindable state = new Bindable(); + public Bindable State { get; } = new Bindable(); private readonly APIBeatmapSet beatmapSet; @@ -48,14 +47,19 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { base.LoadComplete(); preferNoVideo.BindValueChanged(_ => updateState()); - state.BindValueChanged(_ => updateState(), true); + State.BindValueChanged(_ => updateState(), true); FinishTransforms(true); } private void updateState() { - switch (state.Value) + switch (State.Value) { + case DownloadState.Unknown: + Action = null; + TooltipText = string.Empty; + break; + case DownloadState.Downloading: case DownloadState.Importing: Action = null; diff --git a/osu.Game/Online/DownloadState.cs b/osu.Game/Online/DownloadState.cs index a58c40d16a..f4ecb28b90 100644 --- a/osu.Game/Online/DownloadState.cs +++ b/osu.Game/Online/DownloadState.cs @@ -5,6 +5,7 @@ namespace osu.Game.Online { public enum DownloadState { + Unknown, NotDownloaded, Downloading, Importing, diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs index bb8ec4f6ff..7f8f9703e4 100644 --- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs @@ -114,6 +114,7 @@ namespace osu.Game.Online.Rooms switch (downloadTracker.State.Value) { + case DownloadState.Unknown: case DownloadState.NotDownloaded: availability.Value = BeatmapAvailability.NotDownloaded(); break; diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index beecd56b52..bda616d5c3 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -561,6 +561,10 @@ namespace osu.Game.Screens.OnlinePlay { switch (state.NewValue) { + case DownloadState.Unknown: + // Ignore initial state to ensure the button doesn't briefly appear. + break; + case DownloadState.LocallyAvailable: // Perform a local query of the beatmap by beatmap checksum, and reset the state if not matching. if (beatmapManager.QueryBeatmap(b => b.MD5Hash == beatmap.MD5Hash) == null) diff --git a/osu.Game/Screens/Play/SaveFailedScoreButton.cs b/osu.Game/Screens/Play/SaveFailedScoreButton.cs index 3f6e741dff..7358ff3de4 100644 --- a/osu.Game/Screens/Play/SaveFailedScoreButton.cs +++ b/osu.Game/Screens/Play/SaveFailedScoreButton.cs @@ -63,8 +63,7 @@ namespace osu.Game.Screens.Play if (player != null) { importedScore = realm.Run(r => r.Find(player.Score.ScoreInfo.ID)?.Detach()); - if (importedScore != null) - state.Value = DownloadState.LocallyAvailable; + state.Value = importedScore != null ? DownloadState.LocallyAvailable : DownloadState.NotDownloaded; } state.BindValueChanged(state => From b559d4ecdf8dc6c4df4b6582bc34710d734d3b35 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 8 Sep 2022 17:14:06 +0900 Subject: [PATCH 0955/2686] Rename GameplayAdjustments -> AdjustmentsFromMods --- .../NonVisual/GameplayClockContainerTest.cs | 2 +- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 2 +- .../Multiplayer/Spectate/MultiSpectatorPlayer.cs | 11 +++++++++-- .../Multiplayer/Spectate/MultiSpectatorScreen.cs | 6 +++--- .../OnlinePlay/Multiplayer/Spectate/PlayerArea.cs | 6 +++--- osu.Game/Screens/Play/GameplayClockContainer.cs | 2 +- osu.Game/Screens/Play/GameplayClockExtensions.cs | 4 ++-- osu.Game/Screens/Play/IGameplayClock.cs | 4 ++-- osu.Game/Screens/Play/MasterGameplayClockContainer.cs | 4 ++-- osu.Game/Screens/Play/Player.cs | 2 +- 10 files changed, 25 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs b/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs index 80f0aaeb55..363c7a459e 100644 --- a/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs +++ b/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tests.NonVisual public TestGameplayClockContainer(IFrameBasedClock underlyingClock) : base(underlyingClock) { - GameplayAdjustments.AddAdjustment(AdjustableProperty.Frequency, new BindableDouble(2.0)); + AdjustmentsFromMods.AddAdjustment(AdjustableProperty.Frequency, new BindableDouble(2.0)); } } } diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index f0c7a398eb..6f57cfe2f7 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -265,7 +265,7 @@ namespace osu.Game.Rulesets.UI private readonly AudioAdjustments gameplayAdjustments = new AudioAdjustments(); - public IAdjustableAudioComponent GameplayAdjustments => parentGameplayClock?.GameplayAdjustments ?? gameplayAdjustments; + public IAdjustableAudioComponent AdjustmentsFromMods => parentGameplayClock?.AdjustmentsFromMods ?? gameplayAdjustments; #endregion diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 32d0e66d90..2d32bc7516 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -14,7 +14,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public class MultiSpectatorPlayer : SpectatorPlayer { - public IAdjustableAudioComponent GameplayAdjustments => GameplayClockContainer.GameplayAdjustments; + /// + /// All adjustments applied to the clock of this which come from mods. + /// + public readonly AudioAdjustments ClockAdjustmentsFromMods = new AudioAdjustments(); private readonly SpectatorPlayerClock spectatorPlayerClock; @@ -56,6 +59,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) - => new GameplayClockContainer(spectatorPlayerClock); + { + var gameplayClockContainer = new GameplayClockContainer(spectatorPlayerClock); + ClockAdjustmentsFromMods.BindAdjustments(gameplayClockContainer.AdjustmentsFromMods); + return gameplayClockContainer; + } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 617977bdde..42a946a023 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -187,10 +187,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private void bindAudioAdjustments(PlayerArea first) { if (boundAdjustments != null) - masterClockContainer.GameplayAdjustments.UnbindAdjustments(boundAdjustments); + masterClockContainer.AdjustmentsFromMods.UnbindAdjustments(boundAdjustments); - boundAdjustments = first.GameplayAdjustments; - masterClockContainer.GameplayAdjustments.BindAdjustments(boundAdjustments); + boundAdjustments = first.ClockAdjustmentsFromMods; + masterClockContainer.AdjustmentsFromMods.BindAdjustments(boundAdjustments); } private bool isCandidateAudioSource(SpectatorPlayerClock? clock) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index 8ecb5adb76..585d464a2a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -43,9 +43,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public readonly SpectatorPlayerClock SpectatorPlayerClock; /// - /// The gameplay adjustments applied by the loaded in this area. + /// The clock adjustments applied by the loaded in this area. /// - public readonly AudioAdjustments GameplayAdjustments = new AudioAdjustments(); + public readonly AudioAdjustments ClockAdjustmentsFromMods = new AudioAdjustments(); /// /// The currently-loaded score. @@ -103,7 +103,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate var player = new MultiSpectatorPlayer(Score, SpectatorPlayerClock); player.OnGameplayStarted += () => OnGameplayStarted?.Invoke(); - GameplayAdjustments.BindAdjustments(player.GameplayAdjustments); + ClockAdjustmentsFromMods.BindAdjustments(player.ClockAdjustmentsFromMods); return player; })); diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index e64c628fa0..35b79fd628 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Play /// public double StartTime { get; protected set; } - public IAdjustableAudioComponent GameplayAdjustments { get; } = new AudioAdjustments(); + public IAdjustableAudioComponent AdjustmentsFromMods { get; } = new AudioAdjustments(); private readonly BindableBool isPaused = new BindableBool(true); diff --git a/osu.Game/Screens/Play/GameplayClockExtensions.cs b/osu.Game/Screens/Play/GameplayClockExtensions.cs index ec77a94ce9..5e88b41080 100644 --- a/osu.Game/Screens/Play/GameplayClockExtensions.cs +++ b/osu.Game/Screens/Play/GameplayClockExtensions.cs @@ -17,8 +17,8 @@ namespace osu.Game.Screens.Play double rate = clock.Rate == 0 ? 1 : Math.Sign(clock.Rate); return rate - * clock.GameplayAdjustments.AggregateFrequency.Value - * clock.GameplayAdjustments.AggregateTempo.Value; + * clock.AdjustmentsFromMods.AggregateFrequency.Value + * clock.AdjustmentsFromMods.AggregateTempo.Value; } } } diff --git a/osu.Game/Screens/Play/IGameplayClock.cs b/osu.Game/Screens/Play/IGameplayClock.cs index c58d2dbcac..83ba5f3474 100644 --- a/osu.Game/Screens/Play/IGameplayClock.cs +++ b/osu.Game/Screens/Play/IGameplayClock.cs @@ -19,9 +19,9 @@ namespace osu.Game.Screens.Play double StartTime { get; } /// - /// All adjustments applied to this clock which come from gameplay or mods. + /// All adjustments applied to this clock which come from mods. /// - IAdjustableAudioComponent GameplayAdjustments { get; } + IAdjustableAudioComponent AdjustmentsFromMods { get; } IBindable IsPaused { get; } } diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 20a5c95605..047f25a111 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -201,7 +201,7 @@ namespace osu.Game.Screens.Play musicController.ResetTrackAdjustments(); - track.BindAdjustments(GameplayAdjustments); + track.BindAdjustments(AdjustmentsFromMods); track.AddAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.AddAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); @@ -213,7 +213,7 @@ namespace osu.Game.Screens.Play if (!speedAdjustmentsApplied) return; - track.UnbindAdjustments(GameplayAdjustments); + track.UnbindAdjustments(AdjustmentsFromMods); track.RemoveAdjustment(AdjustableProperty.Frequency, GameplayClock.ExternalPauseFrequencyAdjust); track.RemoveAdjustment(AdjustableProperty.Tempo, UserPlaybackRate); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e93502da13..1732c6533e 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -997,7 +997,7 @@ namespace osu.Game.Screens.Play mod.ApplyToHUD(HUDOverlay); foreach (var mod in GameplayState.Mods.OfType()) - mod.ApplyToTrack(GameplayClockContainer.GameplayAdjustments); + mod.ApplyToTrack(GameplayClockContainer.AdjustmentsFromMods); updateGameplayState(); From c61c596c1f392c894e9511a3d2c4576e6ede0838 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 8 Sep 2022 17:37:02 +0900 Subject: [PATCH 0956/2686] Expose as readonly IAggregateAudioAdjustment --- .../Multiplayer/Spectate/MultiSpectatorPlayer.cs | 5 +++-- .../Multiplayer/Spectate/MultiSpectatorScreen.cs | 2 +- .../OnlinePlay/Multiplayer/Spectate/PlayerArea.cs | 10 +++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 2d32bc7516..8e79c89685 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -17,8 +17,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// All adjustments applied to the clock of this which come from mods. /// - public readonly AudioAdjustments ClockAdjustmentsFromMods = new AudioAdjustments(); + public IAggregateAudioAdjustment ClockAdjustmentsFromMods => clockAdjustmentsFromMods; + private readonly AudioAdjustments clockAdjustmentsFromMods = new AudioAdjustments(); private readonly SpectatorPlayerClock spectatorPlayerClock; /// @@ -61,7 +62,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) { var gameplayClockContainer = new GameplayClockContainer(spectatorPlayerClock); - ClockAdjustmentsFromMods.BindAdjustments(gameplayClockContainer.AdjustmentsFromMods); + clockAdjustmentsFromMods.BindAdjustments(gameplayClockContainer.AdjustmentsFromMods); return gameplayClockContainer; } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 42a946a023..1fd04d35f8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate [Resolved] private MultiplayerClient multiplayerClient { get; set; } = null!; - private AudioAdjustments? boundAdjustments; + private IAggregateAudioAdjustment? boundAdjustments; private readonly PlayerArea[] instances; private MasterGameplayClockContainer masterClockContainer = null!; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index 585d464a2a..8eee3d0fb6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The clock adjustments applied by the loaded in this area. /// - public readonly AudioAdjustments ClockAdjustmentsFromMods = new AudioAdjustments(); + public IAggregateAudioAdjustment ClockAdjustmentsFromMods => clockAdjustmentsFromMods; /// /// The currently-loaded score. @@ -55,6 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate [Resolved] private IBindable beatmap { get; set; } = null!; + private readonly AudioAdjustments clockAdjustmentsFromMods = new AudioAdjustments(); private readonly BindableDouble volumeAdjustment = new BindableDouble(); private readonly Container gameplayContent; private readonly LoadingLayer loadingLayer; @@ -101,9 +102,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate stack.Push(new MultiSpectatorPlayerLoader(Score, () => { var player = new MultiSpectatorPlayer(Score, SpectatorPlayerClock); - player.OnGameplayStarted += () => OnGameplayStarted?.Invoke(); - ClockAdjustmentsFromMods.BindAdjustments(player.ClockAdjustmentsFromMods); + player.OnGameplayStarted += () => + { + clockAdjustmentsFromMods.BindAdjustments(player.ClockAdjustmentsFromMods); + OnGameplayStarted?.Invoke(); + }; return player; })); From 76eae73fa4b66268c2bc87a82d330bbc130a9c7f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 8 Sep 2022 17:41:23 +0900 Subject: [PATCH 0957/2686] Revert unintended change --- .../Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index 8eee3d0fb6..96f134568d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -102,12 +102,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate stack.Push(new MultiSpectatorPlayerLoader(Score, () => { var player = new MultiSpectatorPlayer(Score, SpectatorPlayerClock); + player.OnGameplayStarted += () => OnGameplayStarted?.Invoke(); - player.OnGameplayStarted += () => - { - clockAdjustmentsFromMods.BindAdjustments(player.ClockAdjustmentsFromMods); - OnGameplayStarted?.Invoke(); - }; + clockAdjustmentsFromMods.BindAdjustments(player.ClockAdjustmentsFromMods); return player; })); From c6521e4c7274e3cdd7a681a817622bb01e719f20 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 17:50:27 +0900 Subject: [PATCH 0958/2686] Rename ordering helper method --- osu.Game/Rulesets/Scoring/HitResult.cs | 7 ++----- .../Ranking/Statistics/HitEventTimingDistributionGraph.cs | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/HitResult.cs b/osu.Game/Rulesets/Scoring/HitResult.cs index 3349bcf245..96e13e5861 100644 --- a/osu.Game/Rulesets/Scoring/HitResult.cs +++ b/osu.Game/Rulesets/Scoring/HitResult.cs @@ -286,14 +286,11 @@ namespace osu.Game.Rulesets.Scoring } /// - /// Ordered index of a . Used for sorting. + /// Ordered index of a . Used for consistent order when displaying hit results to the user. /// /// The to get the index of. /// The index of . - public static int OrderingIndex(this HitResult result) - { - return order.IndexOf(result); - } + public static int GetIndexForOrderedDisplay(this HitResult result) => order.IndexOf(result); } #pragma warning restore CS0618 } diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 52682c35a0..5335d77243 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -225,7 +225,7 @@ namespace osu.Game.Screens.Ranking.Statistics public Bar(IDictionary values, float maxValue, bool isCentre) { - this.values = values.OrderBy(v => v.Key.OrderingIndex()).ToList(); + this.values = values.OrderBy(v => v.Key.GetIndexForOrderedDisplay()).ToList(); this.maxValue = maxValue; this.isCentre = isCentre; From 0de220c45c502e618cf857b76f963471e54b8c26 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 17:54:29 +0900 Subject: [PATCH 0959/2686] Change `IsExclusive` default value to `true` --- osu.Game/Online/Multiplayer/ForceGameplayStartCountdown.cs | 1 - osu.Game/Online/Multiplayer/MatchStartCountdown.cs | 1 - osu.Game/Online/Multiplayer/MultiplayerCountdown.cs | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Online/Multiplayer/ForceGameplayStartCountdown.cs b/osu.Game/Online/Multiplayer/ForceGameplayStartCountdown.cs index 81ba56f35c..bbfc5a02c6 100644 --- a/osu.Game/Online/Multiplayer/ForceGameplayStartCountdown.cs +++ b/osu.Game/Online/Multiplayer/ForceGameplayStartCountdown.cs @@ -15,6 +15,5 @@ namespace osu.Game.Online.Multiplayer [MessagePackObject] public sealed class ForceGameplayStartCountdown : MultiplayerCountdown { - public override bool IsExclusive => true; } } diff --git a/osu.Game/Online/Multiplayer/MatchStartCountdown.cs b/osu.Game/Online/Multiplayer/MatchStartCountdown.cs index b4c66e6f5b..fe65ebb059 100644 --- a/osu.Game/Online/Multiplayer/MatchStartCountdown.cs +++ b/osu.Game/Online/Multiplayer/MatchStartCountdown.cs @@ -11,6 +11,5 @@ namespace osu.Game.Online.Multiplayer [MessagePackObject] public sealed class MatchStartCountdown : MultiplayerCountdown { - public override bool IsExclusive => true; } } diff --git a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs index e8e2365f7b..61637ae970 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs @@ -33,6 +33,6 @@ namespace osu.Game.Online.Multiplayer /// /// Whether only a single instance of this type may be active at any one time. /// - public virtual bool IsExclusive => false; + public virtual bool IsExclusive => true; } } From 53219ae4e7c7d71dd38dcf12c25b95faeaf7fca8 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Thu, 8 Sep 2022 16:59:48 +0800 Subject: [PATCH 0960/2686] show fixed speed in mania scroll speed settings --- .../Configuration/ManiaRulesetConfigManager.cs | 2 -- osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs | 10 +++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs index 35ad21442e..8e09a01469 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.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. -#nullable disable - using System; using osu.Framework.Configuration.Tracking; using osu.Game.Configuration; diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs index 43d4aa77a2..51a45abd70 100644 --- a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs +++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs @@ -1,8 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; @@ -34,7 +33,7 @@ namespace osu.Game.Rulesets.Mania LabelText = "Scrolling direction", Current = config.GetBindable(ManiaRulesetSetting.ScrollDirection) }, - new SettingsSlider + new SettingsSlider { LabelText = "Scroll speed", Current = config.GetBindable(ManiaRulesetSetting.ScrollTime), @@ -47,5 +46,10 @@ namespace osu.Game.Rulesets.Mania } }; } + + private class ManiaScorllSlider : OsuSliderBar + { + public override LocalisableString TooltipText => $"{(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value)} ({Current.Value}ms)"; + } } } From 4a6c8785af7bd24b5f2e4a1be9e85c19624ac4c8 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Thu, 8 Sep 2022 11:14:56 +0200 Subject: [PATCH 0961/2686] Clean up --- osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs | 31 ++++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs index e1ce43d875..818eb93bfb 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs @@ -38,30 +38,31 @@ namespace osu.Game.Rulesets.Osu.Mods Precision = .25f }; + + public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) + { + (drawableRuleset.Playfield as OsuPlayfield)?.FollowPoints.Hide(); + } + public override void ApplyToBeatmap(IBeatmap beatmap) { base.ApplyToBeatmap(beatmap); foreach (var obj in beatmap.HitObjects.OfType()) { - applyFadeInAdjustment(obj); var point = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime); - obj.TimePreempt += obj.StartTime % (point.BeatLength * BeatDivisor.Value); - } + double val = obj.TimePreempt + obj.StartTime % (point.BeatLength * BeatDivisor.Value); + applyFadeInAdjustment(obj); - static void applyFadeInAdjustment(OsuHitObject osuObject) - { - osuObject.TimeFadeIn = osuObject.TimePreempt; - foreach (var nested in osuObject.NestedHitObjects.OfType()) - applyFadeInAdjustment(nested); + void applyFadeInAdjustment(OsuHitObject osuObject) + { + osuObject.TimePreempt = val; + foreach (var nested in osuObject.NestedHitObjects.OfType()) + applyFadeInAdjustment(nested); + } } } - public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) - { - (drawableRuleset.Playfield as OsuPlayfield)?.FollowPoints.Hide(); - } - protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) { } @@ -74,7 +75,7 @@ namespace osu.Game.Rulesets.Osu.Mods return; var h = (OsuHitObject)drawable.HitObject; - + /* switch (drawable) { case DrawableHitCircle circle: @@ -84,7 +85,7 @@ namespace osu.Game.Rulesets.Osu.Mods } break; - } + }*/ } } } From f0850c42e536178aceeb17a965c9b4e56aea0560 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Thu, 8 Sep 2022 18:16:23 +0900 Subject: [PATCH 0962/2686] fix typo `ManiaScorllSlider` -> `ManiaScrollSlider` --- osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs index 51a45abd70..622450ac4a 100644 --- a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs +++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Mania LabelText = "Scrolling direction", Current = config.GetBindable(ManiaRulesetSetting.ScrollDirection) }, - new SettingsSlider + new SettingsSlider { LabelText = "Scroll speed", Current = config.GetBindable(ManiaRulesetSetting.ScrollTime), @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Mania }; } - private class ManiaScorllSlider : OsuSliderBar + private class ManiaScrollSlider : OsuSliderBar { public override LocalisableString TooltipText => $"{(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value)} ({Current.Value}ms)"; } From 5c2fb3e43453febce253e83c74f5e78e0659bdcc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 18:22:53 +0900 Subject: [PATCH 0963/2686] Simplify calculation method --- .../ClicksPerSecondCalculator.cs | 55 ++++++++----------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs index 20ac923b82..b8cf20ee8f 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.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.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Rulesets.UI; @@ -11,56 +10,48 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond { public class ClicksPerSecondCalculator : Component { - private readonly List timestamps; + private readonly List timestamps = new List(); [Resolved] private IGameplayClock gameplayClock { get; set; } = null!; - [Resolved] - private DrawableRuleset drawableRuleset { get; set; } = null!; - - private double rate; - - // The latest timestamp GC seeked. Does not affect normal gameplay - // but prevents duplicate inputs on replays. - private double latestTime = double.NegativeInfinity; + [Resolved(canBeNull: true)] + private DrawableRuleset? drawableRuleset { get; set; } public int Value { get; private set; } + private IGameplayClock clock => drawableRuleset?.FrameStableClock ?? gameplayClock; + public ClicksPerSecondCalculator() { RelativeSizeAxes = Axes.Both; - timestamps = new List(); } + public void AddInputTimestamp() => timestamps.Add(clock.CurrentTime); + protected override void Update() { base.Update(); - // When pausing in replays (using the space bar) GC.TrueGameplayRate returns 0 - // To prevent CPS value being 0, we store and use the last non-zero TrueGameplayRate - if (gameplayClock.TrueGameplayRate > 0) + double latestValidTime = clock.CurrentTime; + double earliestTimeValid = latestValidTime - 1000 * gameplayClock.TrueGameplayRate; + + int count = 0; + + for (int i = timestamps.Count - 1; i >= 0; i--) { - rate = gameplayClock.TrueGameplayRate; + // handle rewinding by removing future timestamps as we go + if (timestamps[i] > latestValidTime) + { + timestamps.RemoveAt(i); + continue; + } + + if (timestamps[i] >= earliestTimeValid) + count++; } - Value = timestamps.Count(timestamp => - { - double window = 1000 * rate; - double relativeTime = drawableRuleset.FrameStableClock.CurrentTime - timestamp; - return relativeTime > 0 && relativeTime <= window; - }); - } - - public void AddTimestamp() - { - // Discard inputs if current gameplay time is not the latest - // to prevent duplicate inputs - if (drawableRuleset.FrameStableClock.CurrentTime >= latestTime) - { - timestamps.Add(drawableRuleset.FrameStableClock.CurrentTime); - latestTime = drawableRuleset.FrameStableClock.CurrentTime; - } + Value = count; } } } From 6729bb3e1a24e38c92caa542c3e67ddc1c59ad47 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 18:23:54 +0900 Subject: [PATCH 0964/2686] Change `FrameStableClock` to inherit `IGameplayClock` --- osu.Game/Rulesets/UI/FrameStabilityContainer.cs | 2 +- osu.Game/Rulesets/UI/IFrameStableClock.cs | 4 ++-- osu.Game/Rulesets/UI/RulesetInputManager.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 18d0ff0bed..9446ba946b 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.UI /// [Cached(typeof(IGameplayClock))] [Cached(typeof(IFrameStableClock))] - public sealed class FrameStabilityContainer : Container, IHasReplayHandler, IFrameStableClock, IGameplayClock + public sealed class FrameStabilityContainer : Container, IHasReplayHandler, IFrameStableClock { public ReplayInputHandler? ReplayInputHandler { get; set; } diff --git a/osu.Game/Rulesets/UI/IFrameStableClock.cs b/osu.Game/Rulesets/UI/IFrameStableClock.cs index 569ef5e06c..4e50d059e9 100644 --- a/osu.Game/Rulesets/UI/IFrameStableClock.cs +++ b/osu.Game/Rulesets/UI/IFrameStableClock.cs @@ -2,11 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; -using osu.Framework.Timing; +using osu.Game.Screens.Play; namespace osu.Game.Rulesets.UI { - public interface IFrameStableClock : IFrameBasedClock + public interface IFrameStableClock : IGameplayClock { IBindable IsCatchingUp { get; } diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index dcd2c4fb5d..1a97153f2f 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -207,7 +207,7 @@ namespace osu.Game.Rulesets.UI public bool OnPressed(KeyBindingPressEvent e) { - calculator.AddTimestamp(); + calculator.AddInputTimestamp(); return false; } From 07c16224d27fa38ba060f16bc2a3d227d4c2e96c Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Thu, 8 Sep 2022 11:58:14 +0200 Subject: [PATCH 0965/2686] Fix Main file issues --- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 8901612b9b..0713469e10 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -18,7 +18,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public class ColourHitErrorMeter : HitErrorMeter { - private const int default_shape_alpha = 0; private const int animation_duration = 200; private const int drawable_judgement_size = 8; @@ -35,7 +34,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { MinValue = 0.01f, MaxValue = 1, - Precision = .01f, + Precision = 0.01f, }; [SettingSource("Spacing", "Space between hit error shapes")] @@ -43,10 +42,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { MinValue = 0, MaxValue = 10, - Precision = .1f + Precision = 0.1f }; - [SettingSource("Shape", "What shape to use for hit errors")] + [SettingSource("Shape", "The shape of each displayed error")] public Bindable HitShape { get; } = new Bindable(); private readonly JudgementFlow judgementsFlow; @@ -81,7 +80,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }, true); HitShape.BindValueChanged(_ => { - judgementsFlow.ValueParser = getShapeStyle(HitShape.Value); + judgementsFlow.Shape = getShapeStyle(HitShape.Value); judgementsFlow.Clear(); }, true); } @@ -91,7 +90,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private class JudgementFlow : FillFlowContainer { public override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); - internal string ValueParser = null!; + internal string Shape = null!; public JudgementFlow() { @@ -103,7 +102,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public void Push(Color4 colour, int maxErrorShapeCount) { - Add(new HitErrorShape(colour, drawable_judgement_size, ValueParser)); + Add(new HitErrorShape(colour, drawable_judgement_size, Shape)); if (Children.Count > maxErrorShapeCount) Children.FirstOrDefault(c => !c.IsRemoved)?.Remove(); @@ -124,7 +123,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Child = new Circle { RelativeSizeAxes = Axes.Both, - Alpha = default_shape_alpha, + Alpha = 0, Colour = colour }; break; @@ -133,7 +132,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Child = new Box { RelativeSizeAxes = Axes.Both, - Alpha = default_shape_alpha, + Alpha = 0, Colour = colour }; break; From ee094e3a858e409f21b20602438595d8a770d372 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 19:05:13 +0900 Subject: [PATCH 0966/2686] Rewrite tests --- .../Gameplay/TestSceneClicksPerSecond.cs | 292 +++--------------- 1 file changed, 50 insertions(+), 242 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs index a140460251..ed5102e3b3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs @@ -3,22 +3,11 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Timing; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.UI; -using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD.ClicksPerSecond; using osuTK; @@ -27,290 +16,109 @@ namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneClicksPerSecond : OsuTestScene { - private DependencyProvidingContainer dependencyContainer = null!; private ClicksPerSecondCalculator calculator = null!; - private GameplayClockContainer gameplayClockContainer = null!; - private ManualClock manualClock = null!; - private DrawableRuleset? drawableRuleset; - private IFrameStableClock? frameStableClock; + + private TestGameplayClock manualGameplayClock = null!; [SetUpSteps] public void SetUpSteps() { AddStep("create components", () => { - var ruleset = CreateRuleset(); + manualGameplayClock = new TestGameplayClock(); - Debug.Assert(ruleset != null); - - Child = gameplayClockContainer = new GameplayClockContainer(manualClock = new ManualClock()); - gameplayClockContainer.AddRange(new Drawable[] + Child = new DependencyProvidingContainer { - drawableRuleset = new TestDrawableRuleset(frameStableClock = new TestFrameStableClock(manualClock)), - dependencyContainer = new DependencyProvidingContainer + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] { (typeof(IGameplayClock), manualGameplayClock) }, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - CachedDependencies = new (Type, object)[] + calculator = new ClicksPerSecondCalculator(), + new DependencyProvidingContainer { - (typeof(DrawableRuleset), drawableRuleset), - (typeof(IGameplayClock), gameplayClockContainer) + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] { (typeof(ClicksPerSecondCalculator), calculator) }, + Child = new ClicksPerSecondCounter + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(5), + } } - } - }); + }, + }; }); } [Test] public void TestBasicConsistency() { - createCalculator(); - startClock(); - - AddStep("Create gradually increasing KPS inputs", () => - { - addInputs(generateGraduallyIncreasingKps()); - }); - - for (int i = 0; i < 10; i++) - { - seek(i * 10000); - advanceForwards(2); - int kps = i + 1; - AddAssert($"{kps} KPS", () => calculator.Value == kps); - } + seek(1000); + AddStep("add inputs in past", () => addInputs(new double[] { 0, 100, 200, 300, 400, 500, 600, 700, 800, 900 })); + checkClicksPerSecondValue(10); } [Test] public void TestRateAdjustConsistency() { - createCalculator(); - startClock(); - - AddStep("Create consistent KPS inputs", () => addInputs(generateConsistentKps(10))); - - advanceForwards(2); - - for (double i = 1; i <= 2; i += 0.25) - { - changeRate(i); - double rate = i; - AddAssert($"KPS approx. = {i}", () => MathHelper.ApproximatelyEquivalent(calculator.Value, 10 * rate, 0.5)); - } - - for (double i = 1; i >= 0.5; i -= 0.25) - { - changeRate(i); - double rate = i; - AddAssert($"KPS approx. = {i}", () => MathHelper.ApproximatelyEquivalent(calculator.Value, 10 * rate, 0.5)); - } + seek(1000); + AddStep("add inputs in past", () => addInputs(new double[] { 0, 100, 200, 300, 400, 500, 600, 700, 800, 900 })); + checkClicksPerSecondValue(10); + AddStep("set rate 0.5x", () => manualGameplayClock.TrueGameplayRate = 0.5); + checkClicksPerSecondValue(5); } [Test] public void TestInputsDiscardedOnRewind() { - createCalculator(); - startClock(); - - AddStep("Create consistent KPS inputs", () => addInputs(generateConsistentKps(10))); seek(1000); - - AddAssert("KPS = 10", () => calculator.Value == 10); - - AddStep("Create delayed inputs", () => addInputs(generateConsistentKps(10, 50))); + AddStep("add inputs in past", () => addInputs(new double[] { 0, 100, 200, 300, 400, 500, 600, 700, 800, 900 })); + checkClicksPerSecondValue(10); + seek(500); + checkClicksPerSecondValue(6); seek(1000); - AddAssert("KPS didn't changed", () => calculator.Value == 10); + checkClicksPerSecondValue(6); } - private void seekAllClocks(double time) - { - gameplayClockContainer.Seek(time); - manualClock.CurrentTime = time; - } + private void checkClicksPerSecondValue(int i) => AddAssert("clicks/s is correct", () => calculator.Value, () => Is.EqualTo(i)); - protected override Ruleset CreateRuleset() => new OsuRuleset(); + private void seekClockImmediately(double time) => manualGameplayClock.CurrentTime = time; - #region Quick steps methods - - private void createCalculator() - { - AddStep("create calculator", () => - { - dependencyContainer.Children = new Drawable[] - { - calculator = new ClicksPerSecondCalculator(), - new DependencyProvidingContainer - { - RelativeSizeAxes = Axes.Both, - CachedDependencies = new (Type, object)[] { (typeof(ClicksPerSecondCalculator), calculator) }, - Child = new ClicksPerSecondCounter // For visual debugging, has no real purpose in the tests - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(5), - } - } - }; - }); - } - - private void seek(double time) => AddStep($"Seek clocks to {time}ms", () => seekAllClocks(time)); - - private void changeRate(double rate) => AddStep($"Change rate to x{rate}", () => manualClock.Rate = rate); - - private void advanceForwards(double time) => - AddStep($"Advance clocks {time} seconds forward.", () => - { - gameplayClockContainer.Seek(gameplayClockContainer.CurrentTime + time * manualClock.Rate); - - for (int i = 0; i < time; i++) - { - frameStableClock?.ProcessFrame(); - } - }); - - private void startClock() => AddStep("Start clocks", () => - { - gameplayClockContainer.Start(); - manualClock.Rate = 1; - }); - - #endregion - - #region Input generation + private void seek(double time) => AddStep($"Seek to {time}ms", () => seekClockImmediately(time)); private void addInputs(IEnumerable inputs) { - if (!inputs.Any()) return; - - double baseTime = gameplayClockContainer.CurrentTime; + double baseTime = manualGameplayClock.CurrentTime; foreach (double timestamp in inputs) { - seekAllClocks(timestamp); - calculator.AddTimestamp(); + seekClockImmediately(timestamp); + calculator.AddInputTimestamp(); } - seekAllClocks(baseTime); + seekClockImmediately(baseTime); } - private IEnumerable generateGraduallyIncreasingKps() + private class TestGameplayClock : IGameplayClock { - IEnumerable final = null!; + public double CurrentTime { get; set; } - for (int i = 1; i <= 10; i++) - { - var currentKps = generateConsistentKps(i, (i - 1) * 10000); + public double Rate => 1; - if (i == 1) - { - final = currentKps; - continue; - } + public bool IsRunning => true; - final = final.Concat(currentKps); - } - - return final; - } - - private IEnumerable generateConsistentKps(double kps, double start = 0, double duration = 10) - { - double end = start + 1000 * duration; - - for (; start < end; start += 1000 / kps) - { - yield return start; - } - } - - #endregion - - #region Test classes - - private class TestFrameStableClock : IFrameStableClock - { - public TestFrameStableClock(IClock source, double startTime = 0) - { - this.source = source; - - if (source is ManualClock manualClock) - { - manualClock.CurrentTime = startTime; - } - } - - public double CurrentTime => source.CurrentTime; - public double Rate => source.Rate; - public bool IsRunning => source.IsRunning; - - private readonly IClock source; + public double TrueGameplayRate { get; set; } = 1; public void ProcessFrame() { - if (source is ManualClock manualClock) - { - manualClock.CurrentTime += 1000 * Rate; - } - - TimeInfo = new FrameTimeInfo - { - Elapsed = 1000 * Rate, - Current = CurrentTime - }; } - public double ElapsedFrameTime => TimeInfo.Elapsed; - public double FramesPerSecond => 1 / ElapsedFrameTime * 1000; - public FrameTimeInfo TimeInfo { get; private set; } - - public IEnumerable NonGameplayAdjustments => Enumerable.Empty(); - public IBindable IsCatchingUp => new Bindable(); - public IBindable WaitingOnFrames => new Bindable(); + public double ElapsedFrameTime => throw new NotImplementedException(); + public double FramesPerSecond => throw new NotImplementedException(); + public FrameTimeInfo TimeInfo => throw new NotImplementedException(); + public double StartTime => throw new NotImplementedException(); + public IEnumerable NonGameplayAdjustments => throw new NotImplementedException(); + public IBindable IsPaused => throw new NotImplementedException(); } - - [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] - private class TestDrawableRuleset : DrawableRuleset - { - public override IEnumerable Objects => Enumerable.Empty(); - - public override event Action NewResult - { - add => throw new InvalidOperationException($"{nameof(NewResult)} operations not supported in test context"); - remove => throw new InvalidOperationException($"{nameof(NewResult)} operations not supported in test context"); - } - - public override event Action RevertResult - { - add => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); - remove => throw new InvalidOperationException($"{nameof(RevertResult)} operations not supported in test context"); - } - - public override Playfield Playfield => null!; - public override Container Overlays => null!; - public override Container FrameStableComponents => null!; - public override IFrameStableClock FrameStableClock { get; } - - internal override bool FrameStablePlayback { get; set; } - public override IReadOnlyList Mods => Array.Empty(); - - public override double GameplayStartTime => 0; - public override GameplayCursorContainer Cursor => null!; - - public TestDrawableRuleset(IFrameStableClock frameStableClock) - : base(new OsuRuleset()) - { - FrameStableClock = frameStableClock; - } - - public override void SetReplayScore(Score replayScore) => throw new NotImplementedException(); - - public override void SetRecordTarget(Score score) => throw new NotImplementedException(); - - public override void RequestResume(Action continueResume) => throw new NotImplementedException(); - - public override void CancelResume() => throw new NotImplementedException(); - } - - #endregion } } From a98c6b2c1f43e910045cc75a879452a732268be5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 19:14:23 +0900 Subject: [PATCH 0967/2686] Add comment metioning why we need to use `DrawableRuleset` lookup --- .../Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs index b8cf20ee8f..82bf9cfa1e 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs @@ -20,6 +20,8 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond public int Value { get; private set; } + // Even though `FrameStabilityContainer` caches as a `GameplayClock`, we need to check it directly via `drawableRuleset` + // as this calculator is not contained within the `FrameStabilityContainer` and won't see the dependency. private IGameplayClock clock => drawableRuleset?.FrameStableClock ?? gameplayClock; public ClicksPerSecondCalculator() From 15a4eb46c4d3ea9cf387116837733fc741bd53bb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 19:20:26 +0900 Subject: [PATCH 0968/2686] Rename test scene to match class name --- ...ClicksPerSecond.cs => TestSceneClicksPerSecondCalculator.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename osu.Game.Tests/Visual/Gameplay/{TestSceneClicksPerSecond.cs => TestSceneClicksPerSecondCalculator.cs} (98%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs similarity index 98% rename from osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs index ed5102e3b3..b740c06e03 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecond.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneClicksPerSecond : OsuTestScene + public class TestSceneClicksPerSecondCalculator : OsuTestScene { private ClicksPerSecondCalculator calculator = null!; From 8de896a393d14af7c78b17b8f11eaf6d808383d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 19:21:15 +0900 Subject: [PATCH 0969/2686] 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 cd4dfec3d7..2c186a52dd 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6d0827a107..fabef87c28 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 3316bf5a49..89166f924c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -84,7 +84,7 @@ - + From c585f08a3bd3895bea3c5a94a3daf5043ed7baf1 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 8 Sep 2022 19:42:09 +0900 Subject: [PATCH 0970/2686] Fix still inverted condition --- .../Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs index 54b0bc2080..3fc456c411 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("create sprites", () => SetContents(_ => createSprite(lookup_name, Anchor.TopLeft, Vector2.Zero))); AddAssert("sprites present", () => sprites.All(s => s.IsPresent)); AddStep("scale sprite", () => sprites.ForEach(s => s.VectorScale = new Vector2(0, 1))); - AddAssert("sprites not present", () => !sprites.All(s => s.IsPresent)); + AddAssert("sprites not present", () => sprites.All(s => !s.IsPresent)); } [Test] From 4f22616860df51d79b4f7c7e110d0621047da1c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 19:41:04 +0900 Subject: [PATCH 0971/2686] Rename class to match osu! version --- osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs | 8 ++++---- .../UI/{TouchInputField.cs => CatchTouchInputMapper.cs} | 2 +- osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) rename osu.Game.Rulesets.Catch/UI/{TouchInputField.cs => CatchTouchInputMapper.cs} (99%) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs index 24afda4cfa..b510a69f14 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs @@ -12,19 +12,19 @@ namespace osu.Game.Rulesets.Catch.Tests [TestFixture] public class TestSceneCatchTouchInput : OsuTestScene { - private TouchInputField touchInputField = null!; + private CatchTouchInputMapper catchTouchInputMapper = null!; [SetUpSteps] public void SetUpSteps() { - AddStep("create inputfield", () => + AddStep("create input overlay", () => { Child = new CatchInputManager(new CatchRuleset().RulesetInfo) { RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - touchInputField = new TouchInputField + catchTouchInputMapper = new CatchTouchInputMapper { Anchor = Anchor.Centre, Origin = Anchor.Centre @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Catch.Tests [Test] public void TestInputField() { - AddStep("show inputfield", () => touchInputField.Show()); + AddStep("show overlay", () => catchTouchInputMapper.Show()); } } } diff --git a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs similarity index 99% rename from osu.Game.Rulesets.Catch/UI/TouchInputField.cs rename to osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index 80453d6aa3..7607bf60cd 100644 --- a/osu.Game.Rulesets.Catch/UI/TouchInputField.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -16,7 +16,7 @@ using System.Collections.Generic; namespace osu.Game.Rulesets.Catch.UI { - public class TouchInputField : VisibilityContainer + public class CatchTouchInputMapper : VisibilityContainer { public enum TouchCatchAction { diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index b84d0c60d5..ef2936ac94 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.UI [BackgroundDependencyLoader] private void load() { - KeyBindingInputManager.Add(new TouchInputField()); + KeyBindingInputManager.Add(new CatchTouchInputMapper()); } protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay); From b9afe6f4cf86416eba1497cdeaf56ce7ed82cae6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 19:44:29 +0900 Subject: [PATCH 0972/2686] Tidy up code quality --- .../UI/CatchTouchInputMapper.cs | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index 7607bf60cd..bdbd958f6a 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -18,28 +18,17 @@ namespace osu.Game.Rulesets.Catch.UI { public class CatchTouchInputMapper : VisibilityContainer { - public enum TouchCatchAction - { - MoveLeft = 0, - MoveRight = 1, - DashLeft = 2, - DashRight = 3, - None = 4 - } - private Dictionary trackedActions = new Dictionary(); private KeyBindingContainer keyBindingContainer = null!; private Container mainContent = null!; - // Fill values with null because UI is not declared in constructor private ArrowHitbox leftBox = null!; private ArrowHitbox rightBox = null!; private ArrowHitbox leftDashBox = null!; private ArrowHitbox rightDashBox = null!; - // Force input to be prossed even when hidden. public override bool PropagatePositionalInputSubTree => true; public override bool PropagateNonPositionalInputSubTree => true; @@ -151,11 +140,6 @@ namespace osu.Game.Rulesets.Catch.UI return true; } - protected override void OnDragEnd(DragEndEvent e) - { - base.OnDragEnd(e); - } - protected override void OnDrag(DragEvent e) { // I'm not sure if this is posible but let's be safe @@ -167,6 +151,7 @@ namespace osu.Game.Rulesets.Catch.UI base.OnDrag(e); } + protected override void OnTouchMove(TouchMoveEvent e) { // I'm not sure if this is posible but let's be safe @@ -240,6 +225,7 @@ namespace osu.Game.Rulesets.Catch.UI return TouchCatchAction.MoveLeft; if (rightBox.Contains(inputPosition)) return TouchCatchAction.MoveRight; + return TouchCatchAction.None; } @@ -316,5 +302,14 @@ namespace osu.Game.Rulesets.Catch.UI } } } + + public enum TouchCatchAction + { + MoveLeft = 0, + MoveRight = 1, + DashLeft = 2, + DashRight = 3, + None = 4 + } } } From a90ca94a18b3be9db81cbc8c21648dcb4e4fb412 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 8 Sep 2022 19:51:28 +0900 Subject: [PATCH 0973/2686] Remove outdated tests --- .../TestSceneMultiplayerMatchSongSelect.cs | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs index 0ecfc059e4..b87321c047 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs @@ -19,7 +19,6 @@ using osu.Game.Database; using osu.Game.Online.Rooms; using osu.Game.Overlays.Mods; using osu.Game.Rulesets; -using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; @@ -68,37 +67,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded); } - [Test] - public void TestBeatmapRevertedOnExitIfNoSelection() - { - BeatmapInfo selectedBeatmap = null; - - AddStep("select beatmap", - () => songSelect.Carousel.SelectBeatmap(selectedBeatmap = beatmaps.Where(beatmap => beatmap.Ruleset.OnlineID == new OsuRuleset().LegacyID).ElementAt(1))); - AddUntilStep("wait for selection", () => Beatmap.Value.BeatmapInfo.Equals(selectedBeatmap)); - - AddStep("exit song select", () => songSelect.Exit()); - AddAssert("beatmap reverted", () => Beatmap.IsDefault); - } - - [Test] - public void TestModsRevertedOnExitIfNoSelection() - { - AddStep("change mods", () => SelectedMods.Value = new[] { new OsuModDoubleTime() }); - - AddStep("exit song select", () => songSelect.Exit()); - AddAssert("mods reverted", () => SelectedMods.Value.Count == 0); - } - - [Test] - public void TestRulesetRevertedOnExitIfNoSelection() - { - AddStep("change ruleset", () => Ruleset.Value = new CatchRuleset().RulesetInfo); - - AddStep("exit song select", () => songSelect.Exit()); - AddAssert("ruleset reverted", () => Ruleset.Value.Equals(new OsuRuleset().RulesetInfo)); - } - [Test] public void TestBeatmapConfirmed() { From 09fa24c563a8cf476bcf11d88228aadee486c15b Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Thu, 8 Sep 2022 19:12:54 +0800 Subject: [PATCH 0974/2686] new display format --- .../Configuration/ManiaRulesetConfigManager.cs | 2 +- osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs index 8e09a01469..64e1f75e2c 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Mania.Configuration scrollTime => new SettingDescription( rawValue: scrollTime, name: "Scroll Speed", - value: $"{(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / scrollTime)} ({scrollTime}ms)" + value: $"{scrollTime}ms (speed {(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / scrollTime)})" ) ) }; diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs index 622450ac4a..e239068d1d 100644 --- a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs +++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania private class ManiaScrollSlider : OsuSliderBar { - public override LocalisableString TooltipText => $"{(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value)} ({Current.Value}ms)"; + public override LocalisableString TooltipText => $"{Current.Value}ms (speed {(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value)})"; } } } From 888d8b281747b7a34072cc270152aafbe21163d9 Mon Sep 17 00:00:00 2001 From: Josh <43808099+josh-codes@users.noreply.github.com> Date: Thu, 8 Sep 2022 20:39:53 +0800 Subject: [PATCH 0975/2686] Removed redudent code & converted use of `OnDrag to `OnMouseMove` --- .../UI/CatchTouchInputMapper.cs | 47 +++++++------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index bdbd958f6a..7886df69b6 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics; using osuTK.Graphics; using osuTK; using System.Collections.Generic; +using osuTK.Input; namespace osu.Game.Rulesets.Catch.UI { @@ -119,45 +120,29 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool OnMouseDown(MouseDownEvent e) { - if (getTouchCatchActionFromInput(e.ScreenSpaceMousePosition) == TouchCatchAction.None) - return false; - - handleDown(e.Button, e.ScreenSpaceMousePosition); - return true; + return handleDown(e.Button, e.ScreenSpaceMousePosition); } protected override void OnMouseUp(MouseUpEvent e) { - if (getTouchCatchActionFromInput(e.ScreenSpaceMousePosition) == TouchCatchAction.None) - return; - handleUp(e.Button); base.OnMouseUp(e); } - protected override bool OnDragStart(DragStartEvent e) + protected override bool OnMouseMove(MouseMoveEvent e) { - return true; - } + TouchCatchAction touchCatchAction = getTouchCatchActionFromInput(e.ScreenSpaceMousePosition); - protected override void OnDrag(DragEvent e) - { - // I'm not sure if this is posible but let's be safe - if (!trackedActions.ContainsKey(e.Button)) - trackedActions.Add(e.Button, TouchCatchAction.None); + // Loop through the buttons to avoid keeping a button pressed if both mouse buttons are pressed. + foreach (MouseButton i in e.PressedButtons) + trackedActions[i] = touchCatchAction; - trackedActions[e.Button] = getTouchCatchActionFromInput(e.ScreenSpaceMousePosition); calculateActiveKeys(); - - base.OnDrag(e); + return true; } protected override void OnTouchMove(TouchMoveEvent e) { - // I'm not sure if this is posible but let's be safe - if (!trackedActions.ContainsKey(e.Touch.Source)) - trackedActions.Add(e.Touch.Source, TouchCatchAction.None); - trackedActions[e.Touch.Source] = getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position); calculateActiveKeys(); @@ -194,18 +179,20 @@ namespace osu.Game.Rulesets.Catch.UI keyBindingContainer.TriggerReleased(CatchAction.Dash); } - private void handleDown(object source, Vector2 position) + private bool handleDown(object source, Vector2 position) { - Show(); - TouchCatchAction catchAction = getTouchCatchActionFromInput(position); - // Not too sure how this can happen, but let's avoid throwing. - if (trackedActions.ContainsKey(source)) - return; + if (catchAction == TouchCatchAction.None) + return false; + + Show(); + + trackedActions[source] = catchAction; - trackedActions.Add(source, catchAction); calculateActiveKeys(); + + return true; } private void handleUp(object source) From e416c87970de92b0b10e27733c2509bfacdf215c Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Thu, 8 Sep 2022 15:17:22 +0200 Subject: [PATCH 0976/2686] readded approach circles --- .../{OsuModFlash.cs => OsuModFreezeFrame.cs} | 23 +++---------------- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- 2 files changed, 4 insertions(+), 21 deletions(-) rename osu.Game.Rulesets.Osu/Mods/{OsuModFlash.cs => OsuModFreezeFrame.cs} (76%) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs similarity index 76% rename from osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs rename to osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 818eb93bfb..b6b6f4e588 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlash.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -8,13 +8,12 @@ using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModFlash : ModWithVisibilityAdjustment, IHidesApproachCircles, IApplicableToDrawableRuleset + public class OsuModFreezeFrame : ModWithVisibilityAdjustment, IHidesApproachCircles, IApplicableToDrawableRuleset { public override string Name => "Freeze frame"; @@ -26,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Fun; - public override IconUsage? Icon => FontAwesome.Solid.Fire; + public override IconUsage? Icon => FontAwesome.Solid.Camera; public override Type[] IncompatibleMods => new[] { typeof(OsuModTarget), typeof(OsuModStrictTracking) }; @@ -38,7 +37,6 @@ namespace osu.Game.Rulesets.Osu.Mods Precision = .25f }; - public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { (drawableRuleset.Playfield as OsuPlayfield)?.FollowPoints.Hide(); @@ -69,23 +67,8 @@ namespace osu.Game.Rulesets.Osu.Mods protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyFrozenState(hitObject, state); - private void applyFrozenState(DrawableHitObject drawable, ArmedState state) + private void applyFrozenState(DrawableHitObject drawableObject, ArmedState state) { - if (drawable is DrawableSpinner) - return; - - var h = (OsuHitObject)drawable.HitObject; - /* - switch (drawable) - { - case DrawableHitCircle circle: - using (circle.BeginAbsoluteSequence(h.StartTime - h.TimePreempt)) - { - circle.ApproachCircle.Hide(); - } - - break; - }*/ } } } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 6fdf4c3bf8..2b42dc7eef 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -202,7 +202,7 @@ namespace osu.Game.Rulesets.Osu new OsuModNoScope(), new MultiMod(new OsuModMagnetised(), new OsuModRepel()), new ModAdaptiveSpeed(), - new OsuModFlash() + new OsuModFreezeFrame() }; case ModType.System: From 45239fc737423f05f63c93b05e72ef20a33ef267 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Sep 2022 23:03:15 +0900 Subject: [PATCH 0977/2686] Update `TrueGameplayRate` accessing --- .../Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs index 82bf9cfa1e..04774b974f 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond base.Update(); double latestValidTime = clock.CurrentTime; - double earliestTimeValid = latestValidTime - 1000 * gameplayClock.TrueGameplayRate; + double earliestTimeValid = latestValidTime - 1000 * gameplayClock.GetTrueGameplayRate(); int count = 0; From 27aa3552dc03846cf7d23eb7b731b574be20e147 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 00:00:08 +0900 Subject: [PATCH 0978/2686] Update in line with `TrueGameplayRate` changes --- .../Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs index b740c06e03..2dad5e2c32 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using NUnit.Framework; +using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Testing; @@ -107,7 +108,9 @@ namespace osu.Game.Tests.Visual.Gameplay public bool IsRunning => true; - public double TrueGameplayRate { get; set; } = 1; + public double TrueGameplayRate { set => adjustableAudioComponent.Tempo.Value = value; } + + private readonly AudioAdjustments adjustableAudioComponent = new AudioAdjustments(); public void ProcessFrame() { @@ -117,6 +120,9 @@ namespace osu.Game.Tests.Visual.Gameplay public double FramesPerSecond => throw new NotImplementedException(); public FrameTimeInfo TimeInfo => throw new NotImplementedException(); public double StartTime => throw new NotImplementedException(); + + public IAdjustableAudioComponent AdjustmentsFromMods => adjustableAudioComponent; + public IEnumerable NonGameplayAdjustments => throw new NotImplementedException(); public IBindable IsPaused => throw new NotImplementedException(); } From d1e27e8a69d061492e7cf5c8223840de19d6de96 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Thu, 8 Sep 2022 23:14:34 +0800 Subject: [PATCH 0979/2686] add arrow short cut for skin editor basically from `ComposeBlueprintContainer` because they have the same logic --- .../Skinning/Editor/SkinBlueprintContainer.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs index 46f5c1e67f..5a1ef34151 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs +++ b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs @@ -11,9 +11,12 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Screens; using osu.Game.Screens.Edit.Compose.Components; +using osuTK; +using osuTK.Input; namespace osu.Game.Skinning.Editor { @@ -90,6 +93,47 @@ namespace osu.Game.Skinning.Editor base.AddBlueprintFor(item); } + protected override bool OnKeyDown(KeyDownEvent e) + { + switch (e.Key) + { + case Key.Left: + moveSelection(new Vector2(-1, 0)); + return true; + + case Key.Right: + moveSelection(new Vector2(1, 0)); + return true; + + case Key.Up: + moveSelection(new Vector2(0, -1)); + return true; + + case Key.Down: + moveSelection(new Vector2(0, 1)); + return true; + } + + return false; + } + + /// + /// Move the current selection spatially by the specified delta, in screen coordinates (ie. the same coordinates as the blueprints). + /// + /// + private void moveSelection(Vector2 delta) + { + var firstBlueprint = SelectionHandler.SelectedBlueprints.FirstOrDefault(); + + if (firstBlueprint == null) + return; + + // convert to game space coordinates + delta = firstBlueprint.ToScreenSpace(delta) - firstBlueprint.ToScreenSpace(Vector2.Zero); + + SelectionHandler.HandleMovement(new MoveSelectionEvent(firstBlueprint, delta)); + } + protected override SelectionHandler CreateSelectionHandler() => new SkinSelectionHandler(); protected override SelectionBlueprint CreateBlueprintFor(ISkinnableDrawable component) From 2e775e688643176142460c5cc71aee748d7d1418 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Thu, 8 Sep 2022 23:47:55 +0800 Subject: [PATCH 0980/2686] Add test for object move --- osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index bd274dfef5..19d20dd552 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.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. -#nullable disable - using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -22,7 +20,7 @@ namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneSkinEditor : PlayerTestScene { - private SkinEditor skinEditor; + private SkinEditor skinEditor = null!; protected override bool Autoplay => true; @@ -54,7 +52,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestEditComponent() { - BarHitErrorMeter hitErrorMeter = null; + BarHitErrorMeter hitErrorMeter = null!; AddStep("select bar hit error blueprint", () => { @@ -65,6 +63,10 @@ namespace osu.Game.Tests.Visual.Gameplay skinEditor.SelectedComponents.Add(blueprint.Item); }); + AddStep("move by keyboard", () => InputManager.Key(Key.Right)); + + AddAssert("hitErrorMeter moved", () => hitErrorMeter.X != 0); + AddAssert("value is default", () => hitErrorMeter.JudgementLineThickness.IsDefault); AddStep("hover first slider", () => From 38ccd06d5e650ae24507187e207871d476cdcf68 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Thu, 8 Sep 2022 20:42:55 +0200 Subject: [PATCH 0981/2686] Test fix --- osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index e3603ee90c..e2576e2577 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -147,6 +147,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestProcessingWhileHidden() { + const int max_displayed_judgements = 20; AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1)); AddStep("hide displays", () => @@ -155,7 +156,7 @@ namespace osu.Game.Tests.Visual.Gameplay hitErrorMeter.Hide(); }); - AddRepeatStep("hit", () => newJudgement(), 10); + AddRepeatStep("hit", () => newJudgement(), max_displayed_judgements * 2); AddAssert("bars added", () => this.ChildrenOfType().Any()); AddAssert("circle added", () => this.ChildrenOfType().Any()); From 28477f3b9763fe876030b24c03ea884c3bf35930 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 9 Sep 2022 08:55:35 +0900 Subject: [PATCH 0982/2686] Fix inspection --- osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 19d20dd552..578718b7c9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneSkinEditor : PlayerTestScene { - private SkinEditor skinEditor = null!; + private SkinEditor? skinEditor; protected override bool Autoplay => true; @@ -40,13 +40,13 @@ namespace osu.Game.Tests.Visual.Gameplay Player.ScaleTo(0.4f); LoadComponentAsync(skinEditor = new SkinEditor(Player), Add); }); - AddUntilStep("wait for loaded", () => skinEditor.IsLoaded); + AddUntilStep("wait for loaded", () => skinEditor!.IsLoaded); } [Test] public void TestToggleEditor() { - AddToggleStep("toggle editor visibility", _ => skinEditor.ToggleVisibility()); + AddToggleStep("toggle editor visibility", _ => skinEditor!.ToggleVisibility()); } [Test] @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Gameplay var blueprint = skinEditor.ChildrenOfType().First(b => b.Item is BarHitErrorMeter); hitErrorMeter = (BarHitErrorMeter)blueprint.Item; - skinEditor.SelectedComponents.Clear(); + skinEditor!.SelectedComponents.Clear(); skinEditor.SelectedComponents.Add(blueprint.Item); }); From 731d3f3b6358710943b1ed5230bedc3b7c9cfbcf Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 8 Sep 2022 22:06:44 +0900 Subject: [PATCH 0983/2686] Add MaximumStatistics upgrade for databased scores --- osu.Game/BackgroundBeatmapProcessor.cs | 55 ++++++++++++++++++- osu.Game/OsuGameBase.cs | 2 +- osu.Game/Scoring/ScoreImporter.cs | 73 +++++++++++++++++++++++++- osu.Game/Scoring/ScoreManager.cs | 11 +++- 4 files changed, 136 insertions(+), 5 deletions(-) diff --git a/osu.Game/BackgroundBeatmapProcessor.cs b/osu.Game/BackgroundBeatmapProcessor.cs index 14fdb2e1ef..405386660c 100644 --- a/osu.Game/BackgroundBeatmapProcessor.cs +++ b/osu.Game/BackgroundBeatmapProcessor.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Newtonsoft.Json; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -14,6 +15,7 @@ using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Rulesets; +using osu.Game.Scoring; using osu.Game.Screens.Play; namespace osu.Game @@ -23,6 +25,9 @@ namespace osu.Game [Resolved] private RulesetStore rulesetStore { get; set; } = null!; + [Resolved] + private ScoreManager scoreManager { get; set; } = null!; + [Resolved] private RealmAccess realmAccess { get; set; } = null!; @@ -41,11 +46,12 @@ namespace osu.Game { base.LoadComplete(); - Task.Run(() => + Task.Run(async () => { Logger.Log("Beginning background beatmap processing.."); checkForOutdatedStarRatings(); processBeatmapSetsWithMissingMetrics(); + await processScoresWithMissingStatistics(); }).ContinueWith(t => { if (t.Exception?.InnerException is ObjectDisposedException) @@ -140,5 +146,52 @@ namespace osu.Game }); } } + + private async Task processScoresWithMissingStatistics() + { + HashSet scoreIds = new HashSet(); + + Logger.Log("Querying for scores to reprocess..."); + + realmAccess.Run(r => + { + foreach (var score in r.All()) + { + if (score.Statistics.Sum(kvp => kvp.Value) > 0 && score.MaximumStatistics.Sum(kvp => kvp.Value) == 0) + scoreIds.Add(score.ID); + } + }); + + Logger.Log($"Found {scoreIds.Count} scores which require reprocessing."); + + foreach (var id in scoreIds) + { + while (localUserPlayInfo?.IsPlaying.Value == true) + { + Logger.Log("Background processing sleeping due to active gameplay..."); + Thread.Sleep(TimeToSleepDuringGameplay); + } + + try + { + var score = scoreManager.Query(s => s.ID == id); + + await scoreManager.PopulateMaximumStatistics(score); + + // Can't use async overload because we're not on the update thread. + // ReSharper disable once MethodHasAsyncOverload + realmAccess.Write(r => + { + r.Find(id).MaximumStatisticsJson = JsonConvert.SerializeObject(score.MaximumStatistics); + }); + + Logger.Log($"Populated maximum statistics for score {id}"); + } + catch (Exception e) + { + Logger.Log(@$"Failed to populate maximum statistics for {id}: {e}"); + } + } + } } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index c95a281f09..c95dde8759 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -279,7 +279,7 @@ namespace osu.Game dependencies.Cache(difficultyCache = new BeatmapDifficultyCache()); // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() - dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, API, LocalConfig)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, API, LocalConfig, difficultyCache)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, realm, API, Audio, Resources, Host, defaultBeatmap, difficultyCache, performOnlineLookups: true)); diff --git a/osu.Game/Scoring/ScoreImporter.cs b/osu.Game/Scoring/ScoreImporter.cs index 45f827354e..488f5815f8 100644 --- a/osu.Game/Scoring/ScoreImporter.cs +++ b/osu.Game/Scoring/ScoreImporter.cs @@ -5,7 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Newtonsoft.Json; +using osu.Framework.Extensions; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Beatmaps; @@ -16,6 +18,8 @@ using osu.Game.Scoring.Legacy; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; using Realms; namespace osu.Game.Scoring @@ -28,15 +32,17 @@ namespace osu.Game.Scoring private readonly RulesetStore rulesets; private readonly Func beatmaps; + private readonly BeatmapDifficultyCache? difficultyCache; private readonly IAPIProvider api; - public ScoreImporter(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, IAPIProvider api) + public ScoreImporter(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, IAPIProvider api, BeatmapDifficultyCache? difficultyCache = null) : base(storage, realm) { this.rulesets = rulesets; this.beatmaps = beatmaps; this.api = api; + this.difficultyCache = difficultyCache; } protected override ScoreInfo? CreateModel(ArchiveReader archive) @@ -71,6 +77,8 @@ namespace osu.Game.Scoring if (model.BeatmapInfo == null) throw new ArgumentNullException(nameof(model.BeatmapInfo)); if (model.Ruleset == null) throw new ArgumentNullException(nameof(model.Ruleset)); + PopulateMaximumStatistics(model).WaitSafely(); + if (string.IsNullOrEmpty(model.StatisticsJson)) model.StatisticsJson = JsonConvert.SerializeObject(model.Statistics); @@ -78,6 +86,69 @@ namespace osu.Game.Scoring model.MaximumStatisticsJson = JsonConvert.SerializeObject(model.MaximumStatistics); } + /// + /// Populates the for a given . + /// + /// The score to populate the statistics of. + public async Task PopulateMaximumStatistics(ScoreInfo score) + { + if (score.MaximumStatistics.Select(kvp => kvp.Value).Sum() > 0) + return; + + var beatmap = score.BeatmapInfo.Detach(); + var ruleset = score.Ruleset.Detach(); + + // Populate the maximum statistics. + HitResult maxBasicResult = ruleset.CreateInstance().GetHitResults() + .Select(h => h.result) + .Where(h => h.IsBasic()) + .OrderByDescending(Judgement.ToNumericResult).First(); + + foreach ((HitResult result, int count) in score.Statistics) + { + switch (result) + { + case HitResult.LargeTickHit: + case HitResult.LargeTickMiss: + score.MaximumStatistics[HitResult.LargeTickHit] = score.MaximumStatistics.GetValueOrDefault(HitResult.LargeTickHit) + count; + break; + + case HitResult.SmallTickHit: + case HitResult.SmallTickMiss: + score.MaximumStatistics[HitResult.SmallTickHit] = score.MaximumStatistics.GetValueOrDefault(HitResult.SmallTickHit) + count; + break; + + case HitResult.IgnoreHit: + case HitResult.IgnoreMiss: + case HitResult.SmallBonus: + case HitResult.LargeBonus: + break; + + default: + score.MaximumStatistics[maxBasicResult] = score.MaximumStatistics.GetValueOrDefault(maxBasicResult) + count; + break; + } + } + + if (!score.IsLegacyScore) + return; + +#pragma warning disable CS0618 + if (difficultyCache == null) + throw new InvalidOperationException($"Cannot populate legacy score statistics without a {nameof(BeatmapDifficultyCache)}."); + + // In osu! and osu!mania, some judgements affect combo but aren't stored to scores. + // A special hit result is used to pad out the combo value to match, based on the max combo from the difficulty attributes. + StarDifficulty? difficulty = await difficultyCache.GetDifficultyAsync(beatmap, ruleset, score.Mods); + if (difficulty == null) + throw new InvalidOperationException("Failed to populate maximum statistics due to missing difficulty attributes."); + + int maxComboFromStatistics = score.MaximumStatistics.Where(kvp => kvp.Key.AffectsCombo()).Select(kvp => kvp.Value).DefaultIfEmpty(0).Sum(); + if (difficulty.Value.MaxCombo > maxComboFromStatistics) + score.MaximumStatistics[HitResult.LegacyComboIncrease] = difficulty.Value.MaxCombo - maxComboFromStatistics; +#pragma warning restore CS0618 + } + protected override void PostImport(ScoreInfo model, Realm realm, bool batchImport) { base.PostImport(model, realm, batchImport); diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 782590114f..87bb834a75 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -28,12 +28,13 @@ namespace osu.Game.Scoring private readonly OsuConfigManager configManager; private readonly ScoreImporter scoreImporter; - public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, IAPIProvider api, OsuConfigManager configManager = null) + public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, IAPIProvider api, + OsuConfigManager configManager = null, BeatmapDifficultyCache difficultyCache = null) : base(storage, realm) { this.configManager = configManager; - scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm, api) + scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm, api, difficultyCache) { PostNotification = obj => PostNotification?.Invoke(obj) }; @@ -178,6 +179,12 @@ namespace osu.Game.Scoring public Live Import(ScoreInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) => scoreImporter.ImportModel(item, archive, batchImport, cancellationToken); + /// + /// Populates the for a given . + /// + /// The score to populate the statistics of. + public Task PopulateMaximumStatistics(ScoreInfo score) => scoreImporter.PopulateMaximumStatistics(score); + #region Implementation of IPresentImports public Action>> PresentImport From 3b932b46ca8870c25e04a4fdcd1db3e792c18212 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 9 Sep 2022 09:59:39 +0900 Subject: [PATCH 0984/2686] Fix entire TPL thread potentially being consumed during gameplay --- osu.Game/BackgroundBeatmapProcessor.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/BackgroundBeatmapProcessor.cs b/osu.Game/BackgroundBeatmapProcessor.cs index 405386660c..7a38abd071 100644 --- a/osu.Game/BackgroundBeatmapProcessor.cs +++ b/osu.Game/BackgroundBeatmapProcessor.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using osu.Framework.Allocation; @@ -50,7 +49,7 @@ namespace osu.Game { Logger.Log("Beginning background beatmap processing.."); checkForOutdatedStarRatings(); - processBeatmapSetsWithMissingMetrics(); + await processBeatmapSetsWithMissingMetrics(); await processScoresWithMissingStatistics(); }).ContinueWith(t => { @@ -100,7 +99,7 @@ namespace osu.Game } } - private void processBeatmapSetsWithMissingMetrics() + private async Task processBeatmapSetsWithMissingMetrics() { HashSet beatmapSetIds = new HashSet(); @@ -124,7 +123,7 @@ namespace osu.Game while (localUserPlayInfo?.IsPlaying.Value == true) { Logger.Log("Background processing sleeping due to active gameplay..."); - Thread.Sleep(TimeToSleepDuringGameplay); + await Task.Delay(TimeToSleepDuringGameplay); } realmAccess.Run(r => @@ -169,7 +168,7 @@ namespace osu.Game while (localUserPlayInfo?.IsPlaying.Value == true) { Logger.Log("Background processing sleeping due to active gameplay..."); - Thread.Sleep(TimeToSleepDuringGameplay); + await Task.Delay(TimeToSleepDuringGameplay); } try From ba2ef424d4cac407692ad78c7c1c75b44110d419 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 9 Sep 2022 11:30:36 +0900 Subject: [PATCH 0985/2686] Turn score ids into `ulong`s --- osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs | 2 +- osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs index cfa9f77634..a0f76c4e14 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs @@ -154,7 +154,7 @@ namespace osu.Game.Tests.Visual.Online }); } - private int onlineID = 1; + private ulong onlineID = 1; private APIScoresCollection createScores() { diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index d7b97cdddf..2c9f250028 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -81,12 +81,12 @@ namespace osu.Game.Online.API.Requests.Responses public int? LegacyTotalScore { get; set; } [JsonProperty("legacy_score_id")] - public uint? LegacyScoreId { get; set; } + public ulong? LegacyScoreId { get; set; } #region osu-web API additions (not stored to database). [JsonProperty("id")] - public long? ID { get; set; } + public ulong? ID { get; set; } [JsonProperty("user")] public APIUser? User { get; set; } @@ -190,6 +190,6 @@ namespace osu.Game.Online.API.Requests.Responses MaximumStatistics = score.MaximumStatistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value), }; - public long OnlineID => ID ?? -1; + public long OnlineID => (long?)ID ?? -1; } } From 08d0c08750ae7341334a99aefa8920c9922f36f3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 9 Sep 2022 13:57:01 +0900 Subject: [PATCH 0986/2686] Fix async exception by using difficulty calculator directly --- osu.Game/BackgroundBeatmapProcessor.cs | 2 +- osu.Game/OsuGameBase.cs | 2 +- osu.Game/Scoring/ScoreImporter.cs | 34 ++++++++++++-------------- osu.Game/Scoring/ScoreManager.cs | 6 ++--- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/osu.Game/BackgroundBeatmapProcessor.cs b/osu.Game/BackgroundBeatmapProcessor.cs index 7a38abd071..071862146f 100644 --- a/osu.Game/BackgroundBeatmapProcessor.cs +++ b/osu.Game/BackgroundBeatmapProcessor.cs @@ -175,7 +175,7 @@ namespace osu.Game { var score = scoreManager.Query(s => s.ID == id); - await scoreManager.PopulateMaximumStatistics(score); + scoreManager.PopulateMaximumStatistics(score); // Can't use async overload because we're not on the update thread. // ReSharper disable once MethodHasAsyncOverload diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index c95dde8759..c95a281f09 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -279,7 +279,7 @@ namespace osu.Game dependencies.Cache(difficultyCache = new BeatmapDifficultyCache()); // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() - dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, API, LocalConfig, difficultyCache)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, realm, API, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, realm, API, Audio, Resources, Host, defaultBeatmap, difficultyCache, performOnlineLookups: true)); diff --git a/osu.Game/Scoring/ScoreImporter.cs b/osu.Game/Scoring/ScoreImporter.cs index 488f5815f8..5c8e21014c 100644 --- a/osu.Game/Scoring/ScoreImporter.cs +++ b/osu.Game/Scoring/ScoreImporter.cs @@ -3,11 +3,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Newtonsoft.Json; -using osu.Framework.Extensions; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Beatmaps; @@ -32,17 +31,15 @@ namespace osu.Game.Scoring private readonly RulesetStore rulesets; private readonly Func beatmaps; - private readonly BeatmapDifficultyCache? difficultyCache; private readonly IAPIProvider api; - public ScoreImporter(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, IAPIProvider api, BeatmapDifficultyCache? difficultyCache = null) + public ScoreImporter(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, IAPIProvider api) : base(storage, realm) { this.rulesets = rulesets; this.beatmaps = beatmaps; this.api = api; - this.difficultyCache = difficultyCache; } protected override ScoreInfo? CreateModel(ArchiveReader archive) @@ -77,7 +74,7 @@ namespace osu.Game.Scoring if (model.BeatmapInfo == null) throw new ArgumentNullException(nameof(model.BeatmapInfo)); if (model.Ruleset == null) throw new ArgumentNullException(nameof(model.Ruleset)); - PopulateMaximumStatistics(model).WaitSafely(); + PopulateMaximumStatistics(model); if (string.IsNullOrEmpty(model.StatisticsJson)) model.StatisticsJson = JsonConvert.SerializeObject(model.Statistics); @@ -90,19 +87,22 @@ namespace osu.Game.Scoring /// Populates the for a given . /// /// The score to populate the statistics of. - public async Task PopulateMaximumStatistics(ScoreInfo score) + public void PopulateMaximumStatistics(ScoreInfo score) { if (score.MaximumStatistics.Select(kvp => kvp.Value).Sum() > 0) return; var beatmap = score.BeatmapInfo.Detach(); var ruleset = score.Ruleset.Detach(); + var rulesetInstance = ruleset.CreateInstance(); + + Debug.Assert(rulesetInstance != null); // Populate the maximum statistics. - HitResult maxBasicResult = ruleset.CreateInstance().GetHitResults() - .Select(h => h.result) - .Where(h => h.IsBasic()) - .OrderByDescending(Judgement.ToNumericResult).First(); + HitResult maxBasicResult = rulesetInstance.GetHitResults() + .Select(h => h.result) + .Where(h => h.IsBasic()) + .OrderByDescending(Judgement.ToNumericResult).First(); foreach ((HitResult result, int count) in score.Statistics) { @@ -134,18 +134,14 @@ namespace osu.Game.Scoring return; #pragma warning disable CS0618 - if (difficultyCache == null) - throw new InvalidOperationException($"Cannot populate legacy score statistics without a {nameof(BeatmapDifficultyCache)}."); - // In osu! and osu!mania, some judgements affect combo but aren't stored to scores. // A special hit result is used to pad out the combo value to match, based on the max combo from the difficulty attributes. - StarDifficulty? difficulty = await difficultyCache.GetDifficultyAsync(beatmap, ruleset, score.Mods); - if (difficulty == null) - throw new InvalidOperationException("Failed to populate maximum statistics due to missing difficulty attributes."); + var calculator = rulesetInstance.CreateDifficultyCalculator(beatmaps().GetWorkingBeatmap(beatmap)); + var attributes = calculator.Calculate(score.Mods); int maxComboFromStatistics = score.MaximumStatistics.Where(kvp => kvp.Key.AffectsCombo()).Select(kvp => kvp.Value).DefaultIfEmpty(0).Sum(); - if (difficulty.Value.MaxCombo > maxComboFromStatistics) - score.MaximumStatistics[HitResult.LegacyComboIncrease] = difficulty.Value.MaxCombo - maxComboFromStatistics; + if (attributes.MaxCombo > maxComboFromStatistics) + score.MaximumStatistics[HitResult.LegacyComboIncrease] = attributes.MaxCombo - maxComboFromStatistics; #pragma warning restore CS0618 } diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 87bb834a75..6bb31eb4db 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -29,12 +29,12 @@ namespace osu.Game.Scoring private readonly ScoreImporter scoreImporter; public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, RealmAccess realm, IAPIProvider api, - OsuConfigManager configManager = null, BeatmapDifficultyCache difficultyCache = null) + OsuConfigManager configManager = null) : base(storage, realm) { this.configManager = configManager; - scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm, api, difficultyCache) + scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm, api) { PostNotification = obj => PostNotification?.Invoke(obj) }; @@ -183,7 +183,7 @@ namespace osu.Game.Scoring /// Populates the for a given . /// /// The score to populate the statistics of. - public Task PopulateMaximumStatistics(ScoreInfo score) => scoreImporter.PopulateMaximumStatistics(score); + public void PopulateMaximumStatistics(ScoreInfo score) => scoreImporter.PopulateMaximumStatistics(score); #region Implementation of IPresentImports From 20ffbc4676a60e6c192131ce33678e2fdada6136 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 14:01:52 +0900 Subject: [PATCH 0987/2686] Fix beat sync stopping after returning to menu from a failed play Closes #20193. Explanation is inline comment. --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 11 +++++++++++ osu.Game/OsuGameBase.cs | 5 ----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index a4787a34e8..3c528ba838 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -121,6 +121,17 @@ namespace osu.Game.Beatmaps protected override void Update() { base.Update(); + + if (Source != null && Source is not IAdjustableClock && Source.CurrentTime < finalClockSource.CurrentTime) + { + // InterpolatingFramedClock won't interpolate backwards unless its source has an ElapsedFrameTime. + // See https://github.com/ppy/osu-framework/blob/ba1385330cc501f34937e08257e586c84e35d772/osu.Framework/Timing/InterpolatingFramedClock.cs#L91-L93 + // This is not always the case here when doing large seeks. + // (Of note, this is not an issue if the source is adjustable, as the source is seeked to be in time by DecoupleableInterpolatingFramedClock). + // Rather than trying to get around this by fixing the framework clock stack, let's work around it for now. + Seek(Source.CurrentTime); + } + finalClockSource.ProcessFrame(); } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index c95a281f09..97142d5472 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -390,11 +390,6 @@ namespace osu.Game var framedClock = new FramedClock(beatmap.Track); beatmapClock.ChangeSource(framedClock); - - // Normally the internal decoupled clock will seek the *track* to the decoupled time, but we blocked this. - // It won't behave nicely unless we also set it to the track's time. - // Probably another thing which should be fixed in the decoupled mess (or just replaced). - beatmapClock.Seek(beatmap.Track.CurrentTime); } protected virtual void InitialiseFonts() From 64cf6b9014aa0db328722e33e17f4b6ff2e64c98 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 14:35:35 +0900 Subject: [PATCH 0988/2686] Compare with decoupled clock directly to avoid including offsets --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index 3c528ba838..594663e7f2 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -122,7 +122,7 @@ namespace osu.Game.Beatmaps { base.Update(); - if (Source != null && Source is not IAdjustableClock && Source.CurrentTime < finalClockSource.CurrentTime) + if (Source != null && Source is not IAdjustableClock && Source.CurrentTime < decoupledClock.CurrentTime) { // InterpolatingFramedClock won't interpolate backwards unless its source has an ElapsedFrameTime. // See https://github.com/ppy/osu-framework/blob/ba1385330cc501f34937e08257e586c84e35d772/osu.Framework/Timing/InterpolatingFramedClock.cs#L91-L93 From d6748d6921117a65846da635a45e0c6d04a5eef8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 14:35:47 +0900 Subject: [PATCH 0989/2686] Avoid double call to `ProcessFrame` --- osu.Game/Beatmaps/FramedBeatmapClock.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index 594663e7f2..c7050cc50f 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -131,8 +131,8 @@ namespace osu.Game.Beatmaps // Rather than trying to get around this by fixing the framework clock stack, let's work around it for now. Seek(Source.CurrentTime); } - - finalClockSource.ProcessFrame(); + else + finalClockSource.ProcessFrame(); } public double TotalAppliedOffset From 856dbbba692a9d1ad31561a78a174c959a05a586 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 14:52:46 +0900 Subject: [PATCH 0990/2686] Fix attempting to use "home" key binding while exiting game causing errors --- osu.Game/OsuGame.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 108153fd9d..9e2384322a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -839,7 +839,9 @@ namespace osu.Game OnHome = delegate { CloseAllOverlays(false); - menuScreen?.MakeCurrent(); + + if (menuScreen?.GetChildScreen() != null) + menuScreen.MakeCurrent(); }, }, topMostOverlayContent.Add); From 2709a4d3984fffd805655ddc722bc72918c63875 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 15:04:25 +0900 Subject: [PATCH 0991/2686] Ensure overlay is always shown when movement is detected on mouse or keyboard --- osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index 7886df69b6..1abca2ae98 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -131,6 +131,8 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool OnMouseMove(MouseMoveEvent e) { + Show(); + TouchCatchAction touchCatchAction = getTouchCatchActionFromInput(e.ScreenSpaceMousePosition); // Loop through the buttons to avoid keeping a button pressed if both mouse buttons are pressed. @@ -143,6 +145,8 @@ namespace osu.Game.Rulesets.Catch.UI protected override void OnTouchMove(TouchMoveEvent e) { + Show(); + trackedActions[e.Touch.Source] = getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position); calculateActiveKeys(); @@ -186,8 +190,6 @@ namespace osu.Game.Rulesets.Catch.UI if (catchAction == TouchCatchAction.None) return false; - Show(); - trackedActions[source] = catchAction; calculateActiveKeys(); From 715e9018da3dd4d57084cbdc76c84100f712a3fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 15:11:26 +0900 Subject: [PATCH 0992/2686] Tidy up code and naming --- .../UI/CatchTouchInputMapper.cs | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index 1abca2ae98..c17946bdb1 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -19,16 +19,16 @@ namespace osu.Game.Rulesets.Catch.UI { public class CatchTouchInputMapper : VisibilityContainer { - private Dictionary trackedActions = new Dictionary(); + private Dictionary trackedActionSources = new Dictionary(); private KeyBindingContainer keyBindingContainer = null!; private Container mainContent = null!; - private ArrowHitbox leftBox = null!; - private ArrowHitbox rightBox = null!; - private ArrowHitbox leftDashBox = null!; - private ArrowHitbox rightDashBox = null!; + private InputArea leftBox = null!; + private InputArea rightBox = null!; + private InputArea leftDashBox = null!; + private InputArea rightDashBox = null!; public override bool PropagatePositionalInputSubTree => true; public override bool PropagateNonPositionalInputSubTree => true; @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Catch.UI Origin = Anchor.CentreLeft, Children = new Drawable[] { - leftBox = new ArrowHitbox(TouchCatchAction.MoveLeft, ref trackedActions, colours.Gray3) + leftBox = new InputArea(TouchCatchAction.MoveLeft, ref trackedActionSources, colours.Gray3) { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Catch.UI RelativePositionAxes = Axes.Both, Width = 0.5f, }, - leftDashBox = new ArrowHitbox(TouchCatchAction.DashLeft, ref trackedActions, colours.Gray2) + leftDashBox = new InputArea(TouchCatchAction.DashLeft, ref trackedActionSources, colours.Gray2) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Catch.UI Origin = Anchor.CentreRight, Children = new Drawable[] { - rightBox = new ArrowHitbox(TouchCatchAction.MoveRight, ref trackedActions, colours.Gray3) + rightBox = new InputArea(TouchCatchAction.MoveRight, ref trackedActionSources, colours.Gray3) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Catch.UI RelativePositionAxes = Axes.Both, Width = 0.5f, }, - rightDashBox = new ArrowHitbox(TouchCatchAction.DashRight, ref trackedActions, colours.Gray2) + rightDashBox = new InputArea(TouchCatchAction.DashRight, ref trackedActionSources, colours.Gray2) { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, @@ -137,7 +137,7 @@ namespace osu.Game.Rulesets.Catch.UI // Loop through the buttons to avoid keeping a button pressed if both mouse buttons are pressed. foreach (MouseButton i in e.PressedButtons) - trackedActions[i] = touchCatchAction; + trackedActionSources[i] = touchCatchAction; calculateActiveKeys(); return true; @@ -147,7 +147,7 @@ namespace osu.Game.Rulesets.Catch.UI { Show(); - trackedActions[e.Touch.Source] = getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position); + trackedActionSources[e.Touch.Source] = getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position); calculateActiveKeys(); base.OnTouchMove(e); @@ -165,24 +165,6 @@ namespace osu.Game.Rulesets.Catch.UI base.OnTouchUp(e); } - private void calculateActiveKeys() - { - if (trackedActions.ContainsValue(TouchCatchAction.DashLeft) || trackedActions.ContainsValue(TouchCatchAction.MoveLeft)) - keyBindingContainer.TriggerPressed(CatchAction.MoveLeft); - else - keyBindingContainer.TriggerReleased(CatchAction.MoveLeft); - - if (trackedActions.ContainsValue(TouchCatchAction.DashRight) || trackedActions.ContainsValue(TouchCatchAction.MoveRight)) - keyBindingContainer.TriggerPressed(CatchAction.MoveRight); - else - keyBindingContainer.TriggerReleased(CatchAction.MoveRight); - - if (trackedActions.ContainsValue(TouchCatchAction.DashRight) || trackedActions.ContainsValue(TouchCatchAction.DashLeft)) - keyBindingContainer.TriggerPressed(CatchAction.Dash); - else - keyBindingContainer.TriggerReleased(CatchAction.Dash); - } - private bool handleDown(object source, Vector2 position) { TouchCatchAction catchAction = getTouchCatchActionFromInput(position); @@ -190,7 +172,7 @@ namespace osu.Game.Rulesets.Catch.UI if (catchAction == TouchCatchAction.None) return false; - trackedActions[source] = catchAction; + trackedActionSources[source] = catchAction; calculateActiveKeys(); @@ -199,11 +181,29 @@ namespace osu.Game.Rulesets.Catch.UI private void handleUp(object source) { - trackedActions.Remove(source); + trackedActionSources.Remove(source); calculateActiveKeys(); } + private void calculateActiveKeys() + { + if (trackedActionSources.ContainsValue(TouchCatchAction.DashLeft) || trackedActionSources.ContainsValue(TouchCatchAction.MoveLeft)) + keyBindingContainer.TriggerPressed(CatchAction.MoveLeft); + else + keyBindingContainer.TriggerReleased(CatchAction.MoveLeft); + + if (trackedActionSources.ContainsValue(TouchCatchAction.DashRight) || trackedActionSources.ContainsValue(TouchCatchAction.MoveRight)) + keyBindingContainer.TriggerPressed(CatchAction.MoveRight); + else + keyBindingContainer.TriggerReleased(CatchAction.MoveRight); + + if (trackedActionSources.ContainsValue(TouchCatchAction.DashRight) || trackedActionSources.ContainsValue(TouchCatchAction.DashLeft)) + keyBindingContainer.TriggerPressed(CatchAction.Dash); + else + keyBindingContainer.TriggerReleased(CatchAction.Dash); + } + private TouchCatchAction getTouchCatchActionFromInput(Vector2 inputPosition) { if (leftDashBox.Contains(inputPosition)) @@ -228,7 +228,7 @@ namespace osu.Game.Rulesets.Catch.UI mainContent.FadeOut(300); } - private class ArrowHitbox : CompositeDrawable, IKeyBindingHandler + private class InputArea : CompositeDrawable, IKeyBindingHandler { private readonly TouchCatchAction handledAction; @@ -238,7 +238,7 @@ namespace osu.Game.Rulesets.Catch.UI private bool isHiglighted; - public ArrowHitbox(TouchCatchAction handledAction, ref Dictionary trackedActions, Color4 colour) + public InputArea(TouchCatchAction handledAction, ref Dictionary trackedActions, Color4 colour) { this.handledAction = handledAction; this.trackedActions = trackedActions; From a42c1af09ea2571d20afeb5435e4388af4225c68 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 15:19:30 +0900 Subject: [PATCH 0993/2686] Tidy up highlighting code and ensure read-only access to dictionary by highlight areas --- .../UI/CatchTouchInputMapper.cs | 90 ++++++++----------- 1 file changed, 35 insertions(+), 55 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index c17946bdb1..58cda7fef4 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -1,8 +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.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; -using System.Diagnostics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -10,16 +11,18 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics; -using osuTK.Graphics; using osuTK; -using System.Collections.Generic; +using osuTK.Graphics; using osuTK.Input; namespace osu.Game.Rulesets.Catch.UI { public class CatchTouchInputMapper : VisibilityContainer { - private Dictionary trackedActionSources = new Dictionary(); + public override bool PropagatePositionalInputSubTree => true; + public override bool PropagateNonPositionalInputSubTree => true; + + private readonly Dictionary trackedActionSources = new Dictionary(); private KeyBindingContainer keyBindingContainer = null!; @@ -30,17 +33,11 @@ namespace osu.Game.Rulesets.Catch.UI private InputArea leftDashBox = null!; private InputArea rightDashBox = null!; - public override bool PropagatePositionalInputSubTree => true; - public override bool PropagateNonPositionalInputSubTree => true; - [BackgroundDependencyLoader] private void load(CatchInputManager catchInputManager, OsuColour colours) { - Debug.Assert(catchInputManager.KeyBindingContainer != null); - keyBindingContainer = catchInputManager.KeyBindingContainer; - // Container should handle input everywhere. RelativeSizeAxes = Axes.Both; Children = new Drawable[] @@ -48,7 +45,6 @@ namespace osu.Game.Rulesets.Catch.UI mainContent = new Container { RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, Alpha = 0, Children = new Drawable[] { @@ -56,25 +52,18 @@ namespace osu.Game.Rulesets.Catch.UI { RelativeSizeAxes = Axes.Both, Width = 0.15f, - Height = 1, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, Children = new Drawable[] { - leftBox = new InputArea(TouchCatchAction.MoveLeft, ref trackedActionSources, colours.Gray3) + leftBox = new InputArea(TouchCatchAction.MoveLeft, trackedActionSources, colours.Gray3) { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, Width = 0.5f, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, }, - leftDashBox = new InputArea(TouchCatchAction.DashLeft, ref trackedActionSources, colours.Gray2) + leftDashBox = new InputArea(TouchCatchAction.DashLeft, trackedActionSources, colours.Gray2) { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, Width = 0.5f, } } @@ -83,26 +72,21 @@ namespace osu.Game.Rulesets.Catch.UI { RelativeSizeAxes = Axes.Both, Width = 0.15f, - Height = 1, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, Children = new Drawable[] { - rightBox = new InputArea(TouchCatchAction.MoveRight, ref trackedActionSources, colours.Gray3) + rightBox = new InputArea(TouchCatchAction.MoveRight, trackedActionSources, colours.Gray3) { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, Width = 0.5f, }, - rightDashBox = new InputArea(TouchCatchAction.DashRight, ref trackedActionSources, colours.Gray2) + rightDashBox = new InputArea(TouchCatchAction.DashRight, trackedActionSources, colours.Gray2) { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, Width = 0.5f, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, }, } }, @@ -218,15 +202,9 @@ namespace osu.Game.Rulesets.Catch.UI return TouchCatchAction.None; } - protected override void PopIn() - { - mainContent.FadeIn(500, Easing.OutQuint); - } + protected override void PopIn() => mainContent.FadeIn(500, Easing.OutQuint); - protected override void PopOut() - { - mainContent.FadeOut(300); - } + protected override void PopOut() => mainContent.FadeOut(300); private class InputArea : CompositeDrawable, IKeyBindingHandler { @@ -234,11 +212,11 @@ namespace osu.Game.Rulesets.Catch.UI private readonly Box overlay; - private readonly Dictionary trackedActions; + private readonly IEnumerable> trackedActions; - private bool isHiglighted; + private bool isHighlighted; - public InputArea(TouchCatchAction handledAction, ref Dictionary trackedActions, Color4 colour) + public InputArea(TouchCatchAction handledAction, IEnumerable> trackedActions, Color4 colour) { this.handledAction = handledAction; this.trackedActions = trackedActions; @@ -273,22 +251,24 @@ namespace osu.Game.Rulesets.Catch.UI public bool OnPressed(KeyBindingPressEvent _) { - if (trackedActions.ContainsValue(handledAction)) - { - isHiglighted = true; - overlay.FadeTo(0.5f, 80, Easing.OutQuint); - } - + updateHighlight(); return false; } public void OnReleased(KeyBindingReleaseEvent _) { - if (isHiglighted && !trackedActions.ContainsValue(handledAction)) - { - isHiglighted = false; - overlay.FadeOut(1000, Easing.Out); - } + updateHighlight(); + } + + private void updateHighlight() + { + bool isHandling = trackedActions.Any(a => a.Value == handledAction); + + if (isHandling == isHighlighted) + return; + + isHighlighted = isHandling; + overlay.FadeTo(isHighlighted ? 0.5f : 0, isHighlighted ? 80 : 400, Easing.OutQuint); } } From 5852a09003fdd41c065f93e64b8d412cf6bfcee0 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Fri, 9 Sep 2022 08:21:33 +0200 Subject: [PATCH 0994/2686] small fix --- osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index e2576e2577..7c668adba5 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -165,7 +165,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("ensure max circles not exceeded", () => { return this.ChildrenOfType() - .All(m => m.ChildrenOfType().Count() <= 10); + .All(m => m.ChildrenOfType().Count() <= max_displayed_judgements); }); AddStep("show displays", () => From e6ba95ee16e7595f748f2ee39a94289918a47327 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 15:22:12 +0900 Subject: [PATCH 0995/2686] Don't bother calculating active keys if input source was not handled --- osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index 58cda7fef4..847814c0ea 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -149,15 +150,14 @@ namespace osu.Game.Rulesets.Catch.UI base.OnTouchUp(e); } - private bool handleDown(object source, Vector2 position) + private bool handleDown(object inputSource, Vector2 position) { TouchCatchAction catchAction = getTouchCatchActionFromInput(position); if (catchAction == TouchCatchAction.None) return false; - trackedActionSources[source] = catchAction; - + trackedActionSources[inputSource] = catchAction; calculateActiveKeys(); return true; @@ -165,9 +165,8 @@ namespace osu.Game.Rulesets.Catch.UI private void handleUp(object source) { - trackedActionSources.Remove(source); - - calculateActiveKeys(); + if (trackedActionSources.Remove(source)) + calculateActiveKeys(); } private void calculateActiveKeys() From ba951b76f73b16c6ea7b1305a78697bea90a6fc4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 15:28:40 +0900 Subject: [PATCH 0996/2686] Unify and simplify input handling code --- .../UI/CatchTouchInputMapper.cs | 63 +++++++++---------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index 847814c0ea..3d634c4e00 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -108,40 +107,30 @@ namespace osu.Game.Rulesets.Catch.UI return handleDown(e.Button, e.ScreenSpaceMousePosition); } - protected override void OnMouseUp(MouseUpEvent e) + protected override bool OnTouchDown(TouchDownEvent e) { - handleUp(e.Button); - base.OnMouseUp(e); + handleDown(e.Touch.Source, e.ScreenSpaceTouch.Position); + return true; } protected override bool OnMouseMove(MouseMoveEvent e) { - Show(); - - TouchCatchAction touchCatchAction = getTouchCatchActionFromInput(e.ScreenSpaceMousePosition); - - // Loop through the buttons to avoid keeping a button pressed if both mouse buttons are pressed. - foreach (MouseButton i in e.PressedButtons) - trackedActionSources[i] = touchCatchAction; - - calculateActiveKeys(); + // multiple mouse buttons may be pressed and handling the same action. + foreach (MouseButton button in e.PressedButtons) + handleMove(button, e.ScreenSpaceMousePosition); return true; } protected override void OnTouchMove(TouchMoveEvent e) { - Show(); - - trackedActionSources[e.Touch.Source] = getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position); - calculateActiveKeys(); - + handleMove(e.Touch.Source, e.ScreenSpaceTouch.Position); base.OnTouchMove(e); } - protected override bool OnTouchDown(TouchDownEvent e) + protected override void OnMouseUp(MouseUpEvent e) { - handleDown(e.Touch.Source, e.ScreenSpaceTouch.Position); - return true; + handleUp(e.Button); + base.OnMouseUp(e); } protected override void OnTouchUp(TouchUpEvent e) @@ -150,15 +139,23 @@ namespace osu.Game.Rulesets.Catch.UI base.OnTouchUp(e); } - private bool handleDown(object inputSource, Vector2 position) + private void handleMove(object inputSource, Vector2 screenSpaceInputPosition) { - TouchCatchAction catchAction = getTouchCatchActionFromInput(position); + Show(); - if (catchAction == TouchCatchAction.None) + trackedActionSources[inputSource] = getTouchCatchActionFromInput(screenSpaceInputPosition); + updatePressedActions(); + } + + private bool handleDown(object inputSource, Vector2 screenSpaceInputPosition) + { + TouchCatchAction action = getTouchCatchActionFromInput(screenSpaceInputPosition); + + if (action == TouchCatchAction.None) return false; - trackedActionSources[inputSource] = catchAction; - calculateActiveKeys(); + trackedActionSources[inputSource] = action; + updatePressedActions(); return true; } @@ -166,10 +163,10 @@ namespace osu.Game.Rulesets.Catch.UI private void handleUp(object source) { if (trackedActionSources.Remove(source)) - calculateActiveKeys(); + updatePressedActions(); } - private void calculateActiveKeys() + private void updatePressedActions() { if (trackedActionSources.ContainsValue(TouchCatchAction.DashLeft) || trackedActionSources.ContainsValue(TouchCatchAction.MoveLeft)) keyBindingContainer.TriggerPressed(CatchAction.MoveLeft); @@ -187,15 +184,15 @@ namespace osu.Game.Rulesets.Catch.UI keyBindingContainer.TriggerReleased(CatchAction.Dash); } - private TouchCatchAction getTouchCatchActionFromInput(Vector2 inputPosition) + private TouchCatchAction getTouchCatchActionFromInput(Vector2 screenSpaceInputPosition) { - if (leftDashBox.Contains(inputPosition)) + if (leftDashBox.Contains(screenSpaceInputPosition)) return TouchCatchAction.DashLeft; - if (rightDashBox.Contains(inputPosition)) + if (rightDashBox.Contains(screenSpaceInputPosition)) return TouchCatchAction.DashRight; - if (leftBox.Contains(inputPosition)) + if (leftBox.Contains(screenSpaceInputPosition)) return TouchCatchAction.MoveLeft; - if (rightBox.Contains(inputPosition)) + if (rightBox.Contains(screenSpaceInputPosition)) return TouchCatchAction.MoveRight; return TouchCatchAction.None; From 64eaf461ac9ce39a9f13ae082b4f56eaacf83a49 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 15:58:43 +0900 Subject: [PATCH 0997/2686] Simplify input handling even further --- .../UI/CatchTouchInputMapper.cs | 97 +++++++++---------- 1 file changed, 46 insertions(+), 51 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index 3d634c4e00..13333ecc61 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -36,6 +35,8 @@ namespace osu.Game.Rulesets.Catch.UI [BackgroundDependencyLoader] private void load(CatchInputManager catchInputManager, OsuColour colours) { + const float width = 0.15f; + keyBindingContainer = catchInputManager.KeyBindingContainer; RelativeSizeAxes = Axes.Both; @@ -51,7 +52,7 @@ namespace osu.Game.Rulesets.Catch.UI new Container { RelativeSizeAxes = Axes.Both, - Width = 0.15f, + Width = width, Children = new Drawable[] { leftBox = new InputArea(TouchCatchAction.MoveLeft, trackedActionSources, colours.Gray3) @@ -71,7 +72,7 @@ namespace osu.Game.Rulesets.Catch.UI new Container { RelativeSizeAxes = Axes.Both, - Width = 0.15f, + Width = width, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Children = new Drawable[] @@ -104,70 +105,69 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool OnMouseDown(MouseDownEvent e) { - return handleDown(e.Button, e.ScreenSpaceMousePosition); + return updateAction(e.Button, getTouchCatchActionFromInput(e.ScreenSpaceMousePosition)); } protected override bool OnTouchDown(TouchDownEvent e) { - handleDown(e.Touch.Source, e.ScreenSpaceTouch.Position); - return true; + return updateAction(e.Touch.Source, getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position)); } protected override bool OnMouseMove(MouseMoveEvent e) { + Show(); + + TouchCatchAction? action = getTouchCatchActionFromInput(e.ScreenSpaceMousePosition); + // multiple mouse buttons may be pressed and handling the same action. foreach (MouseButton button in e.PressedButtons) - handleMove(button, e.ScreenSpaceMousePosition); - return true; + updateAction(button, action); + + return false; } protected override void OnTouchMove(TouchMoveEvent e) { - handleMove(e.Touch.Source, e.ScreenSpaceTouch.Position); + updateAction(e.Touch.Source, getTouchCatchActionFromInput(e.ScreenSpaceTouch.Position)); base.OnTouchMove(e); } protected override void OnMouseUp(MouseUpEvent e) { - handleUp(e.Button); + updateAction(e.Button, null); base.OnMouseUp(e); } protected override void OnTouchUp(TouchUpEvent e) { - handleUp(e.Touch.Source); + updateAction(e.Touch.Source, null); base.OnTouchUp(e); } - private void handleMove(object inputSource, Vector2 screenSpaceInputPosition) + private bool updateAction(object source, TouchCatchAction? newAction) { - Show(); + TouchCatchAction? actionBefore = null; - trackedActionSources[inputSource] = getTouchCatchActionFromInput(screenSpaceInputPosition); - updatePressedActions(); - } + if (trackedActionSources.TryGetValue(source, out TouchCatchAction found)) + actionBefore = found; - private bool handleDown(object inputSource, Vector2 screenSpaceInputPosition) - { - TouchCatchAction action = getTouchCatchActionFromInput(screenSpaceInputPosition); + if (actionBefore != newAction) + { + if (newAction != null) + trackedActionSources[source] = newAction.Value; + else + trackedActionSources.Remove(source); - if (action == TouchCatchAction.None) - return false; - - trackedActionSources[inputSource] = action; - updatePressedActions(); - - return true; - } - - private void handleUp(object source) - { - if (trackedActionSources.Remove(source)) updatePressedActions(); + } + + return newAction != null; } private void updatePressedActions() { + Show(); + if (trackedActionSources.ContainsValue(TouchCatchAction.DashLeft) || trackedActionSources.ContainsValue(TouchCatchAction.MoveLeft)) keyBindingContainer.TriggerPressed(CatchAction.MoveLeft); else @@ -178,13 +178,13 @@ namespace osu.Game.Rulesets.Catch.UI else keyBindingContainer.TriggerReleased(CatchAction.MoveRight); - if (trackedActionSources.ContainsValue(TouchCatchAction.DashRight) || trackedActionSources.ContainsValue(TouchCatchAction.DashLeft)) + if (trackedActionSources.ContainsValue(TouchCatchAction.DashLeft) || trackedActionSources.ContainsValue(TouchCatchAction.DashRight)) keyBindingContainer.TriggerPressed(CatchAction.Dash); else keyBindingContainer.TriggerReleased(CatchAction.Dash); } - private TouchCatchAction getTouchCatchActionFromInput(Vector2 screenSpaceInputPosition) + private TouchCatchAction? getTouchCatchActionFromInput(Vector2 screenSpaceInputPosition) { if (leftDashBox.Contains(screenSpaceInputPosition)) return TouchCatchAction.DashLeft; @@ -195,18 +195,18 @@ namespace osu.Game.Rulesets.Catch.UI if (rightBox.Contains(screenSpaceInputPosition)) return TouchCatchAction.MoveRight; - return TouchCatchAction.None; + return null; } - protected override void PopIn() => mainContent.FadeIn(500, Easing.OutQuint); + protected override void PopIn() => mainContent.FadeIn(300, Easing.OutQuint); - protected override void PopOut() => mainContent.FadeOut(300); + protected override void PopOut() => mainContent.FadeOut(300, Easing.OutQuint); private class InputArea : CompositeDrawable, IKeyBindingHandler { private readonly TouchCatchAction handledAction; - private readonly Box overlay; + private readonly Box highlightOverlay; private readonly IEnumerable> trackedActions; @@ -221,24 +221,20 @@ namespace osu.Game.Rulesets.Catch.UI { new Container { - Width = 1, RelativeSizeAxes = Axes.Both, Children = new Drawable[] { new Box { + RelativeSizeAxes = Axes.Both, Alpha = 0.8f, Colour = colour, - Width = 1, - RelativeSizeAxes = Axes.Both, }, - overlay = new Box + highlightOverlay = new Box { - Alpha = 0, - Colour = colour.Multiply(1.4f), - Blending = BlendingParameters.Additive, - Width = 1, RelativeSizeAxes = Axes.Both, + Alpha = 0, + Blending = BlendingParameters.Additive, } } } @@ -264,17 +260,16 @@ namespace osu.Game.Rulesets.Catch.UI return; isHighlighted = isHandling; - overlay.FadeTo(isHighlighted ? 0.5f : 0, isHighlighted ? 80 : 400, Easing.OutQuint); + highlightOverlay.FadeTo(isHighlighted ? 0.1f : 0, isHighlighted ? 80 : 400, Easing.OutQuint); } } public enum TouchCatchAction { - MoveLeft = 0, - MoveRight = 1, - DashLeft = 2, - DashRight = 3, - None = 4 + MoveLeft, + MoveRight, + DashLeft, + DashRight, } } } From f3fc8af6ee9fde39b0b4c644c2bc702ae0242107 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 16:03:36 +0900 Subject: [PATCH 0998/2686] Adjust visuals --- .../UI/CatchTouchInputMapper.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index 13333ecc61..cdb587ad64 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -11,7 +11,6 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics; using osuTK; -using osuTK.Graphics; using osuTK.Input; namespace osu.Game.Rulesets.Catch.UI @@ -55,18 +54,19 @@ namespace osu.Game.Rulesets.Catch.UI Width = width, Children = new Drawable[] { - leftBox = new InputArea(TouchCatchAction.MoveLeft, trackedActionSources, colours.Gray3) + leftDashBox = new InputArea(TouchCatchAction.DashLeft, trackedActionSources) { RelativeSizeAxes = Axes.Both, Width = 0.5f, + }, + leftBox = new InputArea(TouchCatchAction.MoveLeft, trackedActionSources) + { + RelativeSizeAxes = Axes.Both, + Width = 0.5f, + Colour = colours.GrayC, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }, - leftDashBox = new InputArea(TouchCatchAction.DashLeft, trackedActionSources, colours.Gray2) - { - RelativeSizeAxes = Axes.Both, - Width = 0.5f, - } } }, new Container @@ -77,12 +77,13 @@ namespace osu.Game.Rulesets.Catch.UI Origin = Anchor.TopRight, Children = new Drawable[] { - rightBox = new InputArea(TouchCatchAction.MoveRight, trackedActionSources, colours.Gray3) + rightBox = new InputArea(TouchCatchAction.MoveRight, trackedActionSources) { RelativeSizeAxes = Axes.Both, Width = 0.5f, + Colour = colours.GrayC, }, - rightDashBox = new InputArea(TouchCatchAction.DashRight, trackedActionSources, colours.Gray2) + rightDashBox = new InputArea(TouchCatchAction.DashRight, trackedActionSources) { RelativeSizeAxes = Axes.Both, Width = 0.5f, @@ -212,7 +213,7 @@ namespace osu.Game.Rulesets.Catch.UI private bool isHighlighted; - public InputArea(TouchCatchAction handledAction, IEnumerable> trackedActions, Color4 colour) + public InputArea(TouchCatchAction handledAction, IEnumerable> trackedActions) { this.handledAction = handledAction; this.trackedActions = trackedActions; @@ -227,8 +228,8 @@ namespace osu.Game.Rulesets.Catch.UI new Box { RelativeSizeAxes = Axes.Both, - Alpha = 0.8f, - Colour = colour, + Alpha = 0.2f, + Colour = OsuColour.Gray(0.8f), }, highlightOverlay = new Box { From 280b1dd48406d2af07be856e8abc1cdae097d18f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 9 Sep 2022 16:12:18 +0900 Subject: [PATCH 0999/2686] Revert async Task change --- osu.Game/BackgroundBeatmapProcessor.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game/BackgroundBeatmapProcessor.cs b/osu.Game/BackgroundBeatmapProcessor.cs index 071862146f..ea5904a8d3 100644 --- a/osu.Game/BackgroundBeatmapProcessor.cs +++ b/osu.Game/BackgroundBeatmapProcessor.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using osu.Framework.Allocation; @@ -45,12 +46,12 @@ namespace osu.Game { base.LoadComplete(); - Task.Run(async () => + Task.Run(() => { Logger.Log("Beginning background beatmap processing.."); checkForOutdatedStarRatings(); - await processBeatmapSetsWithMissingMetrics(); - await processScoresWithMissingStatistics(); + processBeatmapSetsWithMissingMetrics(); + processScoresWithMissingStatistics(); }).ContinueWith(t => { if (t.Exception?.InnerException is ObjectDisposedException) @@ -99,7 +100,7 @@ namespace osu.Game } } - private async Task processBeatmapSetsWithMissingMetrics() + private void processBeatmapSetsWithMissingMetrics() { HashSet beatmapSetIds = new HashSet(); @@ -123,7 +124,7 @@ namespace osu.Game while (localUserPlayInfo?.IsPlaying.Value == true) { Logger.Log("Background processing sleeping due to active gameplay..."); - await Task.Delay(TimeToSleepDuringGameplay); + Thread.Sleep(TimeToSleepDuringGameplay); } realmAccess.Run(r => @@ -146,7 +147,7 @@ namespace osu.Game } } - private async Task processScoresWithMissingStatistics() + private void processScoresWithMissingStatistics() { HashSet scoreIds = new HashSet(); @@ -168,7 +169,7 @@ namespace osu.Game while (localUserPlayInfo?.IsPlaying.Value == true) { Logger.Log("Background processing sleeping due to active gameplay..."); - await Task.Delay(TimeToSleepDuringGameplay); + Thread.Sleep(TimeToSleepDuringGameplay); } try From bffc9555bfcf5861ea9bc566f0d76876eef0ef5c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 16:12:54 +0900 Subject: [PATCH 1000/2686] Adjust visuals slightly further (and remove double-gray application) --- .../TestSceneCatchTouchInput.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs index b510a69f14..cbf6e8f202 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Catch.Tests } [Test] - public void TestInputField() + public void TestBasic() { AddStep("show overlay", () => catchTouchInputMapper.Show()); } diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index cdb587ad64..e6736d6c93 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Catch.UI { RelativeSizeAxes = Axes.Both, Width = 0.5f, - Colour = colours.GrayC, + Colour = colours.Gray9, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }, @@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Catch.UI { RelativeSizeAxes = Axes.Both, Width = 0.5f, - Colour = colours.GrayC, + Colour = colours.Gray9, }, rightDashBox = new InputArea(TouchCatchAction.DashRight, trackedActionSources) { @@ -223,13 +223,14 @@ namespace osu.Game.Rulesets.Catch.UI new Container { RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 10, Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, - Alpha = 0.2f, - Colour = OsuColour.Gray(0.8f), + Alpha = 0.15f, }, highlightOverlay = new Box { From 05797cb9e55447823b72c4a56e61a4d152472284 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 16:30:08 +0900 Subject: [PATCH 1001/2686] Fix enum to STRING????????? conversion (and use bindable flow) --- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 81 +++++++++---------- 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 0713469e10..c218ff11e9 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -1,7 +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 System; using System.Collections.Generic; using System.Linq; using osu.Framework.Bindables; @@ -78,11 +77,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters judgementsFlow.Clear(); judgementsFlow.Height = HitShapeCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; }, true); - HitShape.BindValueChanged(_ => - { - judgementsFlow.Shape = getShapeStyle(HitShape.Value); - judgementsFlow.Clear(); - }, true); } public override void Clear() => judgementsFlow.Clear(); @@ -90,7 +84,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private class JudgementFlow : FillFlowContainer { public override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); - internal string Shape = null!; + + public readonly Bindable Shape = new Bindable(); public JudgementFlow() { @@ -102,7 +97,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public void Push(Color4 colour, int maxErrorShapeCount) { - Add(new HitErrorShape(colour, drawable_judgement_size, Shape)); + Add(new HitErrorShape(colour, drawable_judgement_size) + { + Shape = { BindTarget = Shape }, + }); if (Children.Count > maxErrorShapeCount) Children.FirstOrDefault(c => !c.IsRemoved)?.Remove(); @@ -113,36 +111,44 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public bool IsRemoved { get; private set; } - public HitErrorShape(Color4 colour, int size, string shape) + public readonly Bindable Shape = new Bindable(); + + private readonly Color4 colour; + + public HitErrorShape(Color4 colour, int size) { + this.colour = colour; Size = new Vector2(size); - - switch (shape) - { - case "circle": - Child = new Circle - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Colour = colour - }; - break; - - case "square": - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Colour = colour - }; - break; - } } protected override void LoadComplete() { base.LoadComplete(); + Shape.BindValueChanged(shape => + { + switch (shape.NewValue) + { + case ShapeStyle.Circle: + Child = new Circle + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Colour = colour + }; + break; + + case ShapeStyle.Square: + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Colour = colour + }; + break; + } + }, true); + Child.FadeInFromZero(animation_duration, Easing.OutQuint); Child.MoveToY(-DrawSize.Y); Child.MoveToY(0, animation_duration, Easing.OutQuint); @@ -156,21 +162,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - private string getShapeStyle(ShapeStyle shape) - { - switch (shape) - { - case ShapeStyle.Circle: - return "circle"; - - case ShapeStyle.Square: - return "square"; - - default: - throw new ArgumentOutOfRangeException(nameof(shape), shape, @"Unsupported animation style"); - } - } - public enum ShapeStyle { Circle, From ec21ab8171c7b2a346e1f11e4550b5c6896506e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 16:39:22 +0900 Subject: [PATCH 1002/2686] Reduce ramp mod multipliers in line with other difficulty change mods for now Closes https://github.com/ppy/osu/issues/20204. Will require reprocessing of everything server-side. --- osu.Game/Rulesets/Mods/ModTimeRamp.cs | 2 ++ osu.Game/Rulesets/Mods/ModWindDown.cs | 1 - osu.Game/Rulesets/Mods/ModWindUp.cs | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModTimeRamp.cs b/osu.Game/Rulesets/Mods/ModTimeRamp.cs index 7031489d0e..72a7f4b9a3 100644 --- a/osu.Game/Rulesets/Mods/ModTimeRamp.cs +++ b/osu.Game/Rulesets/Mods/ModTimeRamp.cs @@ -19,6 +19,8 @@ namespace osu.Game.Rulesets.Mods /// public const double FINAL_RATE_PROGRESS = 0.75f; + public override double ScoreMultiplier => 0.5; + [SettingSource("Initial rate", "The starting speed of the track")] public abstract BindableNumber InitialRate { get; } diff --git a/osu.Game/Rulesets/Mods/ModWindDown.cs b/osu.Game/Rulesets/Mods/ModWindDown.cs index e84bdab69c..22ed7c2efd 100644 --- a/osu.Game/Rulesets/Mods/ModWindDown.cs +++ b/osu.Game/Rulesets/Mods/ModWindDown.cs @@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "WD"; public override LocalisableString Description => "Sloooow doooown..."; public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleDown; - public override double ScoreMultiplier => 1.0; [SettingSource("Initial rate", "The starting speed of the track")] public override BindableNumber InitialRate { get; } = new BindableDouble diff --git a/osu.Game/Rulesets/Mods/ModWindUp.cs b/osu.Game/Rulesets/Mods/ModWindUp.cs index 39cee50f96..13ece6d9a3 100644 --- a/osu.Game/Rulesets/Mods/ModWindUp.cs +++ b/osu.Game/Rulesets/Mods/ModWindUp.cs @@ -16,7 +16,6 @@ namespace osu.Game.Rulesets.Mods public override string Acronym => "WU"; public override LocalisableString Description => "Can you keep up?"; public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleUp; - public override double ScoreMultiplier => 1.0; [SettingSource("Initial rate", "The starting speed of the track")] public override BindableNumber InitialRate { get; } = new BindableDouble From 648c6245bbe72f1625dcecdb35875580d5f76a93 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 17:39:54 +0900 Subject: [PATCH 1003/2686] Add xmldoc --- osu.Game/Graphics/Sprites/SizePreservingSpriteText.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Sprites/SizePreservingSpriteText.cs b/osu.Game/Graphics/Sprites/SizePreservingSpriteText.cs index 11b81b26fd..baffe106ed 100644 --- a/osu.Game/Graphics/Sprites/SizePreservingSpriteText.cs +++ b/osu.Game/Graphics/Sprites/SizePreservingSpriteText.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. -#nullable disable - using System; using System.Collections.Generic; using osu.Framework.Graphics; @@ -14,6 +12,9 @@ using osuTK.Graphics; namespace osu.Game.Graphics.Sprites { + /// + /// A wrapped version of which will expand in size based on text content, but never shrink back down. + /// public class SizePreservingSpriteText : CompositeDrawable { private readonly OsuSpriteText text = new OsuSpriteText(); From 68d1b7d7cf61603c1ee05e4958be1aec371cc8d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 17:48:51 +0900 Subject: [PATCH 1004/2686] Reduce test count --- .../TestSceneUprightAspectMaintainingContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs index f81f8e8d85..00ecc166d5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.UserInterface private readonly List> childContainers = new List>(rows); // Preferably should be set to (4 * 2^n) - private const int rotation_step_count = 8; + private const int rotation_step_count = 3; private readonly List flipStates = new List(); private readonly List rotationSteps = new List(); @@ -127,7 +127,7 @@ namespace osu.Game.Tests.Visual.UserInterface flipStates.AddRange(new[] { 1, -1 }); rotationSteps.AddRange(Enumerable.Range(0, rotation_step_count).Select(x => 360f * ((float)x / rotation_step_count))); - scaleSteps.AddRange(new[] { 1, 0.5f, 0.3f, 1.5f, 2.0f }); + scaleSteps.AddRange(new[] { 1, 0.3f, 1.5f }); } [Test] From 9ec399a25ac560d409930d0387499ed247e0c549 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 17:49:31 +0900 Subject: [PATCH 1005/2686] Remove NRT overrides in new tests --- .../Visual/UserInterface/TestSceneSizePreservingSpriteText.cs | 2 -- .../UserInterface/TestSceneUprightAspectMaintainingContainer.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingSpriteText.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingSpriteText.cs index 69f5015af6..c4568d9aeb 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingSpriteText.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingSpriteText.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. -#nullable disable - using System; using System.Collections.Generic; using System.Globalization; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs index 00ecc166d5..67c26829df 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; From a2f96ea120b9461edae3194e0bf7a6229fedceab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 17:55:29 +0900 Subject: [PATCH 1006/2686] Make `random` implicitly null to avoid potential incorrect behaviour in `randomBool` --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 24 +++++++++------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 17df1bf489..056a325dce 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Mods private static readonly float playfield_diagonal = OsuPlayfield.BASE_SIZE.LengthFast; - private Random? rng; + private Random random = null!; public void ApplyToBeatmap(IBeatmap beatmap) { @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Mods Seed.Value ??= RNG.Next(); - rng = new Random((int)Seed.Value); + random = new Random((int)Seed.Value); var positionInfos = OsuHitObjectGenerationUtils.GeneratePositionInfos(osuBeatmap.HitObjects); @@ -50,14 +50,14 @@ namespace osu.Game.Rulesets.Osu.Mods { if (shouldStartNewSection(osuBeatmap, positionInfos, i)) { - sectionOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.0008f); + sectionOffset = OsuHitObjectGenerationUtils.RandomGaussian(random, 0, 0.0008f); flowDirection = !flowDirection; } if (i == 0) { - positionInfos[i].DistanceFromPrevious = (float)(rng.NextDouble() * OsuPlayfield.BASE_SIZE.Y / 2); - positionInfos[i].RelativeAngle = (float)(rng.NextDouble() * 2 * Math.PI - Math.PI); + positionInfos[i].DistanceFromPrevious = (float)(random.NextDouble() * OsuPlayfield.BASE_SIZE.Y / 2); + positionInfos[i].RelativeAngle = (float)(random.NextDouble() * 2 * Math.PI - Math.PI); } else { @@ -65,11 +65,11 @@ namespace osu.Game.Rulesets.Osu.Mods float flowChangeOffset = 0; // Offsets only the angle of the current hit object. - float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.002f); + float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(random, 0, 0.002f); if (shouldApplyFlowChange(positionInfos, i)) { - flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(rng, 0, 0.002f); + flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(random, 0, 0.002f); flowDirection = !flowDirection; } @@ -108,9 +108,9 @@ namespace osu.Game.Rulesets.Osu.Mods bool previousObjectWasOnDownbeat = OsuHitObjectGenerationUtils.IsHitObjectOnBeat(beatmap, positionInfos[i - 1].HitObject, true); bool previousObjectWasOnBeat = OsuHitObjectGenerationUtils.IsHitObjectOnBeat(beatmap, positionInfos[i - 1].HitObject); - return (previousObjectStartedCombo && randomBool(0.6f)) || + return (previousObjectStartedCombo && random.NextDouble() < 0.6f) || previousObjectWasOnDownbeat || - (previousObjectWasOnBeat && randomBool(0.4f)); + (previousObjectWasOnBeat && random.NextDouble() < 0.4f); } /// Whether a flow change should be applied at the current . @@ -120,11 +120,7 @@ namespace osu.Game.Rulesets.Osu.Mods bool previousObjectStartedCombo = positionInfos[Math.Max(0, i - 2)].HitObject.IndexInCurrentCombo > 1 && positionInfos[i - 1].HitObject.NewCombo; - return previousObjectStartedCombo && randomBool(0.6f); + return previousObjectStartedCombo && random.NextDouble() < 0.6f; } - - /// true with a probability of , false otherwise. - private bool randomBool(float probability) => - rng?.NextDouble() < probability; } } From 31cd7cdca0902e10605552cfdb004531bfb4a3df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 18:00:51 +0900 Subject: [PATCH 1007/2686] Refactor `IsHitObjectOnBeat` to be understandable --- .../Utils/OsuHitObjectGenerationUtils.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index a890dbde43..3a8b3f67d0 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -195,19 +195,17 @@ namespace osu.Game.Rulesets.Osu.Utils /// true if hitObject is on a (down-)beat, false otherwise. public static bool IsHitObjectOnBeat(OsuBeatmap beatmap, OsuHitObject hitObject, bool downbeatsOnly = false) { - var timingPoints = beatmap.ControlPointInfo.TimingPoints; - var currentTimingPoint = timingPoints.LastOrDefault(p => p.Time <= hitObject.StartTime); + var timingPoint = beatmap.ControlPointInfo.TimingPointAt(hitObject.StartTime); - if (currentTimingPoint == null) - return false; + double timeSinceTimingPoint = hitObject.StartTime - timingPoint.Time; - double timeSinceTimingPoint = hitObject.StartTime - currentTimingPoint.Time; + double beatLength = timingPoint.BeatLength; - double length = downbeatsOnly - ? currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator - : currentTimingPoint.BeatLength; + if (downbeatsOnly) + beatLength *= timingPoint.TimeSignature.Numerator; - return (timeSinceTimingPoint + 1) % length < 2; + // Ensure within 1ms of expected location. + return Math.Abs(timeSinceTimingPoint + 1) % beatLength < 2; } /// From 7d100c5eeca6aab52fc624b31f99b4d66515d01d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 18:10:10 +0900 Subject: [PATCH 1008/2686] Fix test in line with new expectations --- .../Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs index 0af876bfe8..5afda0ad0c 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Beatmaps }; }); AddStep("enable dim", () => thumbnail.Dimmed.Value = true); - AddUntilStep("button visible", () => playButton.IsPresent); + AddUntilStep("button visible", () => playButton.Alpha == 1); AddStep("click button", () => { @@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.Beatmaps AddStep("disable dim", () => thumbnail.Dimmed.Value = false); AddWaitStep("wait some", 3); - AddAssert("button still visible", () => playButton.IsPresent); + AddAssert("button still visible", () => playButton.Alpha == 1); // The track plays in real-time, so we need to check for progress in increments to avoid timeout. AddUntilStep("progress > 0.25", () => thumbnail.ChildrenOfType().Single().Progress.Value > 0.25); @@ -78,7 +78,7 @@ namespace osu.Game.Tests.Visual.Beatmaps AddUntilStep("progress > 0.75", () => thumbnail.ChildrenOfType().Single().Progress.Value > 0.75); AddUntilStep("wait for track to end", () => !playButton.Playing.Value); - AddUntilStep("button hidden", () => !playButton.IsPresent); + AddUntilStep("button hidden", () => playButton.Alpha == 0); } private void iconIs(IconUsage usage) => AddUntilStep("icon is correct", () => playButton.ChildrenOfType().Any(icon => icon.Icon.Equals(usage))); From 602ffebd54d79e76bb19a4b95572b4023f07562f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 9 Sep 2022 23:29:04 +0900 Subject: [PATCH 1009/2686] Apply NRT and fix code style --- osu.Game/Screens/Select/FilterQueryParser.cs | 25 ++++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 75574c061d..a7c1aec361 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.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. -#nullable disable - using System; using System.Collections.Generic; using System.Globalization; @@ -126,16 +124,21 @@ namespace osu.Game.Screens.Select { if (Enum.TryParse(value, true, out result)) return true; - value = Enum.GetNames(typeof(TEnum)).FirstOrDefault(name => name.StartsWith(value, true, CultureInfo.InvariantCulture)); + string? prefixMatch = Enum.GetNames(typeof(TEnum)).FirstOrDefault(name => name.StartsWith(value, true, CultureInfo.InvariantCulture)); + + if (prefixMatch == null) + return false; + return Enum.TryParse(value, true, out result); } - private static GroupCollection tryMatchRegex(string value, string regex) + + private static GroupCollection? tryMatchRegex(string value, string regex) { - Match matchs = Regex.Match(value, regex); - if (matchs.Success) - { - return matchs.Groups; - } + Match matches = Regex.Match(value, regex); + + if (matches.Success) + return matches.Groups; + return null; } @@ -324,7 +327,8 @@ namespace osu.Game.Screens.Select { List parts = new List(); - GroupCollection match = null; + GroupCollection? match = null; + match ??= tryMatchRegex(val, @"^((?\d+):)?(?\d+):(?\d+)$"); match ??= tryMatchRegex(val, @"^((?\d+(\.\d+)?)h)?((?\d+(\.\d+)?)m)?((?\d+(\.\d+)?)s)?$"); match ??= tryMatchRegex(val, @"^(?\d+(\.\d+)?)$"); @@ -358,6 +362,7 @@ namespace osu.Game.Screens.Select totalLength += length * scale; minScale = Math.Min(minScale, scale); } + return tryUpdateCriteriaRange(ref criteria.Length, op, totalLength, minScale / 2.0); } } From 6338b87c63721b941a68397a18b9c2f195be3374 Mon Sep 17 00:00:00 2001 From: StanR Date: Fri, 9 Sep 2022 17:31:52 +0300 Subject: [PATCH 1010/2686] attributes --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 6a221c1a73..2b0e2db898 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double computeAimValue(ScoreInfo score, OsuDifficultyAttributes attributes) { - double aimValue = Math.Pow(5.0 * Math.Max(1.0, Attributes.AimDifficulty / 0.0675) - 4.0, 3.0) / 100000.0; + double aimValue = Math.Pow(5.0 * Math.Max(1.0, attributes.AimDifficulty / 0.0675) - 4.0, 3.0) / 100000.0; double lengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); From ae53e27e6cad2157dba515c71946012dcbca1c5d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 9 Sep 2022 19:39:01 +0300 Subject: [PATCH 1011/2686] Adjust test coverage to read better --- .../SongSelect/TestSceneTopLocalRank.cs | 63 ++++++------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs index 1a72dc2a72..cced9b8b89 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs @@ -1,14 +1,12 @@ // 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.Diagnostics; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Framework.Testing; @@ -49,12 +47,12 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("Create local rank", () => { - Add(topLocalRank = new TopLocalRank(importedBeatmap) + Child = topLocalRank = new TopLocalRank(importedBeatmap) { Anchor = Anchor.Centre, Origin = Anchor.Centre, Scale = new Vector2(10), - }); + }; }); AddAssert("No rank displayed initially", () => topLocalRank.DisplayedRank == null); @@ -63,7 +61,7 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestBasicImportDelete() { - ScoreInfo? testScoreInfo = null; + ScoreInfo testScoreInfo = null!; AddStep("Add score for current user", () => { @@ -77,10 +75,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.B); - AddStep("Delete score", () => - { - scoreManager.Delete(testScoreInfo.AsNonNull()); - }); + AddStep("Delete score", () => scoreManager.Delete(testScoreInfo)); AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank == null); } @@ -88,11 +83,9 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestRulesetChange() { - ScoreInfo testScoreInfo; - AddStep("Add score for current user", () => { - testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); + var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); testScoreInfo.User = API.LocalUser.Value; testScoreInfo.Rank = ScoreRank.B; @@ -112,11 +105,9 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestHigherScoreSet() { - ScoreInfo? testScoreInfo = null; - AddStep("Add score for current user", () => { - testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); + var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap); testScoreInfo.User = API.LocalUser.Value; testScoreInfo.Rank = ScoreRank.B; @@ -131,28 +122,20 @@ namespace osu.Game.Tests.Visual.SongSelect var testScoreInfo2 = TestResources.CreateTestScoreInfo(importedBeatmap); testScoreInfo2.User = API.LocalUser.Value; - testScoreInfo2.Rank = ScoreRank.S; - testScoreInfo2.TotalScore = testScoreInfo.AsNonNull().TotalScore + 1; - testScoreInfo2.Statistics = new Dictionary - { - [HitResult.Miss] = 0, - [HitResult.Perfect] = 970, - [HitResult.SmallTickHit] = 75, - [HitResult.LargeTickHit] = 150, - [HitResult.LargeBonus] = 10, - [HitResult.SmallBonus] = 50 - }; + testScoreInfo2.Rank = ScoreRank.X; + testScoreInfo2.TotalScore = 1000000; + testScoreInfo2.Statistics = testScoreInfo2.MaximumStatistics; scoreManager.Import(testScoreInfo2); }); - AddUntilStep("S rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.S); + AddUntilStep("SS rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.X); } [Test] public void TestLegacyScore() { - ScoreInfo? testScoreInfo = null; + ScoreInfo testScoreInfo = null!; AddStep("Add legacy score for current user", () => { @@ -160,7 +143,7 @@ namespace osu.Game.Tests.Visual.SongSelect testScoreInfo.User = API.LocalUser.Value; testScoreInfo.Rank = ScoreRank.B; - testScoreInfo.TotalScore = scoreManager.GetTotalScoreAsync(testScoreInfo, ScoringMode.Classic).GetResultSafely(); + testScoreInfo.TotalScore = scoreManager.GetTotalScore(testScoreInfo, ScoringMode.Classic); scoreManager.Import(testScoreInfo); }); @@ -172,26 +155,18 @@ namespace osu.Game.Tests.Visual.SongSelect var testScoreInfo2 = TestResources.CreateTestScoreInfo(importedBeatmap); testScoreInfo2.User = API.LocalUser.Value; - testScoreInfo2.Rank = ScoreRank.S; - testScoreInfo2.Statistics = new Dictionary - { - [HitResult.Miss] = 0, - [HitResult.Perfect] = 970, - [HitResult.SmallTickHit] = 75, - [HitResult.LargeTickHit] = 150, - [HitResult.LargeBonus] = 10, - [HitResult.SmallBonus] = 50 - }; + testScoreInfo2.Rank = ScoreRank.X; + testScoreInfo2.Statistics = testScoreInfo2.MaximumStatistics; + testScoreInfo2.TotalScore = scoreManager.GetTotalScore(testScoreInfo2); - testScoreInfo2.TotalScore = scoreManager.GetTotalScoreAsync(testScoreInfo.AsNonNull()).GetResultSafely(); - - // ensure standardised total score is less than classic, otherwise this test is pointless. - Debug.Assert(testScoreInfo2.TotalScore < testScoreInfo.AsNonNull().TotalScore); + // ensure second score has a total score (standardised) less than first one (classic) + // despite having better statistics, otherwise this test is pointless. + Debug.Assert(testScoreInfo2.TotalScore < testScoreInfo.TotalScore); scoreManager.Import(testScoreInfo2); }); - AddUntilStep("S rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.S); + AddUntilStep("SS rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.X); } } } From 95062c2cc8fc804eb8e4a7d52d28e1f8b190d6c7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 9 Sep 2022 19:42:58 +0300 Subject: [PATCH 1012/2686] Remove center origin specification to avoid single-frame layout issues --- osu.Game/Screens/Select/Carousel/TopLocalRank.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs index cb2ff86794..0f000555d5 100644 --- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs +++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs @@ -49,8 +49,6 @@ namespace osu.Game.Screens.Select.Carousel InternalChild = updateable = new UpdateableRank { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, Size = new Vector2(40, 20), Alpha = 0, }; From cb17fb2091b351c0bf79f31a0818923529d2b274 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Fri, 9 Sep 2022 23:13:19 +0200 Subject: [PATCH 1013/2686] Create Test Scene --- .../Mods/TestSceneOsuModFreezeFrame.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs new file mode 100644 index 0000000000..4642229436 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs @@ -0,0 +1,27 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Osu.Mods; + +namespace osu.Game.Rulesets.Osu.Tests.Mods +{ + public class TestSceneOsuModFreezeFrame : OsuModTestScene + { + [TestCase(0.5f)] + [TestCase(1)] + [TestCase(2)] + public void TestFreezeFrequency(float beatMeasure) + { + CreateModTest(new ModTestData + { + Mod = new OsuModFreezeFrame + { + BeatDivisor = { Value = beatMeasure } + }, + PassCondition = () => true, + Autoplay = true + }); + } + } +} From 5e4e3dfc2cb8ea50f83d4edbaab4f8ab19a77e8a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 10 Sep 2022 02:55:20 +0300 Subject: [PATCH 1014/2686] Fix markdown container not rendering certain text correctly --- .../Markdown/OsuMarkdownContainer.cs | 36 ++++++++++++++++--- .../Comments/CommentMarkdownContainer.cs | 2 ++ .../Wiki/Markdown/WikiMarkdownContainer.cs | 2 ++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs index a2370a76cb..62fefe201d 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs @@ -4,7 +4,9 @@ #nullable disable using Markdig; -using Markdig.Extensions.AutoIdentifiers; +using Markdig.Extensions.AutoLinks; +using Markdig.Extensions.EmphasisExtras; +using Markdig.Extensions.Footnotes; using Markdig.Extensions.Tables; using Markdig.Extensions.Yaml; using Markdig.Syntax; @@ -18,6 +20,18 @@ namespace osu.Game.Graphics.Containers.Markdown { public class OsuMarkdownContainer : MarkdownContainer { + /// + /// Allows this markdown container to parse and link footnotes. + /// + /// + protected virtual bool Footnotes => false; + + /// + /// Allows this markdown container to make URL text clickable. + /// + /// + protected virtual bool Autolinks => false; + public OsuMarkdownContainer() { LineSpacing = 21; @@ -78,10 +92,22 @@ namespace osu.Game.Graphics.Containers.Markdown return new OsuMarkdownUnorderedListItem(level); } + // reference: https://github.com/ppy/osu-web/blob/05488a96b25b5a09f2d97c54c06dd2bae59d1dc8/app/Libraries/Markdown/OsuMarkdown.php#L301 protected override MarkdownPipeline CreateBuilder() - => new MarkdownPipelineBuilder().UseAutoIdentifiers(AutoIdentifierOptions.GitHub) - .UseEmojiAndSmiley() - .UseYamlFrontMatter() - .UseAdvancedExtensions().Build(); + { + var pipeline = new MarkdownPipelineBuilder() + .UseAutoIdentifiers() + .UsePipeTables() + .UseEmphasisExtras(EmphasisExtraOptions.Strikethrough) + .UseYamlFrontMatter(); + + if (Footnotes) + pipeline = pipeline.UseFootnotes(); + + if (Autolinks) + pipeline = pipeline.UseAutoLinks(); + + return pipeline.Build(); + } } } diff --git a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs index 8fc011b2bf..b32b1c74c4 100644 --- a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs +++ b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs @@ -11,6 +11,8 @@ namespace osu.Game.Overlays.Comments { public class CommentMarkdownContainer : OsuMarkdownContainer { + protected override bool Autolinks => true; + protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new CommentMarkdownHeading(headingBlock); private class CommentMarkdownHeading : OsuMarkdownHeading diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index 7754c1d450..4f1083a75c 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -15,6 +15,8 @@ namespace osu.Game.Overlays.Wiki.Markdown { public class WikiMarkdownContainer : OsuMarkdownContainer { + protected override bool Footnotes => true; + public string CurrentPath { set => DocumentUrl = value; From ec86700f2903bca40fd9cbc7f5a0d062e0373466 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 10 Sep 2022 10:45:51 +0800 Subject: [PATCH 1015/2686] Add the nullable disable annotation back becuse it will cause the api broken if remove the nullable disable annotation in the mania ruleset. --- .../Configuration/ManiaRulesetConfigManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs index 64e1f75e2c..b30d72f2e2 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable disable + using System; using osu.Framework.Configuration.Tracking; using osu.Game.Configuration; From 2f91b5c846b4055422574620717416c60480f60d Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 10 Sep 2022 10:46:10 +0800 Subject: [PATCH 1016/2686] Add missing import. --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 + osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 24a4f16e9f..90733e0206 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.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 System.Linq; using osu.Framework.Extensions.EnumExtensions; diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index b53dc67584..90d9ffe527 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.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 System.Linq; using osu.Framework.Extensions.EnumExtensions; From 1398a7e11ebffc6815bf26a33a615ae63e30f54c Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 10 Sep 2022 10:46:40 +0800 Subject: [PATCH 1017/2686] Property should accept the nullable state. --- osu.Game/Online/API/APIMod.cs | 2 +- osu.Game/Overlays/Settings/Sections/RulesetSection.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index dcbaaea012..176f10975d 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -48,7 +48,7 @@ namespace osu.Game.Online.API public Mod ToMod(Ruleset ruleset) { - Mod resultMod = ruleset.CreateModFromAcronym(Acronym); + Mod? resultMod = ruleset.CreateModFromAcronym(Acronym); if (resultMod == null) { diff --git a/osu.Game/Overlays/Settings/Sections/RulesetSection.cs b/osu.Game/Overlays/Settings/Sections/RulesetSection.cs index a5f5810214..6f0b3c27a0 100644 --- a/osu.Game/Overlays/Settings/Sections/RulesetSection.cs +++ b/osu.Game/Overlays/Settings/Sections/RulesetSection.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Settings.Sections { try { - SettingsSubsection section = ruleset.CreateSettings(); + SettingsSubsection? section = ruleset.CreateSettings(); if (section != null) Add(section); From 3d7367a8420ca60b029d4b557b7458dff7e7d487 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 10 Sep 2022 11:07:23 +0800 Subject: [PATCH 1018/2686] Move the CreateConvertibleReplayFrame() into the base ruleset class for avoid api breaking change in the customized ruleset. --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 2 +- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 2 +- osu.Game/Rulesets/ILegacyRuleset.cs | 9 --------- osu.Game/Rulesets/Ruleset.cs | 8 ++++++++ osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 2 +- osu.Game/Screens/Play/SpectatorPlayer.cs | 7 ++----- 8 files changed, 15 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index d2e05fbeb9..999b9f6e2c 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -188,7 +188,7 @@ namespace osu.Game.Rulesets.Catch public int LegacyID => 2; - public IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame(); + public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new CatchReplayFrame(); public override HitObjectComposer CreateHitObjectComposer() => new CatchHitObjectComposer(this); diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 72be77ddab..c6a5e8bdaa 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -281,7 +281,7 @@ namespace osu.Game.Rulesets.Mania public int LegacyID => 3; - public IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame(); + public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new ManiaReplayFrame(); public override IRulesetConfigManager CreateConfig(SettingsStore? settings) => new ManiaRulesetConfigManager(settings, RulesetInfo); diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 90733e0206..6af765361d 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Osu public int LegacyID => 0; - public IConvertibleReplayFrame CreateConvertibleReplayFrame() => new OsuReplayFrame(); + public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new OsuReplayFrame(); public override IRulesetConfigManager CreateConfig(SettingsStore? settings) => new OsuRulesetConfigManager(settings, RulesetInfo); diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 90d9ffe527..6beb83575d 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -178,7 +178,7 @@ namespace osu.Game.Rulesets.Taiko public int LegacyID => 1; - public IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame(); + public override IConvertibleReplayFrame CreateConvertibleReplayFrame() => new TaikoReplayFrame(); protected override IEnumerable GetValidHitResults() { diff --git a/osu.Game/Rulesets/ILegacyRuleset.cs b/osu.Game/Rulesets/ILegacyRuleset.cs index c2617a065c..f4b03baccd 100644 --- a/osu.Game/Rulesets/ILegacyRuleset.cs +++ b/osu.Game/Rulesets/ILegacyRuleset.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.Game.Rulesets.Replays.Types; - namespace osu.Game.Rulesets { public interface ILegacyRuleset @@ -13,12 +11,5 @@ namespace osu.Game.Rulesets /// Identifies the server-side ID of a legacy ruleset. /// int LegacyID { get; } - - /// - /// For rulesets which support legacy (osu-stable) replay conversion, this method will create an empty replay frame - /// for conversion use. - /// - /// An empty frame for the current ruleset, or null if unsupported. - IConvertibleReplayFrame CreateConvertibleReplayFrame(); } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index a10575ef73..4bc82a5f7e 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -23,6 +23,7 @@ using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Filter; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; @@ -302,6 +303,13 @@ namespace osu.Game.Rulesets /// A descriptive name of the variant. public virtual LocalisableString GetVariantName(int variant) => string.Empty; + /// + /// For rulesets which support legacy (osu-stable) replay conversion, this method will create an empty replay frame + /// for conversion use. + /// + /// An empty frame for the current ruleset, or null if unsupported. + public virtual IConvertibleReplayFrame? CreateConvertibleReplayFrame() => null; + /// /// Creates the statistics for a to be displayed in the results screen. /// diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs index 2b22b4abc7..f64e730c06 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs @@ -282,7 +282,7 @@ namespace osu.Game.Scoring.Legacy private ReplayFrame convertFrame(LegacyReplayFrame currentFrame, ReplayFrame lastFrame) { - var convertible = (currentRuleset as ILegacyRuleset)?.CreateConvertibleReplayFrame(); + var convertible = currentRuleset.CreateConvertibleReplayFrame(); if (convertible == null) throw new InvalidOperationException($"Legacy replay cannot be converted for the ruleset: {currentRuleset.Description}"); diff --git a/osu.Game/Screens/Play/SpectatorPlayer.cs b/osu.Game/Screens/Play/SpectatorPlayer.cs index 659d7d5d6c..68cc21fc1c 100644 --- a/osu.Game/Screens/Play/SpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SpectatorPlayer.cs @@ -11,7 +11,6 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.Spectator; -using osu.Game.Rulesets; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays.Types; using osu.Game.Scoring; @@ -81,14 +80,12 @@ namespace osu.Game.Screens.Play if (!this.IsCurrentScreen()) return; - var legacyRuleset = GameplayState.Ruleset as ILegacyRuleset; - Debug.Assert(legacyRuleset != null); - bool isFirstBundle = score.Replay.Frames.Count == 0; foreach (var frame in bundle.Frames) { - IConvertibleReplayFrame convertibleFrame = legacyRuleset.CreateConvertibleReplayFrame(); + IConvertibleReplayFrame convertibleFrame = GameplayState.Ruleset.CreateConvertibleReplayFrame(); + Debug.Assert(convertibleFrame != null); convertibleFrame.FromLegacy(frame, GameplayState.Beatmap); var convertedFrame = (ReplayFrame)convertibleFrame; From b056cac10a1259044e65e67ab059f108b66c23bb Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 10 Sep 2022 08:21:38 +0300 Subject: [PATCH 1019/2686] Remove generic and add default implementation for `CalculateEffect` --- .../Overlays/Mods/DifficultyMultiplierDisplay.cs | 3 +-- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 4 ++-- osu.Game/Overlays/Mods/ModsEffectDisplay.cs | 14 ++++++++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index 843310249e..5530947d3d 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -16,10 +16,9 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Mods { - public sealed class DifficultyMultiplierDisplay : ModsEffectDisplay + public sealed class DifficultyMultiplierDisplay : ModsEffectDisplay { protected override LocalisableString Label => DifficultyMultiplierDisplayStrings.DifficultyMultiplier; - protected override ModEffect CalculateEffect(double value) => CalculateForSign(value.CompareTo(1d)); private readonly MultiplierCounter multiplierCounter; diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 80f18eafeb..ccc075b190 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -153,7 +153,7 @@ namespace osu.Game.Overlays.Mods { Padding = new MarginPadding { - Top = (ShowTotalMultiplier ? ModsEffectDisplay.HEIGHT : 0) + PADDING, + Top = (ShowTotalMultiplier ? ModsEffectDisplay.HEIGHT : 0) + PADDING, Bottom = PADDING }, RelativeSizeAxes = Axes.Both, @@ -191,7 +191,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopRight, Origin = Anchor.TopRight, AutoSizeAxes = Axes.X, - Height = ModsEffectDisplay.HEIGHT, + Height = ModsEffectDisplay.HEIGHT, Margin = new MarginPadding { Horizontal = 100 }, Child = multiplierDisplay = new DifficultyMultiplierDisplay { diff --git a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs index 2ff6bf043b..4e630439ee 100644 --- a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs +++ b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Mods /// /// Base class for displays of mods effects. /// - public abstract class ModsEffectDisplay : Container, IHasCurrentValue + public abstract class ModsEffectDisplay : Container, IHasCurrentValue { public const float HEIGHT = 42; private const float transition_duration = 200; @@ -28,13 +28,13 @@ namespace osu.Game.Overlays.Mods private readonly Box labelBackground; private readonly Container content; - public Bindable Current + public Bindable Current { get => current.Current; set => current.Current = value; } - private readonly BindableWithCurrent current = new BindableWithCurrent(); + private readonly BindableWithCurrent current = new BindableWithCurrent(); [Resolved] private OsuColour colours { get; set; } = null!; @@ -52,7 +52,13 @@ namespace osu.Game.Overlays.Mods /// /// Value to calculate for. Will arrive from bindable once it changes. /// Effect of the value. - protected abstract ModEffect CalculateEffect(TValue value); + /// + /// Default implementation compares the value with ., bigger value counts as difficulty increase. + /// + protected virtual ModEffect CalculateEffect(double value) + { + return CalculateForSign(value.CompareTo(Current.Default)); + } protected virtual float ValueAreaWidth => 56; From efe3b1aa7bd047847510fe50f75f1f87d0c2f78b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 10 Sep 2022 14:10:49 +0900 Subject: [PATCH 1020/2686] Allow dismissing notifications without performing action using middle / right click --- .../TestSceneNotificationOverlay.cs | 60 ++++++++++++++++++- .../Overlays/Notifications/Notification.cs | 19 +++++- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 699b8f7d89..c0b29dde9a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -12,11 +12,13 @@ using osu.Framework.Utils; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; +using osuTK; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneNotificationOverlay : OsuTestScene + public class TestSceneNotificationOverlay : OsuManualInputManagerTestScene { private NotificationOverlay notificationOverlay = null!; @@ -32,7 +34,7 @@ namespace osu.Game.Tests.Visual.UserInterface TimeToCompleteProgress = 2000; progressingNotifications.Clear(); - Content.Children = new Drawable[] + Children = new Drawable[] { notificationOverlay = new NotificationOverlay { @@ -45,6 +47,60 @@ namespace osu.Game.Tests.Visual.UserInterface notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count.NewValue}"; }; }); + [Test] + public void TestDismissWithoutActivationRightClick() + { + bool activated = false; + SimpleNotification notification = null!; + + AddStep("post", () => + { + activated = false; + notificationOverlay.Post(notification = new SimpleNotification + { + Text = @"Welcome to osu!. Enjoy your stay!", + Activated = () => activated = true, + }); + }); + + AddStep("click to activate", () => + { + InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Right); + }); + + AddUntilStep("wait for closed", () => notification.WasClosed); + AddAssert("was not activated", () => !activated); + AddStep("reset mouse position", () => InputManager.MoveMouseTo(Vector2.Zero)); + } + + [Test] + public void TestActivate() + { + bool activated = false; + SimpleNotification notification = null!; + + AddStep("post", () => + { + activated = false; + notificationOverlay.Post(notification = new SimpleNotification + { + Text = @"Welcome to osu!. Enjoy your stay!", + Activated = () => activated = true, + }); + }); + + AddStep("click to activate", () => + { + InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("wait for closed", () => notification.WasClosed); + AddAssert("was activated", () => activated); + AddStep("reset mouse position", () => InputManager.MoveMouseTo(Vector2.Zero)); + } + [Test] public void TestPresence() { diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index e5f739bb08..09abdb865d 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -16,6 +16,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osuTK; using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Overlays.Notifications { @@ -170,11 +171,25 @@ namespace osu.Game.Overlays.Notifications base.OnHoverLost(e); } + protected override bool OnMouseDown(MouseDownEvent e) + { + // right click doesn't trigger OnClick so we need to handle here until that changes. + if (e.Button != MouseButton.Left) + { + Close(); + return true; + } + + return base.OnMouseDown(e); + } + protected override bool OnClick(ClickEvent e) { - if (Activated?.Invoke() ?? true) - Close(); + // Clicking with anything but left button should dismiss but not perform the activation action. + if (e.Button == MouseButton.Left) + Activated?.Invoke(); + Close(); return true; } From a9094c6b03bf302382cf171c72a5f217e2668189 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 10 Sep 2022 15:18:32 +0900 Subject: [PATCH 1021/2686] Add test coverage of clicking close button to dismiss --- .../TestSceneNotificationOverlay.cs | 29 +++++++++++++++++++ .../Overlays/Notifications/Notification.cs | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index c0b29dde9a..5f82a0024b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -47,6 +47,35 @@ namespace osu.Game.Tests.Visual.UserInterface notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count.NewValue}"; }; }); + [Test] + public void TestDismissWithoutActivationCloseButton() + { + bool activated = false; + SimpleNotification notification = null!; + + AddStep("post", () => + { + activated = false; + notificationOverlay.Post(notification = new SimpleNotification + { + Text = @"Welcome to osu!. Enjoy your stay!", + Activated = () => activated = true, + }); + }); + + AddStep("click to activate", () => + { + InputManager.MoveMouseTo(notificationOverlay + .ChildrenOfType().Single() + .ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("wait for closed", () => notification.WasClosed); + AddAssert("was not activated", () => !activated); + AddStep("reset mouse position", () => InputManager.MoveMouseTo(Vector2.Zero)); + } + [Test] public void TestDismissWithoutActivationRightClick() { diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 09abdb865d..67739c2089 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -218,7 +218,7 @@ namespace osu.Game.Overlays.Notifications Expire(); } - private class CloseButton : OsuClickableContainer + internal class CloseButton : OsuClickableContainer { private SpriteIcon icon = null!; private Box background = null!; From 23d435bc427c8d1e2780a46d500b77eff084c9df Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Sat, 10 Sep 2022 14:08:04 +0200 Subject: [PATCH 1022/2686] name changes --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index b6b6f4e588..6bbe01063b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -49,12 +49,12 @@ namespace osu.Game.Rulesets.Osu.Mods foreach (var obj in beatmap.HitObjects.OfType()) { var point = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime); - double val = obj.TimePreempt + obj.StartTime % (point.BeatLength * BeatDivisor.Value); + double newPreempt = obj.TimePreempt + (obj.StartTime +5) % (point.BeatLength * BeatDivisor.Value); applyFadeInAdjustment(obj); void applyFadeInAdjustment(OsuHitObject osuObject) { - osuObject.TimePreempt = val; + osuObject.TimePreempt = newPreempt; foreach (var nested in osuObject.NestedHitObjects.OfType()) applyFadeInAdjustment(nested); } From f6aef73f9ee1f4cb76a31cbed78741d4b5675fd8 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Sat, 10 Sep 2022 20:30:43 +0200 Subject: [PATCH 1023/2686] fixed shape bindable not working, test creation, removal of Clear(), adjusted settings names --- .../Gameplay/TestSceneColourHitErrorMeter.cs | 119 ++++++++++++++++++ .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 12 +- 2 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs new file mode 100644 index 0000000000..7cbc70c605 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs @@ -0,0 +1,119 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable +using System; +using System.Diagnostics; +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play.HUD.HitErrorMeters; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneColourHitErrorMeter : OsuTestScene + { + private DependencyProvidingContainer dependencyContainer; + + private readonly Bindable lastJudgementResult = new Bindable(); + private ScoreProcessor scoreProcessor; + private int iteration; + private ColourHitErrorMeter colourHitErrorMeter; + + public TestSceneColourHitErrorMeter() + { + AddSliderStep("Manual Opacity test", 0.01f, 1, 1, alpha => + { + if (colourHitErrorMeter != null) colourHitErrorMeter.HitShapeOpacity.Value = alpha; + }); + AddSliderStep("Manual spacing test", 0, 10, 2, spacing => + { + if (colourHitErrorMeter != null) colourHitErrorMeter.HitShapeSpacing.Value = spacing; + }); + } + + [SetUpSteps] + public void SetupSteps() => AddStep("Create components", () => + { + var ruleset = CreateRuleset(); + + Debug.Assert(ruleset != null); + + scoreProcessor = new ScoreProcessor(ruleset); + Child = dependencyContainer = new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] + { + (typeof(ScoreProcessor), scoreProcessor) + } + }; + dependencyContainer.Child = colourHitErrorMeter = new ColourHitErrorMeter + { + Margin = new MarginPadding + { + Top = 100 + }, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Scale = new Vector2(2), + }; + }); + + protected override Ruleset CreateRuleset() => new OsuRuleset(); + + [Test] + public void TestOpacityChange() + { + AddRepeatStep("Add judgement", applyOneJudgement, 5); + AddStep("Change opacity to 30%", () => colourHitErrorMeter.HitShapeOpacity.Value = 0.3f); + AddRepeatStep("Add judgement", applyOneJudgement, 5); + } + + [Test] + public void TestSpacingChange() + { + AddRepeatStep("Add judgement", applyOneJudgement, 5); + AddStep("Change spacing", () => colourHitErrorMeter.HitShapeSpacing.Value = 10); + AddRepeatStep("Add judgement", applyOneJudgement, 5); + } + + [Test] + public void TestShapeChange() + { + AddRepeatStep("Add judgement", applyOneJudgement, 10); + AddStep("Judgement count change to 4", () => colourHitErrorMeter.HitShapeCount.Value = 4); + AddRepeatStep("Add judgement", applyOneJudgement, 8); + } + + [Test] + public void TestHitErrorShapeChange() + { + AddRepeatStep("Add judgement", applyOneJudgement, 8); + AddStep("Change shape square", () => colourHitErrorMeter.HitShape.Value = ColourHitErrorMeter.ShapeStyle.Square); + AddRepeatStep("Add judgement", applyOneJudgement, 10); + } + + private void applyOneJudgement() + { + lastJudgementResult.Value = new OsuJudgementResult(new HitObject + { + StartTime = iteration * 10000, + }, new OsuJudgement()) + { + Type = HitResult.Great, + }; + scoreProcessor.ApplyResult(lastJudgementResult.Value); + + iteration++; + } + } +} diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index c218ff11e9..b5a8cfc44f 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private const int animation_duration = 200; private const int drawable_judgement_size = 8; - [SettingSource("Hit error amount", "Number of hit error shapes")] + [SettingSource("Judgement count", "Number of displayed judgements")] public BindableNumber HitShapeCount { get; } = new BindableNumber(20) { MinValue = 1, @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Precision = 1 }; - [SettingSource("Opacity", "Visibility of object")] + [SettingSource("Opacity", "Visibility of the displayed judgements")] public BindableNumber HitShapeOpacity { get; } = new BindableNumber(1) { MinValue = 0.01f, @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Precision = 0.01f, }; - [SettingSource("Spacing", "Space between hit error shapes")] + [SettingSource("Spacing", "Space between each displayed judgement")] public BindableNumber HitShapeSpacing { get; } = new BindableNumber(2) { MinValue = 0, @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Precision = 0.1f }; - [SettingSource("Shape", "The shape of each displayed error")] + [SettingSource("Shape", "The shape of each displayed judgement")] public Bindable HitShape { get; } = new Bindable(); private readonly JudgementFlow judgementsFlow; @@ -74,9 +74,11 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }, true); HitShapeCount.BindValueChanged(_ => { - judgementsFlow.Clear(); + //Used to clear out the overflowing judgement children when the value is lowered + judgementsFlow.RemoveAll(_ => true); judgementsFlow.Height = HitShapeCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; }, true); + HitShape.BindValueChanged(_ => judgementsFlow.Shape.Value = HitShape.Value, true); } public override void Clear() => judgementsFlow.Clear(); From 46d9262a6066c47f5fdf694e5d1ea78bb5dabec6 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Sat, 10 Sep 2022 20:38:34 +0200 Subject: [PATCH 1024/2686] test naming oversight --- osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs index 7cbc70c605..5fdd00a7f6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual.Gameplay } [Test] - public void TestShapeChange() + public void TestJudgementAmountChange() { AddRepeatStep("Add judgement", applyOneJudgement, 10); AddStep("Judgement count change to 4", () => colourHitErrorMeter.HitShapeCount.Value = 4); From c00bf612738c7a75ab00803349eeeea664b61186 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Sat, 10 Sep 2022 21:24:29 +0200 Subject: [PATCH 1025/2686] Framework change adressed --- osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index b5a8cfc44f..8991d97bd4 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters HitShapeCount.BindValueChanged(_ => { //Used to clear out the overflowing judgement children when the value is lowered - judgementsFlow.RemoveAll(_ => true); + judgementsFlow.RemoveAll(_ => true, true); judgementsFlow.Height = HitShapeCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; }, true); HitShape.BindValueChanged(_ => judgementsFlow.Shape.Value = HitShape.Value, true); From 667854b03445f7eb73292fa40fcc84ac2970fd4a Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 10 Sep 2022 23:18:48 +0300 Subject: [PATCH 1026/2686] Make effect display have a built-in counter --- osu.Game/Overlays/Mods/ModsEffectDisplay.cs | 37 +++++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs index 4e630439ee..98651ef5f0 100644 --- a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs +++ b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -11,6 +12,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Mods; using osuTK; @@ -26,7 +28,7 @@ namespace osu.Game.Overlays.Mods private readonly Box contentBackground; private readonly Box labelBackground; - private readonly Container content; + private readonly FillFlowContainer content; public Bindable Current { @@ -62,6 +64,8 @@ namespace osu.Game.Overlays.Mods protected virtual float ValueAreaWidth => 56; + protected virtual string CounterFormat => "N0"; + protected override Container Content => content; protected ModsEffectDisplay() @@ -121,12 +125,20 @@ namespace osu.Game.Overlays.Mods } } }, - content = new Container + content = new FillFlowContainer { AutoSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0) + Direction = FillDirection.Horizontal, + Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), + Spacing = new Vector2(2, 0), + Child = new EffectCounter(CounterFormat) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = { BindTarget = Current } + } } } } @@ -203,5 +215,24 @@ namespace osu.Game.Overlays.Mods DifficultyReduction, DifficultyIncrease } + + private class EffectCounter : RollingCounter + { + private readonly string? format; + + public EffectCounter(string? format) + { + this.format = format; + } + + protected override double RollingDuration => 500; + + protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(format); + + protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText + { + Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) + }; + } } } From 064fe832c78196b05cd0a807951747940e81d39b Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 10 Sep 2022 23:18:59 +0300 Subject: [PATCH 1027/2686] Fix test --- .../TestSceneModsEffectDisplay.cs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs index ec50a07998..42eceb3242 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; using osu.Framework.Testing; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; @@ -54,28 +53,15 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("colours are correct", () => testDisplay.Container.Colour == colourProvider.Background5 && background.Colour == colours.ForModType(ModType.DifficultyIncrease)); } - private class TestDisplay : ModsEffectDisplay + private class TestDisplay : ModsEffectDisplay { - private readonly OsuSpriteText text; - public Container Container => Content; protected override LocalisableString Label => "Test display"; - protected override ModEffect CalculateEffect(int value) => CalculateForSign(value.CompareTo(50)); public TestDisplay() { - Add(text = new OsuSpriteText - { - Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold), - Text = "50" - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - Current.BindValueChanged(e => text.Text = e.NewValue.ToString(), true); + Current.Default = 50; } } } From 3f93ec8538d3082bd0255d46ec0995372c18ed90 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 10 Sep 2022 23:20:28 +0300 Subject: [PATCH 1028/2686] Expose counter to inheritors --- osu.Game/Overlays/Mods/ModsEffectDisplay.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs index 98651ef5f0..3b112fdbd3 100644 --- a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs +++ b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs @@ -68,6 +68,8 @@ namespace osu.Game.Overlays.Mods protected override Container Content => content; + protected readonly RollingCounter Counter; + protected ModsEffectDisplay() { Height = HEIGHT; @@ -133,7 +135,7 @@ namespace osu.Game.Overlays.Mods Direction = FillDirection.Horizontal, Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0), Spacing = new Vector2(2, 0), - Child = new EffectCounter(CounterFormat) + Child = Counter = new EffectCounter(CounterFormat) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, From 324a3723a5dbba4b85f6d39617028acef7af005a Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 10 Sep 2022 23:23:04 +0300 Subject: [PATCH 1029/2686] Rewrite DMD --- .../Mods/DifficultyMultiplierDisplay.cs | 48 ++++--------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index 5530947d3d..f582a010c6 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -3,14 +3,9 @@ #nullable disable -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osuTK; using osu.Game.Localisation; @@ -20,34 +15,19 @@ namespace osu.Game.Overlays.Mods { protected override LocalisableString Label => DifficultyMultiplierDisplayStrings.DifficultyMultiplier; - private readonly MultiplierCounter multiplierCounter; + protected override string CounterFormat => @"N2"; public DifficultyMultiplierDisplay() { Current.Default = 1d; Current.Value = 1d; - Add(new FillFlowContainer + Add(new SpriteIcon { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(2, 0), - Children = new Drawable[] - { - multiplierCounter = new MultiplierCounter - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Current = { BindTarget = Current } - }, - new SpriteIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Icon = FontAwesome.Solid.Times, - Size = new Vector2(7), - Margin = new MarginPadding { Top = 1 } - } - } + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Icon = FontAwesome.Solid.Times, + Size = new Vector2(7), + Margin = new MarginPadding { Top = 1 } }); } @@ -57,19 +37,7 @@ namespace osu.Game.Overlays.Mods // required to prevent the counter initially rolling up from 0 to 1 // due to `Current.Value` having a nonstandard default value of 1. - multiplierCounter.SetCountWithoutRolling(Current.Value); - } - - private class MultiplierCounter : RollingCounter - { - protected override double RollingDuration => 500; - - protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(@"N2"); - - protected override OsuSpriteText CreateSpriteText() => new OsuSpriteText - { - Font = OsuFont.Default.With(size: 17, weight: FontWeight.SemiBold) - }; + Counter.SetCountWithoutRolling(Current.Value); } } } From 1eb2c74e57c3d18dfcac974bf7c52101a18806ec Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sun, 11 Sep 2022 18:50:51 +0900 Subject: [PATCH 1030/2686] Fix countdown serialisation --- osu.Game/Online/Multiplayer/MultiplayerCountdown.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs index 61637ae970..fd22420b99 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs @@ -33,6 +33,7 @@ namespace osu.Game.Online.Multiplayer /// /// Whether only a single instance of this type may be active at any one time. /// + [IgnoreMember] public virtual bool IsExclusive => true; } } From d6f90e3b9fd23496db6c57b8a3cb5339cf691cca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 11 Sep 2022 21:32:22 +0900 Subject: [PATCH 1031/2686] Add basic fling-to-dismiss support --- .../Overlays/Notifications/Notification.cs | 132 +++++++++++++++++- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 67739c2089..3e7bd0ab2f 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -2,16 +2,19 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osuTK; @@ -56,6 +59,8 @@ namespace osu.Game.Overlays.Notifications protected Container MainContent; + private readonly DragContainer dragContainer; + public virtual bool Read { get; set; } protected virtual IconUsage CloseButtonIcon => FontAwesome.Solid.Check; @@ -80,7 +85,11 @@ namespace osu.Game.Overlays.Notifications Anchor = Anchor.CentreLeft, Origin = Anchor.CentreRight, }, - MainContent = new Container + dragContainer = new DragContainer(this) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }.WithChild(MainContent = new Container { CornerRadius = 6, Masking = true, @@ -144,7 +153,7 @@ namespace osu.Game.Overlays.Notifications Blending = BlendingParameters.Additive, }, } - } + }) }; } @@ -213,11 +222,126 @@ namespace osu.Game.Overlays.Notifications WasClosed = true; - Closed?.Invoke(); - this.FadeOut(100); + if (dragContainer.FlingLeft()) + { + Light.FadeOut(100); + this.FadeOut(600, Easing.In); + } + else + { + Closed?.Invoke(); + this.FadeOut(100); + } + Expire(); } + private class DragContainer : Container + { + private Vector2 velocity; + private Vector2 lastPosition; + + private readonly Notification notification; + + public DragContainer(Notification notification) + { + this.notification = notification; + notification.Closed += () => FlingLeft(); + } + + public override RectangleF BoundingBox + { + get + { + var childBounding = Children.First().BoundingBox; + + if (X < 0) childBounding *= new Vector2(1, Math.Max(0, 1 + (X / 800))); + if (Y > 0) childBounding *= new Vector2(1, Math.Max(0, 1 - (Y / 800))); + + return childBounding; + } + } + + protected override bool OnDragStart(DragStartEvent e) => true; + + protected override void OnDrag(DragEvent e) + { + Vector2 change = e.MousePosition - e.MouseDownPosition; + + // Diminish the drag distance as we go further to simulate "rubber band" feeling. + change *= change.Length <= 0 ? 0 : MathF.Pow(change.Length, 0.9f) / change.Length; + + // Only apply Y change if dragging to the left. + if (change.X > 0) + change.Y = 0; + + this.MoveTo(change); + } + + protected override void OnDragEnd(DragEndEvent e) + { + if (Rotation < -10 || velocity.X < -0.3f) + { + FlingLeft(); + } + else + { + this.MoveTo(Vector2.Zero, 800, Easing.OutElastic); + this.RotateTo(0, 800, Easing.OutElastic); + } + + base.OnDragEnd(e); + } + + private bool flinging; + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + Rotation = Math.Min(0, X * 0.1f); + + if (flinging) + { + velocity.Y += (float)Clock.ElapsedFrameTime * 0.005f; + Position += (float)Clock.ElapsedFrameTime * velocity; + } + else + { + Vector2 change = (Position - lastPosition) / (float)Clock.ElapsedFrameTime; + + if (velocity.X == 0) + velocity = change; + else + { + velocity = new Vector2( + (float)Interpolation.DampContinuously(velocity.X, change.X, 40, Clock.ElapsedFrameTime), + (float)Interpolation.DampContinuously(velocity.Y, change.Y, 40, Clock.ElapsedFrameTime) + ); + } + + lastPosition = Position; + } + } + + public bool FlingLeft() + { + if (this.FindClosestParent() == null) + return false; + + if (flinging) + return true; + + if (velocity.X > -0.3f) + velocity.X = -0.3f - 0.5f * RNG.NextSingle(); + + flinging = true; + ClearTransforms(); + notification.Close(); + return true; + } + } + internal class CloseButton : OsuClickableContainer { private SpriteIcon icon = null!; From b5a2f7003e0d0770c53c775a36a2a24a893be05a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 11 Sep 2022 21:34:35 +0900 Subject: [PATCH 1032/2686] Disallow flinging when not in toast state --- osu.Game/Overlays/NotificationOverlay.cs | 5 +++++ osu.Game/Overlays/Notifications/Notification.cs | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index b170ea5dfa..708bd4874d 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -158,7 +158,10 @@ namespace osu.Game.Overlays playDebouncedSample(notification.PopInSampleName); if (State.Value == Visibility.Hidden) + { + notification.IsInTray = true; toastTray.Post(notification); + } else addPermanently(notification); @@ -167,6 +170,8 @@ namespace osu.Game.Overlays private void addPermanently(Notification notification) { + notification.IsInTray = false; + var ourType = notification.GetType(); int depth = notification.DisplayOnTop ? -runningDepth : runningDepth; diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 3e7bd0ab2f..595cff4171 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -68,6 +68,11 @@ namespace osu.Game.Overlays.Notifications [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + /// + /// Whether this notification is in the . + /// + public bool IsInTray { get; set; } + private readonly Box initialFlash; private Box background = null!; @@ -262,7 +267,7 @@ namespace osu.Game.Overlays.Notifications } } - protected override bool OnDragStart(DragStartEvent e) => true; + protected override bool OnDragStart(DragStartEvent e) => notification.IsInTray; protected override void OnDrag(DragEvent e) { @@ -326,7 +331,7 @@ namespace osu.Game.Overlays.Notifications public bool FlingLeft() { - if (this.FindClosestParent() == null) + if (!notification.IsInTray) return false; if (flinging) From a56cadcf9057278f2aa3735a79385e0c2c097239 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 11 Sep 2022 21:52:19 +0900 Subject: [PATCH 1033/2686] Ensure drag position is reset when transferred to tray --- osu.Game/Overlays/NotificationOverlay.cs | 4 +-- .../Overlays/Notifications/Notification.cs | 33 ++++++++++++++----- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 708bd4874d..15573f99af 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -159,7 +159,7 @@ namespace osu.Game.Overlays if (State.Value == Visibility.Hidden) { - notification.IsInTray = true; + notification.IsInToastTray = true; toastTray.Post(notification); } else @@ -170,7 +170,7 @@ namespace osu.Game.Overlays private void addPermanently(Notification notification) { - notification.IsInTray = false; + notification.IsInToastTray = false; var ourType = notification.GetType(); int depth = notification.DisplayOnTop ? -runningDepth : runningDepth; diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 595cff4171..ded3c1606a 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -68,10 +68,21 @@ namespace osu.Game.Overlays.Notifications [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + private bool isInToastTray; + /// /// Whether this notification is in the . /// - public bool IsInTray { get; set; } + public bool IsInToastTray + { + private get => isInToastTray; + set + { + isInToastTray = value; + if (!isInToastTray) + dragContainer.ResetPosition(); + } + } private readonly Box initialFlash; @@ -267,10 +278,13 @@ namespace osu.Game.Overlays.Notifications } } - protected override bool OnDragStart(DragStartEvent e) => notification.IsInTray; + protected override bool OnDragStart(DragStartEvent e) => notification.IsInToastTray; protected override void OnDrag(DragEvent e) { + if (!notification.IsInToastTray) + return; + Vector2 change = e.MousePosition - e.MouseDownPosition; // Diminish the drag distance as we go further to simulate "rubber band" feeling. @@ -286,14 +300,9 @@ namespace osu.Game.Overlays.Notifications protected override void OnDragEnd(DragEndEvent e) { if (Rotation < -10 || velocity.X < -0.3f) - { FlingLeft(); - } else - { - this.MoveTo(Vector2.Zero, 800, Easing.OutElastic); - this.RotateTo(0, 800, Easing.OutElastic); - } + ResetPosition(); base.OnDragEnd(e); } @@ -331,7 +340,7 @@ namespace osu.Game.Overlays.Notifications public bool FlingLeft() { - if (!notification.IsInTray) + if (!notification.IsInToastTray) return false; if (flinging) @@ -345,6 +354,12 @@ namespace osu.Game.Overlays.Notifications notification.Close(); return true; } + + public void ResetPosition() + { + this.MoveTo(Vector2.Zero, 800, Easing.OutElastic); + this.RotateTo(0, 800, Easing.OutElastic); + } } internal class CloseButton : OsuClickableContainer From 9ef23c79ced4e8ca705bec6ba20505a216791312 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 11 Sep 2022 22:05:44 +0900 Subject: [PATCH 1034/2686] Disallow forwarding during a drag operation --- osu.Game/Overlays/NotificationOverlayToastTray.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index 40324963fc..e4d3864beb 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -118,7 +118,7 @@ namespace osu.Game.Overlays return; // Notification hovered; delay dismissal. - if (notification.IsHovered) + if (notification.IsHovered || notification.IsDragged) { scheduleDismissal(); return; From bb3d5bc9f4d8b5c47ec2c833fd59a985c90264e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 12 Sep 2022 04:43:15 +0900 Subject: [PATCH 1035/2686] test(osu.Game): add slider steps to change the size in timing distribution graph tests --- .../TestSceneHitEventTimingDistributionGraph.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs index 198be4035b..e014d79402 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; @@ -19,14 +20,24 @@ namespace osu.Game.Tests.Visual.Ranking public class TestSceneHitEventTimingDistributionGraph : OsuTestScene { private HitEventTimingDistributionGraph graph = null!; + private readonly BindableFloat width = new BindableFloat(600); + private readonly BindableFloat height = new BindableFloat(130); private static readonly HitObject placeholder_object = new HitCircle(); + public TestSceneHitEventTimingDistributionGraph() + { + width.BindValueChanged(e => graph.Width = e.NewValue); + height.BindValueChanged(e => graph.Height = e.NewValue); + } + [Test] public void TestManyDistributedEvents() { createTest(CreateDistributedHitEvents()); AddStep("add adjustment", () => graph.UpdateOffset(10)); + AddSliderStep("width", 0.0f, 1000.0f, width.Value, width.Set); + AddSliderStep("height", 0.0f, 1000.0f, height.Value, height.Set); } [Test] @@ -137,7 +148,7 @@ namespace osu.Game.Tests.Visual.Ranking { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(600, 130) + Size = new Vector2(width.Value, height.Value) } }; }); From ac324c63e2d0e3f0e9293519b6728aa7d415f90b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 12 Sep 2022 04:46:32 +0900 Subject: [PATCH 1036/2686] fix(osu.Game): handle size changes in timing distribution graph --- .../HitEventTimingDistributionGraph.cs | 83 ++++++++++++++----- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 5335d77243..72603fd46b 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -209,13 +210,12 @@ namespace osu.Game.Screens.Ranking.Statistics private class Bar : CompositeDrawable { - private float totalValue => values.Sum(v => v.Value); - private float basalHeight => BoundingBox.Width / BoundingBox.Height; - private float availableHeight => 1 - basalHeight; - private readonly IReadOnlyList> values; private readonly float maxValue; private readonly bool isCentre; + private readonly float totalValue; + private readonly BindableFloat basalHeight; + private readonly BindableFloat offsetAdjustment; private Circle[] boxOriginals; private Circle boxAdjustment; @@ -228,6 +228,9 @@ namespace osu.Game.Screens.Ranking.Statistics this.values = values.OrderBy(v => v.Key.GetIndexForOrderedDisplay()).ToList(); this.maxValue = maxValue; this.isCentre = isCentre; + totalValue = values.Sum(v => v.Value); + basalHeight = new BindableFloat(); + offsetAdjustment = new BindableFloat(totalValue); RelativeSizeAxes = Axes.Both; Masking = true; @@ -254,38 +257,70 @@ namespace osu.Game.Screens.Ranking.Statistics else { // A bin with no value draws a grey dot instead. - InternalChildren = boxOriginals = new[] + Circle dot = new Circle { - new Circle - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Colour = isCentre ? Color4.White : Color4.Gray, - Height = 0, - }, + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Colour = isCentre ? Color4.White : Color4.Gray, + Height = 0, }; + InternalChildren = boxOriginals = new[] { dot }; + basalHeight.BindValueChanged(e => dot.Height = e.NewValue); } + + offsetAdjustment.BindValueChanged(_ => drawAdjustmentBar()); } private const double duration = 300; - private float offsetForValue(float value) + private float calculateBasalHeight() => DrawHeight == 0 ? 0 : DrawWidth / DrawHeight; + + private float offsetForValue(float value) => (1 - basalHeight.Value) * value / maxValue; + + private float heightForValue(float value) => MathF.Max(basalHeight.Value + offsetForValue(value), 0); + + private void draw() { - return availableHeight * value / maxValue; + resizeBars(); + + if (boxAdjustment != null) + drawAdjustmentBar(); } - private float heightForValue(float value) + private void resizeBars() { - return basalHeight + offsetForValue(value); + float offsetValue = 0; + + for (int i = 0; i < values.Count; i++) + { + boxOriginals[i].Y = offsetForValue(offsetValue) * BoundingBox.Height; + boxOriginals[i].Height = heightForValue(values[i].Value); + offsetValue -= values[i].Value; + } + } + + private void drawAdjustmentBar() + { + bool hasAdjustment = offsetAdjustment.Value != totalValue; + + boxAdjustment.ResizeHeightTo(heightForValue(offsetAdjustment.Value), duration, Easing.OutQuint); + boxAdjustment.FadeTo(!hasAdjustment ? 0 : 1, duration, Easing.OutQuint); } protected override void LoadComplete() { base.LoadComplete(); + float height = calculateBasalHeight(); + + basalHeight.Set(height); + + if (!values.Any()) + return; + foreach (var boxOriginal in boxOriginals) - boxOriginal.Height = basalHeight; + boxOriginal.Height = height; float offsetValue = 0; @@ -295,6 +330,15 @@ namespace osu.Game.Screens.Ranking.Statistics boxOriginals[i].ResizeHeightTo(heightForValue(values[i].Value), duration, Easing.OutQuint); offsetValue -= values[i].Value; } + + basalHeight.BindValueChanged(_ => draw()); + } + + protected override void Update() + { + base.Update(); + + basalHeight.Set(calculateBasalHeight()); } public void UpdateOffset(float adjustment) @@ -318,8 +362,7 @@ namespace osu.Game.Screens.Ranking.Statistics }); } - boxAdjustment.ResizeHeightTo(heightForValue(adjustment), duration, Easing.OutQuint); - boxAdjustment.FadeTo(!hasAdjustment ? 0 : 1, duration, Easing.OutQuint); + offsetAdjustment.Set(adjustment); } } } From 24138b65a74c1d57a2267dce3510f01442a3fabb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 14:05:16 +0900 Subject: [PATCH 1037/2686] Fix storyboard animations not starting their animation playback from the correct point in time --- .../Drawables/DrawableStoryboardAnimation.cs | 16 ++++++++++++++++ osu.Game/Storyboards/StoryboardSprite.cs | 10 +++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index f3187d77b7..369a3ee7ba 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; +using osu.Game.Screens.Play; using osu.Game.Skinning; using osuTK; @@ -115,6 +116,21 @@ namespace osu.Game.Storyboards.Drawables Animation.ApplyTransforms(this); } + [Resolved] + private IGameplayClock gameplayClock { get; set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + // Framework animation class tries its best to synchronise the animation at LoadComplete, + // but in some cases (such as fast forward) this results in an incorrect start offset. + // + // In the case of storyboard animations, we want to synchronise with game time perfectly + // so let's get a correct time based on gameplay clock and earliest transform. + PlaybackPosition = gameplayClock.CurrentTime - Animation.EarliestTransformTime; + } + private void skinSourceChanged() { ClearFrames(); diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index 1eeaa0f084..589bcb60be 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -26,7 +26,7 @@ namespace osu.Game.Storyboards public readonly CommandTimelineGroup TimelineGroup = new CommandTimelineGroup(); - public double StartTime + public virtual double StartTime { get { @@ -54,6 +54,14 @@ namespace osu.Game.Storyboards return firstAlpha.startTime; } + return EarliestTransformTime; + } + } + + public double EarliestTransformTime + { + get + { // If we got to this point, either no alpha commands were present, or the earliest had a non-zero start value. // The sprite's StartTime will be determined by the earliest command, regardless of type. double earliestStartTime = TimelineGroup.StartTime; From cf25ee8e8482b5c60fb6fd8b8f0d7e23fcf903d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 14:17:15 +0900 Subject: [PATCH 1038/2686] Add test coverage of storyboard animation start time --- .../Formats/LegacyStoryboardDecoderTest.cs | 19 +++++++++++++++++++ .../animation-starts-before-alpha.osb | 5 +++++ 2 files changed, 24 insertions(+) create mode 100644 osu.Game.Tests/Resources/animation-starts-before-alpha.osb diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs index 6e41043b0b..d9e80fa111 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs @@ -97,6 +97,25 @@ namespace osu.Game.Tests.Beatmaps.Formats } } + [Test] + public void TestCorrectAnimationStartTime() + { + var decoder = new LegacyStoryboardDecoder(); + + using (var resStream = TestResources.OpenResource("animation-starts-before-alpha.osb")) + using (var stream = new LineBufferedReader(resStream)) + { + var storyboard = decoder.Decode(stream); + + StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); + Assert.AreEqual(1, background.Elements.Count); + + Assert.AreEqual(2000, background.Elements[0].StartTime); + // This property should be used in DrawableStoryboardAnimation as a starting point for animation playback. + Assert.AreEqual(1000, (background.Elements[0] as StoryboardAnimation)?.EarliestTransformTime); + } + } + [Test] public void TestOutOfOrderStartTimes() { diff --git a/osu.Game.Tests/Resources/animation-starts-before-alpha.osb b/osu.Game.Tests/Resources/animation-starts-before-alpha.osb new file mode 100644 index 0000000000..ceef204f3f --- /dev/null +++ b/osu.Game.Tests/Resources/animation-starts-before-alpha.osb @@ -0,0 +1,5 @@ +[Events] +//Storyboard Layer 0 (Background) +Animation,Background,Centre,"img.jpg",320,240,2,150,LoopForever + S,0,1000,1500,0.08 // animation should start playing from this point in time.. + F,0,2000,,0,1 // .. not this point in time From bbf906ee064507157512ba692962707a4c682b1b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 14:20:48 +0900 Subject: [PATCH 1039/2686] Remove unnecessary `virtual` spec --- osu.Game/Storyboards/StoryboardSprite.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index 589bcb60be..cd7788bb08 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -26,7 +26,7 @@ namespace osu.Game.Storyboards public readonly CommandTimelineGroup TimelineGroup = new CommandTimelineGroup(); - public virtual double StartTime + public double StartTime { get { From eca241e9a71943f45b0226b02ea645c1790751e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 14:52:11 +0900 Subject: [PATCH 1040/2686] Move `UpdateProgressNotification` to base `UpdateManager` class --- osu.Desktop/Updater/SquirrelUpdateManager.cs | 112 ++++++------------- osu.Game/Updater/UpdateManager.cs | 72 +++++++++++- 2 files changed, 99 insertions(+), 85 deletions(-) diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index 6f45237522..84bac9da7c 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -5,26 +5,24 @@ using System; using System.Runtime.Versioning; using System.Threading.Tasks; using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; using osu.Framework.Logging; using osu.Game; -using osu.Game.Graphics; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osuTK; using Squirrel; using Squirrel.SimpleSplat; +using LogLevel = Squirrel.SimpleSplat.LogLevel; +using UpdateManager = osu.Game.Updater.UpdateManager; namespace osu.Desktop.Updater { [SupportedOSPlatform("windows")] - public class SquirrelUpdateManager : osu.Game.Updater.UpdateManager + public class SquirrelUpdateManager : UpdateManager { - private UpdateManager? updateManager; + private Squirrel.UpdateManager? updateManager; private INotificationOverlay notificationOverlay = null!; - public Task PrepareUpdateAsync() => UpdateManager.RestartAppWhenExited(); + public Task PrepareUpdateAsync() => Squirrel.UpdateManager.RestartAppWhenExited(); private static readonly Logger logger = Logger.GetLogger("updater"); @@ -35,6 +33,9 @@ namespace osu.Desktop.Updater private readonly SquirrelLogger squirrelLogger = new SquirrelLogger(); + [Resolved] + private OsuGameBase game { get; set; } = null!; + [BackgroundDependencyLoader] private void load(INotificationOverlay notifications) { @@ -63,7 +64,14 @@ namespace osu.Desktop.Updater if (updatePending) { // the user may have dismissed the completion notice, so show it again. - notificationOverlay.Post(new UpdateCompleteNotification(this)); + notificationOverlay.Post(new UpdateApplicationCompleteNotification + { + Activated = () => + { + restartToApplyUpdate(); + return true; + }, + }); return true; } @@ -75,19 +83,21 @@ namespace osu.Desktop.Updater if (notification == null) { - notification = new UpdateProgressNotification(this) { State = ProgressNotificationState.Active }; + notification = new UpdateProgressNotification + { + CompletionClickAction = restartToApplyUpdate, + }; + Schedule(() => notificationOverlay.Post(notification)); } - notification.Progress = 0; - notification.Text = @"Downloading update..."; + notification.StartDownload(); try { await updateManager.DownloadReleases(info.ReleasesToApply, p => notification.Progress = p / 100f).ConfigureAwait(false); - notification.Progress = 0; - notification.Text = @"Installing update..."; + notification.StartInstall(); await updateManager.ApplyReleases(info, p => notification.Progress = p / 100f).ConfigureAwait(false); @@ -107,9 +117,7 @@ namespace osu.Desktop.Updater else { // In the case of an error, a separate notification will be displayed. - notification.State = ProgressNotificationState.Cancelled; - notification.Close(); - + notification.FailDownload(); Logger.Error(e, @"update failed!"); } } @@ -131,78 +139,24 @@ namespace osu.Desktop.Updater return true; } + private bool restartToApplyUpdate() + { + PrepareUpdateAsync() + .ContinueWith(_ => Schedule(() => game.AttemptExit())); + return true; + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); updateManager?.Dispose(); } - private class UpdateCompleteNotification : ProgressCompletionNotification - { - [Resolved] - private OsuGame game { get; set; } = null!; - - public UpdateCompleteNotification(SquirrelUpdateManager updateManager) - { - Text = @"Update ready to install. Click to restart!"; - - Activated = () => - { - updateManager.PrepareUpdateAsync() - .ContinueWith(_ => updateManager.Schedule(() => game.AttemptExit())); - return true; - }; - } - } - - private class UpdateProgressNotification : ProgressNotification - { - private readonly SquirrelUpdateManager updateManager; - - public UpdateProgressNotification(SquirrelUpdateManager updateManager) - { - this.updateManager = updateManager; - } - - protected override Notification CreateCompletionNotification() - { - return new UpdateCompleteNotification(updateManager); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - IconContent.AddRange(new Drawable[] - { - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Icon = FontAwesome.Solid.Upload, - Size = new Vector2(20), - } - }); - } - - public override void Close() - { - // cancelling updates is not currently supported by the underlying updater. - // only allow dismissing for now. - - switch (State) - { - case ProgressNotificationState.Cancelled: - base.Close(); - break; - } - } - } - private class SquirrelLogger : ILogger, IDisposable { - public Squirrel.SimpleSplat.LogLevel Level { get; set; } = Squirrel.SimpleSplat.LogLevel.Info; + public LogLevel Level { get; set; } = LogLevel.Info; - public void Write(string message, Squirrel.SimpleSplat.LogLevel logLevel) + public void Write(string message, LogLevel logLevel) { if (logLevel < Level) return; diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index 4790055cd1..801f2daac5 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -1,16 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; +using osuTK; namespace osu.Game.Updater { @@ -27,13 +27,13 @@ namespace osu.Game.Updater GetType() != typeof(UpdateManager); [Resolved] - private OsuConfigManager config { get; set; } + private OsuConfigManager config { get; set; } = null!; [Resolved] - private OsuGameBase game { get; set; } + private OsuGameBase game { get; set; } = null!; [Resolved] - protected INotificationOverlay Notifications { get; private set; } + protected INotificationOverlay Notifications { get; private set; } = null!; protected override void LoadComplete() { @@ -59,7 +59,7 @@ namespace osu.Game.Updater private readonly object updateTaskLock = new object(); - private Task updateCheckTask; + private Task? updateCheckTask; public async Task CheckForUpdateAsync() { @@ -109,5 +109,65 @@ namespace osu.Game.Updater }; } } + + protected class UpdateApplicationCompleteNotification : ProgressCompletionNotification + { + public UpdateApplicationCompleteNotification() + { + Text = @"Update ready to install. Click to restart!"; + } + } + + public class UpdateProgressNotification : ProgressNotification + { + protected override Notification CreateCompletionNotification() => new UpdateApplicationCompleteNotification(); + + [BackgroundDependencyLoader] + private void load() + { + IconContent.AddRange(new Drawable[] + { + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Icon = FontAwesome.Solid.Upload, + Size = new Vector2(14), + } + }); + } + + public override void Close() + { + // cancelling updates is not currently supported by the underlying updater. + // only allow dismissing for now. + + switch (State) + { + case ProgressNotificationState.Cancelled: + base.Close(); + break; + } + } + + public void StartDownload() + { + State = ProgressNotificationState.Active; + Progress = 0; + Text = @"Downloading update..."; + } + + public void StartInstall() + { + Progress = 0; + Text = @"Installing update..."; + } + + public void FailDownload() + { + State = ProgressNotificationState.Cancelled; + Close(); + } + } } } From 2b79e6b2de20e64cd984c4bb8c5878bc28bdb10e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 14:52:16 +0900 Subject: [PATCH 1041/2686] Add test coverage of update notification --- .../TestSceneNotificationOverlay.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 699b8f7d89..1afe8327b3 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -12,6 +12,7 @@ using osu.Framework.Utils; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; +using osu.Game.Updater; namespace osu.Game.Tests.Visual.UserInterface { @@ -134,6 +135,31 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("cancel notification", () => notification.State = ProgressNotificationState.Cancelled); } + [Test] + public void TestUpdateNotificationFlow() + { + bool applyUpdate = false; + + AddStep(@"post update", () => + { + applyUpdate = false; + + var updateNotification = new UpdateManager.UpdateProgressNotification + { + CompletionClickAction = () => applyUpdate = true + }; + + notificationOverlay.Post(updateNotification); + progressingNotifications.Add(updateNotification); + }); + + checkProgressingCount(1); + waitForCompletion(); + AddStep("click notification", () => notificationOverlay.ChildrenOfType().Single().TriggerClick()); + + AddUntilStep("wait for update applied", () => applyUpdate); + } + [Test] public void TestBasicFlow() { From 60b0b909a51d1986956cddbf56a6927f1025b649 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 14:58:46 +0900 Subject: [PATCH 1042/2686] Move update icon to background to avoid colour collission with progress spinner --- .../Overlays/Notifications/ProgressNotification.cs | 1 + osu.Game/Updater/UpdateManager.cs | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 64ad69adf3..bdf6f704e5 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -226,6 +226,7 @@ namespace osu.Game.Overlays.Notifications { RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, + Depth = float.MaxValue, }, loadingSpinner = new LoadingSpinner { diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index 801f2daac5..8dcb1c4562 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -132,11 +132,19 @@ namespace osu.Game.Updater Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = FontAwesome.Solid.Upload, - Size = new Vector2(14), + Size = new Vector2(34), + Colour = OsuColour.Gray(0.2f), + Depth = float.MaxValue, } }); } + protected override void LoadComplete() + { + base.LoadComplete(); + StartDownload(); + } + public override void Close() { // cancelling updates is not currently supported by the underlying updater. From 9b31aa6d7ace1a41888315f0bdcfc06ebf86c01a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 15:04:30 +0900 Subject: [PATCH 1043/2686] Fix activation not firing with refactors --- .../Visual/UserInterface/TestSceneNotificationOverlay.cs | 6 +++++- osu.Game/Updater/UpdateManager.cs | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 1afe8327b3..f497a5bd6b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -155,7 +155,11 @@ namespace osu.Game.Tests.Visual.UserInterface checkProgressingCount(1); waitForCompletion(); - AddStep("click notification", () => notificationOverlay.ChildrenOfType().Single().TriggerClick()); + + UpdateManager.UpdateApplicationCompleteNotification? completionNotification = null; + AddUntilStep("wait for completion notification", + () => (completionNotification = notificationOverlay.ChildrenOfType().SingleOrDefault()) != null); + AddStep("click notification", () => completionNotification?.TriggerClick()); AddUntilStep("wait for update applied", () => applyUpdate); } diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index 8dcb1c4562..49009e9124 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -110,7 +110,7 @@ namespace osu.Game.Updater } } - protected class UpdateApplicationCompleteNotification : ProgressCompletionNotification + public class UpdateApplicationCompleteNotification : ProgressCompletionNotification { public UpdateApplicationCompleteNotification() { @@ -120,7 +120,10 @@ namespace osu.Game.Updater public class UpdateProgressNotification : ProgressNotification { - protected override Notification CreateCompletionNotification() => new UpdateApplicationCompleteNotification(); + protected override Notification CreateCompletionNotification() => new UpdateApplicationCompleteNotification + { + Activated = CompletionClickAction + }; [BackgroundDependencyLoader] private void load() From 92beb6cbe740336ab84e920818bb4fe5b372563f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 15:16:45 +0900 Subject: [PATCH 1044/2686] Hide notification read light when in a toast state Also adds test coverage of read state and light. --- .../TestSceneNotificationOverlay.cs | 20 +++++++++++++++++++ .../Overlays/Notifications/Notification.cs | 11 ++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 5f82a0024b..6b737b7f5f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -219,6 +219,26 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("cancel notification", () => notification.State = ProgressNotificationState.Cancelled); } + [Test] + public void TestReadState() + { + SimpleNotification notification = null!; + AddStep(@"post", () => notificationOverlay.Post(notification = new BackgroundNotification { Text = @"Welcome to osu!. Enjoy your stay!" })); + AddUntilStep("check is toast", () => !notification.IsInToastTray); + AddAssert("light is not visible", () => notification.ChildrenOfType().Single().Alpha == 0); + + AddUntilStep("wait for forward to overlay", () => !notification.IsInToastTray); + + setState(Visibility.Visible); + AddAssert("state is not read", () => !notification.Read); + AddUntilStep("light is visible", () => notification.ChildrenOfType().Single().Alpha == 1); + + setState(Visibility.Hidden); + setState(Visibility.Visible); + AddAssert("state is read", () => notification.Read); + AddUntilStep("light is not visible", () => notification.ChildrenOfType().Single().Alpha == 0); + } + [Test] public void TestBasicFlow() { diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index ded3c1606a..91f5f3b19b 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -75,12 +75,17 @@ namespace osu.Game.Overlays.Notifications ///
public bool IsInToastTray { - private get => isInToastTray; + get => isInToastTray; set { isInToastTray = value; + if (!isInToastTray) + { dragContainer.ResetPosition(); + if (!Read) + Light.FadeIn(100); + } } } @@ -97,6 +102,7 @@ namespace osu.Game.Overlays.Notifications { Light = new NotificationLight { + Alpha = 0, Margin = new MarginPadding { Right = 5 }, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreRight, @@ -239,10 +245,7 @@ namespace osu.Game.Overlays.Notifications WasClosed = true; if (dragContainer.FlingLeft()) - { - Light.FadeOut(100); this.FadeOut(600, Easing.In); - } else { Closed?.Invoke(); From e06a0f7300fc9cb71b7a9914a1f8143481a57790 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 15:21:01 +0900 Subject: [PATCH 1045/2686] Fix dragged state not being exposed correctly --- osu.Game/Overlays/Notifications/Notification.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 91f5f3b19b..248d66ac16 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -63,6 +63,8 @@ namespace osu.Game.Overlays.Notifications public virtual bool Read { get; set; } + public new bool IsDragged => dragContainer.IsDragged; + protected virtual IconUsage CloseButtonIcon => FontAwesome.Solid.Check; [Resolved] From 2476cf8fb36e4e964b397d86ae082a0ab1de6149 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 15:37:48 +0900 Subject: [PATCH 1046/2686] Adjust movement to look less sudden when snapping back to Y=0 --- osu.Game/Overlays/Notifications/Notification.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 248d66ac16..2e4b0c430a 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -293,11 +293,13 @@ namespace osu.Game.Overlays.Notifications Vector2 change = e.MousePosition - e.MouseDownPosition; // Diminish the drag distance as we go further to simulate "rubber band" feeling. - change *= change.Length <= 0 ? 0 : MathF.Pow(change.Length, 0.9f) / change.Length; + change *= change.Length <= 0 ? 0 : MathF.Pow(change.Length, 0.8f) / change.Length; // Only apply Y change if dragging to the left. - if (change.X > 0) + if (change.X >= 0) change.Y = 0; + else + change.Y *= (float)Interpolation.ApplyEasing(Easing.InOutQuart, Math.Min(1, -change.X / 200)); this.MoveTo(change); } From 0755289ec3cfce14b47250baffabbbcacb76203e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 15:48:50 +0900 Subject: [PATCH 1047/2686] Apply NRT to `HitEventTimingDistributionGraph` --- .../HitEventTimingDistributionGraph.cs | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 72603fd46b..930a702958 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -48,6 +46,12 @@ namespace osu.Game.Screens.Ranking.Statistics ///
private readonly IReadOnlyList hitEvents; + private readonly IDictionary[] bins; + private double binSize; + private double hitOffset; + + private Bar[]? barDrawables; + /// /// Creates a new . /// @@ -55,22 +59,15 @@ namespace osu.Game.Screens.Ranking.Statistics public HitEventTimingDistributionGraph(IReadOnlyList hitEvents) { this.hitEvents = hitEvents.Where(e => !(e.HitObject.HitWindows is HitWindows.EmptyHitWindows) && e.Result.IsHit()).ToList(); + bins = Enumerable.Range(0, total_timing_distribution_bins).Select(_ => new Dictionary()).ToArray>(); } - private IDictionary[] bins; - private double binSize; - private double hitOffset; - - private Bar[] barDrawables; - [BackgroundDependencyLoader] private void load() { - if (hitEvents == null || hitEvents.Count == 0) + if (hitEvents.Count == 0) return; - bins = Enumerable.Range(0, total_timing_distribution_bins).Select(_ => new Dictionary()).ToArray>(); - binSize = Math.Ceiling(hitEvents.Max(e => Math.Abs(e.TimeOffset)) / timing_distribution_bins); // Prevent div-by-0 by enforcing a minimum bin size @@ -217,11 +214,12 @@ namespace osu.Game.Screens.Ranking.Statistics private readonly BindableFloat basalHeight; private readonly BindableFloat offsetAdjustment; - private Circle[] boxOriginals; - private Circle boxAdjustment; + private Circle[] boxOriginals = null!; + + private Circle? boxAdjustment; [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; public Bar(IDictionary values, float maxValue, bool isCentre) { From bcd2445d9b7a91d9e870cde3d3db5b505ca94a21 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 15:50:10 +0900 Subject: [PATCH 1048/2686] Move helper functions down in file --- .../HitEventTimingDistributionGraph.cs | 115 +++++++++--------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 930a702958..8ef85d24c4 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -221,6 +221,8 @@ namespace osu.Game.Screens.Ranking.Statistics [Resolved] private OsuColour colours { get; set; } = null!; + private const double duration = 300; + public Bar(IDictionary values, float maxValue, bool isCentre) { this.values = values.OrderBy(v => v.Key.GetIndexForOrderedDisplay()).ToList(); @@ -270,7 +272,61 @@ namespace osu.Game.Screens.Ranking.Statistics offsetAdjustment.BindValueChanged(_ => drawAdjustmentBar()); } - private const double duration = 300; + protected override void LoadComplete() + { + base.LoadComplete(); + + float height = calculateBasalHeight(); + + basalHeight.Value = height; + + if (!values.Any()) + return; + + foreach (var boxOriginal in boxOriginals) + boxOriginal.Height = height; + + float offsetValue = 0; + + for (int i = 0; i < values.Count; i++) + { + boxOriginals[i].MoveToY(offsetForValue(offsetValue) * BoundingBox.Height, duration, Easing.OutQuint); + boxOriginals[i].ResizeHeightTo(heightForValue(values[i].Value), duration, Easing.OutQuint); + offsetValue -= values[i].Value; + } + + basalHeight.BindValueChanged(_ => draw()); + } + + protected override void Update() + { + base.Update(); + basalHeight.Value = calculateBasalHeight(); + } + + public void UpdateOffset(float adjustment) + { + bool hasAdjustment = adjustment != totalValue; + + if (boxAdjustment == null) + { + if (!hasAdjustment) + return; + + AddInternal(boxAdjustment = new Circle + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Colour = Color4.Yellow, + Blending = BlendingParameters.Additive, + Alpha = 0.6f, + Height = 0, + }); + } + + offsetAdjustment.Set(adjustment); + } private float calculateBasalHeight() => DrawHeight == 0 ? 0 : DrawWidth / DrawHeight; @@ -305,63 +361,6 @@ namespace osu.Game.Screens.Ranking.Statistics boxAdjustment.ResizeHeightTo(heightForValue(offsetAdjustment.Value), duration, Easing.OutQuint); boxAdjustment.FadeTo(!hasAdjustment ? 0 : 1, duration, Easing.OutQuint); } - - protected override void LoadComplete() - { - base.LoadComplete(); - - float height = calculateBasalHeight(); - - basalHeight.Set(height); - - if (!values.Any()) - return; - - foreach (var boxOriginal in boxOriginals) - boxOriginal.Height = height; - - float offsetValue = 0; - - for (int i = 0; i < values.Count; i++) - { - boxOriginals[i].MoveToY(offsetForValue(offsetValue) * BoundingBox.Height, duration, Easing.OutQuint); - boxOriginals[i].ResizeHeightTo(heightForValue(values[i].Value), duration, Easing.OutQuint); - offsetValue -= values[i].Value; - } - - basalHeight.BindValueChanged(_ => draw()); - } - - protected override void Update() - { - base.Update(); - - basalHeight.Set(calculateBasalHeight()); - } - - public void UpdateOffset(float adjustment) - { - bool hasAdjustment = adjustment != totalValue; - - if (boxAdjustment == null) - { - if (!hasAdjustment) - return; - - AddInternal(boxAdjustment = new Circle - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - Colour = Color4.Yellow, - Blending = BlendingParameters.Additive, - Alpha = 0.6f, - Height = 0, - }); - } - - offsetAdjustment.Set(adjustment); - } } } } From 96951057df199df099e61af0b4136cd1909ebe1f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 15:56:06 +0900 Subject: [PATCH 1049/2686] Avoid using bindables --- .../HitEventTimingDistributionGraph.cs | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 8ef85d24c4..ebf521ba21 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -211,8 +210,9 @@ namespace osu.Game.Screens.Ranking.Statistics private readonly float maxValue; private readonly bool isCentre; private readonly float totalValue; - private readonly BindableFloat basalHeight; - private readonly BindableFloat offsetAdjustment; + + private float basalHeight; + private float offsetAdjustment; private Circle[] boxOriginals = null!; @@ -229,8 +229,7 @@ namespace osu.Game.Screens.Ranking.Statistics this.maxValue = maxValue; this.isCentre = isCentre; totalValue = values.Sum(v => v.Value); - basalHeight = new BindableFloat(); - offsetAdjustment = new BindableFloat(totalValue); + offsetAdjustment = totalValue; RelativeSizeAxes = Axes.Both; Masking = true; @@ -266,25 +265,20 @@ namespace osu.Game.Screens.Ranking.Statistics Height = 0, }; InternalChildren = boxOriginals = new[] { dot }; - basalHeight.BindValueChanged(e => dot.Height = e.NewValue); } - - offsetAdjustment.BindValueChanged(_ => drawAdjustmentBar()); } protected override void LoadComplete() { base.LoadComplete(); - float height = calculateBasalHeight(); - - basalHeight.Value = height; - if (!values.Any()) return; + updateBasalHeight(); + foreach (var boxOriginal in boxOriginals) - boxOriginal.Height = height; + boxOriginal.Height = basalHeight; float offsetValue = 0; @@ -294,14 +288,12 @@ namespace osu.Game.Screens.Ranking.Statistics boxOriginals[i].ResizeHeightTo(heightForValue(values[i].Value), duration, Easing.OutQuint); offsetValue -= values[i].Value; } - - basalHeight.BindValueChanged(_ => draw()); } protected override void Update() { base.Update(); - basalHeight.Value = calculateBasalHeight(); + updateBasalHeight(); } public void UpdateOffset(float adjustment) @@ -325,14 +317,27 @@ namespace osu.Game.Screens.Ranking.Statistics }); } - offsetAdjustment.Set(adjustment); + offsetAdjustment = adjustment; + drawAdjustmentBar(); } - private float calculateBasalHeight() => DrawHeight == 0 ? 0 : DrawWidth / DrawHeight; + private void updateBasalHeight() + { + float newBasalHeight = DrawHeight == 0 ? 0 : DrawWidth / DrawHeight; - private float offsetForValue(float value) => (1 - basalHeight.Value) * value / maxValue; + if (newBasalHeight == basalHeight) + return; - private float heightForValue(float value) => MathF.Max(basalHeight.Value + offsetForValue(value), 0); + basalHeight = newBasalHeight; + foreach (var dot in boxOriginals) + dot.Height = basalHeight; + + draw(); + } + + private float offsetForValue(float value) => (1 - basalHeight) * value / maxValue; + + private float heightForValue(float value) => MathF.Max(basalHeight + offsetForValue(value), 0); private void draw() { @@ -356,9 +361,9 @@ namespace osu.Game.Screens.Ranking.Statistics private void drawAdjustmentBar() { - bool hasAdjustment = offsetAdjustment.Value != totalValue; + bool hasAdjustment = offsetAdjustment != totalValue; - boxAdjustment.ResizeHeightTo(heightForValue(offsetAdjustment.Value), duration, Easing.OutQuint); + boxAdjustment.ResizeHeightTo(heightForValue(offsetAdjustment), duration, Easing.OutQuint); boxAdjustment.FadeTo(!hasAdjustment ? 0 : 1, duration, Easing.OutQuint); } } From 94f8197e22f647d61ee82c42bee7d9dbd386d65c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 16:15:14 +0900 Subject: [PATCH 1050/2686] Show login overlay when attempting to update a beatmap while logged out --- .../Select/Carousel/UpdateBeatmapSetButton.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs b/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs index 73e7d23df0..3c4ed4734b 100644 --- a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs +++ b/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs @@ -11,6 +11,8 @@ using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Overlays; using osuTK; using osuTK.Graphics; @@ -22,6 +24,15 @@ namespace osu.Game.Screens.Select.Carousel private SpriteIcon icon = null!; private Box progressFill = null!; + [Resolved] + private BeatmapModelDownloader beatmapDownloader { get; set; } = null!; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + [Resolved(canBeNull: true)] + private LoginOverlay? loginOverlay { get; set; } + public UpdateBeatmapSetButton(BeatmapSetInfo beatmapSetInfo) { this.beatmapSetInfo = beatmapSetInfo; @@ -32,9 +43,6 @@ namespace osu.Game.Screens.Select.Carousel Origin = Anchor.CentreLeft; } - [Resolved] - private BeatmapModelDownloader beatmapDownloader { get; set; } = null!; - [BackgroundDependencyLoader] private void load() { @@ -90,6 +98,12 @@ namespace osu.Game.Screens.Select.Carousel Action = () => { + if (!api.IsLoggedIn) + { + loginOverlay?.Show(); + return; + } + beatmapDownloader.DownloadAsUpdate(beatmapSetInfo); attachExistingDownload(); }; From 0d0e2e7bcce9445e9513cacb8281b03b8adf91be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 12 Sep 2022 16:20:33 +0900 Subject: [PATCH 1051/2686] fix(osu.Game): bars in hit distribution graph stretching in the opposite direction when `DrawHeight` is less than `DrawWidth` --- .../Ranking/Statistics/HitEventTimingDistributionGraph.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index ebf521ba21..5f3b2773ea 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -323,7 +323,7 @@ namespace osu.Game.Screens.Ranking.Statistics private void updateBasalHeight() { - float newBasalHeight = DrawHeight == 0 ? 0 : DrawWidth / DrawHeight; + float newBasalHeight = DrawHeight > DrawWidth ? DrawWidth / DrawHeight : 1; if (newBasalHeight == basalHeight) return; @@ -353,7 +353,7 @@ namespace osu.Game.Screens.Ranking.Statistics for (int i = 0; i < values.Count; i++) { - boxOriginals[i].Y = offsetForValue(offsetValue) * BoundingBox.Height; + boxOriginals[i].Y = offsetForValue(offsetValue) * DrawHeight; boxOriginals[i].Height = heightForValue(values[i].Value); offsetValue -= values[i].Value; } From 4f298db066bba408f1aaaa8c5cfa76b29738cec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 12 Sep 2022 16:25:29 +0900 Subject: [PATCH 1052/2686] fix(osu.Game): reset Y axis of the bars in hit distribution graph at the first drawing --- .../Ranking/Statistics/HitEventTimingDistributionGraph.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 5f3b2773ea..764237ef96 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -278,7 +278,10 @@ namespace osu.Game.Screens.Ranking.Statistics updateBasalHeight(); foreach (var boxOriginal in boxOriginals) + { + boxOriginal.Y = 0; boxOriginal.Height = basalHeight; + } float offsetValue = 0; From bd3673baa9fe9fa5c5b77659e270c1e784938191 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 16:25:32 +0900 Subject: [PATCH 1053/2686] Fix being able to drag after already closing a notification --- osu.Game/Overlays/Notifications/Notification.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 2e4b0c430a..facf43128d 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -70,6 +70,8 @@ namespace osu.Game.Overlays.Notifications [Resolved] private OverlayColourProvider colourProvider { get; set; } = null!; + public override bool PropagatePositionalInputSubTree => base.PropagatePositionalInputSubTree && !WasClosed; + private bool isInToastTray; /// @@ -327,7 +329,7 @@ namespace osu.Game.Overlays.Notifications velocity.Y += (float)Clock.ElapsedFrameTime * 0.005f; Position += (float)Clock.ElapsedFrameTime * velocity; } - else + else if (Clock.ElapsedFrameTime > 0) { Vector2 change = (Position - lastPosition) / (float)Clock.ElapsedFrameTime; From a50617857176acbefb571e777429d9411cfdbff0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 16:39:46 +0900 Subject: [PATCH 1054/2686] Make bounding box shrink faster to allow for rapid flinging --- osu.Game/Overlays/Notifications/Notification.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index facf43128d..f83be0c446 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -278,8 +278,8 @@ namespace osu.Game.Overlays.Notifications { var childBounding = Children.First().BoundingBox; - if (X < 0) childBounding *= new Vector2(1, Math.Max(0, 1 + (X / 800))); - if (Y > 0) childBounding *= new Vector2(1, Math.Max(0, 1 - (Y / 800))); + if (X < 0) childBounding *= new Vector2(1, Math.Max(0, 1 + (X / 300))); + if (Y > 0) childBounding *= new Vector2(1, Math.Max(0, 1 - (Y / 200))); return childBounding; } From 5a02e1e7133e2be8f6eba967049b058a720957f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 16:46:45 +0900 Subject: [PATCH 1055/2686] Use padding instead of `FillFlow.Spacing` to avoid artifact during animation --- osu.Game/Overlays/NotificationOverlayToastTray.cs | 1 - osu.Game/Overlays/Notifications/Notification.cs | 3 +++ osu.Game/Overlays/Notifications/NotificationSection.cs | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index e4d3864beb..1da05dab75 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -78,7 +78,6 @@ namespace osu.Game.Overlays { LayoutDuration = 150, LayoutEasing = Easing.OutQuart, - Spacing = new Vector2(3), RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }, diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index f83be0c446..fe2f67973a 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -113,6 +113,9 @@ namespace osu.Game.Overlays.Notifications }, dragContainer = new DragContainer(this) { + // Use margin instead of FillFlow spacing to fix extra padding appearing when notification shrinks + // in height. + Padding = new MarginPadding { Vertical = 3f }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }.WithChild(MainContent = new Container diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index d2e18a0cee..14bacca534 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -106,7 +106,6 @@ namespace osu.Game.Overlays.Notifications RelativeSizeAxes = Axes.X, LayoutDuration = 150, LayoutEasing = Easing.OutQuart, - Spacing = new Vector2(3), } }); } From d561fcb126689dade097acce3f4f425504680fff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 16:54:25 +0900 Subject: [PATCH 1056/2686] Don't trigger fling animation when `Close` is triggered by non-user action --- .../Online/TestSceneBeatmapDownloading.cs | 2 +- osu.Game/Database/ModelDownloader.cs | 2 +- osu.Game/Overlays/Notifications/Notification.cs | 13 ++++++------- .../Overlays/Notifications/NotificationSection.cs | 2 +- .../Overlays/Notifications/ProgressNotification.cs | 6 +++--- osu.Game/Updater/UpdateManager.cs | 6 +++--- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs b/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs index e7a6e9a543..641c1ad523 100644 --- a/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs +++ b/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs @@ -91,7 +91,7 @@ namespace osu.Game.Tests.Online { AddStep("download beatmap", () => beatmaps.Download(test_db_model)); - AddStep("cancel download from notification", () => recentNotification.Close()); + AddStep("cancel download from notification", () => recentNotification.Close(true)); AddUntilStep("is removed from download list", () => beatmaps.GetExistingDownload(test_db_model) == null); AddAssert("is notification cancelled", () => recentNotification.State == ProgressNotificationState.Cancelled); diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index a3678602d1..877c90a534 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -111,7 +111,7 @@ namespace osu.Game.Database { if (error is WebException webException && webException.Message == @"TooManyRequests") { - notification.Close(); + notification.Close(false); PostNotification?.Invoke(new TooManyDownloadsNotification()); } else diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index fe2f67973a..acb277d4b4 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -168,7 +168,7 @@ namespace osu.Game.Overlays.Notifications }, new CloseButton(CloseButtonIcon) { - Action = Close, + Action = () => Close(true), Anchor = Anchor.TopRight, Origin = Anchor.TopRight, } @@ -214,7 +214,7 @@ namespace osu.Game.Overlays.Notifications // right click doesn't trigger OnClick so we need to handle here until that changes. if (e.Button != MouseButton.Left) { - Close(); + Close(true); return true; } @@ -227,7 +227,7 @@ namespace osu.Game.Overlays.Notifications if (e.Button == MouseButton.Left) Activated?.Invoke(); - Close(); + Close(true); return true; } @@ -245,13 +245,13 @@ namespace osu.Game.Overlays.Notifications public bool WasClosed; - public virtual void Close() + public virtual void Close(bool userTriggered) { if (WasClosed) return; WasClosed = true; - if (dragContainer.FlingLeft()) + if (userTriggered && dragContainer.FlingLeft()) this.FadeOut(600, Easing.In); else { @@ -272,7 +272,6 @@ namespace osu.Game.Overlays.Notifications public DragContainer(Notification notification) { this.notification = notification; - notification.Closed += () => FlingLeft(); } public override RectangleF BoundingBox @@ -363,7 +362,7 @@ namespace osu.Game.Overlays.Notifications flinging = true; ClearTransforms(); - notification.Close(); + notification.Close(true); return true; } diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 14bacca534..16105f913f 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -112,7 +112,7 @@ namespace osu.Game.Overlays.Notifications private void clearAll() { - notifications.Children.ForEach(c => c.Close()); + notifications.Children.ForEach(c => c.Close(true)); } protected override void Update() diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index bdf6f704e5..55d6d5057a 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -142,7 +142,7 @@ namespace osu.Game.Overlays.Notifications case ProgressNotificationState.Completed: loadingSpinner.Hide(); attemptPostCompletion(); - base.Close(); + base.Close(false); break; } } @@ -235,12 +235,12 @@ namespace osu.Game.Overlays.Notifications }); } - public override void Close() + public override void Close(bool userTriggered) { switch (State) { case ProgressNotificationState.Cancelled: - base.Close(); + base.Close(userTriggered); break; case ProgressNotificationState.Active: diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index 49009e9124..2ef6741ffd 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -148,7 +148,7 @@ namespace osu.Game.Updater StartDownload(); } - public override void Close() + public override void Close(bool userTriggered) { // cancelling updates is not currently supported by the underlying updater. // only allow dismissing for now. @@ -156,7 +156,7 @@ namespace osu.Game.Updater switch (State) { case ProgressNotificationState.Cancelled: - base.Close(); + base.Close(userTriggered); break; } } @@ -177,7 +177,7 @@ namespace osu.Game.Updater public void FailDownload() { State = ProgressNotificationState.Cancelled; - Close(); + Close(false); } } } From 91c415f29b693460123762b6e7023c15d32b856c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 16:58:20 +0900 Subject: [PATCH 1057/2686] Fix nullability oversight in `ManiaRulesetConfigManager` --- .../Configuration/ManiaRulesetConfigManager.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs index b30d72f2e2..d367c82ed8 100644 --- a/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.cs +++ b/osu.Game.Rulesets.Mania/Configuration/ManiaRulesetConfigManager.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. -#nullable disable - using System; using osu.Framework.Configuration.Tracking; using osu.Game.Configuration; @@ -13,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Configuration { public class ManiaRulesetConfigManager : RulesetConfigManager { - public ManiaRulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null) + public ManiaRulesetConfigManager(SettingsStore? settings, RulesetInfo ruleset, int? variant = null) : base(settings, ruleset, variant) { } From 89e128c0f3469e31d80ef2e165b324d4cbe80385 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 17:35:56 +0900 Subject: [PATCH 1058/2686] Fix bindable event binds to `HitObject` directly --- .../Blueprints/Sliders/Components/PathControlPointPiece.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index 92d83d900e..ab4b492767 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -53,6 +54,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private IBindable sliderPosition; private IBindable sliderScale; + [UsedImplicitly] + private readonly IBindable sliderVersion; + public PathControlPointPiece(Slider slider, PathControlPoint controlPoint) { this.slider = slider; @@ -61,7 +65,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components // we don't want to run the path type update on construction as it may inadvertently change the slider. cachePoints(slider); - slider.Path.Version.BindValueChanged(_ => + sliderVersion = slider.Path.Version.GetBoundCopy(); + sliderVersion.BindValueChanged(_ => { cachePoints(slider); updatePathType(); From 58c1ea03215bc894bb770e2864d3b33c869d19db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 17:51:15 +0900 Subject: [PATCH 1059/2686] Fix potential crash when opening changelog overlay if entry has no URL --- osu.Game/Overlays/Changelog/ChangelogEntry.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogEntry.cs b/osu.Game/Overlays/Changelog/ChangelogEntry.cs index fdeba3f304..4d034007b1 100644 --- a/osu.Game/Overlays/Changelog/ChangelogEntry.cs +++ b/osu.Game/Overlays/Changelog/ChangelogEntry.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Diagnostics; using System.Net; using System.Text.RegularExpressions; using osu.Framework.Allocation; @@ -93,7 +94,7 @@ namespace osu.Game.Overlays.Changelog t.Colour = entryColour; }); - if (!string.IsNullOrEmpty(entry.Repository)) + if (!string.IsNullOrEmpty(entry.Repository) && !string.IsNullOrEmpty(entry.GithubUrl)) addRepositoryReference(title, entryColour); if (entry.GithubUser != null) @@ -104,17 +105,22 @@ namespace osu.Game.Overlays.Changelog private void addRepositoryReference(LinkFlowContainer title, Color4 entryColour) { + Debug.Assert(!string.IsNullOrEmpty(entry.Repository)); + Debug.Assert(!string.IsNullOrEmpty(entry.GithubUrl)); + title.AddText(" (", t => { t.Font = fontLarge; t.Colour = entryColour; }); + title.AddLink($"{entry.Repository.Replace("ppy/", "")}#{entry.GithubPullRequestId}", entry.GithubUrl, t => { t.Font = fontLarge; t.Colour = entryColour; }); + title.AddText(")", t => { t.Font = fontLarge; From 27d4016ccb360991c37750bf5fe67e193b8fa038 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 12 Sep 2022 18:32:14 +0900 Subject: [PATCH 1060/2686] Add `ScoreProcessor.ComputeAccuracy()` --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 64d5639133..7456ce06bd 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -272,7 +272,24 @@ namespace osu.Game.Rulesets.Scoring } /// - /// Computes the total score of a given finalised . This should be used when a score is known to be complete. + /// Computes the accuracy of a given . + /// + /// The to compute the total score of. + /// The score's accuracy. + [Pure] + public double ComputeAccuracy(ScoreInfo scoreInfo) + { + if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset)) + throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\"."); + + // We only extract scoring values from the score's statistics. This is because accuracy is always relative to the point of pass or fail rather than relative to the whole beatmap. + extractScoringValues(scoreInfo.Statistics, out var current, out var maximum); + + return maximum.BaseScore > 0 ? current.BaseScore / maximum.BaseScore : 1; + } + + /// + /// Computes the total score of a given . /// /// /// Does not require to have been called before use. From e29f5cb4568019d031c85394aaca8b648e471a78 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 18:53:37 +0900 Subject: [PATCH 1061/2686] Fix new-style legacy skins with animated judgements not adding correct transforms Closes #16173. --- osu.Game/Skinning/LegacyJudgementPieceNew.cs | 2 +- osu.Game/Skinning/LegacyJudgementPieceOld.cs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Skinning/LegacyJudgementPieceNew.cs b/osu.Game/Skinning/LegacyJudgementPieceNew.cs index b87fc9acb5..2cb055d8ba 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceNew.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceNew.cs @@ -56,7 +56,7 @@ namespace osu.Game.Skinning if (result != HitResult.Miss) { //new judgement shows old as a temporary effect - AddInternal(temporaryOldStyle = new LegacyJudgementPieceOld(result, createMainDrawable, 1.05f) + AddInternal(temporaryOldStyle = new LegacyJudgementPieceOld(result, createMainDrawable, 1.05f, true) { Blending = BlendingParameters.Additive, Anchor = Anchor.Centre, diff --git a/osu.Game/Skinning/LegacyJudgementPieceOld.cs b/osu.Game/Skinning/LegacyJudgementPieceOld.cs index c47f46ed2b..7e7f0f027d 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceOld.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceOld.cs @@ -19,10 +19,13 @@ namespace osu.Game.Skinning private readonly float finalScale; - public LegacyJudgementPieceOld(HitResult result, Func createMainDrawable, float finalScale = 1f) + private readonly bool allowTransforms; + + public LegacyJudgementPieceOld(HitResult result, Func createMainDrawable, float finalScale = 1f, bool allowTransforms = false) { this.result = result; this.finalScale = finalScale; + this.allowTransforms = allowTransforms; AutoSizeAxes = Axes.Both; Origin = Anchor.Centre; @@ -43,8 +46,8 @@ namespace osu.Game.Skinning this.FadeInFromZero(fade_in_length); this.Delay(fade_out_delay).FadeOut(fade_out_length); - // legacy judgements don't play any transforms if they are an animation. - if (animation?.FrameCount > 1) + // legacy judgements don't play any transforms if they are an animation.... UNLESS they are the temporary displayed judgement from new piece. + if (!allowTransforms && animation?.FrameCount > 1) return; switch (result) From 4ee3e8f087e14631622ffca7f446485f50d4982c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 18:57:18 +0900 Subject: [PATCH 1062/2686] Don't play fling animation when activating a notification --- osu.Game/Overlays/Notifications/Notification.cs | 6 +++--- osu.Game/Overlays/Notifications/ProgressNotification.cs | 4 ++-- osu.Game/Updater/UpdateManager.cs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index acb277d4b4..887d729de7 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -227,7 +227,7 @@ namespace osu.Game.Overlays.Notifications if (e.Button == MouseButton.Left) Activated?.Invoke(); - Close(true); + Close(false); return true; } @@ -245,13 +245,13 @@ namespace osu.Game.Overlays.Notifications public bool WasClosed; - public virtual void Close(bool userTriggered) + public virtual void Close(bool runFlingAnimation) { if (WasClosed) return; WasClosed = true; - if (userTriggered && dragContainer.FlingLeft()) + if (runFlingAnimation && dragContainer.FlingLeft()) this.FadeOut(600, Easing.In); else { diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 55d6d5057a..c4d402e5b9 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -235,12 +235,12 @@ namespace osu.Game.Overlays.Notifications }); } - public override void Close(bool userTriggered) + public override void Close(bool runFlingAnimation) { switch (State) { case ProgressNotificationState.Cancelled: - base.Close(userTriggered); + base.Close(runFlingAnimation); break; case ProgressNotificationState.Active: diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index 2ef6741ffd..100464029b 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -148,7 +148,7 @@ namespace osu.Game.Updater StartDownload(); } - public override void Close(bool userTriggered) + public override void Close(bool runFlingAnimation) { // cancelling updates is not currently supported by the underlying updater. // only allow dismissing for now. @@ -156,7 +156,7 @@ namespace osu.Game.Updater switch (State) { case ProgressNotificationState.Cancelled: - base.Close(userTriggered); + base.Close(runFlingAnimation); break; } } From d92e000fe6db82e258ec9a68e6d0fe9885c99d75 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 19:00:03 +0900 Subject: [PATCH 1063/2686] Fix flinging a notification not correctly running `Close` --- osu.Game/Overlays/Notifications/Notification.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 887d729de7..6c1b43c3b5 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -254,11 +254,9 @@ namespace osu.Game.Overlays.Notifications if (runFlingAnimation && dragContainer.FlingLeft()) this.FadeOut(600, Easing.In); else - { - Closed?.Invoke(); this.FadeOut(100); - } + Closed?.Invoke(); Expire(); } @@ -311,7 +309,7 @@ namespace osu.Game.Overlays.Notifications protected override void OnDragEnd(DragEndEvent e) { if (Rotation < -10 || velocity.X < -0.3f) - FlingLeft(); + notification.Close(true); else ResetPosition(); @@ -362,7 +360,6 @@ namespace osu.Game.Overlays.Notifications flinging = true; ClearTransforms(); - notification.Close(true); return true; } From f56f6545c04cd3f4f56a7398a49998ab8fe13da7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 19:06:09 +0900 Subject: [PATCH 1064/2686] Add test coverage of flinging --- .../TestSceneNotificationOverlay.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 8504da69a7..3d13e98865 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -48,6 +48,40 @@ namespace osu.Game.Tests.Visual.UserInterface notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count.NewValue}"; }; }); + [Test] + public void TestDismissWithoutActivationFling() + { + bool activated = false; + SimpleNotification notification = null!; + + AddStep("post", () => + { + activated = false; + notificationOverlay.Post(notification = new SimpleNotification + { + Text = @"Welcome to osu!. Enjoy your stay!", + Activated = () => activated = true, + }); + }); + + AddStep("start drag", () => + { + InputManager.MoveMouseTo(notification.ChildrenOfType().Single()); + InputManager.PressButton(MouseButton.Left); + InputManager.MoveMouseTo(notification.ChildrenOfType().Single().ScreenSpaceDrawQuad.Centre + new Vector2(-500, 0)); + }); + + AddStep("fling away", () => + { + InputManager.ReleaseButton(MouseButton.Left); + }); + + AddUntilStep("wait for closed", () => notification.WasClosed); + AddAssert("was not activated", () => !activated); + AddStep("reset mouse position", () => InputManager.MoveMouseTo(Vector2.Zero)); + AddAssert("unread count zero", () => notificationOverlay.UnreadCount.Value == 0); + } + [Test] public void TestDismissWithoutActivationCloseButton() { @@ -75,6 +109,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait for closed", () => notification.WasClosed); AddAssert("was not activated", () => !activated); AddStep("reset mouse position", () => InputManager.MoveMouseTo(Vector2.Zero)); + AddAssert("unread count zero", () => notificationOverlay.UnreadCount.Value == 0); } [Test] From 431e84f99207fb0a429b85ad0a61ab7f7f55a206 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 19:09:24 +0900 Subject: [PATCH 1065/2686] Cancel in progress CI runs when new commits are pushed Same as https://github.com/ppy/osu-web/pull/9268. Should hopefully help with organisation concurrent limits. --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef729a779f..082e0d247c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,8 @@ on: [push, pull_request] name: Continuous Integration +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: inspect-code: From 857e943b8d5b3924378a1de65804d6fdc4c5467d Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Sun, 11 Sep 2022 17:30:14 +0800 Subject: [PATCH 1066/2686] hide catchcombo when Hud hide --- .../Legacy/LegacyCatchComboCounter.cs | 2 - .../UI/CatchComboDisplay.cs | 64 +++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs index b2dd29841b..b4d29988d9 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.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. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Catch.UI; diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs index e9c289e46a..a923aca2c8 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs @@ -4,9 +4,13 @@ #nullable disable using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Configuration; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; using osu.Game.Skinning; using osuTK.Graphics; @@ -22,11 +26,69 @@ namespace osu.Game.Rulesets.Catch.UI [CanBeNull] public ICatchComboCounter ComboCounter => Drawable as ICatchComboCounter; + private Bindable hudVisibilityMode = null!; + + private readonly BindableBool replayLoaded = new BindableBool(); + + private readonly BindableBool showCombo = new BindableBool(); + + [Resolved] + private OsuConfigManager config { get; set; } + public CatchComboDisplay() : base(new CatchSkinComponent(CatchSkinComponents.CatchComboCounter), _ => Empty()) { } + [BackgroundDependencyLoader(true)] + private void load(DrawableRuleset drawableRuleset) + { + hudVisibilityMode = config.GetBindable(OsuSetting.HUDVisibilityMode); + + hudVisibilityMode.BindValueChanged(s => + { + updateVisibilityState(); + }); + + if (drawableRuleset != null) + replayLoaded.BindTo(drawableRuleset.HasReplayLoaded); + + replayLoaded.BindValueChanged(s => + { + updateVisibilityState(); + }); + + showCombo.BindValueChanged(s => + { + if (ComboCounter == null) return; + + if (!s.NewValue) + { + ComboCounter.Hide(); + } + }); + + updateVisibilityState(); + + void updateVisibilityState() + { + switch (hudVisibilityMode.Value) + { + case HUDVisibilityMode.Never: + showCombo.Value = false; + break; + + case HUDVisibilityMode.HideDuringGameplay: + showCombo.Value = replayLoaded.Value; + break; + + case HUDVisibilityMode.Always: + showCombo.Value = true; + break; + } + } + } + protected override void SkinChanged(ISkinSource skin) { base.SkinChanged(skin); @@ -57,6 +119,8 @@ namespace osu.Game.Rulesets.Catch.UI private void updateCombo(int newCombo, Color4? hitObjectColour) { + if (!showCombo.Value) return; + currentCombo = newCombo; ComboCounter?.UpdateCombo(newCombo, hitObjectColour); } From 837cc760195cd5c0c4aa5c445657a42151b8b7ca Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 12 Sep 2022 12:50:16 +0200 Subject: [PATCH 1067/2686] Create TestSceneSelectionBlueprintDeselection.cs --- .../TestSceneSelectionBlueprintDeselection.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs new file mode 100644 index 0000000000..fdc05e9456 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Tests.Beatmaps; + +namespace osu.Game.Rulesets.Osu.Tests.Editor +{ + public class TestSceneSelectionBlueprintDeselection : TestSceneOsuEditor + { + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false); + + [Test] + public void TestSingleDeleteAtSameTime() + { + HitCircle? circle1 = null; + HitCircle? circle2 = null; + + AddStep("add two circles at the same time", () => + { + circle1 = new HitCircle(); + circle2 = new HitCircle(); + EditorClock.Seek(0); + EditorBeatmap.Add(circle1); + EditorBeatmap.Add(circle2); + EditorBeatmap.SelectedHitObjects.Add(circle1); + EditorBeatmap.SelectedHitObjects.Add(circle2); + }); + + AddStep("delete the first circle", () => EditorBeatmap.Remove(circle1)); + } + } +} From f31deaef7ca8dd0f7defd794c77f8a8b6f0f718c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 19:51:49 +0900 Subject: [PATCH 1068/2686] Simplify skin bindable flow Now, nothing touches the configuration apart from `OsuGame`, making everything else flow better and avoid weird cyclic set bugs. Closes https://github.com/ppy/osu/issues/20234. --- osu.Game/OsuGame.cs | 24 ++----- .../Overlays/Settings/Sections/SkinSection.cs | 62 ++++--------------- osu.Game/Skinning/SkinManager.cs | 20 +++++- 3 files changed, 36 insertions(+), 70 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 9e2384322a..0d115f62fe 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -56,14 +56,12 @@ using osu.Game.Screens.Menu; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; -using osu.Game.Skinning; using osu.Game.Skinning.Editor; using osu.Game.Updater; using osu.Game.Users; using osu.Game.Utils; using osuTK.Graphics; using Sentry; -using Logger = osu.Framework.Logging.Logger; namespace osu.Game { @@ -294,25 +292,13 @@ namespace osu.Game Ruleset.ValueChanged += r => configRuleset.Value = r.NewValue.ShortName; - // bind config int to database SkinInfo configSkin = LocalConfig.GetBindable(OsuSetting.Skin); + + // Transfer skin from config to realm instance once on startup. + SkinManager.SetSkinFromConfiguration(configSkin.Value); + + // Transfer any runtime changes back to configuration file. SkinManager.CurrentSkinInfo.ValueChanged += skin => configSkin.Value = skin.NewValue.ID.ToString(); - configSkin.ValueChanged += skinId => - { - Live skinInfo = null; - - if (Guid.TryParse(skinId.NewValue, out var guid)) - skinInfo = SkinManager.Query(s => s.ID == guid); - - if (skinInfo == null) - { - if (guid == SkinInfo.CLASSIC_SKIN) - skinInfo = DefaultLegacySkin.CreateInfo().ToLiveUnmanaged(); - } - - SkinManager.CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.CreateInfo().ToLiveUnmanaged(); - }; - configSkin.TriggerChange(); IsActive.BindValueChanged(active => updateActiveState(active.NewValue), true); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index d23ef7e3e7..13249e37ca 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Platform; -using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; @@ -36,9 +35,6 @@ namespace osu.Game.Overlays.Settings.Sections Icon = FontAwesome.Solid.PaintBrush }; - private readonly Bindable> dropdownBindable = new Bindable> { Default = DefaultSkin.CreateInfo().ToLiveUnmanaged() }; - private readonly Bindable configBindable = new Bindable(); - private static readonly Live random_skin_info = new SkinInfo { ID = SkinInfo.RANDOM_SKIN, @@ -56,13 +52,14 @@ namespace osu.Game.Overlays.Settings.Sections private IDisposable realmSubscription; [BackgroundDependencyLoader(permitNulls: true)] - private void load(OsuConfigManager config, [CanBeNull] SkinEditorOverlay skinEditor) + private void load([CanBeNull] SkinEditorOverlay skinEditor) { Children = new Drawable[] { skinDropdown = new SkinSettingsDropdown { LabelText = SkinSettingsStrings.CurrentSkin, + Current = skins.CurrentSkinInfo, Keywords = new[] { @"skins" } }, new SettingsButton @@ -73,47 +70,30 @@ namespace osu.Game.Overlays.Settings.Sections new ExportSkinButton(), new DeleteSkinButton(), }; - - config.BindWith(OsuSetting.Skin, configBindable); } protected override void LoadComplete() { base.LoadComplete(); - skinDropdown.Current = dropdownBindable; + skinDropdown.Current = skins.CurrentSkinInfo; realmSubscription = realm.RegisterForNotifications(_ => realm.Realm.All() .Where(s => !s.DeletePending) .OrderByDescending(s => s.Protected) // protected skins should be at the top. .ThenBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged); - configBindable.BindValueChanged(_ => Scheduler.AddOnce(updateSelectedSkinFromConfig)); - - dropdownBindable.BindValueChanged(dropdownSelectionChanged); - } - - private void dropdownSelectionChanged(ValueChangedEvent> skin) - { - // Only handle cases where it's clear the user has intent to change skins. - if (skin.OldValue == null) return; - - if (skin.NewValue.Equals(random_skin_info)) + skinDropdown.Current.BindValueChanged(skin => { - var skinBefore = skins.CurrentSkinInfo.Value; - - skins.SelectRandomSkin(); - - if (skinBefore == skins.CurrentSkinInfo.Value) + if (skin.NewValue == random_skin_info) { - // the random selection didn't change the skin, so we should manually update the dropdown to match. - dropdownBindable.Value = skins.CurrentSkinInfo.Value; + // before selecting random, set the skin back to the previous selection. + // this is done because at this point it will be random_skin_info, and would + // cause SelectRandomSkin to be unable to skip the previous selection. + skins.CurrentSkinInfo.Value = skin.OldValue; + skins.SelectRandomSkin(); } - - return; - } - - configBindable.Value = skin.NewValue.ID.ToString(); + }); } private void skinsChanged(IRealmCollection sender, ChangeSet changes, Exception error) @@ -132,25 +112,7 @@ namespace osu.Game.Overlays.Settings.Sections dropdownItems.Add(skin.ToLive(realm)); dropdownItems.Insert(protectedCount, random_skin_info); - Schedule(() => - { - skinDropdown.Items = dropdownItems; - - updateSelectedSkinFromConfig(); - }); - } - - private void updateSelectedSkinFromConfig() - { - if (!skinDropdown.Items.Any()) - return; - - Live skin = null; - - if (Guid.TryParse(configBindable.Value, out var configId)) - skin = skinDropdown.Items.FirstOrDefault(s => s.ID == configId); - - dropdownBindable.Value = skin ?? skinDropdown.Items.First(); + Schedule(() => skinDropdown.Items = dropdownItems); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index f677cebe51..7ffea3b54f 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -119,7 +119,9 @@ namespace osu.Game.Skinning Realm.Run(r => { // choose from only user skins, removing the current selection to ensure a new one is chosen. - var randomChoices = r.All().Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID).ToArray(); + var randomChoices = r.All() + .Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID) + .ToArray(); if (randomChoices.Length == 0) { @@ -297,5 +299,21 @@ namespace osu.Game.Skinning Delete(items.ToList(), silent); }); } + + public void SetSkinFromConfiguration(string guidString) + { + Live skinInfo = null; + + if (Guid.TryParse(guidString, out var guid)) + skinInfo = Query(s => s.ID == guid); + + if (skinInfo == null) + { + if (guid == SkinInfo.CLASSIC_SKIN) + skinInfo = DefaultLegacySkin.SkinInfo; + } + + CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.SkinInfo; + } } } From 2bd72fd9b439f6b723ed43f963b7b5db62daf8d6 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Mon, 12 Sep 2022 17:53:38 +0800 Subject: [PATCH 1069/2686] add test for hide catchercombo --- .../TestSceneComboCounter.cs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs index 7f513728af..f39af76a2d 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs @@ -1,12 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Utils; +using osu.Game.Configuration; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Catch.UI; @@ -19,15 +19,25 @@ namespace osu.Game.Rulesets.Catch.Tests { public class TestSceneComboCounter : CatchSkinnableTestScene { - private ScoreProcessor scoreProcessor; + private OsuConfigManager localConfig = null!; + + private ScoreProcessor scoreProcessor = null!; private Color4 judgedObjectColour = Color4.White; + [BackgroundDependencyLoader] + private void load() + { + Dependencies.Cache(localConfig = new OsuConfigManager(LocalStorage)); + } + [SetUp] public void SetUp() => Schedule(() => { scoreProcessor = new ScoreProcessor(new CatchRuleset()); + localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always); + SetContents(_ => new CatchComboDisplay { Anchor = Anchor.Centre, @@ -51,9 +61,15 @@ namespace osu.Game.Rulesets.Catch.Tests 1f ); }); + + AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never)); + AddRepeatStep("perform hit", () => performJudgement(HitResult.Great), 5); + + AddStep("set hud to show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always)); + AddRepeatStep("perform hit", () => performJudgement(HitResult.Great), 5); } - private void performJudgement(HitResult type, Judgement judgement = null) + private void performJudgement(HitResult type, Judgement? judgement = null) { var judgedObject = new DrawableFruit(new Fruit()) { AccentColour = { Value = judgedObjectColour } }; From 2b4b14ca9990a4626fefcbecf624ca2d97bf4244 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 20:06:52 +0900 Subject: [PATCH 1070/2686] Fix `SongProgress` invalidating too often This regressed with https://github.com/ppy/osu/pull/19556. Rather than try and figure whether that new container needs to handle size differently, this is a simple solution. Height was taken from a runtime check (maxes out at about 14.5). Closes #20235. --- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index d0eb8f8ca1..b3d5066a9e 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -47,7 +47,10 @@ namespace osu.Game.Screens.Play.HUD if (clock != null) gameplayClock = clock; - AutoSizeAxes = Axes.Y; + // Lock height so changes in text autosize (if character height changes) + // don't cause parent invalidation. + Height = 14; + Children = new Drawable[] { new Container From 88107108eea0c440babac6e69c1367274c509e18 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Sep 2022 20:18:40 +0900 Subject: [PATCH 1071/2686] Add ability to flick notifications to the right to store for later --- .../TestSceneNotificationOverlay.cs | 37 +++++++++++++++++++ .../Overlays/NotificationOverlayToastTray.cs | 5 +++ .../Overlays/Notifications/Notification.cs | 4 ++ 3 files changed, 46 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 3d13e98865..e978b57ba4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -48,6 +48,43 @@ namespace osu.Game.Tests.Visual.UserInterface notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count.NewValue}"; }; }); + [Test] + public void TestForwardWithFlingRight() + { + bool activated = false; + SimpleNotification notification = null!; + + AddStep("post", () => + { + activated = false; + notificationOverlay.Post(notification = new SimpleNotification + { + Text = @"Welcome to osu!. Enjoy your stay!", + Activated = () => activated = true, + }); + }); + + AddStep("start drag", () => + { + InputManager.MoveMouseTo(notification.ChildrenOfType().Single()); + InputManager.PressButton(MouseButton.Left); + InputManager.MoveMouseTo(notification.ChildrenOfType().Single().ScreenSpaceDrawQuad.Centre + new Vector2(500, 0)); + }); + + AddStep("fling away", () => + { + InputManager.ReleaseButton(MouseButton.Left); + }); + + AddAssert("was not closed", () => !notification.WasClosed); + AddAssert("was not activated", () => !activated); + AddAssert("is not read", () => !notification.Read); + AddAssert("is not toast", () => !notification.IsInToastTray); + + AddStep("reset mouse position", () => InputManager.MoveMouseTo(Vector2.Zero)); + AddAssert("unread count one", () => notificationOverlay.UnreadCount.Value == 1); + } + [Test] public void TestDismissWithoutActivationFling() { diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index 1da05dab75..e3f8734581 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -100,6 +100,8 @@ namespace osu.Game.Overlays { ++runningDepth; + notification.ForwardToOverlay = () => forwardNotification(notification); + int depth = notification.DisplayOnTop ? -runningDepth : runningDepth; toastFlow.Insert(depth, notification); @@ -130,6 +132,9 @@ namespace osu.Game.Overlays private void forwardNotification(Notification notification) { + if (!notification.IsInToastTray) + return; + Debug.Assert(notification.Parent == toastFlow); // Temporarily remove from flow so we can animate the position off to the right. diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 6c1b43c3b5..885bb2fc6c 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -42,6 +42,8 @@ namespace osu.Game.Overlays.Notifications /// public Func? Activated; + public Action? ForwardToOverlay { get; set; } + /// /// Should we show at the top of our section on display? /// @@ -310,6 +312,8 @@ namespace osu.Game.Overlays.Notifications { if (Rotation < -10 || velocity.X < -0.3f) notification.Close(true); + else if (X > 30 || velocity.X > 0.3f) + notification.ForwardToOverlay?.Invoke(); else ResetPosition(); From 8cbc0502aea885ce2468ccfda0b457297382ead9 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 12 Sep 2022 15:51:18 +0300 Subject: [PATCH 1072/2686] Inline `CalculateEffect` --- osu.Game/Overlays/Mods/ModsEffectDisplay.cs | 27 ++++----------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs index 3b112fdbd3..eed3181e49 100644 --- a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs +++ b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs @@ -49,22 +49,9 @@ namespace osu.Game.Overlays.Mods ///
protected abstract LocalisableString Label { get; } - /// - /// Calculates, does current value increase difficulty or decrease it. - /// - /// Value to calculate for. Will arrive from bindable once it changes. - /// Effect of the value. - /// - /// Default implementation compares the value with ., bigger value counts as difficulty increase. - /// - protected virtual ModEffect CalculateEffect(double value) - { - return CalculateForSign(value.CompareTo(Current.Default)); - } - protected virtual float ValueAreaWidth => 56; - protected virtual string CounterFormat => "N0"; + protected virtual string CounterFormat => @"N0"; protected override Container Content => content; @@ -159,7 +146,7 @@ namespace osu.Game.Overlays.Mods { Current.BindValueChanged(e => { - var effect = CalculateEffect(e.NewValue); + var effect = CalculateEffectForComparison(e.NewValue.CompareTo(Current.Default)); setColours(effect); }, true); } @@ -192,14 +179,12 @@ namespace osu.Game.Overlays.Mods } } - #region Quick implementations for CalculateEffect - /// /// Converts signed integer into . Negative values are counted as difficulty reduction, positive as increase. /// - /// Value to convert. Can be obtained from CompareTo. - /// Effect. - protected ModEffect CalculateForSign(int comparison) + /// Value to convert. Will arrive from comparison between bindable once it changes and it's . + /// Effect of the value. + protected virtual ModEffect CalculateEffectForComparison(int comparison) { if (comparison == 0) return ModEffect.NotChanged; @@ -209,8 +194,6 @@ namespace osu.Game.Overlays.Mods return ModEffect.DifficultyIncrease; } - #endregion - protected enum ModEffect { NotChanged, From 8400de4b2ea1922138fc0d581f0ac8c3a531bd12 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 12 Sep 2022 17:50:11 +0200 Subject: [PATCH 1073/2686] invoking hitobject updated before invoking removed --- .../TestSceneSelectionBlueprintDeselection.cs | 35 +++++++++++++-- osu.Game/Screens/Edit/EditorBeatmap.cs | 45 +++++++++++++------ 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs index fdc05e9456..b00582d6f3 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs @@ -1,10 +1,12 @@ // 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 NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Tests.Beatmaps; +using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { @@ -16,13 +18,12 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor public void TestSingleDeleteAtSameTime() { HitCircle? circle1 = null; - HitCircle? circle2 = null; AddStep("add two circles at the same time", () => { - circle1 = new HitCircle(); - circle2 = new HitCircle(); EditorClock.Seek(0); + circle1 = new HitCircle(); + var circle2 = new HitCircle(); EditorBeatmap.Add(circle1); EditorBeatmap.Add(circle2); EditorBeatmap.SelectedHitObjects.Add(circle1); @@ -31,5 +32,33 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddStep("delete the first circle", () => EditorBeatmap.Remove(circle1)); } + + [Test] + public void TestBigStackDeleteAtSameTime() + { + AddStep("add 20 circles at the same time", () => + { + EditorClock.Seek(0); + + for (int i = 0; i < 20; i++) + { + EditorBeatmap.Add(new HitCircle()); + } + }); + + AddStep("select half of the circles", () => + { + foreach (var hitObject in EditorBeatmap.HitObjects.SkipLast(10).Reverse()) + { + EditorBeatmap.SelectedHitObjects.Add(hitObject); + } + }); + + AddStep("delete all selected circles", () => + { + InputManager.PressKey(Key.Delete); + InputManager.ReleaseKey(Key.Delete); + }); + } } } diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 8aa754b305..95b848fec0 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -16,6 +16,7 @@ using osu.Game.Beatmaps.Legacy; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Skinning; namespace osu.Game.Screens.Edit @@ -79,7 +80,7 @@ namespace osu.Game.Screens.Edit private readonly IBeatmapProcessor beatmapProcessor; - private readonly Dictionary> startTimeBindables = new Dictionary>(); + private readonly Dictionary> hitObjectBindables = new Dictionary>(); public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null, BeatmapInfo beatmapInfo = null) { @@ -97,7 +98,7 @@ namespace osu.Game.Screens.Edit beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap); foreach (var obj in HitObjects) - trackStartTime(obj); + trackBindables(obj); } /// @@ -222,7 +223,7 @@ namespace osu.Game.Screens.Edit /// The to insert. public void Insert(int index, HitObject hitObject) { - trackStartTime(hitObject); + trackBindables(hitObject); mutableHitObjects.Insert(index, hitObject); @@ -299,9 +300,9 @@ namespace osu.Game.Screens.Edit mutableHitObjects.RemoveAt(index); - var bindable = startTimeBindables[hitObject]; - bindable.UnbindAll(); - startTimeBindables.Remove(hitObject); + var bindables = hitObjectBindables[hitObject]; + bindables.ForEach(b => b.UnbindAll()); + hitObjectBindables.Remove(hitObject); BeginChange(); batchPendingDeletes.Add(hitObject); @@ -325,25 +326,25 @@ namespace osu.Game.Screens.Edit beatmapProcessor?.PreProcess(); + foreach (var h in batchPendingUpdates) processHitObject(h); foreach (var h in batchPendingDeletes) processHitObject(h); foreach (var h in batchPendingInserts) processHitObject(h); - foreach (var h in batchPendingUpdates) processHitObject(h); beatmapProcessor?.PostProcess(); // callbacks may modify the lists so let's be safe about it + var updates = batchPendingUpdates.ToArray(); + batchPendingUpdates.Clear(); + var deletes = batchPendingDeletes.ToArray(); batchPendingDeletes.Clear(); var inserts = batchPendingInserts.ToArray(); batchPendingInserts.Clear(); - var updates = batchPendingUpdates.ToArray(); - batchPendingUpdates.Clear(); - + foreach (var h in updates) HitObjectUpdated?.Invoke(h); foreach (var h in deletes) HitObjectRemoved?.Invoke(h); foreach (var h in inserts) HitObjectAdded?.Invoke(h); - foreach (var h in updates) HitObjectUpdated?.Invoke(h); updateInProgress.Value = false; } @@ -355,10 +356,12 @@ namespace osu.Game.Screens.Edit private void processHitObject(HitObject hitObject) => hitObject.ApplyDefaults(ControlPointInfo, PlayableBeatmap.Difficulty); - private void trackStartTime(HitObject hitObject) + private void trackBindables(HitObject hitObject) { - startTimeBindables[hitObject] = hitObject.StartTimeBindable.GetBoundCopy(); - startTimeBindables[hitObject].ValueChanged += _ => + var bindables = new List(3); + + var startTimeBindable = hitObject.StartTimeBindable.GetBoundCopy(); + startTimeBindable.ValueChanged += _ => { // For now we'll remove and re-add the hitobject. This is not optimal and can be improved if required. mutableHitObjects.Remove(hitObject); @@ -368,6 +371,20 @@ namespace osu.Game.Screens.Edit Update(hitObject); }; + bindables.Add(startTimeBindable); + + if (hitObject is IHasComboInformation hasCombo) + { + var comboIndexBindable = hasCombo.ComboIndexBindable.GetBoundCopy(); + comboIndexBindable.ValueChanged += _ => Update(hitObject); + bindables.Add(comboIndexBindable); + + var indexInCurrentComboBindable = hasCombo.IndexInCurrentComboBindable.GetBoundCopy(); + indexInCurrentComboBindable.ValueChanged += _ => Update(hitObject); + bindables.Add(indexInCurrentComboBindable); + } + + hitObjectBindables[hitObject] = bindables; } private int findInsertionIndex(IReadOnlyList list, double startTime) From a5b962d9a3bc55beac3b4f89aa1544879adf6c20 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 13 Sep 2022 01:37:23 +0300 Subject: [PATCH 1074/2686] Add failing test case --- .../Online/TestSceneBeatmapListingOverlay.cs | 55 ++++++++++++++++--- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs index 8ef120d252..2c9b34e4a7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs @@ -35,6 +35,8 @@ namespace osu.Game.Tests.Visual.Online private OsuConfigManager localConfig; + private bool returnCursorOnResponse; + [BackgroundDependencyLoader] private void load() { @@ -61,6 +63,7 @@ namespace osu.Game.Tests.Visual.Online searchBeatmapSetsRequest.TriggerSuccess(new SearchBeatmapSetsResponse { BeatmapSets = setsForResponse, + Cursor = returnCursorOnResponse ? new Cursor() : null, }); return true; @@ -106,7 +109,7 @@ namespace osu.Game.Tests.Visual.Online { AddAssert("is visible", () => overlay.State.Value == Visibility.Visible); - AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 100).ToArray())); + AddStep("show many results", () => fetchFor(getManyBeatmaps(100).ToArray())); AddUntilStep("placeholder hidden", () => !overlay.ChildrenOfType().Any(d => d.IsPresent)); @@ -127,10 +130,10 @@ namespace osu.Game.Tests.Visual.Online { AddAssert("is visible", () => overlay.State.Value == Visibility.Visible); - AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 100).ToArray())); + AddStep("show many results", () => fetchFor(getManyBeatmaps(100).ToArray())); assertAllCardsOfType(100); - AddStep("show more results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 30).ToArray())); + AddStep("show more results", () => fetchFor(getManyBeatmaps(30).ToArray())); assertAllCardsOfType(30); } @@ -139,7 +142,7 @@ namespace osu.Game.Tests.Visual.Online { AddAssert("is visible", () => overlay.State.Value == Visibility.Visible); - AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 100).ToArray())); + AddStep("show many results", () => fetchFor(getManyBeatmaps(100).ToArray())); assertAllCardsOfType(100); setCardSize(BeatmapCardSize.Extra, viaConfig); @@ -161,7 +164,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("fetch for 0 beatmaps", () => fetchFor()); placeholderShown(); - AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateAPIBeatmapSet(Ruleset.Value), 100).ToArray())); + AddStep("show many results", () => fetchFor(getManyBeatmaps(100).ToArray())); AddUntilStep("wait for loaded", () => this.ChildrenOfType().Count() == 100); AddUntilStep("placeholder hidden", () => !overlay.ChildrenOfType().Any(d => d.IsPresent)); @@ -180,6 +183,32 @@ namespace osu.Game.Tests.Visual.Online }); } + /// + /// During pagination, the first beatmap of the second page may be a duplicate of the last beatmap from the previous page. + /// This is currently the case with osu!web API due to ES relevance score's presence in the response cursor. + /// See: https://github.com/ppy/osu-web/issues/9270 + /// + [Test] + public void TestDuplicatedBeatmapOnlyShowsOnce() + { + APIBeatmapSet beatmapSet = null; + + AddStep("show many results", () => + { + beatmapSet = CreateAPIBeatmapSet(Ruleset.Value); + beatmapSet.Title = "last beatmap of first page"; + + fetchFor(getManyBeatmaps(49).Append(beatmapSet).ToArray(), true); + }); + AddUntilStep("wait for loaded", () => this.ChildrenOfType().Count() == 50); + + AddStep("set next page", () => setSearchResponse(getManyBeatmaps(49).Prepend(beatmapSet).ToArray(), false)); + AddStep("scroll to end", () => overlay.ChildrenOfType().Single().ScrollToEnd()); + AddUntilStep("wait for loaded", () => this.ChildrenOfType().Count() == 99); + + AddAssert("beatmap not duplicated", () => overlay.ChildrenOfType().Count(c => c.BeatmapSet.Equals(beatmapSet)) == 1); + } + [Test] public void TestUserWithoutSupporterUsesSupporterOnlyFiltersWithoutResults() { @@ -336,15 +365,25 @@ namespace osu.Game.Tests.Visual.Online private static int searchCount; - private void fetchFor(params APIBeatmapSet[] beatmaps) + private APIBeatmapSet[] getManyBeatmaps(int count) => Enumerable.Range(0, count).Select(_ => CreateAPIBeatmapSet(Ruleset.Value)).ToArray(); + + private void fetchFor(params APIBeatmapSet[] beatmaps) => fetchFor(beatmaps, false); + + private void fetchFor(APIBeatmapSet[] beatmaps, bool hasNextPage) { - setsForResponse.Clear(); - setsForResponse.AddRange(beatmaps); + setSearchResponse(beatmaps, hasNextPage); // trigger arbitrary change for fetching. searchControl.Query.Value = $"search {searchCount++}"; } + private void setSearchResponse(APIBeatmapSet[] beatmaps, bool hasNextPage) + { + setsForResponse.Clear(); + setsForResponse.AddRange(beatmaps); + returnCursorOnResponse = hasNextPage; + } + private void setRankAchievedFilter(ScoreRank[] ranks) { AddStep($"set Rank Achieved filter to [{string.Join(',', ranks)}]", () => From 07f577a0c67314035588ba33856e135643632a02 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 13 Sep 2022 01:38:52 +0300 Subject: [PATCH 1075/2686] Fix beatmap listing potentially showing duplicate beatmap cards --- osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs | 13 ++++++++++++- osu.Game/Overlays/BeatmapListingOverlay.cs | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs index b9e0a4e6cb..70312a1535 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Beatmaps.Drawables.Cards { - public abstract class BeatmapCard : OsuClickableContainer + public abstract class BeatmapCard : OsuClickableContainer, IEquatable { public const float TRANSITION_DURATION = 400; public const float CORNER_RADIUS = 10; @@ -96,5 +96,16 @@ namespace osu.Game.Beatmaps.Drawables.Cards throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size"); } } + + public bool Equals(BeatmapCard? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return BeatmapSet.Equals(other.BeatmapSet); + } + + public override bool Equals(object obj) => obj is BeatmapCard other && Equals(other); + public override int GetHashCode() => BeatmapSet.GetHashCode(); } } diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 3136492af0..70c6c60ecd 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -176,6 +176,8 @@ namespace osu.Game.Overlays } else { + newCards = newCards.Except(foundContent); + panelLoadTask = LoadComponentsAsync(newCards, loaded => { lastFetchDisplayedTime = Time.Current; @@ -185,7 +187,7 @@ namespace osu.Game.Overlays } } - private BeatmapCard[] createCardsFor(IEnumerable beatmapSets) => beatmapSets.Select(set => BeatmapCard.Create(set, filterControl.CardSize.Value).With(c => + private IEnumerable createCardsFor(IEnumerable beatmapSets) => beatmapSets.Select(set => BeatmapCard.Create(set, filterControl.CardSize.Value).With(c => { c.Anchor = Anchor.TopCentre; c.Origin = Anchor.TopCentre; From 718f8c4ee206bfeaa52177730fc74cb0c7d404b6 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 13 Sep 2022 01:09:42 +0200 Subject: [PATCH 1076/2686] revert the fix --- osu.Game/Screens/Edit/EditorBeatmap.cs | 45 ++++++++------------------ 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 95b848fec0..8aa754b305 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -16,7 +16,6 @@ using osu.Game.Beatmaps.Legacy; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Skinning; namespace osu.Game.Screens.Edit @@ -80,7 +79,7 @@ namespace osu.Game.Screens.Edit private readonly IBeatmapProcessor beatmapProcessor; - private readonly Dictionary> hitObjectBindables = new Dictionary>(); + private readonly Dictionary> startTimeBindables = new Dictionary>(); public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null, BeatmapInfo beatmapInfo = null) { @@ -98,7 +97,7 @@ namespace osu.Game.Screens.Edit beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap); foreach (var obj in HitObjects) - trackBindables(obj); + trackStartTime(obj); } /// @@ -223,7 +222,7 @@ namespace osu.Game.Screens.Edit /// The to insert. public void Insert(int index, HitObject hitObject) { - trackBindables(hitObject); + trackStartTime(hitObject); mutableHitObjects.Insert(index, hitObject); @@ -300,9 +299,9 @@ namespace osu.Game.Screens.Edit mutableHitObjects.RemoveAt(index); - var bindables = hitObjectBindables[hitObject]; - bindables.ForEach(b => b.UnbindAll()); - hitObjectBindables.Remove(hitObject); + var bindable = startTimeBindables[hitObject]; + bindable.UnbindAll(); + startTimeBindables.Remove(hitObject); BeginChange(); batchPendingDeletes.Add(hitObject); @@ -326,25 +325,25 @@ namespace osu.Game.Screens.Edit beatmapProcessor?.PreProcess(); - foreach (var h in batchPendingUpdates) processHitObject(h); foreach (var h in batchPendingDeletes) processHitObject(h); foreach (var h in batchPendingInserts) processHitObject(h); + foreach (var h in batchPendingUpdates) processHitObject(h); beatmapProcessor?.PostProcess(); // callbacks may modify the lists so let's be safe about it - var updates = batchPendingUpdates.ToArray(); - batchPendingUpdates.Clear(); - var deletes = batchPendingDeletes.ToArray(); batchPendingDeletes.Clear(); var inserts = batchPendingInserts.ToArray(); batchPendingInserts.Clear(); - foreach (var h in updates) HitObjectUpdated?.Invoke(h); + var updates = batchPendingUpdates.ToArray(); + batchPendingUpdates.Clear(); + foreach (var h in deletes) HitObjectRemoved?.Invoke(h); foreach (var h in inserts) HitObjectAdded?.Invoke(h); + foreach (var h in updates) HitObjectUpdated?.Invoke(h); updateInProgress.Value = false; } @@ -356,12 +355,10 @@ namespace osu.Game.Screens.Edit private void processHitObject(HitObject hitObject) => hitObject.ApplyDefaults(ControlPointInfo, PlayableBeatmap.Difficulty); - private void trackBindables(HitObject hitObject) + private void trackStartTime(HitObject hitObject) { - var bindables = new List(3); - - var startTimeBindable = hitObject.StartTimeBindable.GetBoundCopy(); - startTimeBindable.ValueChanged += _ => + startTimeBindables[hitObject] = hitObject.StartTimeBindable.GetBoundCopy(); + startTimeBindables[hitObject].ValueChanged += _ => { // For now we'll remove and re-add the hitobject. This is not optimal and can be improved if required. mutableHitObjects.Remove(hitObject); @@ -371,20 +368,6 @@ namespace osu.Game.Screens.Edit Update(hitObject); }; - bindables.Add(startTimeBindable); - - if (hitObject is IHasComboInformation hasCombo) - { - var comboIndexBindable = hasCombo.ComboIndexBindable.GetBoundCopy(); - comboIndexBindable.ValueChanged += _ => Update(hitObject); - bindables.Add(comboIndexBindable); - - var indexInCurrentComboBindable = hasCombo.IndexInCurrentComboBindable.GetBoundCopy(); - indexInCurrentComboBindable.ValueChanged += _ => Update(hitObject); - bindables.Add(indexInCurrentComboBindable); - } - - hitObjectBindables[hitObject] = bindables; } private int findInsertionIndex(IReadOnlyList list, double startTime) From 5fba21d658335f88010cc1748891a9be65f6ea01 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 13 Sep 2022 02:21:01 +0300 Subject: [PATCH 1077/2686] Rename parameter to clarify purpose --- osu.Game/Skinning/LegacyJudgementPieceOld.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Skinning/LegacyJudgementPieceOld.cs b/osu.Game/Skinning/LegacyJudgementPieceOld.cs index 7e7f0f027d..3f4d13c082 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceOld.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceOld.cs @@ -18,14 +18,13 @@ namespace osu.Game.Skinning private readonly HitResult result; private readonly float finalScale; + private readonly bool forceTransforms; - private readonly bool allowTransforms; - - public LegacyJudgementPieceOld(HitResult result, Func createMainDrawable, float finalScale = 1f, bool allowTransforms = false) + public LegacyJudgementPieceOld(HitResult result, Func createMainDrawable, float finalScale = 1f, bool forceTransforms = false) { this.result = result; this.finalScale = finalScale; - this.allowTransforms = allowTransforms; + this.forceTransforms = forceTransforms; AutoSizeAxes = Axes.Both; Origin = Anchor.Centre; @@ -47,7 +46,7 @@ namespace osu.Game.Skinning this.Delay(fade_out_delay).FadeOut(fade_out_length); // legacy judgements don't play any transforms if they are an animation.... UNLESS they are the temporary displayed judgement from new piece. - if (!allowTransforms && animation?.FrameCount > 1) + if (animation?.FrameCount > 1 && !forceTransforms) return; switch (result) From a1f4724685c356272ca11342b0eff4eff3470b46 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 13 Sep 2022 01:38:29 +0200 Subject: [PATCH 1078/2686] moved the location of the tests --- .../Editing}/TestSceneSelectionBlueprintDeselection.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) rename {osu.Game.Rulesets.Osu.Tests/Editor => osu.Game.Tests/Visual/Editing}/TestSceneSelectionBlueprintDeselection.cs (88%) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs b/osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs similarity index 88% rename from osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs rename to osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs index b00582d6f3..6141e5f31c 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSelectionBlueprintDeselection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs @@ -4,14 +4,18 @@ using System.Linq; using NUnit.Framework; using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Tests.Beatmaps; using osuTK.Input; -namespace osu.Game.Rulesets.Osu.Tests.Editor +namespace osu.Game.Tests.Visual.Editing { - public class TestSceneSelectionBlueprintDeselection : TestSceneOsuEditor + public class TestSceneSelectionBlueprintDeselection : EditorTestScene { + protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false); [Test] From a6f68e4a908dc8a6593445f6ee639b1912577b66 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 13 Sep 2022 03:08:13 +0300 Subject: [PATCH 1079/2686] Fix NRT inspections --- osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs index 4510fda11d..1042341337 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs @@ -126,7 +126,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select unchanged Difficulty Adjust mod", () => { var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull(); - var difficultyAdjustMod = ruleset.CreateMod(); + var difficultyAdjustMod = ruleset.CreateMod().AsNonNull(); difficultyAdjustMod.ReadFromDifficulty(advancedStats.BeatmapInfo.Difficulty); SelectedMods.Value = new[] { difficultyAdjustMod }; }); @@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select changed Difficulty Adjust mod", () => { var ruleset = advancedStats.BeatmapInfo.Ruleset.CreateInstance().AsNonNull(); - var difficultyAdjustMod = ruleset.CreateMod(); + var difficultyAdjustMod = ruleset.CreateMod().AsNonNull(); var originalDifficulty = advancedStats.BeatmapInfo.Difficulty; difficultyAdjustMod.ReadFromDifficulty(originalDifficulty); From fd48249eef42c8af74fb50373744d58bc80eb3f7 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Tue, 13 Sep 2022 02:20:52 +0200 Subject: [PATCH 1080/2686] fix with new event --- .../Components/HitObjectOrderedSelectionContainer.cs | 6 ++---- osu.Game/Screens/Edit/EditorBeatmap.cs | 8 ++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs b/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs index d6fd07c998..2d8dca9c2d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs @@ -24,11 +24,9 @@ namespace osu.Game.Screens.Edit.Compose.Components { base.LoadComplete(); - editorBeatmap.HitObjectUpdated += hitObjectUpdated; + editorBeatmap.SelectionBlueprintsShouldBeSorted += SortInternal; } - private void hitObjectUpdated(HitObject _) => SortInternal(); - public override void Add(SelectionBlueprint drawable) { SortInternal(); @@ -72,7 +70,7 @@ namespace osu.Game.Screens.Edit.Compose.Components base.Dispose(isDisposing); if (editorBeatmap != null) - editorBeatmap.HitObjectUpdated -= hitObjectUpdated; + editorBeatmap.SelectionBlueprintsShouldBeSorted -= SortInternal; } } } diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 8aa754b305..82f2187901 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -48,6 +48,11 @@ namespace osu.Game.Screens.Edit /// public event Action HitObjectUpdated; + /// + /// Invoked after is updated during and blueprints need to be sorted immediately to prevent a crash. + /// + public event Action SelectionBlueprintsShouldBeSorted; + /// /// All currently selected s. /// @@ -331,6 +336,9 @@ namespace osu.Game.Screens.Edit beatmapProcessor?.PostProcess(); + // Signal selection blueprint sorting because it is possible that the beatmap processor changed the order of the selection blueprints + SelectionBlueprintsShouldBeSorted?.Invoke(); + // callbacks may modify the lists so let's be safe about it var deletes = batchPendingDeletes.ToArray(); batchPendingDeletes.Clear(); From 0ca4be5e5bf43db46950b56c900891e1fd1097d4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 13 Sep 2022 03:45:31 +0300 Subject: [PATCH 1081/2686] Fix one more inspection --- .../UI/DrawableRulesetDependencies.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs index cffbf2c9a1..52387a5740 100644 --- a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs +++ b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs @@ -53,20 +53,17 @@ namespace osu.Game.Rulesets.UI { var resources = ruleset.CreateResourceStore(); - if (resources != null) - { - var host = parent.Get(); + var host = parent.Get(); - TextureStore = new TextureStore(host.Renderer, parent.Get().CreateTextureLoaderStore(new NamespacedResourceStore(resources, @"Textures"))); - CacheAs(TextureStore = new FallbackTextureStore(host.Renderer, TextureStore, parent.Get())); + TextureStore = new TextureStore(host.Renderer, parent.Get().CreateTextureLoaderStore(new NamespacedResourceStore(resources, @"Textures"))); + CacheAs(TextureStore = new FallbackTextureStore(host.Renderer, TextureStore, parent.Get())); - SampleStore = parent.Get().GetSampleStore(new NamespacedResourceStore(resources, @"Samples")); - SampleStore.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY; - CacheAs(SampleStore = new FallbackSampleStore(SampleStore, parent.Get())); + SampleStore = parent.Get().GetSampleStore(new NamespacedResourceStore(resources, @"Samples")); + SampleStore.PlaybackConcurrency = OsuGameBase.SAMPLE_CONCURRENCY; + CacheAs(SampleStore = new FallbackSampleStore(SampleStore, parent.Get())); - ShaderManager = new ShaderManager(host.Renderer, new NamespacedResourceStore(resources, @"Shaders")); - CacheAs(ShaderManager = new FallbackShaderManager(host.Renderer, ShaderManager, parent.Get())); - } + ShaderManager = new ShaderManager(host.Renderer, new NamespacedResourceStore(resources, @"Shaders")); + CacheAs(ShaderManager = new FallbackShaderManager(host.Renderer, ShaderManager, parent.Get())); RulesetConfigManager = parent.Get().GetConfigFor(ruleset); if (RulesetConfigManager != null) From 6bf6b7e125639aa3a20d972bb87cf2d712975b41 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 13:07:23 +0900 Subject: [PATCH 1082/2686] Fix null considerations in `DrawableRulesetDependencies` --- .../UI/DrawableRulesetDependencies.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs index 52387a5740..ad52b4affc 100644 --- a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs +++ b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.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. -#nullable disable - using System; using System.Collections.Generic; using System.IO; @@ -12,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; @@ -44,9 +43,9 @@ namespace osu.Game.Rulesets.UI public ShaderManager ShaderManager { get; } /// - /// The ruleset config manager. + /// The ruleset config manager. May be null if ruleset does not expose a configuration manager. /// - public IRulesetConfigManager RulesetConfigManager { get; private set; } + public IRulesetConfigManager? RulesetConfigManager { get; } public DrawableRulesetDependencies(Ruleset ruleset, IReadOnlyDependencyContainer parent) : base(parent) @@ -93,10 +92,9 @@ namespace osu.Game.Rulesets.UI isDisposed = true; - SampleStore?.Dispose(); - TextureStore?.Dispose(); - ShaderManager?.Dispose(); - RulesetConfigManager = null; + if (ShaderManager.IsNotNull()) SampleStore.Dispose(); + if (TextureStore.IsNotNull()) TextureStore.Dispose(); + if (ShaderManager.IsNotNull()) ShaderManager.Dispose(); } #endregion @@ -157,7 +155,7 @@ namespace osu.Game.Rulesets.UI public void Dispose() { - primary?.Dispose(); + if (primary.IsNotNull()) primary.Dispose(); } } @@ -182,7 +180,7 @@ namespace osu.Game.Rulesets.UI protected override void Dispose(bool disposing) { base.Dispose(disposing); - primary?.Dispose(); + if (primary.IsNotNull()) primary.Dispose(); } } @@ -198,12 +196,12 @@ namespace osu.Game.Rulesets.UI this.fallback = fallback; } - public override byte[] LoadRaw(string name) => primary.LoadRaw(name) ?? fallback.LoadRaw(name); + public override byte[]? LoadRaw(string name) => primary.LoadRaw(name) ?? fallback.LoadRaw(name); protected override void Dispose(bool disposing) { base.Dispose(disposing); - primary?.Dispose(); + if (primary.IsNotNull()) primary.Dispose(); } } } From d368f37c3ab8c360cd1a31138543118f90fd1625 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 13:50:59 +0900 Subject: [PATCH 1083/2686] Remove redundant second `Current` set operation --- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 13249e37ca..4787b07af8 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -76,8 +76,6 @@ namespace osu.Game.Overlays.Settings.Sections { base.LoadComplete(); - skinDropdown.Current = skins.CurrentSkinInfo; - realmSubscription = realm.RegisterForNotifications(_ => realm.Realm.All() .Where(s => !s.DeletePending) .OrderByDescending(s => s.Protected) // protected skins should be at the top. From 0fcd9e02f632230d3d1b884e88a5d4c0891f2c9c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 14:01:40 +0900 Subject: [PATCH 1084/2686] Fix skin dropdown not updating correctly when skin is changed externally --- osu.Game/Database/Live.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Database/Live.cs b/osu.Game/Database/Live.cs index 52e1d420f7..a21b7f606b 100644 --- a/osu.Game/Database/Live.cs +++ b/osu.Game/Database/Live.cs @@ -53,6 +53,8 @@ namespace osu.Game.Database public bool Equals(Live? other) => ID == other?.ID; + public override int GetHashCode() => HashCode.Combine(ID); + public override string ToString() => PerformRead(i => i.ToString()); } } From ac034bffebe3597716bdaf14395452925881549d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 14:21:54 +0900 Subject: [PATCH 1085/2686] Fix potential crash if multiplayer spectator load is aborted early --- .../Multiplayer/Spectate/MultiSpectatorPlayer.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 8e79c89685..6e939c3916 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.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.Threading; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Game.Beatmaps; @@ -34,8 +35,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } [BackgroundDependencyLoader] - private void load() + private void load(CancellationToken cancellationToken) { + // HUD overlay may not be loaded if load has been cancelled early. + if (cancellationToken.IsCancellationRequested) + return; + HUDOverlay.PlayerSettingsOverlay.Expire(); HUDOverlay.HoldToQuit.Expire(); } From f53507828c0bfdb7909c895a0d921c6de31ef9ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 14:59:30 +0900 Subject: [PATCH 1086/2686] Rename event to be more generic (and add comprehensive xmldoc) --- .../Components/HitObjectOrderedSelectionContainer.cs | 4 ++-- osu.Game/Screens/Edit/EditorBeatmap.cs | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs b/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs index 2d8dca9c2d..18bb6284b8 100644 --- a/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Edit.Compose.Components { base.LoadComplete(); - editorBeatmap.SelectionBlueprintsShouldBeSorted += SortInternal; + editorBeatmap.BeatmapReprocessed += SortInternal; } public override void Add(SelectionBlueprint drawable) @@ -70,7 +70,7 @@ namespace osu.Game.Screens.Edit.Compose.Components base.Dispose(isDisposing); if (editorBeatmap != null) - editorBeatmap.SelectionBlueprintsShouldBeSorted -= SortInternal; + editorBeatmap.BeatmapReprocessed -= SortInternal; } } } diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 82f2187901..16c0064e80 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -49,9 +49,13 @@ namespace osu.Game.Screens.Edit public event Action HitObjectUpdated; /// - /// Invoked after is updated during and blueprints need to be sorted immediately to prevent a crash. + /// Invoked after any state changes occurred which triggered a beatmap reprocess via an . /// - public event Action SelectionBlueprintsShouldBeSorted; + /// + /// Beatmap processing may change the order of hitobjects. This event gives external components a chance to handle any changes + /// not covered by the / / events. + /// + public event Action BeatmapReprocessed; /// /// All currently selected s. @@ -336,8 +340,7 @@ namespace osu.Game.Screens.Edit beatmapProcessor?.PostProcess(); - // Signal selection blueprint sorting because it is possible that the beatmap processor changed the order of the selection blueprints - SelectionBlueprintsShouldBeSorted?.Invoke(); + BeatmapReprocessed?.Invoke(); // callbacks may modify the lists so let's be safe about it var deletes = batchPendingDeletes.ToArray(); From 608c893b23f2007e6793de9cff1e72aec92fe70b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 15:03:13 +0900 Subject: [PATCH 1087/2686] Add basic test guarantees --- .../Editing/TestSceneSelectionBlueprintDeselection.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs b/osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs index 6141e5f31c..5c933468be 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs @@ -28,13 +28,17 @@ namespace osu.Game.Tests.Visual.Editing EditorClock.Seek(0); circle1 = new HitCircle(); var circle2 = new HitCircle(); + EditorBeatmap.Add(circle1); EditorBeatmap.Add(circle2); + EditorBeatmap.SelectedHitObjects.Add(circle1); EditorBeatmap.SelectedHitObjects.Add(circle2); }); AddStep("delete the first circle", () => EditorBeatmap.Remove(circle1)); + AddAssert("one hitobject remains", () => EditorBeatmap.HitObjects.Count == 1); + AddAssert("one hitobject selected", () => EditorBeatmap.SelectedHitObjects.Count == 1); } [Test] @@ -63,6 +67,9 @@ namespace osu.Game.Tests.Visual.Editing InputManager.PressKey(Key.Delete); InputManager.ReleaseKey(Key.Delete); }); + + AddAssert("10 hitobjects remain", () => EditorBeatmap.HitObjects.Count == 10); + AddAssert("no hitobjects selected", () => EditorBeatmap.SelectedHitObjects.Count == 0); } } } From 3490b160563b74ab4a227d1f3a1885d233ab16da Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 10 Sep 2022 01:10:55 +0300 Subject: [PATCH 1088/2686] Add simplified `SoloGameplayLeaderboard` implementation Note that this doesn't support waiting until leaderboard finishes fetching scores. --- .../Play/HUD/SoloGameplayLeaderboard.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs new file mode 100644 index 0000000000..20af036ec9 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using osu.Framework.Allocation; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Leaderboards; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Screens.Play.HUD +{ + public class SoloGameplayLeaderboard : GameplayLeaderboard + { + [BackgroundDependencyLoader] + private void load(IAPIProvider api, ScoreProcessor processor, ILeaderboard leaderboard) + { + var local = Add(api.LocalUser.Value, true); + local.TotalScore.BindTarget = processor.TotalScore; + local.Accuracy.BindTarget = processor.Accuracy; + local.Combo.BindTarget = processor.Combo; + + foreach (var player in leaderboard.Scores) + { + // todo: APIUser is pain for IScoreInfo. + var score = Add(new APIUser + { + Id = player.User.OnlineID, + Username = player.User.Username, + }, false); + + score.TotalScore.Value = player.TotalScore; + score.Accuracy.Value = player.Accuracy; + score.Combo.Value = player.MaxCombo; + } + } + } +} From fed9a47866664a689ac6dd0c916e578b7a653970 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 10 Sep 2022 01:12:57 +0300 Subject: [PATCH 1089/2686] Add test coverage --- .../TestSceneSoloGameplayLeaderboard.cs | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs new file mode 100644 index 0000000000..0ea2271fbf --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -0,0 +1,64 @@ +// 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.Graphics; +using osu.Framework.Utils; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Screens.Play.HUD; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneSoloGameplayLeaderboard : OsuTestScene + { + [Cached] + private readonly ScoreProcessor scoreProcessor = new ScoreProcessor(new OsuRuleset()); + + private SoloGameplayLeaderboard leaderboard = null!; + + [SetUp] + public void SetUp() => Schedule(() => + { + var trackingUser = new APIUser + { + Username = "local user", + Id = 2, + }; + + Child = leaderboard = new SoloGameplayLeaderboard(trackingUser) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Expanded = { Value = true }, + }; + + leaderboard.ShowScores(createSampleScores()); + }); + + [Test] + public void TestLocalUser() + { + AddSliderStep("score", 0, 1000000, 500000, v => scoreProcessor.TotalScore.Value = v); + AddSliderStep("accuracy", 0f, 1f, 0.5f, v => scoreProcessor.Accuracy.Value = v); + AddSliderStep("combo", 0, 1000, 0, v => scoreProcessor.Combo.Value = v); + } + + private static List createSampleScores() + { + return new[] + { + new ScoreInfo { User = new APIUser { Username = @"peppy" }, TotalScore = RNG.Next(500000, 1000000) }, + new ScoreInfo { User = new APIUser { Username = @"smoogipoo" }, TotalScore = RNG.Next(500000, 1000000) }, + new ScoreInfo { User = new APIUser { Username = @"spaceman_atlas" }, TotalScore = RNG.Next(500000, 1000000) }, + new ScoreInfo { User = new APIUser { Username = @"frenzibyte" }, TotalScore = RNG.Next(500000, 1000000) }, + new ScoreInfo { User = new APIUser { Username = @"Susko3" }, TotalScore = RNG.Next(500000, 1000000) }, + }.Concat(Enumerable.Range(0, 50).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 500000 + i * 10000 })).ToList(); + } + } +} From 4c669e2bce8889bef580d5936fa7320f89e83358 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 16:04:38 +0900 Subject: [PATCH 1090/2686] Track local `Player.Score`'s user rather than using `APIProvider` --- .../Screens/Play/HUD/GameplayLeaderboard.cs | 9 +++------ .../Play/HUD/SoloGameplayLeaderboard.cs | 20 +++++++++---------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index f21ce5e36a..16b36a7468 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -1,11 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Caching; using osu.Framework.Extensions.Color4Extensions; @@ -31,7 +28,7 @@ namespace osu.Game.Screens.Play.HUD private bool requiresScroll; private readonly OsuScrollContainer scroll; - private GameplayLeaderboardScore trackedScore; + private GameplayLeaderboardScore? trackedScore; /// /// Create a new leaderboard. @@ -77,7 +74,7 @@ namespace osu.Game.Screens.Play.HUD /// Whether the player should be tracked on the leaderboard. /// Set to true for the local player or a player whose replay is currently being played. /// - public ILeaderboardScore Add([CanBeNull] APIUser user, bool isTracked) + public ILeaderboardScore Add(APIUser? user, bool isTracked) { var drawable = CreateLeaderboardScoreDrawable(user, isTracked); @@ -108,7 +105,7 @@ namespace osu.Game.Screens.Play.HUD scroll.ScrollToStart(false); } - protected virtual GameplayLeaderboardScore CreateLeaderboardScoreDrawable(APIUser user, bool isTracked) => + protected virtual GameplayLeaderboardScore CreateLeaderboardScoreDrawable(APIUser? user, bool isTracked) => new GameplayLeaderboardScore(user, isTracked); protected override void Update() diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 20af036ec9..cfe1b4c86a 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -1,10 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; -using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Scoring; @@ -14,25 +11,26 @@ namespace osu.Game.Screens.Play.HUD public class SoloGameplayLeaderboard : GameplayLeaderboard { [BackgroundDependencyLoader] - private void load(IAPIProvider api, ScoreProcessor processor, ILeaderboard leaderboard) + private void load(Player player, ScoreProcessor processor, ILeaderboard leaderboard) { - var local = Add(api.LocalUser.Value, true); + ILeaderboardScore local = Add(player.Score.ScoreInfo.User, true); + local.TotalScore.BindTarget = processor.TotalScore; local.Accuracy.BindTarget = processor.Accuracy; local.Combo.BindTarget = processor.Combo; - foreach (var player in leaderboard.Scores) + foreach (var s in leaderboard.Scores) { // todo: APIUser is pain for IScoreInfo. var score = Add(new APIUser { - Id = player.User.OnlineID, - Username = player.User.Username, + Id = s.User.OnlineID, + Username = s.User.Username, }, false); - score.TotalScore.Value = player.TotalScore; - score.Accuracy.Value = player.Accuracy; - score.Combo.Value = player.MaxCombo; + score.TotalScore.Value = s.TotalScore; + score.Accuracy.Value = s.Accuracy; + score.Combo.Value = s.MaxCombo; } } } From 368faa00847b9d33011af1d3c331339c0445475b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 16:07:31 +0900 Subject: [PATCH 1091/2686] Make constructor `protected` in base implementation --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 16b36a7468..8bcc831de7 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -16,9 +16,8 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { - public class GameplayLeaderboard : CompositeDrawable + public abstract class GameplayLeaderboard : CompositeDrawable { - private readonly int maxPanels; private readonly Cached sorting = new Cached(); public Bindable Expanded = new Bindable(); @@ -30,14 +29,13 @@ namespace osu.Game.Screens.Play.HUD private GameplayLeaderboardScore? trackedScore; + private const int max_panels = 8; + /// /// Create a new leaderboard. /// - /// The maximum panels to show at once. Defines the maximum height of this component. - public GameplayLeaderboard(int maxPanels = 8) + protected GameplayLeaderboard() { - this.maxPanels = maxPanels; - Width = GameplayLeaderboardScore.EXTENDED_WIDTH + GameplayLeaderboardScore.SHEAR_WIDTH; InternalChildren = new Drawable[] @@ -91,7 +89,7 @@ namespace osu.Game.Screens.Play.HUD Flow.Add(drawable); drawable.TotalScore.BindValueChanged(_ => sorting.Invalidate(), true); - int displayCount = Math.Min(Flow.Count, maxPanels); + int displayCount = Math.Min(Flow.Count, max_panels); Height = displayCount * (GameplayLeaderboardScore.PANEL_HEIGHT + Flow.Spacing.Y); requiresScroll = displayCount != Flow.Count; From d251c0b2acbc5e9e52f0b5f4d800780ac61d35ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 16:36:09 +0900 Subject: [PATCH 1092/2686] Move leaderboard implementation to `Player` itself --- .../Multiplayer/MultiplayerPlayer.cs | 58 ++++++++----------- osu.Game/Screens/Play/Player.cs | 36 ++++++++++++ 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 773e68162e..d6d381d721 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -41,15 +41,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private readonly TaskCompletionSource resultsReady = new TaskCompletionSource(); - private MultiplayerGameplayLeaderboard leaderboard; - private readonly MultiplayerRoomUser[] users; - private readonly Bindable leaderboardExpanded = new BindableBool(); - private LoadingLayer loadingDisplay; private FillFlowContainer leaderboardFlow; + private MultiplayerGameplayLeaderboard multiplayerLeaderboard; + /// /// Construct a multiplayer player. /// @@ -81,38 +79,33 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Spacing = new Vector2(5) }); - HUDOverlay.HoldingForHUD.BindValueChanged(_ => updateLeaderboardExpandedState()); - LocalUserPlaying.BindValueChanged(_ => updateLeaderboardExpandedState(), true); - - // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. - LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(users), l => - { - if (!LoadedBeatmapSuccessfully) - return; - - leaderboard.Expanded.BindTo(leaderboardExpanded); - - leaderboardFlow.Insert(0, l); - - if (leaderboard.TeamScores.Count >= 2) - { - LoadComponentAsync(new GameplayMatchScoreDisplay - { - Team1Score = { BindTarget = leaderboard.TeamScores.First().Value }, - Team2Score = { BindTarget = leaderboard.TeamScores.Last().Value }, - Expanded = { BindTarget = HUDOverlay.ShowHud }, - }, scoreDisplay => leaderboardFlow.Insert(1, scoreDisplay)); - } - }); - LoadComponentAsync(new GameplayChatDisplay(Room) { - Expanded = { BindTarget = leaderboardExpanded }, + Expanded = { BindTarget = LeaderboardExpandedState }, }, chat => leaderboardFlow.Insert(2, chat)); HUDOverlay.Add(loadingDisplay = new LoadingLayer(true) { Depth = float.MaxValue }); } + protected override GameplayLeaderboard CreateGameplayLeaderboard() => multiplayerLeaderboard = new MultiplayerGameplayLeaderboard(users); + + protected override void AddLeaderboardToHUD(GameplayLeaderboard leaderboard) + { + Debug.Assert(leaderboard == multiplayerLeaderboard); + + leaderboardFlow.Insert(0, leaderboard); + + if (multiplayerLeaderboard.TeamScores.Count >= 2) + { + LoadComponentAsync(new GameplayMatchScoreDisplay + { + Team1Score = { BindTarget = multiplayerLeaderboard.TeamScores.First().Value }, + Team2Score = { BindTarget = multiplayerLeaderboard.TeamScores.Last().Value }, + Expanded = { BindTarget = HUDOverlay.ShowHud }, + }, scoreDisplay => leaderboardFlow.Insert(1, scoreDisplay)); + } + } + protected override void LoadAsyncComplete() { base.LoadAsyncComplete(); @@ -167,9 +160,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer } } - private void updateLeaderboardExpandedState() => - leaderboardExpanded.Value = !LocalUserPlaying.Value || HUDOverlay.HoldingForHUD.Value; - private void failAndBail(string message = null) { if (!string.IsNullOrEmpty(message)) @@ -232,8 +222,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { Debug.Assert(Room.RoomID.Value != null); - return leaderboard.TeamScores.Count == 2 - ? new MultiplayerTeamResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem, leaderboard.TeamScores) + return multiplayerLeaderboard.TeamScores.Count == 2 + ? new MultiplayerTeamResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem, multiplayerLeaderboard.TeamScores) : new MultiplayerResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 91e9c3b58f..3fd57496bb 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -34,6 +34,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; +using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Users; @@ -375,6 +376,8 @@ namespace osu.Game.Screens.Play if (Configuration.AutomaticallySkipIntro) skipIntroOverlay.SkipWhenReady(); + + loadLeaderboard(); } protected virtual GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) => new MasterGameplayClockContainer(beatmap, gameplayStart); @@ -820,6 +823,39 @@ namespace osu.Game.Screens.Play return mouseWheelDisabled.Value && !e.AltPressed; } + #region Gameplay leaderboard + + protected readonly Bindable LeaderboardExpandedState = new BindableBool(); + + private void loadLeaderboard() + { + HUDOverlay.HoldingForHUD.BindValueChanged(_ => updateLeaderboardExpandedState()); + LocalUserPlaying.BindValueChanged(_ => updateLeaderboardExpandedState(), true); + + LoadComponentAsync(CreateGameplayLeaderboard(), leaderboard => + { + if (!LoadedBeatmapSuccessfully) + return; + + leaderboard.Expanded.BindTo(LeaderboardExpandedState); + AddLeaderboardToHUD(leaderboard); + }); + } + + protected virtual GameplayLeaderboard CreateGameplayLeaderboard() => new SoloGameplayLeaderboard(Score.ScoreInfo.User) + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Margin = new MarginPadding { Bottom = 75, Left = 20 }, + }; + + protected virtual void AddLeaderboardToHUD(GameplayLeaderboard leaderboard) => HUDOverlay.Add(leaderboard); + + private void updateLeaderboardExpandedState() => + LeaderboardExpandedState.Value = !LocalUserPlaying.Value || HUDOverlay.HoldingForHUD.Value; + + #endregion + #region Fail Logic protected FailOverlay FailOverlay { get; private set; } From ac58c222b9d798cc9163b466ca69c092ca95929f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 16:54:03 +0900 Subject: [PATCH 1093/2686] Allow `DrawableAvatar` to accept an `IUser` for now --- osu.Game/Users/Drawables/DrawableAvatar.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Users/Drawables/DrawableAvatar.cs b/osu.Game/Users/Drawables/DrawableAvatar.cs index 483106d3f4..155f63dc18 100644 --- a/osu.Game/Users/Drawables/DrawableAvatar.cs +++ b/osu.Game/Users/Drawables/DrawableAvatar.cs @@ -14,13 +14,13 @@ namespace osu.Game.Users.Drawables [LongRunningLoad] public class DrawableAvatar : Sprite { - private readonly APIUser user; + private readonly IUser user; /// /// A simple, non-interactable avatar sprite for the specified user. /// /// The user. A null value will get a placeholder avatar. - public DrawableAvatar(APIUser user = null) + public DrawableAvatar(IUser user = null) { this.user = user; @@ -33,10 +33,10 @@ namespace osu.Game.Users.Drawables [BackgroundDependencyLoader] private void load(LargeTextureStore textures) { - if (user != null && user.Id > 1) + if (user != null && user.OnlineID > 1) // TODO: The fallback here should not need to exist. Users should be looked up and populated via UserLookupCache or otherwise // in remaining cases where this is required (chat tabs, local leaderboard), at which point this should be removed. - Texture = textures.Get(user.AvatarUrl ?? $@"https://a.ppy.sh/{user.Id}"); + Texture = textures.Get((user as APIUser)?.AvatarUrl ?? $@"https://a.ppy.sh/{user.OnlineID}"); Texture ??= textures.Get(@"Online/avatar-guest"); } From d2b80645ab50a75736f39e4ae652c73cd687fae3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 16:56:19 +0900 Subject: [PATCH 1094/2686] Change `Leaderboard` to use `IUser` instead of `APIUser` --- .../Multiplayer/TestSceneMultiSpectatorLeaderboard.cs | 2 +- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 2 +- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 6 +++--- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 6 +++--- osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs | 5 +++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs index 9e6941738a..4fda4c1c50 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs @@ -120,6 +120,6 @@ namespace osu.Game.Tests.Visual.Multiplayer => AddStep($"set user {userId} time {time}", () => clocks[userId].CurrentTime = time); private void assertCombo(int userId, int expectedCombo) - => AddUntilStep($"player {userId} has {expectedCombo} combo", () => this.ChildrenOfType().Single(s => s.User?.Id == userId).Combo.Value == expectedCombo); + => AddUntilStep($"player {userId} has {expectedCombo} combo", () => this.ChildrenOfType().Single(s => s.User?.OnlineID == userId).Combo.Value == expectedCombo); } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 70f498e7f2..13fde4fd72 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -522,7 +522,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private PlayerArea getInstance(int userId) => spectatorScreen.ChildrenOfType().Single(p => p.UserId == userId); - private GameplayLeaderboardScore getLeaderboardScore(int userId) => spectatorScreen.ChildrenOfType().Single(s => s.User?.Id == userId); + private GameplayLeaderboardScore getLeaderboardScore(int userId) => spectatorScreen.ChildrenOfType().Single(s => s.User?.OnlineID == userId); private int[] getPlayerIds(int count) => Enumerable.Range(PLAYER_1_ID, count).ToArray(); } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 8bcc831de7..8b37e0bacb 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; -using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -72,7 +72,7 @@ namespace osu.Game.Screens.Play.HUD /// Whether the player should be tracked on the leaderboard. /// Set to true for the local player or a player whose replay is currently being played. /// - public ILeaderboardScore Add(APIUser? user, bool isTracked) + public ILeaderboardScore Add(IUser? user, bool isTracked) { var drawable = CreateLeaderboardScoreDrawable(user, isTracked); @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Play.HUD scroll.ScrollToStart(false); } - protected virtual GameplayLeaderboardScore CreateLeaderboardScoreDrawable(APIUser? user, bool isTracked) => + protected virtual GameplayLeaderboardScore CreateLeaderboardScoreDrawable(IUser? user, bool isTracked) => new GameplayLeaderboardScore(user, isTracked); protected override void Update() diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 0f007cd1cb..64a470311f 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users; using osu.Game.Users.Drawables; using osu.Game.Utils; using osuTK; @@ -81,7 +81,7 @@ namespace osu.Game.Screens.Play.HUD } [CanBeNull] - public APIUser User { get; } + public IUser User { get; } /// /// Whether this score is the local user or a replay player (and should be focused / always visible). @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Play.HUD /// /// The score's player. /// Whether the player is the local user or a replay player. - public GameplayLeaderboardScore([CanBeNull] APIUser user, bool tracked) + public GameplayLeaderboardScore([CanBeNull] IUser user, bool tracked) { User = user; Tracked = tracked; diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index ac58325060..56756249b3 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -21,6 +21,7 @@ using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; +using osu.Game.Users; using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD @@ -125,11 +126,11 @@ namespace osu.Game.Screens.Play.HUD playingUserIds.BindCollectionChanged(playingUsersChanged); } - protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(APIUser user, bool isTracked) + protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(IUser user, bool isTracked) { var leaderboardScore = base.CreateLeaderboardScoreDrawable(user, isTracked); - if (UserScores[user.Id].Team is int team) + if (UserScores[user.OnlineID].Team is int team) { leaderboardScore.BackgroundColour = getTeamColour(team).Lighten(1.2f); leaderboardScore.TextColour = Color4.White; From 70e6b595f1a7801a2b39e727d378f33dff3e1e5a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 17:07:13 +0900 Subject: [PATCH 1095/2686] Refactor `SoloGameplayLeaderboard` to not read scores via DI Also allows updating scores if they arrive late. --- .../Play/HUD/SoloGameplayLeaderboard.cs | 41 ++++++++++++------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index cfe1b4c86a..61be602d53 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -1,32 +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 System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Users; namespace osu.Game.Screens.Play.HUD { public class SoloGameplayLeaderboard : GameplayLeaderboard { - [BackgroundDependencyLoader] - private void load(Player player, ScoreProcessor processor, ILeaderboard leaderboard) + private readonly IUser trackingUser; + + [Resolved] + private ScoreProcessor scoreProcessor { get; set; } = null!; + + public SoloGameplayLeaderboard(IUser trackingUser) { - ILeaderboardScore local = Add(player.Score.ScoreInfo.User, true); + this.trackingUser = trackingUser; + } - local.TotalScore.BindTarget = processor.TotalScore; - local.Accuracy.BindTarget = processor.Accuracy; - local.Combo.BindTarget = processor.Combo; + public void ShowScores(IEnumerable scores) + { + Clear(); - foreach (var s in leaderboard.Scores) + if (!scores.Any()) + return; + + ILeaderboardScore local = Add(trackingUser, true); + + local.TotalScore.BindTarget = scoreProcessor.TotalScore; + local.Accuracy.BindTarget = scoreProcessor.Accuracy; + local.Combo.BindTarget = scoreProcessor.Combo; + + foreach (var s in scores) { - // todo: APIUser is pain for IScoreInfo. - var score = Add(new APIUser - { - Id = s.User.OnlineID, - Username = s.User.Username, - }, false); + var score = Add(s.User, false); score.TotalScore.Value = s.TotalScore; score.Accuracy.Value = s.Accuracy; From 6d167070f8629558dcbc7f83390c9906e7f4b272 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 17:49:53 +0900 Subject: [PATCH 1096/2686] Add back DI leaderboard retrieval via bindable pathway --- .../TestSceneSoloGameplayLeaderboard.cs | 42 ++++++++++++------- .../Leaderboards/ILeaderboardScoreSource.cs | 15 +++++++ osu.Game/Online/Leaderboards/Leaderboard.cs | 15 ++++--- .../Play/HUD/SoloGameplayLeaderboard.cs | 15 ++++++- .../Select/Leaderboards/BeatmapLeaderboard.cs | 5 ++- osu.Game/Screens/Select/PlaySongSelect.cs | 23 ++++++++-- 6 files changed, 86 insertions(+), 29 deletions(-) create mode 100644 osu.Game/Online/Leaderboards/ILeaderboardScoreSource.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index 0ea2271fbf..6839fafa93 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -5,9 +5,12 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; @@ -15,31 +18,36 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSoloGameplayLeaderboard : OsuTestScene + public class TestSceneSoloGameplayLeaderboard : OsuTestScene, ILeaderboardScoreSource { [Cached] private readonly ScoreProcessor scoreProcessor = new ScoreProcessor(new OsuRuleset()); - private SoloGameplayLeaderboard leaderboard = null!; + private readonly BindableList scores = new BindableList(); - [SetUp] - public void SetUp() => Schedule(() => + [SetUpSteps] + public void SetUpSteps() { - var trackingUser = new APIUser - { - Username = "local user", - Id = 2, - }; + AddStep("clear scores", () => scores.Clear()); - Child = leaderboard = new SoloGameplayLeaderboard(trackingUser) + AddStep("create component", () => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Expanded = { Value = true }, - }; + var trackingUser = new APIUser + { + Username = "local user", + Id = 2, + }; - leaderboard.ShowScores(createSampleScores()); - }); + Child = new SoloGameplayLeaderboard(trackingUser) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Expanded = { Value = true }, + }; + }); + + AddStep("add scores", () => scores.AddRange(createSampleScores())); + } [Test] public void TestLocalUser() @@ -49,6 +57,8 @@ namespace osu.Game.Tests.Visual.Gameplay AddSliderStep("combo", 0, 1000, 0, v => scoreProcessor.Combo.Value = v); } + IBindableList ILeaderboardScoreSource.Scores => scores; + private static List createSampleScores() { return new[] diff --git a/osu.Game/Online/Leaderboards/ILeaderboardScoreSource.cs b/osu.Game/Online/Leaderboards/ILeaderboardScoreSource.cs new file mode 100644 index 0000000000..e7ed43633e --- /dev/null +++ b/osu.Game/Online/Leaderboards/ILeaderboardScoreSource.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.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Scoring; + +namespace osu.Game.Online.Leaderboards +{ + [Cached] + public interface ILeaderboardScoreSource + { + IBindableList Scores { get; } + } +} diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 58b1ea62aa..9b6e9fbec7 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -39,7 +39,9 @@ namespace osu.Game.Online.Leaderboards /// /// The currently displayed scores. /// - public IEnumerable Scores => scores; + public IBindableList Scores => scores; + + private readonly BindableList scores = new BindableList(); /// /// Whether the current scope should refetch in response to changes in API connectivity state. @@ -68,8 +70,6 @@ namespace osu.Game.Online.Leaderboards private readonly IBindable apiState = new Bindable(); - private ICollection scores; - private TScope scope; public TScope Scope @@ -169,7 +169,7 @@ namespace osu.Game.Online.Leaderboards throw new InvalidOperationException($"State {state} cannot be set by a leaderboard implementation."); } - Debug.Assert(scores?.Any() != true); + Debug.Assert(scores.Any() != true); setState(state); } @@ -181,7 +181,10 @@ namespace osu.Game.Online.Leaderboards /// The user top score, if any. protected void SetScores(IEnumerable scores, TScoreInfo userScore = default) { - this.scores = scores?.ToList(); + this.scores.Clear(); + if (scores != null) + this.scores.AddRange(scores); + userScoreContainer.Score.Value = userScore; if (userScore == null) @@ -247,7 +250,7 @@ namespace osu.Game.Online.Leaderboards .Expire(); scoreFlowContainer = null; - if (scores?.Any() != true) + if (scores.Any() != true) { setState(LeaderboardState.NoScores); return; diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 61be602d53..a67e59df05 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Users; @@ -14,6 +16,8 @@ namespace osu.Game.Screens.Play.HUD { private readonly IUser trackingUser; + private readonly IBindableList scores = new BindableList(); + [Resolved] private ScoreProcessor scoreProcessor { get; set; } = null!; @@ -22,7 +26,16 @@ namespace osu.Game.Screens.Play.HUD this.trackingUser = trackingUser; } - public void ShowScores(IEnumerable scores) + [BackgroundDependencyLoader(true)] + private void load(ILeaderboardScoreSource? scoreSource) + { + if (scoreSource != null) + scores.BindTo(scoreSource.Scores); + + scores.BindCollectionChanged((_, __) => Scheduler.AddOnce(showScores, scores), true); + } + + private void showScores(IEnumerable scores) { Clear(); diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 343b815e9f..ee62160a21 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -23,7 +23,7 @@ using Realms; namespace osu.Game.Screens.Select.Leaderboards { - public class BeatmapLeaderboard : Leaderboard + public class BeatmapLeaderboard : Leaderboard, ILeaderboardScoreSource { public Action ScoreSelected; @@ -152,7 +152,8 @@ namespace osu.Game.Screens.Select.Leaderboards { SetScores( scoreManager.OrderByTotalScore(r.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))), - r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo)); + r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo) + ); }); return req; diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index c24ca9a7cf..a4c797a034 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -6,10 +6,12 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Screens; using osu.Game.Graphics; +using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; @@ -22,7 +24,7 @@ using osuTK.Input; namespace osu.Game.Screens.Select { - public class PlaySongSelect : SongSelect + public class PlaySongSelect : SongSelect, ILeaderboardScoreSource { private OsuScreen playerLoader; @@ -37,14 +39,25 @@ namespace osu.Game.Screens.Select private void load(OsuColour colours) { BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit()); - - ((PlayBeatmapDetailArea)BeatmapDetails).Leaderboard.ScoreSelected += PresentScore; } protected void PresentScore(ScoreInfo score) => FinaliseSelection(score.BeatmapInfo, score.Ruleset, () => this.Push(new SoloResultsScreen(score, false))); - protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); + protected override BeatmapDetailArea CreateBeatmapDetailArea() + { + var playBeatmapDetailArea = new PlayBeatmapDetailArea + { + Leaderboard = + { + ScoreSelected = PresentScore + } + }; + + Scores.BindTo(playBeatmapDetailArea.Leaderboard.Scores); + + return playBeatmapDetailArea; + } protected override bool OnKeyDown(KeyDownEvent e) { @@ -121,5 +134,7 @@ namespace osu.Game.Screens.Select playerLoader = null; } } + + IBindableList ILeaderboardScoreSource.Scores { get; } = new BindableList(); } } From 5894d2f0bca96e4af328dab2c7604b671943c529 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 18:12:49 +0900 Subject: [PATCH 1097/2686] Ensure gameplay leaderboard hides with rest of HUD when it should --- .../OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 3 ++- osu.Game/Screens/Play/HUDOverlay.cs | 12 ++++++++++-- osu.Game/Screens/Play/Player.cs | 3 ++- osu.Game/Screens/Play/PlayerConfiguration.cs | 5 +++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index d6d381d721..655aa08a72 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -60,7 +60,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer AllowPause = false, AllowRestart = false, AllowSkipping = room.AutoSkip.Value, - AutomaticallySkipIntro = room.AutoSkip.Value + AutomaticallySkipIntro = room.AutoSkip.Value, + AlwaysShowLeaderboard = true, }) { this.users = users; diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index f9f3693385..a727b8925b 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -9,7 +9,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.EnumExtensions; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; @@ -80,7 +79,7 @@ namespace osu.Game.Screens.Play private readonly SkinnableTargetContainer mainComponents; - private IEnumerable hideTargets => new Drawable[] { mainComponents, KeyCounter, topRightElements }; + private readonly List hideTargets; public HUDOverlay(DrawableRuleset drawableRuleset, IReadOnlyList mods) { @@ -129,6 +128,8 @@ namespace osu.Game.Screens.Play }, clicksPerSecondCalculator = new ClicksPerSecondCalculator() }; + + hideTargets = new List { mainComponents, KeyCounter, topRightElements }; } [BackgroundDependencyLoader(true)] @@ -173,6 +174,13 @@ namespace osu.Game.Screens.Play replayLoaded.BindValueChanged(replayLoadedValueChanged, true); } + public void Add(Drawable drawable, bool hideWithHUD) + { + base.Add(drawable); + if (hideWithHUD) + hideTargets.Add(drawable); + } + protected override void Update() { base.Update(); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 3fd57496bb..659dbd06ef 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -838,6 +838,7 @@ namespace osu.Game.Screens.Play return; leaderboard.Expanded.BindTo(LeaderboardExpandedState); + AddLeaderboardToHUD(leaderboard); }); } @@ -849,7 +850,7 @@ namespace osu.Game.Screens.Play Margin = new MarginPadding { Bottom = 75, Left = 20 }, }; - protected virtual void AddLeaderboardToHUD(GameplayLeaderboard leaderboard) => HUDOverlay.Add(leaderboard); + protected virtual void AddLeaderboardToHUD(GameplayLeaderboard leaderboard) => HUDOverlay.Add(leaderboard, !Configuration.AlwaysShowLeaderboard); private void updateLeaderboardExpandedState() => LeaderboardExpandedState.Value = !LocalUserPlaying.Value || HUDOverlay.HoldingForHUD.Value; diff --git a/osu.Game/Screens/Play/PlayerConfiguration.cs b/osu.Game/Screens/Play/PlayerConfiguration.cs index b1b0e01d80..b82925ccb8 100644 --- a/osu.Game/Screens/Play/PlayerConfiguration.cs +++ b/osu.Game/Screens/Play/PlayerConfiguration.cs @@ -36,5 +36,10 @@ namespace osu.Game.Screens.Play /// Whether the intro should be skipped by default. /// public bool AutomaticallySkipIntro { get; set; } + + /// + /// Whether the gameplay leaderboard should always be shown (usually in a contracted state). + /// + public bool AlwaysShowLeaderboard { get; set; } } } From 678eec1c674d0d591d08c35e017d197e55f35503 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 18:23:47 +0900 Subject: [PATCH 1098/2686] Move `LeaderboardFlow` to `HUDOverlay` to share positioning logic --- .../Multiplayer/MultiplayerPlayer.cs | 34 ++----------------- osu.Game/Screens/Play/HUDOverlay.cs | 34 ++++++++++++++----- osu.Game/Screens/Play/Player.cs | 11 ++---- 3 files changed, 31 insertions(+), 48 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 655aa08a72..a2c43898f7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -9,8 +9,6 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Graphics.UserInterface; @@ -21,7 +19,6 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; using osu.Game.Users; -using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer { @@ -44,7 +41,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private readonly MultiplayerRoomUser[] users; private LoadingLayer loadingDisplay; - private FillFlowContainer leaderboardFlow; private MultiplayerGameplayLeaderboard multiplayerLeaderboard; @@ -73,17 +69,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer if (!LoadedBeatmapSuccessfully) return; - HUDOverlay.Add(leaderboardFlow = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(5) - }); - LoadComponentAsync(new GameplayChatDisplay(Room) { Expanded = { BindTarget = LeaderboardExpandedState }, - }, chat => leaderboardFlow.Insert(2, chat)); + }, chat => HUDOverlay.LeaderboardFlow.Insert(2, chat)); HUDOverlay.Add(loadingDisplay = new LoadingLayer(true) { Depth = float.MaxValue }); } @@ -94,7 +83,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { Debug.Assert(leaderboard == multiplayerLeaderboard); - leaderboardFlow.Insert(0, leaderboard); + HUDOverlay.LeaderboardFlow.Insert(0, leaderboard); if (multiplayerLeaderboard.TeamScores.Count >= 2) { @@ -103,7 +92,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Team1Score = { BindTarget = multiplayerLeaderboard.TeamScores.First().Value }, Team2Score = { BindTarget = multiplayerLeaderboard.TeamScores.Last().Value }, Expanded = { BindTarget = HUDOverlay.ShowHud }, - }, scoreDisplay => leaderboardFlow.Insert(1, scoreDisplay)); + }, scoreDisplay => HUDOverlay.LeaderboardFlow.Insert(1, scoreDisplay)); } } @@ -169,23 +158,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Schedule(() => PerformExit(false)); } - protected override void Update() - { - base.Update(); - - if (!LoadedBeatmapSuccessfully) - return; - - adjustLeaderboardPosition(); - } - - private void adjustLeaderboardPosition() - { - const float padding = 44; // enough margin to avoid the hit error display. - - leaderboardFlow.Position = new Vector2(padding, padding + HUDOverlay.TopScoringElementsHeight); - } - private void onGameplayStarted() => Scheduler.Add(() => { if (!this.IsCurrentScreen()) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index a727b8925b..d08f3fc07f 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -79,9 +79,15 @@ namespace osu.Game.Screens.Play private readonly SkinnableTargetContainer mainComponents; + /// + /// A flow which sits at the left side of the screen to house leaderboard (and related) components. + /// Will automatically be positioned to avoid colliding with top scoring elements. + /// + public readonly FillFlowContainer LeaderboardFlow; + private readonly List hideTargets; - public HUDOverlay(DrawableRuleset drawableRuleset, IReadOnlyList mods) + public HUDOverlay(DrawableRuleset drawableRuleset, IReadOnlyList mods, bool alwaysShowLeaderboard = true) { this.drawableRuleset = drawableRuleset; this.mods = mods; @@ -126,10 +132,19 @@ namespace osu.Game.Screens.Play HoldToQuit = CreateHoldForMenuButton(), } }, - clicksPerSecondCalculator = new ClicksPerSecondCalculator() + LeaderboardFlow = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5) + }, + clicksPerSecondCalculator = new ClicksPerSecondCalculator(), }; hideTargets = new List { mainComponents, KeyCounter, topRightElements }; + + if (alwaysShowLeaderboard) + hideTargets.Add(LeaderboardFlow); } [BackgroundDependencyLoader(true)] @@ -174,13 +189,6 @@ namespace osu.Game.Screens.Play replayLoaded.BindValueChanged(replayLoadedValueChanged, true); } - public void Add(Drawable drawable, bool hideWithHUD) - { - base.Add(drawable); - if (hideWithHUD) - hideTargets.Add(drawable); - } - protected override void Update() { base.Update(); @@ -220,6 +228,14 @@ namespace osu.Game.Screens.Play bottomRightElements.Y = BottomScoringElementsHeight = -MathHelper.Clamp(DrawHeight - ToLocalSpace(highestBottomScreenSpace.Value).Y, 0, DrawHeight - bottomRightElements.DrawHeight); else bottomRightElements.Y = 0; + + adjustLeaderboardPosition(); + } + + private void adjustLeaderboardPosition() + { + const float padding = 44; // enough margin to avoid the hit error display. + LeaderboardFlow.Position = new Vector2(padding, padding + TopScoringElementsHeight); } private void updateVisibility() diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 659dbd06ef..95e3e75c8a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -420,7 +420,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(DrawableRuleset, GameplayState.Mods) + HUDOverlay = new HUDOverlay(DrawableRuleset, GameplayState.Mods, Configuration.AlwaysShowLeaderboard) { HoldToQuit = { @@ -843,14 +843,9 @@ namespace osu.Game.Screens.Play }); } - protected virtual GameplayLeaderboard CreateGameplayLeaderboard() => new SoloGameplayLeaderboard(Score.ScoreInfo.User) - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Margin = new MarginPadding { Bottom = 75, Left = 20 }, - }; + protected virtual GameplayLeaderboard CreateGameplayLeaderboard() => new SoloGameplayLeaderboard(Score.ScoreInfo.User); - protected virtual void AddLeaderboardToHUD(GameplayLeaderboard leaderboard) => HUDOverlay.Add(leaderboard, !Configuration.AlwaysShowLeaderboard); + protected virtual void AddLeaderboardToHUD(GameplayLeaderboard leaderboard) => HUDOverlay.LeaderboardFlow.Add(leaderboard); private void updateLeaderboardExpandedState() => LeaderboardExpandedState.Value = !LocalUserPlaying.Value || HUDOverlay.HoldingForHUD.Value; From e15a25ea492061306cff82ef09e58d4f95490b56 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 18:42:57 +0900 Subject: [PATCH 1099/2686] Fix leaderboard positioning logic to actually consider elements on the left side --- osu.Game/Screens/Play/HUDOverlay.cs | 47 +++++++++++++++++------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index d08f3fc07f..c340f262ed 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -34,11 +34,6 @@ namespace osu.Game.Screens.Play public const Easing FADE_EASING = Easing.OutQuint; - /// - /// The total height of all the top of screen scoring elements. - /// - public float TopScoringElementsHeight { get; private set; } - /// /// The total height of all the bottom of screen scoring elements. /// @@ -136,6 +131,7 @@ namespace osu.Game.Screens.Play { AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, + Padding = new MarginPadding(44), // enough margin to avoid the hit error display Spacing = new Vector2(5) }, clicksPerSecondCalculator = new ClicksPerSecondCalculator(), @@ -193,22 +189,36 @@ namespace osu.Game.Screens.Play { base.Update(); - Vector2? lowestTopScreenSpace = null; + float? lowestTopScreenSpaceLeft = null; + float? lowestTopScreenSpaceRight = null; + Vector2? highestBottomScreenSpace = null; // LINQ cast can be removed when IDrawable interface includes Anchor / RelativeSizeAxes. foreach (var element in mainComponents.Components.Cast()) { // for now align top-right components with the bottom-edge of the lowest top-anchored hud element. - if (element.Anchor.HasFlagFast(Anchor.TopRight) || (element.Anchor.HasFlagFast(Anchor.y0) && element.RelativeSizeAxes == Axes.X)) + if (element.Anchor.HasFlagFast(Anchor.y0)) { // health bars are excluded for the sake of hacky legacy skins which extend the health bar to take up the full screen area. if (element is LegacyHealthDisplay) continue; - var bottomRight = element.ScreenSpaceDrawQuad.BottomRight; - if (lowestTopScreenSpace == null || bottomRight.Y > lowestTopScreenSpace.Value.Y) - lowestTopScreenSpace = bottomRight; + float bottom = element.ScreenSpaceDrawQuad.BottomRight.Y; + + bool isRelativeX = element.RelativeSizeAxes == Axes.X; + + if (element.Anchor.HasFlagFast(Anchor.TopRight) || isRelativeX) + { + if (lowestTopScreenSpaceRight == null || bottom > lowestTopScreenSpaceRight.Value) + lowestTopScreenSpaceRight = bottom; + } + + if (element.Anchor.HasFlagFast(Anchor.TopLeft) || isRelativeX) + { + if (lowestTopScreenSpaceLeft == null || bottom > lowestTopScreenSpaceLeft.Value) + lowestTopScreenSpaceLeft = bottom; + } } // and align bottom-right components with the top-edge of the highest bottom-anchored hud element. else if (element.Anchor.HasFlagFast(Anchor.BottomRight) || (element.Anchor.HasFlagFast(Anchor.y2) && element.RelativeSizeAxes == Axes.X)) @@ -219,23 +229,20 @@ namespace osu.Game.Screens.Play } } - if (lowestTopScreenSpace.HasValue) - topRightElements.Y = TopScoringElementsHeight = MathHelper.Clamp(ToLocalSpace(lowestTopScreenSpace.Value).Y, 0, DrawHeight - topRightElements.DrawHeight); + if (lowestTopScreenSpaceRight.HasValue) + topRightElements.Y = MathHelper.Clamp(ToLocalSpace(new Vector2(0, lowestTopScreenSpaceRight.Value)).Y, 0, DrawHeight - topRightElements.DrawHeight); else topRightElements.Y = 0; + if (lowestTopScreenSpaceLeft.HasValue) + LeaderboardFlow.Y = MathHelper.Clamp(ToLocalSpace(new Vector2(0, lowestTopScreenSpaceLeft.Value)).Y, 0, DrawHeight - LeaderboardFlow.DrawHeight); + else + LeaderboardFlow.Y = 0; + if (highestBottomScreenSpace.HasValue) bottomRightElements.Y = BottomScoringElementsHeight = -MathHelper.Clamp(DrawHeight - ToLocalSpace(highestBottomScreenSpace.Value).Y, 0, DrawHeight - bottomRightElements.DrawHeight); else bottomRightElements.Y = 0; - - adjustLeaderboardPosition(); - } - - private void adjustLeaderboardPosition() - { - const float padding = 44; // enough margin to avoid the hit error display. - LeaderboardFlow.Position = new Vector2(padding, padding + TopScoringElementsHeight); } private void updateVisibility() From 9226f0abbca34bd14e6c3571ea7a4426cf9abf57 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 19:16:25 +0900 Subject: [PATCH 1100/2686] Implement equality correctly in `Live` --- osu.Game/Database/Live.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/Live.cs b/osu.Game/Database/Live.cs index a21b7f606b..3bb11c3a50 100644 --- a/osu.Game/Database/Live.cs +++ b/osu.Game/Database/Live.cs @@ -51,7 +51,13 @@ namespace osu.Game.Database ID = id; } - public bool Equals(Live? other) => ID == other?.ID; + public bool Equals(Live? other) + { + if (ReferenceEquals(this, other)) return true; + if (other == null) return false; + + return ID == other.ID; + } public override int GetHashCode() => HashCode.Combine(ID); From 94693a466767179a7307b469e584547e9fe7d990 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 19:55:57 +0900 Subject: [PATCH 1101/2686] Fix oversight when making interface implementation explicit --- osu.Game/Screens/Select/PlaySongSelect.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index a4c797a034..619ec97535 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; @@ -26,15 +24,17 @@ namespace osu.Game.Screens.Select { public class PlaySongSelect : SongSelect, ILeaderboardScoreSource { - private OsuScreen playerLoader; + private OsuScreen? playerLoader; [Resolved(CanBeNull = true)] - private INotificationOverlay notifications { get; set; } + private INotificationOverlay? notifications { get; set; } public override bool AllowExternalScreenChange => true; protected override UserActivity InitialActivity => new UserActivity.ChoosingBeatmap(); + private PlayBeatmapDetailArea playBeatmapDetailArea = null!; + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Select protected override BeatmapDetailArea CreateBeatmapDetailArea() { - var playBeatmapDetailArea = new PlayBeatmapDetailArea + playBeatmapDetailArea = new PlayBeatmapDetailArea { Leaderboard = { @@ -54,8 +54,6 @@ namespace osu.Game.Screens.Select } }; - Scores.BindTo(playBeatmapDetailArea.Leaderboard.Scores); - return playBeatmapDetailArea; } @@ -74,9 +72,9 @@ namespace osu.Game.Screens.Select return base.OnKeyDown(e); } - private IReadOnlyList modsAtGameplayStart; + private IReadOnlyList? modsAtGameplayStart; - private ModAutoplay getAutoplayMod() => Ruleset.Value.CreateInstance().GetAutoplayMod(); + private ModAutoplay? getAutoplayMod() => Ruleset.Value.CreateInstance().GetAutoplayMod(); protected override bool OnStart() { @@ -135,6 +133,6 @@ namespace osu.Game.Screens.Select } } - IBindableList ILeaderboardScoreSource.Scores { get; } = new BindableList(); + IBindableList ILeaderboardScoreSource.Scores => playBeatmapDetailArea.Leaderboard.Scores; } } From 81b5e4a8654513937945301029f596abc8ee123a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Sep 2022 19:57:40 +0900 Subject: [PATCH 1102/2686] Fix back-to-front condition on leaderboard always show configuration --- osu.Game/Screens/Play/HUDOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index c340f262ed..3e661e76f4 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -139,7 +139,7 @@ namespace osu.Game.Screens.Play hideTargets = new List { mainComponents, KeyCounter, topRightElements }; - if (alwaysShowLeaderboard) + if (!alwaysShowLeaderboard) hideTargets.Add(LeaderboardFlow); } From 04dbb6fc1b61e8e3be64484b079d7c20d0b26127 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Sep 2022 00:49:02 +0300 Subject: [PATCH 1103/2686] Add inline comment --- osu.Game/Overlays/BeatmapListingOverlay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 70c6c60ecd..2be328427b 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -176,6 +176,9 @@ namespace osu.Game.Overlays } else { + // new results may contain beatmaps from a previous page, + // this is dodgy but matches web behaviour for now. + // see: https://github.com/ppy/osu-web/issues/9270 newCards = newCards.Except(foundContent); panelLoadTask = LoadComponentsAsync(newCards, loaded => From b4e6a20846d10ddd8a2590d0fd5b8701ef9e5294 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Sep 2022 12:59:04 +0900 Subject: [PATCH 1104/2686] Fix song select status prefix matching no longer working Regressed in #19275 due to weird logic. Closes #20289. --- .../NonVisual/Filtering/FilterQueryParserTest.cs | 10 ++++++++++ osu.Game/Screens/Select/FilterQueryParser.cs | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index ac16c59e5b..da32edb8fb 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -191,6 +191,16 @@ namespace osu.Game.Tests.NonVisual.Filtering Assert.IsTrue(filterCriteria.BeatDivisor.IsUpperInclusive); } + [Test] + public void TestPartialStatusMatch() + { + const string query = "status=r"; + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, query); + Assert.AreEqual(BeatmapOnlineStatus.Ranked, filterCriteria.OnlineStatus.Min); + Assert.AreEqual(BeatmapOnlineStatus.Ranked, filterCriteria.OnlineStatus.Max); + } + [Test] public void TestApplyStatusQueries() { diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index a7c1aec361..c86554ddbc 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -122,14 +122,17 @@ namespace osu.Game.Screens.Select private static bool tryParseEnum(string value, out TEnum result) where TEnum : struct { - if (Enum.TryParse(value, true, out result)) return true; + // First try an exact match. + if (Enum.TryParse(value, true, out result)) + return true; + // Then try a prefix match. string? prefixMatch = Enum.GetNames(typeof(TEnum)).FirstOrDefault(name => name.StartsWith(value, true, CultureInfo.InvariantCulture)); if (prefixMatch == null) return false; - return Enum.TryParse(value, true, out result); + return Enum.TryParse(prefixMatch, true, out result); } private static GroupCollection? tryMatchRegex(string value, string regex) From 85e3a681b12e79b8cb12b6b8551bb3eea7e28566 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 13 Sep 2022 21:07:30 -0700 Subject: [PATCH 1105/2686] Fix notification overlay toast tray background absorbing input from behind --- osu.Game/Overlays/NotificationOverlayToastTray.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index e3f8734581..329379de4a 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -26,6 +26,8 @@ namespace osu.Game.Overlays { public override bool IsPresent => toastContentBackground.Height > 0 || toastFlow.Count > 0; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => toastFlow.ReceivePositionalInputAt(screenSpacePos); + public bool IsDisplayingToasts => toastFlow.Count > 0; private FillFlowContainer toastFlow = null!; From 8a6977213a285344f81a987af80cd0d6337ac243 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Sep 2022 14:02:35 +0900 Subject: [PATCH 1106/2686] Fix displayed scores in gameplay leaderboard not tracking display mode changes --- .../Play/HUD/SoloGameplayLeaderboard.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index a67e59df05..2282277c3c 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -18,9 +18,15 @@ namespace osu.Game.Screens.Play.HUD private readonly IBindableList scores = new BindableList(); + // hold references to ensure bindables are updated. + private readonly List> scoreBindables = new List>(); + [Resolved] private ScoreProcessor scoreProcessor { get; set; } = null!; + [Resolved] + private ScoreManager scoreManager { get; set; } = null!; + public SoloGameplayLeaderboard(IUser trackingUser) { this.trackingUser = trackingUser; @@ -32,12 +38,13 @@ namespace osu.Game.Screens.Play.HUD if (scoreSource != null) scores.BindTo(scoreSource.Scores); - scores.BindCollectionChanged((_, __) => Scheduler.AddOnce(showScores, scores), true); + scores.BindCollectionChanged((_, _) => Scheduler.AddOnce(showScores), true); } - private void showScores(IEnumerable scores) + private void showScores() { Clear(); + scoreBindables.Clear(); if (!scores.Any()) return; @@ -52,7 +59,12 @@ namespace osu.Game.Screens.Play.HUD { var score = Add(s.User, false); - score.TotalScore.Value = s.TotalScore; + var bindableTotal = scoreManager.GetBindableTotalScore(s); + + // Direct binding not possible due to differing types (see https://github.com/ppy/osu/issues/20298). + bindableTotal.BindValueChanged(total => score.TotalScore.Value = total.NewValue, true); + scoreBindables.Add(bindableTotal); + score.Accuracy.Value = s.Accuracy; score.Combo.Value = s.MaxCombo; } From fcf54f1bc80ce018e9247fe5ecd7835e6488fb6d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Sep 2022 14:18:12 +0900 Subject: [PATCH 1107/2686] Fix gameplay leaderboard not being sorted correctly in tie situations --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 6 +++++- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 1 + osu.Game/Screens/Play/HUD/ILeaderboardScore.cs | 6 ++++++ osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs | 4 ++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 8b37e0bacb..325253e9d4 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -88,6 +88,7 @@ namespace osu.Game.Screens.Play.HUD Flow.Add(drawable); drawable.TotalScore.BindValueChanged(_ => sorting.Invalidate(), true); + drawable.DisplayOrder.BindValueChanged(_ => sorting.Invalidate(), true); int displayCount = Math.Min(Flow.Count, max_panels); Height = displayCount * (GameplayLeaderboardScore.PANEL_HEIGHT + Flow.Spacing.Y); @@ -160,7 +161,10 @@ namespace osu.Game.Screens.Play.HUD if (sorting.IsValid) return; - var orderedByScore = Flow.OrderByDescending(i => i.TotalScore.Value).ToList(); + var orderedByScore = Flow + .OrderByDescending(i => i.TotalScore.Value) + .ThenBy(i => i.DisplayOrder.Value) + .ToList(); for (int i = 0; i < Flow.Count; i++) { diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 64a470311f..29354e610d 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -55,6 +55,7 @@ namespace osu.Game.Screens.Play.HUD public BindableDouble Accuracy { get; } = new BindableDouble(1); public BindableInt Combo { get; } = new BindableInt(); public BindableBool HasQuit { get; } = new BindableBool(); + public Bindable DisplayOrder { get; } = new Bindable(); public Color4? BackgroundColour { get; set; } diff --git a/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs b/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs index 20bf7045b8..aa06bb08a5 100644 --- a/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs @@ -14,5 +14,11 @@ namespace osu.Game.Screens.Play.HUD BindableInt Combo { get; } BindableBool HasQuit { get; } + + /// + /// An optional value to guarantee stable ordering. + /// Lower numbers will appear higher in cases of ties. + /// + Bindable DisplayOrder { get; } } } diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 2282277c3c..6141260beb 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -55,6 +55,9 @@ namespace osu.Game.Screens.Play.HUD local.Accuracy.BindTarget = scoreProcessor.Accuracy; local.Combo.BindTarget = scoreProcessor.Combo; + // Local score should always show lower than any existing scores in cases of ties. + local.DisplayOrder.Value = long.MaxValue; + foreach (var s in scores) { var score = Add(s.User, false); @@ -67,6 +70,7 @@ namespace osu.Game.Screens.Play.HUD score.Accuracy.Value = s.Accuracy; score.Combo.Value = s.MaxCombo; + score.DisplayOrder.Value = s.OnlineID > 0 ? s.OnlineID : s.Date.ToUnixTimeSeconds(); } } } From bc07513c3c19f4440676aff013b111eec321ad50 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Sep 2022 14:19:53 +0900 Subject: [PATCH 1108/2686] Fix local scores potentially not being stable-sorted for leaderboard display --- osu.Game/Scoring/ScoreManager.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 6bb31eb4db..8342d3bcc1 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -58,7 +58,10 @@ namespace osu.Game.Scoring /// The array of s to reorder. /// The given ordered by decreasing total score. public IEnumerable OrderByTotalScore(IEnumerable scores) - => scores.OrderByDescending(s => GetTotalScore(s)).ThenBy(s => s.OnlineID); + => scores.OrderByDescending(s => GetTotalScore(s)) + .ThenBy(s => s.OnlineID) + // Local scores may not have an online ID. Fall back to date in these cases. + .ThenBy(s => s.Date); /// /// Retrieves a bindable that represents the total score of a . From 30cf14e824bc0eeb9f01f0eeb63eb91462c7954e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 14 Sep 2022 14:40:45 +0900 Subject: [PATCH 1109/2686] Update ReSharper CLI to 2022.2.3 --- .config/dotnet-tools.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 57694d7f57..1f937e1837 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "jetbrains.resharper.globaltools": { - "version": "2022.1.1", + "version": "2022.2.3", "commands": [ "jb" ] From a9eba2712991229a99e1f1b80c85d92e720a8264 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 15 Jun 2021 19:41:37 +0900 Subject: [PATCH 1110/2686] Factor out pooling logic from `Playfield` --- .../Objects/Pooling/HitObjectEntryManager.cs | 69 +++++++++++++++++++ osu.Game/Rulesets/UI/Playfield.cs | 49 +++++++------ 2 files changed, 98 insertions(+), 20 deletions(-) create mode 100644 osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs new file mode 100644 index 0000000000..129c4cab44 --- /dev/null +++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.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. + +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace osu.Game.Rulesets.Objects.Pooling +{ + /// + /// Manages a mapping between and + /// + internal class HitObjectEntryManager + { + /// + /// All entries, including entries of the nested hit objects. + /// + public IEnumerable AllEntries => entryMap.Values; + + public event Action? OnEntryAdded; + public event Action? OnEntryRemoved; + + private readonly Func createLifetimeEntry; + + private readonly Dictionary entryMap = new Dictionary(); + private readonly Dictionary parentMap = new Dictionary(); + + public HitObjectEntryManager(Func createLifetimeEntry) + { + this.createLifetimeEntry = createLifetimeEntry; + } + + public HitObjectLifetimeEntry Add(HitObject hitObject, HitObject? parentHitObject) + { + if (parentHitObject != null && !entryMap.TryGetValue(parentHitObject, out var parentEntry)) + throw new InvalidOperationException($@"The parent {nameof(HitObject)} must be added to this {nameof(HitObjectEntryManager)} before nested {nameof(HitObject)} is added."); + + if (entryMap.ContainsKey(hitObject)) + throw new InvalidOperationException($@"The {nameof(HitObject)} is already added to this {nameof(HitObjectEntryManager)}."); + + if (parentHitObject != null) + parentMap[hitObject] = parentHitObject; + + var entry = createLifetimeEntry(hitObject); + entryMap[hitObject] = entry; + + OnEntryAdded?.Invoke(entry, parentHitObject); + return entry; + } + + public bool Remove(HitObject hitObject) + { + if (!entryMap.TryGetValue(hitObject, out var entry)) + return false; + + parentMap.Remove(hitObject, out var parentHitObject); + + OnEntryRemoved?.Invoke(entry, parentHitObject); + return true; + } + + public bool TryGet(HitObject hitObject, [MaybeNullWhen(false)] out HitObjectLifetimeEntry entry) + { + return entryMap.TryGetValue(hitObject, out entry); + } + } +} diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 60d1555052..5aaa7682db 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -21,6 +21,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Skinning; using osuTK; +using osu.Game.Rulesets.Objects.Pooling; namespace osu.Game.Rulesets.UI { @@ -94,6 +95,8 @@ namespace osu.Game.Rulesets.UI [Resolved(CanBeNull = true)] private IReadOnlyList mods { get; set; } + private readonly HitObjectEntryManager entryManager; + /// /// Creates a new . /// @@ -108,6 +111,10 @@ namespace osu.Game.Rulesets.UI h.HitObjectUsageBegan += o => HitObjectUsageBegan?.Invoke(o); h.HitObjectUsageFinished += o => HitObjectUsageFinished?.Invoke(o); })); + + entryManager = new HitObjectEntryManager(CreateLifetimeEntry); + entryManager.OnEntryAdded += onEntryAdded; + entryManager.OnEntryRemoved += onEntryRemoved; } [BackgroundDependencyLoader] @@ -171,6 +178,7 @@ namespace osu.Game.Rulesets.UI /// The added . protected virtual void OnHitObjectAdded(HitObject hitObject) { + preloadSamples(hitObject); } /// @@ -263,13 +271,7 @@ namespace osu.Game.Rulesets.UI /// public virtual void Add(HitObject hitObject) { - var entry = CreateLifetimeEntry(hitObject); - lifetimeEntryMap[entry.HitObject] = entry; - - preloadSamples(hitObject); - - HitObjectContainer.Add(entry); - OnHitObjectAdded(entry.HitObject); + entryManager.Add(hitObject, null); } private void preloadSamples(HitObject hitObject) @@ -292,14 +294,23 @@ namespace osu.Game.Rulesets.UI /// Whether the was successfully removed. public virtual bool Remove(HitObject hitObject) { - if (lifetimeEntryMap.Remove(hitObject, out var entry)) - { - HitObjectContainer.Remove(entry); - OnHitObjectRemoved(hitObject); - return true; - } + return entryManager.Remove(hitObject) || nestedPlayfields.Any(p => p.Remove(hitObject)); + } - return nestedPlayfields.Any(p => p.Remove(hitObject)); + private void onEntryAdded(HitObjectLifetimeEntry entry, [CanBeNull] HitObject parentHitObject) + { + if (parentHitObject != null) return; + + HitObjectContainer.Add(entry); + OnHitObjectAdded(entry.HitObject); + } + + private void onEntryRemoved(HitObjectLifetimeEntry entry, [CanBeNull] HitObject parentHitObject) + { + if (parentHitObject != null) return; + + HitObjectContainer.Remove(entry); + OnHitObjectRemoved(entry.HitObject); } /// @@ -366,8 +377,8 @@ namespace osu.Game.Rulesets.UI } } - if (!lifetimeEntryMap.TryGetValue(hitObject, out var entry)) - lifetimeEntryMap[hitObject] = entry = CreateLifetimeEntry(hitObject); + if (!entryManager.TryGet(hitObject, out var entry)) + entry = entryManager.Add(hitObject, parent?.HitObject); dho.ParentHitObject = parent; dho.Apply(entry); @@ -442,8 +453,6 @@ namespace osu.Game.Rulesets.UI /// internal event Action HitObjectUsageFinished; - private readonly Dictionary lifetimeEntryMap = new Dictionary(); - /// /// Sets whether to keep a given always alive within this or any nested . /// @@ -451,7 +460,7 @@ namespace osu.Game.Rulesets.UI /// Whether to keep always alive. internal void SetKeepAlive(HitObject hitObject, bool keepAlive) { - if (lifetimeEntryMap.TryGetValue(hitObject, out var entry)) + if (entryManager.TryGet(hitObject, out var entry)) { entry.KeepAlive = keepAlive; return; @@ -466,7 +475,7 @@ namespace osu.Game.Rulesets.UI /// internal void KeepAllAlive() { - foreach (var (_, entry) in lifetimeEntryMap) + foreach (var entry in entryManager.AllEntries) entry.KeepAlive = true; foreach (var p in nestedPlayfields) From bde390828b017f3d62698f263ec14a962d05ad19 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 15 Jun 2021 20:48:00 +0900 Subject: [PATCH 1111/2686] Manage entries of nested hit objects in `HitObjectEntryManager` - Fix nested hit objects are leaked when parent hit object is edited or deleted --- .../Objects/Pooling/HitObjectEntryManager.cs | 54 ++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs index 129c4cab44..f14f8b6f61 100644 --- a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs +++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs @@ -25,39 +25,54 @@ namespace osu.Game.Rulesets.Objects.Pooling private readonly Func createLifetimeEntry; private readonly Dictionary entryMap = new Dictionary(); - private readonly Dictionary parentMap = new Dictionary(); + private readonly Dictionary parentMap = new Dictionary(); + private readonly Dictionary> childrenMap = new Dictionary>(); public HitObjectEntryManager(Func createLifetimeEntry) { this.createLifetimeEntry = createLifetimeEntry; } - public HitObjectLifetimeEntry Add(HitObject hitObject, HitObject? parentHitObject) + public HitObjectLifetimeEntry Add(HitObject hitObject, HitObject? parent) { - if (parentHitObject != null && !entryMap.TryGetValue(parentHitObject, out var parentEntry)) - throw new InvalidOperationException($@"The parent {nameof(HitObject)} must be added to this {nameof(HitObjectEntryManager)} before nested {nameof(HitObject)} is added."); - if (entryMap.ContainsKey(hitObject)) throw new InvalidOperationException($@"The {nameof(HitObject)} is already added to this {nameof(HitObjectEntryManager)}."); - if (parentHitObject != null) - parentMap[hitObject] = parentHitObject; - var entry = createLifetimeEntry(hitObject); entryMap[hitObject] = entry; + parentMap[entry] = parent; - OnEntryAdded?.Invoke(entry, parentHitObject); + if (parent != null && childrenMap.TryGetValue(parent, out var parentChildEntries)) + parentChildEntries.Add(entry); + + hitObject.DefaultsApplied += onDefaultsApplied; + + childrenMap[entry.HitObject] = new List(); + + OnEntryAdded?.Invoke(entry, parent); return entry; } public bool Remove(HitObject hitObject) { - if (!entryMap.TryGetValue(hitObject, out var entry)) + if (!entryMap.Remove(hitObject, out var entry)) return false; - parentMap.Remove(hitObject, out var parentHitObject); + parentMap.Remove(entry, out var parent); - OnEntryRemoved?.Invoke(entry, parentHitObject); + if (parent != null && childrenMap.TryGetValue(parent, out var parentChildEntries)) + parentChildEntries.Remove(entry); + + hitObject.DefaultsApplied -= onDefaultsApplied; + + // Remove all entries of the nested hit objects + if (childrenMap.Remove(entry.HitObject, out var childEntries)) + { + foreach (var childEntry in childEntries) + Remove(childEntry.HitObject); + } + + OnEntryRemoved?.Invoke(entry, parent); return true; } @@ -65,5 +80,20 @@ namespace osu.Game.Rulesets.Objects.Pooling { return entryMap.TryGetValue(hitObject, out entry); } + + /// + /// As nested hit objects are recreated, remove entries of the old nested hit objects. + /// + private void onDefaultsApplied(HitObject hitObject) + { + if (!childrenMap.Remove(hitObject, out var childEntries)) + return; + + foreach (var entry in childEntries) + Remove(entry.HitObject); + + childEntries.Clear(); + childrenMap[hitObject] = childEntries; + } } } From 47539e2129d85e50866e659e850d8bc769927057 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 16 Jun 2021 15:09:01 +0900 Subject: [PATCH 1112/2686] Add doc comments to `HitObjectEntryManager` --- .../Objects/Pooling/HitObjectEntryManager.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs index f14f8b6f61..71c0a88616 100644 --- a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs +++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs @@ -19,13 +19,38 @@ namespace osu.Game.Rulesets.Objects.Pooling /// public IEnumerable AllEntries => entryMap.Values; + /// + /// Invoked when a new is added to this .. + /// The second parameter of the event is the parent hit object. + /// public event Action? OnEntryAdded; + + /// + /// Invoked when a is removed from this . + /// The second parameter of the event is the parent hit object. + /// public event Action? OnEntryRemoved; private readonly Func createLifetimeEntry; + /// + /// Provides the reverse mapping of for each entry. + /// private readonly Dictionary entryMap = new Dictionary(); + + /// + /// Stores the parent hit object for entries of the nested hit objects. + /// A null is stored for entries of the top-level hit objects. + /// + /// + /// The parent hit object of a pooled hit object may be non-pooled. + /// In that case, no corresponding is stored in this . + /// private readonly Dictionary parentMap = new Dictionary(); + + /// + /// Stores the list of entries managed by this for each hit object managed by this . + /// private readonly Dictionary> childrenMap = new Dictionary>(); public HitObjectEntryManager(Func createLifetimeEntry) From c59aa574509d153883fc6dd6f4627058a7089e27 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 16 Jun 2021 15:15:33 +0900 Subject: [PATCH 1113/2686] Remove `createLifetimeEntry` from `HitObjectEntryManager` --- .../Objects/Pooling/HitObjectEntryManager.cs | 33 ++++++++----------- osu.Game/Rulesets/UI/Playfield.cs | 19 ++++++++--- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs index 71c0a88616..d8dd6fab7e 100644 --- a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs +++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs @@ -31,8 +31,6 @@ namespace osu.Game.Rulesets.Objects.Pooling /// public event Action? OnEntryRemoved; - private readonly Func createLifetimeEntry; - /// /// Provides the reverse mapping of for each entry. /// @@ -53,37 +51,33 @@ namespace osu.Game.Rulesets.Objects.Pooling /// private readonly Dictionary> childrenMap = new Dictionary>(); - public HitObjectEntryManager(Func createLifetimeEntry) + public void Add(HitObjectLifetimeEntry entry, HitObject? parent) { - this.createLifetimeEntry = createLifetimeEntry; - } + if (parentMap.ContainsKey(entry)) + throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is already added to this {nameof(HitObjectEntryManager)}."); - public HitObjectLifetimeEntry Add(HitObject hitObject, HitObject? parent) - { - if (entryMap.ContainsKey(hitObject)) - throw new InvalidOperationException($@"The {nameof(HitObject)} is already added to this {nameof(HitObjectEntryManager)}."); - - var entry = createLifetimeEntry(hitObject); - entryMap[hitObject] = entry; + var hitObject = entry.HitObject; parentMap[entry] = parent; + entryMap[hitObject] = entry; if (parent != null && childrenMap.TryGetValue(parent, out var parentChildEntries)) parentChildEntries.Add(entry); hitObject.DefaultsApplied += onDefaultsApplied; - childrenMap[entry.HitObject] = new List(); + childrenMap[hitObject] = new List(); OnEntryAdded?.Invoke(entry, parent); - return entry; } - public bool Remove(HitObject hitObject) + public void Remove(HitObjectLifetimeEntry entry) { - if (!entryMap.Remove(hitObject, out var entry)) - return false; + if (!parentMap.ContainsKey(entry)) + throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is not contained in this {nameof(HitObjectLifetimeEntry)}."); + var hitObject = entry.HitObject; parentMap.Remove(entry, out var parent); + entryMap.Remove(hitObject); if (parent != null && childrenMap.TryGetValue(parent, out var parentChildEntries)) parentChildEntries.Remove(entry); @@ -94,11 +88,10 @@ namespace osu.Game.Rulesets.Objects.Pooling if (childrenMap.Remove(entry.HitObject, out var childEntries)) { foreach (var childEntry in childEntries) - Remove(childEntry.HitObject); + Remove(childEntry); } OnEntryRemoved?.Invoke(entry, parent); - return true; } public bool TryGet(HitObject hitObject, [MaybeNullWhen(false)] out HitObjectLifetimeEntry entry) @@ -115,7 +108,7 @@ namespace osu.Game.Rulesets.Objects.Pooling return; foreach (var entry in childEntries) - Remove(entry.HitObject); + Remove(entry); childEntries.Clear(); childrenMap[hitObject] = childEntries; diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 5aaa7682db..2ec72d8fe3 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.UI [Resolved(CanBeNull = true)] private IReadOnlyList mods { get; set; } - private readonly HitObjectEntryManager entryManager; + private readonly HitObjectEntryManager entryManager = new HitObjectEntryManager(); /// /// Creates a new . @@ -112,7 +112,6 @@ namespace osu.Game.Rulesets.UI h.HitObjectUsageFinished += o => HitObjectUsageFinished?.Invoke(o); })); - entryManager = new HitObjectEntryManager(CreateLifetimeEntry); entryManager.OnEntryAdded += onEntryAdded; entryManager.OnEntryRemoved += onEntryRemoved; } @@ -271,7 +270,8 @@ namespace osu.Game.Rulesets.UI /// public virtual void Add(HitObject hitObject) { - entryManager.Add(hitObject, null); + var entry = CreateLifetimeEntry(hitObject); + entryManager.Add(entry, null); } private void preloadSamples(HitObject hitObject) @@ -294,7 +294,13 @@ namespace osu.Game.Rulesets.UI /// Whether the was successfully removed. public virtual bool Remove(HitObject hitObject) { - return entryManager.Remove(hitObject) || nestedPlayfields.Any(p => p.Remove(hitObject)); + if (entryManager.TryGet(hitObject, out var entry)) + { + entryManager.Remove(entry); + return true; + } + + return nestedPlayfields.Any(p => p.Remove(hitObject)); } private void onEntryAdded(HitObjectLifetimeEntry entry, [CanBeNull] HitObject parentHitObject) @@ -378,7 +384,10 @@ namespace osu.Game.Rulesets.UI } if (!entryManager.TryGet(hitObject, out var entry)) - entry = entryManager.Add(hitObject, parent?.HitObject); + { + entry = CreateLifetimeEntry(hitObject); + entryManager.Add(entry, parent?.HitObject); + } dho.ParentHitObject = parent; dho.Apply(entry); From 5dc0d32e4207199f93c0d2f054f3d145952ab066 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Sep 2022 15:24:20 +0900 Subject: [PATCH 1114/2686] Apply NRT to hitobject lifetime related classes --- osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs | 4 +--- osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs index 9af4cf3544..fedf419973 100644 --- a/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.cs +++ b/osu.Game/Rulesets/Objects/HitObjectLifetimeEntry.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. -#nullable disable - using osu.Framework.Bindables; using osu.Framework.Graphics.Performance; using osu.Game.Rulesets.Judgements; @@ -24,7 +22,7 @@ namespace osu.Game.Rulesets.Objects /// The result that was judged with. /// This is set by the accompanying , and reused when required for rewinding. /// - internal JudgementResult Result; + internal JudgementResult? Result; private readonly IBindable startTimeBindable = new BindableDouble(); diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs index d8dd6fab7e..30a8e8f549 100644 --- a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs +++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.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. -#nullable enable - using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; From 1801ae3c6a16b20fd4ec7ad7e7741919566c083c Mon Sep 17 00:00:00 2001 From: StanR Date: Wed, 14 Sep 2022 17:40:22 +0300 Subject: [PATCH 1115/2686] Move flashlight TD difficulty reduction to diffcalc --- .../Difficulty/OsuDifficultyCalculator.cs | 3 +++ .../Difficulty/OsuPerformanceCalculator.cs | 7 +------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 295fefffa3..fd4a21bb76 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -46,7 +46,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; if (mods.Any(m => m is OsuModTouchDevice)) + { aimRating = Math.Pow(aimRating, 0.8); + flashlightRating = Math.Pow(flashlightRating, 0.8); + } if (mods.Any(h => h is OsuModRelax)) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 2b0e2db898..30b56ff769 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -228,12 +228,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (!score.Mods.Any(h => h is OsuModFlashlight)) return 0.0; - double rawFlashlight = attributes.FlashlightDifficulty; - - if (score.Mods.Any(m => m is OsuModTouchDevice)) - rawFlashlight = Math.Pow(rawFlashlight, 0.8); - - double flashlightValue = Math.Pow(rawFlashlight, 2.0) * 25.0; + double flashlightValue = Math.Pow(attributes.FlashlightDifficulty, 2.0) * 25.0; // Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses. if (effectiveMissCount > 0) From 87384db8729401b7b6824880cd5cc95eeefa9126 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 00:51:02 +0900 Subject: [PATCH 1116/2686] Fix slider rotation causing thousands of new drawables to be created --- .../Sliders/Components/PathControlPointPiece.cs | 7 +++++-- osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs | 9 ++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index ab4b492767..59edbe8dc6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -66,11 +66,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components cachePoints(slider); sliderVersion = slider.Path.Version.GetBoundCopy(); - sliderVersion.BindValueChanged(_ => + + // schedule ensure that updates are only applied after all operations from a single frame are applied. + // this avoids inadvertently changing the slider path type for bach operations. + sliderVersion.BindValueChanged(_ => Scheduler.AddOnce(() => { cachePoints(slider); updatePathType(); - }); + })); controlPoint.Changed += updateMarkerDisplay; diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 57d67acad5..280a35500a 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -186,13 +186,8 @@ namespace osu.Game.Rulesets.Osu.Edit if (h is IHasPath path) { - var controlPoints = path.Path.ControlPoints.Select(p => - new PathControlPoint(RotatePointAroundOrigin(p.Position, Vector2.Zero, delta), p.Type)).ToArray(); - - // Importantly, update as a single operation so automatic adjustment of control points to different - // curve types does not unexpectedly trigger and change the slider's shape. - path.Path.ControlPoints.Clear(); - path.Path.ControlPoints.AddRange(controlPoints); + foreach (PathControlPoint t in path.Path.ControlPoints) + t.Position = RotatePointAroundOrigin(t.Position, Vector2.Zero, delta); } } From d6db82283a806ab62114ee3c830cd15152a5a1ef Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Wed, 14 Sep 2022 18:01:29 +0200 Subject: [PATCH 1117/2686] Removes unused class --- osu.Game/Screens/Play/KeyCounterState.cs | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 osu.Game/Screens/Play/KeyCounterState.cs diff --git a/osu.Game/Screens/Play/KeyCounterState.cs b/osu.Game/Screens/Play/KeyCounterState.cs deleted file mode 100644 index 45d027e5ec..0000000000 --- a/osu.Game/Screens/Play/KeyCounterState.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -namespace osu.Game.Screens.Play -{ - public class KeyCounterState - { - public KeyCounterState(double time, int count) - { - Time = time; - Count = count; - } - - public readonly double Time; - public readonly int Count; - } -} From c203a030c1bdec9b40168b1ca8844c802436b4d8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 04:28:07 +0900 Subject: [PATCH 1118/2686] Update osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs Co-authored-by: apollo <83023433+apollo-dw@users.noreply.github.com> --- .../Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index 59edbe8dc6..5dec5d1cb0 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components sliderVersion = slider.Path.Version.GetBoundCopy(); // schedule ensure that updates are only applied after all operations from a single frame are applied. - // this avoids inadvertently changing the slider path type for bach operations. + // this avoids inadvertently changing the slider path type for batch operations. sliderVersion.BindValueChanged(_ => Scheduler.AddOnce(() => { cachePoints(slider); From de7dd29d791304fe588ae1f297ecff8e128168c4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 15 Sep 2022 03:57:05 +0300 Subject: [PATCH 1119/2686] Add "Nominations" and "Updated" sorting criteria in beatmap listing --- osu.Game/Overlays/BeatmapListing/SortCriteria.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapListing/SortCriteria.cs b/osu.Game/Overlays/BeatmapListing/SortCriteria.cs index ff6e62b274..6c010c7504 100644 --- a/osu.Game/Overlays/BeatmapListing/SortCriteria.cs +++ b/osu.Game/Overlays/BeatmapListing/SortCriteria.cs @@ -19,6 +19,9 @@ namespace osu.Game.Overlays.BeatmapListing [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingDifficulty))] Difficulty, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingUpdated))] + Updated, + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingRanked))] Ranked, @@ -32,6 +35,9 @@ namespace osu.Game.Overlays.BeatmapListing Favourites, [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingRelevance))] - Relevance + Relevance, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.ListingSearchSortingNominations))] + Nominations, } } From efebe55d228f9a669bc500a822bf211ca34e6ba3 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 15 Sep 2022 03:58:32 +0300 Subject: [PATCH 1120/2686] Display certain sort criterias based on selected category and query --- .../BeatmapListingFilterControl.cs | 21 ++++---- .../BeatmapListingSortTabControl.cs | 53 +++++++++++++++++-- osu.Game/Overlays/OverlaySortTabControl.cs | 4 +- 3 files changed, 65 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index 2ca369d459..ff9a46ed4f 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -151,19 +151,20 @@ namespace osu.Game.Overlays.BeatmapListing config.BindWith(OsuSetting.BeatmapListingCardSize, cardSize); - var sortCriteria = sortControl.Current; - var sortDirection = sortControl.SortDirection; - - searchControl.Query.BindValueChanged(query => + searchControl.Query.BindValueChanged(_ => { - sortCriteria.Value = string.IsNullOrEmpty(query.NewValue) ? SortCriteria.Ranked : SortCriteria.Relevance; - sortDirection.Value = SortDirection.Descending; + resetSortControl(); queueUpdateSearch(true); }); + searchControl.Category.BindValueChanged(_ => + { + resetSortControl(); + queueUpdateSearch(); + }); + searchControl.General.CollectionChanged += (_, _) => queueUpdateSearch(); searchControl.Ruleset.BindValueChanged(_ => queueUpdateSearch()); - searchControl.Category.BindValueChanged(_ => queueUpdateSearch()); searchControl.Genre.BindValueChanged(_ => queueUpdateSearch()); searchControl.Language.BindValueChanged(_ => queueUpdateSearch()); searchControl.Extra.CollectionChanged += (_, _) => queueUpdateSearch(); @@ -171,8 +172,8 @@ namespace osu.Game.Overlays.BeatmapListing searchControl.Played.BindValueChanged(_ => queueUpdateSearch()); searchControl.ExplicitContent.BindValueChanged(_ => queueUpdateSearch()); - sortCriteria.BindValueChanged(_ => queueUpdateSearch()); - sortDirection.BindValueChanged(_ => queueUpdateSearch()); + sortControl.Current.BindValueChanged(_ => queueUpdateSearch()); + sortControl.SortDirection.BindValueChanged(_ => queueUpdateSearch()); apiUser = api.LocalUser.GetBoundCopy(); apiUser.BindValueChanged(_ => queueUpdateSearch()); @@ -199,6 +200,8 @@ namespace osu.Game.Overlays.BeatmapListing performRequest(); } + private void resetSortControl() => sortControl.Reset(searchControl.Category.Value, !string.IsNullOrEmpty(searchControl.Query.Value)); + private void queueUpdateSearch(bool queryTextChanged = false) { SearchStarted?.Invoke(); diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs index 454f381c60..bc1f30dcaf 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs @@ -17,18 +17,65 @@ namespace osu.Game.Overlays.BeatmapListing { public readonly Bindable SortDirection = new Bindable(Overlays.SortDirection.Descending); - public BeatmapListingSortTabControl() + private SearchCategory? lastCategory; + private bool? lastHasQuery; + + protected override void LoadComplete() { - Current.Value = SortCriteria.Ranked; + base.LoadComplete(); + Reset(SearchCategory.Leaderboard, false); + } + + public void Reset(SearchCategory category, bool hasQuery) + { + if (category != lastCategory || hasQuery != lastHasQuery) + { + TabControl.Clear(); + + TabControl.AddItem(SortCriteria.Title); + TabControl.AddItem(SortCriteria.Artist); + TabControl.AddItem(SortCriteria.Difficulty); + + if (category == SearchCategory.Any || category > SearchCategory.Loved) + TabControl.AddItem(SortCriteria.Updated); + + if (category < SearchCategory.Pending || category == SearchCategory.Mine) + TabControl.AddItem(SortCriteria.Ranked); + + TabControl.AddItem(SortCriteria.Rating); + TabControl.AddItem(SortCriteria.Plays); + TabControl.AddItem(SortCriteria.Favourites); + + if (hasQuery) + TabControl.AddItem(SortCriteria.Relevance); + + if (category == SearchCategory.Pending) + TabControl.AddItem(SortCriteria.Nominations); + } + + var nonQueryCriteria = category >= SearchCategory.Pending ? SortCriteria.Updated : SortCriteria.Ranked; + + Current.Value = hasQuery ? SortCriteria.Relevance : nonQueryCriteria; + SortDirection.Value = Overlays.SortDirection.Descending; + + // if the new criteria isn't different from the previous one, + // then re-adding tab items will not mark the current tab as selected. + // see: https://github.com/ppy/osu-framework/issues/5412 + TabControl.Current.TriggerChange(); + + lastCategory = category; + lastHasQuery = hasQuery; } protected override SortTabControl CreateControl() => new BeatmapSortTabControl { - SortDirection = { BindTarget = SortDirection } + SortDirection = { BindTarget = SortDirection }, }; private class BeatmapSortTabControl : SortTabControl { + protected override bool AddEnumEntriesAutomatically => false; + public readonly Bindable SortDirection = new Bindable(); protected override TabItem CreateTabItem(SortCriteria value) => new BeatmapSortTabItem(value) diff --git a/osu.Game/Overlays/OverlaySortTabControl.cs b/osu.Game/Overlays/OverlaySortTabControl.cs index f02d2b388f..befb011353 100644 --- a/osu.Game/Overlays/OverlaySortTabControl.cs +++ b/osu.Game/Overlays/OverlaySortTabControl.cs @@ -26,6 +26,8 @@ namespace osu.Game.Overlays { public class OverlaySortTabControl : CompositeDrawable, IHasCurrentValue { + public TabControl TabControl { get; } + private readonly BindableWithCurrent current = new BindableWithCurrent(); public Bindable Current @@ -59,7 +61,7 @@ namespace osu.Game.Overlays Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold), Text = SortStrings.Default }, - CreateControl().With(c => + TabControl = CreateControl().With(c => { c.Anchor = Anchor.CentreLeft; c.Origin = Anchor.CentreLeft; From 9824d09d490341424a52cfa54cb594036710de82 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 15 Sep 2022 03:58:42 +0300 Subject: [PATCH 1121/2686] Add test coverage --- .../TestSceneBeatmapListingSortTabControl.cs | 85 ++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSortTabControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSortTabControl.cs index 3247461fba..0ef13385ec 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSortTabControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSortTabControl.cs @@ -3,9 +3,13 @@ #nullable disable +using System.Linq; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Testing; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; using osu.Game.Overlays.BeatmapListing; @@ -15,12 +19,13 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneBeatmapListingSortTabControl : OsuTestScene { + private readonly BeatmapListingSortTabControl control; + [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); public TestSceneBeatmapListingSortTabControl() { - BeatmapListingSortTabControl control; OsuSpriteText current; OsuSpriteText direction; @@ -45,5 +50,83 @@ namespace osu.Game.Tests.Visual.UserInterface control.SortDirection.BindValueChanged(sortDirection => direction.Text = $"Sort direction: {sortDirection.NewValue}", true); control.Current.BindValueChanged(criteria => current.Text = $"Criteria: {criteria.NewValue}", true); } + + [Test] + public void TestRankedSort() + { + criteriaShowsOnCategory(true, SortCriteria.Ranked, SearchCategory.Any); + criteriaShowsOnCategory(true, SortCriteria.Ranked, SearchCategory.Leaderboard); + criteriaShowsOnCategory(true, SortCriteria.Ranked, SearchCategory.Ranked); + criteriaShowsOnCategory(true, SortCriteria.Ranked, SearchCategory.Qualified); + criteriaShowsOnCategory(true, SortCriteria.Ranked, SearchCategory.Loved); + criteriaShowsOnCategory(true, SortCriteria.Ranked, SearchCategory.Favourites); + criteriaShowsOnCategory(false, SortCriteria.Ranked, SearchCategory.Pending); + criteriaShowsOnCategory(false, SortCriteria.Ranked, SearchCategory.Wip); + criteriaShowsOnCategory(false, SortCriteria.Ranked, SearchCategory.Graveyard); + criteriaShowsOnCategory(true, SortCriteria.Ranked, SearchCategory.Mine); + } + + [Test] + public void TestUpdatedSort() + { + criteriaShowsOnCategory(true, SortCriteria.Updated, SearchCategory.Any); + criteriaShowsOnCategory(false, SortCriteria.Updated, SearchCategory.Leaderboard); + criteriaShowsOnCategory(false, SortCriteria.Updated, SearchCategory.Ranked); + criteriaShowsOnCategory(false, SortCriteria.Updated, SearchCategory.Qualified); + criteriaShowsOnCategory(false, SortCriteria.Updated, SearchCategory.Loved); + criteriaShowsOnCategory(true, SortCriteria.Updated, SearchCategory.Favourites); + criteriaShowsOnCategory(true, SortCriteria.Updated, SearchCategory.Pending); + criteriaShowsOnCategory(true, SortCriteria.Updated, SearchCategory.Wip); + criteriaShowsOnCategory(true, SortCriteria.Updated, SearchCategory.Graveyard); + criteriaShowsOnCategory(true, SortCriteria.Updated, SearchCategory.Mine); + } + + [Test] + public void TestNominationsSort() + { + criteriaShowsOnCategory(false, SortCriteria.Nominations, SearchCategory.Any); + criteriaShowsOnCategory(false, SortCriteria.Nominations, SearchCategory.Leaderboard); + criteriaShowsOnCategory(false, SortCriteria.Nominations, SearchCategory.Ranked); + criteriaShowsOnCategory(false, SortCriteria.Nominations, SearchCategory.Qualified); + criteriaShowsOnCategory(false, SortCriteria.Nominations, SearchCategory.Loved); + criteriaShowsOnCategory(false, SortCriteria.Nominations, SearchCategory.Favourites); + criteriaShowsOnCategory(true, SortCriteria.Nominations, SearchCategory.Pending); + criteriaShowsOnCategory(false, SortCriteria.Nominations, SearchCategory.Wip); + criteriaShowsOnCategory(false, SortCriteria.Nominations, SearchCategory.Graveyard); + criteriaShowsOnCategory(false, SortCriteria.Nominations, SearchCategory.Mine); + } + + [Test] + public void TestResetNoQuery() + { + resetUsesCriteriaOnCategory(SortCriteria.Ranked, SearchCategory.Any); + resetUsesCriteriaOnCategory(SortCriteria.Ranked, SearchCategory.Leaderboard); + resetUsesCriteriaOnCategory(SortCriteria.Ranked, SearchCategory.Ranked); + resetUsesCriteriaOnCategory(SortCriteria.Ranked, SearchCategory.Qualified); + resetUsesCriteriaOnCategory(SortCriteria.Ranked, SearchCategory.Loved); + resetUsesCriteriaOnCategory(SortCriteria.Ranked, SearchCategory.Favourites); + resetUsesCriteriaOnCategory(SortCriteria.Updated, SearchCategory.Pending); + resetUsesCriteriaOnCategory(SortCriteria.Updated, SearchCategory.Wip); + resetUsesCriteriaOnCategory(SortCriteria.Updated, SearchCategory.Graveyard); + resetUsesCriteriaOnCategory(SortCriteria.Updated, SearchCategory.Mine); + } + + private void criteriaShowsOnCategory(bool expected, SortCriteria criteria, SearchCategory category) + { + AddAssert($"{criteria.ToString().ToLowerInvariant()} {(expected ? "shown" : "not shown")} on {category.ToString().ToLowerInvariant()}", () => + { + control.Reset(category, false); + return control.ChildrenOfType>().Single().Items.Contains(criteria) == expected; + }); + } + + private void resetUsesCriteriaOnCategory(SortCriteria criteria, SearchCategory category) + { + AddAssert($"reset uses {criteria.ToString().ToLowerInvariant()} on {category.ToString().ToLowerInvariant()}", () => + { + control.Reset(category, false); + return control.Current.Value == criteria; + }); + } } } From 31bc067dd1f9a194729580875ef0a82f191988fb Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 15 Sep 2022 15:38:44 +0900 Subject: [PATCH 1122/2686] Don't store nulls to parentMap --- .../Objects/Pooling/HitObjectEntryManager.cs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs index 30a8e8f549..66aa2cfaf7 100644 --- a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs +++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs @@ -36,13 +36,12 @@ namespace osu.Game.Rulesets.Objects.Pooling /// /// Stores the parent hit object for entries of the nested hit objects. - /// A null is stored for entries of the top-level hit objects. /// /// /// The parent hit object of a pooled hit object may be non-pooled. /// In that case, no corresponding is stored in this . /// - private readonly Dictionary parentMap = new Dictionary(); + private readonly Dictionary parentMap = new Dictionary(); /// /// Stores the list of entries managed by this for each hit object managed by this . @@ -55,16 +54,17 @@ namespace osu.Game.Rulesets.Objects.Pooling throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is already added to this {nameof(HitObjectEntryManager)}."); var hitObject = entry.HitObject; - parentMap[entry] = parent; entryMap[hitObject] = entry; - - if (parent != null && childrenMap.TryGetValue(parent, out var parentChildEntries)) - parentChildEntries.Add(entry); - - hitObject.DefaultsApplied += onDefaultsApplied; - childrenMap[hitObject] = new List(); + if (parent != null) + { + parentMap[entry] = parent; + if (childrenMap.TryGetValue(parent, out var parentChildEntries)) + parentChildEntries.Add(entry); + } + + hitObject.DefaultsApplied += onDefaultsApplied; OnEntryAdded?.Invoke(entry, parent); } @@ -74,14 +74,11 @@ namespace osu.Game.Rulesets.Objects.Pooling throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is not contained in this {nameof(HitObjectLifetimeEntry)}."); var hitObject = entry.HitObject; - parentMap.Remove(entry, out var parent); entryMap.Remove(hitObject); - if (parent != null && childrenMap.TryGetValue(parent, out var parentChildEntries)) + if (parentMap.Remove(entry, out var parent) && childrenMap.TryGetValue(parent, out var parentChildEntries)) parentChildEntries.Remove(entry); - hitObject.DefaultsApplied -= onDefaultsApplied; - // Remove all entries of the nested hit objects if (childrenMap.Remove(entry.HitObject, out var childEntries)) { @@ -89,6 +86,7 @@ namespace osu.Game.Rulesets.Objects.Pooling Remove(childEntry); } + hitObject.DefaultsApplied -= onDefaultsApplied; OnEntryRemoved?.Invoke(entry, parent); } From 68e4d2289814dedf98fbe48dfe7116c3a30c9df6 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 15 Sep 2022 15:40:03 +0900 Subject: [PATCH 1123/2686] Precondition against entryMap intead of parentMap --- .../Objects/Pooling/HitObjectEntryManager.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs index 66aa2cfaf7..11caf79d8b 100644 --- a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs +++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs @@ -50,10 +50,11 @@ namespace osu.Game.Rulesets.Objects.Pooling public void Add(HitObjectLifetimeEntry entry, HitObject? parent) { - if (parentMap.ContainsKey(entry)) + HitObject hitObject = entry.HitObject; + + if (entryMap.ContainsKey(hitObject)) throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is already added to this {nameof(HitObjectEntryManager)}."); - var hitObject = entry.HitObject; entryMap[hitObject] = entry; childrenMap[hitObject] = new List(); @@ -70,17 +71,18 @@ namespace osu.Game.Rulesets.Objects.Pooling public void Remove(HitObjectLifetimeEntry entry) { - if (!parentMap.ContainsKey(entry)) + HitObject hitObject = entry.HitObject; + + if (!entryMap.ContainsKey(hitObject)) throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is not contained in this {nameof(HitObjectLifetimeEntry)}."); - var hitObject = entry.HitObject; entryMap.Remove(hitObject); if (parentMap.Remove(entry, out var parent) && childrenMap.TryGetValue(parent, out var parentChildEntries)) parentChildEntries.Remove(entry); // Remove all entries of the nested hit objects - if (childrenMap.Remove(entry.HitObject, out var childEntries)) + if (childrenMap.Remove(hitObject, out var childEntries)) { foreach (var childEntry in childEntries) Remove(childEntry); From c847cc521e34022b9146aa45b96aa069cd2715a1 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 15 Sep 2022 16:00:35 +0900 Subject: [PATCH 1124/2686] Add some inline comments --- .../Rulesets/Objects/Pooling/HitObjectEntryManager.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs index 11caf79d8b..0b30ec09f9 100644 --- a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs +++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs @@ -55,9 +55,11 @@ namespace osu.Game.Rulesets.Objects.Pooling if (entryMap.ContainsKey(hitObject)) throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is already added to this {nameof(HitObjectEntryManager)}."); + // Add the entry. entryMap[hitObject] = entry; childrenMap[hitObject] = new List(); + // If the entry has a parent, set it and add the entry to the parent's children. if (parent != null) { parentMap[entry] = parent; @@ -74,14 +76,15 @@ namespace osu.Game.Rulesets.Objects.Pooling HitObject hitObject = entry.HitObject; if (!entryMap.ContainsKey(hitObject)) - throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is not contained in this {nameof(HitObjectLifetimeEntry)}."); + throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is not contained in this {nameof(HitObjectEntryManager)}."); entryMap.Remove(hitObject); + // If the entry has a parent, unset it and remove the entry from the parents' children. if (parentMap.Remove(entry, out var parent) && childrenMap.TryGetValue(parent, out var parentChildEntries)) parentChildEntries.Remove(entry); - // Remove all entries of the nested hit objects + // Remove all the entries' children. if (childrenMap.Remove(hitObject, out var childEntries)) { foreach (var childEntry in childEntries) @@ -105,9 +108,11 @@ namespace osu.Game.Rulesets.Objects.Pooling if (!childrenMap.Remove(hitObject, out var childEntries)) return; + // Remove all the entries' children. At this point the parents' (this entries') children list has been removed from the map, so this does not cause upwards traversal. foreach (var entry in childEntries) Remove(entry); + // The removed children list needs to be added back to the map for the entry to potentially receive children. childEntries.Clear(); childrenMap[hitObject] = childEntries; } From e56ea58e71ca78b6f284e37e0c68def4a5889eb5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 15 Sep 2022 16:06:21 +0900 Subject: [PATCH 1125/2686] Fix up xmldoc --- osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs index 0b30ec09f9..6c39ea44da 100644 --- a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs +++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Objects.Pooling private readonly Dictionary parentMap = new Dictionary(); /// - /// Stores the list of entries managed by this for each hit object managed by this . + /// Stores the list of child entries for each hit object managed by this . /// private readonly Dictionary> childrenMap = new Dictionary>(); From 0329601e84c1a26929f0b89c3b86eb1e1ebf350e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 15 Sep 2022 16:09:27 +0900 Subject: [PATCH 1126/2686] Fix inspection --- .../Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index 79e3cf000e..b6da562bd0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("hit first hitobject", () => { InputManager.Click(MouseButton.Left); - return nextObjectEntry.Result.HasResult; + return nextObjectEntry.Result?.HasResult == true; }); AddAssert("check correct object after hit", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[1]); From 40a60f7145312992a29f0496fc9bb8c08827e1bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 16:31:00 +0900 Subject: [PATCH 1127/2686] Remove all entity framework code and migrations --- CodeAnalysis/BannedSymbols.txt | 2 - osu.Desktop/osu.Desktop.csproj | 4 - .../Navigation/TestEFToRealmMigration.cs | 63 -- .../Beatmaps/BeatmapUpdaterMetadataLookup.cs | 2 +- osu.Game/Database/DatabaseContextFactory.cs | 218 ------- osu.Game/Database/DatabaseWriteUsage.cs | 60 -- osu.Game/Database/EFToRealmMigrator.cs | 595 ------------------ osu.Game/Database/IDatabaseContextFactory.cs | 23 - osu.Game/Database/OsuDbContext.cs | 214 ------- .../20171019041408_InitialCreate.Designer.cs | 293 --------- .../20171019041408_InitialCreate.cs | 314 --------- ...025071459_AddMissingIndexRules.Designer.cs | 299 --------- .../20171025071459_AddMissingIndexRules.cs | 83 --- ...eatmapOnlineIDUniqueConstraint.Designer.cs | 302 --------- ...5731_AddBeatmapOnlineIDUniqueConstraint.cs | 26 - ...034410_AddRulesetInfoShortName.Designer.cs | 307 --------- .../20171209034410_AddRulesetInfoShortName.cs | 36 -- .../20180125143340_Settings.Designer.cs | 329 ---------- .../Migrations/20180125143340_Settings.cs | 58 -- .../20180131154205_AddMuteBinding.cs | 26 - .../20180219060912_AddSkins.Designer.cs | 379 ----------- .../Migrations/20180219060912_AddSkins.cs | 74 --- ...54_RemoveUniqueHashConstraints.Designer.cs | 377 ----------- ...80529055154_RemoveUniqueHashConstraints.cs | 54 -- ...111_UpdateTaikoDefaultBindings.Designer.cs | 376 ----------- ...180621044111_UpdateTaikoDefaultBindings.cs | 20 - ...628011956_RemoveNegativeSetIDs.Designer.cs | 376 ----------- .../20180628011956_RemoveNegativeSetIDs.cs | 21 - .../20180913080842_AddRankStatus.Designer.cs | 380 ----------- .../20180913080842_AddRankStatus.cs | 36 -- ...0181007180454_StandardizePaths.Designer.cs | 380 ----------- .../20181007180454_StandardizePaths.cs | 27 - ...20181128100659_AddSkinInfoHash.Designer.cs | 387 ------------ .../20181128100659_AddSkinInfoHash.cs | 44 -- ...81130113755_AddScoreInfoTables.Designer.cs | 484 -------------- .../20181130113755_AddScoreInfoTables.cs | 115 ---- ...20190225062029_AddUserIDColumn.Designer.cs | 487 -------------- .../20190225062029_AddUserIDColumn.cs | 25 - .../20190525060824_SkinSettings.Designer.cs | 498 --------------- .../Migrations/20190525060824_SkinSettings.cs | 57 -- ...AddDateAddedColumnToBeatmapSet.Designer.cs | 489 -------------- ...05091246_AddDateAddedColumnToBeatmapSet.cs | 27 - ...8070844_AddBPMAndLengthColumns.Designer.cs | 504 --------------- .../20190708070844_AddBPMAndLengthColumns.cs | 36 -- ...20190913104727_AddBeatmapVideo.Designer.cs | 506 --------------- .../20190913104727_AddBeatmapVideo.cs | 25 - ...02094919_RefreshVolumeBindings.Designer.cs | 506 --------------- .../20200302094919_RefreshVolumeBindings.cs | 19 - ...01019224408_AddEpilepsyWarning.Designer.cs | 508 --------------- .../20201019224408_AddEpilepsyWarning.cs | 26 - ...700_RefreshVolumeBindingsAgain.Designer.cs | 506 --------------- ...210412045700_RefreshVolumeBindingsAgain.cs | 19 - ...60743_AddSkinInstantiationInfo.Designer.cs | 508 --------------- ...20210511060743_AddSkinInstantiationInfo.cs | 25 - ...9_AddAuthorIdToBeatmapMetadata.Designer.cs | 511 --------------- ...0514062639_AddAuthorIdToBeatmapMetadata.cs | 26 - ...824185035_AddCountdownSettings.Designer.cs | 513 --------------- .../20210824185035_AddCountdownSettings.cs | 26 - ...11_AddSamplesMatchPlaybackRate.Designer.cs | 515 --------------- ...10912144011_AddSamplesMatchPlaybackRate.cs | 26 - .../20211020081609_ResetSkinHashes.cs | 23 - .../Migrations/OsuDbContextModelSnapshot.cs | 513 --------------- osu.Game/OsuGameBase.cs | 10 +- osu.Game/Screens/Loader.cs | 22 +- osu.sln.DotSettings | 1 - 65 files changed, 3 insertions(+), 13738 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Navigation/TestEFToRealmMigration.cs delete mode 100644 osu.Game/Database/DatabaseContextFactory.cs delete mode 100644 osu.Game/Database/DatabaseWriteUsage.cs delete mode 100644 osu.Game/Database/EFToRealmMigrator.cs delete mode 100644 osu.Game/Database/IDatabaseContextFactory.cs delete mode 100644 osu.Game/Database/OsuDbContext.cs delete mode 100644 osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs delete mode 100644 osu.Game/Migrations/20171019041408_InitialCreate.cs delete mode 100644 osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs delete mode 100644 osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs delete mode 100644 osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs delete mode 100644 osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs delete mode 100644 osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs delete mode 100644 osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.cs delete mode 100644 osu.Game/Migrations/20180125143340_Settings.Designer.cs delete mode 100644 osu.Game/Migrations/20180125143340_Settings.cs delete mode 100644 osu.Game/Migrations/20180131154205_AddMuteBinding.cs delete mode 100644 osu.Game/Migrations/20180219060912_AddSkins.Designer.cs delete mode 100644 osu.Game/Migrations/20180219060912_AddSkins.cs delete mode 100644 osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs delete mode 100644 osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs delete mode 100644 osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs delete mode 100644 osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs delete mode 100644 osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.Designer.cs delete mode 100644 osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs delete mode 100644 osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs delete mode 100644 osu.Game/Migrations/20180913080842_AddRankStatus.cs delete mode 100644 osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs delete mode 100644 osu.Game/Migrations/20181007180454_StandardizePaths.cs delete mode 100644 osu.Game/Migrations/20181128100659_AddSkinInfoHash.Designer.cs delete mode 100644 osu.Game/Migrations/20181128100659_AddSkinInfoHash.cs delete mode 100644 osu.Game/Migrations/20181130113755_AddScoreInfoTables.Designer.cs delete mode 100644 osu.Game/Migrations/20181130113755_AddScoreInfoTables.cs delete mode 100644 osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs delete mode 100644 osu.Game/Migrations/20190225062029_AddUserIDColumn.cs delete mode 100644 osu.Game/Migrations/20190525060824_SkinSettings.Designer.cs delete mode 100644 osu.Game/Migrations/20190525060824_SkinSettings.cs delete mode 100644 osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.Designer.cs delete mode 100644 osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.cs delete mode 100644 osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs delete mode 100644 osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs delete mode 100644 osu.Game/Migrations/20190913104727_AddBeatmapVideo.Designer.cs delete mode 100644 osu.Game/Migrations/20190913104727_AddBeatmapVideo.cs delete mode 100644 osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs delete mode 100644 osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs delete mode 100644 osu.Game/Migrations/20201019224408_AddEpilepsyWarning.Designer.cs delete mode 100644 osu.Game/Migrations/20201019224408_AddEpilepsyWarning.cs delete mode 100644 osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.Designer.cs delete mode 100644 osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.cs delete mode 100644 osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.Designer.cs delete mode 100644 osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.cs delete mode 100644 osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs delete mode 100644 osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.cs delete mode 100644 osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs delete mode 100644 osu.Game/Migrations/20210824185035_AddCountdownSettings.cs delete mode 100644 osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs delete mode 100644 osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs delete mode 100644 osu.Game/Migrations/20211020081609_ResetSkinHashes.cs delete mode 100644 osu.Game/Migrations/OsuDbContextModelSnapshot.cs diff --git a/CodeAnalysis/BannedSymbols.txt b/CodeAnalysis/BannedSymbols.txt index e779ee6658..022da0a2ea 100644 --- a/CodeAnalysis/BannedSymbols.txt +++ b/CodeAnalysis/BannedSymbols.txt @@ -6,8 +6,6 @@ T:System.IComparable;Don't use non-generic IComparable. Use generic version inst T:SixLabors.ImageSharp.IDeepCloneable`1;Use osu.Game.Utils.IDeepCloneable instead. M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText. M:osu.Framework.Bindables.IBindableList`1.GetBoundCopy();Fails on iOS. Use manual ctor + BindTo instead. (see https://github.com/mono/mono/issues/19900) -T:Microsoft.EntityFrameworkCore.Internal.EnumerableExtensions;Don't use internal extension methods. -T:Microsoft.EntityFrameworkCore.Internal.TypeExtensions;Don't use internal extension methods. T:NuGet.Packaging.CollectionExtensions;Don't use internal extension methods. M:System.Enum.HasFlag(System.Enum);Use osu.Framework.Extensions.EnumExtensions.HasFlagFast() instead. M:Realms.IRealmCollection`1.SubscribeForNotifications`1(Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IRealmCollection,NotificationCallbackDelegate) instead. diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index c67017f175..8ef480d4e3 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -28,10 +28,6 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/osu.Game.Tests/Visual/Navigation/TestEFToRealmMigration.cs b/osu.Game.Tests/Visual/Navigation/TestEFToRealmMigration.cs deleted file mode 100644 index c3559589ed..0000000000 --- a/osu.Game.Tests/Visual/Navigation/TestEFToRealmMigration.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.Linq; -using System.Runtime.InteropServices; -using NUnit.Framework; -using osu.Framework; -using osu.Framework.Allocation; -using osu.Game.Beatmaps; -using osu.Game.Database; -using osu.Game.Models; -using osu.Game.Scoring; -using osu.Game.Skinning; -using osu.Game.Tests.Resources; - -namespace osu.Game.Tests.Visual.Navigation -{ - public class TestEFToRealmMigration : OsuGameTestScene - { - public override void RecycleLocalStorage(bool isDisposing) - { - base.RecycleLocalStorage(isDisposing); - - if (isDisposing) - return; - - using (var outStream = LocalStorage.CreateFileSafely(DatabaseContextFactory.DATABASE_NAME)) - using (var stream = TestResources.OpenResource(DatabaseContextFactory.DATABASE_NAME)) - stream.CopyTo(outStream); - } - - [SetUp] - public void SetUp() - { - if (RuntimeInfo.OS == RuntimeInfo.Platform.macOS && RuntimeInformation.OSArchitecture == Architecture.Arm64) - Assert.Ignore("EF-to-realm migrations are not supported on M1 ARM architectures."); - } - - public override void SetUpSteps() - { - // base SetUpSteps are executed before the above SetUp, therefore early-return to allow ignoring test properly. - // attempting to ignore here would yield a TargetInvocationException instead. - if (RuntimeInfo.OS == RuntimeInfo.Platform.macOS && RuntimeInformation.OSArchitecture == Architecture.Arm64) - return; - - base.SetUpSteps(); - } - - [Test] - public void TestMigration() - { - // Numbers are taken from the test database (see commit f03de16ee5a46deac3b5f2ca1edfba5c4c5dca7d). - AddAssert("Check beatmaps", () => Game.Dependencies.Get().Run(r => r.All().Count(s => !s.Protected) == 1)); - AddAssert("Check skins", () => Game.Dependencies.Get().Run(r => r.All().Count(s => !s.Protected) == 1)); - AddAssert("Check scores", () => Game.Dependencies.Get().Run(r => r.All().Count() == 1)); - - // One extra file is created during realm migration / startup due to the circles intro import. - AddAssert("Check files", () => Game.Dependencies.Get().Run(r => r.All().Count() == 271)); - } - } -} diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index f96fcc2630..aa773da6d3 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -192,7 +192,7 @@ namespace osu.Game.Beatmaps try { - using (var db = new SqliteConnection(DatabaseContextFactory.CreateDatabaseConnectionString("online.db", storage))) + using (var db = new SqliteConnection(string.Concat("Data Source=", storage.GetFullPath($@"{"online.db"}", true)))) { db.Open(); diff --git a/osu.Game/Database/DatabaseContextFactory.cs b/osu.Game/Database/DatabaseContextFactory.cs deleted file mode 100644 index af91fb4971..0000000000 --- a/osu.Game/Database/DatabaseContextFactory.cs +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.IO; -using System.Linq; -using System.Threading; -using Microsoft.EntityFrameworkCore.Storage; -using osu.Framework.Logging; -using osu.Framework.Platform; -using osu.Framework.Statistics; - -namespace osu.Game.Database -{ - public class DatabaseContextFactory : IDatabaseContextFactory - { - private readonly Storage storage; - - public const string DATABASE_NAME = @"client.db"; - - private ThreadLocal threadContexts; - - private readonly object writeLock = new object(); - - private bool currentWriteDidWrite; - private bool currentWriteDidError; - - private int currentWriteUsages; - - private IDbContextTransaction currentWriteTransaction; - - public DatabaseContextFactory(Storage storage) - { - this.storage = storage; - recycleThreadContexts(); - } - - private static readonly GlobalStatistic reads = GlobalStatistics.Get("Database", "Get (Read)"); - private static readonly GlobalStatistic writes = GlobalStatistics.Get("Database", "Get (Write)"); - private static readonly GlobalStatistic commits = GlobalStatistics.Get("Database", "Commits"); - private static readonly GlobalStatistic rollbacks = GlobalStatistics.Get("Database", "Rollbacks"); - - /// - /// Get a context for the current thread for read-only usage. - /// If a is in progress, the existing write-safe context will be returned. - /// - public OsuDbContext Get() - { - reads.Value++; - return threadContexts.Value; - } - - /// - /// Request a context for write usage. Can be consumed in a nested fashion (and will return the same underlying context). - /// This method may block if a write is already active on a different thread. - /// - /// Whether to start a transaction for this write. - /// A usage containing a usable context. - public DatabaseWriteUsage GetForWrite(bool withTransaction = true) - { - writes.Value++; - Monitor.Enter(writeLock); - OsuDbContext context; - - try - { - if (currentWriteTransaction == null && withTransaction) - { - // this mitigates the fact that changes on tracked entities will not be rolled back with the transaction by ensuring write operations are always executed in isolated contexts. - // if this results in sub-optimal efficiency, we may need to look into removing Database-level transactions in favour of running SaveChanges where we currently commit the transaction. - if (threadContexts.IsValueCreated) - recycleThreadContexts(); - - context = threadContexts.Value; - currentWriteTransaction = context.Database.BeginTransaction(); - } - else - { - // we want to try-catch the retrieval of the context because it could throw an error (in CreateContext). - context = threadContexts.Value; - } - } - catch - { - // retrieval of a context could trigger a fatal error. - Monitor.Exit(writeLock); - throw; - } - - Interlocked.Increment(ref currentWriteUsages); - - return new DatabaseWriteUsage(context, usageCompleted) { IsTransactionLeader = currentWriteTransaction != null && currentWriteUsages == 1 }; - } - - private void usageCompleted(DatabaseWriteUsage usage) - { - int usages = Interlocked.Decrement(ref currentWriteUsages); - - try - { - currentWriteDidWrite |= usage.PerformedWrite; - currentWriteDidError |= usage.Errors.Any(); - - if (usages == 0) - { - if (currentWriteDidError) - { - rollbacks.Value++; - currentWriteTransaction?.Rollback(); - } - else - { - commits.Value++; - currentWriteTransaction?.Commit(); - } - - if (currentWriteDidWrite || currentWriteDidError) - { - // explicitly dispose to ensure any outstanding flushes happen as soon as possible (and underlying resources are purged). - usage.Context.Dispose(); - - // once all writes are complete, we want to refresh thread-specific contexts to make sure they don't have stale local caches. - recycleThreadContexts(); - } - - currentWriteTransaction = null; - currentWriteDidWrite = false; - currentWriteDidError = false; - } - } - finally - { - Monitor.Exit(writeLock); - } - } - - private void recycleThreadContexts() - { - // Contexts for other threads are not disposed as they may be in use elsewhere. Instead, fresh contexts are exposed - // for other threads to use, and we rely on the finalizer inside OsuDbContext to handle their previous contexts - threadContexts?.Value.Dispose(); - threadContexts = new ThreadLocal(CreateContext, true); - } - - protected virtual OsuDbContext CreateContext() => new OsuDbContext(CreateDatabaseConnectionString(DATABASE_NAME, storage)) - { - Database = { AutoTransactionsEnabled = false } - }; - - public void CreateBackup(string backupFilename) - { - Logger.Log($"Creating full EF database backup at {backupFilename}", LoggingTarget.Database); - - using (var source = storage.GetStream(DATABASE_NAME, mode: FileMode.Open)) - using (var destination = storage.GetStream(backupFilename, FileAccess.Write, FileMode.CreateNew)) - source.CopyTo(destination); - } - - public void ResetDatabase() - { - lock (writeLock) - { - recycleThreadContexts(); - - try - { - int attempts = 10; - - // Retry logic taken from MigratableStorage.AttemptOperation. - while (true) - { - try - { - storage.Delete(DATABASE_NAME); - return; - } - catch (Exception) - { - if (attempts-- == 0) - throw; - } - - Thread.Sleep(250); - } - } - catch - { - // for now we are not sure why file handles are kept open by EF, but this is generally only used in testing - } - } - } - - public void FlushConnections() - { - if (threadContexts != null) - { - foreach (var context in threadContexts.Values) - context.Dispose(); - } - - recycleThreadContexts(); - } - - public static string CreateDatabaseConnectionString(string filename, Storage storage) => string.Concat("Data Source=", storage.GetFullPath($@"{filename}", true)); - - private readonly ManualResetEventSlim migrationComplete = new ManualResetEventSlim(); - - public void SetMigrationCompletion() => migrationComplete.Set(); - - public void WaitForMigrationCompletion() - { - if (!migrationComplete.Wait(300000)) - throw new TimeoutException("Migration took too long (likely stuck)."); - } - } -} diff --git a/osu.Game/Database/DatabaseWriteUsage.cs b/osu.Game/Database/DatabaseWriteUsage.cs deleted file mode 100644 index b5f25eae20..0000000000 --- a/osu.Game/Database/DatabaseWriteUsage.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; - -namespace osu.Game.Database -{ - public class DatabaseWriteUsage : IDisposable - { - public readonly OsuDbContext Context; - private readonly Action usageCompleted; - - public DatabaseWriteUsage(OsuDbContext context, Action onCompleted) - { - Context = context; - usageCompleted = onCompleted; - } - - public bool PerformedWrite { get; private set; } - - private bool isDisposed; - public List Errors = new List(); - - /// - /// Whether this write usage will commit a transaction on completion. - /// If false, there is a parent usage responsible for transaction commit. - /// - public bool IsTransactionLeader; - - protected void Dispose(bool disposing) - { - if (isDisposed) return; - - isDisposed = true; - - try - { - PerformedWrite |= Context.SaveChanges() > 0; - } - catch (Exception e) - { - Errors.Add(e); - throw; - } - finally - { - usageCompleted?.Invoke(this); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - } -} diff --git a/osu.Game/Database/EFToRealmMigrator.cs b/osu.Game/Database/EFToRealmMigrator.cs deleted file mode 100644 index 294a8cd3ed..0000000000 --- a/osu.Game/Database/EFToRealmMigrator.cs +++ /dev/null @@ -1,595 +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.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using osu.Framework; -using osu.Framework.Allocation; -using osu.Framework.Development; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Logging; -using osu.Framework.Platform; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Models; -using osu.Game.Overlays; -using osu.Game.Overlays.Notifications; -using osu.Game.Rulesets; -using osu.Game.Scoring; -using osu.Game.Skinning; -using osuTK; -using Realms; -using SharpCompress.Archives; -using SharpCompress.Archives.Zip; -using SharpCompress.Common; -using SharpCompress.Writers.Zip; - -namespace osu.Game.Database -{ - internal class EFToRealmMigrator : CompositeDrawable - { - public Task MigrationCompleted => migrationCompleted.Task; - - private readonly TaskCompletionSource migrationCompleted = new TaskCompletionSource(); - - [Resolved] - private DatabaseContextFactory efContextFactory { get; set; } = null!; - - [Resolved] - private RealmAccess realm { get; set; } = null!; - - [Resolved] - private OsuConfigManager config { get; set; } = null!; - - [Resolved] - private INotificationOverlay notificationOverlay { get; set; } = null!; - - [Resolved] - private OsuGame game { get; set; } = null!; - - [Resolved] - private Storage storage { get; set; } = null!; - - private readonly OsuTextFlowContainer currentOperationText; - - public EFToRealmMigrator() - { - RelativeSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Spacing = new Vector2(10), - Children = new Drawable[] - { - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "Database migration in progress", - Font = OsuFont.Default.With(size: 40) - }, - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "This could take a few minutes depending on the speed of your disk(s).", - Font = OsuFont.Default.With(size: 30) - }, - new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Text = "Please keep the window open until this completes!", - Font = OsuFont.Default.With(size: 30) - }, - new LoadingSpinner(true) - { - State = { Value = Visibility.Visible } - }, - currentOperationText = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 30)) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - TextAnchor = Anchor.TopCentre, - }, - } - }, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - beginMigration(); - } - - private void beginMigration() - { - const string backup_folder = "backups"; - - string backupSuffix = $"before_final_migration_{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}"; - - // required for initial backup. - var realmBlockOperations = realm.BlockAllOperations("EF migration"); - - Task.Factory.StartNew(() => - { - try - { - realm.CreateBackup(Path.Combine(backup_folder, $"client.{backupSuffix}.realm")); - } - finally - { - // Once the backup is created, we need to stop blocking operations so the migration can complete. - realmBlockOperations.Dispose(); - // Clean up here so we don't accidentally dispose twice. - realmBlockOperations = null; - } - - efContextFactory.CreateBackup(Path.Combine(backup_folder, $"client.{backupSuffix}.db")); - - using (var ef = efContextFactory.Get()) - { - realm.Write(r => - { - // Before beginning, ensure realm is in an empty state. - // Migrations which are half-completed could lead to issues if the user tries a second time. - // Note that we only do this for beatmaps and scores since the other migrations are yonks old. - r.RemoveAll(); - r.RemoveAll(); - r.RemoveAll(); - r.RemoveAll(); - }); - - ef.Migrate(); - - migrateSettings(ef); - migrateSkins(ef); - migrateBeatmaps(ef); - migrateScores(ef); - } - }, TaskCreationOptions.LongRunning).ContinueWith(t => - { - if (t.Exception == null) - { - log("Migration successful!"); - - if (DebugUtils.IsDebugBuild) - { - Logger.Log( - "Your development database has been fully migrated to realm. If you switch back to a pre-realm branch and need your previous database, rename the backup file back to \"client.db\".\n\nNote that doing this can potentially leave your file store in a bad state.", - level: LogLevel.Important); - } - } - else - { - log("Migration failed!"); - Logger.Log(t.Exception.ToString(), LoggingTarget.Database); - - if (RuntimeInfo.OS == RuntimeInfo.Platform.macOS && t.Exception.Flatten().InnerException is TypeInitializationException) - { - // Not guaranteed to be the only cause of exception, but let's roll with it for now. - log("Please download and run the intel version of osu! once\nto allow data migration to complete!"); - efContextFactory.SetMigrationCompletion(); - return; - } - - notificationOverlay.Post(new SimpleErrorNotification - { - Text = - "IMPORTANT: During data migration, some of your data could not be successfully migrated. The previous version has been backed up.\n\nFor further assistance, please open a discussion on github and attach your backup files (click to get started).", - Activated = () => - { - game.OpenUrlExternally( - $@"https://github.com/ppy/osu/discussions/new?title=Realm%20migration%20issue ({t.Exception.Message})&body=Please%20drag%20the%20""attach_me.zip""%20file%20here!&category=q-a", - true); - - const string attachment_filename = "attach_me.zip"; - - var backupStorage = storage.GetStorageForDirectory(backup_folder); - - backupStorage.Delete(attachment_filename); - - try - { - using (var zip = ZipArchive.Create()) - { - zip.AddAllFromDirectory(backupStorage.GetFullPath(string.Empty)); - zip.SaveTo(Path.Combine(backupStorage.GetFullPath(string.Empty), attachment_filename), new ZipWriterOptions(CompressionType.Deflate)); - } - } - catch { } - - backupStorage.PresentFileExternally(attachment_filename); - - return true; - } - }); - } - - // Regardless of success, since the game is going to continue with startup let's move the ef database out of the way. - // If we were to not do this, the migration would run another time the next time the user starts the game. - deletePreRealmData(); - - // If something went wrong and the disposal token wasn't invoked above, ensure it is here. - realmBlockOperations?.Dispose(); - - migrationCompleted.SetResult(true); - efContextFactory.SetMigrationCompletion(); - }); - } - - private void deletePreRealmData() - { - // Delete the database permanently. - // Will cause future startups to not attempt migration. - efContextFactory.ResetDatabase(); - } - - private void log(string message) - { - Logger.Log(message, LoggingTarget.Database); - Scheduler.AddOnce(m => currentOperationText.Text = m, message); - } - - private void migrateBeatmaps(OsuDbContext ef) - { - // can be removed 20220730. - var existingBeatmapSets = ef.EFBeatmapSetInfo - .Include(s => s.Beatmaps).ThenInclude(b => b.RulesetInfo) - .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) - .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty) - .Include(s => s.Files).ThenInclude(f => f.FileInfo) - .Include(s => s.Metadata) - .AsSplitQuery(); - - log("Beginning beatmaps migration to realm"); - - // previous entries in EF are removed post migration. - if (!existingBeatmapSets.Any()) - { - log("No beatmaps found to migrate"); - return; - } - - int count = existingBeatmapSets.Count(); - - realm.Run(r => - { - log($"Found {count} beatmaps in EF"); - - var transaction = r.BeginWrite(); - int written = 0; - int missing = 0; - - try - { - foreach (var beatmapSet in existingBeatmapSets) - { - if (++written % 1000 == 0) - { - transaction.Commit(); - transaction = r.BeginWrite(); - log($"Migrated {written}/{count} beatmaps..."); - } - - var realmBeatmapSet = new BeatmapSetInfo - { - OnlineID = beatmapSet.OnlineID ?? -1, - DateAdded = beatmapSet.DateAdded, - Status = beatmapSet.Status, - DeletePending = beatmapSet.DeletePending, - Hash = beatmapSet.Hash, - Protected = beatmapSet.Protected, - }; - - migrateFiles(beatmapSet, r, realmBeatmapSet); - - foreach (var beatmap in beatmapSet.Beatmaps) - { - var ruleset = r.Find(beatmap.RulesetInfo.ShortName); - var metadata = getBestMetadata(beatmap.Metadata, beatmapSet.Metadata); - - if (ruleset == null) - { - log($"Skipping {++missing} beatmaps with missing ruleset"); - continue; - } - - var realmBeatmap = new BeatmapInfo(ruleset, new BeatmapDifficulty(beatmap.BaseDifficulty), metadata) - { - DifficultyName = beatmap.DifficultyName, - Status = beatmap.Status, - OnlineID = beatmap.OnlineID ?? -1, - Length = beatmap.Length, - BPM = beatmap.BPM, - Hash = beatmap.Hash, - StarRating = beatmap.StarRating, - MD5Hash = beatmap.MD5Hash, - Hidden = beatmap.Hidden, - AudioLeadIn = beatmap.AudioLeadIn, - StackLeniency = beatmap.StackLeniency, - SpecialStyle = beatmap.SpecialStyle, - LetterboxInBreaks = beatmap.LetterboxInBreaks, - WidescreenStoryboard = beatmap.WidescreenStoryboard, - EpilepsyWarning = beatmap.EpilepsyWarning, - SamplesMatchPlaybackRate = beatmap.SamplesMatchPlaybackRate, - DistanceSpacing = beatmap.DistanceSpacing, - BeatDivisor = beatmap.BeatDivisor, - GridSize = beatmap.GridSize, - TimelineZoom = beatmap.TimelineZoom, - Countdown = beatmap.Countdown, - CountdownOffset = beatmap.CountdownOffset, - Bookmarks = beatmap.Bookmarks, - BeatmapSet = realmBeatmapSet, - }; - - realmBeatmapSet.Beatmaps.Add(realmBeatmap); - } - - r.Add(realmBeatmapSet); - } - } - finally - { - transaction.Commit(); - } - - log($"Successfully migrated {count} beatmaps to realm"); - }); - } - - private BeatmapMetadata getBestMetadata(EFBeatmapMetadata? beatmapMetadata, EFBeatmapMetadata? beatmapSetMetadata) - { - var metadata = beatmapMetadata ?? beatmapSetMetadata ?? new EFBeatmapMetadata(); - - return new BeatmapMetadata - { - Title = metadata.Title, - TitleUnicode = metadata.TitleUnicode, - Artist = metadata.Artist, - ArtistUnicode = metadata.ArtistUnicode, - Author = - { - OnlineID = metadata.Author.Id, - Username = metadata.Author.Username, - }, - Source = metadata.Source, - Tags = metadata.Tags, - PreviewTime = metadata.PreviewTime, - AudioFile = metadata.AudioFile, - BackgroundFile = metadata.BackgroundFile, - }; - } - - private void migrateScores(OsuDbContext db) - { - // can be removed 20220730. - var existingScores = db.ScoreInfo - .Include(s => s.Ruleset) - .Include(s => s.BeatmapInfo) - .Include(s => s.Files) - .ThenInclude(f => f.FileInfo) - .AsSplitQuery(); - - log("Beginning scores migration to realm"); - - // previous entries in EF are removed post migration. - if (!existingScores.Any()) - { - log("No scores found to migrate"); - return; - } - - int count = existingScores.Count(); - - realm.Run(r => - { - log($"Found {count} scores in EF"); - - var transaction = r.BeginWrite(); - int written = 0; - int missing = 0; - - try - { - foreach (var score in existingScores) - { - if (++written % 1000 == 0) - { - transaction.Commit(); - transaction = r.BeginWrite(); - log($"Migrated {written}/{count} scores..."); - } - - var beatmap = r.All().FirstOrDefault(b => b.Hash == score.BeatmapInfo.Hash); - var ruleset = r.Find(score.Ruleset.ShortName); - - if (beatmap == null || ruleset == null) - { - log($"Skipping {++missing} scores with missing ruleset or beatmap"); - continue; - } - - var user = new RealmUser - { - OnlineID = score.User.OnlineID, - Username = score.User.Username - }; - - var realmScore = new ScoreInfo(beatmap, ruleset, user) - { - Hash = score.Hash, - DeletePending = score.DeletePending, - OnlineID = score.OnlineID ?? -1, - ModsJson = score.ModsJson, - StatisticsJson = score.StatisticsJson, - TotalScore = score.TotalScore, - MaxCombo = score.MaxCombo, - Accuracy = score.Accuracy, - Date = score.Date, - PP = score.PP, - Rank = score.Rank, - HitEvents = score.HitEvents, - Passed = score.Passed, - Combo = score.Combo, - Position = score.Position, - Statistics = score.Statistics, - Mods = score.Mods, - APIMods = score.APIMods, - }; - - migrateFiles(score, r, realmScore); - - r.Add(realmScore); - } - } - finally - { - transaction.Commit(); - } - - log($"Successfully migrated {count} scores to realm"); - }); - } - - private void migrateSkins(OsuDbContext db) - { - // can be removed 20220530. - var existingSkins = db.SkinInfo - .Include(s => s.Files) - .ThenInclude(f => f.FileInfo) - .AsSplitQuery() - .ToList(); - - // previous entries in EF are removed post migration. - if (!existingSkins.Any()) - return; - - var userSkinChoice = config.GetBindable(OsuSetting.Skin); - int.TryParse(userSkinChoice.Value, out int userSkinInt); - - switch (userSkinInt) - { - case EFSkinInfo.DEFAULT_SKIN: - userSkinChoice.Value = SkinInfo.DEFAULT_SKIN.ToString(); - break; - - case EFSkinInfo.CLASSIC_SKIN: - userSkinChoice.Value = SkinInfo.CLASSIC_SKIN.ToString(); - break; - } - - realm.Run(r => - { - using (var transaction = r.BeginWrite()) - { - // only migrate data if the realm database is empty. - // note that this cannot be written as: `r.All().All(s => s.Protected)`, because realm does not support `.All()`. - if (!r.All().Any(s => !s.Protected)) - { - log($"Migrating {existingSkins.Count} skins"); - - foreach (var skin in existingSkins) - { - var realmSkin = new SkinInfo - { - Name = skin.Name, - Creator = skin.Creator, - Hash = skin.Hash, - Protected = false, - InstantiationInfo = skin.InstantiationInfo, - }; - - migrateFiles(skin, r, realmSkin); - - r.Add(realmSkin); - - if (skin.ID == userSkinInt) - userSkinChoice.Value = realmSkin.ID.ToString(); - } - } - - transaction.Commit(); - } - }); - } - - private static void migrateFiles(IHasFiles fileSource, Realm realm, IHasRealmFiles realmObject) where T : INamedFileInfo - { - foreach (var file in fileSource.Files) - { - var realmFile = realm.Find(file.FileInfo.Hash); - - if (realmFile == null) - realm.Add(realmFile = new RealmFile { Hash = file.FileInfo.Hash }); - - realmObject.Files.Add(new RealmNamedFileUsage(realmFile, file.Filename)); - } - } - - private void migrateSettings(OsuDbContext db) - { - // migrate ruleset settings. can be removed 20220315. - var existingSettings = db.DatabasedSetting.ToList(); - - // previous entries in EF are removed post migration. - if (!existingSettings.Any()) - return; - - log("Beginning settings migration to realm"); - - realm.Run(r => - { - using (var transaction = r.BeginWrite()) - { - // only migrate data if the realm database is empty. - if (!r.All().Any()) - { - log($"Migrating {existingSettings.Count} settings"); - - foreach (var dkb in existingSettings) - { - if (dkb.RulesetID == null) - continue; - - string? shortName = getRulesetShortNameFromLegacyID(dkb.RulesetID.Value); - - if (string.IsNullOrEmpty(shortName)) - continue; - - r.Add(new RealmRulesetSetting - { - Key = dkb.Key, - Value = dkb.StringValue, - RulesetName = shortName, - Variant = dkb.Variant ?? 0, - }); - } - } - - transaction.Commit(); - } - }); - } - - private string? getRulesetShortNameFromLegacyID(long rulesetId) => - efContextFactory.Get().RulesetInfo.FirstOrDefault(r => r.ID == rulesetId)?.ShortName; - } -} diff --git a/osu.Game/Database/IDatabaseContextFactory.cs b/osu.Game/Database/IDatabaseContextFactory.cs deleted file mode 100644 index bddabad586..0000000000 --- a/osu.Game/Database/IDatabaseContextFactory.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -namespace osu.Game.Database -{ - public interface IDatabaseContextFactory - { - /// - /// Get a context for read-only usage. - /// - OsuDbContext Get(); - - /// - /// Request a context for write usage. Can be consumed in a nested fashion (and will return the same underlying context). - /// This method may block if a write is already active on a different thread. - /// - /// Whether to start a transaction for this write. - /// A usage containing a usable context. - DatabaseWriteUsage GetForWrite(bool withTransaction = true); - } -} diff --git a/osu.Game/Database/OsuDbContext.cs b/osu.Game/Database/OsuDbContext.cs deleted file mode 100644 index 118a8ee469..0000000000 --- a/osu.Game/Database/OsuDbContext.cs +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using osu.Framework.Logging; -using osu.Framework.Statistics; -using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.IO; -using osu.Game.Rulesets; -using osu.Game.Scoring; -using osu.Game.Skinning; -using SQLitePCL; -using LogLevel = Microsoft.Extensions.Logging.LogLevel; - -namespace osu.Game.Database -{ - public class OsuDbContext : DbContext - { - public DbSet EFBeatmapInfo { get; set; } - public DbSet BeatmapDifficulty { get; set; } - public DbSet BeatmapMetadata { get; set; } - public DbSet EFBeatmapSetInfo { get; set; } - public DbSet FileInfo { get; set; } - public DbSet RulesetInfo { get; set; } - public DbSet SkinInfo { get; set; } - public DbSet ScoreInfo { get; set; } - - // migrated to realm - public DbSet DatabasedSetting { get; set; } - - private readonly string connectionString; - - private static readonly Lazy logger = new Lazy(() => new OsuDbLoggerFactory()); - - private static readonly GlobalStatistic contexts = GlobalStatistics.Get("Database", "Contexts"); - - static OsuDbContext() - { - // required to initialise native SQLite libraries on some platforms. - Batteries_V2.Init(); - - // https://github.com/aspnet/EntityFrameworkCore/issues/9994#issuecomment-508588678 - raw.sqlite3_config(2 /*SQLITE_CONFIG_MULTITHREAD*/); - } - - /// - /// Create a new in-memory OsuDbContext instance. - /// - public OsuDbContext() - : this("DataSource=:memory:") - { - // required for tooling (see https://wildermuth.com/2017/07/06/Program-cs-in-ASP-NET-Core-2-0). - - Migrate(); - } - - /// - /// Create a new OsuDbContext instance. - /// - /// A valid SQLite connection string. - public OsuDbContext(string connectionString) - { - this.connectionString = connectionString; - - var connection = Database.GetDbConnection(); - - try - { - connection.Open(); - - using (var cmd = connection.CreateCommand()) - { - cmd.CommandText = "PRAGMA journal_mode=WAL;"; - cmd.ExecuteNonQuery(); - - cmd.CommandText = "PRAGMA foreign_keys=OFF;"; - cmd.ExecuteNonQuery(); - } - } - catch - { - connection.Close(); - throw; - } - - contexts.Value++; - } - - ~OsuDbContext() - { - // DbContext does not contain a finalizer (https://github.com/aspnet/EntityFrameworkCore/issues/8872) - // This is used to clean up previous contexts when fresh contexts are exposed via DatabaseContextFactory - Dispose(); - } - - private bool isDisposed; - - public override void Dispose() - { - if (isDisposed) return; - - isDisposed = true; - - base.Dispose(); - - contexts.Value--; - GC.SuppressFinalize(this); - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - base.OnConfiguring(optionsBuilder); - optionsBuilder - // this is required for the time being due to the way we are querying in places like BeatmapStore. - // if we ever move to having consumers file their own .Includes, or get eager loading support, this could be re-enabled. - .UseSqlite(connectionString, sqliteOptions => sqliteOptions.CommandTimeout(10)) - .UseLoggerFactory(logger.Value); - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - modelBuilder.Entity().HasIndex(b => b.OnlineID).IsUnique(); - modelBuilder.Entity().HasIndex(b => b.MD5Hash); - modelBuilder.Entity().HasIndex(b => b.Hash); - - modelBuilder.Entity().HasIndex(b => b.OnlineID).IsUnique(); - modelBuilder.Entity().HasIndex(b => b.DeletePending); - modelBuilder.Entity().HasIndex(b => b.Hash).IsUnique(); - - modelBuilder.Entity().HasIndex(b => b.Hash).IsUnique(); - modelBuilder.Entity().HasIndex(b => b.DeletePending); - modelBuilder.Entity().HasMany(s => s.Files).WithOne(f => f.SkinInfo); - - modelBuilder.Entity().HasIndex(b => new { b.RulesetID, b.Variant }); - - modelBuilder.Entity().HasIndex(b => b.Hash).IsUnique(); - modelBuilder.Entity().HasIndex(b => b.ReferenceCount); - - modelBuilder.Entity().HasIndex(b => b.Available); - modelBuilder.Entity().HasIndex(b => b.ShortName).IsUnique(); - - modelBuilder.Entity().HasOne(b => b.BaseDifficulty); - - modelBuilder.Entity().HasIndex(b => b.OnlineID).IsUnique(); - } - - private class OsuDbLoggerFactory : ILoggerFactory - { - #region Disposal - - public void Dispose() - { - } - - #endregion - - public ILogger CreateLogger(string categoryName) => new OsuDbLogger(); - - public void AddProvider(ILoggerProvider provider) - { - // no-op. called by tooling. - } - - private class OsuDbLogger : ILogger - { - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - if (logLevel < LogLevel.Information) - return; - - Framework.Logging.LogLevel frameworkLogLevel; - - switch (logLevel) - { - default: - frameworkLogLevel = Framework.Logging.LogLevel.Debug; - break; - - case LogLevel.Warning: - frameworkLogLevel = Framework.Logging.LogLevel.Important; - break; - - case LogLevel.Error: - case LogLevel.Critical: - frameworkLogLevel = Framework.Logging.LogLevel.Error; - break; - } - - Logger.Log(formatter(state, exception), LoggingTarget.Database, frameworkLogLevel); - } - - public bool IsEnabled(LogLevel logLevel) - { -#if DEBUG_DATABASE - return logLevel > LogLevel.Debug; -#else - return logLevel > LogLevel.Information; -#endif - } - - public IDisposable BeginScope(TState state) => null; - } - } - - public void Migrate() => Database.Migrate(); - } -} diff --git a/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs b/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs deleted file mode 100644 index c751530bf4..0000000000 --- a/osu.Game/Migrations/20171019041408_InitialCreate.Designer.cs +++ /dev/null @@ -1,293 +0,0 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using osu.Game.Database; -using System; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20171019041408_InitialCreate")] - partial class InitialCreate - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash"); - - b.HasIndex("MetadataID"); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20171019041408_InitialCreate.cs b/osu.Game/Migrations/20171019041408_InitialCreate.cs deleted file mode 100644 index 08ab64fd08..0000000000 --- a/osu.Game/Migrations/20171019041408_InitialCreate.cs +++ /dev/null @@ -1,314 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class InitialCreate : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "BeatmapDifficulty", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - ApproachRate = table.Column(type: "REAL", nullable: false), - CircleSize = table.Column(type: "REAL", nullable: false), - DrainRate = table.Column(type: "REAL", nullable: false), - OverallDifficulty = table.Column(type: "REAL", nullable: false), - SliderMultiplier = table.Column(type: "REAL", nullable: false), - SliderTickRate = table.Column(type: "REAL", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapDifficulty", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "BeatmapMetadata", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Artist = table.Column(type: "TEXT", nullable: true), - ArtistUnicode = table.Column(type: "TEXT", nullable: true), - AudioFile = table.Column(type: "TEXT", nullable: true), - Author = table.Column(type: "TEXT", nullable: true), - BackgroundFile = table.Column(type: "TEXT", nullable: true), - PreviewTime = table.Column(type: "INTEGER", nullable: false), - Source = table.Column(type: "TEXT", nullable: true), - Tags = table.Column(type: "TEXT", nullable: true), - Title = table.Column(type: "TEXT", nullable: true), - TitleUnicode = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapMetadata", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "FileInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Hash = table.Column(type: "TEXT", nullable: true), - ReferenceCount = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_FileInfo", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "KeyBinding", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Action = table.Column(type: "INTEGER", nullable: false), - Keys = table.Column(type: "TEXT", nullable: true), - RulesetID = table.Column(type: "INTEGER", nullable: true), - Variant = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_KeyBinding", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "RulesetInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Available = table.Column(type: "INTEGER", nullable: false), - InstantiationInfo = table.Column(type: "TEXT", nullable: true), - Name = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_RulesetInfo", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "BeatmapSetInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - DeletePending = table.Column(type: "INTEGER", nullable: false), - Hash = table.Column(type: "TEXT", nullable: true), - MetadataID = table.Column(type: "INTEGER", nullable: true), - OnlineBeatmapSetID = table.Column(type: "INTEGER", nullable: true), - Protected = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapSetInfo", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapSetInfo_BeatmapMetadata_MetadataID", - column: x => x.MetadataID, - principalTable: "BeatmapMetadata", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "BeatmapInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - AudioLeadIn = table.Column(type: "INTEGER", nullable: false), - BaseDifficultyID = table.Column(type: "INTEGER", nullable: false), - BeatDivisor = table.Column(type: "INTEGER", nullable: false), - BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false), - Countdown = table.Column(type: "INTEGER", nullable: false), - DistanceSpacing = table.Column(type: "REAL", nullable: false), - GridSize = table.Column(type: "INTEGER", nullable: false), - Hash = table.Column(type: "TEXT", nullable: true), - Hidden = table.Column(type: "INTEGER", nullable: false), - LetterboxInBreaks = table.Column(type: "INTEGER", nullable: false), - MD5Hash = table.Column(type: "TEXT", nullable: true), - MetadataID = table.Column(type: "INTEGER", nullable: true), - OnlineBeatmapID = table.Column(type: "INTEGER", nullable: true), - Path = table.Column(type: "TEXT", nullable: true), - RulesetID = table.Column(type: "INTEGER", nullable: false), - SpecialStyle = table.Column(type: "INTEGER", nullable: false), - StackLeniency = table.Column(type: "REAL", nullable: false), - StarDifficulty = table.Column(type: "REAL", nullable: false), - StoredBookmarks = table.Column(type: "TEXT", nullable: true), - TimelineZoom = table.Column(type: "REAL", nullable: false), - Version = table.Column(type: "TEXT", nullable: true), - WidescreenStoryboard = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapInfo", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapDifficulty_BaseDifficultyID", - column: x => x.BaseDifficultyID, - principalTable: "BeatmapDifficulty", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapSetInfo_BeatmapSetInfoID", - column: x => x.BeatmapSetInfoID, - principalTable: "BeatmapSetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BeatmapInfo_BeatmapMetadata_MetadataID", - column: x => x.MetadataID, - principalTable: "BeatmapMetadata", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_BeatmapInfo_RulesetInfo_RulesetID", - column: x => x.RulesetID, - principalTable: "RulesetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "BeatmapSetFileInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - BeatmapSetInfoID = table.Column(type: "INTEGER", nullable: false), - FileInfoID = table.Column(type: "INTEGER", nullable: false), - Filename = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_BeatmapSetFileInfo", x => x.ID); - table.ForeignKey( - name: "FK_BeatmapSetFileInfo_BeatmapSetInfo_BeatmapSetInfoID", - column: x => x.BeatmapSetInfoID, - principalTable: "BeatmapSetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_BeatmapSetFileInfo_FileInfo_FileInfoID", - column: x => x.FileInfoID, - principalTable: "FileInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_BaseDifficultyID", - table: "BeatmapInfo", - column: "BaseDifficultyID"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_BeatmapSetInfoID", - table: "BeatmapInfo", - column: "BeatmapSetInfoID"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_Hash", - table: "BeatmapInfo", - column: "Hash"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_MD5Hash", - table: "BeatmapInfo", - column: "MD5Hash"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_MetadataID", - table: "BeatmapInfo", - column: "MetadataID"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_RulesetID", - table: "BeatmapInfo", - column: "RulesetID"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapSetFileInfo_BeatmapSetInfoID", - table: "BeatmapSetFileInfo", - column: "BeatmapSetInfoID"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapSetFileInfo_FileInfoID", - table: "BeatmapSetFileInfo", - column: "FileInfoID"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapSetInfo_DeletePending", - table: "BeatmapSetInfo", - column: "DeletePending"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapSetInfo_Hash", - table: "BeatmapSetInfo", - column: "Hash"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapSetInfo_MetadataID", - table: "BeatmapSetInfo", - column: "MetadataID"); - - migrationBuilder.CreateIndex( - name: "IX_FileInfo_Hash", - table: "FileInfo", - column: "Hash", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_FileInfo_ReferenceCount", - table: "FileInfo", - column: "ReferenceCount"); - - migrationBuilder.CreateIndex( - name: "IX_KeyBinding_Action", - table: "KeyBinding", - column: "Action"); - - migrationBuilder.CreateIndex( - name: "IX_KeyBinding_Variant", - table: "KeyBinding", - column: "Variant"); - - migrationBuilder.CreateIndex( - name: "IX_RulesetInfo_Available", - table: "RulesetInfo", - column: "Available"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "BeatmapInfo"); - - migrationBuilder.DropTable( - name: "BeatmapSetFileInfo"); - - migrationBuilder.DropTable( - name: "KeyBinding"); - - migrationBuilder.DropTable( - name: "BeatmapDifficulty"); - - migrationBuilder.DropTable( - name: "RulesetInfo"); - - migrationBuilder.DropTable( - name: "BeatmapSetInfo"); - - migrationBuilder.DropTable( - name: "FileInfo"); - - migrationBuilder.DropTable( - name: "BeatmapMetadata"); - } - } -} diff --git a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs deleted file mode 100644 index 4cd234f2ef..0000000000 --- a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.Designer.cs +++ /dev/null @@ -1,299 +0,0 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using osu.Game.Database; -using System; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20171025071459_AddMissingIndexRules")] - partial class AddMissingIndexRules - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MD5Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs b/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs deleted file mode 100644 index 4ec3952941..0000000000 --- a/osu.Game/Migrations/20171025071459_AddMissingIndexRules.cs +++ /dev/null @@ -1,83 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddMissingIndexRules : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_BeatmapSetInfo_Hash", - table: "BeatmapSetInfo"); - - migrationBuilder.DropIndex( - name: "IX_BeatmapInfo_Hash", - table: "BeatmapInfo"); - - migrationBuilder.DropIndex( - name: "IX_BeatmapInfo_MD5Hash", - table: "BeatmapInfo"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapSetInfo_Hash", - table: "BeatmapSetInfo", - column: "Hash", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapSetInfo_OnlineBeatmapSetID", - table: "BeatmapSetInfo", - column: "OnlineBeatmapSetID", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_Hash", - table: "BeatmapInfo", - column: "Hash", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_MD5Hash", - table: "BeatmapInfo", - column: "MD5Hash", - unique: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_BeatmapSetInfo_Hash", - table: "BeatmapSetInfo"); - - migrationBuilder.DropIndex( - name: "IX_BeatmapSetInfo_OnlineBeatmapSetID", - table: "BeatmapSetInfo"); - - migrationBuilder.DropIndex( - name: "IX_BeatmapInfo_Hash", - table: "BeatmapInfo"); - - migrationBuilder.DropIndex( - name: "IX_BeatmapInfo_MD5Hash", - table: "BeatmapInfo"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapSetInfo_Hash", - table: "BeatmapSetInfo", - column: "Hash"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_Hash", - table: "BeatmapInfo", - column: "Hash"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_MD5Hash", - table: "BeatmapInfo", - column: "MD5Hash"); - } - } -} diff --git a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs deleted file mode 100644 index 006acf12cd..0000000000 --- a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.Designer.cs +++ /dev/null @@ -1,302 +0,0 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using osu.Game.Database; -using System; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20171119065731_AddBeatmapOnlineIDUniqueConstraint")] - partial class AddBeatmapOnlineIDUniqueConstraint - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MD5Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs b/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs deleted file mode 100644 index 6aba12f86f..0000000000 --- a/osu.Game/Migrations/20171119065731_AddBeatmapOnlineIDUniqueConstraint.cs +++ /dev/null @@ -1,26 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddBeatmapOnlineIDUniqueConstraint : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_OnlineBeatmapID", - table: "BeatmapInfo", - column: "OnlineBeatmapID", - unique: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_BeatmapInfo_OnlineBeatmapID", - table: "BeatmapInfo"); - } - } -} diff --git a/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs b/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs deleted file mode 100644 index fc2496bc24..0000000000 --- a/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.Designer.cs +++ /dev/null @@ -1,307 +0,0 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using osu.Game.Database; -using System; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20171209034410_AddRulesetInfoShortName")] - partial class AddRulesetInfoShortName - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MD5Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.cs b/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.cs deleted file mode 100644 index 5688455f79..0000000000 --- a/osu.Game/Migrations/20171209034410_AddRulesetInfoShortName.cs +++ /dev/null @@ -1,36 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddRulesetInfoShortName : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "ShortName", - table: "RulesetInfo", - type: "TEXT", - nullable: true); - - migrationBuilder.CreateIndex( - name: "IX_RulesetInfo_ShortName", - table: "RulesetInfo", - column: "ShortName", - unique: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_RulesetInfo_ShortName", - table: "RulesetInfo"); - - migrationBuilder.DropColumn( - name: "ShortName", - table: "RulesetInfo"); - } - } -} diff --git a/osu.Game/Migrations/20180125143340_Settings.Designer.cs b/osu.Game/Migrations/20180125143340_Settings.Designer.cs deleted file mode 100644 index 4bb599eec1..0000000000 --- a/osu.Game/Migrations/20180125143340_Settings.Designer.cs +++ /dev/null @@ -1,329 +0,0 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using osu.Game.Database; -using System; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20180125143340_Settings")] - partial class Settings - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MD5Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntKey") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20180125143340_Settings.cs b/osu.Game/Migrations/20180125143340_Settings.cs deleted file mode 100644 index 1feb37531f..0000000000 --- a/osu.Game/Migrations/20180125143340_Settings.cs +++ /dev/null @@ -1,58 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class Settings : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_KeyBinding_Variant", - table: "KeyBinding"); - - migrationBuilder.CreateTable( - name: "Settings", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Key = table.Column(type: "TEXT", nullable: false), - RulesetID = table.Column(type: "INTEGER", nullable: true), - Value = table.Column(type: "TEXT", nullable: true), - Variant = table.Column(type: "INTEGER", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Settings", x => x.ID); - }); - - migrationBuilder.CreateIndex( - name: "IX_KeyBinding_RulesetID_Variant", - table: "KeyBinding", - columns: new[] { "RulesetID", "Variant" }); - - migrationBuilder.CreateIndex( - name: "IX_Settings_RulesetID_Variant", - table: "Settings", - columns: new[] { "RulesetID", "Variant" }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Settings"); - - migrationBuilder.DropIndex( - name: "IX_KeyBinding_RulesetID_Variant", - table: "KeyBinding"); - - migrationBuilder.CreateIndex( - name: "IX_KeyBinding_Variant", - table: "KeyBinding", - column: "Variant"); - } - } -} diff --git a/osu.Game/Migrations/20180131154205_AddMuteBinding.cs b/osu.Game/Migrations/20180131154205_AddMuteBinding.cs deleted file mode 100644 index 8646d1d76b..0000000000 --- a/osu.Game/Migrations/20180131154205_AddMuteBinding.cs +++ /dev/null @@ -1,26 +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 Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Infrastructure; -using osu.Game.Database; -using osu.Game.Input.Bindings; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20180131154205_AddMuteBinding")] - public partial class AddMuteBinding : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.Sql($"UPDATE KeyBinding SET Action = Action + 1 WHERE RulesetID IS NULL AND Variant IS NULL AND Action >= {(int)GlobalAction.ToggleMute}"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.Sql($"DELETE FROM KeyBinding WHERE RulesetID IS NULL AND Variant IS NULL AND Action = {(int)GlobalAction.ToggleMute}"); - migrationBuilder.Sql($"UPDATE KeyBinding SET Action = Action - 1 WHERE RulesetID IS NULL AND Variant IS NULL AND Action > {(int)GlobalAction.ToggleMute}"); - } - } -} diff --git a/osu.Game/Migrations/20180219060912_AddSkins.Designer.cs b/osu.Game/Migrations/20180219060912_AddSkins.Designer.cs deleted file mode 100644 index cdc4ef2e66..0000000000 --- a/osu.Game/Migrations/20180219060912_AddSkins.Designer.cs +++ /dev/null @@ -1,379 +0,0 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using osu.Game.Database; -using System; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20180219060912_AddSkins")] - partial class AddSkins - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MD5Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntKey") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20180219060912_AddSkins.cs b/osu.Game/Migrations/20180219060912_AddSkins.cs deleted file mode 100644 index 319748bed6..0000000000 --- a/osu.Game/Migrations/20180219060912_AddSkins.cs +++ /dev/null @@ -1,74 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddSkins : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "SkinInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Creator = table.Column(type: "TEXT", nullable: true), - DeletePending = table.Column(type: "INTEGER", nullable: false), - Name = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_SkinInfo", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "SkinFileInfo", - columns: table => new - { - ID = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - FileInfoID = table.Column(type: "INTEGER", nullable: false), - Filename = table.Column(type: "TEXT", nullable: false), - SkinInfoID = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_SkinFileInfo", x => x.ID); - table.ForeignKey( - name: "FK_SkinFileInfo_FileInfo_FileInfoID", - column: x => x.FileInfoID, - principalTable: "FileInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_SkinFileInfo_SkinInfo_SkinInfoID", - column: x => x.SkinInfoID, - principalTable: "SkinInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_SkinFileInfo_FileInfoID", - table: "SkinFileInfo", - column: "FileInfoID"); - - migrationBuilder.CreateIndex( - name: "IX_SkinFileInfo_SkinInfoID", - table: "SkinFileInfo", - column: "SkinInfoID"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "SkinFileInfo"); - - migrationBuilder.DropTable( - name: "SkinInfo"); - } - } -} diff --git a/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs b/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs deleted file mode 100644 index f28408bfb3..0000000000 --- a/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.Designer.cs +++ /dev/null @@ -1,377 +0,0 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage; -using osu.Game.Database; -using System; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20180529055154_RemoveUniqueHashConstraints")] - partial class RemoveUniqueHashConstraints - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.0.3-rtm-10026"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntKey") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs b/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs deleted file mode 100644 index 91eabe8868..0000000000 --- a/osu.Game/Migrations/20180529055154_RemoveUniqueHashConstraints.cs +++ /dev/null @@ -1,54 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class RemoveUniqueHashConstraints : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_BeatmapInfo_Hash", - table: "BeatmapInfo"); - - migrationBuilder.DropIndex( - name: "IX_BeatmapInfo_MD5Hash", - table: "BeatmapInfo"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_Hash", - table: "BeatmapInfo", - column: "Hash"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_MD5Hash", - table: "BeatmapInfo", - column: "MD5Hash"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_BeatmapInfo_Hash", - table: "BeatmapInfo"); - - migrationBuilder.DropIndex( - name: "IX_BeatmapInfo_MD5Hash", - table: "BeatmapInfo"); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_Hash", - table: "BeatmapInfo", - column: "Hash", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_BeatmapInfo_MD5Hash", - table: "BeatmapInfo", - column: "MD5Hash", - unique: true); - } - } -} diff --git a/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs b/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs deleted file mode 100644 index aaa11e88b6..0000000000 --- a/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.Designer.cs +++ /dev/null @@ -1,376 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20180621044111_UpdateTaikoDefaultBindings")] - partial class UpdateTaikoDefaultBindings - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.1.1-rtm-30846"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntKey") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs b/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs deleted file mode 100644 index d888ccd5a2..0000000000 --- a/osu.Game/Migrations/20180621044111_UpdateTaikoDefaultBindings.cs +++ /dev/null @@ -1,20 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class UpdateTaikoDefaultBindings : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.Sql("DELETE FROM KeyBinding WHERE RulesetID = 1"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - // we can't really tell if these should be restored or not, so let's just not do so. - } - } -} diff --git a/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.Designer.cs b/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.Designer.cs deleted file mode 100644 index 7eeacd56d7..0000000000 --- a/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.Designer.cs +++ /dev/null @@ -1,376 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20180628011956_RemoveNegativeSetIDs")] - partial class RemoveNegativeSetIDs - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.1.1-rtm-30846"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntKey") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs b/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs deleted file mode 100644 index fdea636ac6..0000000000 --- a/osu.Game/Migrations/20180628011956_RemoveNegativeSetIDs.cs +++ /dev/null @@ -1,21 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class RemoveNegativeSetIDs : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - // There was a change that beatmaps were being loaded with "-1" online IDs, which is completely incorrect. - // This ensures there will not be unique key conflicts as a result of these incorrectly imported beatmaps. - migrationBuilder.Sql("UPDATE BeatmapSetInfo SET OnlineBeatmapSetID = null WHERE OnlineBeatmapSetID <= 0"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - } - } -} diff --git a/osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs b/osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs deleted file mode 100644 index 5ab43da046..0000000000 --- a/osu.Game/Migrations/20180913080842_AddRankStatus.Designer.cs +++ /dev/null @@ -1,380 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20180913080842_AddRankStatus")] - partial class AddRankStatus - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.1.2-rtm-30932"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntKey") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20180913080842_AddRankStatus.cs b/osu.Game/Migrations/20180913080842_AddRankStatus.cs deleted file mode 100644 index bb147dff84..0000000000 --- a/osu.Game/Migrations/20180913080842_AddRankStatus.cs +++ /dev/null @@ -1,36 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddRankStatus : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "Status", - table: "BeatmapSetInfo", - nullable: false, - defaultValue: -3); // NONE - - migrationBuilder.AddColumn( - name: "Status", - table: "BeatmapInfo", - nullable: false, - defaultValue: -3); // NONE - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "Status", - table: "BeatmapSetInfo"); - - migrationBuilder.DropColumn( - name: "Status", - table: "BeatmapInfo"); - } - } -} diff --git a/osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs b/osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs deleted file mode 100644 index b387a45ecf..0000000000 --- a/osu.Game/Migrations/20181007180454_StandardizePaths.Designer.cs +++ /dev/null @@ -1,380 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20181007180454_StandardizePaths")] - partial class StandardizePaths - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.1.3-rtm-32065"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntKey") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20181007180454_StandardizePaths.cs b/osu.Game/Migrations/20181007180454_StandardizePaths.cs deleted file mode 100644 index 30f27043a0..0000000000 --- a/osu.Game/Migrations/20181007180454_StandardizePaths.cs +++ /dev/null @@ -1,27 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class StandardizePaths : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - string windowsStyle = @"\"; - string standardized = "/"; - - // Escaping \ does not seem to be needed. - migrationBuilder.Sql($"UPDATE `BeatmapInfo` SET `Path` = REPLACE(`Path`, '{windowsStyle}', '{standardized}')"); - migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `AudioFile` = REPLACE(`AudioFile`, '{windowsStyle}', '{standardized}')"); - migrationBuilder.Sql($"UPDATE `BeatmapMetadata` SET `BackgroundFile` = REPLACE(`BackgroundFile`, '{windowsStyle}', '{standardized}')"); - migrationBuilder.Sql($"UPDATE `BeatmapSetFileInfo` SET `Filename` = REPLACE(`Filename`, '{windowsStyle}', '{standardized}')"); - migrationBuilder.Sql($"UPDATE `SkinFileInfo` SET `Filename` = REPLACE(`Filename`, '{windowsStyle}', '{standardized}')"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - } - } -} diff --git a/osu.Game/Migrations/20181128100659_AddSkinInfoHash.Designer.cs b/osu.Game/Migrations/20181128100659_AddSkinInfoHash.Designer.cs deleted file mode 100644 index 120674671a..0000000000 --- a/osu.Game/Migrations/20181128100659_AddSkinInfoHash.Designer.cs +++ /dev/null @@ -1,387 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20181128100659_AddSkinInfoHash")] - partial class AddSkinInfoHash - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.1.4-rtm-31024"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntKey") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20181128100659_AddSkinInfoHash.cs b/osu.Game/Migrations/20181128100659_AddSkinInfoHash.cs deleted file mode 100644 index ee825a1e9c..0000000000 --- a/osu.Game/Migrations/20181128100659_AddSkinInfoHash.cs +++ /dev/null @@ -1,44 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddSkinInfoHash : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "Hash", - table: "SkinInfo", - nullable: true); - - migrationBuilder.CreateIndex( - name: "IX_SkinInfo_DeletePending", - table: "SkinInfo", - column: "DeletePending"); - - migrationBuilder.CreateIndex( - name: "IX_SkinInfo_Hash", - table: "SkinInfo", - column: "Hash", - unique: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex( - name: "IX_SkinInfo_DeletePending", - table: "SkinInfo"); - - migrationBuilder.DropIndex( - name: "IX_SkinInfo_Hash", - table: "SkinInfo"); - - migrationBuilder.DropColumn( - name: "Hash", - table: "SkinInfo"); - } - } -} diff --git a/osu.Game/Migrations/20181130113755_AddScoreInfoTables.Designer.cs b/osu.Game/Migrations/20181130113755_AddScoreInfoTables.Designer.cs deleted file mode 100644 index eee53182ce..0000000000 --- a/osu.Game/Migrations/20181130113755_AddScoreInfoTables.Designer.cs +++ /dev/null @@ -1,484 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20181130113755_AddScoreInfoTables")] - partial class AddScoreInfoTables - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.1.4-rtm-31024"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntKey") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany() - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20181130113755_AddScoreInfoTables.cs b/osu.Game/Migrations/20181130113755_AddScoreInfoTables.cs deleted file mode 100644 index 58980132f3..0000000000 --- a/osu.Game/Migrations/20181130113755_AddScoreInfoTables.cs +++ /dev/null @@ -1,115 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddScoreInfoTables : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "ScoreInfo", - columns: table => new - { - ID = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Rank = table.Column(nullable: false), - TotalScore = table.Column(nullable: false), - Accuracy = table.Column(type: "DECIMAL(1,4)", nullable: false), - PP = table.Column(nullable: true), - MaxCombo = table.Column(nullable: false), - Combo = table.Column(nullable: false), - RulesetID = table.Column(nullable: false), - Mods = table.Column(nullable: true), - User = table.Column(nullable: true), - BeatmapInfoID = table.Column(nullable: false), - OnlineScoreID = table.Column(nullable: true), - Date = table.Column(nullable: false), - Statistics = table.Column(nullable: true), - Hash = table.Column(nullable: true), - DeletePending = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_ScoreInfo", x => x.ID); - table.ForeignKey( - name: "FK_ScoreInfo_BeatmapInfo_BeatmapInfoID", - column: x => x.BeatmapInfoID, - principalTable: "BeatmapInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_ScoreInfo_RulesetInfo_RulesetID", - column: x => x.RulesetID, - principalTable: "RulesetInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "ScoreFileInfo", - columns: table => new - { - ID = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - FileInfoID = table.Column(nullable: false), - Filename = table.Column(nullable: false), - ScoreInfoID = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_ScoreFileInfo", x => x.ID); - table.ForeignKey( - name: "FK_ScoreFileInfo_FileInfo_FileInfoID", - column: x => x.FileInfoID, - principalTable: "FileInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_ScoreFileInfo_ScoreInfo_ScoreInfoID", - column: x => x.ScoreInfoID, - principalTable: "ScoreInfo", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateIndex( - name: "IX_ScoreFileInfo_FileInfoID", - table: "ScoreFileInfo", - column: "FileInfoID"); - - migrationBuilder.CreateIndex( - name: "IX_ScoreFileInfo_ScoreInfoID", - table: "ScoreFileInfo", - column: "ScoreInfoID"); - - migrationBuilder.CreateIndex( - name: "IX_ScoreInfo_BeatmapInfoID", - table: "ScoreInfo", - column: "BeatmapInfoID"); - - migrationBuilder.CreateIndex( - name: "IX_ScoreInfo_OnlineScoreID", - table: "ScoreInfo", - column: "OnlineScoreID", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_ScoreInfo_RulesetID", - table: "ScoreInfo", - column: "RulesetID"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "ScoreFileInfo"); - - migrationBuilder.DropTable( - name: "ScoreInfo"); - } - } -} diff --git a/osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs b/osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs deleted file mode 100644 index 8e1e3a59f3..0000000000 --- a/osu.Game/Migrations/20190225062029_AddUserIDColumn.Designer.cs +++ /dev/null @@ -1,487 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20190225062029_AddUserIDColumn")] - partial class AddUserIDColumn - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.1-servicing-10028"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntKey") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20190225062029_AddUserIDColumn.cs b/osu.Game/Migrations/20190225062029_AddUserIDColumn.cs deleted file mode 100644 index f2eef600dc..0000000000 --- a/osu.Game/Migrations/20190225062029_AddUserIDColumn.cs +++ /dev/null @@ -1,25 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddUserIDColumn : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "UserID", - table: "ScoreInfo", - nullable: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "UserID", - table: "ScoreInfo"); - } - } -} diff --git a/osu.Game/Migrations/20190525060824_SkinSettings.Designer.cs b/osu.Game/Migrations/20190525060824_SkinSettings.Designer.cs deleted file mode 100644 index 348c42adb9..0000000000 --- a/osu.Game/Migrations/20190525060824_SkinSettings.Designer.cs +++ /dev/null @@ -1,498 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20190525060824_SkinSettings")] - partial class SkinSettings - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.4-servicing-10062"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20190525060824_SkinSettings.cs b/osu.Game/Migrations/20190525060824_SkinSettings.cs deleted file mode 100644 index 7779b55bb7..0000000000 --- a/osu.Game/Migrations/20190525060824_SkinSettings.cs +++ /dev/null @@ -1,57 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class SkinSettings : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.Sql(@"create table Settings_dg_tmp - ( - ID INTEGER not null - constraint PK_Settings - primary key autoincrement, - Key TEXT not null, - RulesetID INTEGER, - Value TEXT, - Variant INTEGER, - SkinInfoID int - constraint Settings_SkinInfo_ID_fk - references SkinInfo - on delete restrict - ); - - insert into Settings_dg_tmp(ID, Key, RulesetID, Value, Variant) select ID, Key, RulesetID, Value, Variant from Settings; - - drop table Settings; - - alter table Settings_dg_tmp rename to Settings; - - create index IX_Settings_RulesetID_Variant - on Settings (RulesetID, Variant); - - create index Settings_SkinInfoID_index - on Settings (SkinInfoID); - - "); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Settings_SkinInfo_SkinInfoID", - table: "Settings"); - - migrationBuilder.DropIndex( - name: "IX_Settings_SkinInfoID", - table: "Settings"); - - migrationBuilder.DropColumn( - name: "SkinInfoID", - table: "Settings"); - } - } -} diff --git a/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.Designer.cs b/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.Designer.cs deleted file mode 100644 index 9477369aa0..0000000000 --- a/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.Designer.cs +++ /dev/null @@ -1,489 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20190605091246_AddDateAddedColumnToBeatmapSet")] - partial class AddDateAddedColumnToBeatmapSet - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.4-servicing-10062"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.cs b/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.cs deleted file mode 100644 index 0620a0624f..0000000000 --- a/osu.Game/Migrations/20190605091246_AddDateAddedColumnToBeatmapSet.cs +++ /dev/null @@ -1,27 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddDateAddedColumnToBeatmapSet : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "DateAdded", - table: "BeatmapSetInfo", - nullable: false, - defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "DateAdded", - table: "BeatmapSetInfo"); - } - } -} diff --git a/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs b/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs deleted file mode 100644 index c5fcc16f84..0000000000 --- a/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.Designer.cs +++ /dev/null @@ -1,504 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20190708070844_AddBPMAndLengthColumns")] - partial class AddBPMAndLengthColumns - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.4-servicing-10062"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BPM"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("Length"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs b/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs deleted file mode 100644 index f8ce354aa1..0000000000 --- a/osu.Game/Migrations/20190708070844_AddBPMAndLengthColumns.cs +++ /dev/null @@ -1,36 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddBPMAndLengthColumns : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "BPM", - table: "BeatmapInfo", - nullable: false, - defaultValue: 0.0); - - migrationBuilder.AddColumn( - name: "Length", - table: "BeatmapInfo", - nullable: false, - defaultValue: 0.0); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "BPM", - table: "BeatmapInfo"); - - migrationBuilder.DropColumn( - name: "Length", - table: "BeatmapInfo"); - } - } -} diff --git a/osu.Game/Migrations/20190913104727_AddBeatmapVideo.Designer.cs b/osu.Game/Migrations/20190913104727_AddBeatmapVideo.Designer.cs deleted file mode 100644 index 826233a2b0..0000000000 --- a/osu.Game/Migrations/20190913104727_AddBeatmapVideo.Designer.cs +++ /dev/null @@ -1,506 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20190913104727_AddBeatmapVideo")] - partial class AddBeatmapVideo - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BPM"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("Length"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.Property("VideoFile"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20190913104727_AddBeatmapVideo.cs b/osu.Game/Migrations/20190913104727_AddBeatmapVideo.cs deleted file mode 100644 index af82b4db20..0000000000 --- a/osu.Game/Migrations/20190913104727_AddBeatmapVideo.cs +++ /dev/null @@ -1,25 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddBeatmapVideo : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "VideoFile", - table: "BeatmapMetadata", - nullable: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "VideoFile", - table: "BeatmapMetadata"); - } - } -} diff --git a/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs b/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs deleted file mode 100644 index 22316b0380..0000000000 --- a/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs +++ /dev/null @@ -1,506 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20200302094919_RefreshVolumeBindings")] - partial class RefreshVolumeBindings - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BPM"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("Length"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.Property("VideoFile"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs b/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs deleted file mode 100644 index 3d2ddbf6fc..0000000000 --- a/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs +++ /dev/null @@ -1,19 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class RefreshVolumeBindings : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.Sql("DELETE FROM KeyBinding WHERE action in (6,7)"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - } - } -} diff --git a/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.Designer.cs b/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.Designer.cs deleted file mode 100644 index 1c05de832e..0000000000 --- a/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.Designer.cs +++ /dev/null @@ -1,508 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20201019224408_AddEpilepsyWarning")] - partial class AddEpilepsyWarning - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BPM"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("EpilepsyWarning"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("Length"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.Property("VideoFile"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.cs b/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.cs deleted file mode 100644 index 58a35a7bf3..0000000000 --- a/osu.Game/Migrations/20201019224408_AddEpilepsyWarning.cs +++ /dev/null @@ -1,26 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddEpilepsyWarning : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "EpilepsyWarning", - table: "BeatmapInfo", - nullable: false, - defaultValue: false); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "EpilepsyWarning", - table: "BeatmapInfo"); - } - } -} diff --git a/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.Designer.cs b/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.Designer.cs deleted file mode 100644 index 2c100d39b9..0000000000 --- a/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.Designer.cs +++ /dev/null @@ -1,506 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20210412045700_RefreshVolumeBindingsAgain")] - partial class RefreshVolumeBindingsAgain - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BPM"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("Length"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.Property("VideoFile"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.cs b/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.cs deleted file mode 100644 index 4d3941dd20..0000000000 --- a/osu.Game/Migrations/20210412045700_RefreshVolumeBindingsAgain.cs +++ /dev/null @@ -1,19 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class RefreshVolumeBindingsAgain : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.Sql("DELETE FROM KeyBinding WHERE action in (6,7)"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - } - } -} diff --git a/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.Designer.cs b/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.Designer.cs deleted file mode 100644 index b808c648da..0000000000 --- a/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.Designer.cs +++ /dev/null @@ -1,508 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20210511060743_AddSkinInstantiationInfo")] - partial class AddSkinInstantiationInfo - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BPM"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("EpilepsyWarning"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("Length"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.cs b/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.cs deleted file mode 100644 index 887635fa85..0000000000 --- a/osu.Game/Migrations/20210511060743_AddSkinInstantiationInfo.cs +++ /dev/null @@ -1,25 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddSkinInstantiationInfo : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "InstantiationInfo", - table: "SkinInfo", - nullable: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "InstantiationInfo", - table: "SkinInfo"); - } - } -} diff --git a/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs b/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs deleted file mode 100644 index 89bab3a0fa..0000000000 --- a/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.Designer.cs +++ /dev/null @@ -1,511 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20210514062639_AddAuthorIdToBeatmapMetadata")] - partial class AddAuthorIdToBeatmapMetadata - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BPM"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("DistanceSpacing"); - - b.Property("EpilepsyWarning"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("Length"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorID") - .HasColumnName("AuthorID"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.cs b/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.cs deleted file mode 100644 index 7b579e27b9..0000000000 --- a/osu.Game/Migrations/20210514062639_AddAuthorIdToBeatmapMetadata.cs +++ /dev/null @@ -1,26 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddAuthorIdToBeatmapMetadata : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "AuthorID", - table: "BeatmapMetadata", - nullable: false, - defaultValue: 0); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "AuthorID", - table: "BeatmapMetadata"); - } - } -} diff --git a/osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs b/osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs deleted file mode 100644 index afeb42130d..0000000000 --- a/osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs +++ /dev/null @@ -1,513 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20210824185035_AddCountdownSettings")] - partial class AddCountdownSettings - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BPM"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("CountdownOffset"); - - b.Property("DistanceSpacing"); - - b.Property("EpilepsyWarning"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("Length"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorID") - .HasColumnName("AuthorID"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20210824185035_AddCountdownSettings.cs b/osu.Game/Migrations/20210824185035_AddCountdownSettings.cs deleted file mode 100644 index d1b09e2c1d..0000000000 --- a/osu.Game/Migrations/20210824185035_AddCountdownSettings.cs +++ /dev/null @@ -1,26 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddCountdownSettings : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "CountdownOffset", - table: "BeatmapInfo", - nullable: false, - defaultValue: 0); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "CountdownOffset", - table: "BeatmapInfo"); - } - } -} diff --git a/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs b/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs deleted file mode 100644 index 6e53d7fae0..0000000000 --- a/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs +++ /dev/null @@ -1,515 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20210912144011_AddSamplesMatchPlaybackRate")] - partial class AddSamplesMatchPlaybackRate - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BPM"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("CountdownOffset"); - - b.Property("DistanceSpacing"); - - b.Property("EpilepsyWarning"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("Length"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SamplesMatchPlaybackRate"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorID") - .HasColumnName("AuthorID"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs b/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs deleted file mode 100644 index f6fc1f4420..0000000000 --- a/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs +++ /dev/null @@ -1,26 +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 Microsoft.EntityFrameworkCore.Migrations; - -namespace osu.Game.Migrations -{ - public partial class AddSamplesMatchPlaybackRate : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "SamplesMatchPlaybackRate", - table: "BeatmapInfo", - nullable: false, - defaultValue: false); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "SamplesMatchPlaybackRate", - table: "BeatmapInfo"); - } - } -} diff --git a/osu.Game/Migrations/20211020081609_ResetSkinHashes.cs b/osu.Game/Migrations/20211020081609_ResetSkinHashes.cs deleted file mode 100644 index 6d53c019ec..0000000000 --- a/osu.Game/Migrations/20211020081609_ResetSkinHashes.cs +++ /dev/null @@ -1,23 +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 Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - [Migration("20211020081609_ResetSkinHashes")] - public partial class ResetSkinHashes : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.Sql($"UPDATE SkinInfo SET Hash = null"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - } - } -} diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs deleted file mode 100644 index 036c26cb0a..0000000000 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ /dev/null @@ -1,513 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using osu.Game.Database; - -namespace osu.Game.Migrations -{ - [DbContext(typeof(OsuDbContext))] - partial class OsuDbContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("ApproachRate"); - - b.Property("CircleSize"); - - b.Property("DrainRate"); - - b.Property("OverallDifficulty"); - - b.Property("SliderMultiplier"); - - b.Property("SliderTickRate"); - - b.HasKey("ID"); - - b.ToTable("BeatmapDifficulty"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("AudioLeadIn"); - - b.Property("BPM"); - - b.Property("BaseDifficultyID"); - - b.Property("BeatDivisor"); - - b.Property("BeatmapSetInfoID"); - - b.Property("Countdown"); - - b.Property("CountdownOffset"); - - b.Property("DistanceSpacing"); - - b.Property("EpilepsyWarning"); - - b.Property("GridSize"); - - b.Property("Hash"); - - b.Property("Hidden"); - - b.Property("Length"); - - b.Property("LetterboxInBreaks"); - - b.Property("MD5Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapID"); - - b.Property("Path"); - - b.Property("RulesetID"); - - b.Property("SamplesMatchPlaybackRate"); - - b.Property("SpecialStyle"); - - b.Property("StackLeniency"); - - b.Property("StarDifficulty"); - - b.Property("Status"); - - b.Property("StoredBookmarks"); - - b.Property("TimelineZoom"); - - b.Property("Version"); - - b.Property("WidescreenStoryboard"); - - b.HasKey("ID"); - - b.HasIndex("BaseDifficultyID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("Hash"); - - b.HasIndex("MD5Hash"); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("BeatmapInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Artist"); - - b.Property("ArtistUnicode"); - - b.Property("AudioFile"); - - b.Property("AuthorID") - .HasColumnName("AuthorID"); - - b.Property("AuthorString") - .HasColumnName("Author"); - - b.Property("BackgroundFile"); - - b.Property("PreviewTime"); - - b.Property("Source"); - - b.Property("Tags"); - - b.Property("Title"); - - b.Property("TitleUnicode"); - - b.HasKey("ID"); - - b.ToTable("BeatmapMetadata"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("BeatmapSetInfoID"); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.HasKey("ID"); - - b.HasIndex("BeatmapSetInfoID"); - - b.HasIndex("FileInfoID"); - - b.ToTable("BeatmapSetFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("DateAdded"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MetadataID"); - - b.Property("OnlineBeatmapSetID"); - - b.Property("Protected"); - - b.Property("Status"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("MetadataID"); - - b.HasIndex("OnlineBeatmapSetID") - .IsUnique(); - - b.ToTable("BeatmapSetInfo"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Key") - .HasColumnName("Key"); - - b.Property("RulesetID"); - - b.Property("SkinInfoID"); - - b.Property("StringValue") - .HasColumnName("Value"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("SkinInfoID"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("Settings"); - }); - - modelBuilder.Entity("osu.Game.IO.FileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Hash"); - - b.Property("ReferenceCount"); - - b.HasKey("ID"); - - b.HasIndex("Hash") - .IsUnique(); - - b.HasIndex("ReferenceCount"); - - b.ToTable("FileInfo"); - }); - - modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("IntAction") - .HasColumnName("Action"); - - b.Property("KeysString") - .HasColumnName("Keys"); - - b.Property("RulesetID"); - - b.Property("Variant"); - - b.HasKey("ID"); - - b.HasIndex("IntAction"); - - b.HasIndex("RulesetID", "Variant"); - - b.ToTable("KeyBinding"); - }); - - modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Available"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.Property("ShortName"); - - b.HasKey("ID"); - - b.HasIndex("Available"); - - b.HasIndex("ShortName") - .IsUnique(); - - b.ToTable("RulesetInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("ScoreInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("ScoreInfoID"); - - b.ToTable("ScoreFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Accuracy") - .HasColumnType("DECIMAL(1,4)"); - - b.Property("BeatmapInfoID"); - - b.Property("Combo"); - - b.Property("Date"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("MaxCombo"); - - b.Property("ModsJson") - .HasColumnName("Mods"); - - b.Property("OnlineScoreID"); - - b.Property("PP"); - - b.Property("Rank"); - - b.Property("RulesetID"); - - b.Property("StatisticsJson") - .HasColumnName("Statistics"); - - b.Property("TotalScore"); - - b.Property("UserID") - .HasColumnName("UserID"); - - b.Property("UserString") - .HasColumnName("User"); - - b.HasKey("ID"); - - b.HasIndex("BeatmapInfoID"); - - b.HasIndex("OnlineScoreID") - .IsUnique(); - - b.HasIndex("RulesetID"); - - b.ToTable("ScoreInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("FileInfoID"); - - b.Property("Filename") - .IsRequired(); - - b.Property("SkinInfoID"); - - b.HasKey("ID"); - - b.HasIndex("FileInfoID"); - - b.HasIndex("SkinInfoID"); - - b.ToTable("SkinFileInfo"); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => - { - b.Property("ID") - .ValueGeneratedOnAdd(); - - b.Property("Creator"); - - b.Property("DeletePending"); - - b.Property("Hash"); - - b.Property("InstantiationInfo"); - - b.Property("Name"); - - b.HasKey("ID"); - - b.HasIndex("DeletePending"); - - b.HasIndex("Hash") - .IsUnique(); - - b.ToTable("SkinInfo"); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") - .WithMany() - .HasForeignKey("BaseDifficultyID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") - .WithMany("Beatmaps") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("Beatmaps") - .HasForeignKey("MetadataID"); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") - .WithMany("Files") - .HasForeignKey("BeatmapSetInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") - .WithMany("BeatmapSets") - .HasForeignKey("MetadataID"); - }); - - modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => - { - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Settings") - .HasForeignKey("SkinInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Scoring.ScoreInfo") - .WithMany("Files") - .HasForeignKey("ScoreInfoID"); - }); - - modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => - { - b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") - .WithMany("Scores") - .HasForeignKey("BeatmapInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") - .WithMany() - .HasForeignKey("RulesetID") - .OnDelete(DeleteBehavior.Cascade); - }); - - modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => - { - b.HasOne("osu.Game.IO.FileInfo", "FileInfo") - .WithMany() - .HasForeignKey("FileInfoID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("osu.Game.Skinning.SkinInfo") - .WithMany("Files") - .HasForeignKey("SkinInfoID") - .OnDelete(DeleteBehavior.Cascade); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 97142d5472..b30a065371 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -199,11 +199,6 @@ namespace osu.Game private readonly BindableNumber globalTrackVolumeAdjust = new BindableNumber(global_track_volume_adjust); - /// - /// A legacy EF context factory if migration has not been performed to realm yet. - /// - protected DatabaseContextFactory EFContextFactory { get; private set; } - /// /// Number of unhandled exceptions to allow before aborting execution. /// @@ -242,10 +237,7 @@ namespace osu.Game Resources.AddStore(new DllResourceStore(OsuResources.ResourceAssembly)); - if (Storage.Exists(DatabaseContextFactory.DATABASE_NAME)) - dependencies.Cache(EFContextFactory = new DatabaseContextFactory(Storage)); - - dependencies.Cache(realm = new RealmAccess(Storage, CLIENT_DATABASE_FILENAME, Host.UpdateThread, EFContextFactory)); + dependencies.Cache(realm = new RealmAccess(Storage, CLIENT_DATABASE_FILENAME, Host.UpdateThread)); dependencies.CacheAs(RulesetStore = new RealmRulesetStore(realm, Storage)); dependencies.CacheAs(RulesetStore); diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index dbb1278d76..afba00274c 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -14,7 +14,6 @@ using osu.Game.Screens.Menu; using osu.Framework.Screens; using osu.Framework.Threading; using osu.Game.Configuration; -using osu.Game.Database; using osu.Game.Graphics.UserInterface; using IntroSequence = osu.Game.Configuration.IntroSequence; @@ -66,32 +65,13 @@ namespace osu.Game.Screens protected virtual ShaderPrecompiler CreateShaderPrecompiler() => new ShaderPrecompiler(); - [Resolved(canBeNull: true)] - private DatabaseContextFactory efContextFactory { get; set; } - - private EFToRealmMigrator realmMigrator; - public override void OnEntering(ScreenTransitionEvent e) { base.OnEntering(e); LoadComponentAsync(precompiler = CreateShaderPrecompiler(), AddInternal); - // A non-null context factory means there's still content to migrate. - if (efContextFactory != null) - { - LoadComponentAsync(realmMigrator = new EFToRealmMigrator(), AddInternal); - realmMigrator.MigrationCompleted.ContinueWith(_ => Schedule(() => - { - // Delay initial screen loading to ensure that the migration is in a complete and sane state - // before the intro screen may import the game intro beatmap. - LoadComponentAsync(loadableScreen = CreateLoadableScreen()); - })); - } - else - { - LoadComponentAsync(loadableScreen = CreateLoadableScreen()); - } + LoadComponentAsync(loadableScreen = CreateLoadableScreen()); LoadComponentAsync(spinner = new LoadingSpinner(true, true) { diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 3ad29ea6db..44df495929 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -807,7 +807,6 @@ See the LICENCE file in the repository root for full licence text. True True - True True True True From 0aa92c78ec0ae000f8f241db3b5a65a6ea28b7bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 16:34:35 +0900 Subject: [PATCH 1128/2686] Add local sqlite initialisation to `BeatmapUpdaterMetadataLookup` for now --- osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index aa773da6d3..007bec46bb 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -19,6 +19,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using SharpCompress.Compressors; using SharpCompress.Compressors.BZip2; +using SQLitePCL; namespace osu.Game.Beatmaps { @@ -41,6 +42,10 @@ namespace osu.Game.Beatmaps public BeatmapUpdaterMetadataLookup(IAPIProvider api, Storage storage) { + // required to initialise native SQLite libraries on some platforms. + Batteries_V2.Init(); + raw.sqlite3_config(2 /*SQLITE_CONFIG_MULTITHREAD*/); + this.api = api; this.storage = storage; From 581a4d2d6d033069af55d972e345f0d63b29a2fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 16:39:59 +0900 Subject: [PATCH 1129/2686] Use `APIBeatmap` for realm migration requiring `ShortName` mapping --- osu.Game/Database/RealmAccess.cs | 20 ++++++++++++------- .../API/Requests/Responses/APIBeatmap.cs | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index e23fc912df..cefc7da503 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -24,6 +24,7 @@ using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Input.Bindings; using osu.Game.Models; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; @@ -45,8 +46,6 @@ namespace osu.Game.Database /// public readonly string Filename; - private readonly IDatabaseContextFactory? efContextFactory; - private readonly SynchronizationContext? updateThreadSyncContext; /// @@ -162,11 +161,9 @@ namespace osu.Game.Database /// The game storage which will be used to create the realm backing file. /// The filename to use for the realm backing file. A ".realm" extension will be added automatically if not specified. /// The game update thread, used to post realm operations into a thread-safe context. - /// An EF factory used only for migration purposes. - public RealmAccess(Storage storage, string filename, GameThread? updateThread = null, IDatabaseContextFactory? efContextFactory = null) + public RealmAccess(Storage storage, string filename, GameThread? updateThread = null) { this.storage = storage; - this.efContextFactory = efContextFactory; updateThreadSyncContext = updateThread?.SynchronizationContext ?? SynchronizationContext.Current; @@ -876,8 +873,17 @@ namespace osu.Game.Database } } - private string? getRulesetShortNameFromLegacyID(long rulesetId) => - efContextFactory?.Get().RulesetInfo.FirstOrDefault(r => r.ID == rulesetId)?.ShortName; + private string? getRulesetShortNameFromLegacyID(long rulesetId) + { + try + { + return new APIBeatmap.APIRuleset { OnlineID = (int)rulesetId }.ShortName; + } + catch + { + return null; + } + } /// /// Create a full realm backup. diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 3fee81cf33..8a77801c3a 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -111,7 +111,7 @@ namespace osu.Game.Online.API.Requests.Responses public bool Equals(IBeatmapInfo? other) => other is APIBeatmap b && this.MatchesOnlineID(b); - private class APIRuleset : IRulesetInfo + public class APIRuleset : IRulesetInfo { public int OnlineID { get; set; } = -1; From 65d1c40dd54ec556ca28e30f01bfb16a56a5e048 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 16:47:26 +0900 Subject: [PATCH 1130/2686] Remove remaining package references and replace with `SQLitePCLRaw` direct reference This may require further consideration for test and iOS projects. --- .../osu.Game.Rulesets.EmptyFreeform.Tests.csproj | 1 - .../osu.Game.Rulesets.Pippidon.Tests.csproj | 1 - .../osu.Game.Rulesets.EmptyScrolling.Tests.csproj | 1 - .../osu.Game.Rulesets.Pippidon.Tests.csproj | 1 - osu.Desktop/osu.Desktop.csproj | 1 - .../osu.Game.Rulesets.Catch.Tests.csproj | 1 - .../osu.Game.Rulesets.Mania.Tests.csproj | 1 - .../osu.Game.Rulesets.Osu.Tests.csproj | 1 - .../osu.Game.Rulesets.Taiko.Tests.csproj | 1 - osu.Game.Tests/osu.Game.Tests.csproj | 1 - osu.Game/osu.Game.csproj | 4 ++-- osu.iOS.props | 2 -- 12 files changed, 2 insertions(+), 14 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj index 011a37cbdc..b8604169aa 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj @@ -12,7 +12,6 @@ - diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index c04f6132f3..4117452579 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -12,7 +12,6 @@ - diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj index 529054fd4f..0b119c8680 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj @@ -12,7 +12,6 @@ - diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index c04f6132f3..4117452579 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -12,7 +12,6 @@ - diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 8ef480d4e3..3f926ed45a 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -27,7 +27,6 @@ - diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 3ac1491946..d45f8a9692 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -4,7 +4,6 @@ - WinExe diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index d07df75864..2951076591 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -4,7 +4,6 @@ - WinExe diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 36c40c0fe2..c2973644cf 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -5,7 +5,6 @@ - WinExe diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 51d4bbc630..e8eaff4368 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -4,7 +4,6 @@ - WinExe diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 65679deb01..2572864e09 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -6,7 +6,6 @@ - diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fabef87c28..953087f9c8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -26,8 +26,7 @@ - - + @@ -41,6 +40,7 @@ + diff --git a/osu.iOS.props b/osu.iOS.props index 89166f924c..496bfbb85c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -81,8 +81,6 @@ - - From 28b15e232df3d8b6b9cc38b14d22819510e7b2f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 16:59:03 +0900 Subject: [PATCH 1131/2686] Remove all EF models --- osu.Game/Beatmaps/BeatmapSetFileInfo.cs | 31 --- osu.Game/Beatmaps/EFBeatmapDifficulty.cs | 80 ------- osu.Game/Beatmaps/EFBeatmapInfo.cs | 183 --------------- osu.Game/Beatmaps/EFBeatmapMetadata.cs | 89 -------- osu.Game/Beatmaps/EFBeatmapSetInfo.cs | 108 --------- osu.Game/Rulesets/EFRulesetInfo.cs | 87 -------- osu.Game/Scoring/EFScoreInfo.cs | 272 ----------------------- osu.Game/Scoring/ScoreFileInfo.cs | 31 --- osu.Game/Skinning/EFSkinInfo.cs | 65 ------ osu.Game/Skinning/SkinFileInfo.cs | 31 --- 10 files changed, 977 deletions(-) delete mode 100644 osu.Game/Beatmaps/BeatmapSetFileInfo.cs delete mode 100644 osu.Game/Beatmaps/EFBeatmapDifficulty.cs delete mode 100644 osu.Game/Beatmaps/EFBeatmapInfo.cs delete mode 100644 osu.Game/Beatmaps/EFBeatmapMetadata.cs delete mode 100644 osu.Game/Beatmaps/EFBeatmapSetInfo.cs delete mode 100644 osu.Game/Rulesets/EFRulesetInfo.cs delete mode 100644 osu.Game/Scoring/EFScoreInfo.cs delete mode 100644 osu.Game/Scoring/ScoreFileInfo.cs delete mode 100644 osu.Game/Skinning/EFSkinInfo.cs delete mode 100644 osu.Game/Skinning/SkinFileInfo.cs diff --git a/osu.Game/Beatmaps/BeatmapSetFileInfo.cs b/osu.Game/Beatmaps/BeatmapSetFileInfo.cs deleted file mode 100644 index 051366fb99..0000000000 --- a/osu.Game/Beatmaps/BeatmapSetFileInfo.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.ComponentModel.DataAnnotations; -using osu.Game.Database; -using osu.Game.IO; - -namespace osu.Game.Beatmaps -{ - public class BeatmapSetFileInfo : INamedFileInfo, IHasPrimaryKey, INamedFileUsage - { - public int ID { get; set; } - - public bool IsManaged => ID > 0; - - public int BeatmapSetInfoID { get; set; } - - public EFBeatmapSetInfo BeatmapSetInfo { get; set; } - - public int FileInfoID { get; set; } - - public FileInfo FileInfo { get; set; } - - [Required] - public string Filename { get; set; } - - IFileInfo INamedFileUsage.File => FileInfo; - } -} diff --git a/osu.Game/Beatmaps/EFBeatmapDifficulty.cs b/osu.Game/Beatmaps/EFBeatmapDifficulty.cs deleted file mode 100644 index 8bcac24ca1..0000000000 --- a/osu.Game/Beatmaps/EFBeatmapDifficulty.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.ComponentModel.DataAnnotations.Schema; -using osu.Game.Database; - -namespace osu.Game.Beatmaps -{ - [Table(@"BeatmapDifficulty")] - public class EFBeatmapDifficulty : IHasPrimaryKey, IBeatmapDifficultyInfo - { - /// - /// The default value used for all difficulty settings except and . - /// - public const float DEFAULT_DIFFICULTY = 5; - - public int ID { get; set; } - - public bool IsManaged => ID > 0; - - public float DrainRate { get; set; } = DEFAULT_DIFFICULTY; - public float CircleSize { get; set; } = DEFAULT_DIFFICULTY; - public float OverallDifficulty { get; set; } = DEFAULT_DIFFICULTY; - - private float? approachRate; - - public EFBeatmapDifficulty() - { - } - - public EFBeatmapDifficulty(IBeatmapDifficultyInfo source) - { - CopyFrom(source); - } - - public float ApproachRate - { - get => approachRate ?? OverallDifficulty; - set => approachRate = value; - } - - public double SliderMultiplier { get; set; } = 1; - public double SliderTickRate { get; set; } = 1; - - /// - /// Returns a shallow-clone of this . - /// - public EFBeatmapDifficulty Clone() - { - var diff = (EFBeatmapDifficulty)Activator.CreateInstance(GetType()); - CopyTo(diff); - return diff; - } - - public virtual void CopyFrom(IBeatmapDifficultyInfo other) - { - ApproachRate = other.ApproachRate; - DrainRate = other.DrainRate; - CircleSize = other.CircleSize; - OverallDifficulty = other.OverallDifficulty; - - SliderMultiplier = other.SliderMultiplier; - SliderTickRate = other.SliderTickRate; - } - - public virtual void CopyTo(EFBeatmapDifficulty other) - { - other.ApproachRate = ApproachRate; - other.DrainRate = DrainRate; - other.CircleSize = CircleSize; - other.OverallDifficulty = OverallDifficulty; - - other.SliderMultiplier = SliderMultiplier; - other.SliderTickRate = SliderTickRate; - } - } -} diff --git a/osu.Game/Beatmaps/EFBeatmapInfo.cs b/osu.Game/Beatmaps/EFBeatmapInfo.cs deleted file mode 100644 index 20abdc686a..0000000000 --- a/osu.Game/Beatmaps/EFBeatmapInfo.cs +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using Newtonsoft.Json; -using osu.Framework.Testing; -using osu.Game.Database; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Rulesets; -using osu.Game.Scoring; - -namespace osu.Game.Beatmaps -{ - [ExcludeFromDynamicCompile] - [Serializable] - [Table(@"BeatmapInfo")] - public class EFBeatmapInfo : IEquatable, IHasPrimaryKey, IBeatmapInfo - { - public int ID { get; set; } - - public bool IsManaged => ID > 0; - - public int BeatmapVersion; - - private int? onlineID; - - [JsonProperty("id")] - [Column("OnlineBeatmapID")] - public int? OnlineID - { - get => onlineID; - set => onlineID = value > 0 ? value : null; - } - - [JsonIgnore] - public int BeatmapSetInfoID { get; set; } - - public BeatmapOnlineStatus Status { get; set; } = BeatmapOnlineStatus.None; - - [Required] - public EFBeatmapSetInfo BeatmapSetInfo { get; set; } - - public EFBeatmapMetadata Metadata { get; set; } - - [JsonIgnore] - public int BaseDifficultyID { get; set; } - - public EFBeatmapDifficulty BaseDifficulty { get; set; } - - [NotMapped] - public APIBeatmap OnlineInfo { get; set; } - - /// - /// The playable length in milliseconds of this beatmap. - /// - public double Length { get; set; } - - /// - /// The most common BPM of this beatmap. - /// - public double BPM { get; set; } - - public string Path { get; set; } - - [JsonProperty("file_sha2")] - public string Hash { get; set; } - - [JsonIgnore] - public bool Hidden { get; set; } - - /// - /// MD5 is kept for legacy support (matching against replays, osu-web-10 etc.). - /// - [JsonProperty("file_md5")] - public string MD5Hash { get; set; } - - // General - public double AudioLeadIn { get; set; } - public float StackLeniency { get; set; } = 0.7f; - public bool SpecialStyle { get; set; } - - [Column("RulesetID")] - public int RulesetInfoID { get; set; } - - public EFRulesetInfo RulesetInfo { get; set; } - - public bool LetterboxInBreaks { get; set; } - public bool WidescreenStoryboard { get; set; } - public bool EpilepsyWarning { get; set; } - - /// - /// Whether or not sound samples should change rate when playing with speed-changing mods. - /// TODO: only read/write supported for now, requires implementation in gameplay. - /// - public bool SamplesMatchPlaybackRate { get; set; } - - public CountdownType Countdown { get; set; } = CountdownType.Normal; - - /// - /// The number of beats to move the countdown backwards (compared to its default location). - /// - public int CountdownOffset { get; set; } - - [NotMapped] - public int[] Bookmarks { get; set; } = Array.Empty(); - - public double DistanceSpacing { get; set; } - public int BeatDivisor { get; set; } - public int GridSize { get; set; } - public double TimelineZoom { get; set; } - - // Metadata - [Column("Version")] - public string DifficultyName { get; set; } - - [JsonProperty("difficulty_rating")] - [Column("StarDifficulty")] - public double StarRating { get; set; } - - /// - /// Currently only populated for beatmap deletion. Use to query scores. - /// - public List Scores { get; set; } - - [JsonIgnore] - public DifficultyRating DifficultyRating => StarDifficulty.GetDifficultyRating(StarRating); - - public override string ToString() => this.GetDisplayTitle(); - - public bool Equals(EFBeatmapInfo other) - { - if (ReferenceEquals(this, other)) return true; - if (other == null) return false; - - if (ID != 0 && other.ID != 0) - return ID == other.ID; - - return false; - } - - public bool Equals(IBeatmapInfo other) => other is EFBeatmapInfo b && Equals(b); - - public bool AudioEquals(EFBeatmapInfo other) => other != null && BeatmapSetInfo != null && other.BeatmapSetInfo != null && - BeatmapSetInfo.Hash == other.BeatmapSetInfo.Hash && - (Metadata ?? BeatmapSetInfo.Metadata).AudioFile == (other.Metadata ?? other.BeatmapSetInfo.Metadata).AudioFile; - - public bool BackgroundEquals(EFBeatmapInfo other) => other != null && BeatmapSetInfo != null && other.BeatmapSetInfo != null && - BeatmapSetInfo.Hash == other.BeatmapSetInfo.Hash && - (Metadata ?? BeatmapSetInfo.Metadata).BackgroundFile == (other.Metadata ?? other.BeatmapSetInfo.Metadata).BackgroundFile; - - /// - /// Returns a shallow-clone of this . - /// - public EFBeatmapInfo Clone() => (EFBeatmapInfo)MemberwiseClone(); - - #region Implementation of IHasOnlineID - - int IHasOnlineID.OnlineID => OnlineID ?? -1; - - #endregion - - #region Implementation of IBeatmapInfo - - [JsonIgnore] - IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata ?? BeatmapSetInfo?.Metadata ?? new EFBeatmapMetadata(); - - [JsonIgnore] - IBeatmapDifficultyInfo IBeatmapInfo.Difficulty => BaseDifficulty; - - [JsonIgnore] - IBeatmapSetInfo IBeatmapInfo.BeatmapSet => BeatmapSetInfo; - - [JsonIgnore] - IRulesetInfo IBeatmapInfo.Ruleset => RulesetInfo; - - #endregion - } -} diff --git a/osu.Game/Beatmaps/EFBeatmapMetadata.cs b/osu.Game/Beatmaps/EFBeatmapMetadata.cs deleted file mode 100644 index c0588f128c..0000000000 --- a/osu.Game/Beatmaps/EFBeatmapMetadata.cs +++ /dev/null @@ -1,89 +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.ComponentModel.DataAnnotations.Schema; -using Newtonsoft.Json; -using osu.Framework.Testing; -using osu.Game.Database; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Users; - -namespace osu.Game.Beatmaps -{ - [ExcludeFromDynamicCompile] - [Serializable] - [Table(@"BeatmapMetadata")] - public class EFBeatmapMetadata : IEquatable, IHasPrimaryKey, IBeatmapMetadataInfo - { - public int ID { get; set; } - - public bool IsManaged => ID > 0; - - public string Title { get; set; } = string.Empty; - - [JsonProperty("title_unicode")] - public string TitleUnicode { get; set; } = string.Empty; - - public string Artist { get; set; } = string.Empty; - - [JsonProperty("artist_unicode")] - public string ArtistUnicode { get; set; } = string.Empty; - - [JsonIgnore] - public List Beatmaps { get; set; } = new List(); - - [JsonIgnore] - public List BeatmapSets { get; set; } = new List(); - - /// - /// The author of the beatmaps in this set. - /// - [JsonIgnore] - public APIUser Author = new APIUser(); - - /// - /// Helper property to deserialize a username to . - /// - [JsonProperty(@"user_id")] - [Column("AuthorID")] - public int AuthorID - { - get => Author.Id; // This should not be used, but is required to make EF work correctly. - set => Author.Id = value; - } - - /// - /// Helper property to deserialize a username to . - /// - [JsonProperty(@"creator")] - [Column("Author")] - public string AuthorString - { - get => Author.Username; // This should not be used, but is required to make EF work correctly. - set => Author.Username = value; - } - - public string Source { get; set; } = string.Empty; - - [JsonProperty(@"tags")] - public string Tags { get; set; } = string.Empty; - - /// - /// The time in milliseconds to begin playing the track for preview purposes. - /// If -1, the track should begin playing at 40% of its length. - /// - public int PreviewTime { get; set; } = -1; - - public string AudioFile { get; set; } = string.Empty; - - public string BackgroundFile { get; set; } = string.Empty; - - public bool Equals(EFBeatmapMetadata other) => ((IBeatmapMetadataInfo)this).Equals(other); - - public override string ToString() => this.GetDisplayTitle(); - - IUser IBeatmapMetadataInfo.Author => Author; - } -} diff --git a/osu.Game/Beatmaps/EFBeatmapSetInfo.cs b/osu.Game/Beatmaps/EFBeatmapSetInfo.cs deleted file mode 100644 index 1f41d3727c..0000000000 --- a/osu.Game/Beatmaps/EFBeatmapSetInfo.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using JetBrains.Annotations; -using Newtonsoft.Json; -using osu.Framework.Testing; -using osu.Game.Database; -using osu.Game.Extensions; - -namespace osu.Game.Beatmaps -{ - [ExcludeFromDynamicCompile] - [Serializable] - [Table(@"BeatmapSetInfo")] - public class EFBeatmapSetInfo : IHasPrimaryKey, IHasFiles, ISoftDelete, IEquatable, IBeatmapSetInfo - { - public int ID { get; set; } - - public bool IsManaged => ID > 0; - - private int? onlineID; - - [Column("OnlineBeatmapSetID")] - public int? OnlineID - { - get => onlineID; - set => onlineID = value > 0 ? value : null; - } - - public DateTimeOffset DateAdded { get; set; } - - public EFBeatmapMetadata Metadata { get; set; } - - [NotNull] - public List Beatmaps { get; } = new List(); - - public BeatmapOnlineStatus Status { get; set; } = BeatmapOnlineStatus.None; - - public List Files { get; } = new List(); - - /// - /// The maximum star difficulty of all beatmaps in this set. - /// - [JsonIgnore] - public double MaxStarDifficulty => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.StarRating); - - /// - /// The maximum playable length in milliseconds of all beatmaps in this set. - /// - [JsonIgnore] - public double MaxLength => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.Length); - - /// - /// The maximum BPM of all beatmaps in this set. - /// - [JsonIgnore] - public double MaxBPM => Beatmaps.Count == 0 ? 0 : Beatmaps.Max(b => b.BPM); - - [NotMapped] - public bool DeletePending { get; set; } - - public string Hash { get; set; } - - /// - /// Returns the storage path for the file in this beatmapset with the given filename, if any exists, otherwise null. - /// The path returned is relative to the user file storage. - /// - /// The name of the file to get the storage path of. - public string GetPathForFile(string filename) => Files.SingleOrDefault(f => string.Equals(f.Filename, filename, StringComparison.OrdinalIgnoreCase))?.FileInfo.GetStoragePath(); - - public override string ToString() => Metadata?.ToString() ?? base.ToString(); - - public bool Protected { get; set; } - - public bool Equals(EFBeatmapSetInfo other) - { - if (ReferenceEquals(this, other)) return true; - if (other == null) return false; - - if (ID != 0 && other.ID != 0) - return ID == other.ID; - - return false; - } - - public bool Equals(IBeatmapSetInfo other) => other is EFBeatmapSetInfo b && Equals(b); - - #region Implementation of IHasOnlineID - - int IHasOnlineID.OnlineID => OnlineID ?? -1; - - #endregion - - #region Implementation of IBeatmapSetInfo - - IBeatmapMetadataInfo IBeatmapSetInfo.Metadata => Metadata ?? Beatmaps.FirstOrDefault()?.Metadata ?? new EFBeatmapMetadata(); - IEnumerable IBeatmapSetInfo.Beatmaps => Beatmaps; - IEnumerable IHasNamedFiles.Files => Files; - - #endregion - } -} diff --git a/osu.Game/Rulesets/EFRulesetInfo.cs b/osu.Game/Rulesets/EFRulesetInfo.cs deleted file mode 100644 index bd67bdb93c..0000000000 --- a/osu.Game/Rulesets/EFRulesetInfo.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.ComponentModel.DataAnnotations.Schema; -using System.Diagnostics.CodeAnalysis; -using Newtonsoft.Json; -using osu.Framework.Testing; - -namespace osu.Game.Rulesets -{ - [ExcludeFromDynamicCompile] - [Table(@"RulesetInfo")] - public sealed class EFRulesetInfo : IEquatable, IComparable, IRulesetInfo - { - public int? ID { get; set; } - - public string Name { get; set; } - - public string ShortName { get; set; } - - public string InstantiationInfo { get; set; } - - [JsonIgnore] - public bool Available { get; set; } - - // TODO: this should probably be moved to RulesetStore. - public Ruleset CreateInstance() - { - if (!Available) - return null; - - var type = Type.GetType(InstantiationInfo); - - if (type == null) - return null; - - var ruleset = Activator.CreateInstance(type) as Ruleset; - - return ruleset; - } - - public bool Equals(EFRulesetInfo other) => other != null && ID == other.ID && Available == other.Available && Name == other.Name && InstantiationInfo == other.InstantiationInfo; - - public int CompareTo(EFRulesetInfo other) => OnlineID.CompareTo(other.OnlineID); - - public int CompareTo(IRulesetInfo other) - { - if (!(other is EFRulesetInfo ruleset)) - throw new ArgumentException($@"Object is not of type {nameof(EFRulesetInfo)}.", nameof(other)); - - return CompareTo(ruleset); - } - - public override bool Equals(object obj) => obj is EFRulesetInfo rulesetInfo && Equals(rulesetInfo); - - public bool Equals(IRulesetInfo other) => other is RulesetInfo b && Equals(b); - - [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] - public override int GetHashCode() - { - unchecked - { - int hashCode = ID.HasValue ? ID.GetHashCode() : 0; - hashCode = (hashCode * 397) ^ (InstantiationInfo != null ? InstantiationInfo.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (Name != null ? Name.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ Available.GetHashCode(); - return hashCode; - } - } - - public override string ToString() => Name ?? $"{Name} ({ShortName}) ID: {ID}"; - - #region Implementation of IHasOnlineID - - [NotMapped] - public int OnlineID - { - get => ID ?? -1; - set => ID = value >= 0 ? value : null; - } - - #endregion - } -} diff --git a/osu.Game/Scoring/EFScoreInfo.cs b/osu.Game/Scoring/EFScoreInfo.cs deleted file mode 100644 index 8a5bbbf0da..0000000000 --- a/osu.Game/Scoring/EFScoreInfo.cs +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using Newtonsoft.Json; -using osu.Framework.Localisation; -using osu.Game.Beatmaps; -using osu.Game.Database; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Scoring; -using osu.Game.Users; -using osu.Game.Utils; - -namespace osu.Game.Scoring -{ - [Table(@"ScoreInfo")] - public class EFScoreInfo : IScoreInfo, IHasFiles, IHasPrimaryKey, ISoftDelete, IEquatable, IDeepCloneable - { - public int ID { get; set; } - - public bool IsManaged => ID > 0; - - public ScoreRank Rank { get; set; } - - public long TotalScore { get; set; } - - [Column(TypeName = "DECIMAL(1,4)")] // TODO: This data type is wrong (should contain more precision). But at the same time, we probably don't need to be storing this in the database. - public double Accuracy { get; set; } - - public LocalisableString DisplayAccuracy => Accuracy.FormatAccuracy(); - - public double? PP { get; set; } - - public int MaxCombo { get; set; } - - public int Combo { get; set; } // Todo: Shouldn't exist in here - - public int RulesetID { get; set; } - - [NotMapped] - public bool Passed { get; set; } = true; - - public EFRulesetInfo Ruleset { get; set; } - - private APIMod[] localAPIMods; - - private Mod[] mods; - - [NotMapped] - public Mod[] Mods - { - get - { - var rulesetInstance = Ruleset?.CreateInstance(); - if (rulesetInstance == null) - return mods ?? Array.Empty(); - - Mod[] scoreMods = Array.Empty(); - - if (mods != null) - scoreMods = mods; - else if (localAPIMods != null) - scoreMods = APIMods.Select(m => m.ToMod(rulesetInstance)).ToArray(); - - return scoreMods; - } - set - { - localAPIMods = null; - mods = value; - } - } - - // Used for API serialisation/deserialisation. - [NotMapped] - public APIMod[] APIMods - { - get - { - if (localAPIMods != null) - return localAPIMods; - - if (mods == null) - return Array.Empty(); - - return localAPIMods = mods.Select(m => new APIMod(m)).ToArray(); - } - set - { - localAPIMods = value; - - // We potentially can't update this yet due to Ruleset being late-bound, so instead update on read as necessary. - mods = null; - } - } - - // Used for database serialisation/deserialisation. - [Column("Mods")] - public string ModsJson - { - get => JsonConvert.SerializeObject(APIMods); - set => APIMods = !string.IsNullOrEmpty(value) ? JsonConvert.DeserializeObject(value) : Array.Empty(); - } - - [NotMapped] - public APIUser User { get; set; } - - [Column("User")] - public string UserString - { - get => User?.Username; - set - { - User ??= new APIUser(); - User.Username = value; - } - } - - [Column("UserID")] - public int? UserID - { - get => User?.Id ?? 1; - set - { - User ??= new APIUser(); - User.Id = value ?? 1; - } - } - - public int BeatmapInfoID { get; set; } - - [Column("Beatmap")] - public EFBeatmapInfo BeatmapInfo { get; set; } - - private long? onlineID; - - [JsonProperty("id")] - [Column("OnlineScoreID")] - public long? OnlineID - { - get => onlineID; - set => onlineID = value > 0 ? value : null; - } - - public DateTimeOffset Date { get; set; } - - [NotMapped] - public Dictionary Statistics { get; set; } = new Dictionary(); - - [Column("Statistics")] - public string StatisticsJson - { - get => JsonConvert.SerializeObject(Statistics); - set - { - if (value == null) - { - Statistics.Clear(); - return; - } - - Statistics = JsonConvert.DeserializeObject>(value); - } - } - - [NotMapped] - public List HitEvents { get; set; } - - public List Files { get; } = new List(); - - public string Hash { get; set; } - - public bool DeletePending { get; set; } - - /// - /// The position of this score, starting at 1. - /// - [NotMapped] - public int? Position { get; set; } // TODO: remove after all calls to `CreateScoreInfo` are gone. - - /// - /// Whether this represents a legacy (osu!stable) score. - /// - [NotMapped] - public bool IsLegacyScore => Mods.OfType().Any(); - - public IEnumerable GetStatisticsForDisplay() - { - foreach (var r in Ruleset.CreateInstance().GetHitResults()) - { - int value = Statistics.GetValueOrDefault(r.result); - - switch (r.result) - { - case HitResult.SmallTickHit: - { - int total = value + Statistics.GetValueOrDefault(HitResult.SmallTickMiss); - if (total > 0) - yield return new HitResultDisplayStatistic(r.result, value, total, r.displayName); - - break; - } - - case HitResult.LargeTickHit: - { - int total = value + Statistics.GetValueOrDefault(HitResult.LargeTickMiss); - if (total > 0) - yield return new HitResultDisplayStatistic(r.result, value, total, r.displayName); - - break; - } - - case HitResult.SmallTickMiss: - case HitResult.LargeTickMiss: - break; - - default: - yield return new HitResultDisplayStatistic(r.result, value, null, r.displayName); - - break; - } - } - } - - public EFScoreInfo DeepClone() - { - var clone = (EFScoreInfo)MemberwiseClone(); - - clone.Statistics = new Dictionary(clone.Statistics); - - return clone; - } - - public override string ToString() => this.GetDisplayTitle(); - - public bool Equals(EFScoreInfo other) - { - if (ReferenceEquals(this, other)) return true; - if (other == null) return false; - - if (ID != 0 && other.ID != 0) - return ID == other.ID; - - return false; - } - - #region Implementation of IHasOnlineID - - long IHasOnlineID.OnlineID => OnlineID ?? -1; - - #endregion - - #region Implementation of IScoreInfo - - IBeatmapInfo IScoreInfo.Beatmap => BeatmapInfo; - IRulesetInfo IScoreInfo.Ruleset => Ruleset; - IUser IScoreInfo.User => User; - bool IScoreInfo.HasReplay => Files.Any(); - - #endregion - - IEnumerable IHasNamedFiles.Files => Files; - } -} diff --git a/osu.Game/Scoring/ScoreFileInfo.cs b/osu.Game/Scoring/ScoreFileInfo.cs deleted file mode 100644 index 6c3509bccd..0000000000 --- a/osu.Game/Scoring/ScoreFileInfo.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.ComponentModel.DataAnnotations; -using osu.Game.Database; -using osu.Game.IO; - -namespace osu.Game.Scoring -{ - public class ScoreFileInfo : INamedFileInfo, IHasPrimaryKey, INamedFileUsage - { - public int ID { get; set; } - - public bool IsManaged => ID > 0; - - public int ScoreInfoID { get; set; } - - public EFScoreInfo ScoreInfo { get; set; } - - public int FileInfoID { get; set; } - - public FileInfo FileInfo { get; set; } - - [Required] - public string Filename { get; set; } - - IFileInfo INamedFileUsage.File => FileInfo; - } -} diff --git a/osu.Game/Skinning/EFSkinInfo.cs b/osu.Game/Skinning/EFSkinInfo.cs deleted file mode 100644 index 4204364c50..0000000000 --- a/osu.Game/Skinning/EFSkinInfo.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using osu.Framework.Extensions.ObjectExtensions; -using osu.Game.Database; -using osu.Game.Extensions; -using osu.Game.IO; - -namespace osu.Game.Skinning -{ - [Table(@"SkinInfo")] - public class EFSkinInfo : IHasFiles, IEquatable, IHasPrimaryKey, ISoftDelete - { - internal const int DEFAULT_SKIN = 0; - internal const int CLASSIC_SKIN = -1; - internal const int RANDOM_SKIN = -2; - - public int ID { get; set; } - - public string Name { get; set; } = string.Empty; - - public string Creator { get; set; } = string.Empty; - - public string Hash { get; set; } - - public string InstantiationInfo { get; set; } - - public virtual Skin CreateInstance(IStorageResourceProvider resources) - { - var type = string.IsNullOrEmpty(InstantiationInfo) - // handle the case of skins imported before InstantiationInfo was added. - ? typeof(LegacySkin) - : Type.GetType(InstantiationInfo).AsNonNull(); - - return (Skin)Activator.CreateInstance(type, this, resources); - } - - public List Files { get; set; } = new List(); - - public bool DeletePending { get; set; } - - public static EFSkinInfo Default { get; } = new EFSkinInfo - { - ID = DEFAULT_SKIN, - Name = "osu! (triangles)", - Creator = "team osu!", - InstantiationInfo = typeof(DefaultSkin).GetInvariantInstantiationInfo() - }; - - public bool Equals(EFSkinInfo other) => other != null && ID == other.ID; - - public override string ToString() - { - string author = Creator == null ? string.Empty : $"({Creator})"; - return $"{Name} {author}".Trim(); - } - - public bool IsManaged => ID > 0; - } -} diff --git a/osu.Game/Skinning/SkinFileInfo.cs b/osu.Game/Skinning/SkinFileInfo.cs deleted file mode 100644 index f3243d3f24..0000000000 --- a/osu.Game/Skinning/SkinFileInfo.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System.ComponentModel.DataAnnotations; -using osu.Game.Database; -using osu.Game.IO; - -namespace osu.Game.Skinning -{ - public class SkinFileInfo : INamedFileInfo, IHasPrimaryKey, INamedFileUsage - { - public int ID { get; set; } - - public bool IsManaged => ID > 0; - - public int SkinInfoID { get; set; } - - public EFSkinInfo SkinInfo { get; set; } - - public int FileInfoID { get; set; } - - public FileInfo FileInfo { get; set; } - - [Required] - public string Filename { get; set; } - - IFileInfo INamedFileUsage.File => FileInfo; - } -} From 8286ab0d04d7e6fb27cac79b26f2fbc1d161ddb5 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Thu, 15 Sep 2022 11:11:58 +0100 Subject: [PATCH 1132/2686] Revert "Fix `SongProgress` invalidating too often" This reverts commit 2b4b14ca9990a4626fefcbecf624ca2d97bf4244. --- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index b3d5066a9e..d0eb8f8ca1 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -47,10 +47,7 @@ namespace osu.Game.Screens.Play.HUD if (clock != null) gameplayClock = clock; - // Lock height so changes in text autosize (if character height changes) - // don't cause parent invalidation. - Height = 14; - + AutoSizeAxes = Axes.Y; Children = new Drawable[] { new Container From 2092008251cf5d0cc4846763b86719155f59a8bd Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Thu, 15 Sep 2022 11:16:00 +0100 Subject: [PATCH 1133/2686] Set InvalidationSource to Self --- osu.Game/Screens/Play/SquareGraph.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs index 00d6ede3bf..a1e004bfcc 100644 --- a/osu.Game/Screens/Play/SquareGraph.cs +++ b/osu.Game/Screens/Play/SquareGraph.cs @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Play } } - private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawSize); + private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawSize, InvalidationSource.Self); private ScheduledDelegate scheduledCreate; protected override void Update() From 4af76b9f48fd1d4602319af4552bee120b89f2ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 19:55:18 +0900 Subject: [PATCH 1134/2686] Apply the same change to `HandleFlip` --- .../Edit/OsuSelectionHandler.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 280a35500a..eddc1390f0 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -127,16 +127,13 @@ namespace osu.Game.Rulesets.Osu.Edit { didFlip = true; - var controlPoints = slider.Path.ControlPoints.Select(p => - new PathControlPoint(new Vector2( - (direction == Direction.Horizontal ? -1 : 1) * p.Position.X, - (direction == Direction.Vertical ? -1 : 1) * p.Position.Y - ), p.Type)).ToArray(); - - // Importantly, update as a single operation so automatic adjustment of control points to different - // curve types does not unexpectedly trigger and change the slider's shape. - slider.Path.ControlPoints.Clear(); - slider.Path.ControlPoints.AddRange(controlPoints); + foreach (var cp in slider.Path.ControlPoints) + { + cp.Position = new Vector2( + (direction == Direction.Horizontal ? -1 : 1) * cp.Position.X, + (direction == Direction.Vertical ? -1 : 1) * cp.Position.Y + ); + } } } @@ -186,8 +183,8 @@ namespace osu.Game.Rulesets.Osu.Edit if (h is IHasPath path) { - foreach (PathControlPoint t in path.Path.ControlPoints) - t.Position = RotatePointAroundOrigin(t.Position, Vector2.Zero, delta); + foreach (PathControlPoint cp in path.Path.ControlPoints) + cp.Position = RotatePointAroundOrigin(cp.Position, Vector2.Zero, delta); } } From c7f8f948b928c9a240e6fc5f791ad07c7dd26746 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 17:36:14 +0900 Subject: [PATCH 1135/2686] Rename `CreateLegacySkinProvider` to `CreateSkinTransformer` and apply to all skins --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 11 +++++++++- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 11 +++++++++- .../TestSceneSliderApplication.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 11 +++++++++- osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 11 +++++++++- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 8 +++++++- .../Skinning/RulesetSkinProvidingContainer.cs | 20 +++++++++---------- osu.Game/Tests/Visual/SkinnableTestScene.cs | 2 +- 9 files changed, 60 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 999b9f6e2c..5c9c95827a 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -182,7 +182,16 @@ namespace osu.Game.Rulesets.Catch public override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new CatchDifficultyCalculator(RulesetInfo, beatmap); - public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new CatchLegacySkinTransformer(skin); + public override ISkin? CreateSkinTransformer(ISkin skin, IBeatmap beatmap) + { + switch (skin) + { + case LegacySkin: + return new CatchLegacySkinTransformer(skin); + } + + return null; + } public override PerformanceCalculator CreatePerformanceCalculator() => new CatchPerformanceCalculator(); diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index c6a5e8bdaa..061dedb07a 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -62,7 +62,16 @@ namespace osu.Game.Rulesets.Mania public override HitObjectComposer CreateHitObjectComposer() => new ManiaHitObjectComposer(this); - public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new ManiaLegacySkinTransformer(skin, beatmap); + public override ISkin? CreateSkinTransformer(ISkin skin, IBeatmap beatmap) + { + switch (skin) + { + case LegacySkin: + return new ManiaLegacySkinTransformer(skin, beatmap); + } + + return null; + } public override IEnumerable ConvertFromLegacyMods(LegacyMods mods) { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs index 08a62fe3ae..0169627867 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Tests var tintingSkin = skinManager.GetSkin(DefaultLegacySkin.CreateInfo()); tintingSkin.Configuration.ConfigDictionary["AllowSliderBallTint"] = "1"; - var provider = Ruleset.Value.CreateInstance().CreateLegacySkinProvider(tintingSkin, Beatmap.Value.Beatmap); + var provider = Ruleset.Value.CreateInstance().CreateSkinTransformer(tintingSkin, Beatmap.Value.Beatmap); Child = new SkinProvidingContainer(provider) { diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 6af765361d..0a5b3139fc 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -231,7 +231,16 @@ namespace osu.Game.Rulesets.Osu public override RulesetSettingsSubsection CreateSettings() => new OsuSettingsSubsection(this); - public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new OsuLegacySkinTransformer(skin); + public override ISkin? CreateSkinTransformer(ISkin skin, IBeatmap beatmap) + { + switch (skin) + { + case LegacySkin: + return new OsuLegacySkinTransformer(skin); + } + + return null; + } public int LegacyID => 0; diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index 6beb83575d..dc36bc0320 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -43,7 +43,16 @@ namespace osu.Game.Rulesets.Taiko public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap, this); - public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new TaikoLegacySkinTransformer(skin); + public override ISkin? CreateSkinTransformer(ISkin skin, IBeatmap beatmap) + { + switch (skin) + { + case LegacySkin: + return new TaikoLegacySkinTransformer(skin); + } + + return null; + } public const string SHORT_NAME = "taiko"; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 5c7321fb24..e12be6d3b4 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -122,7 +122,7 @@ namespace osu.Game.Tests.Visual.Gameplay private class TestOsuRuleset : OsuRuleset { - public override ISkin CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => new TestOsuLegacySkinTransformer(skin); + public override ISkin CreateSkinTransformer(ISkin skin, IBeatmap beatmap) => new TestOsuLegacySkinTransformer(skin); private class TestOsuLegacySkinTransformer : OsuLegacySkinTransformer { diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 4bc82a5f7e..a446210c8a 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -200,7 +200,13 @@ namespace osu.Game.Rulesets public ModAutoplay? GetAutoplayMod() => CreateMod(); - public virtual ISkin? CreateLegacySkinProvider(ISkin skin, IBeatmap beatmap) => null; + /// + /// Create a transformer which adds lookups specific to a ruleset to skin sources. + /// + /// The source skin. + /// The current beatmap. + /// A skin with a transformer applied, or null if no transformation is provided by this ruleset. + public virtual ISkin? CreateSkinTransformer(ISkin skin, IBeatmap beatmap) => null; protected Ruleset() { diff --git a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs index 937cf20bc6..d5690710bb 100644 --- a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs +++ b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs @@ -41,7 +41,7 @@ namespace osu.Game.Skinning Ruleset = ruleset; Beatmap = beatmap; - InternalChild = new BeatmapSkinProvidingContainer(beatmapSkin is LegacySkin ? GetLegacyRulesetTransformedSkin(beatmapSkin) : beatmapSkin) + InternalChild = new BeatmapSkinProvidingContainer(beatmapSkin is LegacySkin ? GetRulesetTransformedSkin(beatmapSkin) : beatmapSkin) { Child = Content = new Container { @@ -67,16 +67,16 @@ namespace osu.Game.Skinning Debug.Assert(ParentSource != null); - foreach (var skin in ParentSource.AllSources) + foreach (var source in ParentSource.AllSources) { - switch (skin) + switch (source) { - case LegacySkin legacySkin: - sources.Add(GetLegacyRulesetTransformedSkin(legacySkin)); + case Skin skin: + sources.Add(GetRulesetTransformedSkin(skin)); break; default: - sources.Add(skin); + sources.Add(source); break; } } @@ -94,16 +94,16 @@ namespace osu.Game.Skinning SetSources(sources); } - protected ISkin GetLegacyRulesetTransformedSkin(ISkin legacySkin) + protected ISkin GetRulesetTransformedSkin(ISkin skin) { - if (legacySkin == null) + if (skin == null) return null; - var rulesetTransformed = Ruleset.CreateLegacySkinProvider(legacySkin, Beatmap); + var rulesetTransformed = Ruleset.CreateSkinTransformer(skin, Beatmap); if (rulesetTransformed != null) return rulesetTransformed; - return legacySkin; + return skin; } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index ffdde782a5..7278e1e93f 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual ISkin provider = skin; if (provider is LegacySkin legacyProvider) - provider = Ruleset.Value.CreateInstance().CreateLegacySkinProvider(legacyProvider, beatmap); + provider = Ruleset.Value.CreateInstance().CreateSkinTransformer(legacyProvider, beatmap); var children = new Container { From 5ce67345ae129f4d0fd80ca15bbb7130af15f8b7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 01:02:38 +0900 Subject: [PATCH 1136/2686] Catch against sqlite initialisation failures --- osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index 007bec46bb..2fd1d06b7b 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -42,9 +42,16 @@ namespace osu.Game.Beatmaps public BeatmapUpdaterMetadataLookup(IAPIProvider api, Storage storage) { - // required to initialise native SQLite libraries on some platforms. - Batteries_V2.Init(); - raw.sqlite3_config(2 /*SQLITE_CONFIG_MULTITHREAD*/); + try + { + // required to initialise native SQLite libraries on some platforms. + Batteries_V2.Init(); + raw.sqlite3_config(2 /*SQLITE_CONFIG_MULTITHREAD*/); + } + catch + { + // may fail if platform not supported. + } this.api = api; this.storage = storage; From db822696eda362206817b1881c17e7613f79f4d1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 01:02:46 +0900 Subject: [PATCH 1137/2686] Use latest version of sqlite3 bundle --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 953087f9c8..fed7c27f07 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -40,7 +40,7 @@ - + From 4f208416bedfd8cb3cd11474d7de2dca5aa40c8d Mon Sep 17 00:00:00 2001 From: Drison64 Date: Fri, 16 Sep 2022 13:50:18 +1400 Subject: [PATCH 1138/2686] Fixed irresponsiveness of score panel timestamp to time format --- .../Expanded/ExpandedPanelMiddleContent.cs | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index b496f4242d..e212dad65f 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -7,12 +7,14 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -34,6 +36,7 @@ namespace osu.Game.Screens.Ranking.Expanded private const float padding = 10; private readonly ScoreInfo score; + private Bindable bindableUse24HourDisplay; private readonly bool withFlair; private readonly List statisticDisplays = new List(); @@ -61,8 +64,9 @@ namespace osu.Game.Screens.Ranking.Expanded } [BackgroundDependencyLoader] - private void load(BeatmapDifficultyCache beatmapDifficultyCache) + private void load(BeatmapDifficultyCache beatmapDifficultyCache, OsuConfigManager config) { + bindableUse24HourDisplay = config.GetBindable(OsuSetting.Prefer24HourTime); var beatmap = score.BeatmapInfo; var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata; string creator = metadata.Author.Username; @@ -224,7 +228,7 @@ namespace osu.Game.Screens.Ranking.Expanded }); if (score.Date != default) - AddInternal(new PlayedOnText(score.Date)); + AddInternal(new PlayedOnText(score.Date, bindableUse24HourDisplay)); var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).GetResultSafely(); @@ -280,12 +284,25 @@ namespace osu.Game.Screens.Ranking.Expanded public class PlayedOnText : OsuSpriteText { - public PlayedOnText(DateTimeOffset time) + private bool use24HourDisplay; + + public PlayedOnText(DateTimeOffset time, Bindable bindableUse24HourDisplay) { + use24HourDisplay = bindableUse24HourDisplay.Value; + bindableUse24HourDisplay.BindValueChanged(prefer24H => + { + use24HourDisplay = prefer24H.NewValue; + UpdateHourDisplay(time); + }, true); Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold); - Text = $"Played on {time.ToLocalTime():d MMMM yyyy HH:mm}"; + UpdateHourDisplay(time); + } + + public void UpdateHourDisplay(DateTimeOffset time) + { + Text = use24HourDisplay ? $"Played on {time.ToLocalTime():d MMMM yyyy HH:mm}" : $"Played on {time.ToLocalTime():d MMMM yyyy h:mm tt}"; } } } From eb84c513e34a682914322ee94bf78b6836e64e1a Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Fri, 16 Sep 2022 02:14:14 +0200 Subject: [PATCH 1139/2686] Add ability to adjust to BPM changes fix first hitcircle being off time Bpm changes not working fix --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 6bbe01063b..84e41810ab 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -26,7 +26,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Fun; public override IconUsage? Icon => FontAwesome.Solid.Camera; - public override Type[] IncompatibleMods => new[] { typeof(OsuModTarget), typeof(OsuModStrictTracking) }; [SettingSource("Beat divisor")] @@ -48,13 +47,17 @@ namespace osu.Game.Rulesets.Osu.Mods foreach (var obj in beatmap.HitObjects.OfType()) { - var point = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime); - double newPreempt = obj.TimePreempt + (obj.StartTime +5) % (point.BeatLength * BeatDivisor.Value); + var lastTimingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime + 1); + double controlPointDifference = obj.StartTime + 1 - lastTimingPoint.Time; + double remainder = controlPointDifference % (lastTimingPoint.BeatLength * BeatDivisor.Value); + + double finalPreempt = obj.TimePreempt + remainder; + obj.TimePreempt = finalPreempt; applyFadeInAdjustment(obj); void applyFadeInAdjustment(OsuHitObject osuObject) { - osuObject.TimePreempt = newPreempt; + osuObject.TimePreempt = finalPreempt; foreach (var nested in osuObject.NestedHitObjects.OfType()) applyFadeInAdjustment(nested); } From 5a9b027ebcb32ecb44f6985ea86813682b5202f9 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Fri, 16 Sep 2022 02:57:21 +0200 Subject: [PATCH 1140/2686] Use Enum for Settings --- .../Mods/OsuModFreezeFrame.cs | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 84e41810ab..42c4a8fa20 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -29,12 +29,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override Type[] IncompatibleMods => new[] { typeof(OsuModTarget), typeof(OsuModStrictTracking) }; [SettingSource("Beat divisor")] - public BindableFloat BeatDivisor { get; } = new BindableFloat(1) - { - MinValue = .25f, - MaxValue = 5, - Precision = .25f - }; + public Bindable Divisor { get; } = new Bindable(BeatDivisor.Measure); public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { @@ -48,11 +43,11 @@ namespace osu.Game.Rulesets.Osu.Mods foreach (var obj in beatmap.HitObjects.OfType()) { var lastTimingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime + 1); + // +1 is added due to First HitCircle in each measure not appearing appropriately without it double controlPointDifference = obj.StartTime + 1 - lastTimingPoint.Time; - double remainder = controlPointDifference % (lastTimingPoint.BeatLength * BeatDivisor.Value); + double remainder = controlPointDifference % (lastTimingPoint.BeatLength * getMeasure(Divisor.Value)); double finalPreempt = obj.TimePreempt + remainder; - obj.TimePreempt = finalPreempt; applyFadeInAdjustment(obj); void applyFadeInAdjustment(OsuHitObject osuObject) @@ -64,14 +59,41 @@ namespace osu.Game.Rulesets.Osu.Mods } } - protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) + protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) { } + + protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) { } + + private float getMeasure(BeatDivisor divisor) { + switch (divisor) + { + case BeatDivisor.Quarter_Measure: + return 0.25f; + + case BeatDivisor.Half_Measure: + return 0.5f; + + case BeatDivisor.Measure: + return 1; + + case BeatDivisor.Double_Measure: + return 2; + + case BeatDivisor.Quadruple_Measure: + return 4; + + default: + throw new ArgumentOutOfRangeException(nameof(divisor), divisor, null); + } } - protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyFrozenState(hitObject, state); - - private void applyFrozenState(DrawableHitObject drawableObject, ArmedState state) + public enum BeatDivisor { + Quarter_Measure, + Half_Measure, + Measure, + Double_Measure, + Quadruple_Measure } } } From d9499abc3387367b4922abda985c2ee90ff76c07 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 16 Sep 2022 13:14:25 +0900 Subject: [PATCH 1141/2686] Refactor to avoid passing around bindables --- .../Expanded/ExpandedPanelMiddleContent.cs | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index e212dad65f..829ba83696 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -36,7 +36,6 @@ namespace osu.Game.Screens.Ranking.Expanded private const float padding = 10; private readonly ScoreInfo score; - private Bindable bindableUse24HourDisplay; private readonly bool withFlair; private readonly List statisticDisplays = new List(); @@ -64,9 +63,8 @@ namespace osu.Game.Screens.Ranking.Expanded } [BackgroundDependencyLoader] - private void load(BeatmapDifficultyCache beatmapDifficultyCache, OsuConfigManager config) + private void load(BeatmapDifficultyCache beatmapDifficultyCache) { - bindableUse24HourDisplay = config.GetBindable(OsuSetting.Prefer24HourTime); var beatmap = score.BeatmapInfo; var metadata = beatmap.BeatmapSet?.Metadata ?? beatmap.Metadata; string creator = metadata.Author.Username; @@ -228,7 +226,7 @@ namespace osu.Game.Screens.Ranking.Expanded }); if (score.Date != default) - AddInternal(new PlayedOnText(score.Date, bindableUse24HourDisplay)); + AddInternal(new PlayedOnText(score.Date)); var starDifficulty = beatmapDifficultyCache.GetDifficultyAsync(beatmap, score.Ruleset, score.Mods).GetResultSafely(); @@ -284,25 +282,34 @@ namespace osu.Game.Screens.Ranking.Expanded public class PlayedOnText : OsuSpriteText { - private bool use24HourDisplay; + private readonly DateTimeOffset time; + private readonly Bindable prefer24HourTime = new Bindable(); - public PlayedOnText(DateTimeOffset time, Bindable bindableUse24HourDisplay) + public PlayedOnText(DateTimeOffset time) { - use24HourDisplay = bindableUse24HourDisplay.Value; - bindableUse24HourDisplay.BindValueChanged(prefer24H => - { - use24HourDisplay = prefer24H.NewValue; - UpdateHourDisplay(time); - }, true); + this.time = time; + Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold); - UpdateHourDisplay(time); } - public void UpdateHourDisplay(DateTimeOffset time) + [BackgroundDependencyLoader] + private void load(OsuConfigManager configManager) { - Text = use24HourDisplay ? $"Played on {time.ToLocalTime():d MMMM yyyy HH:mm}" : $"Played on {time.ToLocalTime():d MMMM yyyy h:mm tt}"; + configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + prefer24HourTime.BindValueChanged(_ => updateDisplay(), true); + } + + private void updateDisplay() + { + Text = prefer24HourTime.Value ? $"Played on {time.ToLocalTime():d MMMM yyyy HH:mm}" : $"Played on {time.ToLocalTime():d MMMM yyyy h:mm tt}"; } } } From 21ac3fd88be99c7b057e420b2d3d75dd5b592dff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 14:00:05 +0900 Subject: [PATCH 1142/2686] Catch any unobserved exceptions during beatmap metadata harvesting The process will retry when a connection is successful, so this doesn't need to be as loud as it was. Addresses https://github.com/ppy/osu/discussions/20331. --- osu.Game/Online/Metadata/OnlineMetadataClient.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Online/Metadata/OnlineMetadataClient.cs b/osu.Game/Online/Metadata/OnlineMetadataClient.cs index 95228c380f..06d24a82f3 100644 --- a/osu.Game/Online/Metadata/OnlineMetadataClient.cs +++ b/osu.Game/Online/Metadata/OnlineMetadataClient.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.Diagnostics; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR.Client; @@ -80,6 +81,10 @@ namespace osu.Game.Online.Metadata await ProcessChanges(catchUpChanges.BeatmapSetIDs); } } + catch (Exception e) + { + Logger.Log($"Error while processing catch-up of metadata ({e.Message})"); + } finally { catchingUp = false; From 289e6ad977f6e073ca61e20aafe961b3c0e479f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 15:12:05 +0900 Subject: [PATCH 1143/2686] Fix follow point animations in legacy skins not always starting at correct point in time --- .../Connections/FollowPointConnection.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs index 0306c99fd5..1a9d12e860 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs @@ -1,9 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; +using System.Diagnostics; using osu.Framework.Graphics; using osu.Framework.Graphics.Pooling; using osu.Game.Rulesets.Objects; @@ -21,32 +20,36 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections public const int SPACING = 32; public const double PREEMPT = 800; - public DrawablePool Pool; + public DrawablePool? Pool { private get; set; } protected override void OnApply(FollowPointLifetimeEntry entry) { base.OnApply(entry); - entry.Invalidated += onEntryInvalidated; - refreshPoints(); + entry.Invalidated += scheduleRefresh; + + // Our clock may not be correct at this point if `LoadComplete` has not run yet. + // Without a schedule, animations referencing FollowPoint's clock (see `IAnimationTimeReference`) would be incorrect on first pool usage. + scheduleRefresh(); } protected override void OnFree(FollowPointLifetimeEntry entry) { base.OnFree(entry); - entry.Invalidated -= onEntryInvalidated; + entry.Invalidated -= scheduleRefresh; // Return points to the pool. ClearInternal(false); } - private void onEntryInvalidated() => Scheduler.AddOnce(refreshPoints); - - private void refreshPoints() + private void scheduleRefresh() => Scheduler.AddOnce(() => { + Debug.Assert(Pool != null); + ClearInternal(false); var entry = Entry; + if (entry?.End == null) return; OsuHitObject start = entry.Start; @@ -95,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections } entry.LifetimeEnd = finalTransformEndTime; - } + }); /// /// Computes the fade time of follow point positioned between two hitobjects. From 0ff4e343f87c82b04692584c0e61c1ef26ba56d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 16:29:53 +0900 Subject: [PATCH 1144/2686] Add failing test showing incorrect unread notification count --- .../Visual/UserInterface/TestSceneNotificationOverlay.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index e978b57ba4..a97096e143 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.UserInterface displayedCount = new OsuSpriteText() }; - notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count.NewValue}"; }; + notificationOverlay.UnreadCount.ValueChanged += count => { displayedCount.Text = $"unread count: {count.NewValue}"; }; }); [Test] @@ -270,6 +270,8 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait completion", () => notification.State == ProgressNotificationState.Completed); AddAssert("Completion toast shown", () => notificationOverlay.ToastCount == 1); + AddUntilStep("wait forwarded", () => notificationOverlay.ToastCount == 0); + AddAssert("only one unread", () => notificationOverlay.UnreadCount.Value == 1); } [Test] From 0d24fda4b9cbaaa107717feab3fc9adc4635cdd5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 16:36:56 +0900 Subject: [PATCH 1145/2686] Fire `Notification.Closed` immediately to ensure off-screen notifications are closed --- osu.Game/Overlays/NotificationOverlay.cs | 4 ++-- .../Overlays/Notifications/Notification.cs | 23 +++++++++++-------- .../Notifications/ProgressNotification.cs | 5 ++-- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 15573f99af..fad8afd371 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -210,14 +210,14 @@ namespace osu.Game.Overlays mainContent.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); } - private void notificationClosed() + private void notificationClosed() => Schedule(() => { updateCounts(); // this debounce is currently shared between popin/popout sounds, which means one could potentially not play when the user is expecting it. // popout is constant across all notification types, and should therefore be handled using playback concurrency instead, but seems broken at the moment. playDebouncedSample("UI/overlay-pop-out"); - } + }); private void playDebouncedSample(string sampleName) { diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 885bb2fc6c..4e7cebf0ae 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -26,7 +26,8 @@ namespace osu.Game.Overlays.Notifications public abstract class Notification : Container { /// - /// User requested close. + /// Notification was closed, either by user or otherwise. + /// Importantly, this event may be fired from a non-update thread. /// public event Action? Closed; @@ -55,6 +56,8 @@ namespace osu.Game.Overlays.Notifications protected Container IconContent; + public bool WasClosed { get; private set; } + private readonly Container content; protected override Container Content => content; @@ -245,21 +248,23 @@ namespace osu.Game.Overlays.Notifications initialFlash.FadeOutFromOne(2000, Easing.OutQuart); } - public bool WasClosed; - public virtual void Close(bool runFlingAnimation) { if (WasClosed) return; WasClosed = true; - if (runFlingAnimation && dragContainer.FlingLeft()) - this.FadeOut(600, Easing.In); - else - this.FadeOut(100); - Closed?.Invoke(); - Expire(); + + Schedule(() => + { + if (runFlingAnimation && dragContainer.FlingLeft()) + this.FadeOut(600, Easing.In); + else + this.FadeOut(100); + + Expire(); + }); } private class DragContainer : Container diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index c4d402e5b9..58c9814781 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -141,8 +141,6 @@ namespace osu.Game.Overlays.Notifications case ProgressNotificationState.Completed: loadingSpinner.Hide(); - attemptPostCompletion(); - base.Close(false); break; } } @@ -166,6 +164,8 @@ namespace osu.Game.Overlays.Notifications CompletionTarget.Invoke(CreateCompletionNotification()); completionSent = true; + + Close(false); } private ProgressNotificationState state; @@ -239,6 +239,7 @@ namespace osu.Game.Overlays.Notifications { switch (State) { + case ProgressNotificationState.Completed: case ProgressNotificationState.Cancelled: base.Close(runFlingAnimation); break; From 38d8d457d97a43d64deb14cec6f6e8b11b493d53 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 17:54:44 +0900 Subject: [PATCH 1146/2686] Add back second completion post attempt for case when notification overlay isn't loaded yet --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 58c9814781..61bb22041e 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -141,6 +141,7 @@ namespace osu.Game.Overlays.Notifications case ProgressNotificationState.Completed: loadingSpinner.Hide(); + attemptPostCompletion(); break; } } From 4c4fdfd15379afe3906b69512b367e8bf1b403c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 18:15:17 +0900 Subject: [PATCH 1147/2686] Provide scores directly to `Player` instance rather than relying on DI --- .../TestSceneSoloGameplayLeaderboard.cs | 6 ++---- .../Leaderboards/ILeaderboardScoreSource.cs | 15 --------------- .../Screens/Play/HUD/SoloGameplayLeaderboard.cs | 16 ++++++---------- osu.Game/Screens/Play/Player.cs | 7 ++++++- .../Select/Leaderboards/BeatmapLeaderboard.cs | 2 +- osu.Game/Screens/Select/PlaySongSelect.cs | 17 +++++++++-------- 6 files changed, 24 insertions(+), 39 deletions(-) delete mode 100644 osu.Game/Online/Leaderboards/ILeaderboardScoreSource.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index 6839fafa93..2b8eb3a80c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; @@ -18,7 +17,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSoloGameplayLeaderboard : OsuTestScene, ILeaderboardScoreSource + public class TestSceneSoloGameplayLeaderboard : OsuTestScene { [Cached] private readonly ScoreProcessor scoreProcessor = new ScoreProcessor(new OsuRuleset()); @@ -40,6 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay Child = new SoloGameplayLeaderboard(trackingUser) { + Scores = { BindTarget = scores }, Anchor = Anchor.Centre, Origin = Anchor.Centre, Expanded = { Value = true }, @@ -57,8 +57,6 @@ namespace osu.Game.Tests.Visual.Gameplay AddSliderStep("combo", 0, 1000, 0, v => scoreProcessor.Combo.Value = v); } - IBindableList ILeaderboardScoreSource.Scores => scores; - private static List createSampleScores() { return new[] diff --git a/osu.Game/Online/Leaderboards/ILeaderboardScoreSource.cs b/osu.Game/Online/Leaderboards/ILeaderboardScoreSource.cs deleted file mode 100644 index e7ed43633e..0000000000 --- a/osu.Game/Online/Leaderboards/ILeaderboardScoreSource.cs +++ /dev/null @@ -1,15 +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.Allocation; -using osu.Framework.Bindables; -using osu.Game.Scoring; - -namespace osu.Game.Online.Leaderboards -{ - [Cached] - public interface ILeaderboardScoreSource - { - IBindableList Scores { get; } - } -} diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 6141260beb..00efcb1ea9 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Game.Online.Leaderboards; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Users; @@ -16,7 +15,7 @@ namespace osu.Game.Screens.Play.HUD { private readonly IUser trackingUser; - private readonly IBindableList scores = new BindableList(); + public readonly IBindableList Scores = new BindableList(); // hold references to ensure bindables are updated. private readonly List> scoreBindables = new List>(); @@ -32,13 +31,10 @@ namespace osu.Game.Screens.Play.HUD this.trackingUser = trackingUser; } - [BackgroundDependencyLoader(true)] - private void load(ILeaderboardScoreSource? scoreSource) + protected override void LoadComplete() { - if (scoreSource != null) - scores.BindTo(scoreSource.Scores); - - scores.BindCollectionChanged((_, _) => Scheduler.AddOnce(showScores), true); + base.LoadComplete(); + Scores.BindCollectionChanged((_, _) => Scheduler.AddOnce(showScores), true); } private void showScores() @@ -46,7 +42,7 @@ namespace osu.Game.Screens.Play.HUD Clear(); scoreBindables.Clear(); - if (!scores.Any()) + if (!Scores.Any()) return; ILeaderboardScore local = Add(trackingUser, true); @@ -58,7 +54,7 @@ namespace osu.Game.Screens.Play.HUD // Local score should always show lower than any existing scores in cases of ties. local.DisplayOrder.Value = long.MaxValue; - foreach (var s in scores) + foreach (var s in Scores) { var score = Add(s.User, false); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 95e3e75c8a..e1530d7ea2 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -843,7 +843,12 @@ namespace osu.Game.Screens.Play }); } - protected virtual GameplayLeaderboard CreateGameplayLeaderboard() => new SoloGameplayLeaderboard(Score.ScoreInfo.User); + public readonly BindableList LeaderboardScores = new BindableList(); + + protected virtual GameplayLeaderboard CreateGameplayLeaderboard() => new SoloGameplayLeaderboard(Score.ScoreInfo.User) + { + Scores = { BindTarget = LeaderboardScores } + }; protected virtual void AddLeaderboardToHUD(GameplayLeaderboard leaderboard) => HUDOverlay.LeaderboardFlow.Add(leaderboard); diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index ee62160a21..ed4da5e848 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -23,7 +23,7 @@ using Realms; namespace osu.Game.Screens.Select.Leaderboards { - public class BeatmapLeaderboard : Leaderboard, ILeaderboardScoreSource + public class BeatmapLeaderboard : Leaderboard { public Action ScoreSelected; diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 619ec97535..068f78172b 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Screens; using osu.Game.Graphics; -using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Rulesets.Mods; @@ -22,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Screens.Select { - public class PlaySongSelect : SongSelect, ILeaderboardScoreSource + public class PlaySongSelect : SongSelect { private OsuScreen? playerLoader; @@ -111,14 +110,18 @@ namespace osu.Game.Screens.Select Player createPlayer() { + Player player; + var replayGeneratingMod = Mods.Value.OfType().FirstOrDefault(); if (replayGeneratingMod != null) - { - return new ReplayPlayer((beatmap, mods) => replayGeneratingMod.CreateScoreFromReplayData(beatmap, mods)); - } + player = new ReplayPlayer((beatmap, mods) => replayGeneratingMod.CreateScoreFromReplayData(beatmap, mods)); + else + player = new SoloPlayer(); - return new SoloPlayer(); + ((IBindableList)player.LeaderboardScores).BindTo(playBeatmapDetailArea.Leaderboard.Scores); + + return player; } } @@ -132,7 +135,5 @@ namespace osu.Game.Screens.Select playerLoader = null; } } - - IBindableList ILeaderboardScoreSource.Scores => playBeatmapDetailArea.Leaderboard.Scores; } } From c0e2ba419e60bf72affedb4dcb5a8d0cc7f73424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=A2=E3=82=BA=E3=82=BF=E3=82=B1?= Date: Fri, 16 Sep 2022 18:31:02 +0900 Subject: [PATCH 1148/2686] Localize non-localizable setting items --- osu.Game/Localisation/DebugSettingsStrings.cs | 10 ++ .../Localisation/GeneralSettingsStrings.cs | 5 + .../MaintenanceSettingsStrings.cs | 111 ++++++++++++++++++ .../Localisation/TabletSettingsStrings.cs | 5 + .../Sections/DebugSettings/MemorySettings.cs | 4 +- .../Sections/General/UpdateSettings.cs | 2 +- .../Settings/Sections/Input/TabletSettings.cs | 7 +- .../Sections/Maintenance/BeatmapSettings.cs | 2 +- .../Maintenance/CollectionsSettings.cs | 4 +- .../MassDeleteConfirmationDialog.cs | 3 +- .../MassVideoDeleteConfirmationDialog.cs | 3 +- .../Maintenance/MigrationRunScreen.cs | 9 +- .../Maintenance/MigrationSelectScreen.cs | 7 +- .../Sections/Maintenance/ModPresetSettings.cs | 6 +- .../Sections/Maintenance/ScoreSettings.cs | 2 +- .../Sections/Maintenance/SkinSettings.cs | 2 +- .../StableDirectoryLocationDialog.cs | 5 +- .../StableDirectorySelectScreen.cs | 3 +- 18 files changed, 163 insertions(+), 27 deletions(-) diff --git a/osu.Game/Localisation/DebugSettingsStrings.cs b/osu.Game/Localisation/DebugSettingsStrings.cs index 74b2c8d892..66ce0fa109 100644 --- a/osu.Game/Localisation/DebugSettingsStrings.cs +++ b/osu.Game/Localisation/DebugSettingsStrings.cs @@ -49,6 +49,16 @@ namespace osu.Game.Localisation /// public static LocalisableString CompactRealm => new TranslatableString(getKey(@"compact_realm"), @"Compact realm"); + /// + /// "Block realm" + /// + public static LocalisableString BlockRealm => new TranslatableString(getKey(@"block_realm"), @"Block realm"); + + /// + /// "Unblock realm" + /// + public static LocalisableString UnblockRealm => new TranslatableString(getKey(@"unblock_realm"), @"Unblock realm"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index 2aa91f5245..bbad80976e 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -64,6 +64,11 @@ namespace osu.Game.Localisation /// public static LocalisableString RunSetupWizard => new TranslatableString(getKey(@"run_setup_wizard"), @"Run setup wizard"); + /// + /// "You are running the latest release ({0})" + /// + public static LocalisableString RunningLatestRelease(string arg0) => new TranslatableString(getKey(@"running_latest_release"), @"You are running the latest release ({0})", arg0); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/MaintenanceSettingsStrings.cs b/osu.Game/Localisation/MaintenanceSettingsStrings.cs index a398eced07..8b7ca8d93a 100644 --- a/osu.Game/Localisation/MaintenanceSettingsStrings.cs +++ b/osu.Game/Localisation/MaintenanceSettingsStrings.cs @@ -14,11 +14,72 @@ namespace osu.Game.Localisation /// public static LocalisableString MaintenanceSectionHeader => new TranslatableString(getKey(@"maintenance_section_header"), @"Maintenance"); + /// + /// "Beatmaps" + /// + public static LocalisableString Beatmaps => new TranslatableString(getKey(@"beatmaps"), @"Beatmaps"); + + /// + /// "Skins" + /// + public static LocalisableString Skins => new TranslatableString(getKey(@"skins"), @"Skins"); + + /// + /// "Collections" + /// + public static LocalisableString Collections => new TranslatableString(getKey(@"collections"), @"Collections"); + + + /// + /// "Scores" + /// + public static LocalisableString Scores => new TranslatableString(getKey(@"scores"), @"Scores"); + + /// + /// "Mod presets" + /// + public static LocalisableString ModPresets => new TranslatableString(getKey(@"mod_presets"), @"Mod presets"); + /// /// "Select directory" /// public static LocalisableString SelectDirectory => new TranslatableString(getKey(@"select_directory"), @"Select directory"); + /// + /// "Migration in progress" + /// + public static LocalisableString MigrationInProgress => new TranslatableString(getKey(@"migration_in_progress"), @"Migration in progress"); + + /// + /// "This could take a few minutes depending on the speed of your disk(s)." + /// + public static LocalisableString MigrationDescription => new TranslatableString(getKey(@"migration_description"), @"This could take a few minutes depending on the speed of your disk(s)."); + + /// + /// "Please avoid interacting with the game!" + /// + public static LocalisableString ProhibitedInteractDuringMigration => new TranslatableString(getKey(@"prohibited_interact_during_migration"), @"Please avoid interacting with the game!"); + + /// + /// "Some files couldn't be cleaned up during migration. Clicking this notification will open the folder so you can manually clean things up." + /// + public static LocalisableString FailedCleanupNotification => new TranslatableString(getKey(@"failed_cleanup_notification"), @"Some files couldn't be cleaned up during migration. Clicking this notification will open the folder so you can manually clean things up."); + + /// + /// "Please select a new location" + /// + public static LocalisableString SelectNewLocation => new TranslatableString(getKey(@"select_new_location"), @"Please select a new location"); + + /// + /// "The target directory already seems to have an osu! install. Use that data instead?" + /// + public static LocalisableString TargetDirectoryAlreadyInstalledOsu => new TranslatableString(getKey(@"target_directory_already_installed_osu"), @"The target directory already seems to have an osu! install. Use that data instead?"); + + /// + /// "To complete this operation, osu! will close. Please open it again to use the new data location." + /// + public static LocalisableString RestartAndReOpenRequiredForCompletion => new TranslatableString(getKey(@"restart_and_re_open_required_for_completion"), @"To complete this operation, osu! will close. Please open it again to use the new data location."); + /// /// "Import beatmaps from stable" /// @@ -84,6 +145,56 @@ namespace osu.Game.Localisation /// public static LocalisableString RestoreAllRecentlyDeletedModPresets => new TranslatableString(getKey(@"restore_all_recently_deleted_mod_presets"), @"Restore all recently deleted mod presets"); + /// + /// "Deleted all collections!" + /// + public static LocalisableString DeletedAllCollections => new TranslatableString(getKey(@"deleted_all_collections"), @"Deleted all collections!"); + + /// + /// "Deleted all mod presets!" + /// + public static LocalisableString DeletedAllModPresets => new TranslatableString(getKey(@"deleted_all_mod_presets"), @"Deleted all mod presets!"); + + /// + /// "Restored all deleted mod presets!" + /// + public static LocalisableString RestoredAllDeletedModPresets => new TranslatableString(getKey(@"restored_all_deleted_mod_presets"), @"Restored all deleted mod presets!"); + + /// + /// "Everything?" + /// + public static LocalisableString MassDeleteConfirmation => new TranslatableString(getKey(@"mass_delete_confirmation"), @"Everything?"); + + /// + /// "All beatmap videos? This cannot be undone!" + /// + public static LocalisableString MassVideoDeleteConfirmation => new TranslatableString(getKey(@"mass_video_delete_confirmation"), @"All beatmap videos? This cannot be undone!"); + + /// + /// "Failed to automatically locate an osu!stable installation." + /// + public static LocalisableString StableDirectoryLocationHeader => new TranslatableString(getKey(@"stable_directory_location_header"), @"Failed to automatically locate an osu!stable installation."); + + /// + /// "An existing install could not be located. If you know where it is, you can help locate it." + /// + public static LocalisableString StableDirectoryLocationBody => new TranslatableString(getKey(@"stable_directory_location_body"), @"An existing install could not be located. If you know where it is, you can help locate it."); + + /// + /// "Sure! I know where it is located!" + /// + public static LocalisableString StableDirectoryLocationOk => new TranslatableString(getKey(@"stable_directory_location_ok"), @"Sure! I know where it is located!"); + + /// + /// "Actually I don't have osu!stable installed." + /// + public static LocalisableString StableDirectoryLocationCancel => new TranslatableString(getKey(@"stable_directory_location_cancel"), @"Actually I don't have osu!stable installed."); + + /// + /// "Please select your osu!stable install location" + /// + public static LocalisableString StableDirectorySelectHeader => new TranslatableString(getKey(@"stable_directory_select_header"), @"Please select your osu!stable install location"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/TabletSettingsStrings.cs b/osu.Game/Localisation/TabletSettingsStrings.cs index d62d348df9..6c2e3c1f9c 100644 --- a/osu.Game/Localisation/TabletSettingsStrings.cs +++ b/osu.Game/Localisation/TabletSettingsStrings.cs @@ -19,6 +19,11 @@ namespace osu.Game.Localisation /// public static LocalisableString NoTabletDetected => new TranslatableString(getKey(@"no_tablet_detected"), @"No tablet detected!"); + /// + /// "If your tablet is not detected, please read [this FAQ]({0}) for troubleshooting steps." + /// + public static LocalisableString NoTabletDetectedDescription(string url) => new TranslatableString(getKey(@"no_tablet_detected_description"), @"If your tablet is not detected, please read [this FAQ]({0}) for troubleshooting steps.", url); + /// /// "Reset to full area" /// diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs index 42ac4adb34..5ec09adfda 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs @@ -46,11 +46,11 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings }, blockAction = new SettingsButton { - Text = "Block realm", + Text = DebugSettingsStrings.BlockRealm, }, unblockAction = new SettingsButton { - Text = "Unblock realm", + Text = DebugSettingsStrings.UnblockRealm, }, }; diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index b68a4fed48..d97cf699e5 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Settings.Sections.General { notifications?.Post(new SimpleNotification { - Text = $"You are running the latest release ({game.Version})", + Text = GeneralSettingsStrings.RunningLatestRelease(game.Version), Icon = FontAwesome.Solid.CheckCircle, }); } diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 271438ed14..43676c5bbe 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -110,11 +110,10 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux) { t.NewLine(); - t.AddText("If your tablet is not detected, please read "); - t.AddLink("this FAQ", LinkAction.External, RuntimeInfo.OS == RuntimeInfo.Platform.Windows + var formattedSource = MessageFormatter.FormatText(TabletSettingsStrings.NoTabletDetectedDescription(RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? @"https://opentabletdriver.net/Wiki/FAQ/Windows" - : @"https://opentabletdriver.net/Wiki/FAQ/Linux"); - t.AddText(" for troubleshooting steps."); + : @"https://opentabletdriver.net/Wiki/FAQ/Linux").ToString()); + t.AddLinks(formattedSource.Text, formattedSource.Links); } }), } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs index 453dbd2e18..00342faf3b 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class BeatmapSettings : SettingsSubsection { - protected override LocalisableString Header => "Beatmaps"; + protected override LocalisableString Header => MaintenanceSettingsStrings.Beatmaps; private SettingsButton importBeatmapsButton = null!; private SettingsButton deleteBeatmapsButton = null!; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs index 5a91213eb8..9ec6f59fb5 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class CollectionsSettings : SettingsSubsection { - protected override LocalisableString Header => "Collections"; + protected override LocalisableString Header => MaintenanceSettingsStrings.Collections; private SettingsButton importCollectionsButton = null!; @@ -51,7 +51,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private void deleteAllCollections() { realm.Write(r => r.RemoveAll()); - notificationOverlay?.Post(new ProgressCompletionNotification { Text = "Deleted all collections!" }); + notificationOverlay?.Post(new ProgressCompletionNotification { Text = MaintenanceSettingsStrings.DeletedAllCollections }); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs index 19e6f83dac..bcfccaa5e2 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Game.Localisation; using osu.Game.Overlays.Dialog; namespace osu.Game.Overlays.Settings.Sections.Maintenance @@ -10,7 +11,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public MassDeleteConfirmationDialog(Action deleteAction) { - BodyText = "Everything?"; + BodyText = MaintenanceSettingsStrings.MassDeleteConfirmation; DeleteAction = deleteAction; } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs index fc8c9d497b..a386c64806 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Maintenance { @@ -10,7 +11,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance public MassVideoDeleteConfirmationDialog(Action deleteAction) : base(deleteAction) { - BodyText = "All beatmap videos? This cannot be undone!"; + BodyText = MaintenanceSettingsStrings.MassVideoDeleteConfirmation; } } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs index d565576d09..158e1a8aa0 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs @@ -15,6 +15,7 @@ using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays.Notifications; using osu.Game.Screens; using osuTK; @@ -71,14 +72,14 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = "Migration in progress", + Text = MaintenanceSettingsStrings.MigrationInProgress, Font = OsuFont.Default.With(size: 40) }, new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = "This could take a few minutes depending on the speed of your disk(s).", + Text = MaintenanceSettingsStrings.MigrationDescription, Font = OsuFont.Default.With(size: 30) }, new LoadingSpinner(true) @@ -89,7 +90,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = "Please avoid interacting with the game!", + Text = MaintenanceSettingsStrings.ProhibitedInteractDuringMigration, Font = OsuFont.Default.With(size: 30) }, } @@ -111,7 +112,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { notifications.Post(new SimpleNotification { - Text = "Some files couldn't be cleaned up during migration. Clicking this notification will open the folder so you can manually clean things up.", + Text = MaintenanceSettingsStrings.FailedCleanupNotification, Activated = () => { originalStorage.PresentExternally(); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs index 0d32e33d87..2f4f04fbc2 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs @@ -12,6 +12,7 @@ using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Game.IO; +using osu.Game.Localisation; using osu.Game.Overlays.Dialog; namespace osu.Game.Overlays.Settings.Sections.Maintenance @@ -35,7 +36,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance public override bool HideOverlaysOnEnter => true; - public override LocalisableString HeaderText => "Please select a new location"; + public override LocalisableString HeaderText => MaintenanceSettingsStrings.SelectNewLocation; protected override void OnSelection(DirectoryInfo directory) { @@ -51,9 +52,9 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance // Quick test for whether there's already an osu! install at the target path. if (fileInfos.Any(f => f.Name == OsuGameBase.CLIENT_DATABASE_FILENAME)) { - dialogOverlay.Push(new ConfirmDialog("The target directory already seems to have an osu! install. Use that data instead?", () => + dialogOverlay.Push(new ConfirmDialog(MaintenanceSettingsStrings.TargetDirectoryAlreadyInstalledOsu.ToString(), () => { - dialogOverlay.Push(new ConfirmDialog("To complete this operation, osu! will close. Please open it again to use the new data location.", () => + dialogOverlay.Push(new ConfirmDialog(MaintenanceSettingsStrings.RestartAndReOpenRequiredForCompletion.ToString(), () => { (storage as OsuStorage)?.ChangeDataPath(target.FullName); game.Exit(); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs index d35d3ff468..3e3138f041 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class ModPresetSettings : SettingsSubsection { - protected override LocalisableString Header => "Mod presets"; + protected override LocalisableString Header => MaintenanceSettingsStrings.ModPresets; [Resolved] private RealmAccess realm { get; set; } = null!; @@ -64,7 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance deleteAllButton.Enabled.Value = true; if (deletionTask.IsCompletedSuccessfully) - notificationOverlay?.Post(new ProgressCompletionNotification { Text = "Deleted all mod presets!" }); + notificationOverlay?.Post(new ProgressCompletionNotification { Text = MaintenanceSettingsStrings.DeletedAllModPresets }); else if (deletionTask.IsFaulted) Logger.Error(deletionTask.Exception, "Failed to delete all mod presets"); } @@ -81,7 +81,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance undeleteButton.Enabled.Value = true; if (undeletionTask.IsCompletedSuccessfully) - notificationOverlay?.Post(new ProgressCompletionNotification { Text = "Restored all deleted mod presets!" }); + notificationOverlay?.Post(new ProgressCompletionNotification { Text = MaintenanceSettingsStrings.RestoredAllDeletedModPresets }); else if (undeletionTask.IsFaulted) Logger.Error(undeletionTask.Exception, "Failed to restore mod presets"); } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs index 70e11d45dc..6377d59e2a 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class ScoreSettings : SettingsSubsection { - protected override LocalisableString Header => "Scores"; + protected override LocalisableString Header => MaintenanceSettingsStrings.Scores; private SettingsButton importScoresButton = null!; private SettingsButton deleteScoresButton = null!; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs index c95b1d4dd8..893981f3d9 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class SkinSettings : SettingsSubsection { - protected override LocalisableString Header => "Skins"; + protected override LocalisableString Header => MaintenanceSettingsStrings.Skins; private SettingsButton importSkinsButton = null!; private SettingsButton deleteSkinsButton = null!; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs index 8aff4520b5..31e5b05596 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Framework.Screens; +using osu.Game.Localisation; using osu.Game.Overlays.Dialog; using osu.Game.Screens; @@ -19,8 +20,8 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance public StableDirectoryLocationDialog(TaskCompletionSource taskCompletionSource) { - HeaderText = "Failed to automatically locate an osu!stable installation."; - BodyText = "An existing install could not be located. If you know where it is, you can help locate it."; + HeaderText = MaintenanceSettingsStrings.StableDirectoryLocationHeader; + BodyText = MaintenanceSettingsStrings.StableDirectoryLocationBody; Icon = FontAwesome.Solid.QuestionCircle; Buttons = new PopupDialogButton[] diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs index 047d589689..22cf2e7076 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Localisation; using osu.Framework.Screens; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Maintenance { @@ -19,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance protected override bool IsValidDirectory(DirectoryInfo info) => info?.GetFiles("osu!.*.cfg").Any() ?? false; - public override LocalisableString HeaderText => "Please select your osu!stable install location"; + public override LocalisableString HeaderText => MaintenanceSettingsStrings.StableDirectorySelectHeader; public StableDirectorySelectScreen(TaskCompletionSource taskCompletionSource) { From b99b10e586e79367459983aa45aac55e33cd9654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=A2=E3=82=BA=E3=82=BF=E3=82=B1?= Date: Fri, 16 Sep 2022 18:34:13 +0900 Subject: [PATCH 1149/2686] fix code style problem --- osu.Game/Localisation/MaintenanceSettingsStrings.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Localisation/MaintenanceSettingsStrings.cs b/osu.Game/Localisation/MaintenanceSettingsStrings.cs index 8b7ca8d93a..4d7fdc60f7 100644 --- a/osu.Game/Localisation/MaintenanceSettingsStrings.cs +++ b/osu.Game/Localisation/MaintenanceSettingsStrings.cs @@ -29,7 +29,6 @@ namespace osu.Game.Localisation ///
public static LocalisableString Collections => new TranslatableString(getKey(@"collections"), @"Collections"); - /// /// "Scores" /// From 3a62d292698aa279f765c154e6004317e3d92fee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=A2=E3=82=BA=E3=82=BF=E3=82=B1?= Date: Fri, 16 Sep 2022 18:43:59 +0900 Subject: [PATCH 1150/2686] fix tab spacing --- osu.Game/Localisation/GeneralSettingsStrings.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index bbad80976e..8506971756 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -65,9 +65,9 @@ namespace osu.Game.Localisation public static LocalisableString RunSetupWizard => new TranslatableString(getKey(@"run_setup_wizard"), @"Run setup wizard"); /// - /// "You are running the latest release ({0})" - /// - public static LocalisableString RunningLatestRelease(string arg0) => new TranslatableString(getKey(@"running_latest_release"), @"You are running the latest release ({0})", arg0); + /// "You are running the latest release ({0})" + ///
+ public static LocalisableString RunningLatestRelease(string arg0) => new TranslatableString(getKey(@"running_latest_release"), @"You are running the latest release ({0})", arg0); private static string getKey(string key) => $"{prefix}:{key}"; } From 85bb6f0beb859cf9f57d6ef6e68f28f557cb9c64 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 00:54:16 +0900 Subject: [PATCH 1151/2686] Update framework Update framework (again) 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 2c186a52dd..77c29a5d6e 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fed7c27f07..29e690a024 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 496bfbb85c..83410b08f6 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -82,7 +82,7 @@ - + From 433bb5ae2492aeee65446eb44b29adcd4cfda61c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 15 Sep 2022 20:54:06 +0900 Subject: [PATCH 1152/2686] Add ServerShuttingDownCountdown --- .../Online/Multiplayer/MultiplayerClient.cs | 26 +++++++++++++++++++ .../Multiplayer/MultiplayerCountdown.cs | 1 + .../ServerShuttingDownCountdown.cs | 20 ++++++++++++++ osu.Game/Online/SignalRWorkaroundTypes.cs | 3 ++- osu.Game/OsuGame.cs | 2 ++ osu.Game/OsuGameBase.cs | 6 ++--- 6 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Online/Multiplayer/ServerShuttingDownCountdown.cs diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index c398d72118..20efe5662d 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -18,6 +18,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Multiplayer.Countdown; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; +using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Utils; @@ -26,6 +27,8 @@ namespace osu.Game.Online.Multiplayer { public abstract class MultiplayerClient : Component, IMultiplayerClient, IMultiplayerRoomServer { + public Action? PostNotification { protected get; set; } + /// /// Invoked when any change occurs to the multiplayer room. /// @@ -554,6 +557,14 @@ namespace osu.Game.Online.Multiplayer { case CountdownStartedEvent countdownStartedEvent: Room.ActiveCountdowns.Add(countdownStartedEvent.Countdown); + + switch (countdownStartedEvent.Countdown) + { + case ServerShuttingDownCountdown: + postServerShuttingDownNotification(); + break; + } + break; case CountdownStoppedEvent countdownStoppedEvent: @@ -569,6 +580,21 @@ namespace osu.Game.Online.Multiplayer return Task.CompletedTask; } + private void postServerShuttingDownNotification() + { + ServerShuttingDownCountdown? countdown = room?.ActiveCountdowns.OfType().FirstOrDefault(); + + if (countdown == null) + return; + + PostNotification?.Invoke(new SimpleNotification + { + Text = countdown.FinalNotification + ? $"The multiplayer server is restarting in {countdown.TimeRemaining:hh\\:mm\\:ss}. This multiplayer room will be closed shortly." + : $"The multiplayer server is restarting in {countdown.TimeRemaining:hh\\:mm\\:ss}." + }); + } + Task IMultiplayerClient.UserBeatmapAvailabilityChanged(int userId, BeatmapAvailability beatmapAvailability) { Scheduler.Add(() => diff --git a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs index fd22420b99..c59f5937b0 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerCountdown.cs @@ -13,6 +13,7 @@ namespace osu.Game.Online.Multiplayer [MessagePackObject] [Union(0, typeof(MatchStartCountdown))] // IMPORTANT: Add rules to SignalRUnionWorkaroundResolver for new derived types. [Union(1, typeof(ForceGameplayStartCountdown))] + [Union(2, typeof(ServerShuttingDownCountdown))] public abstract class MultiplayerCountdown { /// diff --git a/osu.Game/Online/Multiplayer/ServerShuttingDownCountdown.cs b/osu.Game/Online/Multiplayer/ServerShuttingDownCountdown.cs new file mode 100644 index 0000000000..4def3acc5e --- /dev/null +++ b/osu.Game/Online/Multiplayer/ServerShuttingDownCountdown.cs @@ -0,0 +1,20 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using MessagePack; + +namespace osu.Game.Online.Multiplayer +{ + /// + /// A countdown that indicates the current multiplayer server is shutting down. + /// + [MessagePackObject] + public class ServerShuttingDownCountdown : MultiplayerCountdown + { + /// + /// If this is the final notification, no more events will be sent after this. + /// + [Key(2)] + public bool FinalNotification { get; set; } + } +} diff --git a/osu.Game/Online/SignalRWorkaroundTypes.cs b/osu.Game/Online/SignalRWorkaroundTypes.cs index 3518fbb4fe..0b545821ee 100644 --- a/osu.Game/Online/SignalRWorkaroundTypes.cs +++ b/osu.Game/Online/SignalRWorkaroundTypes.cs @@ -28,7 +28,8 @@ namespace osu.Game.Online (typeof(TeamVersusRoomState), typeof(MatchRoomState)), (typeof(TeamVersusUserState), typeof(MatchUserState)), (typeof(MatchStartCountdown), typeof(MultiplayerCountdown)), - (typeof(ForceGameplayStartCountdown), typeof(MultiplayerCountdown)) + (typeof(ForceGameplayStartCountdown), typeof(MultiplayerCountdown)), + (typeof(ServerShuttingDownCountdown), typeof(MultiplayerCountdown)), }; } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 9e2384322a..63a46e63d6 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -730,6 +730,8 @@ namespace osu.Game ScoreManager.PostNotification = n => Notifications.Post(n); ScoreManager.PresentImport = items => PresentScore(items.First().Value); + MultiplayerClient.PostNotification = n => Notifications.Post(n); + // make config aware of how to lookup skins for on-screen display purposes. // if this becomes a more common thing, tracked settings should be reconsidered to allow local DI. LocalConfig.LookupSkinName = id => SkinManager.Query(s => s.ID == id)?.ToString() ?? "Unknown"; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b30a065371..8b016e8eb0 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -179,7 +179,7 @@ namespace osu.Game private SpectatorClient spectatorClient; - private MultiplayerClient multiplayerClient; + protected MultiplayerClient MultiplayerClient { get; private set; } private MetadataClient metadataClient; @@ -284,7 +284,7 @@ namespace osu.Game // TODO: OsuGame or OsuGameBase? dependencies.CacheAs(beatmapUpdater = new BeatmapUpdater(BeatmapManager, difficultyCache, API, Storage)); dependencies.CacheAs(spectatorClient = new OnlineSpectatorClient(endpoints)); - dependencies.CacheAs(multiplayerClient = new OnlineMultiplayerClient(endpoints)); + dependencies.CacheAs(MultiplayerClient = new OnlineMultiplayerClient(endpoints)); dependencies.CacheAs(metadataClient = new OnlineMetadataClient(endpoints)); AddInternal(new BeatmapOnlineChangeIngest(beatmapUpdater, realm, metadataClient)); @@ -329,7 +329,7 @@ namespace osu.Game AddInternal(apiAccess); AddInternal(spectatorClient); - AddInternal(multiplayerClient); + AddInternal(MultiplayerClient); AddInternal(metadataClient); AddInternal(rulesetConfigCache); From 7fc0366afd56bfea4fcc91c45fc14124924218a6 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Fri, 16 Sep 2022 13:18:38 +0200 Subject: [PATCH 1153/2686] Improve Tests Fix divisor in test --- .../Mods/TestSceneOsuModFreezeFrame.cs | 31 +++++++++++++------ .../Mods/OsuModFreezeFrame.cs | 17 +++++----- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs index 4642229436..8af63aa5e2 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs @@ -1,27 +1,40 @@ // 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 NUnit.Framework; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests.Mods { public class TestSceneOsuModFreezeFrame : OsuModTestScene { - [TestCase(0.5f)] - [TestCase(1)] - [TestCase(2)] - public void TestFreezeFrequency(float beatMeasure) + [TestCase(OsuModFreezeFrame.BeatDivisor.Quarter_Measure)] + [TestCase(OsuModFreezeFrame.BeatDivisor.Single_Measure)] + [TestCase(OsuModFreezeFrame.BeatDivisor.Quadruple_Measure)] + public void TestFreezeFrequency(OsuModFreezeFrame.BeatDivisor divisor) { CreateModTest(new ModTestData { - Mod = new OsuModFreezeFrame - { - BeatDivisor = { Value = beatMeasure } - }, - PassCondition = () => true, + Mod = new OsuModFreezeFrame { Divisor = { Value = divisor } }, + PassCondition = checkSomeHit, Autoplay = true }); } + + [Test] + public void TestWithHidden() + { + var mods = new List { new OsuModHidden(), new OsuModFreezeFrame { Divisor = { Value = OsuModFreezeFrame.BeatDivisor.Quadruple_Measure } } }; + CreateModTest(new ModTestData + { + Mods = mods, + PassCondition = checkSomeHit, + Autoplay = true + }); + } + + private bool checkSomeHit() => Player.ScoreProcessor.JudgedHits >= 8; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 42c4a8fa20..08a8a85740 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public class OsuModFreezeFrame : ModWithVisibilityAdjustment, IHidesApproachCircles, IApplicableToDrawableRuleset { - public override string Name => "Freeze frame"; + public override string Name => "Freeze Frame"; public override string Acronym => "FF"; @@ -26,10 +26,9 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Fun; public override IconUsage? Icon => FontAwesome.Solid.Camera; - public override Type[] IncompatibleMods => new[] { typeof(OsuModTarget), typeof(OsuModStrictTracking) }; - [SettingSource("Beat divisor")] - public Bindable Divisor { get; } = new Bindable(BeatDivisor.Measure); + [SettingSource("Measure", "How often the hitcircles should be Grouped to freeze")] + public Bindable Divisor { get; } = new Bindable(BeatDivisor.Single_Measure); public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { @@ -42,11 +41,10 @@ namespace osu.Game.Rulesets.Osu.Mods foreach (var obj in beatmap.HitObjects.OfType()) { + // The +1s below are added due to First HitCircle in each measure not appearing appropriately without them. var lastTimingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime + 1); - // +1 is added due to First HitCircle in each measure not appearing appropriately without it double controlPointDifference = obj.StartTime + 1 - lastTimingPoint.Time; - double remainder = controlPointDifference % (lastTimingPoint.BeatLength * getMeasure(Divisor.Value)); - + double remainder = controlPointDifference % (lastTimingPoint.BeatLength * getMeasure(Divisor.Value)) - 1; double finalPreempt = obj.TimePreempt + remainder; applyFadeInAdjustment(obj); @@ -73,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Mods case BeatDivisor.Half_Measure: return 0.5f; - case BeatDivisor.Measure: + case BeatDivisor.Single_Measure: return 1; case BeatDivisor.Double_Measure: @@ -87,11 +85,12 @@ namespace osu.Game.Rulesets.Osu.Mods } } + //Todo: find better way to represent these Enums to the player public enum BeatDivisor { Quarter_Measure, Half_Measure, - Measure, + Single_Measure, Double_Measure, Quadruple_Measure } From 427bd182697cf40af987cd09526f643213752520 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Fri, 16 Sep 2022 13:36:04 +0200 Subject: [PATCH 1154/2686] Add Copyright header --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 08a8a85740..6b29c511ec 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -1,3 +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 System; using System.Linq; using osu.Framework.Bindables; @@ -27,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override IconUsage? Icon => FontAwesome.Solid.Camera; - [SettingSource("Measure", "How often the hitcircles should be Grouped to freeze")] + [SettingSource("Measure", "How often the hit-circles should be Grouped to freeze")] public Bindable Divisor { get; } = new Bindable(BeatDivisor.Single_Measure); public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) From 6db8f51c02fd7d96e67870951a02ded4eb7c865b Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Fri, 16 Sep 2022 13:45:18 +0200 Subject: [PATCH 1155/2686] Improve Tests Fix divisor in test Add Copyright header --- .../Mods/TestSceneOsuModFreezeFrame.cs | 31 +++++++++++++------ .../Mods/OsuModFreezeFrame.cs | 20 ++++++------ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs index 4642229436..8af63aa5e2 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs @@ -1,27 +1,40 @@ // 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 NUnit.Framework; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests.Mods { public class TestSceneOsuModFreezeFrame : OsuModTestScene { - [TestCase(0.5f)] - [TestCase(1)] - [TestCase(2)] - public void TestFreezeFrequency(float beatMeasure) + [TestCase(OsuModFreezeFrame.BeatDivisor.Quarter_Measure)] + [TestCase(OsuModFreezeFrame.BeatDivisor.Single_Measure)] + [TestCase(OsuModFreezeFrame.BeatDivisor.Quadruple_Measure)] + public void TestFreezeFrequency(OsuModFreezeFrame.BeatDivisor divisor) { CreateModTest(new ModTestData { - Mod = new OsuModFreezeFrame - { - BeatDivisor = { Value = beatMeasure } - }, - PassCondition = () => true, + Mod = new OsuModFreezeFrame { Divisor = { Value = divisor } }, + PassCondition = checkSomeHit, Autoplay = true }); } + + [Test] + public void TestWithHidden() + { + var mods = new List { new OsuModHidden(), new OsuModFreezeFrame { Divisor = { Value = OsuModFreezeFrame.BeatDivisor.Quadruple_Measure } } }; + CreateModTest(new ModTestData + { + Mods = mods, + PassCondition = checkSomeHit, + Autoplay = true + }); + } + + private bool checkSomeHit() => Player.ScoreProcessor.JudgedHits >= 8; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 42c4a8fa20..6b29c511ec 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -1,3 +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 System; using System.Linq; using osu.Framework.Bindables; @@ -15,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public class OsuModFreezeFrame : ModWithVisibilityAdjustment, IHidesApproachCircles, IApplicableToDrawableRuleset { - public override string Name => "Freeze frame"; + public override string Name => "Freeze Frame"; public override string Acronym => "FF"; @@ -26,10 +29,9 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Fun; public override IconUsage? Icon => FontAwesome.Solid.Camera; - public override Type[] IncompatibleMods => new[] { typeof(OsuModTarget), typeof(OsuModStrictTracking) }; - [SettingSource("Beat divisor")] - public Bindable Divisor { get; } = new Bindable(BeatDivisor.Measure); + [SettingSource("Measure", "How often the hit-circles should be Grouped to freeze")] + public Bindable Divisor { get; } = new Bindable(BeatDivisor.Single_Measure); public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { @@ -42,11 +44,10 @@ namespace osu.Game.Rulesets.Osu.Mods foreach (var obj in beatmap.HitObjects.OfType()) { + // The +1s below are added due to First HitCircle in each measure not appearing appropriately without them. var lastTimingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime + 1); - // +1 is added due to First HitCircle in each measure not appearing appropriately without it double controlPointDifference = obj.StartTime + 1 - lastTimingPoint.Time; - double remainder = controlPointDifference % (lastTimingPoint.BeatLength * getMeasure(Divisor.Value)); - + double remainder = controlPointDifference % (lastTimingPoint.BeatLength * getMeasure(Divisor.Value)) - 1; double finalPreempt = obj.TimePreempt + remainder; applyFadeInAdjustment(obj); @@ -73,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.Mods case BeatDivisor.Half_Measure: return 0.5f; - case BeatDivisor.Measure: + case BeatDivisor.Single_Measure: return 1; case BeatDivisor.Double_Measure: @@ -87,11 +88,12 @@ namespace osu.Game.Rulesets.Osu.Mods } } + //Todo: find better way to represent these Enums to the player public enum BeatDivisor { Quarter_Measure, Half_Measure, - Measure, + Single_Measure, Double_Measure, Quadruple_Measure } From 81d582c051280ee3dbe6de607d654c7788ac7ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=A2=E3=82=BA=E3=82=BF=E3=82=B1?= Date: Fri, 16 Sep 2022 21:08:25 +0900 Subject: [PATCH 1156/2686] fix review points and fine tuning --- osu.Game/Localisation/CommonStrings.cs | 5 ++++ osu.Game/Localisation/DebugSettingsStrings.cs | 15 ----------- .../MaintenanceSettingsStrings.cs | 25 ------------------- osu.Game/Overlays/Dialog/ConfirmDialog.cs | 3 ++- .../Sections/DebugSettings/MemorySettings.cs | 6 ++--- .../Settings/Sections/Input/TabletSettings.cs | 6 ++--- .../Sections/Maintenance/BeatmapSettings.cs | 2 +- .../Maintenance/CollectionsSettings.cs | 2 +- .../Maintenance/MigrationSelectScreen.cs | 4 +-- .../Sections/Maintenance/ModPresetSettings.cs | 2 +- .../Sections/Maintenance/ScoreSettings.cs | 2 +- .../Sections/Maintenance/SkinSettings.cs | 2 +- .../StableDirectoryLocationDialog.cs | 4 +-- 13 files changed, 22 insertions(+), 56 deletions(-) diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 93e3276f59..385ebd0593 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -89,6 +89,11 @@ namespace osu.Game.Localisation /// public static LocalisableString Collections => new TranslatableString(getKey(@"collections"), @"Collections"); + /// + /// "Mod presets" + /// + public static LocalisableString ModPresets => new TranslatableString(getKey(@"mod_presets"), @"Mod presets"); + /// /// "Name" /// diff --git a/osu.Game/Localisation/DebugSettingsStrings.cs b/osu.Game/Localisation/DebugSettingsStrings.cs index 66ce0fa109..dd21739096 100644 --- a/osu.Game/Localisation/DebugSettingsStrings.cs +++ b/osu.Game/Localisation/DebugSettingsStrings.cs @@ -44,21 +44,6 @@ namespace osu.Game.Localisation ///
public static LocalisableString ClearAllCaches => new TranslatableString(getKey(@"clear_all_caches"), @"Clear all caches"); - /// - /// "Compact realm" - /// - public static LocalisableString CompactRealm => new TranslatableString(getKey(@"compact_realm"), @"Compact realm"); - - /// - /// "Block realm" - /// - public static LocalisableString BlockRealm => new TranslatableString(getKey(@"block_realm"), @"Block realm"); - - /// - /// "Unblock realm" - /// - public static LocalisableString UnblockRealm => new TranslatableString(getKey(@"unblock_realm"), @"Unblock realm"); - private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/MaintenanceSettingsStrings.cs b/osu.Game/Localisation/MaintenanceSettingsStrings.cs index 4d7fdc60f7..4648682e64 100644 --- a/osu.Game/Localisation/MaintenanceSettingsStrings.cs +++ b/osu.Game/Localisation/MaintenanceSettingsStrings.cs @@ -14,31 +14,6 @@ namespace osu.Game.Localisation ///
public static LocalisableString MaintenanceSectionHeader => new TranslatableString(getKey(@"maintenance_section_header"), @"Maintenance"); - /// - /// "Beatmaps" - /// - public static LocalisableString Beatmaps => new TranslatableString(getKey(@"beatmaps"), @"Beatmaps"); - - /// - /// "Skins" - /// - public static LocalisableString Skins => new TranslatableString(getKey(@"skins"), @"Skins"); - - /// - /// "Collections" - /// - public static LocalisableString Collections => new TranslatableString(getKey(@"collections"), @"Collections"); - - /// - /// "Scores" - /// - public static LocalisableString Scores => new TranslatableString(getKey(@"scores"), @"Scores"); - - /// - /// "Mod presets" - /// - public static LocalisableString ModPresets => new TranslatableString(getKey(@"mod_presets"), @"Mod presets"); - /// /// "Select directory" /// diff --git a/osu.Game/Overlays/Dialog/ConfirmDialog.cs b/osu.Game/Overlays/Dialog/ConfirmDialog.cs index 8be865ee16..c17080f602 100644 --- a/osu.Game/Overlays/Dialog/ConfirmDialog.cs +++ b/osu.Game/Overlays/Dialog/ConfirmDialog.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Dialog @@ -20,7 +21,7 @@ namespace osu.Game.Overlays.Dialog /// The description of the action to be displayed to the user. /// An action to perform on confirmation. /// An optional action to perform on cancel. - public ConfirmDialog(string message, Action onConfirm, Action onCancel = null) + public ConfirmDialog(LocalisableString message, Action onConfirm, Action onCancel = null) { HeaderText = message; BodyText = "Last chance to turn back"; diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs index 5ec09adfda..3afb060e49 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs @@ -35,7 +35,7 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings }, new SettingsButton { - Text = DebugSettingsStrings.CompactRealm, + Text = "Compact realm", Action = () => { // Blocking operations implicitly causes a Compact(). @@ -46,11 +46,11 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings }, blockAction = new SettingsButton { - Text = DebugSettingsStrings.BlockRealm, + Text = "Block realm", }, unblockAction = new SettingsButton { - Text = DebugSettingsStrings.UnblockRealm, + Text = "Unblock realm", }, }; diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 43676c5bbe..e32639f476 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -72,7 +72,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, LocalisationManager localisation) { Children = new Drawable[] { @@ -110,9 +110,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux) { t.NewLine(); - var formattedSource = MessageFormatter.FormatText(TabletSettingsStrings.NoTabletDetectedDescription(RuntimeInfo.OS == RuntimeInfo.Platform.Windows + var formattedSource = MessageFormatter.FormatText(localisation.GetLocalisedBindableString(TabletSettingsStrings.NoTabletDetectedDescription(RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? @"https://opentabletdriver.net/Wiki/FAQ/Windows" - : @"https://opentabletdriver.net/Wiki/FAQ/Linux").ToString()); + : @"https://opentabletdriver.net/Wiki/FAQ/Linux")).Value); t.AddLinks(formattedSource.Text, formattedSource.Links); } }), diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs index 00342faf3b..beae5a6aad 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class BeatmapSettings : SettingsSubsection { - protected override LocalisableString Header => MaintenanceSettingsStrings.Beatmaps; + protected override LocalisableString Header => CommonStrings.Beatmaps; private SettingsButton importBeatmapsButton = null!; private SettingsButton deleteBeatmapsButton = null!; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs index 9ec6f59fb5..17fef37e40 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class CollectionsSettings : SettingsSubsection { - protected override LocalisableString Header => MaintenanceSettingsStrings.Collections; + protected override LocalisableString Header => CommonStrings.Collections; private SettingsButton importCollectionsButton = null!; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs index 2f4f04fbc2..5de33fdd55 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs @@ -52,9 +52,9 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance // Quick test for whether there's already an osu! install at the target path. if (fileInfos.Any(f => f.Name == OsuGameBase.CLIENT_DATABASE_FILENAME)) { - dialogOverlay.Push(new ConfirmDialog(MaintenanceSettingsStrings.TargetDirectoryAlreadyInstalledOsu.ToString(), () => + dialogOverlay.Push(new ConfirmDialog(MaintenanceSettingsStrings.TargetDirectoryAlreadyInstalledOsu, () => { - dialogOverlay.Push(new ConfirmDialog(MaintenanceSettingsStrings.RestartAndReOpenRequiredForCompletion.ToString(), () => + dialogOverlay.Push(new ConfirmDialog(MaintenanceSettingsStrings.RestartAndReOpenRequiredForCompletion, () => { (storage as OsuStorage)?.ChangeDataPath(target.FullName); game.Exit(); diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs index 3e3138f041..51f6e1bf60 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class ModPresetSettings : SettingsSubsection { - protected override LocalisableString Header => MaintenanceSettingsStrings.ModPresets; + protected override LocalisableString Header => CommonStrings.ModPresets; [Resolved] private RealmAccess realm { get; set; } = null!; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs index 6377d59e2a..eb2d3171ea 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class ScoreSettings : SettingsSubsection { - protected override LocalisableString Header => MaintenanceSettingsStrings.Scores; + protected override LocalisableString Header => CommonStrings.Scores; private SettingsButton importScoresButton = null!; private SettingsButton deleteScoresButton = null!; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs index 893981f3d9..93c65513b7 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public class SkinSettings : SettingsSubsection { - protected override LocalisableString Header => MaintenanceSettingsStrings.Skins; + protected override LocalisableString Header => CommonStrings.Skins; private SettingsButton importSkinsButton = null!; private SettingsButton deleteSkinsButton = null!; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs index 31e5b05596..7b7ea7cee0 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs @@ -28,12 +28,12 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { new PopupDialogOkButton { - Text = "Sure! I know where it is located!", + Text = MaintenanceSettingsStrings.StableDirectoryLocationOk, Action = () => Schedule(() => performer.PerformFromScreen(screen => screen.Push(new StableDirectorySelectScreen(taskCompletionSource)))) }, new PopupDialogCancelButton { - Text = "Actually I don't have osu!stable installed.", + Text = MaintenanceSettingsStrings.StableDirectoryLocationCancel, Action = () => taskCompletionSource.TrySetCanceled() } }; From 92b2417d4c7afbde92896e234bcae9b3fcc6f717 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 16 Sep 2022 21:10:11 +0900 Subject: [PATCH 1157/2686] Post notification when room joined --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 20efe5662d..f9236cbfac 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -210,6 +210,8 @@ namespace osu.Game.Online.Multiplayer updateLocalRoomSettings(joinedRoom.Settings); + postServerShuttingDownNotification(); + OnRoomJoined(); }, cancellationSource.Token).ConfigureAwait(false); }, cancellationSource.Token).ConfigureAwait(false); From 877165eb98f02fa0531cac2d63e86cb3626ff868 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Sep 2022 16:16:53 +0300 Subject: [PATCH 1158/2686] Allow specifying icon colour on simple notifications --- osu.Game/Overlays/Notifications/SimpleNotification.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index 1dba60fb5f..f3bb6a0578 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; @@ -41,6 +42,12 @@ namespace osu.Game.Overlays.Notifications } } + public ColourInfo IconColour + { + get => IconContent.Colour; + set => IconContent.Colour = value; + } + private TextFlowContainer? textDrawable; private SpriteIcon? iconDrawable; From a0c493656f7e738bb0fe5d52d00308ebc4310ab2 Mon Sep 17 00:00:00 2001 From: Mk-56spn Date: Fri, 16 Sep 2022 15:27:36 +0200 Subject: [PATCH 1159/2686] Remove Incompatibility with Approach Circle requiring mods --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 6b29c511ec..6a0faf9298 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModFreezeFrame : ModWithVisibilityAdjustment, IHidesApproachCircles, IApplicableToDrawableRuleset + public class OsuModFreezeFrame : ModWithVisibilityAdjustment, IApplicableToDrawableRuleset { public override string Name => "Freeze Frame"; From 110652592fc3a96c36e2d6e9b2f0639ea5c2f192 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Sep 2022 16:17:24 +0300 Subject: [PATCH 1160/2686] Display readable tablet notifications and link to supported list page --- osu.Game/OsuGame.cs | 49 +++++++++++++++++++++++++++++++++++++++-- osu.Game/OsuGameBase.cs | 4 +++- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 0d115f62fe..ce0a961190 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -24,6 +24,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Screens; @@ -187,7 +188,8 @@ namespace osu.Game { this.args = args; - forwardLoggedErrorsToNotifications(); + forwardRuntimeLogsToNotifications(); + forwardTabletLogsToNotifications(); SentryLogger = new SentryLogger(this); } @@ -992,7 +994,7 @@ namespace osu.Game overlay.Depth = (float)-Clock.CurrentTime; } - private void forwardLoggedErrorsToNotifications() + private void forwardRuntimeLogsToNotifications() { int recentLogCount = 0; @@ -1033,6 +1035,49 @@ namespace osu.Game }; } + private void forwardTabletLogsToNotifications() + { + bool notifyOnWarning = true; + + Logger.NewEntry += entry => + { + if (entry.Level < LogLevel.Important || entry.LoggerName != ITabletHandler.LOGGER_NAME) + return; + + if (entry.Level == LogLevel.Error) + { + Schedule(() => Notifications.Post(new SimpleNotification + { + Text = $"Encountered tablet error: \"{entry.Message}\"", + Icon = FontAwesome.Solid.PenSquare, + IconColour = Colours.RedDark, + })); + } + else if (notifyOnWarning) + { + Schedule(() => Notifications.Post(new SimpleNotification + { + Text = @"Encountered tablet warning, your tablet may not function correctly. Click here for a list of all tablets supported.", + Icon = FontAwesome.Solid.PenSquare, + IconColour = Colours.YellowDark, + Activated = () => + { + OpenUrlExternally("https://opentabletdriver.net/Tablets", true); + return true; + } + })); + + notifyOnWarning = false; + } + }; + + Schedule(() => + { + ITabletHandler tablet = Host.AvailableInputHandlers.OfType().SingleOrDefault(); + tablet?.Tablet.BindValueChanged(_ => notifyOnWarning = true, true); + }); + } + private Task asyncLoadStream; /// diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b30a065371..9bc4508e42 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -124,6 +124,8 @@ namespace osu.Game protected SessionStatics SessionStatics { get; private set; } + protected OsuColour Colours { get; private set; } + protected BeatmapManager BeatmapManager { get; private set; } protected BeatmapModelDownloader BeatmapDownloader { get; private set; } @@ -308,7 +310,7 @@ namespace osu.Game dependencies.CacheAs(powerStatus); dependencies.Cache(SessionStatics = new SessionStatics()); - dependencies.Cache(new OsuColour()); + dependencies.Cache(Colours = new OsuColour()); RegisterImportHandler(BeatmapManager); RegisterImportHandler(ScoreManager); From f512106bee0ae1adc2faa16eb3abc09d3552b7a4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Sep 2022 20:00:38 +0300 Subject: [PATCH 1161/2686] Adjust test scene to match expectations - Adds a scenario where no button is pressed before second hitobject. - Adjusts press time to not conflict with break start time. --- .../Mods/TestSceneOsuModAlternate.cs | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs index 5e46498aca..8994abcea5 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.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 AutoMapper.Internal; using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Timing; @@ -125,7 +127,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods /// Ensures alternation is reset before the first hitobject after a break. /// [Test] - public void TestInputSingularWithBreak() => CreateModTest(new ModTestData + public void TestInputSingularWithBreak([Values] bool pressBeforeSecondObject) => CreateModTest(new ModTestData { Mod = new OsuModAlternate(), PassCondition = () => Player.ScoreProcessor.Combo.Value == 0 && Player.ScoreProcessor.HighestCombo.Value == 2, @@ -155,21 +157,26 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods }, } }, - ReplayFrames = new List + ReplayFrames = new ReplayFrame[] { // first press to start alternate lock. - new OsuReplayFrame(500, new Vector2(100), OsuAction.LeftButton), - new OsuReplayFrame(501, new Vector2(100)), - // press same key after break but before hit object. - new OsuReplayFrame(2250, new Vector2(300, 100), OsuAction.LeftButton), - new OsuReplayFrame(2251, new Vector2(300, 100)), + new OsuReplayFrame(450, new Vector2(100), OsuAction.LeftButton), + new OsuReplayFrame(451, new Vector2(100)), // press same key at second hitobject and ensure it has been hit. - new OsuReplayFrame(2500, new Vector2(500, 100), OsuAction.LeftButton), - new OsuReplayFrame(2501, new Vector2(500, 100)), + new OsuReplayFrame(2450, new Vector2(500, 100), OsuAction.LeftButton), + new OsuReplayFrame(2451, new Vector2(500, 100)), // press same key at third hitobject and ensure it has been missed. - new OsuReplayFrame(3000, new Vector2(500, 100), OsuAction.LeftButton), - new OsuReplayFrame(3001, new Vector2(500, 100)), - } + new OsuReplayFrame(2950, new Vector2(500, 100), OsuAction.LeftButton), + new OsuReplayFrame(2951, new Vector2(500, 100)), + }.Concat(!pressBeforeSecondObject + ? Enumerable.Empty() + : new ReplayFrame[] + { + // press same key after break but before hit object. + new OsuReplayFrame(2250, new Vector2(300, 100), OsuAction.LeftButton), + new OsuReplayFrame(2251, new Vector2(300, 100)), + } + ).ToList() }); } } From 557b39b69b051cc4bc3e74ac9d7fc775f0dc1d21 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Sep 2022 19:48:24 +0300 Subject: [PATCH 1162/2686] Fix `InputBlockingMod` not always clearing last action on break periods --- osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs b/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs index a7aca8257b..e4e8905722 100644 --- a/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs +++ b/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs @@ -18,7 +18,7 @@ using osu.Game.Utils; namespace osu.Game.Rulesets.Osu.Mods { - public abstract class InputBlockingMod : Mod, IApplicableToDrawableRuleset + public abstract class InputBlockingMod : Mod, IApplicableToDrawableRuleset, IUpdatableByPlayfield { public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax), typeof(OsuModCinema) }; @@ -62,15 +62,18 @@ namespace osu.Game.Rulesets.Osu.Mods gameplayClock = drawableRuleset.FrameStableClock; } + public void Update(Playfield playfield) + { + if (LastAcceptedAction != null && nonGameplayPeriods.IsInAny(gameplayClock.CurrentTime)) + LastAcceptedAction = null; + } + protected abstract bool CheckValidNewAction(OsuAction action); private bool checkCorrectAction(OsuAction action) { if (nonGameplayPeriods.IsInAny(gameplayClock.CurrentTime)) - { - LastAcceptedAction = null; return true; - } switch (action) { From fe7223711890b614cdc2eabf9933d6400da73b9e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Sep 2022 20:08:50 +0300 Subject: [PATCH 1163/2686] Remove unused using --- osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs index 8994abcea5..521c10c10c 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using AutoMapper.Internal; using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Timing; From 288cc7b201b8a404dc677017fe002220c4b2ab97 Mon Sep 17 00:00:00 2001 From: vegguid <75315940+vegguid@users.noreply.github.com> Date: Fri, 16 Sep 2022 21:36:17 +0200 Subject: [PATCH 1164/2686] Fixed Leaderboard tooltip not following time format setting --- .../Leaderboards/LeaderboardScoreTooltip.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs index 2f3ece0e3b..7123a274d4 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs @@ -15,6 +15,8 @@ using osu.Framework.Localisation; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; +using osu.Framework.Bindables; +using osu.Game.Configuration; namespace osu.Game.Online.Leaderboards { @@ -24,7 +26,7 @@ namespace osu.Game.Online.Leaderboards private FillFlowContainer topScoreStatistics = null!; private FillFlowContainer bottomScoreStatistics = null!; private FillFlowContainer modStatistics = null!; - + private readonly Bindable prefer24HourTime = new Bindable(); public LeaderboardScoreTooltip() { AutoSizeAxes = Axes.Both; @@ -36,8 +38,9 @@ namespace osu.Game.Online.Leaderboards } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, OsuConfigManager configManager) { + configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime); InternalChildren = new Drawable[] { new Box @@ -92,6 +95,13 @@ namespace osu.Game.Online.Leaderboards }; } + private void updateDisplay() + { + if (displayedScore != null) + { + timestampLabel.Text = prefer24HourTime.Value ? $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy HH:mm}" : $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy h:mm tt}"; + } + } private ScoreInfo? displayedScore; public void SetContent(ScoreInfo score) @@ -101,7 +111,7 @@ namespace osu.Game.Online.Leaderboards displayedScore = score; - timestampLabel.Text = $"Played on {score.Date.ToLocalTime():d MMMM yyyy HH:mm}"; + prefer24HourTime.BindValueChanged(_ => updateDisplay(), true); modStatistics.Clear(); topScoreStatistics.Clear(); From 48527f2d076faddf0288903ac06ecf0daa16b8c6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Sep 2022 22:50:49 +0300 Subject: [PATCH 1165/2686] Ignore case during logger name comparison --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ce0a961190..9a63ccbf48 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1041,7 +1041,7 @@ namespace osu.Game Logger.NewEntry += entry => { - if (entry.Level < LogLevel.Important || entry.LoggerName != ITabletHandler.LOGGER_NAME) + if (entry.Level < LogLevel.Important || !entry.LoggerName.Equals(ITabletHandler.LOGGER_NAME, StringComparison.OrdinalIgnoreCase)) return; if (entry.Level == LogLevel.Error) From 0d76f4501d4cb47d7a0f7880b9c9c19755315d12 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Sat, 17 Sep 2022 10:10:20 +0100 Subject: [PATCH 1166/2686] Revert "Set InvalidationSource to Self" This reverts commit 2092008251cf5d0cc4846763b86719155f59a8bd. --- osu.Game/Screens/Play/SquareGraph.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs index a1e004bfcc..00d6ede3bf 100644 --- a/osu.Game/Screens/Play/SquareGraph.cs +++ b/osu.Game/Screens/Play/SquareGraph.cs @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Play } } - private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawSize, InvalidationSource.Self); + private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawSize); private ScheduledDelegate scheduledCreate; protected override void Update() From e3d5ba530147644677938b74f68de09359c6c776 Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Sat, 17 Sep 2022 10:45:04 +0100 Subject: [PATCH 1167/2686] Check if graph DrawSize changed --- osu.Game/Screens/Play/SquareGraph.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs index 00d6ede3bf..092e056c85 100644 --- a/osu.Game/Screens/Play/SquareGraph.cs +++ b/osu.Game/Screens/Play/SquareGraph.cs @@ -78,11 +78,13 @@ namespace osu.Game.Screens.Play private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawSize); private ScheduledDelegate scheduledCreate; + private Vector2 previousDrawSize; + protected override void Update() { base.Update(); - if (values != null && !layout.IsValid) + if (values != null && !layout.IsValid && DrawSize != previousDrawSize) { columns?.FadeOut(500, Easing.OutQuint).Expire(); @@ -90,6 +92,7 @@ namespace osu.Game.Screens.Play scheduledCreate = Scheduler.AddDelayed(RecreateGraph, 500); layout.Validate(); + previousDrawSize = DrawSize; } } From 0bfe967452a0ae9a910d4ca31318aed155c58608 Mon Sep 17 00:00:00 2001 From: vegguid <75315940+vegguid@users.noreply.github.com> Date: Sat, 17 Sep 2022 12:58:23 +0200 Subject: [PATCH 1168/2686] moved BindValueChanged to LoadComplete --- .../Leaderboards/LeaderboardScoreTooltip.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs index 7123a274d4..0651fe0072 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs @@ -94,13 +94,11 @@ namespace osu.Game.Online.Leaderboards } }; } - - private void updateDisplay() + protected override void LoadComplete() { - if (displayedScore != null) - { - timestampLabel.Text = prefer24HourTime.Value ? $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy HH:mm}" : $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy h:mm tt}"; - } + base.LoadComplete(); + + prefer24HourTime.BindValueChanged(_ => updateTimestampLabel(), true); } private ScoreInfo? displayedScore; @@ -111,7 +109,7 @@ namespace osu.Game.Online.Leaderboards displayedScore = score; - prefer24HourTime.BindValueChanged(_ => updateDisplay(), true); + updateTimestampLabel(); modStatistics.Clear(); topScoreStatistics.Clear(); @@ -130,6 +128,13 @@ namespace osu.Game.Online.Leaderboards topScoreStatistics.Add(new HitResultCell(result)); } } + private void updateTimestampLabel() + { + if (displayedScore != null) + { + timestampLabel.Text = prefer24HourTime.Value ? $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy HH:mm}" : $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy h:mm tt}"; + } + } protected override void PopIn() => this.FadeIn(20, Easing.OutQuint); protected override void PopOut() => this.FadeOut(80, Easing.OutQuint); From a1d830e47f3728329353a39be1fce94de727c483 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 17 Sep 2022 22:22:56 +0900 Subject: [PATCH 1169/2686] Fix formatting --- osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs index 0651fe0072..f51f57c031 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs @@ -27,6 +27,7 @@ namespace osu.Game.Online.Leaderboards private FillFlowContainer bottomScoreStatistics = null!; private FillFlowContainer modStatistics = null!; private readonly Bindable prefer24HourTime = new Bindable(); + public LeaderboardScoreTooltip() { AutoSizeAxes = Axes.Both; @@ -94,12 +95,14 @@ namespace osu.Game.Online.Leaderboards } }; } + protected override void LoadComplete() { base.LoadComplete(); prefer24HourTime.BindValueChanged(_ => updateTimestampLabel(), true); } + private ScoreInfo? displayedScore; public void SetContent(ScoreInfo score) @@ -128,11 +131,14 @@ namespace osu.Game.Online.Leaderboards topScoreStatistics.Add(new HitResultCell(result)); } } + private void updateTimestampLabel() { if (displayedScore != null) { - timestampLabel.Text = prefer24HourTime.Value ? $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy HH:mm}" : $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy h:mm tt}"; + timestampLabel.Text = prefer24HourTime.Value + ? $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy HH:mm}" + : $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy h:mm tt}"; } } From d580b07063f2c83bd165809f210c82c64ee7b19e Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Sat, 17 Sep 2022 14:40:36 +0100 Subject: [PATCH 1170/2686] Refactor update condition logic --- osu.Game/Screens/Play/SquareGraph.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs index 092e056c85..210ae21156 100644 --- a/osu.Game/Screens/Play/SquareGraph.cs +++ b/osu.Game/Screens/Play/SquareGraph.cs @@ -15,7 +15,6 @@ using osuTK; using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Allocation; -using osu.Framework.Layout; using osu.Framework.Threading; namespace osu.Game.Screens.Play @@ -24,11 +23,6 @@ namespace osu.Game.Screens.Play { private BufferedContainer columns; - public SquareGraph() - { - AddLayout(layout); - } - public int ColumnCount => columns?.Children.Count ?? 0; private int progress; @@ -57,7 +51,7 @@ namespace osu.Game.Screens.Play if (value == values) return; values = value; - layout.Invalidate(); + graphNeedsUpdate = true; } } @@ -75,24 +69,25 @@ namespace osu.Game.Screens.Play } } - private readonly LayoutValue layout = new LayoutValue(Invalidation.DrawSize); private ScheduledDelegate scheduledCreate; + private bool graphNeedsUpdate = false; + private Vector2 previousDrawSize; protected override void Update() { base.Update(); - if (values != null && !layout.IsValid && DrawSize != previousDrawSize) + if (graphNeedsUpdate || (values != null && DrawSize != previousDrawSize)) { columns?.FadeOut(500, Easing.OutQuint).Expire(); scheduledCreate?.Cancel(); scheduledCreate = Scheduler.AddDelayed(RecreateGraph, 500); - layout.Validate(); previousDrawSize = DrawSize; + graphNeedsUpdate = false; } } From 0b6a77bc8bd90c76aa9fbf491d6542e5e7dff887 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Sat, 17 Sep 2022 15:59:42 +0200 Subject: [PATCH 1171/2686] EditorBeatmap's TimelineZoom should never be zero --- osu.Game/Screens/Edit/EditorBeatmap.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 16c0064e80..356276039c 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -96,6 +96,7 @@ namespace osu.Game.Screens.Edit PlayableBeatmap.ControlPointInfo = ConvertControlPoints(PlayableBeatmap.ControlPointInfo); this.beatmapInfo = beatmapInfo ?? playableBeatmap.BeatmapInfo; + if (this.beatmapInfo.TimelineZoom <= 0) this.beatmapInfo.TimelineZoom = 1; if (beatmapSkin is Skin skin) { From 2dfa89c62e255c4d806db3ea8ab92aa028afedca Mon Sep 17 00:00:00 2001 From: HiddenNode Date: Sat, 17 Sep 2022 15:05:25 +0100 Subject: [PATCH 1172/2686] Clean up --- osu.Game/Screens/Play/SquareGraph.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs index 210ae21156..9ac673ae52 100644 --- a/osu.Game/Screens/Play/SquareGraph.cs +++ b/osu.Game/Screens/Play/SquareGraph.cs @@ -71,7 +71,7 @@ namespace osu.Game.Screens.Play private ScheduledDelegate scheduledCreate; - private bool graphNeedsUpdate = false; + private bool graphNeedsUpdate; private Vector2 previousDrawSize; From 51841988bf32532267a65c3e0bb3f28d335ae1f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 15:40:20 +0900 Subject: [PATCH 1173/2686] Rename references to `DefaultSkin` to have `Triangles` suffix --- .../TestSceneCatchSkinConfiguration.cs | 2 +- .../Editor/TestSceneManiaComposeScreen.cs | 2 +- .../TestSceneHitCircleArea.cs | 2 +- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 4 ++-- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 2 +- .../Navigation/TestSceneEditDefaultSkin.cs | 4 ++-- osu.Game/Configuration/OsuConfigManager.cs | 2 +- .../Backgrounds/BackgroundScreenDefault.cs | 2 +- ...DefaultSkin.cs => DefaultSkinTriangles.cs} | 10 +++++----- .../Skinning/RulesetSkinProvidingContainer.cs | 2 +- osu.Game/Skinning/SkinInfo.cs | 2 +- osu.Game/Skinning/SkinManager.cs | 20 +++++++++---------- osu.Game/Skinning/SkinnableSprite.cs | 2 +- osu.Game/Tests/Visual/SkinnableTestScene.cs | 6 +++--- 14 files changed, 31 insertions(+), 31 deletions(-) rename osu.Game/Skinning/{DefaultSkin.cs => DefaultSkinTriangles.cs} (95%) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs index 6ecbf58a52..06235d3744 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Catch.Tests }); } - private class TestSkin : DefaultSkin + private class TestSkin : DefaultSkinTriangles { public bool FlipCatcherPlate { get; set; } diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs index 0354228cca..9e02424eb8 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor [Test] public void TestDefaultSkin() { - AddStep("set default skin", () => skins.CurrentSkinInfo.Value = DefaultSkin.CreateInfo().ToLiveUnmanaged()); + AddStep("set default skin", () => skins.CurrentSkinInfo.Value = DefaultSkinTriangles.CreateInfo().ToLiveUnmanaged()); } [Test] diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs index 0cf2ec6b7e..d3f58ca868 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Tests hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - Child = new SkinProvidingContainer(new DefaultSkin(null)) + Child = new SkinProvidingContainer(new DefaultSkinTriangles(null)) { RelativeSizeAxes = Axes.Both, Child = drawableHitCircle = new DrawableHitCircle(hitCircle) diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index c3c10215a5..57f2578200 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -202,7 +202,7 @@ namespace osu.Game.Tests.Skins.IO skinManager.CurrentSkinInfo.Value.PerformRead(s => { Assert.IsFalse(s.Protected); - Assert.AreEqual(typeof(DefaultSkin), s.CreateInstance(skinManager).GetType()); + Assert.AreEqual(typeof(DefaultSkinTriangles), s.CreateInstance(skinManager).GetType()); new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream); @@ -215,7 +215,7 @@ namespace osu.Game.Tests.Skins.IO { Assert.IsFalse(s.Protected); Assert.AreNotEqual(originalSkinId, s.ID); - Assert.AreEqual(typeof(DefaultSkin), s.CreateInstance(skinManager).GetType()); + Assert.AreEqual(typeof(DefaultSkinTriangles), s.CreateInstance(skinManager).GetType()); }); return Task.CompletedTask; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index e12be6d3b4..b24a65820d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestEmptyLegacyBeatmapSkinFallsBack() { - CreateSkinTest(DefaultSkin.CreateInfo(), () => new LegacyBeatmapSkin(new BeatmapInfo(), null)); + CreateSkinTest(DefaultSkinTriangles.CreateInfo(), () => new LegacyBeatmapSkin(new BeatmapInfo(), null)); AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded)); AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value)); } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs index 4ca55e8744..bc6458b62b 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs @@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestEditDefaultSkin() { - AddAssert("is default skin", () => skinManager.CurrentSkinInfo.Value.ID == SkinInfo.DEFAULT_SKIN); + AddAssert("is default skin", () => skinManager.CurrentSkinInfo.Value.ID == SkinInfo.DEFAULT_SKIN_TRIANGLES); AddStep("open settings", () => { Game.Settings.Show(); }); @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("open skin editor", () => skinEditor.Show()); // Until step required as the skin editor may take time to load (and an extra scheduled frame for the mutable part). - AddUntilStep("is modified default skin", () => skinManager.CurrentSkinInfo.Value.ID != SkinInfo.DEFAULT_SKIN); + AddUntilStep("is modified default skin", () => skinManager.CurrentSkinInfo.Value.ID != SkinInfo.DEFAULT_SKIN_TRIANGLES); AddAssert("is not protected", () => skinManager.CurrentSkinInfo.Value.PerformRead(s => !s.Protected)); AddUntilStep("export button enabled", () => Game.Settings.ChildrenOfType().SingleOrDefault()?.Enabled.Value == true); diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 5f49557685..ec97508522 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -39,7 +39,7 @@ namespace osu.Game.Configuration { // UI/selection defaults SetDefault(OsuSetting.Ruleset, string.Empty); - SetDefault(OsuSetting.Skin, SkinInfo.DEFAULT_SKIN.ToString()); + SetDefault(OsuSetting.Skin, SkinInfo.DEFAULT_SKIN_TRIANGLES.ToString()); SetDefault(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details); SetDefault(OsuSetting.BeatmapDetailModsFilter, false); diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index c794c768c6..e04e6d4849 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Backgrounds case BackgroundSource.Skin: // default skins should use the default background rotation, which won't be the case if a SkinBackground is created for them. - if (skin.Value is DefaultSkin || skin.Value is DefaultLegacySkin) + if (skin.Value is DefaultSkinTriangles || skin.Value is DefaultLegacySkin) break; newBackground = new SkinBackground(skin.Value, getBackgroundTextureName()); diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkinTriangles.cs similarity index 95% rename from osu.Game/Skinning/DefaultSkin.cs rename to osu.Game/Skinning/DefaultSkinTriangles.cs index f10e8412b1..26d933105a 100644 --- a/osu.Game/Skinning/DefaultSkin.cs +++ b/osu.Game/Skinning/DefaultSkinTriangles.cs @@ -22,26 +22,26 @@ using osuTK.Graphics; namespace osu.Game.Skinning { - public class DefaultSkin : Skin + public class DefaultSkinTriangles : Skin { public static SkinInfo CreateInfo() => new SkinInfo { - ID = osu.Game.Skinning.SkinInfo.DEFAULT_SKIN, + ID = osu.Game.Skinning.SkinInfo.DEFAULT_SKIN_TRIANGLES, Name = "osu! (triangles)", Creator = "team osu!", Protected = true, - InstantiationInfo = typeof(DefaultSkin).GetInvariantInstantiationInfo() + InstantiationInfo = typeof(DefaultSkinTriangles).GetInvariantInstantiationInfo() }; private readonly IStorageResourceProvider resources; - public DefaultSkin(IStorageResourceProvider resources) + public DefaultSkinTriangles(IStorageResourceProvider resources) : this(CreateInfo(), resources) { } [UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)] - public DefaultSkin(SkinInfo skin, IStorageResourceProvider resources) + public DefaultSkinTriangles(SkinInfo skin, IStorageResourceProvider resources) : base(skin, resources) { this.resources = resources; diff --git a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs index d5690710bb..9ece48a6cb 100644 --- a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs +++ b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs @@ -81,7 +81,7 @@ namespace osu.Game.Skinning } } - int lastDefaultSkinIndex = sources.IndexOf(sources.OfType().LastOrDefault()); + int lastDefaultSkinIndex = sources.IndexOf(sources.OfType().LastOrDefault()); // Ruleset resources should be given the ability to override game-wide defaults // This is achieved by placing them before the last instance of DefaultSkin. diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index bf3cf77257..2984381604 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -19,7 +19,7 @@ namespace osu.Game.Skinning [JsonObject(MemberSerialization.OptIn)] public class SkinInfo : RealmObject, IHasRealmFiles, IEquatable, IHasGuidPrimaryKey, ISoftDelete, IHasNamedFiles { - internal static readonly Guid DEFAULT_SKIN = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD"); + internal static readonly Guid DEFAULT_SKIN_TRIANGLES = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD"); internal static readonly Guid CLASSIC_SKIN = new Guid("81F02CD3-EEC6-4865-AC23-FAE26A386187"); internal static readonly Guid RANDOM_SKIN = new Guid("D39DFEFB-477C-4372-B1EA-2BCEA5FB8908"); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 7ffea3b54f..bce58424d4 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -49,9 +49,9 @@ namespace osu.Game.Skinning public readonly Bindable CurrentSkin = new Bindable(); - public readonly Bindable> CurrentSkinInfo = new Bindable>(Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged()) + public readonly Bindable> CurrentSkinInfo = new Bindable>(Skinning.DefaultSkinTriangles.CreateInfo().ToLiveUnmanaged()) { - Default = Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged() + Default = Skinning.DefaultSkinTriangles.CreateInfo().ToLiveUnmanaged() }; private readonly SkinImporter skinImporter; @@ -61,7 +61,7 @@ namespace osu.Game.Skinning /// /// The default skin. /// - public Skin DefaultSkin { get; } + public Skin DefaultSkinTriangles { get; } /// /// The default legacy skin. @@ -86,7 +86,7 @@ namespace osu.Game.Skinning var defaultSkins = new[] { DefaultLegacySkin = new DefaultLegacySkin(this), - DefaultSkin = new DefaultSkin(this), + DefaultSkinTriangles = new DefaultSkinTriangles(this), }; // Ensure the default entries are present. @@ -104,7 +104,7 @@ namespace osu.Game.Skinning CurrentSkin.Value = skin.NewValue.PerformRead(GetSkin); }; - CurrentSkin.Value = DefaultSkin; + CurrentSkin.Value = DefaultSkinTriangles; CurrentSkin.ValueChanged += skin => { if (!skin.NewValue.SkinInfo.Equals(CurrentSkinInfo.Value)) @@ -125,7 +125,7 @@ namespace osu.Game.Skinning if (randomChoices.Length == 0) { - CurrentSkinInfo.Value = Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged(); + CurrentSkinInfo.Value = Skinning.DefaultSkinTriangles.CreateInfo().ToLiveUnmanaged(); return; } @@ -232,8 +232,8 @@ namespace osu.Game.Skinning if (CurrentSkin.Value is LegacySkin && CurrentSkin.Value != DefaultLegacySkin) yield return DefaultLegacySkin; - if (CurrentSkin.Value != DefaultSkin) - yield return DefaultSkin; + if (CurrentSkin.Value != DefaultSkinTriangles) + yield return DefaultSkinTriangles; } } @@ -294,7 +294,7 @@ namespace osu.Game.Skinning Guid currentUserSkin = CurrentSkinInfo.Value.ID; if (items.Any(s => s.ID == currentUserSkin)) - scheduler.Add(() => CurrentSkinInfo.Value = Skinning.DefaultSkin.CreateInfo().ToLiveUnmanaged()); + scheduler.Add(() => CurrentSkinInfo.Value = Skinning.DefaultSkinTriangles.CreateInfo().ToLiveUnmanaged()); Delete(items.ToList(), silent); }); @@ -313,7 +313,7 @@ namespace osu.Game.Skinning skinInfo = DefaultLegacySkin.SkinInfo; } - CurrentSkinInfo.Value = skinInfo ?? DefaultSkin.SkinInfo; + CurrentSkinInfo.Value = skinInfo ?? DefaultSkinTriangles.SkinInfo; } } } diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 57beb6e803..cb4a91691e 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -112,7 +112,7 @@ namespace osu.Game.Skinning // Temporarily used to exclude undesirable ISkin implementations static bool isUserSkin(ISkin skin) - => skin.GetType() == typeof(DefaultSkin) + => skin.GetType() == typeof(DefaultSkinTriangles) || skin.GetType() == typeof(DefaultLegacySkin) || skin.GetType() == typeof(LegacySkin); } diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 7278e1e93f..21ecdf7dbe 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual public abstract class SkinnableTestScene : OsuGridTestScene, IStorageResourceProvider { private Skin metricsSkin; - private Skin defaultSkin; + private Skin defaultSkinTriangles; private Skin specialSkin; private Skin oldSkin; @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual var dllStore = new DllResourceStore(GetType().Assembly); metricsSkin = new TestLegacySkin(new SkinInfo { Name = "metrics-skin" }, new NamespacedResourceStore(dllStore, "Resources/metrics_skin"), this, true); - defaultSkin = new DefaultLegacySkin(this); + defaultSkinTriangles = new DefaultLegacySkin(this); specialSkin = new TestLegacySkin(new SkinInfo { Name = "special-skin" }, new NamespacedResourceStore(dllStore, "Resources/special_skin"), this, true); oldSkin = new TestLegacySkin(new SkinInfo { Name = "old-skin" }, new NamespacedResourceStore(dllStore, "Resources/old_skin"), this, true); } @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual Cell(0).Child = createProvider(null, creationFunction, beatmap); Cell(1).Child = createProvider(metricsSkin, creationFunction, beatmap); - Cell(2).Child = createProvider(defaultSkin, creationFunction, beatmap); + Cell(2).Child = createProvider(defaultSkinTriangles, creationFunction, beatmap); Cell(3).Child = createProvider(specialSkin, creationFunction, beatmap); Cell(4).Child = createProvider(oldSkin, creationFunction, beatmap); } From 3e28ab72cefb4b28e1566662b75b72ed4fe1a016 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 15:49:15 +0900 Subject: [PATCH 1174/2686] Standardise default skin names --- osu.Game/Skinning/DefaultLegacySkin.cs | 2 +- osu.Game/Skinning/DefaultSkinTriangles.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Skinning/DefaultLegacySkin.cs b/osu.Game/Skinning/DefaultLegacySkin.cs index 2ebcc98c53..04f1286dc7 100644 --- a/osu.Game/Skinning/DefaultLegacySkin.cs +++ b/osu.Game/Skinning/DefaultLegacySkin.cs @@ -17,7 +17,7 @@ namespace osu.Game.Skinning public static SkinInfo CreateInfo() => new SkinInfo { ID = Skinning.SkinInfo.CLASSIC_SKIN, // this is temporary until database storage is decided upon. - Name = "osu!classic", + Name = "osu! \"classic\" (2013)", Creator = "team osu!", Protected = true, InstantiationInfo = typeof(DefaultLegacySkin).GetInvariantInstantiationInfo() diff --git a/osu.Game/Skinning/DefaultSkinTriangles.cs b/osu.Game/Skinning/DefaultSkinTriangles.cs index 26d933105a..02df247c36 100644 --- a/osu.Game/Skinning/DefaultSkinTriangles.cs +++ b/osu.Game/Skinning/DefaultSkinTriangles.cs @@ -27,7 +27,7 @@ namespace osu.Game.Skinning public static SkinInfo CreateInfo() => new SkinInfo { ID = osu.Game.Skinning.SkinInfo.DEFAULT_SKIN_TRIANGLES, - Name = "osu! (triangles)", + Name = "osu! \"triangles\" (2017)", Creator = "team osu!", Protected = true, InstantiationInfo = typeof(DefaultSkinTriangles).GetInvariantInstantiationInfo() From 487378f732989463c2431c4075d873e623da86fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 15:49:26 +0900 Subject: [PATCH 1175/2686] Fallback to default skin if instantiation fails --- osu.Game/Skinning/SkinInfo.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index 2984381604..9e268fd7ec 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -47,7 +47,17 @@ namespace osu.Game.Skinning ? typeof(LegacySkin) : Type.GetType(InstantiationInfo).AsNonNull(); - return (Skin)Activator.CreateInstance(type, this, resources); + try + { + return (Skin)Activator.CreateInstance(type, this, resources); + } + catch + { + // This defaults to triangles to catch the case where a user has a modified triangles skin. + // If we ever add more default skins in the future this will need some kind of proper migration rather than + // a single catch. + return new DefaultSkinTriangles(this, resources); + } } public IList Files { get; } = null!; From 64ee2108257326c9f188a966726732d097d531f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 16:17:48 +0900 Subject: [PATCH 1176/2686] Add realm migration to update skin names --- osu.Game/Database/RealmAccess.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index cefc7da503..edcd020226 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -69,8 +69,9 @@ namespace osu.Game.Database /// 22 2022-07-31 Added ModPreset. /// 23 2022-08-01 Added LastLocalUpdate to BeatmapInfo. /// 24 2022-08-22 Added MaximumStatistics to ScoreInfo. + /// 25 2022-09-18 Remove skins to add with new naming. /// - private const int schema_version = 24; + private const int schema_version = 25; /// /// Lock object which is held during sections, blocking realm retrieval during blocking periods. @@ -870,6 +871,11 @@ namespace osu.Game.Database } break; + + case 25: + // Remove the default skins so they can be added back by SkinManager with updated naming. + migration.NewRealm.RemoveRange(migration.NewRealm.All().Where(s => s.Protected)); + break; } } From 1b475f9360842a1704050a12ece8e1477a3006cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 16:21:39 +0900 Subject: [PATCH 1177/2686] Ensure skin `InstantiationInfo` is updated when saving --- osu.Game/Skinning/SkinImporter.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index f270abd163..701dcdfc2d 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -232,6 +232,9 @@ namespace osu.Game.Skinning { skin.SkinInfo.PerformWrite(s => { + // Update for safety + s.InstantiationInfo = skin.GetType().GetInvariantInstantiationInfo(); + // Serialise out the SkinInfo itself. string skinInfoJson = JsonConvert.SerializeObject(s, new JsonSerializerSettings { Formatting = Formatting.Indented }); From 1c4e02fae8db6e16a58f26c99c4238626d3b4d13 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 17 Sep 2022 23:58:42 +0900 Subject: [PATCH 1178/2686] Explicitly order default skins in dropdown to get correct order --- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 4787b07af8..f1a00dc958 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -78,8 +78,7 @@ namespace osu.Game.Overlays.Settings.Sections realmSubscription = realm.RegisterForNotifications(_ => realm.Realm.All() .Where(s => !s.DeletePending) - .OrderByDescending(s => s.Protected) // protected skins should be at the top. - .ThenBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged); + .OrderBy(s => s.Name, StringComparer.OrdinalIgnoreCase), skinsChanged); skinDropdown.Current.BindValueChanged(skin => { @@ -101,14 +100,17 @@ namespace osu.Game.Overlays.Settings.Sections if (!sender.Any()) return; - int protectedCount = sender.Count(s => s.Protected); - // For simplicity repopulate the full list. // In the future we should change this to properly handle ChangeSet events. dropdownItems.Clear(); - foreach (var skin in sender) + + dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.DEFAULT_SKIN_TRIANGLES).ToLive(realm)); + dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.CLASSIC_SKIN).ToLive(realm)); + + dropdownItems.Add(random_skin_info); + + foreach (var skin in sender.Where(s => !s.Protected)) dropdownItems.Add(skin.ToLive(realm)); - dropdownItems.Insert(protectedCount, random_skin_info); Schedule(() => skinDropdown.Items = dropdownItems); } From 41e69fbca69bd23f824660c883bf6d50f5e3e0eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Sep 2022 00:14:49 +0900 Subject: [PATCH 1179/2686] Remove "default" prefix from naming --- .../TestSceneCatchSkinConfiguration.cs | 2 +- .../Editor/TestSceneManiaComposeScreen.cs | 2 +- osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs | 2 +- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 4 ++-- .../Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 2 +- .../Visual/Navigation/TestSceneEditDefaultSkin.cs | 4 ++-- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +- .../Screens/Backgrounds/BackgroundScreenDefault.cs | 2 +- osu.Game/Skinning/RulesetSkinProvidingContainer.cs | 2 +- osu.Game/Skinning/SkinInfo.cs | 4 ++-- osu.Game/Skinning/SkinManager.cs | 10 +++++----- osu.Game/Skinning/SkinnableSprite.cs | 2 +- .../{DefaultSkinTriangles.cs => TrianglesSkin.cs} | 10 +++++----- osu.Game/Tests/Visual/SkinnableTestScene.cs | 6 +++--- 15 files changed, 28 insertions(+), 28 deletions(-) rename osu.Game/Skinning/{DefaultSkinTriangles.cs => TrianglesSkin.cs} (95%) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs index 06235d3744..a4b2b26624 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Catch.Tests }); } - private class TestSkin : DefaultSkinTriangles + private class TestSkin : TrianglesSkin { public bool FlipCatcherPlate { get; set; } diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs index 9e02424eb8..e96a186ae4 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor [Test] public void TestDefaultSkin() { - AddStep("set default skin", () => skins.CurrentSkinInfo.Value = DefaultSkinTriangles.CreateInfo().ToLiveUnmanaged()); + AddStep("set default skin", () => skins.CurrentSkinInfo.Value = TrianglesSkin.CreateInfo().ToLiveUnmanaged()); } [Test] diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs index d3f58ca868..57734236da 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Tests hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - Child = new SkinProvidingContainer(new DefaultSkinTriangles(null)) + Child = new SkinProvidingContainer(new TrianglesSkin(null)) { RelativeSizeAxes = Axes.Both, Child = drawableHitCircle = new DrawableHitCircle(hitCircle) diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index 57f2578200..d87bee0d05 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -202,7 +202,7 @@ namespace osu.Game.Tests.Skins.IO skinManager.CurrentSkinInfo.Value.PerformRead(s => { Assert.IsFalse(s.Protected); - Assert.AreEqual(typeof(DefaultSkinTriangles), s.CreateInstance(skinManager).GetType()); + Assert.AreEqual(typeof(TrianglesSkin), s.CreateInstance(skinManager).GetType()); new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream); @@ -215,7 +215,7 @@ namespace osu.Game.Tests.Skins.IO { Assert.IsFalse(s.Protected); Assert.AreNotEqual(originalSkinId, s.ID); - Assert.AreEqual(typeof(DefaultSkinTriangles), s.CreateInstance(skinManager).GetType()); + Assert.AreEqual(typeof(TrianglesSkin), s.CreateInstance(skinManager).GetType()); }); return Task.CompletedTask; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index b24a65820d..01cc856a4a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestEmptyLegacyBeatmapSkinFallsBack() { - CreateSkinTest(DefaultSkinTriangles.CreateInfo(), () => new LegacyBeatmapSkin(new BeatmapInfo(), null)); + CreateSkinTest(TrianglesSkin.CreateInfo(), () => new LegacyBeatmapSkin(new BeatmapInfo(), null)); AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded)); AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value)); } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs index bc6458b62b..3757c49f18 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs @@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestEditDefaultSkin() { - AddAssert("is default skin", () => skinManager.CurrentSkinInfo.Value.ID == SkinInfo.DEFAULT_SKIN_TRIANGLES); + AddAssert("is default skin", () => skinManager.CurrentSkinInfo.Value.ID == SkinInfo.TRIANGLES_SKIN); AddStep("open settings", () => { Game.Settings.Show(); }); @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("open skin editor", () => skinEditor.Show()); // Until step required as the skin editor may take time to load (and an extra scheduled frame for the mutable part). - AddUntilStep("is modified default skin", () => skinManager.CurrentSkinInfo.Value.ID != SkinInfo.DEFAULT_SKIN_TRIANGLES); + AddUntilStep("is modified default skin", () => skinManager.CurrentSkinInfo.Value.ID != SkinInfo.TRIANGLES_SKIN); AddAssert("is not protected", () => skinManager.CurrentSkinInfo.Value.PerformRead(s => !s.Protected)); AddUntilStep("export button enabled", () => Game.Settings.ChildrenOfType().SingleOrDefault()?.Enabled.Value == true); diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index ec97508522..54c545e367 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -39,7 +39,7 @@ namespace osu.Game.Configuration { // UI/selection defaults SetDefault(OsuSetting.Ruleset, string.Empty); - SetDefault(OsuSetting.Skin, SkinInfo.DEFAULT_SKIN_TRIANGLES.ToString()); + SetDefault(OsuSetting.Skin, SkinInfo.TRIANGLES_SKIN.ToString()); SetDefault(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details); SetDefault(OsuSetting.BeatmapDetailModsFilter, false); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index f1a00dc958..8d491a980a 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.Settings.Sections // In the future we should change this to properly handle ChangeSet events. dropdownItems.Clear(); - dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.DEFAULT_SKIN_TRIANGLES).ToLive(realm)); + dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.TRIANGLES_SKIN).ToLive(realm)); dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.CLASSIC_SKIN).ToLive(realm)); dropdownItems.Add(random_skin_info); diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index e04e6d4849..dbc4e2b2e1 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Backgrounds case BackgroundSource.Skin: // default skins should use the default background rotation, which won't be the case if a SkinBackground is created for them. - if (skin.Value is DefaultSkinTriangles || skin.Value is DefaultLegacySkin) + if (skin.Value is TrianglesSkin || skin.Value is DefaultLegacySkin) break; newBackground = new SkinBackground(skin.Value, getBackgroundTextureName()); diff --git a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs index 9ece48a6cb..4c35681f66 100644 --- a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs +++ b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs @@ -81,7 +81,7 @@ namespace osu.Game.Skinning } } - int lastDefaultSkinIndex = sources.IndexOf(sources.OfType().LastOrDefault()); + int lastDefaultSkinIndex = sources.IndexOf(sources.OfType().LastOrDefault()); // Ruleset resources should be given the ability to override game-wide defaults // This is achieved by placing them before the last instance of DefaultSkin. diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index 9e268fd7ec..63f3fd12d1 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -19,7 +19,7 @@ namespace osu.Game.Skinning [JsonObject(MemberSerialization.OptIn)] public class SkinInfo : RealmObject, IHasRealmFiles, IEquatable, IHasGuidPrimaryKey, ISoftDelete, IHasNamedFiles { - internal static readonly Guid DEFAULT_SKIN_TRIANGLES = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD"); + internal static readonly Guid TRIANGLES_SKIN = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD"); internal static readonly Guid CLASSIC_SKIN = new Guid("81F02CD3-EEC6-4865-AC23-FAE26A386187"); internal static readonly Guid RANDOM_SKIN = new Guid("D39DFEFB-477C-4372-B1EA-2BCEA5FB8908"); @@ -56,7 +56,7 @@ namespace osu.Game.Skinning // This defaults to triangles to catch the case where a user has a modified triangles skin. // If we ever add more default skins in the future this will need some kind of proper migration rather than // a single catch. - return new DefaultSkinTriangles(this, resources); + return new TrianglesSkin(this, resources); } } diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index bce58424d4..20af72e4f6 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -49,9 +49,9 @@ namespace osu.Game.Skinning public readonly Bindable CurrentSkin = new Bindable(); - public readonly Bindable> CurrentSkinInfo = new Bindable>(Skinning.DefaultSkinTriangles.CreateInfo().ToLiveUnmanaged()) + public readonly Bindable> CurrentSkinInfo = new Bindable>(TrianglesSkin.CreateInfo().ToLiveUnmanaged()) { - Default = Skinning.DefaultSkinTriangles.CreateInfo().ToLiveUnmanaged() + Default = TrianglesSkin.CreateInfo().ToLiveUnmanaged() }; private readonly SkinImporter skinImporter; @@ -86,7 +86,7 @@ namespace osu.Game.Skinning var defaultSkins = new[] { DefaultLegacySkin = new DefaultLegacySkin(this), - DefaultSkinTriangles = new DefaultSkinTriangles(this), + DefaultSkinTriangles = new TrianglesSkin(this), }; // Ensure the default entries are present. @@ -125,7 +125,7 @@ namespace osu.Game.Skinning if (randomChoices.Length == 0) { - CurrentSkinInfo.Value = Skinning.DefaultSkinTriangles.CreateInfo().ToLiveUnmanaged(); + CurrentSkinInfo.Value = TrianglesSkin.CreateInfo().ToLiveUnmanaged(); return; } @@ -294,7 +294,7 @@ namespace osu.Game.Skinning Guid currentUserSkin = CurrentSkinInfo.Value.ID; if (items.Any(s => s.ID == currentUserSkin)) - scheduler.Add(() => CurrentSkinInfo.Value = Skinning.DefaultSkinTriangles.CreateInfo().ToLiveUnmanaged()); + scheduler.Add(() => CurrentSkinInfo.Value = TrianglesSkin.CreateInfo().ToLiveUnmanaged()); Delete(items.ToList(), silent); }); diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index cb4a91691e..69454de979 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -112,7 +112,7 @@ namespace osu.Game.Skinning // Temporarily used to exclude undesirable ISkin implementations static bool isUserSkin(ISkin skin) - => skin.GetType() == typeof(DefaultSkinTriangles) + => skin.GetType() == typeof(TrianglesSkin) || skin.GetType() == typeof(DefaultLegacySkin) || skin.GetType() == typeof(LegacySkin); } diff --git a/osu.Game/Skinning/DefaultSkinTriangles.cs b/osu.Game/Skinning/TrianglesSkin.cs similarity index 95% rename from osu.Game/Skinning/DefaultSkinTriangles.cs rename to osu.Game/Skinning/TrianglesSkin.cs index 02df247c36..2c70963524 100644 --- a/osu.Game/Skinning/DefaultSkinTriangles.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -22,26 +22,26 @@ using osuTK.Graphics; namespace osu.Game.Skinning { - public class DefaultSkinTriangles : Skin + public class TrianglesSkin : Skin { public static SkinInfo CreateInfo() => new SkinInfo { - ID = osu.Game.Skinning.SkinInfo.DEFAULT_SKIN_TRIANGLES, + ID = osu.Game.Skinning.SkinInfo.TRIANGLES_SKIN, Name = "osu! \"triangles\" (2017)", Creator = "team osu!", Protected = true, - InstantiationInfo = typeof(DefaultSkinTriangles).GetInvariantInstantiationInfo() + InstantiationInfo = typeof(TrianglesSkin).GetInvariantInstantiationInfo() }; private readonly IStorageResourceProvider resources; - public DefaultSkinTriangles(IStorageResourceProvider resources) + public TrianglesSkin(IStorageResourceProvider resources) : this(CreateInfo(), resources) { } [UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)] - public DefaultSkinTriangles(SkinInfo skin, IStorageResourceProvider resources) + public TrianglesSkin(SkinInfo skin, IStorageResourceProvider resources) : base(skin, resources) { this.resources = resources; diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 21ecdf7dbe..0299a45238 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual public abstract class SkinnableTestScene : OsuGridTestScene, IStorageResourceProvider { private Skin metricsSkin; - private Skin defaultSkinTriangles; + private Skin trianglesSkin; private Skin specialSkin; private Skin oldSkin; @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual var dllStore = new DllResourceStore(GetType().Assembly); metricsSkin = new TestLegacySkin(new SkinInfo { Name = "metrics-skin" }, new NamespacedResourceStore(dllStore, "Resources/metrics_skin"), this, true); - defaultSkinTriangles = new DefaultLegacySkin(this); + trianglesSkin = new DefaultLegacySkin(this); specialSkin = new TestLegacySkin(new SkinInfo { Name = "special-skin" }, new NamespacedResourceStore(dllStore, "Resources/special_skin"), this, true); oldSkin = new TestLegacySkin(new SkinInfo { Name = "old-skin" }, new NamespacedResourceStore(dllStore, "Resources/old_skin"), this, true); } @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual Cell(0).Child = createProvider(null, creationFunction, beatmap); Cell(1).Child = createProvider(metricsSkin, creationFunction, beatmap); - Cell(2).Child = createProvider(defaultSkinTriangles, creationFunction, beatmap); + Cell(2).Child = createProvider(trianglesSkin, creationFunction, beatmap); Cell(3).Child = createProvider(specialSkin, creationFunction, beatmap); Cell(4).Child = createProvider(oldSkin, creationFunction, beatmap); } From 9a10ecb3789630bd3715ce5e38ffd2cfe5bc1b24 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 17 Sep 2022 19:37:30 +0300 Subject: [PATCH 1180/2686] Clarify purpose of `APIUserScoreAggregate` --- .../Online/API/Requests/Responses/APIUserScoreAggregate.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/APIUserScoreAggregate.cs b/osu.Game/Online/API/Requests/Responses/APIUserScoreAggregate.cs index 30433ab8cd..c870157fec 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUserScoreAggregate.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUserScoreAggregate.cs @@ -10,6 +10,9 @@ using osu.Game.Scoring; namespace osu.Game.Online.API.Requests.Responses { + /// + /// Represents an aggregate score for a user based off all beatmaps that have been played in the playlist. + /// public class APIUserScoreAggregate { [JsonProperty("attempts")] From 3c7ea5c8fadbc0348f5f84304c2872ff1d831a64 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Sat, 17 Sep 2022 18:57:09 +0200 Subject: [PATCH 1181/2686] Update --- osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs | 2 +- osu.Game/Screens/Edit/EditorBeatmap.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 9e96a7386d..721f0c4e3b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -196,7 +196,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { defaultTimelineZoom = getZoomLevelForVisibleMilliseconds(6000); - float initialZoom = (float)(defaultTimelineZoom * editorBeatmap.BeatmapInfo.TimelineZoom); + float initialZoom = (float)(defaultTimelineZoom * (editorBeatmap.BeatmapInfo.TimelineZoom == 0 ? 1 : editorBeatmap.BeatmapInfo.TimelineZoom)); float minimumZoom = getZoomLevelForVisibleMilliseconds(10000); float maximumZoom = getZoomLevelForVisibleMilliseconds(500); diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 356276039c..16c0064e80 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -96,7 +96,6 @@ namespace osu.Game.Screens.Edit PlayableBeatmap.ControlPointInfo = ConvertControlPoints(PlayableBeatmap.ControlPointInfo); this.beatmapInfo = beatmapInfo ?? playableBeatmap.BeatmapInfo; - if (this.beatmapInfo.TimelineZoom <= 0) this.beatmapInfo.TimelineZoom = 1; if (beatmapSkin is Skin skin) { From c8768eb39919c649556a4bb508f1bbde4863a765 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Sat, 17 Sep 2022 19:00:50 +0200 Subject: [PATCH 1182/2686] Changed == to <= on TimelineZoom check --- osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 721f0c4e3b..09fa2c8cee 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -196,7 +196,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { defaultTimelineZoom = getZoomLevelForVisibleMilliseconds(6000); - float initialZoom = (float)(defaultTimelineZoom * (editorBeatmap.BeatmapInfo.TimelineZoom == 0 ? 1 : editorBeatmap.BeatmapInfo.TimelineZoom)); + float initialZoom = (float)(defaultTimelineZoom * (editorBeatmap.BeatmapInfo.TimelineZoom <= 0 ? 1 : editorBeatmap.BeatmapInfo.TimelineZoom)); float minimumZoom = getZoomLevelForVisibleMilliseconds(10000); float maximumZoom = getZoomLevelForVisibleMilliseconds(500); From 9d94343317a00d8cf122b88baf7757cd4c584fae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Vaj=C4=8F=C3=A1k?= Date: Sat, 17 Sep 2022 19:51:44 +0200 Subject: [PATCH 1183/2686] Update osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs Co-authored-by: Salman Ahmed --- osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 09fa2c8cee..721f0c4e3b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -196,7 +196,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { defaultTimelineZoom = getZoomLevelForVisibleMilliseconds(6000); - float initialZoom = (float)(defaultTimelineZoom * (editorBeatmap.BeatmapInfo.TimelineZoom <= 0 ? 1 : editorBeatmap.BeatmapInfo.TimelineZoom)); + float initialZoom = (float)(defaultTimelineZoom * (editorBeatmap.BeatmapInfo.TimelineZoom == 0 ? 1 : editorBeatmap.BeatmapInfo.TimelineZoom)); float minimumZoom = getZoomLevelForVisibleMilliseconds(10000); float maximumZoom = getZoomLevelForVisibleMilliseconds(500); From c075d3de08accdd9f49d1e347a3aad4b6607a078 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Sat, 17 Sep 2022 22:43:40 +0200 Subject: [PATCH 1184/2686] Create a test and a check if initial zoom value of ZoomableScrollContainer is in range --- .../Editing/TestSceneZoomableScrollContainer.cs | 13 +++++++++++++ .../Components/Timeline/ZoomableScrollContainer.cs | 3 +++ 2 files changed, 16 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs index ce418f33f0..1858aee76b 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; @@ -66,6 +67,18 @@ namespace osu.Game.Tests.Visual.Editing AddUntilStep("Scroll container is loaded", () => scrollContainer.LoadState >= LoadState.Loaded); } + [Test] + public void TestInitialZoomOutOfRange() + { + AddStep("Invalid ZoomableScrollContainer throws ArgumentException", () => + { + Assert.Throws(() => + { + _ = new ZoomableScrollContainer(1, 60, 0); + }); + }); + } + [Test] public void TestWidthInitialization() { diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index 7d51284f46..0fb59a8a1f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -87,6 +87,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline if (minimum > maximum) throw new ArgumentException($"{nameof(minimum)} ({minimum}) must be less than {nameof(maximum)} ({maximum})"); + if (initial < minimum || initial > maximum) + throw new ArgumentException($"{nameof(initial)} ({initial}) must be between {nameof(minimum)} ({minimum}) and {nameof(maximum)} ({maximum})"); + minZoom = minimum; maxZoom = maximum; CurrentZoom = zoomTarget = initial; From beef3b418ad1e1ba4023a55348992f69e40fbcde Mon Sep 17 00:00:00 2001 From: O Thiago Date: Sat, 17 Sep 2022 23:41:23 -0400 Subject: [PATCH 1185/2686] Simplifies size calculation --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 558605efc3..a34e55faae 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -50,6 +50,11 @@ namespace osu.Game.Rulesets.Mods where T : HitObject { public const double FLASHLIGHT_FADE_DURATION = 800; + + private const int flashlight_size_decrease_combo = 100; + private const int last_flashlight_size_decrease_combo = 200; + private const float decrease_flashlight_with_combo_multiplier = 0.1f; + protected readonly BindableInt Combo = new BindableInt(); public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) @@ -147,16 +152,12 @@ namespace osu.Game.Rulesets.Mods protected float GetSizeFor(int combo) { float size = defaultFlashlightSize * sizeMultiplier; + int comboForSize = Math.Min(combo, last_flashlight_size_decrease_combo); - if (comboBasedSize) - { - if (combo > 200) - size *= 0.8f; - else if (combo > 100) - size *= 0.9f; - } + if (!comboBasedSize) + comboForSize = 0; - return size; + return size * (1 - decrease_flashlight_with_combo_multiplier * MathF.Floor(MathF.Min(comboForSize, last_flashlight_size_decrease_combo) / flashlight_size_decrease_combo)); } private Vector2 flashlightPosition; From 8464a1941bef4c47a949a1c935bdc58aa2b8791f Mon Sep 17 00:00:00 2001 From: O Thiago Date: Sat, 17 Sep 2022 23:49:23 -0400 Subject: [PATCH 1186/2686] Use linq expression for handling breaks --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index a34e55faae..f43f54541d 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -132,13 +133,8 @@ namespace osu.Game.Rulesets.Mods using (BeginAbsoluteSequence(0)) { - foreach (var breakPeriod in Breaks) + foreach (BreakPeriod breakPeriod in Breaks.Where(breakPeriod => breakPeriod.HasEffect && breakPeriod.Duration >= FLASHLIGHT_FADE_DURATION * 2)) { - if (!breakPeriod.HasEffect) - continue; - - if (breakPeriod.Duration < FLASHLIGHT_FADE_DURATION * 2) continue; - this.Delay(breakPeriod.StartTime + FLASHLIGHT_FADE_DURATION).FadeOutFromOne(FLASHLIGHT_FADE_DURATION); this.Delay(breakPeriod.EndTime - FLASHLIGHT_FADE_DURATION).FadeInFromZero(FLASHLIGHT_FADE_DURATION); } From 3b87ecf56c0f473b7081bad10e715825becbc6b8 Mon Sep 17 00:00:00 2001 From: O Thiago Date: Sun, 18 Sep 2022 00:18:17 -0400 Subject: [PATCH 1187/2686] renames variables to make more logical sense --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index f43f54541d..4d24bdfa02 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -53,8 +53,8 @@ namespace osu.Game.Rulesets.Mods public const double FLASHLIGHT_FADE_DURATION = 800; private const int flashlight_size_decrease_combo = 100; - private const int last_flashlight_size_decrease_combo = 200; - private const float decrease_flashlight_with_combo_multiplier = 0.1f; + private const int flashlight_size_decrease_combo_max = 200; + private const float flashlight_size_decrease_with_combo_multiplier = 0.1f; protected readonly BindableInt Combo = new BindableInt(); @@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Mods using (BeginAbsoluteSequence(0)) { - foreach (BreakPeriod breakPeriod in Breaks.Where(breakPeriod => breakPeriod.HasEffect && breakPeriod.Duration >= FLASHLIGHT_FADE_DURATION * 2)) + foreach (var breakPeriod in Breaks.Where(breakPeriod => breakPeriod.HasEffect && breakPeriod.Duration >= FLASHLIGHT_FADE_DURATION * 2)) { this.Delay(breakPeriod.StartTime + FLASHLIGHT_FADE_DURATION).FadeOutFromOne(FLASHLIGHT_FADE_DURATION); this.Delay(breakPeriod.EndTime - FLASHLIGHT_FADE_DURATION).FadeInFromZero(FLASHLIGHT_FADE_DURATION); @@ -148,12 +148,12 @@ namespace osu.Game.Rulesets.Mods protected float GetSizeFor(int combo) { float size = defaultFlashlightSize * sizeMultiplier; - int comboForSize = Math.Min(combo, last_flashlight_size_decrease_combo); + int comboForSize = Math.Min(combo, flashlight_size_decrease_combo_max); if (!comboBasedSize) comboForSize = 0; - return size * (1 - decrease_flashlight_with_combo_multiplier * MathF.Floor(MathF.Min(comboForSize, last_flashlight_size_decrease_combo) / flashlight_size_decrease_combo)); + return size * (1 - flashlight_size_decrease_with_combo_multiplier * MathF.Floor(MathF.Min(comboForSize, flashlight_size_decrease_combo_max) / flashlight_size_decrease_combo)); } private Vector2 flashlightPosition; From ac4229e3d4654b07758617e6c274d7cde550caad Mon Sep 17 00:00:00 2001 From: O Thiago Date: Sun, 18 Sep 2022 00:38:01 -0400 Subject: [PATCH 1188/2686] Removes overhead when not combo based size --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 4d24bdfa02..490f9120b1 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -148,12 +148,11 @@ namespace osu.Game.Rulesets.Mods protected float GetSizeFor(int combo) { float size = defaultFlashlightSize * sizeMultiplier; - int comboForSize = Math.Min(combo, flashlight_size_decrease_combo_max); - if (!comboBasedSize) - comboForSize = 0; + if (comboBasedSize) + size *= 1 - flashlight_size_decrease_with_combo_multiplier * MathF.Floor(MathF.Min(combo, flashlight_size_decrease_combo_max) / flashlight_size_decrease_combo); - return size * (1 - flashlight_size_decrease_with_combo_multiplier * MathF.Floor(MathF.Min(comboForSize, flashlight_size_decrease_combo_max) / flashlight_size_decrease_combo)); + return size; } private Vector2 flashlightPosition; From 2dcaf7cfd8ee9294cc6c7162d01520f24e9e0691 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Sun, 18 Sep 2022 14:25:31 +0900 Subject: [PATCH 1189/2686] Fix memory leak due to missing event unbind --- .../Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs index 1f80c47d13..5a297f18db 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs @@ -110,6 +110,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer if (Client != null) { Client.RoomUpdated -= invokeOnRoomUpdated; + Client.LoadRequested -= invokeOnRoomLoadRequested; Client.UserLeft -= invokeUserLeft; Client.UserKicked -= invokeUserKicked; Client.UserJoined -= invokeUserJoined; From d0b8409de5418fec79d0b21c64ce0d2c25ff3357 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Sep 2022 18:18:10 +0900 Subject: [PATCH 1190/2686] Apply more renames --- .../Skinning/Legacy/LegacyHitExplosion.cs | 2 +- .../TestSceneCursorParticles.cs | 2 +- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 2 +- .../Visual/Gameplay/TestSceneParticleSpewer.cs | 2 +- osu.Game/Skinning/SkinManager.cs | 14 +++++++------- osu.Game/Tests/Visual/SkinnableTestScene.cs | 10 ++++++---- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs index 0630de9156..8f46bdbe6e 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy [BackgroundDependencyLoader] private void load(SkinManager skins) { - var defaultLegacySkin = skins.DefaultLegacySkin; + var defaultLegacySkin = skins.DefaultClassicSkin; // sprite names intentionally swapped to match stable member naming / ease of cross-referencing explosion1.Texture = defaultLegacySkin.GetTexture("scoreboard-explosion-2"); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs index b5d1c4854c..7f0ecaca2b 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs @@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Tests }); AddStep("setup default legacy skin", () => { - skinManager.CurrentSkinInfo.Value = skinManager.DefaultLegacySkin.SkinInfo; + skinManager.CurrentSkinInfo.Value = skinManager.DefaultClassicSkin.SkinInfo; }); }); } diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index d87bee0d05..3cbc205eaf 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -226,7 +226,7 @@ namespace osu.Game.Tests.Skins.IO { var skinManager = osu.Dependencies.Get(); - skinManager.CurrentSkinInfo.Value = skinManager.DefaultLegacySkin.SkinInfo; + skinManager.CurrentSkinInfo.Value = skinManager.DefaultClassicSkin.SkinInfo; skinManager.EnsureMutableSkin(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index 26706d9465..66441c8bad 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -79,7 +79,7 @@ namespace osu.Game.Tests.Visual.Gameplay } private TestParticleSpewer createSpewer() => - new TestParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2")) + new TestParticleSpewer(skinManager.DefaultClassicSkin.GetTexture("star2")) { Origin = Anchor.Centre, RelativePositionAxes = Axes.Both, diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 20af72e4f6..a9a01dfebf 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -59,14 +59,14 @@ namespace osu.Game.Skinning private readonly IResourceStore userFiles; /// - /// The default skin. + /// The default "triangles" skin. /// public Skin DefaultSkinTriangles { get; } /// - /// The default legacy skin. + /// The default "classic" skin. /// - public Skin DefaultLegacySkin { get; } + public Skin DefaultClassicSkin { get; } public SkinManager(Storage storage, RealmAccess realm, GameHost host, IResourceStore resources, AudioManager audio, Scheduler scheduler) : base(storage, realm) @@ -85,7 +85,7 @@ namespace osu.Game.Skinning var defaultSkins = new[] { - DefaultLegacySkin = new DefaultLegacySkin(this), + DefaultClassicSkin = new DefaultLegacySkin(this), DefaultSkinTriangles = new TrianglesSkin(this), }; @@ -229,8 +229,8 @@ namespace osu.Game.Skinning { yield return CurrentSkin.Value; - if (CurrentSkin.Value is LegacySkin && CurrentSkin.Value != DefaultLegacySkin) - yield return DefaultLegacySkin; + if (CurrentSkin.Value is LegacySkin && CurrentSkin.Value != DefaultClassicSkin) + yield return DefaultClassicSkin; if (CurrentSkin.Value != DefaultSkinTriangles) yield return DefaultSkinTriangles; @@ -310,7 +310,7 @@ namespace osu.Game.Skinning if (skinInfo == null) { if (guid == SkinInfo.CLASSIC_SKIN) - skinInfo = DefaultLegacySkin.SkinInfo; + skinInfo = DefaultClassicSkin.SkinInfo; } CurrentSkinInfo.Value = skinInfo ?? DefaultSkinTriangles.SkinInfo; diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 0299a45238..75224742a2 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -29,8 +29,9 @@ namespace osu.Game.Tests.Visual { public abstract class SkinnableTestScene : OsuGridTestScene, IStorageResourceProvider { + private TrianglesSkin trianglesSkin; private Skin metricsSkin; - private Skin trianglesSkin; + private Skin legacySkin; private Skin specialSkin; private Skin oldSkin; @@ -47,8 +48,9 @@ namespace osu.Game.Tests.Visual { var dllStore = new DllResourceStore(GetType().Assembly); + trianglesSkin = new TrianglesSkin(this); metricsSkin = new TestLegacySkin(new SkinInfo { Name = "metrics-skin" }, new NamespacedResourceStore(dllStore, "Resources/metrics_skin"), this, true); - trianglesSkin = new DefaultLegacySkin(this); + legacySkin = new DefaultLegacySkin(this); specialSkin = new TestLegacySkin(new SkinInfo { Name = "special-skin" }, new NamespacedResourceStore(dllStore, "Resources/special_skin"), this, true); oldSkin = new TestLegacySkin(new SkinInfo { Name = "old-skin" }, new NamespacedResourceStore(dllStore, "Resources/old_skin"), this, true); } @@ -61,9 +63,9 @@ namespace osu.Game.Tests.Visual var beatmap = CreateBeatmapForSkinProvider(); - Cell(0).Child = createProvider(null, creationFunction, beatmap); + Cell(0).Child = createProvider(trianglesSkin, creationFunction, beatmap); Cell(1).Child = createProvider(metricsSkin, creationFunction, beatmap); - Cell(2).Child = createProvider(trianglesSkin, creationFunction, beatmap); + Cell(2).Child = createProvider(legacySkin, creationFunction, beatmap); Cell(3).Child = createProvider(specialSkin, creationFunction, beatmap); Cell(4).Child = createProvider(oldSkin, creationFunction, beatmap); } From 6a06a5b1b5476deb96e8e405cbd83fef66071b48 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Sep 2022 18:20:28 +0900 Subject: [PATCH 1191/2686] Reword fallback instantiation handling comment to hopefully explain things better --- osu.Game/Skinning/SkinInfo.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index 63f3fd12d1..34728245c8 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -53,7 +53,8 @@ namespace osu.Game.Skinning } catch { - // This defaults to triangles to catch the case where a user has a modified triangles skin. + // Since the class was renamed from "DefaultSkin" to "TrianglesSkin", the instantiation would fail + // for user modified skins. This aims to amicably handle that. // If we ever add more default skins in the future this will need some kind of proper migration rather than // a single catch. return new TrianglesSkin(this, resources); From 0ac28cbecc2c58d4acdb614fe291b42bf3d291b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Sep 2022 23:42:16 +0900 Subject: [PATCH 1192/2686] Fix potential crash from missing `DownloadProgress` --- .../Multiplayer/Participants/StateDisplay.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs index 9c05c19d1b..ecef7509d9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs @@ -1,10 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; -using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -25,9 +22,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { private const double fade_time = 50; - private SpriteIcon icon; - private OsuSpriteText text; - private ProgressBar progressBar; + private SpriteIcon icon = null!; + private OsuSpriteText text = null!; + private ProgressBar progressBar = null!; public StateDisplay() { @@ -86,7 +83,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants }; } - private OsuColour colours; + private OsuColour colours = null!; public void UpdateStatus(MultiplayerUserState state, BeatmapAvailability availability) { @@ -164,10 +161,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants break; case DownloadState.Downloading: - Debug.Assert(availability.DownloadProgress != null); - progressBar.FadeIn(fade_time); - progressBar.CurrentTime = availability.DownloadProgress.Value; + progressBar.CurrentTime = availability.DownloadProgress ?? 0; text.Text = "downloading map"; icon.Icon = FontAwesome.Solid.ArrowAltCircleDown; From 6d7d80a4fbb09f2f89d82bfc3366b71d3d06b259 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Sun, 18 Sep 2022 17:29:08 +0200 Subject: [PATCH 1193/2686] Made X position value of CatchHitObject clamp to CatchPlayfield's width --- osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index 6e01c44e1f..c6d63f6b81 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using Newtonsoft.Json; using osu.Framework.Bindables; using osu.Game.Beatmaps; @@ -33,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Objects [JsonIgnore] public float X { - set => originalX.Value = value; + set => originalX.Value = Math.Clamp(value, 0, CatchPlayfield.WIDTH); } private HitObjectProperty xOffset; From 493efd84a3900f4c439887f5db931fb699d143f7 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Sun, 18 Sep 2022 12:08:34 -0700 Subject: [PATCH 1194/2686] Basic smoke path implementation --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 5 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 1 + osu.Game.Rulesets.Osu/OsuSkinComponents.cs | 1 + .../Skinning/Default/DefaultSmoke.cs | 14 ++ .../Skinning/Legacy/LegacySmoke.cs | 26 ++++ .../Legacy/OsuLegacySkinTransformer.cs | 6 + osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 131 ++++++++++++++++++ osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 2 + osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 57 ++++++++ 9 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Smoke.cs create mode 100644 osu.Game.Rulesets.Osu/UI/SmokeContainer.cs diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 12256e93d0..dec965e567 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -80,6 +80,9 @@ namespace osu.Game.Rulesets.Osu LeftButton, [Description("Right button")] - RightButton + RightButton, + + [Description("Smoke")] + Smoke, } } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 302194e91a..76465fe3d5 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -57,6 +57,7 @@ namespace osu.Game.Rulesets.Osu { new KeyBinding(InputKey.Z, OsuAction.LeftButton), new KeyBinding(InputKey.X, OsuAction.RightButton), + new KeyBinding(InputKey.C, OsuAction.Smoke), new KeyBinding(InputKey.MouseLeft, OsuAction.LeftButton), new KeyBinding(InputKey.MouseRight, OsuAction.RightButton), }; diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs index fcf079b6aa..11daa26072 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs @@ -21,6 +21,7 @@ namespace osu.Game.Rulesets.Osu SliderBall, SliderBody, SpinnerBody, + Smoke, ApproachCircle, } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs new file mode 100644 index 0000000000..3c798c2afa --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -0,0 +1,14 @@ +// 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.Osu.Skinning.Default +{ + public class DefaultSmoke : Smoke + { + public DefaultSmoke() + { + Texture = null; + PathRadius = 2; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs new file mode 100644 index 0000000000..9494d31a63 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -0,0 +1,26 @@ +// 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.Skinning; + +namespace osu.Game.Rulesets.Osu.Skinning.Legacy +{ + public class LegacySmoke : Smoke + { + private ISkin skin; + + public LegacySmoke(ISkin skin) + { + this.skin = skin; + + PathRadius = 8; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Texture = skin.GetTexture("cursor-smoke"); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 885a2c12fb..a9186f821e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -106,6 +106,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return null; + case OsuSkinComponents.Smoke: + if (GetTexture("cursor-smoke") != null) + return new LegacySmoke(this); + + return null; + case OsuSkinComponents.HitCircleText: if (!this.HasFont(LegacyFont.HitCircle)) return null; diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs new file mode 100644 index 0000000000..6c60392c94 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -0,0 +1,131 @@ +// 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.Diagnostics; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Lines; +using osu.Game.Rulesets.Osu.UI; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Skinning +{ + public abstract class Smoke : TexturedPath + { + protected bool IsActive { get; private set; } + protected double SmokeTimeStart { get; private set; } = double.MinValue; + protected double SmokeTimeEnd { get; private set; } = double.MinValue; + + protected readonly List SmokeVertexPositions = new List(); + protected readonly List SmokeVertexTimes = new List(); + + [Resolved(CanBeNull = true)] + private SmokeContainer? smokeContainer { get; set; } + + protected struct SmokePoint + { + public Vector2 Position; + public double Time; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (smokeContainer != null) + { + smokeContainer.SmokeMoved += guardOnSmokeMoved; + smokeContainer.SmokeEnded += guardOnSmokeEnded; + IsActive = true; + } + + Anchor = Anchor.TopLeft; + Origin = Anchor.TopLeft; + + SmokeTimeStart = Time.Current; + } + + private void guardOnSmokeMoved(Vector2 position, double time) + { + if (IsActive) + OnSmokeMoved(position, time); + } + + private void guardOnSmokeEnded(double time) + { + if (IsActive) + OnSmokeEnded(time); + } + + protected virtual void OnSmokeMoved(Vector2 position, double time) + { + addSmokeVertex(position, time); + } + + private void addSmokeVertex(Vector2 position, double time) + { + Debug.Assert(SmokeVertexTimes.Count == SmokeVertexPositions.Count); + + if (SmokeVertexTimes.Count > 0 && SmokeVertexTimes.Last() > time) + { + int index = ~SmokeVertexTimes.BinarySearch(time, new UpperBoundComparer()); + + SmokeVertexTimes.RemoveRange(index, SmokeVertexTimes.Count - index); + SmokeVertexPositions.RemoveRange(index, SmokeVertexPositions.Count - index); + } + + SmokeVertexTimes.Add(time); + SmokeVertexPositions.Add(position); + } + + protected virtual void OnSmokeEnded(double time) + { + IsActive = false; + SmokeTimeEnd = time; + } + + protected override void Update() + { + base.Update(); + + const double visible_duration = 8000; + const float disappear_speed = 3; + + int index = 0; + if (!IsActive) + { + double cutoffTime = SmokeTimeStart + disappear_speed * (Time.Current - (SmokeTimeEnd + visible_duration)); + index = ~SmokeVertexTimes.BinarySearch(cutoffTime, new UpperBoundComparer()); + } + Vertices = new List(SmokeVertexPositions.Skip(index)); + + Position = -PositionInBoundingBox(Vector2.Zero); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (smokeContainer != null) + { + smokeContainer.SmokeMoved -= guardOnSmokeMoved; + smokeContainer.SmokeEnded -= guardOnSmokeEnded; + } + } + + private struct UpperBoundComparer : IComparer + { + public int Compare(double x, double target) + { + // By returning -1 when the target value is equal to x, guarantees that the + // element at BinarySearch's returned index will always be the first element + // larger. Since 0 is never returned, the target is never "found", so the return + // value will be the index's complement. + + return x > target ? 1 : -1; + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index fc2ba8ea2f..8085c07912 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -32,6 +32,7 @@ namespace osu.Game.Rulesets.Osu.UI public class OsuPlayfield : Playfield { private readonly PlayfieldBorder playfieldBorder; + private readonly SmokeContainer smokeContainer; private readonly ProxyContainer approachCircles; private readonly ProxyContainer spinnerProxies; private readonly JudgementContainer judgementLayer; @@ -54,6 +55,7 @@ namespace osu.Game.Rulesets.Osu.UI InternalChildren = new Drawable[] { playfieldBorder = new PlayfieldBorder { RelativeSizeAxes = Axes.Both }, + smokeContainer = new SmokeContainer { RelativeSizeAxes = Axes.Both }, spinnerProxies = new ProxyContainer { RelativeSizeAxes = Axes.Both }, FollowPoints = new FollowPointRenderer { RelativeSizeAxes = Axes.Both }, judgementLayer = new JudgementContainer { RelativeSizeAxes = Axes.Both }, diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs new file mode 100644 index 0000000000..865204f8cc --- /dev/null +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -0,0 +1,57 @@ +// 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.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Osu.Skinning.Default; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Rulesets.Osu.UI +{ + [Cached] + public class SmokeContainer : Container, IRequireHighFrequencyMousePosition, IKeyBindingHandler + { + public event Action? SmokeMoved; + public event Action? SmokeEnded; + + private bool isSmoking = false; + + public override bool ReceivePositionalInputAt(Vector2 _) => true; + + public bool OnPressed(KeyBindingPressEvent e) + { + if (e.Action == OsuAction.Smoke) + { + isSmoking = true; + AddInternal(new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Smoke), _ => new DefaultSmoke())); + + return true; + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + if (e.Action == OsuAction.Smoke) + { + isSmoking = false; + SmokeEnded?.Invoke(Time.Current); + } + } + + protected override bool OnMouseMove(MouseMoveEvent e) + { + if (isSmoking) + SmokeMoved?.Invoke(e.MousePosition, Time.Current); + + return base.OnMouseMove(e); + } + } +} From 613564b5b9ecdb56953aa093982b3c22a565f8e4 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Sun, 18 Sep 2022 12:10:01 -0700 Subject: [PATCH 1195/2686] Full legacy smoke implementation and temp default smoke --- .../Skinning/Default/DefaultSmoke.cs | 51 +- .../Skinning/Legacy/LegacySmoke.cs | 93 +++- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 443 +++++++++++++++--- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 1 - 4 files changed, 521 insertions(+), 67 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs index 3c798c2afa..ecba9d4904 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -1,14 +1,61 @@ // 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.Diagnostics; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Rendering; +using osuTK.Graphics; + namespace osu.Game.Rulesets.Osu.Skinning.Default { public class DefaultSmoke : Smoke { + private const double fade_out_delay = 8000; + private const double fade_out_speed = 3; + private const double fade_out_duration = 50; + private const float alpha = 0.5f; + + protected override double LifetimeAfterSmokeEnd => fade_out_delay + fade_out_duration + (SmokeEndTime - SmokeStartTime) / fade_out_speed; + public DefaultSmoke() { - Texture = null; - PathRadius = 2; + Radius = 2; + } + + protected override DrawNode CreateDrawNode() => new DefaultSmokeDrawNode(this); + + private class DefaultSmokeDrawNode : SmokeDrawNode + { + private double fadeOutTime; + + public DefaultSmokeDrawNode(ITexturedShaderDrawable source) + : base(source) + { + } + + protected override void UpdateDrawVariables(IRenderer renderer) + { + base.UpdateDrawVariables(renderer); + + fadeOutTime = SmokeStartTime + fade_out_speed * (CurrentTime - (SmokeEndTime + fade_out_delay)); + } + + protected override Color4 ColorAtTime(double pointTime) + { + var color = Color4.White; + color.A = alpha; + + double timeDoingFadeOut = fadeOutTime - pointTime; + if (timeDoingFadeOut > 0) + { + float fraction = Math.Clamp((float)(1 - (timeDoingFadeOut / fade_out_duration)), 0, 1); + fraction = MathF.Pow(fraction, 5); + color.A *= fraction; + } + + return color; + } } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index 9494d31a63..6c2c80f746 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -1,19 +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 System; +using System.Diagnostics; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Rendering; using osu.Game.Skinning; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacySmoke : Smoke { + private const double initial_fade_out_duration = 2500; + + private const double re_fade_in_speed = 3; + private const double re_fade_in_duration = 50; + + private const double final_fade_out_duration = 7500; + + private const float initial_alpha = 0.8f; + private const float re_fade_in_alpha = 1.4f; + + protected override double LifetimeAfterSmokeEnd + { + get + { + double initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); + return final_fade_out_duration + initialFadeOutDurationTrunc * (1 + re_fade_in_speed); + } + } + private ISkin skin; public LegacySmoke(ISkin skin) { this.skin = skin; - - PathRadius = 8; + Radius = 3; } protected override void LoadComplete() @@ -22,5 +45,71 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Texture = skin.GetTexture("cursor-smoke"); } + + protected override DrawNode CreateDrawNode() => new LegacySmokeDrawNode(this); + + protected class LegacySmokeDrawNode : SmokeDrawNode + { + private double initialFadeOutDurationTrunc; + private double initialFadeOutTime; + private double reFadeInTime; + private double finalFadeOutTime; + + public LegacySmokeDrawNode(ITexturedShaderDrawable source) + : base(source) + { + } + + public override void ApplyState() + { + base.ApplyState(); + + initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); + } + + protected override void UpdateDrawVariables(IRenderer renderer) + { + base.UpdateDrawVariables(renderer); + + initialFadeOutTime = Math.Min(CurrentTime, SmokeEndTime); + reFadeInTime = re_fade_in_speed * (CurrentTime - SmokeEndTime) + SmokeEndTime - initialFadeOutDurationTrunc; + finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc * (1 + 1 / re_fade_in_speed); + } + + protected override Color4 ColorAtTime(double pointTime) + { + var color = Color4.White; + + double timeDoingInitialFadeOut = initialFadeOutTime - pointTime; + + if (timeDoingInitialFadeOut > 0) + { + float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); + fraction = MathF.Pow(fraction, 5); + color.A = (1 - fraction) * initial_alpha; + } + + if (color.A > 0) + { + double timeDoingReFadeIn = reFadeInTime - pointTime; + double timeDoingFinalFadeOut = finalFadeOutTime - pointTime; + + if (timeDoingFinalFadeOut > 0) + { + float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); + fraction = MathF.Pow(fraction, 5); + color.A = (1 - fraction) * re_fade_in_alpha; + } + else if (timeDoingReFadeIn > 0) + { + float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1); + fraction = 1 - MathF.Pow(1 - fraction, 5); + color.A = fraction * (re_fade_in_alpha - color.A) + color.A; + } + } + + return color; + } + } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 6c60392c94..52de537098 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -1,33 +1,175 @@ // 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.Diagnostics; -using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Lines; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Rendering.Vertices; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Textures; +using osu.Framework.Timing; +using osu.Framework.Utils; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Skinning; using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning { - public abstract class Smoke : TexturedPath + public abstract class Smoke : Drawable, ITexturedShaderDrawable { - protected bool IsActive { get; private set; } - protected double SmokeTimeStart { get; private set; } = double.MinValue; - protected double SmokeTimeEnd { get; private set; } = double.MinValue; + public IShader? TextureShader { get; private set; } + public IShader? RoundedTextureShader { get; private set; } - protected readonly List SmokeVertexPositions = new List(); - protected readonly List SmokeVertexTimes = new List(); + private float radius = 1; + protected float Radius + { + get => radius; + set + { + if (radius == value) + return; + + radius = value; + Invalidate(Invalidation.DrawNode); + } + } + + + private int rotationSeed = RNG.Next(); + protected int RotationSeed + { + get => rotationSeed; + set + { + if (rotationSeed == value) + return; + + rotationSeed = value; + Invalidate(Invalidation.DrawNode); + } + } + + private Texture? texture; + protected Texture? Texture + { + get => texture; + set + { + texture = value; + Invalidate(Invalidation.DrawNode); + } + } + + private double smokeTimeStart = double.MinValue; + protected double SmokeStartTime + { + get => smokeTimeStart; + private set + { + if (smokeTimeStart == value) + return; + + smokeTimeStart = value; + Invalidate(Invalidation.DrawNode); + } + } + + private double smokeTimeEnd = double.MaxValue; + protected double SmokeEndTime + { + get => smokeTimeEnd; + private set + { + if (smokeTimeEnd == value) + return; + + smokeTimeEnd = value; + Invalidate(Invalidation.DrawNode); + } + } + + public override IFrameBasedClock Clock + { + get => base.Clock; + set + { + base.Clock = value; + Invalidate(Invalidation.DrawNode); + } + } + + private Vector2 topLeft; + protected Vector2 TopLeft + { + get => topLeft; + set + { + if (topLeft == value) + return; + + topLeft = value; + Invalidate(Invalidation.All); + } + } + + private Vector2 bottomRight; + protected Vector2 BottomRight + { + get => bottomRight; + set + { + if (bottomRight == value) + return; + + bottomRight = value; + Invalidate(Invalidation.Layout); + } + } + + protected abstract double LifetimeAfterSmokeEnd { get; } + protected virtual float PointInterval => Radius * 7f / 8; + protected bool IsActive { get; private set; } + + protected readonly List SmokePoints = new List(); + + private float totalDistance; + private Vector2? lastPosition = null; + + private const double max_duration = 60_000; + + public override float Height + { + get => base.Height = BottomRight.Y - TopLeft.Y; + set => throw new InvalidOperationException($"Cannot manually set {nameof(Height)} of {nameof(Smoke)}."); + } + + public override float Width + { + get => base.Width = BottomRight.X - TopLeft.X; + set => throw new InvalidOperationException($"Cannot manually set {nameof(Width)} of {nameof(Smoke)}."); + } + + public override Vector2 Size + { + get => base.Size = BottomRight - TopLeft; + set => throw new InvalidOperationException($"Cannot manually set {nameof(Size)} of {nameof(Smoke)}."); + } [Resolved(CanBeNull = true)] private SmokeContainer? smokeContainer { get; set; } - protected struct SmokePoint + [BackgroundDependencyLoader] + private void load(ShaderManager shaders) { - public Vector2 Position; - public double Time; + RoundedTextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); + TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE); } protected override void LoadComplete() @@ -36,72 +178,107 @@ namespace osu.Game.Rulesets.Osu.Skinning if (smokeContainer != null) { - smokeContainer.SmokeMoved += guardOnSmokeMoved; - smokeContainer.SmokeEnded += guardOnSmokeEnded; + smokeContainer.SmokeMoved += onSmokeMoved; + smokeContainer.SmokeEnded += onSmokeEnded; IsActive = true; } Anchor = Anchor.TopLeft; Origin = Anchor.TopLeft; - SmokeTimeStart = Time.Current; + SmokeStartTime = Time.Current; } - private void guardOnSmokeMoved(Vector2 position, double time) + private void onSmokeMoved(Vector2 position, double time) { - if (IsActive) - OnSmokeMoved(position, time); - } + if (!IsActive) + return; - private void guardOnSmokeEnded(double time) - { - if (IsActive) - OnSmokeEnded(time); - } + lastPosition ??= position; - protected virtual void OnSmokeMoved(Vector2 position, double time) - { - addSmokeVertex(position, time); - } + float delta = (position - (Vector2)lastPosition).LengthFast; + totalDistance += delta; + int count = (int)(totalDistance / PointInterval); - private void addSmokeVertex(Vector2 position, double time) - { - Debug.Assert(SmokeVertexTimes.Count == SmokeVertexPositions.Count); - - if (SmokeVertexTimes.Count > 0 && SmokeVertexTimes.Last() > time) + if (count > 0) { - int index = ~SmokeVertexTimes.BinarySearch(time, new UpperBoundComparer()); + Vector2 increment = position - (Vector2)lastPosition; + increment.NormalizeFast(); - SmokeVertexTimes.RemoveRange(index, SmokeVertexTimes.Count - index); - SmokeVertexPositions.RemoveRange(index, SmokeVertexPositions.Count - index); + Vector2 pointPos = (PointInterval - (totalDistance - delta)) * increment + (Vector2)lastPosition; + increment *= PointInterval; + + if (SmokePoints.Count > 0 && SmokePoints[^1].Time > time) + { + int index = ~SmokePoints.BinarySearch(new SmokePoint { Time = time }, new SmokePoint.UpperBoundComparer()); + SmokePoints.RemoveRange(index, SmokePoints.Count - index); + recalculateBounds(); + } + + totalDistance %= PointInterval; + for (int i = 0; i < count; i++) + { + SmokePoints.Add(new SmokePoint + { + Position = pointPos, + Time = time, + }); + + pointPos += increment; + } + + Invalidate(Invalidation.DrawNode); + adaptBounds(position); } - SmokeVertexTimes.Add(time); - SmokeVertexPositions.Add(position); + lastPosition = position; + + if (time - SmokeStartTime > max_duration) + onSmokeEnded(time); } - protected virtual void OnSmokeEnded(double time) + private void recalculateBounds() { - IsActive = false; - SmokeTimeEnd = time; + TopLeft = BottomRight = Vector2.Zero; + + foreach (var point in SmokePoints) + adaptBounds(point.Position); } + private void adaptBounds(Vector2 position) + { + if (position.X < TopLeft.X) + TopLeft = new Vector2(position.X, TopLeft.Y); + else if (position.X > BottomRight.X) + BottomRight = new Vector2(position.X, BottomRight.Y); + + if (position.Y < TopLeft.Y) + TopLeft = new Vector2(TopLeft.X, position.Y); + else if (position.Y > BottomRight.Y) + BottomRight = new Vector2(BottomRight.X, position.Y); + } + + private void onSmokeEnded(double time) + { + if (!IsActive) + return; + + IsActive = false; + SmokeEndTime = time; + LifetimeEnd = time + LifetimeAfterSmokeEnd + 100; + + // TODO: HYPER MEGA JANK WTF?? + if (Parent is SkinnableDrawable) + Parent.LifetimeEnd = LifetimeEnd; + } + + protected abstract override DrawNode CreateDrawNode(); + protected override void Update() { base.Update(); - const double visible_duration = 8000; - const float disappear_speed = 3; - - int index = 0; - if (!IsActive) - { - double cutoffTime = SmokeTimeStart + disappear_speed * (Time.Current - (SmokeTimeEnd + visible_duration)); - index = ~SmokeVertexTimes.BinarySearch(cutoffTime, new UpperBoundComparer()); - } - Vertices = new List(SmokeVertexPositions.Skip(index)); - - Position = -PositionInBoundingBox(Vector2.Zero); + Position = TopLeft; } protected override void Dispose(bool isDisposing) @@ -110,21 +287,163 @@ namespace osu.Game.Rulesets.Osu.Skinning if (smokeContainer != null) { - smokeContainer.SmokeMoved -= guardOnSmokeMoved; - smokeContainer.SmokeEnded -= guardOnSmokeEnded; + smokeContainer.SmokeMoved -= onSmokeMoved; + smokeContainer.SmokeEnded -= onSmokeEnded; } } - private struct UpperBoundComparer : IComparer + protected struct SmokePoint { - public int Compare(double x, double target) - { - // By returning -1 when the target value is equal to x, guarantees that the - // element at BinarySearch's returned index will always be the first element - // larger. Since 0 is never returned, the target is never "found", so the return - // value will be the index's complement. + public Vector2 Position; + public double Time; - return x > target ? 1 : -1; + public struct UpperBoundComparer : IComparer + { + public int Compare(SmokePoint x, SmokePoint target) + { + // By returning -1 when the target value is equal to x, guarantees that the + // element at BinarySearch's returned index will always be the first element + // larger. Since 0 is never returned, the target is never "found", so the return + // value will be the index's complement. + + return x.Time > target.Time ? 1 : -1; + } + } + } + + protected abstract class SmokeDrawNode : TexturedShaderDrawNode + { + protected new Smoke Source => (Smoke)base.Source; + + protected IVertexBatch? QuadBatch; + + protected readonly List Points = new List(); + + protected float Radius; + protected Vector2 DrawSize; + protected Vector2 PositionOffset; + protected Texture? Texture; + + protected double SmokeStartTime; + protected double SmokeEndTime; + protected double CurrentTime; + + protected RectangleF TextureRect; + + private IFrameBasedClock? clock; + + private int rotationSeed; + private Random rotationRNG = new Random(); + + public SmokeDrawNode(ITexturedShaderDrawable source) + : base(source) + { + } + + public override void ApplyState() + { + base.ApplyState(); + + Points.Clear(); + Points.AddRange(Source.SmokePoints); + + Radius = Source.Radius; + DrawSize = Source.DrawSize; + PositionOffset = Source.TopLeft; + Texture = Source.Texture; + clock = Source.Clock; + + SmokeStartTime = Source.SmokeStartTime; + SmokeEndTime = Source.SmokeEndTime; + + rotationSeed = Source.RotationSeed; + } + + public sealed override void Draw(IRenderer renderer) + { + base.Draw(renderer); + + if (Points.Count == 0) + return; + + QuadBatch ??= renderer.CreateQuadBatch(7200, 10); + Texture ??= renderer.WhitePixel; + + var shader = GetAppropriateShader(renderer); + shader.Bind(); + Texture.Bind(); + + UpdateDrawVariables(renderer); + UpdateVertexBuffer(); + + shader.Unbind(); + } + + protected Color4 ColorAtPosition(Vector2 localPos) => DrawColourInfo.Colour.HasSingleColour + ? ((SRGBColour)DrawColourInfo.Colour).Linear + : DrawColourInfo.Colour.Interpolate(Vector2.Divide(localPos, DrawSize)).Linear; + + protected abstract Color4 ColorAtTime(double pointTime); + + protected virtual void UpdateDrawVariables(IRenderer renderer) + { + Debug.Assert(clock != null); + Debug.Assert(Texture != null); + + CurrentTime = clock.CurrentTime; + TextureRect = Texture.GetTextureRect(); + rotationRNG = new Random(rotationSeed); + } + + protected virtual void UpdateVertexBuffer() + { + foreach (var point in Points) + drawPointQuad(point); + } + + private Vector2 nextTextureDirection() + { + float angle = (float)rotationRNG.NextDouble() * 2 * MathF.PI; + return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); + } + + private void drawPointQuad(SmokePoint point) + { + Debug.Assert(QuadBatch != null); + + var color = ColorAtTime(point.Time); + var dir = nextTextureDirection(); + var ortho = dir.PerpendicularLeft; + + var localTopLeft = point.Position + (Radius * (-ortho - dir)) - PositionOffset; + var localTopRight = point.Position + (Radius * (-ortho + dir)) - PositionOffset; + var localBotLeft = point.Position + (Radius * (ortho - dir)) - PositionOffset; + var localBotRight = point.Position + (Radius * (ortho + dir)) - PositionOffset; + + QuadBatch.Add(new TexturedVertex2D + { + Position = Vector2Extensions.Transform(localTopLeft, DrawInfo.Matrix), + TexturePosition = TextureRect.TopLeft, + Colour = Color4Extensions.Multiply(ColorAtPosition(localTopLeft), color), + }); + QuadBatch.Add(new TexturedVertex2D + { + Position = Vector2Extensions.Transform(localTopRight, DrawInfo.Matrix), + TexturePosition = TextureRect.TopRight, + Colour = Color4Extensions.Multiply(ColorAtPosition(localTopRight), color), + }); + QuadBatch.Add(new TexturedVertex2D + { + Position = Vector2Extensions.Transform(localBotRight, DrawInfo.Matrix), + TexturePosition = TextureRect.BottomRight, + Colour = Color4Extensions.Multiply(ColorAtPosition(localBotRight), color), + }); + QuadBatch.Add(new TexturedVertex2D + { + Position = Vector2Extensions.Transform(localBotLeft, DrawInfo.Matrix), + TexturePosition = TextureRect.BottomLeft, + Colour = Color4Extensions.Multiply(ColorAtPosition(localBotLeft), color), + }); } } } diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index 865204f8cc..b8897f2cf1 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; From ca9fe9f24000b40ef60422867d82ed25b0fd6e16 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Sun, 18 Sep 2022 22:05:09 +0200 Subject: [PATCH 1196/2686] Fixed TestCatcherCatchWidth failing --- osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 956d0e0c14..11fa751daf 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -108,14 +108,14 @@ namespace osu.Game.Rulesets.Catch.Tests float halfWidth = Catcher.CalculateCatchWidth(new BeatmapDifficulty { CircleSize = 0 }) / 2; AddStep("catch fruit", () => { - attemptCatch(new Fruit { X = -halfWidth + 1 }); - attemptCatch(new Fruit { X = halfWidth - 1 }); + attemptCatch(new Fruit { OriginalX = -halfWidth + 1 }); + attemptCatch(new Fruit { OriginalX = halfWidth - 1 }); }); checkPlate(2); AddStep("miss fruit", () => { - attemptCatch(new Fruit { X = -halfWidth - 1 }); - attemptCatch(new Fruit { X = halfWidth + 1 }); + attemptCatch(new Fruit { OriginalX = -halfWidth - 1 }); + attemptCatch(new Fruit { OriginalX = halfWidth + 1 }); }); checkPlate(2); } From 4263933c9e4431afd2c085a7d40aa256c241eb22 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sun, 18 Sep 2022 23:43:14 +0200 Subject: [PATCH 1197/2686] Add settings `AngleSharpness` and `Angle variety` --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 52 +++++++++++++++++++--- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 056a325dce..fca42dedee 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -4,9 +4,12 @@ using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Beatmaps; @@ -25,6 +28,26 @@ namespace osu.Game.Rulesets.Osu.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTarget)).ToArray(); + [SettingSource("Angle sharpness", "How sharp angles should be", SettingControlType = typeof(SettingsSlider))] + public BindableFloat AngleSharpness { get; } = new BindableFloat + { + Default = 7, + Value = 7, + MinValue = 1, + MaxValue = 10, + Precision = 0.1f + }; + + [SettingSource("Angle variety", "The amount of variety in how sharp angles are", SettingControlType = typeof(SettingsSlider))] + public BindableFloat AngleVariety { get; } = new BindableFloat + { + Default = 3, + Value = 3, + MinValue = 0, + MaxValue = 10, + Precision = 0.1f + }; + private static readonly float playfield_diagonal = OsuPlayfield.BASE_SIZE.LengthFast; private Random random = null!; @@ -50,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.Mods { if (shouldStartNewSection(osuBeatmap, positionInfos, i)) { - sectionOffset = OsuHitObjectGenerationUtils.RandomGaussian(random, 0, 0.0008f); + sectionOffset = getRandomOffset(0.0008f); flowDirection = !flowDirection; } @@ -65,11 +88,11 @@ namespace osu.Game.Rulesets.Osu.Mods float flowChangeOffset = 0; // Offsets only the angle of the current hit object. - float oneTimeOffset = OsuHitObjectGenerationUtils.RandomGaussian(random, 0, 0.002f); + float oneTimeOffset = getRandomOffset(0.002f); if (shouldApplyFlowChange(positionInfos, i)) { - flowChangeOffset = OsuHitObjectGenerationUtils.RandomGaussian(random, 0, 0.002f); + flowChangeOffset = getRandomOffset(0.002f); flowDirection = !flowDirection; } @@ -86,13 +109,32 @@ namespace osu.Game.Rulesets.Osu.Mods osuBeatmap.HitObjects = OsuHitObjectGenerationUtils.RepositionHitObjects(positionInfos); } + private float getRandomOffset(float stdDev) + { + float customMultiplier = AngleVariety.Value / AngleVariety.Default; + return OsuHitObjectGenerationUtils.RandomGaussian(random, 0, stdDev * customMultiplier); + } + /// The target distance between the previous and the current . /// The angle (in rad) by which the target angle should be offset. /// Whether the relative angle should be positive or negative. - private static float getRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) + private float getRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) { - float angle = (float)(2.16 / (1 + 200 * Math.Exp(0.036 * (targetDistance - 310))) + 0.5 + offset); + // Range 0..1 + float angleSharpness = AngleSharpness.Value / AngleSharpness.MaxValue; + float angleWideness = 1 - angleSharpness; + + // Range: -70..30 + float customOffsetX = angleSharpness * 100 - 70; + // Range: -0.075..0.175 + float customOffsetY = angleWideness * 0.25f - 0.075f; + + targetDistance += customOffsetX; + float angle = (float)(2.16 / (1 + 200 * Math.Exp(0.036 * (targetDistance - 310 + customOffsetX))) + 0.5); + angle += offset + customOffsetY; + float relativeAngle = (float)Math.PI - angle; + return flowDirection ? -relativeAngle : relativeAngle; } From 6d3e42a248021605150fbda3a7cfb8d9a4b98dd4 Mon Sep 17 00:00:00 2001 From: "D.Headley" Date: Sun, 18 Sep 2022 19:35:12 +0200 Subject: [PATCH 1198/2686] Give enums descriptions, change acronym and remove icon --- .../Mods/OsuModFreezeFrame.cs | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 6a0faf9298..26adc0f25f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -3,8 +3,8 @@ using System; using System.Linq; +using System.ComponentModel; using osu.Framework.Bindables; -using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -20,17 +20,15 @@ namespace osu.Game.Rulesets.Osu.Mods { public override string Name => "Freeze Frame"; - public override string Acronym => "FF"; + public override string Acronym => "FR"; public override double ScoreMultiplier => 1; - public override LocalisableString Description => "Burn the notes into your memory"; + public override LocalisableString Description => "Burn the notes into your memory."; public override ModType Type => ModType.Fun; - public override IconUsage? Icon => FontAwesome.Solid.Camera; - - [SettingSource("Measure", "How often the hit-circles should be Grouped to freeze")] + [SettingSource("Beat Divisor", "How often the hitobjects should be grouped according to BPM")] public Bindable Divisor { get; } = new Bindable(BeatDivisor.Single_Measure); public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) @@ -88,15 +86,22 @@ namespace osu.Game.Rulesets.Osu.Mods } } - //Todo: find better way to represent these Enums to the player public enum BeatDivisor { + [Description("1/4")] Quarter_Measure, + + [Description("1/2")] Half_Measure, + + [Description("1")] Single_Measure, + + [Description("2")] Double_Measure, + + [Description("4")] Quadruple_Measure } } } - From 9eb0a21d753b80082937d6abe82ae9c4d8be5ce6 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Mon, 19 Sep 2022 00:45:23 +0200 Subject: [PATCH 1199/2686] Correct comments --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index fca42dedee..c829d1f696 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -120,13 +120,14 @@ namespace osu.Game.Rulesets.Osu.Mods /// Whether the relative angle should be positive or negative. private float getRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) { - // Range 0..1 + // Range [0.1;1] float angleSharpness = AngleSharpness.Value / AngleSharpness.MaxValue; + // Range [0;0.9] float angleWideness = 1 - angleSharpness; - // Range: -70..30 + // Range: [-60;30] float customOffsetX = angleSharpness * 100 - 70; - // Range: -0.075..0.175 + // Range: [-0.075;0.15] float customOffsetY = angleWideness * 0.25f - 0.075f; targetDistance += customOffsetX; From 407b104116c45f99d21d9cd9bde842d5984b8178 Mon Sep 17 00:00:00 2001 From: O Thiago Date: Sun, 18 Sep 2022 18:55:47 -0400 Subject: [PATCH 1200/2686] Revert changes This reverts commit beef3b418ad1e1ba4023a55348992f69e40fbcde. Revert "Use linq expression for handling breaks" This reverts commit 8464a1941bef4c47a949a1c935bdc58aa2b8791f. Revert "renames variables to make more logical sense" This reverts commit 3b87ecf56c0f473b7081bad10e715825becbc6b8. Revert "Removes overhead when not combo based size" This reverts commit ac4229e3d4654b07758617e6c274d7cde550caad. --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 490f9120b1..558605efc3 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -51,11 +50,6 @@ namespace osu.Game.Rulesets.Mods where T : HitObject { public const double FLASHLIGHT_FADE_DURATION = 800; - - private const int flashlight_size_decrease_combo = 100; - private const int flashlight_size_decrease_combo_max = 200; - private const float flashlight_size_decrease_with_combo_multiplier = 0.1f; - protected readonly BindableInt Combo = new BindableInt(); public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor) @@ -133,8 +127,13 @@ namespace osu.Game.Rulesets.Mods using (BeginAbsoluteSequence(0)) { - foreach (var breakPeriod in Breaks.Where(breakPeriod => breakPeriod.HasEffect && breakPeriod.Duration >= FLASHLIGHT_FADE_DURATION * 2)) + foreach (var breakPeriod in Breaks) { + if (!breakPeriod.HasEffect) + continue; + + if (breakPeriod.Duration < FLASHLIGHT_FADE_DURATION * 2) continue; + this.Delay(breakPeriod.StartTime + FLASHLIGHT_FADE_DURATION).FadeOutFromOne(FLASHLIGHT_FADE_DURATION); this.Delay(breakPeriod.EndTime - FLASHLIGHT_FADE_DURATION).FadeInFromZero(FLASHLIGHT_FADE_DURATION); } @@ -150,7 +149,12 @@ namespace osu.Game.Rulesets.Mods float size = defaultFlashlightSize * sizeMultiplier; if (comboBasedSize) - size *= 1 - flashlight_size_decrease_with_combo_multiplier * MathF.Floor(MathF.Min(combo, flashlight_size_decrease_combo_max) / flashlight_size_decrease_combo); + { + if (combo > 200) + size *= 0.8f; + else if (combo > 100) + size *= 0.9f; + } return size; } From a4e9c7711c4b042101d6499a8b30d5fe27bf567c Mon Sep 17 00:00:00 2001 From: O Thiago Date: Sun, 18 Sep 2022 18:59:17 -0400 Subject: [PATCH 1201/2686] Fix when flashlight shrinking takes place --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 558605efc3..6d7706cde2 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -150,9 +150,9 @@ namespace osu.Game.Rulesets.Mods if (comboBasedSize) { - if (combo > 200) + if (combo >= 200) size *= 0.8f; - else if (combo > 100) + else if (combo >= 100) size *= 0.9f; } From 06178104c8953a059f5f26b3b04a5e8978ed551b Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Sun, 18 Sep 2022 17:55:06 -0700 Subject: [PATCH 1202/2686] Show smoke in replays --- osu.Game.Rulesets.Osu/Replays/OsuReplayFrame.cs | 3 +++ osu.Game/Replays/Legacy/LegacyReplayFrame.cs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Replays/OsuReplayFrame.cs b/osu.Game.Rulesets.Osu/Replays/OsuReplayFrame.cs index 85060261fe..8082c5aef4 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuReplayFrame.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuReplayFrame.cs @@ -31,6 +31,7 @@ namespace osu.Game.Rulesets.Osu.Replays Position = currentFrame.Position; if (currentFrame.MouseLeft) Actions.Add(OsuAction.LeftButton); if (currentFrame.MouseRight) Actions.Add(OsuAction.RightButton); + if (currentFrame.Smoke) Actions.Add(OsuAction.Smoke); } public LegacyReplayFrame ToLegacy(IBeatmap beatmap) @@ -41,6 +42,8 @@ namespace osu.Game.Rulesets.Osu.Replays state |= ReplayButtonState.Left1; if (Actions.Contains(OsuAction.RightButton)) state |= ReplayButtonState.Right1; + if (Actions.Contains(OsuAction.Smoke)) + state |= ReplayButtonState.Smoke; return new LegacyReplayFrame(Time, Position.X, Position.Y, state); } diff --git a/osu.Game/Replays/Legacy/LegacyReplayFrame.cs b/osu.Game/Replays/Legacy/LegacyReplayFrame.cs index f6abf259e8..f345504ca1 100644 --- a/osu.Game/Replays/Legacy/LegacyReplayFrame.cs +++ b/osu.Game/Replays/Legacy/LegacyReplayFrame.cs @@ -46,6 +46,10 @@ namespace osu.Game.Replays.Legacy [IgnoreMember] public bool MouseRight2 => ButtonState.HasFlagFast(ReplayButtonState.Right2); + [JsonIgnore] + [IgnoreMember] + public bool Smoke => ButtonState.HasFlagFast(ReplayButtonState.Smoke); + [Key(3)] public ReplayButtonState ButtonState; From 0138663bdcb3d534dd892a68f545f310eb2dfe4d Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Sun, 18 Sep 2022 18:32:33 -0700 Subject: [PATCH 1203/2686] Fix InspectCode errors --- .../Skinning/Default/DefaultSmoke.cs | 2 +- .../Skinning/Legacy/LegacySmoke.cs | 3 +-- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 15 +++++++++++---- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 3 +-- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 2 +- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs index ecba9d4904..e7f526da31 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using osu.Framework.Graphics; using osu.Framework.Graphics.Rendering; using osuTK.Graphics; @@ -47,6 +46,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default color.A = alpha; double timeDoingFadeOut = fadeOutTime - pointTime; + if (timeDoingFadeOut > 0) { float fraction = Math.Clamp((float)(1 - (timeDoingFadeOut / fade_out_duration)), 0, 1); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index 6c2c80f746..23ab2d186f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using osu.Framework.Graphics; using osu.Framework.Graphics.Rendering; using osu.Game.Skinning; @@ -31,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } } - private ISkin skin; + private readonly ISkin skin; public LegacySmoke(ISkin skin) { diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 52de537098..382e54e2ab 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -28,6 +28,7 @@ namespace osu.Game.Rulesets.Osu.Skinning public IShader? RoundedTextureShader { get; private set; } private float radius = 1; + protected float Radius { get => radius; @@ -41,8 +42,8 @@ namespace osu.Game.Rulesets.Osu.Skinning } } - private int rotationSeed = RNG.Next(); + protected int RotationSeed { get => rotationSeed; @@ -57,6 +58,7 @@ namespace osu.Game.Rulesets.Osu.Skinning } private Texture? texture; + protected Texture? Texture { get => texture; @@ -68,6 +70,7 @@ namespace osu.Game.Rulesets.Osu.Skinning } private double smokeTimeStart = double.MinValue; + protected double SmokeStartTime { get => smokeTimeStart; @@ -82,6 +85,7 @@ namespace osu.Game.Rulesets.Osu.Skinning } private double smokeTimeEnd = double.MaxValue; + protected double SmokeEndTime { get => smokeTimeEnd; @@ -106,6 +110,7 @@ namespace osu.Game.Rulesets.Osu.Skinning } private Vector2 topLeft; + protected Vector2 TopLeft { get => topLeft; @@ -115,11 +120,12 @@ namespace osu.Game.Rulesets.Osu.Skinning return; topLeft = value; - Invalidate(Invalidation.All); + Invalidate(); } } private Vector2 bottomRight; + protected Vector2 BottomRight { get => bottomRight; @@ -140,7 +146,7 @@ namespace osu.Game.Rulesets.Osu.Skinning protected readonly List SmokePoints = new List(); private float totalDistance; - private Vector2? lastPosition = null; + private Vector2? lastPosition; private const double max_duration = 60_000; @@ -216,6 +222,7 @@ namespace osu.Game.Rulesets.Osu.Skinning } totalDistance %= PointInterval; + for (int i = 0; i < count; i++) { SmokePoints.Add(new SmokePoint @@ -335,7 +342,7 @@ namespace osu.Game.Rulesets.Osu.Skinning private int rotationSeed; private Random rotationRNG = new Random(); - public SmokeDrawNode(ITexturedShaderDrawable source) + protected SmokeDrawNode(ITexturedShaderDrawable source) : base(source) { } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 8085c07912..2e67e91460 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -32,7 +32,6 @@ namespace osu.Game.Rulesets.Osu.UI public class OsuPlayfield : Playfield { private readonly PlayfieldBorder playfieldBorder; - private readonly SmokeContainer smokeContainer; private readonly ProxyContainer approachCircles; private readonly ProxyContainer spinnerProxies; private readonly JudgementContainer judgementLayer; @@ -55,7 +54,7 @@ namespace osu.Game.Rulesets.Osu.UI InternalChildren = new Drawable[] { playfieldBorder = new PlayfieldBorder { RelativeSizeAxes = Axes.Both }, - smokeContainer = new SmokeContainer { RelativeSizeAxes = Axes.Both }, + new SmokeContainer { RelativeSizeAxes = Axes.Both }, spinnerProxies = new ProxyContainer { RelativeSizeAxes = Axes.Both }, FollowPoints = new FollowPointRenderer { RelativeSizeAxes = Axes.Both }, judgementLayer = new JudgementContainer { RelativeSizeAxes = Axes.Both }, diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index b8897f2cf1..07a073c3e5 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.UI public event Action? SmokeMoved; public event Action? SmokeEnded; - private bool isSmoking = false; + private bool isSmoking; public override bool ReceivePositionalInputAt(Vector2 _) => true; From 6852577dad463994280fbd8a171f4f6098b1bdd1 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Sun, 18 Sep 2022 19:08:01 -0700 Subject: [PATCH 1204/2686] Remove smoke from key overlay --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 15 +++++++++++++++ osu.Game/Rulesets/UI/RulesetInputManager.cs | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index dec965e567..6500ade7ea 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -10,6 +10,7 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Input.StateChanges.Events; using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play; namespace osu.Game.Rulesets.Osu { @@ -56,6 +57,20 @@ namespace osu.Game.Rulesets.Osu return base.HandleMouseTouchStateChange(e); } + public override void Attach(KeyCounterDisplay keyCounter) + { + var receptor = new ActionReceptor(keyCounter); + + KeyBindingContainer.Add(receptor); + + keyCounter.SetReceptor(receptor); + keyCounter.AddRange(new[] + { + new KeyCounterAction(OsuAction.LeftButton), + new KeyCounterAction(OsuAction.RightButton), + }); + } + private class OsuKeyBindingContainer : RulesetKeyBindingContainer { public bool AllowUserPresses = true; diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 7c37913576..902579d9d2 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -154,7 +154,7 @@ namespace osu.Game.Rulesets.UI #region Key Counter Attachment - public void Attach(KeyCounterDisplay keyCounter) + public virtual void Attach(KeyCounterDisplay keyCounter) { var receptor = new ActionReceptor(keyCounter); From 454125123d3aa7a0e06b179b519eb8d67cab1576 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 11:31:38 +0900 Subject: [PATCH 1205/2686] Add failing test coverage showing mod reference leak path --- .../TestScenePlayerLocalScoreImport.cs | 33 +++++++++++++++++++ osu.Game/Tests/Visual/PlayerTestScene.cs | 12 ++++--- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs index 247b822dc3..db9d2bfc1d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs @@ -15,8 +15,10 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -101,6 +103,37 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for last played to update", () => getLastPlayed() != null); } + [Test] + public void TestModReferenceNotRetained() + { + AddStep("allow fail", () => allowFail = false); + + Mod[] originalMods = { new OsuModDaycore { SpeedChange = { Value = 0.8 } } }; + Mod[] playerMods = null!; + + AddStep($"Load player with mods", () => LoadPlayer(originalMods)); + AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1); + + AddStep("get mods at start of gameplay", () => playerMods = Player.Score.ScoreInfo.Mods.ToArray()); + + // Player creates new instance of mods during load. + AddAssert("player score has copied mods", () => playerMods.First(), () => Is.Not.SameAs(originalMods.First())); + AddAssert("player score has matching mods", () => playerMods.First(), () => Is.EqualTo(originalMods.First())); + + AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning); + + AddStep("seek to completion", () => Player.GameplayClockContainer.Seek(Player.DrawableRuleset.Objects.Last().GetEndTime())); + + AddUntilStep("results displayed", () => Player.GetChildScreen() is ResultsScreen); + + // Player creates new instance of mods after gameplay to ensure any runtime references to drawables etc. are not retained. + AddAssert("results screen score has copied mods", () => (Player.GetChildScreen() as ResultsScreen)?.Score.Mods.First(), () => Is.Not.SameAs(playerMods.First())); + AddAssert("results screen score has matching", () => (Player.GetChildScreen() as ResultsScreen)?.Score.Mods.First(), () => Is.EqualTo(playerMods.First())); + + AddUntilStep("score in database", () => Realm.Run(r => r.Find(Player.Score.ScoreInfo.ID) != null)); + AddUntilStep("databased score has correct mods", () => Realm.Run(r => r.Find(Player.Score.ScoreInfo.ID)).Mods.First(), () => Is.EqualTo(playerMods.First())); + } + [Test] public void TestScoreStoredLocally() { diff --git a/osu.Game/Tests/Visual/PlayerTestScene.cs b/osu.Game/Tests/Visual/PlayerTestScene.cs index a9decbae57..9bad867206 100644 --- a/osu.Game/Tests/Visual/PlayerTestScene.cs +++ b/osu.Game/Tests/Visual/PlayerTestScene.cs @@ -7,7 +7,6 @@ using System; using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Testing; using osu.Game.Configuration; using osu.Game.Rulesets; @@ -57,7 +56,9 @@ namespace osu.Game.Tests.Visual protected virtual bool Autoplay => false; - protected void LoadPlayer() + protected void LoadPlayer() => LoadPlayer(Array.Empty()); + + protected void LoadPlayer(Mod[] mods) { var ruleset = CreatePlayerRuleset(); Ruleset.Value = ruleset.RulesetInfo; @@ -65,20 +66,21 @@ namespace osu.Game.Tests.Visual var beatmap = CreateBeatmap(ruleset.RulesetInfo); Beatmap.Value = CreateWorkingBeatmap(beatmap); - SelectedMods.Value = Array.Empty(); + + SelectedMods.Value = mods; if (!AllowFail) { var noFailMod = ruleset.CreateMod(); if (noFailMod != null) - SelectedMods.Value = new[] { noFailMod }; + SelectedMods.Value = SelectedMods.Value.Append(noFailMod).ToArray(); } if (Autoplay) { var mod = ruleset.GetAutoplayMod(); if (mod != null) - SelectedMods.Value = SelectedMods.Value.Concat(mod.Yield()).ToArray(); + SelectedMods.Value = SelectedMods.Value.Append(mod).ToArray(); } Player = CreatePlayer(ruleset); From 0a625bd879d8b525da798f04b00fac1e161515c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 18 Sep 2022 23:48:03 +0900 Subject: [PATCH 1206/2686] Fix mods potentially keeping reference to runtime gameplay elements As noticed by smoogipoo during multiplayer match on the weekend. --- osu.Game/Scoring/ScoreInfo.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 25a7bad9e8..1b36ae176d 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -137,6 +137,11 @@ namespace osu.Game.Scoring clone.Statistics = new Dictionary(clone.Statistics); clone.MaximumStatistics = new Dictionary(clone.MaximumStatistics); + + // Ensure we have fresh mods to avoid any references (ie. after gameplay). + clone.clearAllMods(); + clone.ModsJson = ModsJson; + clone.RealmUser = new RealmUser { OnlineID = RealmUser.OnlineID, From 2b1c5b2c4a11ffbafbf3fb0361647527de2baaac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 12:34:50 +0900 Subject: [PATCH 1207/2686] Fix test failure due to triangle skin no longer being null intests --- .../Visual/Gameplay/SkinnableHUDComponentTestScene.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs index 3ecf560eb1..1bf1bd4c81 100644 --- a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs +++ b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs @@ -1,12 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using NUnit.Framework; using osu.Framework.Graphics; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { @@ -19,7 +18,7 @@ namespace osu.Game.Tests.Visual.Gameplay { SetContents(skin => { - var implementation = skin != null + var implementation = skin is not TrianglesSkin ? CreateLegacyImplementation() : CreateDefaultImplementation(); From 494790294acdd01e3c25127451cc36a08806f329 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 17:43:36 +0900 Subject: [PATCH 1208/2686] Update `SkinnableTestScene` to show new default skin --- osu.Game/Tests/Visual/SkinnableTestScene.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 75224742a2..4ef9a733c4 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -32,6 +32,7 @@ namespace osu.Game.Tests.Visual private TrianglesSkin trianglesSkin; private Skin metricsSkin; private Skin legacySkin; + private Skin argonSkin; private Skin specialSkin; private Skin oldSkin; @@ -48,6 +49,7 @@ namespace osu.Game.Tests.Visual { var dllStore = new DllResourceStore(GetType().Assembly); + argonSkin = new ArgonSkin(this); trianglesSkin = new TrianglesSkin(this); metricsSkin = new TestLegacySkin(new SkinInfo { Name = "metrics-skin" }, new NamespacedResourceStore(dllStore, "Resources/metrics_skin"), this, true); legacySkin = new DefaultLegacySkin(this); @@ -63,11 +65,12 @@ namespace osu.Game.Tests.Visual var beatmap = CreateBeatmapForSkinProvider(); - Cell(0).Child = createProvider(trianglesSkin, creationFunction, beatmap); - Cell(1).Child = createProvider(metricsSkin, creationFunction, beatmap); - Cell(2).Child = createProvider(legacySkin, creationFunction, beatmap); - Cell(3).Child = createProvider(specialSkin, creationFunction, beatmap); - Cell(4).Child = createProvider(oldSkin, creationFunction, beatmap); + Cell(0).Child = createProvider(argonSkin, creationFunction, beatmap); + Cell(1).Child = createProvider(trianglesSkin, creationFunction, beatmap); + Cell(2).Child = createProvider(metricsSkin, creationFunction, beatmap); + Cell(3).Child = createProvider(legacySkin, creationFunction, beatmap); + Cell(4).Child = createProvider(specialSkin, creationFunction, beatmap); + Cell(5).Child = createProvider(oldSkin, creationFunction, beatmap); } protected IEnumerable CreatedDrawables => createdDrawables; @@ -82,10 +85,7 @@ namespace osu.Game.Tests.Visual OutlineBox outlineBox; SkinProvidingContainer skinProvider; - ISkin provider = skin; - - if (provider is LegacySkin legacyProvider) - provider = Ruleset.Value.CreateInstance().CreateSkinTransformer(legacyProvider, beatmap); + ISkin provider = Ruleset.Value.CreateInstance().CreateSkinTransformer(skin, beatmap) ?? skin; var children = new Container { From f6b29d8ebcaf468d43972ed66ccd605e21438b9b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 19:17:54 +0900 Subject: [PATCH 1209/2686] Make `TestSceneHitCircle` show more than one cirle to make testing easier --- osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs index cc69054e23..be224b88ce 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs @@ -58,10 +58,11 @@ namespace osu.Game.Rulesets.Osu.Tests private Drawable testSingle(float circleSize, bool auto = false, double timeOffset = 0, Vector2? positionOffset = null) { - var drawable = createSingle(circleSize, auto, timeOffset, positionOffset); - var playfield = new TestOsuPlayfield(); - playfield.Add(drawable); + + for (double t = timeOffset; t < timeOffset + 60000; t += 2000) + playfield.Add(createSingle(circleSize, auto, t, positionOffset)); + return playfield; } From a0e31018a18af7eeec7c4608cd5dcce7387d0f99 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Sun, 18 Sep 2022 22:06:07 -0700 Subject: [PATCH 1210/2686] Copy stable smoke's fade/alpha values, blending, scale, and rotation --- .../Skinning/Default/DefaultSmoke.cs | 15 +++- .../Skinning/Legacy/LegacySmoke.cs | 83 ++++++++++++++++--- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 57 +++++-------- 3 files changed, 108 insertions(+), 47 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs index e7f526da31..0ba0143466 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Rendering; +using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default @@ -40,12 +41,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default fadeOutTime = SmokeStartTime + fade_out_speed * (CurrentTime - (SmokeEndTime + fade_out_delay)); } - protected override Color4 ColorAtTime(double pointTime) + protected override Color4 PointColor(SmokePoint point) { var color = Color4.White; color.A = alpha; - double timeDoingFadeOut = fadeOutTime - pointTime; + double timeDoingFadeOut = fadeOutTime - point.Time; if (timeDoingFadeOut > 0) { @@ -56,6 +57,16 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default return color; } + + protected override float PointScale(SmokePoint point) + { + throw new NotImplementedException(); + } + + protected override Vector2 PointDirection(SmokePoint point) + { + throw new NotImplementedException(); + } } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index 23ab2d186f..093d8f87eb 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -4,29 +4,59 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Rendering; +using osu.Framework.Utils; using osu.Game.Skinning; +using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacySmoke : Smoke { - private const double initial_fade_out_duration = 2500; + // fade values + private const double initial_fade_out_duration = 4000; private const double re_fade_in_speed = 3; private const double re_fade_in_duration = 50; - private const double final_fade_out_duration = 7500; + private const double final_fade_out_speed = 2; + private const double final_fade_out_duration = 8000; - private const float initial_alpha = 0.8f; - private const float re_fade_in_alpha = 1.4f; + private const float initial_alpha = 0.6f; + private const float re_fade_in_alpha = 1f; + + // scale values + private const double scale_duration = 1200; + + private const float initial_scale = 0.65f; + private const float final_scale = 1f; + + // rotation values + private const double rotation_duration = 500; + + private const float max_rotation = 0.25f; + + private int rotationSeed = RNG.Next(); + + protected int RotationSeed + { + get => rotationSeed; + set + { + if (rotationSeed == value) + return; + + rotationSeed = value; + Invalidate(Invalidation.DrawNode); + } + } protected override double LifetimeAfterSmokeEnd { get { double initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); - return final_fade_out_duration + initialFadeOutDurationTrunc * (1 + re_fade_in_speed); + return final_fade_out_duration + initialFadeOutDurationTrunc / re_fade_in_speed + initialFadeOutDurationTrunc / final_fade_out_speed; } } @@ -49,11 +79,16 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected class LegacySmokeDrawNode : SmokeDrawNode { + protected new LegacySmoke Source => (LegacySmoke)base.Source; + private double initialFadeOutDurationTrunc; private double initialFadeOutTime; private double reFadeInTime; private double finalFadeOutTime; + private int rotationSeed; + private Random rotationRNG = new Random(); + public LegacySmokeDrawNode(ITexturedShaderDrawable source) : base(source) { @@ -64,34 +99,35 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy base.ApplyState(); initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); + rotationSeed = Source.RotationSeed; } protected override void UpdateDrawVariables(IRenderer renderer) { base.UpdateDrawVariables(renderer); + rotationRNG = new Random(rotationSeed); initialFadeOutTime = Math.Min(CurrentTime, SmokeEndTime); reFadeInTime = re_fade_in_speed * (CurrentTime - SmokeEndTime) + SmokeEndTime - initialFadeOutDurationTrunc; - finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc * (1 + 1 / re_fade_in_speed); + finalFadeOutTime = final_fade_out_speed * (CurrentTime - SmokeEndTime) + SmokeEndTime - initialFadeOutDurationTrunc * (1 + 1 / re_fade_in_speed); } - protected override Color4 ColorAtTime(double pointTime) + protected override Color4 PointColor(SmokePoint point) { var color = Color4.White; - double timeDoingInitialFadeOut = initialFadeOutTime - pointTime; + double timeDoingInitialFadeOut = initialFadeOutTime - point.Time; if (timeDoingInitialFadeOut > 0) { float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); - fraction = MathF.Pow(fraction, 5); color.A = (1 - fraction) * initial_alpha; } if (color.A > 0) { - double timeDoingReFadeIn = reFadeInTime - pointTime; - double timeDoingFinalFadeOut = finalFadeOutTime - pointTime; + double timeDoingReFadeIn = reFadeInTime - point.Time; + double timeDoingFinalFadeOut = finalFadeOutTime - point.Time; if (timeDoingFinalFadeOut > 0) { @@ -109,6 +145,31 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return color; } + + protected override float PointScale(SmokePoint point) + { + double timeDoingScale = CurrentTime - point.Time; + float fraction = Math.Clamp((float)(timeDoingScale / scale_duration), 0, 1); + fraction = 1 - MathF.Pow(1 - fraction, 5); + return fraction * (final_scale - initial_scale) + initial_scale; + } + + protected override Vector2 PointDirection(SmokePoint point) + { + float initialAngle = MathF.Atan2(point.Direction.Y, point.Direction.X); + float finalAngle = initialAngle + nextRotation(); + + double timeDoingRotation = CurrentTime - point.Time; + float fraction = Math.Clamp((float)(timeDoingRotation / rotation_duration), 0, 1); + fraction = 1 - MathF.Pow(1 - fraction, 5); + float angle = fraction * (finalAngle - initialAngle) + initialAngle; + + return toVector2(angle); + } + + private float nextRotation() => max_rotation * ((float)rotationRNG.NextDouble() * 2 - 1); + + private Vector2 toVector2(float angle) => new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 382e54e2ab..b725cc028b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -42,21 +42,6 @@ namespace osu.Game.Rulesets.Osu.Skinning } } - private int rotationSeed = RNG.Next(); - - protected int RotationSeed - { - get => rotationSeed; - set - { - if (rotationSeed == value) - return; - - rotationSeed = value; - Invalidate(Invalidation.DrawNode); - } - } - private Texture? texture; protected Texture? Texture @@ -195,6 +180,12 @@ namespace osu.Game.Rulesets.Osu.Skinning SmokeStartTime = Time.Current; } + private Vector2 nextPointDirection() + { + float angle = RNG.NextSingle(0, 2 * MathF.PI); + return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); + } + private void onSmokeMoved(Vector2 position, double time) { if (!IsActive) @@ -229,6 +220,7 @@ namespace osu.Game.Rulesets.Osu.Skinning { Position = pointPos, Time = time, + Direction = nextPointDirection(), }); pointPos += increment; @@ -303,6 +295,7 @@ namespace osu.Game.Rulesets.Osu.Skinning { public Vector2 Position; public double Time; + public Vector2 Direction; public struct UpperBoundComparer : IComparer { @@ -339,9 +332,6 @@ namespace osu.Game.Rulesets.Osu.Skinning private IFrameBasedClock? clock; - private int rotationSeed; - private Random rotationRNG = new Random(); - protected SmokeDrawNode(ITexturedShaderDrawable source) : base(source) { @@ -362,8 +352,6 @@ namespace osu.Game.Rulesets.Osu.Skinning SmokeStartTime = Source.SmokeStartTime; SmokeEndTime = Source.SmokeEndTime; - - rotationSeed = Source.RotationSeed; } public sealed override void Draw(IRenderer renderer) @@ -377,6 +365,9 @@ namespace osu.Game.Rulesets.Osu.Skinning Texture ??= renderer.WhitePixel; var shader = GetAppropriateShader(renderer); + + renderer.SetBlend(BlendingParameters.Additive); + shader.Bind(); Texture.Bind(); @@ -390,7 +381,11 @@ namespace osu.Game.Rulesets.Osu.Skinning ? ((SRGBColour)DrawColourInfo.Colour).Linear : DrawColourInfo.Colour.Interpolate(Vector2.Divide(localPos, DrawSize)).Linear; - protected abstract Color4 ColorAtTime(double pointTime); + protected abstract Color4 PointColor(SmokePoint point); + + protected abstract float PointScale(SmokePoint point); + + protected abstract Vector2 PointDirection(SmokePoint point); protected virtual void UpdateDrawVariables(IRenderer renderer) { @@ -399,7 +394,6 @@ namespace osu.Game.Rulesets.Osu.Skinning CurrentTime = clock.CurrentTime; TextureRect = Texture.GetTextureRect(); - rotationRNG = new Random(rotationSeed); } protected virtual void UpdateVertexBuffer() @@ -408,24 +402,19 @@ namespace osu.Game.Rulesets.Osu.Skinning drawPointQuad(point); } - private Vector2 nextTextureDirection() - { - float angle = (float)rotationRNG.NextDouble() * 2 * MathF.PI; - return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); - } - private void drawPointQuad(SmokePoint point) { Debug.Assert(QuadBatch != null); - var color = ColorAtTime(point.Time); - var dir = nextTextureDirection(); + var color = PointColor(point); + float scale = PointScale(point); + var dir = PointDirection(point); var ortho = dir.PerpendicularLeft; - var localTopLeft = point.Position + (Radius * (-ortho - dir)) - PositionOffset; - var localTopRight = point.Position + (Radius * (-ortho + dir)) - PositionOffset; - var localBotLeft = point.Position + (Radius * (ortho - dir)) - PositionOffset; - var localBotRight = point.Position + (Radius * (ortho + dir)) - PositionOffset; + var localTopLeft = point.Position + (Radius * scale * (-ortho - dir)) - PositionOffset; + var localTopRight = point.Position + (Radius * scale * (-ortho + dir)) - PositionOffset; + var localBotLeft = point.Position + (Radius * scale * (ortho - dir)) - PositionOffset; + var localBotRight = point.Position + (Radius * scale * (ortho + dir)) - PositionOffset; QuadBatch.Add(new TexturedVertex2D { From 8474335aeaf520b61a82b3800f473728e77b402d Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Sun, 18 Sep 2022 22:08:45 -0700 Subject: [PATCH 1211/2686] Remove hacky LifetimeEnd workaround --- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index b725cc028b..822dc113f1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -16,7 +16,6 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Rulesets.Osu.UI; -using osu.Game.Skinning; using osuTK; using osuTK.Graphics; @@ -265,10 +264,6 @@ namespace osu.Game.Rulesets.Osu.Skinning IsActive = false; SmokeEndTime = time; LifetimeEnd = time + LifetimeAfterSmokeEnd + 100; - - // TODO: HYPER MEGA JANK WTF?? - if (Parent is SkinnableDrawable) - Parent.LifetimeEnd = LifetimeEnd; } protected abstract override DrawNode CreateDrawNode(); From 3eb28881e4b0052894f9b60c0ebe649e02921118 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Sun, 18 Sep 2022 22:14:54 -0700 Subject: [PATCH 1212/2686] Temp default smoke scale/rotation anims --- osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs index 0ba0143466..6eebd18305 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -58,15 +58,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default return color; } - protected override float PointScale(SmokePoint point) - { - throw new NotImplementedException(); - } + protected override float PointScale(SmokePoint point) => 1f; - protected override Vector2 PointDirection(SmokePoint point) - { - throw new NotImplementedException(); - } + protected override Vector2 PointDirection(SmokePoint point) => point.Direction; } } } From 8204090e471f6784c9d1a520ac97b61e7391ff66 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 19 Sep 2022 00:07:22 -0700 Subject: [PATCH 1213/2686] Scale smoke radius based on texture width --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs | 5 +---- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index 093d8f87eb..d8c3ff3521 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -65,7 +65,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy public LegacySmoke(ISkin skin) { this.skin = skin; - Radius = 3; } protected override void LoadComplete() @@ -164,12 +163,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy fraction = 1 - MathF.Pow(1 - fraction, 5); float angle = fraction * (finalAngle - initialAngle) + initialAngle; - return toVector2(angle); + return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); } private float nextRotation() => max_rotation * ((float)rotationRNG.NextDouble() * 2 - 1); - - private Vector2 toVector2(float angle) => new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 822dc113f1..bada67816b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -26,11 +26,11 @@ namespace osu.Game.Rulesets.Osu.Skinning public IShader? TextureShader { get; private set; } public IShader? RoundedTextureShader { get; private set; } - private float radius = 1; + private float? radius; protected float Radius { - get => radius; + get => radius ?? Texture?.DisplayWidth * 0.165f ?? 3; set { if (radius == value) From 41e7d271d764bb9f0d5c77b7f192fa1592212f4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 21:51:54 +0900 Subject: [PATCH 1214/2686] Remove redundant string interpolation --- .../Visual/Gameplay/TestScenePlayerLocalScoreImport.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs index db9d2bfc1d..38a091dd85 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs @@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.Gameplay Mod[] originalMods = { new OsuModDaycore { SpeedChange = { Value = 0.8 } } }; Mod[] playerMods = null!; - AddStep($"Load player with mods", () => LoadPlayer(originalMods)); + AddStep("load player with mods", () => LoadPlayer(originalMods)); AddUntilStep("player loaded", () => Player.IsLoaded && Player.Alpha == 1); AddStep("get mods at start of gameplay", () => playerMods = Player.Score.ScoreInfo.Mods.ToArray()); From 0f7b38f4c3c463bc4f1a39f4577d6cccf30e835b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 16:02:57 +0900 Subject: [PATCH 1215/2686] Add new default skin "argon" --- .../Overlays/Settings/Sections/SkinSection.cs | 1 + .../Backgrounds/BackgroundScreenDefault.cs | 16 +- osu.Game/Skinning/ArgonSkin.cs | 198 ++++++++++++++++++ .../Skinning/RulesetSkinProvidingContainer.cs | 1 + osu.Game/Skinning/SkinInfo.cs | 1 + osu.Game/Skinning/SkinManager.cs | 31 +-- osu.Game/Skinning/SkinnableSprite.cs | 1 + osu.Game/Tests/Visual/SkinnableTestScene.cs | 2 +- 8 files changed, 234 insertions(+), 17 deletions(-) create mode 100644 osu.Game/Skinning/ArgonSkin.cs diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 8d491a980a..f602b73065 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -104,6 +104,7 @@ namespace osu.Game.Overlays.Settings.Sections // In the future we should change this to properly handle ChangeSet events. dropdownItems.Clear(); + dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.ARGON_SKIN).ToLive(realm)); dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.TRIANGLES_SKIN).ToLive(realm)); dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.CLASSIC_SKIN).ToLive(realm)); diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index dbc4e2b2e1..f8546d6ed0 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -129,11 +129,19 @@ namespace osu.Game.Screens.Backgrounds } case BackgroundSource.Skin: - // default skins should use the default background rotation, which won't be the case if a SkinBackground is created for them. - if (skin.Value is TrianglesSkin || skin.Value is DefaultLegacySkin) - break; + switch (skin.Value) + { + case TrianglesSkin: + case ArgonSkin: + case DefaultLegacySkin: + // default skins should use the default background rotation, which won't be the case if a SkinBackground is created for them. + break; + + default: + newBackground = new SkinBackground(skin.Value, getBackgroundTextureName()); + break; + } - newBackground = new SkinBackground(skin.Value, getBackgroundTextureName()); break; } } diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs new file mode 100644 index 0000000000..2c17b28b01 --- /dev/null +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -0,0 +1,198 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Game.Audio; +using osu.Game.Beatmaps.Formats; +using osu.Game.Extensions; +using osu.Game.IO; +using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.HUD.HitErrorMeters; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Skinning +{ + public class ArgonSkin : Skin + { + public static SkinInfo CreateInfo() => new SkinInfo + { + ID = osu.Game.Skinning.SkinInfo.ARGON_SKIN, + Name = "osu! \"argon\" (2022)", + Creator = "team osu!", + Protected = true, + InstantiationInfo = typeof(ArgonSkin).GetInvariantInstantiationInfo() + }; + + private readonly IStorageResourceProvider resources; + + public ArgonSkin(IStorageResourceProvider resources) + : this(CreateInfo(), resources) + { + } + + [UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)] + public ArgonSkin(SkinInfo skin, IStorageResourceProvider resources) + : base(skin, resources) + { + this.resources = resources; + } + + public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Textures?.Get(componentName, wrapModeS, wrapModeT); + + public override ISample GetSample(ISampleInfo sampleInfo) + { + foreach (string lookup in sampleInfo.LookupNames) + { + var sample = Samples?.Get(lookup) ?? resources.AudioManager?.Samples.Get(lookup); + if (sample != null) + return sample; + } + + return null; + } + + public override Drawable GetDrawableComponent(ISkinComponent component) + { + if (base.GetDrawableComponent(component) is Drawable c) + return c; + + switch (component) + { + case SkinnableTargetComponent target: + switch (target.Target) + { + case SkinnableTarget.SongSelect: + var songSelectComponents = new SkinnableTargetComponentsContainer(_ => + { + // do stuff when we need to. + }); + + return songSelectComponents; + + case SkinnableTarget.MainHUDComponents: + var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => + { + var score = container.OfType().FirstOrDefault(); + var accuracy = container.OfType().FirstOrDefault(); + var combo = container.OfType().FirstOrDefault(); + var ppCounter = container.OfType().FirstOrDefault(); + + if (score != null) + { + score.Anchor = Anchor.TopCentre; + score.Origin = Anchor.TopCentre; + + // elements default to beneath the health bar + const float vertical_offset = 30; + + const float horizontal_padding = 20; + + score.Position = new Vector2(0, vertical_offset); + + if (ppCounter != null) + { + ppCounter.Y = score.Position.Y + ppCounter.ScreenSpaceDeltaToParentSpace(score.ScreenSpaceDrawQuad.Size).Y - 4; + ppCounter.Origin = Anchor.TopCentre; + ppCounter.Anchor = Anchor.TopCentre; + } + + if (accuracy != null) + { + accuracy.Position = new Vector2(-accuracy.ScreenSpaceDeltaToParentSpace(score.ScreenSpaceDrawQuad.Size).X / 2 - horizontal_padding, vertical_offset + 5); + accuracy.Origin = Anchor.TopRight; + accuracy.Anchor = Anchor.TopCentre; + + if (combo != null) + { + combo.Position = new Vector2(accuracy.ScreenSpaceDeltaToParentSpace(score.ScreenSpaceDrawQuad.Size).X / 2 + horizontal_padding, vertical_offset + 5); + combo.Anchor = Anchor.TopCentre; + } + } + + var hitError = container.OfType().FirstOrDefault(); + + if (hitError != null) + { + hitError.Anchor = Anchor.CentreLeft; + hitError.Origin = Anchor.CentreLeft; + } + + var hitError2 = container.OfType().LastOrDefault(); + + if (hitError2 != null) + { + hitError2.Anchor = Anchor.CentreRight; + hitError2.Scale = new Vector2(-1, 1); + // origin flipped to match scale above. + hitError2.Origin = Anchor.CentreLeft; + } + } + }) + { + Children = new Drawable[] + { + new DefaultComboCounter(), + new DefaultScoreCounter(), + new DefaultAccuracyCounter(), + new DefaultHealthDisplay(), + new DefaultSongProgress(), + new BarHitErrorMeter(), + new BarHitErrorMeter(), + new PerformancePointsCounter() + } + }; + + return skinnableTargetWrapper; + } + + return null; + } + + switch (component.LookupName) + { + // Temporary until default skin has a valid hit lighting. + case @"lighting": + return Drawable.Empty(); + } + + if (GetTexture(component.LookupName) is Texture t) + return new Sprite { Texture = t }; + + return null; + } + + public override IBindable GetConfig(TLookup lookup) + { + // todo: this code is pulled from LegacySkin and should not exist. + // will likely change based on how databased storage of skin configuration goes. + switch (lookup) + { + case GlobalSkinColours global: + switch (global) + { + case GlobalSkinColours.ComboColours: + return SkinUtils.As(new Bindable>(Configuration.ComboColours)); + } + + break; + + case SkinComboColourLookup comboColour: + return SkinUtils.As(new Bindable(getComboColour(Configuration, comboColour.ColourIndex))); + } + + return null; + } + + private static Color4 getComboColour(IHasComboColours source, int colourIndex) + => source.ComboColours[colourIndex % source.ComboColours.Count]; + } +} diff --git a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs index 4c35681f66..6ad5d64e4b 100644 --- a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs +++ b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs @@ -81,6 +81,7 @@ namespace osu.Game.Skinning } } + // TODO: check int lastDefaultSkinIndex = sources.IndexOf(sources.OfType().LastOrDefault()); // Ruleset resources should be given the ability to override game-wide defaults diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index 34728245c8..08d8a81d4c 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -20,6 +20,7 @@ namespace osu.Game.Skinning public class SkinInfo : RealmObject, IHasRealmFiles, IEquatable, IHasGuidPrimaryKey, ISoftDelete, IHasNamedFiles { internal static readonly Guid TRIANGLES_SKIN = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD"); + internal static readonly Guid ARGON_SKIN = new Guid("CFFA69DE-B3E3-4DEE-8563-3C4F425C05D0"); internal static readonly Guid CLASSIC_SKIN = new Guid("81F02CD3-EEC6-4865-AC23-FAE26A386187"); internal static readonly Guid RANDOM_SKIN = new Guid("D39DFEFB-477C-4372-B1EA-2BCEA5FB8908"); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index a9a01dfebf..059767d8f8 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -49,10 +49,7 @@ namespace osu.Game.Skinning public readonly Bindable CurrentSkin = new Bindable(); - public readonly Bindable> CurrentSkinInfo = new Bindable>(TrianglesSkin.CreateInfo().ToLiveUnmanaged()) - { - Default = TrianglesSkin.CreateInfo().ToLiveUnmanaged() - }; + public readonly Bindable> CurrentSkinInfo = new Bindable>(ArgonSkin.CreateInfo().ToLiveUnmanaged()); private readonly SkinImporter skinImporter; @@ -61,7 +58,12 @@ namespace osu.Game.Skinning /// /// The default "triangles" skin. /// - public Skin DefaultSkinTriangles { get; } + private Skin argonSkin { get; } + + /// + /// The default skin (old). + /// + private Skin trianglesSkin { get; } /// /// The default "classic" skin. @@ -86,7 +88,8 @@ namespace osu.Game.Skinning var defaultSkins = new[] { DefaultClassicSkin = new DefaultLegacySkin(this), - DefaultSkinTriangles = new TrianglesSkin(this), + trianglesSkin = new TrianglesSkin(this), + argonSkin = new ArgonSkin(this), }; // Ensure the default entries are present. @@ -104,7 +107,7 @@ namespace osu.Game.Skinning CurrentSkin.Value = skin.NewValue.PerformRead(GetSkin); }; - CurrentSkin.Value = DefaultSkinTriangles; + CurrentSkin.Value = argonSkin; CurrentSkin.ValueChanged += skin => { if (!skin.NewValue.SkinInfo.Equals(CurrentSkinInfo.Value)) @@ -125,7 +128,7 @@ namespace osu.Game.Skinning if (randomChoices.Length == 0) { - CurrentSkinInfo.Value = TrianglesSkin.CreateInfo().ToLiveUnmanaged(); + CurrentSkinInfo.Value = ArgonSkin.CreateInfo().ToLiveUnmanaged(); return; } @@ -229,11 +232,15 @@ namespace osu.Game.Skinning { yield return CurrentSkin.Value; + // Skin manager provides default fallbacks. + // This handles cases where a user skin doesn't have the required resources for complete display of + // certain elements. + if (CurrentSkin.Value is LegacySkin && CurrentSkin.Value != DefaultClassicSkin) yield return DefaultClassicSkin; - if (CurrentSkin.Value != DefaultSkinTriangles) - yield return DefaultSkinTriangles; + if (CurrentSkin.Value != trianglesSkin) + yield return trianglesSkin; } } @@ -294,7 +301,7 @@ namespace osu.Game.Skinning Guid currentUserSkin = CurrentSkinInfo.Value.ID; if (items.Any(s => s.ID == currentUserSkin)) - scheduler.Add(() => CurrentSkinInfo.Value = TrianglesSkin.CreateInfo().ToLiveUnmanaged()); + scheduler.Add(() => CurrentSkinInfo.Value = ArgonSkin.CreateInfo().ToLiveUnmanaged()); Delete(items.ToList(), silent); }); @@ -313,7 +320,7 @@ namespace osu.Game.Skinning skinInfo = DefaultClassicSkin.SkinInfo; } - CurrentSkinInfo.Value = skinInfo ?? DefaultSkinTriangles.SkinInfo; + CurrentSkinInfo.Value = skinInfo ?? trianglesSkin.SkinInfo; } } } diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 69454de979..f8a9aaa6fb 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -113,6 +113,7 @@ namespace osu.Game.Skinning // Temporarily used to exclude undesirable ISkin implementations static bool isUserSkin(ISkin skin) => skin.GetType() == typeof(TrianglesSkin) + || skin.GetType() == typeof(ArgonSkin) || skin.GetType() == typeof(DefaultLegacySkin) || skin.GetType() == typeof(LegacySkin); } diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index 4ef9a733c4..a8193701ef 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -104,7 +104,7 @@ namespace osu.Game.Tests.Visual }, new OsuSpriteText { - Text = skin?.SkinInfo.Value.Name ?? "none", + Text = skin.SkinInfo.Value.Name, Scale = new Vector2(1.5f), Padding = new MarginPadding(5), }, From b766493776071d9ecc6660fb8df200f1066abcad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Sep 2022 17:51:10 +0900 Subject: [PATCH 1216/2686] Add basic argon skin transformer for osu! ruleset --- osu.Game.Rulesets.Osu/OsuRuleset.cs | 4 + .../Skinning/Argon/ArgonMainCirclePiece.cs | 157 ++++++++++++++++++ .../Skinning/Argon/OsuArgonSkinTransformer.cs | 49 ++++++ .../Skinning/Default/RingPiece.cs | 4 +- 4 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 0a5b3139fc..3f5e728651 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -27,6 +27,7 @@ using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.Osu.Scoring; +using osu.Game.Rulesets.Osu.Skinning.Argon; using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.Osu.Statistics; using osu.Game.Rulesets.Osu.UI; @@ -237,6 +238,9 @@ namespace osu.Game.Rulesets.Osu { case LegacySkin: return new OsuLegacySkinTransformer(skin); + + case ArgonSkin: + return new OsuArgonSkinTransformer(skin); } return null; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs new file mode 100644 index 0000000000..7f645f1452 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -0,0 +1,157 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Skinning.Default; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonMainCirclePiece : CompositeDrawable + { + private readonly Circle outerFill; + private readonly Circle outerGradient; + private readonly Circle innerGradient; + private readonly Circle innerFill; + + private readonly RingPiece ring; + private readonly OsuSpriteText number; + + private readonly IBindable accentColour = new Bindable(); + private readonly IBindable indexInCurrentCombo = new Bindable(); + + [Resolved] + private DrawableHitObject drawableObject { get; set; } = null!; + + public ArgonMainCirclePiece() + { + Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + const float border_thickness = 7; + const float fill_thickness = 24; + + InternalChildren = new Drawable[] + { + outerFill = new Circle // renders white outer border and dark fill + { + Size = Size, + Alpha = 1, + }, + outerGradient = new Circle // renders the outer bright gradient + { + Size = outerFill.Size - new Vector2(border_thickness * 3), + Alpha = 1, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + innerGradient = new Circle // renders the inner bright gradient + { + Size = outerGradient.Size - new Vector2(fill_thickness), + Alpha = 1, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + innerFill = new Circle // renders the inner dark fill + { + Size = innerGradient.Size - new Vector2(fill_thickness), + Alpha = 1, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + number = new OsuSpriteText + { + Font = OsuFont.Default.With(size: 52, weight: FontWeight.Bold), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Y = -2, + Text = @"1", + }, + ring = new RingPiece(border_thickness), + }; + } + + [BackgroundDependencyLoader] + private void load() + { + var drawableOsuObject = (DrawableOsuHitObject)drawableObject; + + accentColour.BindTo(drawableObject.AccentColour); + indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + accentColour.BindValueChanged(colour => + { + outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); + outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); + innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); + }, true); + + indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); + + drawableObject.ApplyCustomUpdateState += updateStateTransforms; + updateStateTransforms(drawableObject, drawableObject.State.Value); + } + + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) + { + using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) + { + switch (state) + { + case ArmedState.Hit: + const double fade_out_time = 600; + const double flash_in = 200; + + number.FadeOut(flash_in / 4); + + outerGradient.ResizeTo(Size, fade_out_time / 2, Easing.OutQuint); + outerGradient.FadeOut(flash_in); + + innerGradient.ResizeTo(Size, fade_out_time * 2, Easing.OutQuint); + innerGradient.FadeOut(flash_in); + + innerFill.ResizeTo(Size, fade_out_time * 1.5, Easing.OutQuint); + innerFill.FadeOut(flash_in); + + outerFill.FadeOut(flash_in); + + ring.ResizeTo(Size + new Vector2(ring.BorderThickness * 1.5f), fade_out_time / 1.5f, Easing.OutQuint); + ring.FadeOut(fade_out_time); + + using (BeginDelayedSequence(flash_in)) + this.FadeOut(fade_out_time, Easing.OutQuint); + + break; + } + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (drawableObject.IsNotNull()) + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs new file mode 100644 index 0000000000..6aced740bc --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -0,0 +1,49 @@ +// 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.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; +using osu.Game.Audio; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class OsuArgonSkinTransformer : ISkin + { + public OsuArgonSkinTransformer(ISkin skin) + { + } + + public Drawable? GetDrawableComponent(ISkinComponent component) + { + if (component is OsuSkinComponent osuComponent) + { + switch (osuComponent.Component) + { + case OsuSkinComponents.HitCircle: + case OsuSkinComponents.SliderHeadHitCircle: + return new ArgonMainCirclePiece(); + } + } + + return null; + } + + public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) + { + return null; + } + + public ISample? GetSample(ISampleInfo sampleInfo) + { + return null; + } + + public IBindable? GetConfig(TLookup lookup) where TLookup : notnull where TValue : notnull + { + return null; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs index b941a86171..c14246e90e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { public class RingPiece : CircularContainer { - public RingPiece() + public RingPiece(float thickness = 9) { Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default Origin = Anchor.Centre; Masking = true; - BorderThickness = 9; // roughly matches slider borders and makes stacked circles distinctly visible from each other. + BorderThickness = thickness; BorderColour = Color4.White; Child = new Box From 4a86fe1ca90d79fc46db9fa8a23bd77f55ccfb34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 19:25:12 +0900 Subject: [PATCH 1217/2686] Tweak main circle animations --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 74 +++++++++++++++---- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 7f645f1452..02271b6a7a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -8,6 +8,7 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -32,6 +33,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private readonly IBindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); + private readonly FlashPiece flash; [Resolved] private DrawableHitObject drawableObject { get; set; } = null!; @@ -82,6 +84,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Y = -2, Text = @"1", }, + flash = new FlashPiece(), ring = new RingPiece(border_thickness), }; } @@ -104,6 +107,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); + flash.Colour = colour.NewValue.Multiply(1f); }, true); indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); @@ -119,27 +123,37 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon switch (state) { case ArmedState.Hit: - const double fade_out_time = 600; - const double flash_in = 200; + const double fade_out_time = 800; + const double flash_in = 150; - number.FadeOut(flash_in / 4); - - outerGradient.ResizeTo(Size, fade_out_time / 2, Easing.OutQuint); - outerGradient.FadeOut(flash_in); - - innerGradient.ResizeTo(Size, fade_out_time * 2, Easing.OutQuint); - innerGradient.FadeOut(flash_in); - - innerFill.ResizeTo(Size, fade_out_time * 1.5, Easing.OutQuint); - innerFill.FadeOut(flash_in); + number.FadeOut(flash_in / 2); outerFill.FadeOut(flash_in); - ring.ResizeTo(Size + new Vector2(ring.BorderThickness * 1.5f), fade_out_time / 1.5f, Easing.OutQuint); - ring.FadeOut(fade_out_time); + ring.ResizeTo(Size - new Vector2(ring.BorderThickness * 1.5f), flash_in, Easing.OutQuint); - using (BeginDelayedSequence(flash_in)) - this.FadeOut(fade_out_time, Easing.OutQuint); + ring.TransformTo(nameof + (BorderColour), ColourInfo.GradientVertical( + accentColour.Value.Opacity(0.5f), + accentColour.Value.Opacity(0)), fade_out_time); + + flash.FadeTo(1, flash_in * 2, Easing.OutQuint); + + using (BeginDelayedSequence(flash_in / 8)) + { + outerGradient.ResizeTo(outerGradient.Size * 0.8f, flash_in, Easing.OutQuint); + + using (BeginDelayedSequence(flash_in / 8)) + { + innerGradient.ResizeTo(innerGradient.Size * 0.8f, flash_in, Easing.OutQuint); + innerFill.ResizeTo(innerFill.Size * 0.8f, flash_in, Easing.OutQuint); + } + } + + innerFill.FadeOut(flash_in, Easing.OutQuint); + innerGradient.FadeOut(flash_in, Easing.OutQuint); + + this.FadeOut(fade_out_time, Easing.OutQuad); break; } @@ -153,5 +167,33 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon if (drawableObject.IsNotNull()) drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } + + private class FlashPiece : Circle + { + public FlashPiece() + { + Size = new Vector2(OsuHitObject.OBJECT_RADIUS); + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Alpha = 0; + Blending = BlendingParameters.Additive; + + Child.Alpha = 0; + Child.AlwaysPresent = true; + } + + protected override void Update() + { + base.Update(); + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Colour, + Radius = OsuHitObject.OBJECT_RADIUS * 1.4f, + }; + } + } } } From 02fbb04ba86c8af0ad251f3a1eeb1d146ebfdc4b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Sep 2022 19:25:04 +0900 Subject: [PATCH 1218/2686] Add basic argon judgement --- .../Skinning/Argon/ArgonJudgementPiece.cs | 85 +++++++++++++++++++ .../Skinning/Argon/OsuArgonSkinTransformer.cs | 21 +++-- 2 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs new file mode 100644 index 0000000000..315b9ec65e --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs @@ -0,0 +1,85 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + { + protected readonly HitResult Result; + + protected SpriteText JudgementText { get; private set; } = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + public ArgonJudgementPiece(HitResult result) + { + Result = result; + Origin = Anchor.Centre; + } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + JudgementText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = Result.GetDescription().ToUpperInvariant(), + Colour = colours.ForHitResult(Result), + Spacing = new Vector2(5, 0), + Font = OsuFont.Default.With(size: 20, weight: FontWeight.Bold), + } + }; + } + + /// + /// Plays the default animation for this judgement piece. + /// + /// + /// The base implementation only handles fade (for all result types) and misses. + /// Individual rulesets are recommended to implement their appropriate hit animations. + /// + public virtual void PlayAnimation() + { + switch (Result) + { + default: + JudgementText + .ScaleTo(Vector2.One) + .ScaleTo(new Vector2(1.2f), 1800, Easing.OutQuint); + break; + + case HitResult.Miss: + this.ScaleTo(1.6f); + this.ScaleTo(1, 100, Easing.In); + + this.MoveTo(Vector2.Zero); + this.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint); + + this.RotateTo(0); + this.RotateTo(40, 800, Easing.InQuint); + break; + } + + this.FadeOutFromOne(800); + } + + public Drawable? GetAboveHitObjectsProxiedContent() => null; + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 6aced740bc..6523a5cb88 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -6,6 +6,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Game.Audio; +using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Skinning.Argon @@ -18,14 +19,20 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon public Drawable? GetDrawableComponent(ISkinComponent component) { - if (component is OsuSkinComponent osuComponent) + switch (component) { - switch (osuComponent.Component) - { - case OsuSkinComponents.HitCircle: - case OsuSkinComponents.SliderHeadHitCircle: - return new ArgonMainCirclePiece(); - } + case GameplaySkinComponent resultComponent: + return new ArgonJudgementPiece(resultComponent.Component); + + case OsuSkinComponent osuComponent: + switch (osuComponent.Component) + { + case OsuSkinComponents.HitCircle: + case OsuSkinComponents.SliderHeadHitCircle: + return new ArgonMainCirclePiece(); + } + + break; } return null; From 403cc592088744ebd65ea222b2b3d1700b32243e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 13:19:56 +0900 Subject: [PATCH 1219/2686] Further animation tweaks and better documentation --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 02271b6a7a..1271bd8d61 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private readonly Circle innerGradient; private readonly Circle innerFill; - private readonly RingPiece ring; + private readonly RingPiece border; private readonly OsuSpriteText number; private readonly IBindable accentColour = new Bindable(); @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Text = @"1", }, flash = new FlashPiece(), - ring = new RingPiece(border_thickness), + border = new RingPiece(border_thickness), }; } @@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); - flash.Colour = colour.NewValue.Multiply(1f); + flash.Colour = colour.NewValue; }, true); indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); @@ -123,38 +123,51 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon switch (state) { case ArmedState.Hit: + // Fade out time is at a maximum of 800. Must match `DrawableHitCircle`'s arbitrary lifetime spec. const double fade_out_time = 800; - const double flash_in = 150; - number.FadeOut(flash_in / 2); + const double flash_in_duration = 150; + const double resize_duration = 300; - outerFill.FadeOut(flash_in); + const float shrink_size = 0.8f; - ring.ResizeTo(Size - new Vector2(ring.BorderThickness * 1.5f), flash_in, Easing.OutQuint); + // Animating with the number present is distracting. + // The number disappearing is hidden by the bright flash. + number.FadeOut(flash_in_duration / 2); - ring.TransformTo(nameof + // The fill layers add too much noise during the explosion animation. + // They will be hidden by the additive effects anyway. + outerFill.FadeOut(flash_in_duration, Easing.OutQuint); + innerFill.FadeOut(flash_in_duration, Easing.OutQuint); + + // The inner-most gradient should actually be resizing, but is only visible for + // a few milliseconds before it's hidden by the flash, so it's pointless overhead to bother with it. + innerGradient.FadeOut(flash_in_duration, Easing.OutQuint); + + // The border is always white, but after hit it gets coloured by the skin/beatmap's colouring. + // A gradient is applied to make the border less prominent over the course of the animation. + // Without this, the border dominates the visual presence of the explosion animation in a bad way. + border.TransformTo(nameof (BorderColour), ColourInfo.GradientVertical( accentColour.Value.Opacity(0.5f), accentColour.Value.Opacity(0)), fade_out_time); - flash.FadeTo(1, flash_in * 2, Easing.OutQuint); + // The outer ring shrinks immediately, but accounts for its thickness so it doesn't overlap the inner + // gradient layers. + border.ResizeTo(Size * shrink_size + new Vector2(border.BorderThickness), resize_duration, Easing.OutElasticHalf); - using (BeginDelayedSequence(flash_in / 8)) - { - outerGradient.ResizeTo(outerGradient.Size * 0.8f, flash_in, Easing.OutQuint); + // The outer gradient is resize with a slight delay from the border. + // This is to give it a bomb-like effect, with the border "triggering" its animation when getting close. + using (BeginDelayedSequence(flash_in_duration / 12)) + outerGradient.ResizeTo(outerGradient.Size * shrink_size, resize_duration, Easing.OutElasticHalf); - using (BeginDelayedSequence(flash_in / 8)) - { - innerGradient.ResizeTo(innerGradient.Size * 0.8f, flash_in, Easing.OutQuint); - innerFill.ResizeTo(innerFill.Size * 0.8f, flash_in, Easing.OutQuint); - } - } - - innerFill.FadeOut(flash_in, Easing.OutQuint); - innerGradient.FadeOut(flash_in, Easing.OutQuint); + // The flash layer starts white to give the wanted brightness, but is almost immediately + // recoloured to the accent colour. This would more correctly be done with two layers (one for the initial flash) + // but works well enough with the colour fade. + flash.FadeTo(1, flash_in_duration, Easing.OutQuint); + flash.FlashColour(Color4.White, flash_in_duration, Easing.OutQuint); this.FadeOut(fade_out_time, Easing.OutQuad); - break; } } @@ -180,6 +193,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Alpha = 0; Blending = BlendingParameters.Additive; + // The edge effect provides the fill due to not being rendered hollow. Child.Alpha = 0; Child.AlwaysPresent = true; } @@ -187,11 +201,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon protected override void Update() { base.Update(); + EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow, Colour = Colour, - Radius = OsuHitObject.OBJECT_RADIUS * 1.4f, + Radius = OsuHitObject.OBJECT_RADIUS * 1.2f, }; } } From cd84503e62a7fbd6f9603771225b246b1bddd04b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 14:38:21 +0900 Subject: [PATCH 1220/2686] Add slider body --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 22 +++++------ .../Skinning/Argon/ArgonSliderBody.cs | 38 +++++++++++++++++++ .../Skinning/Argon/OsuArgonSkinTransformer.cs | 3 ++ .../Skinning/Default/PlaySliderBody.cs | 14 ++++--- 4 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 1271bd8d61..e4ed3d8fe8 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -23,7 +23,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { public class ArgonMainCirclePiece : CompositeDrawable { - private readonly Circle outerFill; + public const float BORDER_THICKNESS = 7; + + public const float OUTER_GRADIENT_SIZE = OsuHitObject.OBJECT_RADIUS * 2 - BORDER_THICKNESS * 3; + private readonly Circle outerGradient; private readonly Circle innerGradient; private readonly Circle innerFill; @@ -45,33 +48,27 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Anchor = Anchor.Centre; Origin = Anchor.Centre; - const float border_thickness = 7; const float fill_thickness = 24; InternalChildren = new Drawable[] { - outerFill = new Circle // renders white outer border and dark fill - { - Size = Size, - Alpha = 1, - }, outerGradient = new Circle // renders the outer bright gradient { - Size = outerFill.Size - new Vector2(border_thickness * 3), + Size = new Vector2(OUTER_GRADIENT_SIZE), Alpha = 1, Anchor = Anchor.Centre, Origin = Anchor.Centre, }, innerGradient = new Circle // renders the inner bright gradient { - Size = outerGradient.Size - new Vector2(fill_thickness), + Size = new Vector2(OUTER_GRADIENT_SIZE - fill_thickness), Alpha = 1, Anchor = Anchor.Centre, Origin = Anchor.Centre, }, innerFill = new Circle // renders the inner dark fill { - Size = innerGradient.Size - new Vector2(fill_thickness), + Size = new Vector2(OUTER_GRADIENT_SIZE - 2 * fill_thickness), Alpha = 1, Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -85,7 +82,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Text = @"1", }, flash = new FlashPiece(), - border = new RingPiece(border_thickness), + border = new RingPiece(BORDER_THICKNESS), }; } @@ -104,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon accentColour.BindValueChanged(colour => { - outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); + innerFill.Colour = colour.NewValue.Darken(4); outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); flash.Colour = colour.NewValue; @@ -137,7 +134,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon // The fill layers add too much noise during the explosion animation. // They will be hidden by the additive effects anyway. - outerFill.FadeOut(flash_in_duration, Easing.OutQuint); innerFill.FadeOut(flash_in_duration, Easing.OutQuint); // The inner-most gradient should actually be resizing, but is only visible for diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs new file mode 100644 index 0000000000..115e153f34 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.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.Framework.Extensions.Color4Extensions; +using osu.Game.Rulesets.Osu.Skinning.Default; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonSliderBody : PlaySliderBody + { + protected override void LoadComplete() + { + base.LoadComplete(); + + AccentColourBindable.BindValueChanged(accent => + { + BorderColour = accent.NewValue; + }, true); + ScaleBindable.BindValueChanged(scale => PathRadius = ArgonMainCirclePiece.OUTER_GRADIENT_SIZE / 2 * scale.NewValue, true); + + BorderSize = ArgonMainCirclePiece.BORDER_THICKNESS / 4; + } + + protected override Default.DrawableSliderPath CreateSliderPath() => new DrawableSliderPath(); + + private class DrawableSliderPath : Default.DrawableSliderPath + { + protected override Color4 ColourAt(float position) + { + if (CalculatedBorderPortion != 0f && position <= CalculatedBorderPortion) + return BorderColour; + + return AccentColour.Darken(4); + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 6523a5cb88..d257271455 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -30,6 +30,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon case OsuSkinComponents.HitCircle: case OsuSkinComponents.SliderHeadHitCircle: return new ArgonMainCirclePiece(); + + case OsuSkinComponents.SliderBody: + return new ArgonSliderBody(); } break; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs index 83f7bb8904..6c422cf127 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs @@ -16,9 +16,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { public abstract class PlaySliderBody : SnakingSliderBody { - private IBindable scaleBindable; + protected IBindable ScaleBindable { get; private set; } = null!; + + protected IBindable AccentColourBindable { get; private set; } = null!; + private IBindable pathVersion; - private IBindable accentColour; [Resolved(CanBeNull = true)] private OsuRulesetConfigManager config { get; set; } @@ -30,14 +32,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { var drawableSlider = (DrawableSlider)drawableObject; - scaleBindable = drawableSlider.ScaleBindable.GetBoundCopy(); - scaleBindable.BindValueChanged(scale => PathRadius = OsuHitObject.OBJECT_RADIUS * scale.NewValue, true); + ScaleBindable = drawableSlider.ScaleBindable.GetBoundCopy(); + ScaleBindable.BindValueChanged(scale => PathRadius = OsuHitObject.OBJECT_RADIUS * scale.NewValue, true); pathVersion = drawableSlider.PathVersion.GetBoundCopy(); pathVersion.BindValueChanged(_ => Refresh()); - accentColour = drawableObject.AccentColour.GetBoundCopy(); - accentColour.BindValueChanged(accent => AccentColour = GetBodyAccentColour(skin, accent.NewValue), true); + AccentColourBindable = drawableObject.AccentColour.GetBoundCopy(); + AccentColourBindable.BindValueChanged(accent => AccentColour = GetBodyAccentColour(skin, accent.NewValue), true); config?.BindWith(OsuRulesetSetting.SnakingInSliders, SnakingIn); config?.BindWith(OsuRulesetSetting.SnakingOutSliders, configSnakingOut); From ef6ea49b188b42aeb1771054356ed5bbbc9f4671 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 14:58:27 +0900 Subject: [PATCH 1221/2686] Add slider ball --- .../Skinning/Argon/ArgonSliderBall.cs | 55 +++++++++++++++++++ .../Skinning/Argon/OsuArgonSkinTransformer.cs | 6 ++ 2 files changed, 61 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs new file mode 100644 index 0000000000..5c31f079d4 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs @@ -0,0 +1,55 @@ +// 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.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonSliderBall : CircularContainer + { + private readonly Box fill; + private readonly SpriteIcon icon; + + public ArgonSliderBall() + { + Size = new Vector2(ArgonMainCirclePiece.OUTER_GRADIENT_SIZE); + + Masking = true; + + BorderThickness = ArgonMainCirclePiece.BORDER_THICKNESS * 2; + BorderColour = Color4.White; + + InternalChildren = new Drawable[] + { + fill = new Box + { + Colour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")), + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + icon = new SpriteIcon + { + Size = new Vector2(48), + Scale = new Vector2(0.6f, 0.8f), + Icon = FontAwesome.Solid.AngleRight, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + } + + protected override void Update() + { + base.Update(); + + fill.Rotation = -Rotation; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index d257271455..de55fd5743 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -33,6 +33,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon case OsuSkinComponents.SliderBody: return new ArgonSliderBody(); + + case OsuSkinComponents.SliderBall: + return new ArgonSliderBall(); + + case OsuSkinComponents.SliderScorePoint: + return new ArgonSliderScorePoint(); } break; From d4e2f70f877910d48e69349d2f2e7686cd57384b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 14:59:03 +0900 Subject: [PATCH 1222/2686] Add slider score point --- .../Skinning/Argon/ArgonSliderScorePoint.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs new file mode 100644 index 0000000000..1ab546b613 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Objects.Drawables; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonSliderScorePoint : CircularContainer + { + private Bindable accentColour = null!; + + private const float size = 12; + + [BackgroundDependencyLoader] + private void load(DrawableHitObject hitObject) + { + Masking = true; + Origin = Anchor.Centre; + Size = new Vector2(size); + BorderThickness = 3; + BorderColour = Color4.White; + Child = new Box + { + RelativeSizeAxes = Axes.Both, + AlwaysPresent = true, + Alpha = 0, + }; + + accentColour = hitObject.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(accent => BorderColour = accent.NewValue); + } + } +} From 3c0983b0dbc95ebcc4ea8d7717793cf50a78cbad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 15:39:08 +0900 Subject: [PATCH 1223/2686] Add slider reverse arrow --- .../Skinning/Argon/ArgonReverseArrow.cs | 54 +++++++++++++++++++ .../Skinning/Argon/OsuArgonSkinTransformer.cs | 3 ++ 2 files changed, 57 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs new file mode 100644 index 0000000000..3f13fe135e --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.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.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonReverseArrow : CompositeDrawable + { + private Bindable accentColour = null!; + + private SpriteIcon icon = null!; + + [BackgroundDependencyLoader] + private void load(DrawableHitObject hitObject) + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); + + InternalChildren = new Drawable[] + { + new Circle + { + Size = new Vector2(40, 20), + Colour = Color4.White, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + icon = new SpriteIcon + { + Icon = FontAwesome.Solid.AngleDoubleRight, + Size = new Vector2(16), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + }; + + accentColour = hitObject.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(accent => icon.Colour = accent.NewValue.Darken(4)); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index de55fd5743..dcd198c700 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -39,6 +39,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon case OsuSkinComponents.SliderScorePoint: return new ArgonSliderScorePoint(); + + case OsuSkinComponents.ReverseArrow: + return new ArgonReverseArrow(); } break; From 4f1530c2dbc8abbde9a3ab1813085b69c7aca996 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 16:07:13 +0900 Subject: [PATCH 1224/2686] Add slider follow circle --- .../Skinning/Argon/ArgonFollowCircle.cs | 71 +++++++++++++++++++ .../Skinning/Argon/OsuArgonSkinTransformer.cs | 3 + 2 files changed, 74 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs new file mode 100644 index 0000000000..83c5f6295a --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs @@ -0,0 +1,71 @@ +// 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.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonFollowCircle : FollowCircle + { + public ArgonFollowCircle() + { + InternalChild = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + BorderThickness = 4, + BorderColour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")), + Blending = BlendingParameters.Additive, + Child = new Box + { + Colour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")), + RelativeSizeAxes = Axes.Both, + Alpha = 0.3f, + } + }; + } + + protected override void OnSliderPress() + { + const float duration = 300f; + + if (Precision.AlmostEquals(0, Alpha)) + this.ScaleTo(1); + + this.ScaleTo(DrawableSliderBall.FOLLOW_AREA, duration, Easing.OutQuint) + .FadeIn(duration, Easing.OutQuint); + } + + protected override void OnSliderRelease() + { + const float duration = 150; + + this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.2f, duration, Easing.OutQuint) + .FadeTo(0, duration, Easing.OutQuint); + } + + protected override void OnSliderEnd() + { + const float duration = 300; + + this.ScaleTo(1, duration, Easing.OutQuint) + .FadeOut(duration / 2, Easing.OutQuint); + } + + protected override void OnSliderTick() + { + this.ScaleTo(DrawableSliderBall.FOLLOW_AREA * 1.08f, 40, Easing.OutQuint) + .Then() + .ScaleTo(DrawableSliderBall.FOLLOW_AREA, 200f, Easing.OutQuint); + } + + protected override void OnSliderBreak() + { + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index dcd198c700..6815124056 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -37,6 +37,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon case OsuSkinComponents.SliderBall: return new ArgonSliderBall(); + case OsuSkinComponents.SliderFollowCircle: + return new ArgonFollowCircle(); + case OsuSkinComponents.SliderScorePoint: return new ArgonSliderScorePoint(); From edc624c4beb63114772cc9e2de80c85bff91af16 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 16:07:16 +0900 Subject: [PATCH 1225/2686] Tweak slider ball fade to be less present after slider ends --- .../Skinning/Argon/ArgonSliderBall.cs | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs index 5c31f079d4..ae5c75549c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs @@ -1,11 +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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; using osuTK; using osuTK.Graphics; @@ -16,6 +19,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private readonly Box fill; private readonly SpriteIcon icon; + private readonly Vector2 defaultIconScale = new Vector2(0.6f, 0.8f); + + [Resolved(canBeNull: true)] + private DrawableHitObject? parentObject { get; set; } + public ArgonSliderBall() { Size = new Vector2(ArgonMainCirclePiece.OUTER_GRADIENT_SIZE); @@ -37,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon icon = new SpriteIcon { Size = new Vector2(48), - Scale = new Vector2(0.6f, 0.8f), + Scale = defaultIconScale, Icon = FontAwesome.Solid.AngleRight, Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -45,11 +53,57 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon }; } + protected override void LoadComplete() + { + base.LoadComplete(); + + if (parentObject != null) + { + parentObject.ApplyCustomUpdateState += updateStateTransforms; + updateStateTransforms(parentObject, parentObject.State.Value); + } + } + + private void updateStateTransforms(DrawableHitObject drawableObject, ArmedState _) + { + // Gets called by slider ticks, tails, etc., leading to duplicated + // animations which in this case have no visual impact (due to + // instant fade) but may negatively affect performance + if (drawableObject is not DrawableSlider) + return; + + const float duration = 200; + const float icon_scale = 0.9f; + + using (BeginAbsoluteSequence(drawableObject.StateUpdateTime)) + { + this.FadeInFromZero(duration, Easing.OutQuint); + icon.ScaleTo(0).Then().ScaleTo(defaultIconScale, duration, Easing.OutElasticHalf); + } + + using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) + { + this.FadeOut(duration, Easing.OutQuint); + icon.ScaleTo(defaultIconScale * icon_scale, duration, Easing.OutQuint); + } + } + protected override void Update() { base.Update(); - fill.Rotation = -Rotation; + //undo rotation on layers which should not be rotated. + float appliedRotation = Parent.Rotation; + + fill.Rotation = -appliedRotation; + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (parentObject != null) + parentObject.ApplyCustomUpdateState -= updateStateTransforms; } } } From 4eae5f87331ac25aa6a8e0b3ead84be786051157 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 16:14:35 +0900 Subject: [PATCH 1226/2686] Add back outer fill for hitcircles (but not slider head circles) --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 11 +++++++++-- .../Skinning/Argon/OsuArgonSkinTransformer.cs | 4 +++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index e4ed3d8fe8..9390c60977 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -27,6 +27,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon public const float OUTER_GRADIENT_SIZE = OsuHitObject.OBJECT_RADIUS * 2 - BORDER_THICKNESS * 3; + private readonly Circle outerFill; private readonly Circle outerGradient; private readonly Circle innerGradient; private readonly Circle innerFill; @@ -41,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon [Resolved] private DrawableHitObject drawableObject { get; set; } = null!; - public ArgonMainCirclePiece() + public ArgonMainCirclePiece(bool withOuterFill) { Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); @@ -52,6 +53,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon InternalChildren = new Drawable[] { + outerFill = new Circle // renders white outer border and dark fill + { + Size = Size, + Alpha = withOuterFill ? 1 : 0, + }, outerGradient = new Circle // renders the outer bright gradient { Size = new Vector2(OUTER_GRADIENT_SIZE), @@ -101,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon accentColour.BindValueChanged(colour => { - innerFill.Colour = colour.NewValue.Darken(4); + outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); flash.Colour = colour.NewValue; @@ -134,6 +140,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon // The fill layers add too much noise during the explosion animation. // They will be hidden by the additive effects anyway. + outerFill.FadeOut(flash_in_duration, Easing.OutQuint); innerFill.FadeOut(flash_in_duration, Easing.OutQuint); // The inner-most gradient should actually be resizing, but is only visible for diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 6815124056..8a1bf00877 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -28,8 +28,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon switch (osuComponent.Component) { case OsuSkinComponents.HitCircle: + return new ArgonMainCirclePiece(true); + case OsuSkinComponents.SliderHeadHitCircle: - return new ArgonMainCirclePiece(); + return new ArgonMainCirclePiece(false); case OsuSkinComponents.SliderBody: return new ArgonSliderBody(); From c8206b747b1488a65dc8d6b5f457a828648ced82 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 17:05:36 +0900 Subject: [PATCH 1227/2686] Fix border / slider body metrics --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 15 +++++++++------ .../Skinning/Argon/ArgonSliderBall.cs | 2 +- .../Skinning/Argon/ArgonSliderBody.cs | 14 ++++++++------ .../Skinning/Default/DrawableSliderPath.cs | 4 ++-- .../Skinning/Default/RingPiece.cs | 2 -- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 9390c60977..0479b3ff3e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -23,9 +23,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { public class ArgonMainCirclePiece : CompositeDrawable { - public const float BORDER_THICKNESS = 7; + public const float BORDER_THICKNESS = (OsuHitObject.OBJECT_RADIUS * 2) * (2f / 58); - public const float OUTER_GRADIENT_SIZE = OsuHitObject.OBJECT_RADIUS * 2 - BORDER_THICKNESS * 3; + public const float GRADIENT_THICKNESS = BORDER_THICKNESS * 2.5f; + + public const float OUTER_GRADIENT_SIZE = (OsuHitObject.OBJECT_RADIUS * 2) - BORDER_THICKNESS * 4; + + public const float INNER_GRADIENT_SIZE = OUTER_GRADIENT_SIZE - GRADIENT_THICKNESS * 2; + public const float INNER_FILL_SIZE = INNER_GRADIENT_SIZE - GRADIENT_THICKNESS * 2; private readonly Circle outerFill; private readonly Circle outerGradient; @@ -49,8 +54,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Anchor = Anchor.Centre; Origin = Anchor.Centre; - const float fill_thickness = 24; - InternalChildren = new Drawable[] { outerFill = new Circle // renders white outer border and dark fill @@ -67,14 +70,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon }, innerGradient = new Circle // renders the inner bright gradient { - Size = new Vector2(OUTER_GRADIENT_SIZE - fill_thickness), + Size = new Vector2(INNER_GRADIENT_SIZE), Alpha = 1, Anchor = Anchor.Centre, Origin = Anchor.Centre, }, innerFill = new Circle // renders the inner dark fill { - Size = new Vector2(OUTER_GRADIENT_SIZE - 2 * fill_thickness), + Size = new Vector2(INNER_FILL_SIZE), Alpha = 1, Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs index ae5c75549c..3df9edd225 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Masking = true; - BorderThickness = ArgonMainCirclePiece.BORDER_THICKNESS * 2; + BorderThickness = ArgonMainCirclePiece.GRADIENT_THICKNESS; BorderColour = Color4.White; InternalChildren = new Drawable[] diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs index 115e153f34..e1642d126d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs @@ -11,15 +11,17 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { protected override void LoadComplete() { + const float path_radius = ArgonMainCirclePiece.OUTER_GRADIENT_SIZE / 2; + base.LoadComplete(); - AccentColourBindable.BindValueChanged(accent => - { - BorderColour = accent.NewValue; - }, true); - ScaleBindable.BindValueChanged(scale => PathRadius = ArgonMainCirclePiece.OUTER_GRADIENT_SIZE / 2 * scale.NewValue, true); + AccentColourBindable.BindValueChanged(accent => BorderColour = accent.NewValue, true); + ScaleBindable.BindValueChanged(scale => PathRadius = path_radius * scale.NewValue, true); - BorderSize = ArgonMainCirclePiece.BORDER_THICKNESS / 4; + // This border size thing is kind of weird, hey. + const float intended_thickness = ArgonMainCirclePiece.GRADIENT_THICKNESS / path_radius; + + BorderSize = intended_thickness / Default.DrawableSliderPath.BORDER_PORTION; } protected override Default.DrawableSliderPath CreateSliderPath() => new DrawableSliderPath(); diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs index 94f93807d4..e3a83a9280 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs @@ -10,8 +10,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { public abstract class DrawableSliderPath : SmoothPath { - protected const float BORDER_PORTION = 0.128f; - protected const float GRADIENT_PORTION = 1 - BORDER_PORTION; + public const float BORDER_PORTION = 0.128f; + public const float GRADIENT_PORTION = 1 - BORDER_PORTION; private const float border_max_size = 8f; private const float border_min_size = 0f; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs index c14246e90e..e813a7e274 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.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. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; From 70d60a7e732d622f5e2068a6f43ce567b7c58a4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 17:18:14 +0900 Subject: [PATCH 1228/2686] Update import skin test in line with new default --- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index 3cbc205eaf..5c20f46787 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -202,7 +202,7 @@ namespace osu.Game.Tests.Skins.IO skinManager.CurrentSkinInfo.Value.PerformRead(s => { Assert.IsFalse(s.Protected); - Assert.AreEqual(typeof(TrianglesSkin), s.CreateInstance(skinManager).GetType()); + Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType()); new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream); @@ -215,7 +215,7 @@ namespace osu.Game.Tests.Skins.IO { Assert.IsFalse(s.Protected); Assert.AreNotEqual(originalSkinId, s.ID); - Assert.AreEqual(typeof(TrianglesSkin), s.CreateInstance(skinManager).GetType()); + Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType()); }); return Task.CompletedTask; From b55aa68177b925b27b2147ace222ec052fc77e1b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 22:46:55 +0900 Subject: [PATCH 1229/2686] Remove xmldoc on private fields --- osu.Game/Skinning/SkinManager.cs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 059767d8f8..0e66278fc0 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -39,6 +39,11 @@ namespace osu.Game.Skinning [ExcludeFromDynamicCompile] public class SkinManager : ModelManager, ISkinSource, IStorageResourceProvider, IModelImporter { + /// + /// The default "classic" skin. + /// + public Skin DefaultClassicSkin { get; } + private readonly AudioManager audio; private readonly Scheduler scheduler; @@ -55,21 +60,10 @@ namespace osu.Game.Skinning private readonly IResourceStore userFiles; - /// - /// The default "triangles" skin. - /// private Skin argonSkin { get; } - /// - /// The default skin (old). - /// private Skin trianglesSkin { get; } - /// - /// The default "classic" skin. - /// - public Skin DefaultClassicSkin { get; } - public SkinManager(Storage storage, RealmAccess realm, GameHost host, IResourceStore resources, AudioManager audio, Scheduler scheduler) : base(storage, realm) { From 03cc6b8af3ef954b46c9ba467bc60e4c8a9c4785 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Sep 2022 23:44:03 +0900 Subject: [PATCH 1230/2686] Fix parameter name --- osu.Game/Localisation/GeneralSettingsStrings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index 8506971756..3278b20983 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -67,7 +67,7 @@ namespace osu.Game.Localisation /// /// "You are running the latest release ({0})" /// - public static LocalisableString RunningLatestRelease(string arg0) => new TranslatableString(getKey(@"running_latest_release"), @"You are running the latest release ({0})", arg0); + public static LocalisableString RunningLatestRelease(string version) => new TranslatableString(getKey(@"running_latest_release"), @"You are running the latest release ({0})", version); private static string getKey(string key) => $"{prefix}:{key}"; } From 46db3ad96d0e1cd6ba4176b9b474cb79a338965d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Sep 2022 00:06:02 +0900 Subject: [PATCH 1231/2686] Move implementation to individual classes --- osu.Game/Screens/Play/Player.cs | 26 ++++++++++++----------- osu.Game/Screens/Play/ReplayPlayer.cs | 10 +++++++++ osu.Game/Screens/Play/SoloPlayer.cs | 10 +++++++++ osu.Game/Screens/Select/PlaySongSelect.cs | 17 ++++++++++----- 4 files changed, 46 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e1530d7ea2..e31e18046e 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -832,23 +833,24 @@ namespace osu.Game.Screens.Play HUDOverlay.HoldingForHUD.BindValueChanged(_ => updateLeaderboardExpandedState()); LocalUserPlaying.BindValueChanged(_ => updateLeaderboardExpandedState(), true); - LoadComponentAsync(CreateGameplayLeaderboard(), leaderboard => + var gameplayLeaderboard = CreateGameplayLeaderboard(); + + if (gameplayLeaderboard != null) { - if (!LoadedBeatmapSuccessfully) - return; + LoadComponentAsync(gameplayLeaderboard, leaderboard => + { + if (!LoadedBeatmapSuccessfully) + return; - leaderboard.Expanded.BindTo(LeaderboardExpandedState); + leaderboard.Expanded.BindTo(LeaderboardExpandedState); - AddLeaderboardToHUD(leaderboard); - }); + AddLeaderboardToHUD(leaderboard); + }); + } } - public readonly BindableList LeaderboardScores = new BindableList(); - - protected virtual GameplayLeaderboard CreateGameplayLeaderboard() => new SoloGameplayLeaderboard(Score.ScoreInfo.User) - { - Scores = { BindTarget = LeaderboardScores } - }; + [CanBeNull] + protected virtual GameplayLeaderboard CreateGameplayLeaderboard() => null; protected virtual void AddLeaderboardToHUD(GameplayLeaderboard leaderboard) => HUDOverlay.LeaderboardFlow.Add(leaderboard); diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index e82238945b..163b9c593f 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using osu.Framework.Bindables; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Beatmaps; @@ -14,6 +15,7 @@ using osu.Game.Input.Bindings; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Scoring; +using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Play @@ -55,6 +57,14 @@ namespace osu.Game.Screens.Play // Don't re-import replay scores as they're already present in the database. protected override Task ImportScore(Score score) => Task.CompletedTask; + public readonly BindableList LeaderboardScores = new BindableList(); + + protected override GameplayLeaderboard CreateGameplayLeaderboard() => + new SoloGameplayLeaderboard(Score.ScoreInfo.User) + { + Scores = { BindTarget = LeaderboardScores } + }; + protected override ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, false); public bool OnPressed(KeyBindingPressEvent e) diff --git a/osu.Game/Screens/Play/SoloPlayer.cs b/osu.Game/Screens/Play/SoloPlayer.cs index 565f256277..a36697c96e 100644 --- a/osu.Game/Screens/Play/SoloPlayer.cs +++ b/osu.Game/Screens/Play/SoloPlayer.cs @@ -5,12 +5,14 @@ using System; using System.Diagnostics; +using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Extensions; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Online.Solo; using osu.Game.Scoring; +using osu.Game.Screens.Play.HUD; namespace osu.Game.Screens.Play { @@ -40,6 +42,14 @@ namespace osu.Game.Screens.Play return new CreateSoloScoreRequest(Beatmap.Value.BeatmapInfo, rulesetId, Game.VersionHash); } + public readonly BindableList LeaderboardScores = new BindableList(); + + protected override GameplayLeaderboard CreateGameplayLeaderboard() => + new SoloGameplayLeaderboard(Score.ScoreInfo.User) + { + Scores = { BindTarget = LeaderboardScores } + }; + protected override bool HandleTokenRetrievalFailure(Exception exception) => false; protected override APIRequest CreateSubmissionRequest(Score score, long token) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 068f78172b..94e4215175 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Screens; @@ -115,11 +114,19 @@ namespace osu.Game.Screens.Select var replayGeneratingMod = Mods.Value.OfType().FirstOrDefault(); if (replayGeneratingMod != null) - player = new ReplayPlayer((beatmap, mods) => replayGeneratingMod.CreateScoreFromReplayData(beatmap, mods)); + { + player = new ReplayPlayer((beatmap, mods) => replayGeneratingMod.CreateScoreFromReplayData(beatmap, mods)) + { + LeaderboardScores = { BindTarget = playBeatmapDetailArea.Leaderboard.Scores } + }; + } else - player = new SoloPlayer(); - - ((IBindableList)player.LeaderboardScores).BindTo(playBeatmapDetailArea.Leaderboard.Scores); + { + player = new SoloPlayer + { + LeaderboardScores = { BindTarget = playBeatmapDetailArea.Leaderboard.Scores } + }; + } return player; } From 1c02fa839965ce673f823c4dc2e3def7caa2d181 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Sep 2022 00:08:06 +0900 Subject: [PATCH 1232/2686] Update comment to not mention horizontal plane --- osu.Game/Screens/Play/HUDOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 3e661e76f4..3fbb051c3b 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -197,7 +197,7 @@ namespace osu.Game.Screens.Play // LINQ cast can be removed when IDrawable interface includes Anchor / RelativeSizeAxes. foreach (var element in mainComponents.Components.Cast()) { - // for now align top-right components with the bottom-edge of the lowest top-anchored hud element. + // for now align some top components with the bottom-edge of the lowest top-anchored hud element. if (element.Anchor.HasFlagFast(Anchor.y0)) { // health bars are excluded for the sake of hacky legacy skins which extend the health bar to take up the full screen area. From 18fe37bb222c6a296a866da22ee569be46d36ea4 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Mon, 19 Sep 2022 17:25:35 +0200 Subject: [PATCH 1233/2686] Reverted changes --- osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 11fa751daf..956d0e0c14 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -108,14 +108,14 @@ namespace osu.Game.Rulesets.Catch.Tests float halfWidth = Catcher.CalculateCatchWidth(new BeatmapDifficulty { CircleSize = 0 }) / 2; AddStep("catch fruit", () => { - attemptCatch(new Fruit { OriginalX = -halfWidth + 1 }); - attemptCatch(new Fruit { OriginalX = halfWidth - 1 }); + attemptCatch(new Fruit { X = -halfWidth + 1 }); + attemptCatch(new Fruit { X = halfWidth - 1 }); }); checkPlate(2); AddStep("miss fruit", () => { - attemptCatch(new Fruit { OriginalX = -halfWidth - 1 }); - attemptCatch(new Fruit { OriginalX = halfWidth + 1 }); + attemptCatch(new Fruit { X = -halfWidth - 1 }); + attemptCatch(new Fruit { X = halfWidth + 1 }); }); checkPlate(2); } From 4958421303567ec8817cc340ae78102ae2602ec8 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Mon, 19 Sep 2022 17:26:04 +0200 Subject: [PATCH 1234/2686] Moved X clamping from X to EffectiveX --- osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs index c6d63f6b81..cd2b8348e2 100644 --- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Catch.Objects [JsonIgnore] public float X { - set => originalX.Value = Math.Clamp(value, 0, CatchPlayfield.WIDTH); + set => originalX.Value = value; } private HitObjectProperty xOffset; @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Catch.Objects /// This value is the original value plus the offset applied by the beatmap processing. /// Use if a value not affected by the offset is desired. /// - public float EffectiveX => OriginalX + XOffset; + public float EffectiveX => Math.Clamp(OriginalX + XOffset, 0, CatchPlayfield.WIDTH); public double TimePreempt { get; set; } = 1000; From 74056201e7903fd572bd1a4a9f580cd74db2c78a Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 19 Sep 2022 09:15:59 -0700 Subject: [PATCH 1235/2686] Return smoke key to key overlay --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 14 -------------- osu.Game/Rulesets/UI/RulesetInputManager.cs | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 6500ade7ea..9332aa679a 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -57,20 +57,6 @@ namespace osu.Game.Rulesets.Osu return base.HandleMouseTouchStateChange(e); } - public override void Attach(KeyCounterDisplay keyCounter) - { - var receptor = new ActionReceptor(keyCounter); - - KeyBindingContainer.Add(receptor); - - keyCounter.SetReceptor(receptor); - keyCounter.AddRange(new[] - { - new KeyCounterAction(OsuAction.LeftButton), - new KeyCounterAction(OsuAction.RightButton), - }); - } - private class OsuKeyBindingContainer : RulesetKeyBindingContainer { public bool AllowUserPresses = true; diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index ce87d8b6c0..1a97153f2f 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -155,7 +155,7 @@ namespace osu.Game.Rulesets.UI #region Key Counter Attachment - public virtual void Attach(KeyCounterDisplay keyCounter) + public void Attach(KeyCounterDisplay keyCounter) { var receptor = new ActionReceptor(keyCounter); From c3b8e1d718a8e5c3bc259a752d39aa632a2359dc Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 19 Sep 2022 10:16:05 -0700 Subject: [PATCH 1236/2686] Fix test and spawn smoke immediately --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 1 - osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 14 +++++++++----- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 4 ++++ .../Visual/Gameplay/TestSceneGameplayRewinding.cs | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 9332aa679a..dec965e567 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -10,7 +10,6 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Input.StateChanges.Events; using osu.Game.Rulesets.UI; -using osu.Game.Screens.Play; namespace osu.Game.Rulesets.Osu { diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index bada67816b..7359f6029e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -166,17 +166,21 @@ namespace osu.Game.Rulesets.Osu.Skinning { base.LoadComplete(); + Anchor = Anchor.TopLeft; + Origin = Anchor.TopLeft; + + SmokeStartTime = Time.Current; + + totalDistance = PointInterval; + if (smokeContainer != null) { smokeContainer.SmokeMoved += onSmokeMoved; smokeContainer.SmokeEnded += onSmokeEnded; IsActive = true; + + onSmokeMoved(smokeContainer.LastMousePosition, Time.Current); } - - Anchor = Anchor.TopLeft; - Origin = Anchor.TopLeft; - - SmokeStartTime = Time.Current; } private Vector2 nextPointDirection() diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index 07a073c3e5..2b5bddf959 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -19,6 +19,8 @@ namespace osu.Game.Rulesets.Osu.UI public event Action? SmokeMoved; public event Action? SmokeEnded; + public Vector2 LastMousePosition; + private bool isSmoking; public override bool ReceivePositionalInputAt(Vector2 _) => true; @@ -50,6 +52,8 @@ namespace osu.Game.Rulesets.Osu.UI if (isSmoking) SmokeMoved?.Invoke(e.MousePosition, Time.Current); + LastMousePosition = e.MousePosition; + return base.OnMouseMove(e); } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs index 0a32513834..bd55ed8bd6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning); addSeekStep(3000); AddAssert("all judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged)); - AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7)); + AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Select(kc => kc.CountPresses).Sum() == 15); AddStep("clear results", () => Player.Results.Clear()); addSeekStep(0); AddAssert("none judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged)); From b0a3c9152a413a7467aceb9c0a2634e5dcc7f902 Mon Sep 17 00:00:00 2001 From: B3nn1 Date: Mon, 19 Sep 2022 21:33:38 +0200 Subject: [PATCH 1237/2686] Enable snapping for slider control points in the editor --- .../Sliders/Components/PathControlPointVisualiser.cs | 9 ++++++++- .../Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs | 3 ++- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 5 ++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index c24f78e430..9de62d1a46 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -307,7 +307,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { var controlPoint = controlPoints[i]; if (selectedControlPoints.Contains(controlPoint)) - controlPoint.Position = dragStartPositions[i] + (e.MousePosition - e.MouseDownPosition); + { + Vector2 newPosition = Parent.ToScreenSpace(e.MousePosition + (dragStartPositions[0] - dragStartPositions[draggedControlPointIndex])); + var result = snapProvider?.FindSnappedPositionAndTime(newPosition); + + Vector2 movementDelta = Parent.ToLocalSpace(result?.ScreenSpacePosition ?? newPosition) - slider.Position; + + controlPoint.Position = dragStartPositions[i] + movementDelta; + } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index e2f98c273e..dd5335a743 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -198,7 +198,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders } // Update the cursor position. - cursor.Position = ToLocalSpace(inputManager.CurrentState.Mouse.Position) - HitObject.Position; + var result = snapProvider?.FindSnappedPositionAndTime(inputManager.CurrentState.Mouse.Position); + cursor.Position = ToLocalSpace(result?.ScreenSpacePosition ?? inputManager.CurrentState.Mouse.Position) - HitObject.Position; } else if (cursor != null) { diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index eb69efd636..5673dab7e8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -163,7 +163,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders protected override void OnDrag(DragEvent e) { if (placementControlPoint != null) - placementControlPoint.Position = e.MousePosition - HitObject.Position; + { + var result = snapProvider?.FindSnappedPositionAndTime(ToScreenSpace(e.MousePosition)); + placementControlPoint.Position = ToLocalSpace(result?.ScreenSpacePosition ?? e.MousePosition) - HitObject.Position; + } } protected override void OnMouseUp(MouseUpEvent e) From a9c120c2145ecba824d511dcc94bca3367f05640 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Sep 2022 12:46:35 +0900 Subject: [PATCH 1238/2686] Reduce volume requirement for showing muted notification to 1% --- osu.Game/Screens/Play/PlayerLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 6373633b5a..1491567cab 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -502,7 +502,7 @@ namespace osu.Game.Screens.Play private int restartCount; - private const double volume_requirement = 0.05; + private const double volume_requirement = 0.01; private void showMuteWarningIfNeeded() { From b5771ece41ca51db56c6fd57ca63c4d7e2282fa6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Sep 2022 12:52:04 +0900 Subject: [PATCH 1239/2686] Reduce the amount by which clicking the mute notification incraeses volume --- osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs | 4 ++-- osu.Game/Screens/Play/PlayerLoader.cs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 1d101383cc..6b24ac7384 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -264,13 +264,13 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestMutedNotificationMasterVolume() { - addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, () => audioManager.Volume.IsDefault); + addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, () => audioManager.Volume.Value == 0.5); } [Test] public void TestMutedNotificationTrackVolume() { - addVolumeSteps("music volume", () => audioManager.VolumeTrack.Value = 0, () => audioManager.VolumeTrack.IsDefault); + addVolumeSteps("music volume", () => audioManager.VolumeTrack.Value = 0, () => audioManager.VolumeTrack.Value == 0.5); } [Test] diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 1491567cab..e32d3d90be 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -539,10 +539,11 @@ namespace osu.Game.Screens.Play volumeOverlay.IsMuted.Value = false; // Check values before resetting, as the user may have only had mute enabled, in which case we might not need to adjust volumes. + // Note that we only restore halfway to ensure the user isn't suddenly overloaded by unexpectedly high volume. if (audioManager.Volume.Value <= volume_requirement) - audioManager.Volume.SetDefault(); + audioManager.Volume.Value = 0.5f; if (audioManager.VolumeTrack.Value <= volume_requirement) - audioManager.VolumeTrack.SetDefault(); + audioManager.VolumeTrack.Value = 0.5f; return true; }; From d22d009fb33a97df29dc1b9759c3c625a95259c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=A2=E3=82=BA=E3=82=BF=E3=82=B1?= Date: Tue, 20 Sep 2022 14:02:11 +0900 Subject: [PATCH 1240/2686] fix review points. items not included in this localization were reverted. --- .../MaintenanceSettingsStrings.cs | 30 ------------------- .../MassDeleteConfirmationDialog.cs | 3 +- .../MassVideoDeleteConfirmationDialog.cs | 3 +- .../StableDirectoryLocationDialog.cs | 9 +++--- .../StableDirectorySelectScreen.cs | 3 +- 5 files changed, 7 insertions(+), 41 deletions(-) diff --git a/osu.Game/Localisation/MaintenanceSettingsStrings.cs b/osu.Game/Localisation/MaintenanceSettingsStrings.cs index 4648682e64..8aa0adf7a0 100644 --- a/osu.Game/Localisation/MaintenanceSettingsStrings.cs +++ b/osu.Game/Localisation/MaintenanceSettingsStrings.cs @@ -134,36 +134,6 @@ namespace osu.Game.Localisation /// public static LocalisableString RestoredAllDeletedModPresets => new TranslatableString(getKey(@"restored_all_deleted_mod_presets"), @"Restored all deleted mod presets!"); - /// - /// "Everything?" - /// - public static LocalisableString MassDeleteConfirmation => new TranslatableString(getKey(@"mass_delete_confirmation"), @"Everything?"); - - /// - /// "All beatmap videos? This cannot be undone!" - /// - public static LocalisableString MassVideoDeleteConfirmation => new TranslatableString(getKey(@"mass_video_delete_confirmation"), @"All beatmap videos? This cannot be undone!"); - - /// - /// "Failed to automatically locate an osu!stable installation." - /// - public static LocalisableString StableDirectoryLocationHeader => new TranslatableString(getKey(@"stable_directory_location_header"), @"Failed to automatically locate an osu!stable installation."); - - /// - /// "An existing install could not be located. If you know where it is, you can help locate it." - /// - public static LocalisableString StableDirectoryLocationBody => new TranslatableString(getKey(@"stable_directory_location_body"), @"An existing install could not be located. If you know where it is, you can help locate it."); - - /// - /// "Sure! I know where it is located!" - /// - public static LocalisableString StableDirectoryLocationOk => new TranslatableString(getKey(@"stable_directory_location_ok"), @"Sure! I know where it is located!"); - - /// - /// "Actually I don't have osu!stable installed." - /// - public static LocalisableString StableDirectoryLocationCancel => new TranslatableString(getKey(@"stable_directory_location_cancel"), @"Actually I don't have osu!stable installed."); - /// /// "Please select your osu!stable install location" /// diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs index bcfccaa5e2..19e6f83dac 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Game.Localisation; using osu.Game.Overlays.Dialog; namespace osu.Game.Overlays.Settings.Sections.Maintenance @@ -11,7 +10,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public MassDeleteConfirmationDialog(Action deleteAction) { - BodyText = MaintenanceSettingsStrings.MassDeleteConfirmation; + BodyText = "Everything?"; DeleteAction = deleteAction; } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs index a386c64806..fc8c9d497b 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Maintenance { @@ -11,7 +10,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance public MassVideoDeleteConfirmationDialog(Action deleteAction) : base(deleteAction) { - BodyText = MaintenanceSettingsStrings.MassVideoDeleteConfirmation; + BodyText = "All beatmap videos? This cannot be undone!"; } } } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs index 7b7ea7cee0..8aff4520b5 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; using osu.Framework.Screens; -using osu.Game.Localisation; using osu.Game.Overlays.Dialog; using osu.Game.Screens; @@ -20,20 +19,20 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance public StableDirectoryLocationDialog(TaskCompletionSource taskCompletionSource) { - HeaderText = MaintenanceSettingsStrings.StableDirectoryLocationHeader; - BodyText = MaintenanceSettingsStrings.StableDirectoryLocationBody; + HeaderText = "Failed to automatically locate an osu!stable installation."; + BodyText = "An existing install could not be located. If you know where it is, you can help locate it."; Icon = FontAwesome.Solid.QuestionCircle; Buttons = new PopupDialogButton[] { new PopupDialogOkButton { - Text = MaintenanceSettingsStrings.StableDirectoryLocationOk, + Text = "Sure! I know where it is located!", Action = () => Schedule(() => performer.PerformFromScreen(screen => screen.Push(new StableDirectorySelectScreen(taskCompletionSource)))) }, new PopupDialogCancelButton { - Text = MaintenanceSettingsStrings.StableDirectoryLocationCancel, + Text = "Actually I don't have osu!stable installed.", Action = () => taskCompletionSource.TrySetCanceled() } }; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs index 22cf2e7076..047d589689 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Localisation; using osu.Framework.Screens; -using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Maintenance { @@ -20,7 +19,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance protected override bool IsValidDirectory(DirectoryInfo info) => info?.GetFiles("osu!.*.cfg").Any() ?? false; - public override LocalisableString HeaderText => MaintenanceSettingsStrings.StableDirectorySelectHeader; + public override LocalisableString HeaderText => "Please select your osu!stable install location"; public StableDirectorySelectScreen(TaskCompletionSource taskCompletionSource) { From 700000b583d4beb19b537a5e25d17c38fb54d64f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 15:51:56 +0900 Subject: [PATCH 1241/2686] Use custom notification with timer --- .../Online/Multiplayer/MultiplayerClient.cs | 7 +-- .../Multiplayer/ServerShutdownNotification.cs | 49 +++++++++++++++++++ osu.Game/Utils/HumanizerUtils.cs | 23 +++++++++ 3 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Online/Multiplayer/ServerShutdownNotification.cs diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index f9236cbfac..75334952f0 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -589,12 +589,7 @@ namespace osu.Game.Online.Multiplayer if (countdown == null) return; - PostNotification?.Invoke(new SimpleNotification - { - Text = countdown.FinalNotification - ? $"The multiplayer server is restarting in {countdown.TimeRemaining:hh\\:mm\\:ss}. This multiplayer room will be closed shortly." - : $"The multiplayer server is restarting in {countdown.TimeRemaining:hh\\:mm\\:ss}." - }); + PostNotification?.Invoke(new ServerShutdownNotification(countdown.TimeRemaining)); } Task IMultiplayerClient.UserBeatmapAvailabilityChanged(int userId, BeatmapAvailability beatmapAvailability) diff --git a/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs b/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs new file mode 100644 index 0000000000..dc61fe4ce5 --- /dev/null +++ b/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs @@ -0,0 +1,49 @@ +// 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 Humanizer.Localisation; +using osu.Framework.Allocation; +using osu.Game.Overlays.Notifications; +using osu.Game.Utils; + +namespace osu.Game.Online.Multiplayer +{ + public class ServerShutdownNotification : SimpleNotification + { + private readonly DateTimeOffset endDate; + + public ServerShutdownNotification(TimeSpan duration) + { + endDate = DateTimeOffset.UtcNow + duration; + } + + [BackgroundDependencyLoader] + private void load() + { + updateTime(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + Scheduler.Add(updateTimeWithReschedule); + } + + private void updateTimeWithReschedule() + { + updateTime(); + + // The remaining time on a countdown may be at a fractional portion between two seconds. + // We want to align certain audio/visual cues to the point at which integer seconds change. + // To do so, we schedule to the next whole second. Note that scheduler invocation isn't + // guaranteed to be accurate, so this may still occur slightly late, but even in such a case + // the next invocation will be roughly correct. + double timeToNextSecond = endDate.Subtract(DateTimeOffset.UtcNow).TotalMilliseconds % 1000; + + Scheduler.AddDelayed(updateTimeWithReschedule, timeToNextSecond); + } + + private void updateTime() => Text = $"The multiplayer server is restarting in {HumanizerUtils.Humanize(endDate.Subtract(DateTimeOffset.Now), precision: 2, minUnit: TimeUnit.Second)}."; + } +} diff --git a/osu.Game/Utils/HumanizerUtils.cs b/osu.Game/Utils/HumanizerUtils.cs index 5b7c3630d9..0da346ed73 100644 --- a/osu.Game/Utils/HumanizerUtils.cs +++ b/osu.Game/Utils/HumanizerUtils.cs @@ -4,6 +4,7 @@ using System; using System.Globalization; using Humanizer; +using Humanizer.Localisation; namespace osu.Game.Utils { @@ -26,5 +27,27 @@ namespace osu.Game.Utils return input.Humanize(culture: new CultureInfo("en-US")); } } + + /// + /// Turns the current or provided timespan into a human readable sentence + /// + /// The date to be humanized + /// The maximum number of time units to return. Defaulted is 1 which means the largest unit is returned + /// The maximum unit of time to output. The default value is . The time units and will give approximations for time spans bigger 30 days by calculating with 365.2425 days a year and 30.4369 days a month. + /// The minimum unit of time to output. + /// Uses words instead of numbers if true. E.g. one day. + /// distance of time in words + public static string Humanize(TimeSpan input, int precision = 1, TimeUnit maxUnit = TimeUnit.Week, TimeUnit minUnit = TimeUnit.Millisecond, bool toWords = false) + { + // this works around https://github.com/xamarin/xamarin-android/issues/2012 and https://github.com/Humanizr/Humanizer/issues/690#issuecomment-368536282 + try + { + return input.Humanize(precision: precision, maxUnit: maxUnit, minUnit: minUnit); + } + catch (ArgumentException) + { + return input.Humanize(culture: new CultureInfo("en-US"), precision: precision, maxUnit: maxUnit, minUnit: minUnit); + } + } } } From ef29987f362bc51c39b43af4f4d6d4ca7f721652 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 15:52:20 +0900 Subject: [PATCH 1242/2686] Remove FinalNotification --- osu.Game/Online/Multiplayer/ServerShuttingDownCountdown.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game/Online/Multiplayer/ServerShuttingDownCountdown.cs b/osu.Game/Online/Multiplayer/ServerShuttingDownCountdown.cs index 4def3acc5e..b0a45dc768 100644 --- a/osu.Game/Online/Multiplayer/ServerShuttingDownCountdown.cs +++ b/osu.Game/Online/Multiplayer/ServerShuttingDownCountdown.cs @@ -11,10 +11,5 @@ namespace osu.Game.Online.Multiplayer [MessagePackObject] public class ServerShuttingDownCountdown : MultiplayerCountdown { - /// - /// If this is the final notification, no more events will be sent after this. - /// - [Key(2)] - public bool FinalNotification { get; set; } } } From b84f716c22f192ae67907232715c7ae3d87ae67b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 16:02:28 +0900 Subject: [PATCH 1243/2686] Display seconds when hours>0 to be more lively --- osu.Game/Online/Multiplayer/ServerShutdownNotification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs b/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs index dc61fe4ce5..7241341bc9 100644 --- a/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs +++ b/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs @@ -44,6 +44,6 @@ namespace osu.Game.Online.Multiplayer Scheduler.AddDelayed(updateTimeWithReschedule, timeToNextSecond); } - private void updateTime() => Text = $"The multiplayer server is restarting in {HumanizerUtils.Humanize(endDate.Subtract(DateTimeOffset.Now), precision: 2, minUnit: TimeUnit.Second)}."; + private void updateTime() => Text = $"The multiplayer server is restarting in {HumanizerUtils.Humanize(endDate.Subtract(DateTimeOffset.Now), precision: 3, minUnit: TimeUnit.Second)}."; } } From 68c040175a4f026ca450f07fa060f9b86d16c962 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Sep 2022 17:01:44 +0900 Subject: [PATCH 1244/2686] Ensure `Leaderboard.Scores` is updated immediately via request flow --- osu.Game/Online/Leaderboards/Leaderboard.cs | 22 +++++++++++++------ .../Select/Leaderboards/BeatmapLeaderboard.cs | 13 +++++------ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 9b6e9fbec7..d5834c4329 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -185,14 +185,22 @@ namespace osu.Game.Online.Leaderboards if (scores != null) this.scores.AddRange(scores); - userScoreContainer.Score.Value = userScore; + // Schedule needs to be non-delayed here for the weird logic in refetchScores to work. + // If it is removed, the placeholder will be incorrectly updated to "no scores" rather than "retrieving". + // This whole flow should be refactored in the future. + Scheduler.Add(applyNewScores, false); - if (userScore == null) - userScoreContainer.Hide(); - else - userScoreContainer.Show(); + void applyNewScores() + { + userScoreContainer.Score.Value = userScore; - Scheduler.Add(updateScoresDrawables, false); + if (userScore == null) + userScoreContainer.Hide(); + else + userScoreContainer.Show(); + + updateScoresDrawables(); + } } /// @@ -212,8 +220,8 @@ namespace osu.Game.Online.Leaderboards Debug.Assert(ThreadSafety.IsUpdateThread); cancelPendingWork(); - SetScores(null); + SetScores(null); setState(LeaderboardState.Retrieving); currentFetchCancellationSource = new CancellationTokenSource(); diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index ed4da5e848..798cf29715 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -148,13 +148,10 @@ namespace osu.Game.Screens.Select.Leaderboards var req = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods); - req.Success += r => Schedule(() => - { - SetScores( - scoreManager.OrderByTotalScore(r.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))), - r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo) - ); - }); + req.Success += r => SetScores( + scoreManager.OrderByTotalScore(r.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))), + r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo) + ); return req; } @@ -209,7 +206,7 @@ namespace osu.Game.Screens.Select.Leaderboards scores = scoreManager.OrderByTotalScore(scores.Detach()); - Schedule(() => SetScores(scores)); + SetScores(scores); } } From e0f1f1a5e1fe26fa17402a57a8d432b7230e608c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Sep 2022 17:20:47 +0900 Subject: [PATCH 1245/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 77c29a5d6e..4f69d27df6 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 29e690a024..3c24250300 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 83410b08f6..b57256dec9 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + From 90a05f4bed05cb3ed017e9fc3c92d04daddd816b Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 20 Sep 2022 01:40:20 -0700 Subject: [PATCH 1246/2686] Cap smoke on point count + omit invisible vertices --- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 7359f6029e..70913b0851 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Skinning private float totalDistance; private Vector2? lastPosition; - private const double max_duration = 60_000; + private const int max_point_count = 72_000; public override float Height { @@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Osu.Skinning lastPosition = position; - if (time - SmokeStartTime > max_duration) + if (SmokePoints.Count >= max_point_count) onSmokeEnded(time); } @@ -360,7 +360,7 @@ namespace osu.Game.Rulesets.Osu.Skinning if (Points.Count == 0) return; - QuadBatch ??= renderer.CreateQuadBatch(7200, 10); + QuadBatch ??= renderer.CreateQuadBatch(max_point_count / 10, 10); Texture ??= renderer.WhitePixel; var shader = GetAppropriateShader(renderer); @@ -410,6 +410,9 @@ namespace osu.Game.Rulesets.Osu.Skinning var dir = PointDirection(point); var ortho = dir.PerpendicularLeft; + if (color.A == 0 || scale == 0) + return; + var localTopLeft = point.Position + (Radius * scale * (-ortho - dir)) - PositionOffset; var localTopRight = point.Position + (Radius * scale * (-ortho + dir)) - PositionOffset; var localBotLeft = point.Position + (Radius * scale * (ortho - dir)) - PositionOffset; From fc6ab9c6a96b7a7892e77ae8449eb7edc372375e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Sep 2022 17:42:39 +0900 Subject: [PATCH 1247/2686] Add test coverage of shutdown notifications --- .../UserInterface/TestSceneNotificationOverlay.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index e978b57ba4..4f980dc74f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.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 System.Linq; using NUnit.Framework; @@ -10,6 +11,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Graphics.Sprites; +using osu.Game.Online.Multiplayer; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osu.Game.Updater; @@ -422,6 +424,14 @@ namespace osu.Game.Tests.Visual.UserInterface AddRepeatStep("send barrage", sendBarrage, 10); } + [Test] + public void TestServerShuttingDownNotification() + { + AddStep("post with 5 seconds", () => notificationOverlay.Post(new ServerShutdownNotification(TimeSpan.FromSeconds(5)))); + AddStep("post with 30 seconds", () => notificationOverlay.Post(new ServerShutdownNotification(TimeSpan.FromSeconds(30)))); + AddStep("post with 6 hours", () => notificationOverlay.Post(new ServerShutdownNotification(TimeSpan.FromHours(6)))); + } + protected override void Update() { base.Update(); From 979f7f88a17d248d4db249e3caf99c3885d23001 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Tue, 20 Sep 2022 12:41:06 +0200 Subject: [PATCH 1248/2686] Fixed TestCatcherWidth and added TestFruitClampedToCatchableRegion --- .../TestSceneCatcher.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 956d0e0c14..732184a8a8 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -106,20 +106,32 @@ namespace osu.Game.Rulesets.Catch.Tests public void TestCatcherCatchWidth() { float halfWidth = Catcher.CalculateCatchWidth(new BeatmapDifficulty { CircleSize = 0 }) / 2; + const float center_x = CatchPlayfield.CENTER_X; + AddStep("move catcher to center", () => catcher.X = center_x); AddStep("catch fruit", () => { - attemptCatch(new Fruit { X = -halfWidth + 1 }); - attemptCatch(new Fruit { X = halfWidth - 1 }); + attemptCatch(new Fruit { X = center_x + -halfWidth + 1 }); + attemptCatch(new Fruit { X = center_x + halfWidth - 1 }); }); checkPlate(2); AddStep("miss fruit", () => { - attemptCatch(new Fruit { X = -halfWidth - 1 }); - attemptCatch(new Fruit { X = halfWidth + 1 }); + attemptCatch(new Fruit { X = center_x + -halfWidth - 1 }); + attemptCatch(new Fruit { X = center_x + halfWidth + 1 }); }); checkPlate(2); } + [Test] + public void TestFruitClampedToCatchableRegion() + { + AddStep("catch fruit left", () => attemptCatch(new Fruit { X = -CatchPlayfield.WIDTH })); + checkPlate(1); + AddStep("move catcher to right", () => catcher.X = CatchPlayfield.WIDTH); + AddStep("catch fruit right", () => attemptCatch(new Fruit { X = CatchPlayfield.WIDTH * 2 })); + checkPlate(2); + } + [Test] public void TestFruitChangesCatcherState() { From d777afc4542820c6df82e558536a9b8e16d6058b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 19:53:39 +0900 Subject: [PATCH 1249/2686] Remove countdown at under 5 seconds --- .../Multiplayer/ServerShutdownNotification.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs b/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs index 7241341bc9..c114741be8 100644 --- a/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs +++ b/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs @@ -4,6 +4,7 @@ using System; using Humanizer.Localisation; using osu.Framework.Allocation; +using osu.Framework.Threading; using osu.Game.Overlays.Notifications; using osu.Game.Utils; @@ -12,6 +13,7 @@ namespace osu.Game.Online.Multiplayer public class ServerShutdownNotification : SimpleNotification { private readonly DateTimeOffset endDate; + private ScheduledDelegate? updateDelegate; public ServerShutdownNotification(TimeSpan duration) { @@ -27,7 +29,7 @@ namespace osu.Game.Online.Multiplayer protected override void LoadComplete() { base.LoadComplete(); - Scheduler.Add(updateTimeWithReschedule); + updateDelegate = Scheduler.Add(updateTimeWithReschedule); } private void updateTimeWithReschedule() @@ -41,9 +43,20 @@ namespace osu.Game.Online.Multiplayer // the next invocation will be roughly correct. double timeToNextSecond = endDate.Subtract(DateTimeOffset.UtcNow).TotalMilliseconds % 1000; - Scheduler.AddDelayed(updateTimeWithReschedule, timeToNextSecond); + updateDelegate = Scheduler.AddDelayed(updateTimeWithReschedule, timeToNextSecond); } - private void updateTime() => Text = $"The multiplayer server is restarting in {HumanizerUtils.Humanize(endDate.Subtract(DateTimeOffset.Now), precision: 3, minUnit: TimeUnit.Second)}."; + private void updateTime() + { + TimeSpan remaining = endDate.Subtract(DateTimeOffset.Now); + + if (remaining.TotalSeconds <= 5) + { + updateDelegate?.Cancel(); + Text = "The multiplayer server will be right back..."; + } + else + Text = $"The multiplayer server is restarting in {HumanizerUtils.Humanize(remaining, precision: 3, minUnit: TimeUnit.Second)}."; + } } } From 5d73de9021d947346786b356373b6cdd25833556 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 20:20:32 +0900 Subject: [PATCH 1250/2686] Perform matrix mults on the GPU --- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 70913b0851..58ba8ba0b1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -366,14 +366,16 @@ namespace osu.Game.Rulesets.Osu.Skinning var shader = GetAppropriateShader(renderer); renderer.SetBlend(BlendingParameters.Additive); + renderer.PushLocalMatrix(DrawInfo.Matrix); shader.Bind(); Texture.Bind(); UpdateDrawVariables(renderer); - UpdateVertexBuffer(); + UpdateVertexBuffer(renderer); shader.Unbind(); + renderer.PopLocalMatrix(); } protected Color4 ColorAtPosition(Vector2 localPos) => DrawColourInfo.Colour.HasSingleColour @@ -395,7 +397,7 @@ namespace osu.Game.Rulesets.Osu.Skinning TextureRect = Texture.GetTextureRect(); } - protected virtual void UpdateVertexBuffer() + protected virtual void UpdateVertexBuffer(IRenderer renderer) { foreach (var point in Points) drawPointQuad(point); @@ -420,25 +422,25 @@ namespace osu.Game.Rulesets.Osu.Skinning QuadBatch.Add(new TexturedVertex2D { - Position = Vector2Extensions.Transform(localTopLeft, DrawInfo.Matrix), + Position = localTopLeft, TexturePosition = TextureRect.TopLeft, Colour = Color4Extensions.Multiply(ColorAtPosition(localTopLeft), color), }); QuadBatch.Add(new TexturedVertex2D { - Position = Vector2Extensions.Transform(localTopRight, DrawInfo.Matrix), + Position = localTopRight, TexturePosition = TextureRect.TopRight, Colour = Color4Extensions.Multiply(ColorAtPosition(localTopRight), color), }); QuadBatch.Add(new TexturedVertex2D { - Position = Vector2Extensions.Transform(localBotRight, DrawInfo.Matrix), + Position = localBotRight, TexturePosition = TextureRect.BottomRight, Colour = Color4Extensions.Multiply(ColorAtPosition(localBotRight), color), }); QuadBatch.Add(new TexturedVertex2D { - Position = Vector2Extensions.Transform(localBotLeft, DrawInfo.Matrix), + Position = localBotLeft, TexturePosition = TextureRect.BottomLeft, Colour = Color4Extensions.Multiply(ColorAtPosition(localBotLeft), color), }); From f7962c993d88b9072d749cfad8814e43980b8afa Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 20:36:44 +0900 Subject: [PATCH 1251/2686] Reduce the number of points --- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 58ba8ba0b1..80341c5ef1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Skinning private float totalDistance; private Vector2? lastPosition; - private const int max_point_count = 72_000; + private const int max_point_count = 18_000; public override float Height { From 5d3c6efcc52ae54a2755d3bab0d95c948f1e74fa Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 20:38:22 +0900 Subject: [PATCH 1252/2686] Dispose quad batch --- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 80341c5ef1..c07c2f960f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -445,6 +445,12 @@ namespace osu.Game.Rulesets.Osu.Skinning Colour = Color4Extensions.Multiply(ColorAtPosition(localBotLeft), color), }); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + QuadBatch?.Dispose(); + } } } } From 9f23210e7efbea97cda8b56bb73786fb99b8dff3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 20:39:12 +0900 Subject: [PATCH 1253/2686] Use British-English --- .../Skinning/Default/DefaultSmoke.cs | 2 +- .../Skinning/Legacy/LegacySmoke.cs | 2 +- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 17 ++++++++--------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs index 6eebd18305..85d1018b7f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default fadeOutTime = SmokeStartTime + fade_out_speed * (CurrentTime - (SmokeEndTime + fade_out_delay)); } - protected override Color4 PointColor(SmokePoint point) + protected override Color4 PointColour(SmokePoint point) { var color = Color4.White; color.A = alpha; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index d8c3ff3521..d3ce294696 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy finalFadeOutTime = final_fade_out_speed * (CurrentTime - SmokeEndTime) + SmokeEndTime - initialFadeOutDurationTrunc * (1 + 1 / re_fade_in_speed); } - protected override Color4 PointColor(SmokePoint point) + protected override Color4 PointColour(SmokePoint point) { var color = Color4.White; diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index c07c2f960f..63a370981e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -315,7 +315,6 @@ namespace osu.Game.Rulesets.Osu.Skinning protected new Smoke Source => (Smoke)base.Source; protected IVertexBatch? QuadBatch; - protected readonly List Points = new List(); protected float Radius; @@ -378,11 +377,11 @@ namespace osu.Game.Rulesets.Osu.Skinning renderer.PopLocalMatrix(); } - protected Color4 ColorAtPosition(Vector2 localPos) => DrawColourInfo.Colour.HasSingleColour + protected Color4 ColourAtPosition(Vector2 localPos) => DrawColourInfo.Colour.HasSingleColour ? ((SRGBColour)DrawColourInfo.Colour).Linear : DrawColourInfo.Colour.Interpolate(Vector2.Divide(localPos, DrawSize)).Linear; - protected abstract Color4 PointColor(SmokePoint point); + protected abstract Color4 PointColour(SmokePoint point); protected abstract float PointScale(SmokePoint point); @@ -407,12 +406,12 @@ namespace osu.Game.Rulesets.Osu.Skinning { Debug.Assert(QuadBatch != null); - var color = PointColor(point); + var colour = PointColour(point); float scale = PointScale(point); var dir = PointDirection(point); var ortho = dir.PerpendicularLeft; - if (color.A == 0 || scale == 0) + if (colour.A == 0 || scale == 0) return; var localTopLeft = point.Position + (Radius * scale * (-ortho - dir)) - PositionOffset; @@ -424,25 +423,25 @@ namespace osu.Game.Rulesets.Osu.Skinning { Position = localTopLeft, TexturePosition = TextureRect.TopLeft, - Colour = Color4Extensions.Multiply(ColorAtPosition(localTopLeft), color), + Colour = Color4Extensions.Multiply(ColourAtPosition(localTopLeft), colour), }); QuadBatch.Add(new TexturedVertex2D { Position = localTopRight, TexturePosition = TextureRect.TopRight, - Colour = Color4Extensions.Multiply(ColorAtPosition(localTopRight), color), + Colour = Color4Extensions.Multiply(ColourAtPosition(localTopRight), colour), }); QuadBatch.Add(new TexturedVertex2D { Position = localBotRight, TexturePosition = TextureRect.BottomRight, - Colour = Color4Extensions.Multiply(ColorAtPosition(localBotRight), color), + Colour = Color4Extensions.Multiply(ColourAtPosition(localBotRight), colour), }); QuadBatch.Add(new TexturedVertex2D { Position = localBotLeft, TexturePosition = TextureRect.BottomLeft, - Colour = Color4Extensions.Multiply(ColorAtPosition(localBotLeft), color), + Colour = Color4Extensions.Multiply(ColourAtPosition(localBotLeft), colour), }); } From ff6e4e3a9644c03c211a3221cd263ca4edc97732 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 20:42:12 +0900 Subject: [PATCH 1254/2686] Privatise setters --- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 63a370981e..19891c823d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -314,19 +314,19 @@ namespace osu.Game.Rulesets.Osu.Skinning { protected new Smoke Source => (Smoke)base.Source; - protected IVertexBatch? QuadBatch; + protected IVertexBatch? QuadBatch { get; private set; } protected readonly List Points = new List(); - protected float Radius; - protected Vector2 DrawSize; - protected Vector2 PositionOffset; - protected Texture? Texture; + protected float Radius { get; private set; } + protected Vector2 DrawSize { get; private set; } + protected Vector2 PositionOffset { get; private set; } + protected Texture? Texture { get; private set; } - protected double SmokeStartTime; - protected double SmokeEndTime; - protected double CurrentTime; + protected double SmokeStartTime { get; private set; } + protected double SmokeEndTime { get; private set; } + protected double CurrentTime { get; private set; } - protected RectangleF TextureRect; + protected RectangleF TextureRect { get; private set; } private IFrameBasedClock? clock; From c28ed477e152c4dd1fb082b6aedb16bfffa7b6ec Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 20:54:49 +0900 Subject: [PATCH 1255/2686] Expose less stuff, clean up implementation --- .../Skinning/Default/DefaultSmoke.cs | 5 +- .../Skinning/Legacy/LegacySmoke.cs | 6 - osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 148 +++++------------- 3 files changed, 44 insertions(+), 115 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs index 85d1018b7f..a3c5733eb4 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Graphics; -using osu.Framework.Graphics.Rendering; using osuTK; using osuTK.Graphics; @@ -34,9 +33,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { } - protected override void UpdateDrawVariables(IRenderer renderer) + public override void ApplyState() { - base.UpdateDrawVariables(renderer); + base.ApplyState(); fadeOutTime = SmokeStartTime + fade_out_speed * (CurrentTime - (SmokeEndTime + fade_out_delay)); } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index d3ce294696..50669cf79a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Graphics; -using osu.Framework.Graphics.Rendering; using osu.Framework.Utils; using osu.Game.Skinning; using osuTK; @@ -99,11 +98,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); rotationSeed = Source.RotationSeed; - } - - protected override void UpdateDrawVariables(IRenderer renderer) - { - base.UpdateDrawVariables(renderer); rotationRNG = new Random(rotationSeed); initialFadeOutTime = Math.Min(CurrentTime, SmokeEndTime); diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 19891c823d..410ee7b4f0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; -using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Rulesets.Osu.UI; using osuTK; @@ -41,57 +40,11 @@ namespace osu.Game.Rulesets.Osu.Skinning } } - private Texture? texture; + protected Texture? Texture { get; set; } - protected Texture? Texture - { - get => texture; - set - { - texture = value; - Invalidate(Invalidation.DrawNode); - } - } + protected double SmokeStartTime { get; private set; } = double.MinValue; - private double smokeTimeStart = double.MinValue; - - protected double SmokeStartTime - { - get => smokeTimeStart; - private set - { - if (smokeTimeStart == value) - return; - - smokeTimeStart = value; - Invalidate(Invalidation.DrawNode); - } - } - - private double smokeTimeEnd = double.MaxValue; - - protected double SmokeEndTime - { - get => smokeTimeEnd; - private set - { - if (smokeTimeEnd == value) - return; - - smokeTimeEnd = value; - Invalidate(Invalidation.DrawNode); - } - } - - public override IFrameBasedClock Clock - { - get => base.Clock; - set - { - base.Clock = value; - Invalidate(Invalidation.DrawNode); - } - } + protected double SmokeEndTime { get; private set; } = double.MaxValue; private Vector2 topLeft; @@ -104,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Skinning return; topLeft = value; - Invalidate(); + Invalidate(Invalidation.Layout); } } @@ -277,6 +230,8 @@ namespace osu.Game.Rulesets.Osu.Skinning base.Update(); Position = TopLeft; + + Invalidate(Invalidation.DrawNode); } protected override void Dispose(bool isDisposing) @@ -314,21 +269,16 @@ namespace osu.Game.Rulesets.Osu.Skinning { protected new Smoke Source => (Smoke)base.Source; - protected IVertexBatch? QuadBatch { get; private set; } - protected readonly List Points = new List(); - - protected float Radius { get; private set; } - protected Vector2 DrawSize { get; private set; } - protected Vector2 PositionOffset { get; private set; } - protected Texture? Texture { get; private set; } - protected double SmokeStartTime { get; private set; } protected double SmokeEndTime { get; private set; } protected double CurrentTime { get; private set; } - protected RectangleF TextureRect { get; private set; } - - private IFrameBasedClock? clock; + private readonly List points = new List(); + private IVertexBatch? quadBatch; + private float radius; + private Vector2 drawSize; + private Vector2 positionOffset; + private Texture? texture; protected SmokeDrawNode(ITexturedShaderDrawable source) : base(source) @@ -339,28 +289,29 @@ namespace osu.Game.Rulesets.Osu.Skinning { base.ApplyState(); - Points.Clear(); - Points.AddRange(Source.SmokePoints); + points.Clear(); + points.AddRange(Source.SmokePoints); - Radius = Source.Radius; - DrawSize = Source.DrawSize; - PositionOffset = Source.TopLeft; - Texture = Source.Texture; - clock = Source.Clock; + radius = Source.Radius; + drawSize = Source.DrawSize; + positionOffset = Source.TopLeft; + texture = Source.Texture; SmokeStartTime = Source.SmokeStartTime; SmokeEndTime = Source.SmokeEndTime; + CurrentTime = Source.Clock.CurrentTime; } public sealed override void Draw(IRenderer renderer) { base.Draw(renderer); - if (Points.Count == 0) + if (points.Count == 0) return; - QuadBatch ??= renderer.CreateQuadBatch(max_point_count / 10, 10); - Texture ??= renderer.WhitePixel; + quadBatch ??= renderer.CreateQuadBatch(max_point_count / 10, 10); + texture ??= renderer.WhitePixel; + RectangleF textureRect = texture.GetTextureRect(); var shader = GetAppropriateShader(renderer); @@ -368,10 +319,10 @@ namespace osu.Game.Rulesets.Osu.Skinning renderer.PushLocalMatrix(DrawInfo.Matrix); shader.Bind(); - Texture.Bind(); + texture.Bind(); - UpdateDrawVariables(renderer); - UpdateVertexBuffer(renderer); + foreach (var point in points) + drawPointQuad(point, textureRect); shader.Unbind(); renderer.PopLocalMatrix(); @@ -379,7 +330,7 @@ namespace osu.Game.Rulesets.Osu.Skinning protected Color4 ColourAtPosition(Vector2 localPos) => DrawColourInfo.Colour.HasSingleColour ? ((SRGBColour)DrawColourInfo.Colour).Linear - : DrawColourInfo.Colour.Interpolate(Vector2.Divide(localPos, DrawSize)).Linear; + : DrawColourInfo.Colour.Interpolate(Vector2.Divide(localPos, drawSize)).Linear; protected abstract Color4 PointColour(SmokePoint point); @@ -387,24 +338,9 @@ namespace osu.Game.Rulesets.Osu.Skinning protected abstract Vector2 PointDirection(SmokePoint point); - protected virtual void UpdateDrawVariables(IRenderer renderer) + private void drawPointQuad(SmokePoint point, RectangleF textureRect) { - Debug.Assert(clock != null); - Debug.Assert(Texture != null); - - CurrentTime = clock.CurrentTime; - TextureRect = Texture.GetTextureRect(); - } - - protected virtual void UpdateVertexBuffer(IRenderer renderer) - { - foreach (var point in Points) - drawPointQuad(point); - } - - private void drawPointQuad(SmokePoint point) - { - Debug.Assert(QuadBatch != null); + Debug.Assert(quadBatch != null); var colour = PointColour(point); float scale = PointScale(point); @@ -414,33 +350,33 @@ namespace osu.Game.Rulesets.Osu.Skinning if (colour.A == 0 || scale == 0) return; - var localTopLeft = point.Position + (Radius * scale * (-ortho - dir)) - PositionOffset; - var localTopRight = point.Position + (Radius * scale * (-ortho + dir)) - PositionOffset; - var localBotLeft = point.Position + (Radius * scale * (ortho - dir)) - PositionOffset; - var localBotRight = point.Position + (Radius * scale * (ortho + dir)) - PositionOffset; + var localTopLeft = point.Position + (radius * scale * (-ortho - dir)) - positionOffset; + var localTopRight = point.Position + (radius * scale * (-ortho + dir)) - positionOffset; + var localBotLeft = point.Position + (radius * scale * (ortho - dir)) - positionOffset; + var localBotRight = point.Position + (radius * scale * (ortho + dir)) - positionOffset; - QuadBatch.Add(new TexturedVertex2D + quadBatch.Add(new TexturedVertex2D { Position = localTopLeft, - TexturePosition = TextureRect.TopLeft, + TexturePosition = textureRect.TopLeft, Colour = Color4Extensions.Multiply(ColourAtPosition(localTopLeft), colour), }); - QuadBatch.Add(new TexturedVertex2D + quadBatch.Add(new TexturedVertex2D { Position = localTopRight, - TexturePosition = TextureRect.TopRight, + TexturePosition = textureRect.TopRight, Colour = Color4Extensions.Multiply(ColourAtPosition(localTopRight), colour), }); - QuadBatch.Add(new TexturedVertex2D + quadBatch.Add(new TexturedVertex2D { Position = localBotRight, - TexturePosition = TextureRect.BottomRight, + TexturePosition = textureRect.BottomRight, Colour = Color4Extensions.Multiply(ColourAtPosition(localBotRight), colour), }); - QuadBatch.Add(new TexturedVertex2D + quadBatch.Add(new TexturedVertex2D { Position = localBotLeft, - TexturePosition = TextureRect.BottomLeft, + TexturePosition = textureRect.BottomLeft, Colour = Color4Extensions.Multiply(ColourAtPosition(localBotLeft), colour), }); } @@ -448,7 +384,7 @@ namespace osu.Game.Rulesets.Osu.Skinning protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - QuadBatch?.Dispose(); + quadBatch?.Dispose(); } } } From 102c1409674733535121b8957d8194c6a2940515 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 20:59:58 +0900 Subject: [PATCH 1256/2686] Remove another invalidate --- .../Skinning/Legacy/LegacySmoke.cs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index 50669cf79a..556996895c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -35,20 +35,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private const float max_rotation = 0.25f; - private int rotationSeed = RNG.Next(); - - protected int RotationSeed - { - get => rotationSeed; - set - { - if (rotationSeed == value) - return; - - rotationSeed = value; - Invalidate(Invalidation.DrawNode); - } - } + protected int RotationSeed { get; set; } = RNG.Next(); protected override double LifetimeAfterSmokeEnd { From 3ec16063bdb017b7c07f11ed764023a47c1a4efb Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 20 Sep 2022 21:01:18 +0900 Subject: [PATCH 1257/2686] And another invalidate --- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 410ee7b4f0..3afcc031a5 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -30,14 +30,7 @@ namespace osu.Game.Rulesets.Osu.Skinning protected float Radius { get => radius ?? Texture?.DisplayWidth * 0.165f ?? 3; - set - { - if (radius == value) - return; - - radius = value; - Invalidate(Invalidation.DrawNode); - } + set => radius = value; } protected Texture? Texture { get; set; } From ff568211528b63442f858dc459497cb4142c87c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 00:24:29 +0900 Subject: [PATCH 1258/2686] Change `SkinnableHUDComponentTestScene` to show new HUD twice Co-authored-by: Salman Ahmed --- .../Visual/Gameplay/SkinnableHUDComponentTestScene.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs index 1bf1bd4c81..ea4aa98f86 100644 --- a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs +++ b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Gameplay { SetContents(skin => { - var implementation = skin is not TrianglesSkin + var implementation = skin is LegacySkin ? CreateLegacyImplementation() : CreateDefaultImplementation(); From cb8ed1f1449fca16321da357d37505a9de073150 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 01:29:12 +0900 Subject: [PATCH 1259/2686] Adjust variables slightly for readability --- .../TestSceneCatcher.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 732184a8a8..182cc51572 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -106,18 +106,23 @@ namespace osu.Game.Rulesets.Catch.Tests public void TestCatcherCatchWidth() { float halfWidth = Catcher.CalculateCatchWidth(new BeatmapDifficulty { CircleSize = 0 }) / 2; - const float center_x = CatchPlayfield.CENTER_X; - AddStep("move catcher to center", () => catcher.X = center_x); + + AddStep("move catcher to center", () => catcher.X = CatchPlayfield.CENTER_X); + + float leftPlateBounds = CatchPlayfield.CENTER_X - halfWidth; + float rightPlateBounds = CatchPlayfield.CENTER_X + halfWidth; + AddStep("catch fruit", () => { - attemptCatch(new Fruit { X = center_x + -halfWidth + 1 }); - attemptCatch(new Fruit { X = center_x + halfWidth - 1 }); + attemptCatch(new Fruit { X = leftPlateBounds + 1 }); + attemptCatch(new Fruit { X = rightPlateBounds - 1 }); }); checkPlate(2); + AddStep("miss fruit", () => { - attemptCatch(new Fruit { X = center_x + -halfWidth - 1 }); - attemptCatch(new Fruit { X = center_x + halfWidth + 1 }); + attemptCatch(new Fruit { X = leftPlateBounds - 1 }); + attemptCatch(new Fruit { X = rightPlateBounds + 1 }); }); checkPlate(2); } From ddbd69dc678fa10fe237186fc2a6aeaa352a80b7 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 20 Sep 2022 09:44:01 -0700 Subject: [PATCH 1260/2686] Replace LifetimeAfterSmokeEnd with abstract LifetimeEnd --- osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs | 2 +- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs | 4 ++-- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs index a3c5733eb4..65ae490882 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default private const double fade_out_duration = 50; private const float alpha = 0.5f; - protected override double LifetimeAfterSmokeEnd => fade_out_delay + fade_out_duration + (SmokeEndTime - SmokeStartTime) / fade_out_speed; + public override double LifetimeEnd => SmokeEndTime + fade_out_delay + fade_out_duration + (SmokeEndTime - SmokeStartTime) / fade_out_speed; public DefaultSmoke() { diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index 556996895c..f02c20fefb 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -37,12 +37,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected int RotationSeed { get; set; } = RNG.Next(); - protected override double LifetimeAfterSmokeEnd + public override double LifetimeEnd { get { double initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); - return final_fade_out_duration + initialFadeOutDurationTrunc / re_fade_in_speed + initialFadeOutDurationTrunc / final_fade_out_speed; + return SmokeEndTime + final_fade_out_duration + initialFadeOutDurationTrunc / re_fade_in_speed + initialFadeOutDurationTrunc / final_fade_out_speed; } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 3afcc031a5..c381b543b3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -69,7 +69,6 @@ namespace osu.Game.Rulesets.Osu.Skinning } } - protected abstract double LifetimeAfterSmokeEnd { get; } protected virtual float PointInterval => Radius * 7f / 8; protected bool IsActive { get; private set; } @@ -206,6 +205,8 @@ namespace osu.Game.Rulesets.Osu.Skinning BottomRight = new Vector2(BottomRight.X, position.Y); } + public abstract override double LifetimeEnd { get; } + private void onSmokeEnded(double time) { if (!IsActive) @@ -213,7 +214,6 @@ namespace osu.Game.Rulesets.Osu.Skinning IsActive = false; SmokeEndTime = time; - LifetimeEnd = time + LifetimeAfterSmokeEnd + 100; } protected abstract override DrawNode CreateDrawNode(); From 6b1cd1bce353e8766711a12bb36d8bbad958841a Mon Sep 17 00:00:00 2001 From: Drison64 Date: Tue, 20 Sep 2022 19:13:40 +0200 Subject: [PATCH 1261/2686] Clamped JuiceStream to Playfield, but broke few tests --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 311e15116e..0f2ce2e5e3 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -11,6 +11,7 @@ using Newtonsoft.Json; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -84,8 +85,8 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new TinyDroplet { StartTime = t + lastEvent.Value.Time, - X = OriginalX + Path.PositionAt( - lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X, + X = EffectiveX + ClampToPlayField(Path.PositionAt( + lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X), }); } } @@ -102,7 +103,7 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = dropletSamples, StartTime = e.Time, - X = OriginalX + Path.PositionAt(e.PathProgress).X, + X = EffectiveX + ClampToPlayField(Path.PositionAt(e.PathProgress).X), }); break; @@ -113,14 +114,16 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = this.GetNodeSamples(nodeIndex++), StartTime = e.Time, - X = OriginalX + Path.PositionAt(e.PathProgress).X, + X = EffectiveX + ClampToPlayField(Path.PositionAt(e.PathProgress).X), }); break; } } } - public float EndX => OriginalX + this.CurvePositionAt(1).X; + public float EndX => EffectiveX + this.CurvePositionAt(1).X; + + public float ClampToPlayField(float value) => Math.Clamp(value, 0, CatchPlayfield.WIDTH); [JsonIgnore] public double Duration From a4fae370135c046c1d847fec39e10a75b97421a1 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Tue, 20 Sep 2022 19:45:39 +0200 Subject: [PATCH 1262/2686] Fixed tests failing --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 0f2ce2e5e3..a0b6c7e724 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new TinyDroplet { StartTime = t + lastEvent.Value.Time, - X = EffectiveX + ClampToPlayField(Path.PositionAt( + X = ClampToPlayField(EffectiveX + Path.PositionAt( lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X), }); } @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = dropletSamples, StartTime = e.Time, - X = EffectiveX + ClampToPlayField(Path.PositionAt(e.PathProgress).X), + X = ClampToPlayField(EffectiveX + Path.PositionAt(e.PathProgress).X), }); break; @@ -114,14 +114,14 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = this.GetNodeSamples(nodeIndex++), StartTime = e.Time, - X = EffectiveX + ClampToPlayField(Path.PositionAt(e.PathProgress).X), + X = ClampToPlayField(EffectiveX + Path.PositionAt(e.PathProgress).X), }); break; } } } - public float EndX => EffectiveX + this.CurvePositionAt(1).X; + public float EndX => ClampToPlayField(EffectiveX + this.CurvePositionAt(1).X); public float ClampToPlayField(float value) => Math.Clamp(value, 0, CatchPlayfield.WIDTH); From 092e6cfa1da050a5d16d0ac86fc95547f14eabbc Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 20 Sep 2022 12:03:07 -0700 Subject: [PATCH 1263/2686] Lock smoke bounds to playfield --- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 86 ++----------------------- 1 file changed, 5 insertions(+), 81 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index c381b543b3..4d2a193a8a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -39,36 +39,6 @@ namespace osu.Game.Rulesets.Osu.Skinning protected double SmokeEndTime { get; private set; } = double.MaxValue; - private Vector2 topLeft; - - protected Vector2 TopLeft - { - get => topLeft; - set - { - if (topLeft == value) - return; - - topLeft = value; - Invalidate(Invalidation.Layout); - } - } - - private Vector2 bottomRight; - - protected Vector2 BottomRight - { - get => bottomRight; - set - { - if (bottomRight == value) - return; - - bottomRight = value; - Invalidate(Invalidation.Layout); - } - } - protected virtual float PointInterval => Radius * 7f / 8; protected bool IsActive { get; private set; } @@ -79,24 +49,6 @@ namespace osu.Game.Rulesets.Osu.Skinning private const int max_point_count = 18_000; - public override float Height - { - get => base.Height = BottomRight.Y - TopLeft.Y; - set => throw new InvalidOperationException($"Cannot manually set {nameof(Height)} of {nameof(Smoke)}."); - } - - public override float Width - { - get => base.Width = BottomRight.X - TopLeft.X; - set => throw new InvalidOperationException($"Cannot manually set {nameof(Width)} of {nameof(Smoke)}."); - } - - public override Vector2 Size - { - get => base.Size = BottomRight - TopLeft; - set => throw new InvalidOperationException($"Cannot manually set {nameof(Size)} of {nameof(Smoke)}."); - } - [Resolved(CanBeNull = true)] private SmokeContainer? smokeContainer { get; set; } @@ -111,8 +63,7 @@ namespace osu.Game.Rulesets.Osu.Skinning { base.LoadComplete(); - Anchor = Anchor.TopLeft; - Origin = Anchor.TopLeft; + RelativeSizeAxes = Axes.Both; SmokeStartTime = Time.Current; @@ -157,7 +108,6 @@ namespace osu.Game.Rulesets.Osu.Skinning { int index = ~SmokePoints.BinarySearch(new SmokePoint { Time = time }, new SmokePoint.UpperBoundComparer()); SmokePoints.RemoveRange(index, SmokePoints.Count - index); - recalculateBounds(); } totalDistance %= PointInterval; @@ -175,7 +125,6 @@ namespace osu.Game.Rulesets.Osu.Skinning } Invalidate(Invalidation.DrawNode); - adaptBounds(position); } lastPosition = position; @@ -184,27 +133,6 @@ namespace osu.Game.Rulesets.Osu.Skinning onSmokeEnded(time); } - private void recalculateBounds() - { - TopLeft = BottomRight = Vector2.Zero; - - foreach (var point in SmokePoints) - adaptBounds(point.Position); - } - - private void adaptBounds(Vector2 position) - { - if (position.X < TopLeft.X) - TopLeft = new Vector2(position.X, TopLeft.Y); - else if (position.X > BottomRight.X) - BottomRight = new Vector2(position.X, BottomRight.Y); - - if (position.Y < TopLeft.Y) - TopLeft = new Vector2(TopLeft.X, position.Y); - else if (position.Y > BottomRight.Y) - BottomRight = new Vector2(BottomRight.X, position.Y); - } - public abstract override double LifetimeEnd { get; } private void onSmokeEnded(double time) @@ -222,8 +150,6 @@ namespace osu.Game.Rulesets.Osu.Skinning { base.Update(); - Position = TopLeft; - Invalidate(Invalidation.DrawNode); } @@ -270,7 +196,6 @@ namespace osu.Game.Rulesets.Osu.Skinning private IVertexBatch? quadBatch; private float radius; private Vector2 drawSize; - private Vector2 positionOffset; private Texture? texture; protected SmokeDrawNode(ITexturedShaderDrawable source) @@ -287,7 +212,6 @@ namespace osu.Game.Rulesets.Osu.Skinning radius = Source.Radius; drawSize = Source.DrawSize; - positionOffset = Source.TopLeft; texture = Source.Texture; SmokeStartTime = Source.SmokeStartTime; @@ -343,10 +267,10 @@ namespace osu.Game.Rulesets.Osu.Skinning if (colour.A == 0 || scale == 0) return; - var localTopLeft = point.Position + (radius * scale * (-ortho - dir)) - positionOffset; - var localTopRight = point.Position + (radius * scale * (-ortho + dir)) - positionOffset; - var localBotLeft = point.Position + (radius * scale * (ortho - dir)) - positionOffset; - var localBotRight = point.Position + (radius * scale * (ortho + dir)) - positionOffset; + var localTopLeft = point.Position + (radius * scale * (-ortho - dir)); + var localTopRight = point.Position + (radius * scale * (-ortho + dir)); + var localBotLeft = point.Position + (radius * scale * (ortho - dir)); + var localBotRight = point.Position + (radius * scale * (ortho + dir)); quadBatch.Add(new TexturedVertex2D { From b8f2e13503c8899880c065ac0f2bdba808674b23 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 20 Sep 2022 22:27:27 +0300 Subject: [PATCH 1264/2686] Avoid catching all exceptions raising from skin instance creation --- osu.Game/Skinning/SkinInfo.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index 34728245c8..04d1216ed6 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using JetBrains.Annotations; using Newtonsoft.Json; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Testing; using osu.Game.Database; using osu.Game.IO; @@ -45,20 +44,18 @@ namespace osu.Game.Skinning var type = string.IsNullOrEmpty(InstantiationInfo) // handle the case of skins imported before InstantiationInfo was added. ? typeof(LegacySkin) - : Type.GetType(InstantiationInfo).AsNonNull(); + : Type.GetType(InstantiationInfo); - try + if (type == null) { - return (Skin)Activator.CreateInstance(type, this, resources); - } - catch - { - // Since the class was renamed from "DefaultSkin" to "TrianglesSkin", the instantiation would fail + // Since the class was renamed from "DefaultSkin" to "TrianglesSkin", the type retrieval would fail // for user modified skins. This aims to amicably handle that. // If we ever add more default skins in the future this will need some kind of proper migration rather than - // a single catch. + // a single fallback. return new TrianglesSkin(this, resources); } + + return (Skin)Activator.CreateInstance(type, this, resources); } public IList Files { get; } = null!; From b7c1e8cc5ace501a15384c45ec49b14d03d17573 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Tue, 20 Sep 2022 23:11:38 +0200 Subject: [PATCH 1265/2686] Remove setting `AngleVariety` --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index c829d1f696..e1ebecc6f2 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -38,16 +38,6 @@ namespace osu.Game.Rulesets.Osu.Mods Precision = 0.1f }; - [SettingSource("Angle variety", "The amount of variety in how sharp angles are", SettingControlType = typeof(SettingsSlider))] - public BindableFloat AngleVariety { get; } = new BindableFloat - { - Default = 3, - Value = 3, - MinValue = 0, - MaxValue = 10, - Precision = 0.1f - }; - private static readonly float playfield_diagonal = OsuPlayfield.BASE_SIZE.LengthFast; private Random random = null!; @@ -111,7 +101,9 @@ namespace osu.Game.Rulesets.Osu.Mods private float getRandomOffset(float stdDev) { - float customMultiplier = AngleVariety.Value / AngleVariety.Default; + // Range: [0.5;2] + float customMultiplier = (1.5f * AngleSharpness.MaxValue - AngleSharpness.Value) / (1.5f * AngleSharpness.MaxValue - AngleSharpness.Default); + return OsuHitObjectGenerationUtils.RandomGaussian(random, 0, stdDev * customMultiplier); } From b1ecac514ad7fd0580878f02942d237e7c9763b0 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Tue, 20 Sep 2022 23:13:38 +0200 Subject: [PATCH 1266/2686] Correct comments --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index e1ebecc6f2..78c7aa53f4 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -101,7 +101,8 @@ namespace osu.Game.Rulesets.Osu.Mods private float getRandomOffset(float stdDev) { - // Range: [0.5;2] + // Range: [0.5, 2] + // Higher angle sharpness -> lower multiplier float customMultiplier = (1.5f * AngleSharpness.MaxValue - AngleSharpness.Value) / (1.5f * AngleSharpness.MaxValue - AngleSharpness.Default); return OsuHitObjectGenerationUtils.RandomGaussian(random, 0, stdDev * customMultiplier); @@ -112,14 +113,14 @@ namespace osu.Game.Rulesets.Osu.Mods /// Whether the relative angle should be positive or negative. private float getRelativeTargetAngle(float targetDistance, float offset, bool flowDirection) { - // Range [0.1;1] + // Range: [0.1, 1] float angleSharpness = AngleSharpness.Value / AngleSharpness.MaxValue; - // Range [0;0.9] + // Range: [0, 0.9] float angleWideness = 1 - angleSharpness; - // Range: [-60;30] + // Range: [-60, 30] float customOffsetX = angleSharpness * 100 - 70; - // Range: [-0.075;0.15] + // Range: [-0.075, 0.15] float customOffsetY = angleWideness * 0.25f - 0.075f; targetDistance += customOffsetX; From 8b918d29fc2e2387430eea1010b5c0ff01be93de Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 21 Sep 2022 00:15:49 +0300 Subject: [PATCH 1267/2686] Add failing test case --- .../TestSceneNotificationOverlay.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index c8126d883c..19da31a91b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -230,6 +230,31 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait overlay not present", () => !notificationOverlay.IsPresent); } + [Test] + public void TestProgressClick() + { + ProgressNotification notification = null!; + + AddStep("add progress notification", () => + { + notification = new ProgressNotification + { + Text = @"Uploading to BSS...", + CompletionText = "Uploaded to BSS!", + }; + notificationOverlay.Post(notification); + progressingNotifications.Add(notification); + }); + + AddStep("hover over notification", () => InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType().Single())); + + AddStep("left click", () => InputManager.Click(MouseButton.Left)); + AddAssert("not cancelled", () => notification.State == ProgressNotificationState.Active); + + AddStep("right click", () => InputManager.Click(MouseButton.Right)); + AddAssert("cancelled", () => notification.State == ProgressNotificationState.Cancelled); + } + [Test] public void TestCompleteProgress() { From dcfb6a2f060a1de3e86128080bae42d6d81935b7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 21 Sep 2022 00:15:45 +0300 Subject: [PATCH 1268/2686] Fix progress notifications no longer blocking close on click --- osu.Game/Overlays/Notifications/Notification.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 4e7cebf0ae..ea654e1272 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -229,8 +229,8 @@ namespace osu.Game.Overlays.Notifications protected override bool OnClick(ClickEvent e) { // Clicking with anything but left button should dismiss but not perform the activation action. - if (e.Button == MouseButton.Left) - Activated?.Invoke(); + if (e.Button == MouseButton.Left && Activated?.Invoke() == false) + return true; Close(false); return true; From fe9e8635fc3424f635f0a6db04441abee170bb1a Mon Sep 17 00:00:00 2001 From: B3nn1 Date: Wed, 21 Sep 2022 01:04:39 +0200 Subject: [PATCH 1269/2686] Fix snapping of already existing slider control points in the editor --- .../Sliders/Components/PathControlPointVisualiser.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 9de62d1a46..0dd522fd47 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -303,16 +303,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components } else { + var result = snapProvider?.FindSnappedPositionAndTime(ToScreenSpace(e.MousePosition)); + + Vector2 movementDelta = Parent.ToLocalSpace(result?.ScreenSpacePosition ?? ToScreenSpace(e.MousePosition)) - dragStartPositions[draggedControlPointIndex] - slider.Position; + for (int i = 0; i < controlPoints.Count; ++i) { var controlPoint = controlPoints[i]; if (selectedControlPoints.Contains(controlPoint)) { - Vector2 newPosition = Parent.ToScreenSpace(e.MousePosition + (dragStartPositions[0] - dragStartPositions[draggedControlPointIndex])); - var result = snapProvider?.FindSnappedPositionAndTime(newPosition); - - Vector2 movementDelta = Parent.ToLocalSpace(result?.ScreenSpacePosition ?? newPosition) - slider.Position; - controlPoint.Position = dragStartPositions[i] + movementDelta; } } From 368229f324bca76a9ea409f39f49c8a926e168d4 Mon Sep 17 00:00:00 2001 From: B3nn1 Date: Wed, 21 Sep 2022 01:25:01 +0200 Subject: [PATCH 1270/2686] Remove unnecessary brackets --- .../Blueprints/Sliders/Components/PathControlPointVisualiser.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 0dd522fd47..628329ba64 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -311,9 +311,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { var controlPoint = controlPoints[i]; if (selectedControlPoints.Contains(controlPoint)) - { controlPoint.Position = dragStartPositions[i] + movementDelta; - } } } From 29fa868fde5ab7162c742515150d7569977414b0 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 21 Sep 2022 03:03:34 +0300 Subject: [PATCH 1271/2686] Fix test scene not resetting mouse position Also fixes until step flipped. --- .../Visual/UserInterface/TestSceneNotificationOverlay.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 19da31a91b..b314d95597 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -34,6 +34,8 @@ namespace osu.Game.Tests.Visual.UserInterface [SetUp] public void SetUp() => Schedule(() => { + InputManager.MoveMouseTo(Vector2.Zero); + TimeToCompleteProgress = 2000; progressingNotifications.Clear(); @@ -326,7 +328,7 @@ namespace osu.Game.Tests.Visual.UserInterface { SimpleNotification notification = null!; AddStep(@"post", () => notificationOverlay.Post(notification = new BackgroundNotification { Text = @"Welcome to osu!. Enjoy your stay!" })); - AddUntilStep("check is toast", () => !notification.IsInToastTray); + AddUntilStep("check is toast", () => notification.IsInToastTray); AddAssert("light is not visible", () => notification.ChildrenOfType().Single().Alpha == 0); AddUntilStep("wait for forward to overlay", () => !notification.IsInToastTray); From a8338c4efd5cf9dbb89b772850c30b557cee3125 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 13:38:40 +0900 Subject: [PATCH 1272/2686] Add local score after existing scores to avoid initial re-sort --- .../Play/HUD/SoloGameplayLeaderboard.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 00efcb1ea9..eff7870d89 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -45,15 +45,6 @@ namespace osu.Game.Screens.Play.HUD if (!Scores.Any()) return; - ILeaderboardScore local = Add(trackingUser, true); - - local.TotalScore.BindTarget = scoreProcessor.TotalScore; - local.Accuracy.BindTarget = scoreProcessor.Accuracy; - local.Combo.BindTarget = scoreProcessor.Combo; - - // Local score should always show lower than any existing scores in cases of ties. - local.DisplayOrder.Value = long.MaxValue; - foreach (var s in Scores) { var score = Add(s.User, false); @@ -68,6 +59,15 @@ namespace osu.Game.Screens.Play.HUD score.Combo.Value = s.MaxCombo; score.DisplayOrder.Value = s.OnlineID > 0 ? s.OnlineID : s.Date.ToUnixTimeSeconds(); } + + ILeaderboardScore local = Add(trackingUser, true); + + local.TotalScore.BindTarget = scoreProcessor.TotalScore; + local.Accuracy.BindTarget = scoreProcessor.Accuracy; + local.Combo.BindTarget = scoreProcessor.Combo; + + // Local score should always show lower than any existing scores in cases of ties. + local.DisplayOrder.Value = long.MaxValue; } } } From 4385001d282c83eadb462d74fcab789af9d68538 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 13:59:11 +0900 Subject: [PATCH 1273/2686] Fix solo leaderboard seeing imported score via realm subscription flow --- osu.Game/Screens/Play/SoloPlayer.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Screens/Play/SoloPlayer.cs b/osu.Game/Screens/Play/SoloPlayer.cs index a36697c96e..d7730737d6 100644 --- a/osu.Game/Screens/Play/SoloPlayer.cs +++ b/osu.Game/Screens/Play/SoloPlayer.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; +using System.Threading.Tasks; using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Extensions; @@ -52,6 +53,16 @@ namespace osu.Game.Screens.Play protected override bool HandleTokenRetrievalFailure(Exception exception) => false; + protected override Task ImportScore(Score score) + { + // Before importing a score, stop binding the leaderboard with its score source. + // This avoids a case where the imported score may cause a leaderboard refresh + // (if the leaderboard's source is local). + LeaderboardScores.UnbindBindings(); + + return base.ImportScore(score); + } + protected override APIRequest CreateSubmissionRequest(Score score, long token) { IBeatmapInfo beatmap = score.ScoreInfo.BeatmapInfo; From 5cc2721e9afaaf5476df4024cbd9b1e069449062 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 14:42:02 +0900 Subject: [PATCH 1274/2686] Add failing test showing layout failure in gameplay leaderboard --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 74 +++++++++++++++---- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 663e398c01..72656c29b1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -6,7 +6,9 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Bindables; +using osu.Framework.Extensions.PolygonExtensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.API.Requests.Responses; @@ -18,37 +20,52 @@ namespace osu.Game.Tests.Visual.Gameplay [TestFixture] public class TestSceneGameplayLeaderboard : OsuTestScene { - private readonly TestGameplayLeaderboard leaderboard; + private TestGameplayLeaderboard leaderboard; private readonly BindableDouble playerScore = new BindableDouble(); public TestSceneGameplayLeaderboard() { - Add(leaderboard = new TestGameplayLeaderboard + AddStep("toggle expanded", () => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(2), + if (leaderboard != null) + leaderboard.Expanded.Value = !leaderboard.Expanded.Value; }); + + AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } - [SetUpSteps] - public void SetUpSteps() + [Test] + public void TestLayoutWithManyScores() { - AddStep("reset leaderboard", () => + createLeaderboard(); + + AddStep("add many scores in one go", () => { - leaderboard.Clear(); - playerScore.Value = 1222333; + for (int i = 0; i < 32; i++) + createRandomScore(new APIUser { Username = $"Player {i + 1}" }); + + // Add player at end to force an animation down the whole list. + playerScore.Value = 0; + createLeaderboardScore(playerScore, new APIUser { Username = "You", Id = 3 }, true); }); - AddStep("add local player", () => createLeaderboardScore(playerScore, new APIUser { Username = "You", Id = 3 }, true)); - AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value); - AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); + // Gameplay leaderboard has custom scroll logic, which when coupled with LayoutDuration + // has caused layout to not work in the past. + + AddUntilStep("wait for fill flow layout", + () => leaderboard.ChildrenOfType>().First().ScreenSpaceDrawQuad.Intersects(leaderboard.ScreenSpaceDrawQuad)); + + AddUntilStep("wait for some scores not masked away", + () => leaderboard.ChildrenOfType().Any(s => leaderboard.ScreenSpaceDrawQuad.Contains(s.ScreenSpaceDrawQuad.Centre))); } [Test] public void TestPlayerScore() { + createLeaderboard(); + addLocalPlayer(); + var player2Score = new BindableDouble(1234567); var player3Score = new BindableDouble(1111111); @@ -73,6 +90,9 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestRandomScores() { + createLeaderboard(); + addLocalPlayer(); + int playerNumber = 1; AddRepeatStep("add player with random score", () => createRandomScore(new APIUser { Username = $"Player {playerNumber++}" }), 10); } @@ -80,6 +100,9 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestExistingUsers() { + createLeaderboard(); + addLocalPlayer(); + AddStep("add peppy", () => createRandomScore(new APIUser { Username = "peppy", Id = 2 })); AddStep("add smoogipoo", () => createRandomScore(new APIUser { Username = "smoogipoo", Id = 1040328 })); AddStep("add flyte", () => createRandomScore(new APIUser { Username = "flyte", Id = 3103765 })); @@ -89,6 +112,9 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestMaxHeight() { + createLeaderboard(); + addLocalPlayer(); + int playerNumber = 1; AddRepeatStep("add 3 other players", () => createRandomScore(new APIUser { Username = $"Player {playerNumber++}" }), 3); checkHeight(4); @@ -103,6 +129,28 @@ namespace osu.Game.Tests.Visual.Gameplay => AddAssert($"leaderboard height is {panelCount} panels high", () => leaderboard.DrawHeight == (GameplayLeaderboardScore.PANEL_HEIGHT + leaderboard.Spacing) * panelCount); } + private void addLocalPlayer() + { + AddStep("add local player", () => + { + playerScore.Value = 1222333; + createLeaderboardScore(playerScore, new APIUser { Username = "You", Id = 3 }, true); + }); + } + + private void createLeaderboard() + { + AddStep("create leaderboard", () => + { + Child = leaderboard = new TestGameplayLeaderboard + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(2), + }; + }); + } + private void createRandomScore(APIUser user) => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), user); private void createLeaderboardScore(BindableDouble score, APIUser user, bool isTracked = false) From 087ca59ebb0362a19202704cd4e94141839d476d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 14:48:53 +0900 Subject: [PATCH 1275/2686] Add extra margin space to flow equal to height of leaderboard This ensures the content is always on screen, but also accounts for the fact that scroll operations without animation were actually forcing the local score to a location it can't usually reside at. Basically, the local score was in the scroll extension region (due to always trying to scroll the local player to the middle of the display, but there being no other content below the local player to scroll up by). --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index f21ce5e36a..62c8788396 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -96,6 +96,7 @@ namespace osu.Game.Screens.Play.HUD int displayCount = Math.Min(Flow.Count, maxPanels); Height = displayCount * (GameplayLeaderboardScore.PANEL_HEIGHT + Flow.Spacing.Y); + Flow.Margin = new MarginPadding { Bottom = Height }; requiresScroll = displayCount != Flow.Count; return drawable; From b04871f40a0060ac0474f5fc5cbcd416d5127ed2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 14:50:23 +0900 Subject: [PATCH 1276/2686] Animate scroll for a better visual experience --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 62c8788396..c4d81e7e2a 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -119,7 +119,7 @@ namespace osu.Game.Screens.Play.HUD if (requiresScroll && trackedScore != null) { float scrollTarget = scroll.GetChildPosInContent(trackedScore) + trackedScore.DrawHeight / 2 - scroll.DrawHeight / 2; - scroll.ScrollTo(scrollTarget, false); + scroll.ScrollTo(scrollTarget); } const float panel_height = GameplayLeaderboardScore.PANEL_HEIGHT; From 09960512716ebb755c2ed6d91cd8e9637203a3b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 15:03:06 +0900 Subject: [PATCH 1277/2686] Order test scores more correctly --- .../Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index 2b8eb3a80c..ac73e88468 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Gameplay new ScoreInfo { User = new APIUser { Username = @"spaceman_atlas" }, TotalScore = RNG.Next(500000, 1000000) }, new ScoreInfo { User = new APIUser { Username = @"frenzibyte" }, TotalScore = RNG.Next(500000, 1000000) }, new ScoreInfo { User = new APIUser { Username = @"Susko3" }, TotalScore = RNG.Next(500000, 1000000) }, - }.Concat(Enumerable.Range(0, 50).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 500000 + i * 10000 })).ToList(); + }.Concat(Enumerable.Range(0, 50).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 1000000 - i * 10000 })).ToList(); } } } From 5b73f24864058b3c6ac85e12a9fec5d87ece2e0c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 15:21:32 +0900 Subject: [PATCH 1278/2686] Fix outdated scores being held by `BeatmapLeaderboard` after external beatmap switch --- osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 798cf29715..0f6ac2b455 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -41,6 +41,11 @@ namespace osu.Game.Screens.Select.Leaderboards return; beatmapInfo = value; + + // Refetch is scheduled, which can cause scores to be outdated if the leaderboard is not currently updating. + // As scores are potentially used by other components, clear them eagerly to ensure a more correct state. + SetScores(null); + RefetchScores(); } } From 992441b9de388e8b463862ec8960ded13085a385 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 16:04:32 +0900 Subject: [PATCH 1279/2686] Disable alpha component parsing in beatmap / skin colour sections --- osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 2 +- osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 6 +++--- osu.Game/Skinning/LegacyManiaSkinDecoder.cs | 2 +- osu.Game/Skinning/LegacySkinDecoder.cs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 9fc1eb7650..fdd0167ed3 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -306,7 +306,7 @@ namespace osu.Game.Tests.Beatmaps.Formats new Color4(128, 255, 128, 255), new Color4(255, 187, 255, 255), new Color4(255, 177, 140, 255), - new Color4(100, 100, 100, 100), + new Color4(100, 100, 100, 255), // alpha is specified as 100, but should be ignored. }; Assert.AreEqual(expectedColors.Length, comboColors.Count); for (int i = 0; i < expectedColors.Length; i++) diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 419eb87b1a..6756f27ecd 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -29,7 +29,7 @@ namespace osu.Game.Tests.Skins 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(100, 100, 100, 255), // alpha is specified as 100, but should be ignored. }; Assert.AreEqual(expectedColors.Count, comboColors.Count); diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 3d65ab8e0f..9c066ada08 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -79,7 +79,7 @@ namespace osu.Game.Beatmaps.Formats switch (section) { case Section.Colours: - HandleColours(output, line); + HandleColours(output, line, false); return; } } @@ -93,7 +93,7 @@ namespace osu.Game.Beatmaps.Formats return line; } - protected void HandleColours(TModel output, string line) + protected void HandleColours(TModel output, string line, bool allowAlpha) { var pair = SplitKeyVal(line); @@ -108,7 +108,7 @@ namespace osu.Game.Beatmaps.Formats try { - byte alpha = split.Length == 4 ? byte.Parse(split[3]) : (byte)255; + byte alpha = allowAlpha && split.Length == 4 ? byte.Parse(split[3]) : (byte)255; colour = new Color4(byte.Parse(split[0]), byte.Parse(split[1]), byte.Parse(split[2]), alpha); } catch diff --git a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs index 49914c53aa..0aafdd4db0 100644 --- a/osu.Game/Skinning/LegacyManiaSkinDecoder.cs +++ b/osu.Game/Skinning/LegacyManiaSkinDecoder.cs @@ -121,7 +121,7 @@ namespace osu.Game.Skinning break; case string when pair.Key.StartsWith("Colour", StringComparison.Ordinal): - HandleColours(currentConfig, line); + HandleColours(currentConfig, line, true); break; // Custom sprite paths diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs index e5f87b3230..11c21d432f 100644 --- a/osu.Game/Skinning/LegacySkinDecoder.cs +++ b/osu.Game/Skinning/LegacySkinDecoder.cs @@ -48,7 +48,7 @@ namespace osu.Game.Skinning // osu!catch section only has colour settings // so no harm in handling the entire section case Section.CatchTheBeat: - HandleColours(skin, line); + HandleColours(skin, line, true); return; } From 2b8b138079aefad5586c70cf5cf84f1ab9f1dfe2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 21 Sep 2022 18:44:01 +0900 Subject: [PATCH 1280/2686] Add "keybindings" search term to settings --- osu.Game/Overlays/Settings/Sections/InputSection.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/Settings/Sections/InputSection.cs b/osu.Game/Overlays/Settings/Sections/InputSection.cs index 4d75537f6b..a8fe3d04be 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSection.cs @@ -3,6 +3,8 @@ #nullable disable +using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; @@ -20,6 +22,8 @@ namespace osu.Game.Overlays.Settings.Sections public override LocalisableString Header => InputSettingsStrings.InputSectionHeader; + public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "keybindings" }); + public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.Solid.Keyboard From 1ef09f2ae1e3cfb9c0c7080af6fc4b003300da67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 23:26:25 +0900 Subject: [PATCH 1281/2686] Fix regression in `TestSceneSongProgress` --- .../Visual/Gameplay/TestSceneSongProgress.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index 3487f4dbff..6127aa304c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -1,8 +1,8 @@ // 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.Extensions.IEnumerableExtensions; @@ -51,13 +51,14 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestToggleSeeking() { - DefaultSongProgress getDefaultProgress() => this.ChildrenOfType().Single(); + void applyToDefaultProgress(Action action) => + this.ChildrenOfType().ForEach(action); - AddStep("allow seeking", () => getDefaultProgress().AllowSeeking.Value = true); - AddStep("hide graph", () => getDefaultProgress().ShowGraph.Value = false); - AddStep("disallow seeking", () => getDefaultProgress().AllowSeeking.Value = false); - AddStep("allow seeking", () => getDefaultProgress().AllowSeeking.Value = true); - AddStep("show graph", () => getDefaultProgress().ShowGraph.Value = true); + AddStep("allow seeking", () => applyToDefaultProgress(s => s.AllowSeeking.Value = true)); + AddStep("hide graph", () => applyToDefaultProgress(s => s.ShowGraph.Value = false)); + AddStep("disallow seeking", () => applyToDefaultProgress(s => s.AllowSeeking.Value = false)); + AddStep("allow seeking", () => applyToDefaultProgress(s => s.AllowSeeking.Value = true)); + AddStep("show graph", () => applyToDefaultProgress(s => s.ShowGraph.Value = true)); } private void setHitObjects() From 86a09ad2cfee383ef397aeacbcdb2152c40e4f12 Mon Sep 17 00:00:00 2001 From: Drison64 Date: Wed, 21 Sep 2022 17:14:02 +0200 Subject: [PATCH 1282/2686] Rename ClampToPlayField --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index a0b6c7e724..015457e84f 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Catch.Objects AddNested(new TinyDroplet { StartTime = t + lastEvent.Value.Time, - X = ClampToPlayField(EffectiveX + Path.PositionAt( + X = ClampToPlayfield(EffectiveX + Path.PositionAt( lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X), }); } @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = dropletSamples, StartTime = e.Time, - X = ClampToPlayField(EffectiveX + Path.PositionAt(e.PathProgress).X), + X = ClampToPlayfield(EffectiveX + Path.PositionAt(e.PathProgress).X), }); break; @@ -114,16 +114,16 @@ namespace osu.Game.Rulesets.Catch.Objects { Samples = this.GetNodeSamples(nodeIndex++), StartTime = e.Time, - X = ClampToPlayField(EffectiveX + Path.PositionAt(e.PathProgress).X), + X = ClampToPlayfield(EffectiveX + Path.PositionAt(e.PathProgress).X), }); break; } } } - public float EndX => ClampToPlayField(EffectiveX + this.CurvePositionAt(1).X); + public float EndX => ClampToPlayfield(EffectiveX + this.CurvePositionAt(1).X); - public float ClampToPlayField(float value) => Math.Clamp(value, 0, CatchPlayfield.WIDTH); + public float ClampToPlayfield(float value) => Math.Clamp(value, 0, CatchPlayfield.WIDTH); [JsonIgnore] public double Duration From 5d543545884a3543644f816cce00b08ab055850d Mon Sep 17 00:00:00 2001 From: B3nn1 Date: Wed, 21 Sep 2022 18:53:25 +0200 Subject: [PATCH 1283/2686] Add missing ToScreenSpace() call --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 5673dab7e8..7c289b5b05 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -165,7 +165,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders if (placementControlPoint != null) { var result = snapProvider?.FindSnappedPositionAndTime(ToScreenSpace(e.MousePosition)); - placementControlPoint.Position = ToLocalSpace(result?.ScreenSpacePosition ?? e.MousePosition) - HitObject.Position; + placementControlPoint.Position = ToLocalSpace(result?.ScreenSpacePosition ?? ToScreenSpace(e.MousePosition)) - HitObject.Position; } } From 112bbe2296b3ea9e068e14a8cdaee03031ee2c40 Mon Sep 17 00:00:00 2001 From: B3nn1 Date: Wed, 21 Sep 2022 18:56:22 +0200 Subject: [PATCH 1284/2686] Always use Parent.ToScreenSpace() in PathControlPointVisualiser --- .../Sliders/Components/PathControlPointVisualiser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 628329ba64..94655f3cf7 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -303,9 +303,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components } else { - var result = snapProvider?.FindSnappedPositionAndTime(ToScreenSpace(e.MousePosition)); + var result = snapProvider?.FindSnappedPositionAndTime(Parent.ToScreenSpace(e.MousePosition)); - Vector2 movementDelta = Parent.ToLocalSpace(result?.ScreenSpacePosition ?? ToScreenSpace(e.MousePosition)) - dragStartPositions[draggedControlPointIndex] - slider.Position; + Vector2 movementDelta = Parent.ToLocalSpace(result?.ScreenSpacePosition ?? Parent.ToScreenSpace(e.MousePosition)) - dragStartPositions[draggedControlPointIndex] - slider.Position; for (int i = 0; i < controlPoints.Count; ++i) { From db21601632d36e48399b95439f571ee75e1fb115 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 12:52:24 +0900 Subject: [PATCH 1285/2686] Add warning message in `files` folder to avoid accidental deletion This is a pretty standard practice for applications that have data stored in folders where a user may accidentally determine that the content is unnecessary. Aims to address cases like https://github.com/ppy/osu/discussions/20394#discussioncomment-3705694. It's not the first time this has come up, and definitely won't be the last. --- osu.Game/OsuGameBase.cs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 8b016e8eb0..2d32fe398a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Reflection; using System.Threading; @@ -255,6 +256,8 @@ namespace osu.Game InitialiseFonts(); + addFilesWarning(); + Audio.Samples.PlaybackConcurrency = SAMPLE_CONCURRENCY; dependencies.Cache(SkinManager = new SkinManager(Storage, realm, Host, Resources, Audio, Scheduler)); @@ -373,6 +376,29 @@ namespace osu.Game Beatmap.BindValueChanged(onBeatmapChanged); } + private void addFilesWarning() + { + var realmStore = new RealmFileStore(realm, Storage); + + const string filename = "IMPORTANT READ ME.txt"; + + if (!realmStore.Storage.Exists(filename)) + { + using (var stream = realmStore.Storage.CreateFileSafely(filename)) + using (var textWriter = new StreamWriter(stream)) + { + textWriter.WriteLine(@"This folder contains all your user files (beatmaps, skins, replays etc.)"); + textWriter.WriteLine(@"Please do not touch or delete this folder!!"); + textWriter.WriteLine(); + textWriter.WriteLine(@"If you are really looking to completely delete user data, please delete"); + textWriter.WriteLine(@"the parent folder including all other files and directories"); + textWriter.WriteLine(); + textWriter.WriteLine(@"For more information on how these files are organised,"); + textWriter.WriteLine(@"see https://github.com/ppy/osu/wiki/User-file-storage"); + } + } + } + private void onTrackChanged(WorkingBeatmap beatmap, TrackChangeDirection direction) { // FramedBeatmapClock uses a decoupled clock internally which will mutate the source if it is an `IAdjustableClock`. From 2bdc6417e9f23105d6df4c3e4c49c445added1c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Sep 2022 23:38:02 +0900 Subject: [PATCH 1286/2686] Mark `DrawableOsuHitObject` `abstract` for clarity --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 6e525071ca..c0acae378c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableOsuHitObject : DrawableHitObject + public abstract class DrawableOsuHitObject : DrawableHitObject { public readonly IBindable PositionBindable = new Bindable(); public readonly IBindable StackHeightBindable = new Bindable(); From 78625fda7d82de8a62bd3000b4db29e4b3f3fa49 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 14:42:19 +0900 Subject: [PATCH 1287/2686] Improve exception when attempting to call `DrawableHitObject.ClearInternal` --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 39ccaa2e5d..e218da918c 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -172,7 +172,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { config.BindWith(OsuSetting.PositionalHitsoundsLevel, positionalHitsoundsLevel); - // Explicit non-virtual function call. + // Explicit non-virtual function call in case a DrawableHitObject overrides AddInternal. base.AddInternal(Samples = new PausableSkinnableSound()); CurrentSkin = skinSource; @@ -405,7 +405,10 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public event Action ApplyCustomUpdateState; - protected override void ClearInternal(bool disposeChildren = true) => throw new InvalidOperationException($"Should never clear a {nameof(DrawableHitObject)}"); + protected override void ClearInternal(bool disposeChildren = true) => + // See sample addition in load method. + throw new InvalidOperationException( + $"Should never clear a {nameof(DrawableHitObject)} as the base implementation adds components. If attempting to use {nameof(InternalChild)} or {nameof(InternalChildren)}, using {nameof(AddInternal)} or {nameof(AddRangeInternal)} instead."); private void updateState(ArmedState newState, bool force = false) { From b844d76311e535f908e312be03f6f2c9fc314f2c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 14:30:01 +0900 Subject: [PATCH 1288/2686] Move `Shake` logic local to hitcircle/slider --- .../Mods/TestSceneOsuModDifficultyAdjust.cs | 2 +- .../Objects/Drawables/DrawableHitCircle.cs | 35 +++++++++++++------ .../Objects/Drawables/DrawableOsuHitObject.cs | 22 +++--------- .../Objects/Drawables/DrawableSlider.cs | 22 +++++++++--- .../Objects/Drawables/DrawableSliderHead.cs | 9 ++--- 5 files changed, 53 insertions(+), 37 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs index 9d06ff5801..e5b7208da6 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods if (!objects.Any()) return false; - return objects.All(o => Precision.AlmostEquals(o.ChildrenOfType().First().Children.OfType().Single().Scale.X, target)); + return objects.All(o => Precision.AlmostEquals(o.ChildrenOfType().First().Scale.X, target)); } private bool checkSomeHit() diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 23e5cb0ad7..09a460569a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; @@ -47,6 +48,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { } + private ShakeContainer shakeContainer; + [BackgroundDependencyLoader] private void load() { @@ -72,18 +75,26 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables return true; }, }, - CirclePiece = new SkinnableDrawable(new OsuSkinComponent(CirclePieceComponent), _ => new MainCirclePiece()) + shakeContainer = new ShakeContainer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - ApproachCircle = new ProxyableSkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ApproachCircle), _ => new DefaultApproachCircle()) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + ShakeDuration = 30, RelativeSizeAxes = Axes.Both, - Alpha = 0, - Scale = new Vector2(4), + Children = new Drawable[] + { + CirclePiece = new SkinnableDrawable(new OsuSkinComponent(CirclePieceComponent), _ => new MainCirclePiece()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + ApproachCircle = new ProxyableSkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ApproachCircle), _ => new DefaultApproachCircle()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Scale = new Vector2(4), + } + } } } }, @@ -123,6 +134,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } + public override void Shake() => shakeContainer.Shake(); + protected override void CheckForResult(bool userTriggered, double timeOffset) { Debug.Assert(HitObject.HitWindows != null); @@ -139,7 +152,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables if (result == HitResult.None || CheckHittable?.Invoke(this, Time.Current) == false) { - Shake(Math.Abs(timeOffset) - HitObject.HitWindows.WindowFor(HitResult.Miss)); + Shake(); return; } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index c0acae378c..6f4ca30bd0 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -6,12 +6,11 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; -using osu.Game.Graphics.Containers; using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables @@ -34,8 +33,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables /// public Func CheckHittable; - private ShakeContainer shakeContainer; - protected DrawableOsuHitObject(OsuHitObject hitObject) : base(hitObject) { @@ -45,12 +42,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private void load() { Alpha = 0; - - base.AddInternal(shakeContainer = new ShakeContainer - { - ShakeDuration = 30, - RelativeSizeAxes = Axes.Both - }); } protected override void OnApply() @@ -73,18 +64,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables ScaleBindable.UnbindFrom(HitObject.ScaleBindable); } - // Forward all internal management to shakeContainer. - // This is a bit ugly but we don't have the concept of InternalContent so it'll have to do for now. (https://github.com/ppy/osu-framework/issues/1690) - protected override void AddInternal(Drawable drawable) => shakeContainer.Add(drawable); - protected override void ClearInternal(bool disposeChildren = true) => shakeContainer.Clear(disposeChildren); - protected override bool RemoveInternal(Drawable drawable, bool disposeImmediately) => shakeContainer.Remove(drawable, disposeImmediately); - protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; private OsuInputManager osuActionInputManager; internal OsuInputManager OsuActionInputManager => osuActionInputManager ??= GetContainingInputManager() as OsuInputManager; - public virtual void Shake(double maximumLength) => shakeContainer.Shake(maximumLength); + /// + /// Shake the hit object in case it was clicked far too early or late (aka "note lock"). + /// + public virtual void Shake() { } /// /// Causes this to get missed, disregarding all conditions in implementations of . diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index d83f5df7a3..3393d26e01 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -11,6 +11,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Audio; +using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Skinning; @@ -34,6 +35,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public SkinnableDrawable Body { get; private set; } + private ShakeContainer shakeContainer; + /// /// A target container which can be used to add top level elements to the slider's display. /// Intended to be used for proxy purposes only. @@ -76,10 +79,19 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { InternalChildren = new Drawable[] { - Body = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBody), _ => new DefaultSliderBody(), confineMode: ConfineMode.NoScaling), - tailContainer = new Container { RelativeSizeAxes = Axes.Both }, - tickContainer = new Container { RelativeSizeAxes = Axes.Both }, - repeatContainer = new Container { RelativeSizeAxes = Axes.Both }, + shakeContainer = new ShakeContainer + { + ShakeDuration = 30, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + Body = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBody), _ => new DefaultSliderBody(), confineMode: ConfineMode.NoScaling), + tailContainer = new Container { RelativeSizeAxes = Axes.Both }, + tickContainer = new Container { RelativeSizeAxes = Axes.Both }, + repeatContainer = new Container { RelativeSizeAxes = Axes.Both }, + } + }, + // slider head is not included in shake as it handles hit detection, and handles its own shaking. headContainer = new Container { RelativeSizeAxes = Axes.Both }, OverlayElementContainer = new Container { RelativeSizeAxes = Axes.Both, }, Ball, @@ -109,6 +121,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables PathVersion.BindTo(HitObject.Path.Version); } + public override void Shake() => shakeContainer.Shake(); + protected override void OnFree() { base.OnFree(); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index 70b1bd225f..80b9544e5b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -63,7 +63,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables pathVersion.BindTo(DrawableSlider.PathVersion); - OnShake = DrawableSlider.Shake; CheckHittable = (d, t) => DrawableSlider.CheckHittable?.Invoke(d, t) ?? true; } @@ -96,9 +95,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables return result.IsHit() ? HitResult.LargeTickHit : HitResult.LargeTickMiss; } - public Action OnShake; - - public override void Shake(double maximumLength) => OnShake?.Invoke(maximumLength); + public override void Shake() + { + base.Shake(); + DrawableSlider.Shake(); + } private void updatePosition() { From 749053481a2d0fa210754f9d53840a6852b5ad99 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 14:46:37 +0900 Subject: [PATCH 1289/2686] Update osu! hitobject implementation to avoid triggering `ClearInternal` --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs | 4 ++-- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs | 4 ++-- .../Objects/Drawables/DrawableSliderRepeat.cs | 4 ++-- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs | 4 ++-- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 09a460569a..c5992b359d 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { Origin = Anchor.Centre; - InternalChildren = new Drawable[] + AddRangeInternal(new Drawable[] { scaleContainer = new Container { @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } }, - }; + }); Size = HitArea.DrawSize; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 3393d26e01..d58a435728 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables [BackgroundDependencyLoader] private void load() { - InternalChildren = new Drawable[] + AddRangeInternal(new Drawable[] { shakeContainer = new ShakeContainer { @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables OverlayElementContainer = new Container { RelativeSizeAxes = Axes.Both, }, Ball, slidingSample = new PausableSkinnableSound { Looping = true } - }; + }); PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition); StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 1bddc603ac..7b9c0c7e40 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Origin = Anchor.Centre; Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); - InternalChild = scaleContainer = new Container + AddInternal(scaleContainer = new Container { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables }, Arrow = new ReverseArrowPiece(), } - }; + }); ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue)); } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index df3a12fe33..063d297f5a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Origin = Anchor.Centre; Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); - InternalChildren = new Drawable[] + AddRangeInternal(new Drawable[] { scaleContainer = new Container { @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) } }, - }; + }); ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue)); } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs index 3ffbe68b98..4bd98fc8b2 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Origin = Anchor.Centre; - InternalChild = scaleContainer = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderScorePoint), _ => new CircularContainer + AddInternal(scaleContainer = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderScorePoint), _ => new CircularContainer { Masking = true, Origin = Anchor.Centre, @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { Anchor = Anchor.Centre, Origin = Anchor.Centre, - }; + }); ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue)); } From e48fe3a9e23d5f40f7703812244727406e09db67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 15:17:37 +0900 Subject: [PATCH 1290/2686] Add nullability to test scene --- .../Gameplay/TestSceneColourHitErrorMeter.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs index 5fdd00a7f6..edb95ecf70 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs @@ -1,11 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable using System; using System.Diagnostics; using NUnit.Framework; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Rulesets; @@ -21,22 +21,27 @@ namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneColourHitErrorMeter : OsuTestScene { - private DependencyProvidingContainer dependencyContainer; + private DependencyProvidingContainer dependencyContainer = null!; private readonly Bindable lastJudgementResult = new Bindable(); - private ScoreProcessor scoreProcessor; + private ScoreProcessor scoreProcessor = null!; + private int iteration; - private ColourHitErrorMeter colourHitErrorMeter; + + private ColourHitErrorMeter colourHitErrorMeter = null!; public TestSceneColourHitErrorMeter() { AddSliderStep("Manual Opacity test", 0.01f, 1, 1, alpha => { - if (colourHitErrorMeter != null) colourHitErrorMeter.HitShapeOpacity.Value = alpha; + if (colourHitErrorMeter.IsNotNull()) + colourHitErrorMeter.HitShapeOpacity.Value = alpha; }); + AddSliderStep("Manual spacing test", 0, 10, 2, spacing => { - if (colourHitErrorMeter != null) colourHitErrorMeter.HitShapeSpacing.Value = spacing; + if (colourHitErrorMeter.IsNotNull()) + colourHitErrorMeter.HitShapeSpacing.Value = spacing; }); } From f3898da37ade7ba9ee848499034eecd13e31817e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 15:18:20 +0900 Subject: [PATCH 1291/2686] Rename judgement count to not mention "shape" --- .../Visual/Gameplay/TestSceneColourHitErrorMeter.cs | 2 +- .../Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs index edb95ecf70..23c7410231 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs @@ -95,7 +95,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestJudgementAmountChange() { AddRepeatStep("Add judgement", applyOneJudgement, 10); - AddStep("Judgement count change to 4", () => colourHitErrorMeter.HitShapeCount.Value = 4); + AddStep("Judgement count change to 4", () => colourHitErrorMeter.JudgementCount.Value = 4); AddRepeatStep("Add judgement", applyOneJudgement, 8); } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 8991d97bd4..08df9833d0 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private const int drawable_judgement_size = 8; [SettingSource("Judgement count", "Number of displayed judgements")] - public BindableNumber HitShapeCount { get; } = new BindableNumber(20) + public BindableNumber JudgementCount { get; } = new BindableNumber(20) { MinValue = 1, MaxValue = 30, @@ -60,7 +60,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters if (!judgement.Type.IsScorable() || judgement.Type.IsBonus()) return; - judgementsFlow.Push(GetColourForHitResult(judgement.Type), HitShapeCount.Value); + judgementsFlow.Push(GetColourForHitResult(judgement.Type), JudgementCount.Value); } protected override void LoadComplete() @@ -69,14 +69,14 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters HitShapeOpacity.BindValueChanged(_ => judgementsFlow.Alpha = HitShapeOpacity.Value, true); HitShapeSpacing.BindValueChanged(_ => { - judgementsFlow.Height = HitShapeCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; + judgementsFlow.Height = JudgementCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; judgementsFlow.Spacing = new Vector2(0, HitShapeSpacing.Value); }, true); - HitShapeCount.BindValueChanged(_ => + JudgementCount.BindValueChanged(_ => { //Used to clear out the overflowing judgement children when the value is lowered judgementsFlow.RemoveAll(_ => true, true); - judgementsFlow.Height = HitShapeCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; + judgementsFlow.Height = JudgementCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; }, true); HitShape.BindValueChanged(_ => judgementsFlow.Shape.Value = HitShape.Value, true); } From 19db7c5977dec67acc528047b80f0e9920f0cb9c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 15:19:00 +0900 Subject: [PATCH 1292/2686] Remove "Opacity" setting This should be implemented at a higher level --- .../Gameplay/TestSceneColourHitErrorMeter.cs | 14 -------------- .../Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs | 9 --------- 2 files changed, 23 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs index 23c7410231..84be2c8eb9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs @@ -32,12 +32,6 @@ namespace osu.Game.Tests.Visual.Gameplay public TestSceneColourHitErrorMeter() { - AddSliderStep("Manual Opacity test", 0.01f, 1, 1, alpha => - { - if (colourHitErrorMeter.IsNotNull()) - colourHitErrorMeter.HitShapeOpacity.Value = alpha; - }); - AddSliderStep("Manual spacing test", 0, 10, 2, spacing => { if (colourHitErrorMeter.IsNotNull()) @@ -75,14 +69,6 @@ namespace osu.Game.Tests.Visual.Gameplay protected override Ruleset CreateRuleset() => new OsuRuleset(); - [Test] - public void TestOpacityChange() - { - AddRepeatStep("Add judgement", applyOneJudgement, 5); - AddStep("Change opacity to 30%", () => colourHitErrorMeter.HitShapeOpacity.Value = 0.3f); - AddRepeatStep("Add judgement", applyOneJudgement, 5); - } - [Test] public void TestSpacingChange() { diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 08df9833d0..bed815b98e 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -28,14 +28,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Precision = 1 }; - [SettingSource("Opacity", "Visibility of the displayed judgements")] - public BindableNumber HitShapeOpacity { get; } = new BindableNumber(1) - { - MinValue = 0.01f, - MaxValue = 1, - Precision = 0.01f, - }; - [SettingSource("Spacing", "Space between each displayed judgement")] public BindableNumber HitShapeSpacing { get; } = new BindableNumber(2) { @@ -66,7 +58,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters protected override void LoadComplete() { base.LoadComplete(); - HitShapeOpacity.BindValueChanged(_ => judgementsFlow.Alpha = HitShapeOpacity.Value, true); HitShapeSpacing.BindValueChanged(_ => { judgementsFlow.Height = JudgementCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; From ae70b2c32fcf5805aafae8da1d81290b0e1bd7e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 15:21:27 +0900 Subject: [PATCH 1293/2686] Fix other weirdness in variable and description naming --- .../Gameplay/TestSceneColourHitErrorMeter.cs | 6 ++--- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 26 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs index 84be2c8eb9..fccbf092fc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs @@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddSliderStep("Manual spacing test", 0, 10, 2, spacing => { if (colourHitErrorMeter.IsNotNull()) - colourHitErrorMeter.HitShapeSpacing.Value = spacing; + colourHitErrorMeter.JudgementSpacing.Value = spacing; }); } @@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestSpacingChange() { AddRepeatStep("Add judgement", applyOneJudgement, 5); - AddStep("Change spacing", () => colourHitErrorMeter.HitShapeSpacing.Value = 10); + AddStep("Change spacing", () => colourHitErrorMeter.JudgementSpacing.Value = 10); AddRepeatStep("Add judgement", applyOneJudgement, 5); } @@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestHitErrorShapeChange() { AddRepeatStep("Add judgement", applyOneJudgement, 8); - AddStep("Change shape square", () => colourHitErrorMeter.HitShape.Value = ColourHitErrorMeter.ShapeStyle.Square); + AddStep("Change shape square", () => colourHitErrorMeter.JudgementShape.Value = ColourHitErrorMeter.ShapeStyle.Square); AddRepeatStep("Add judgement", applyOneJudgement, 10); } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index bed815b98e..48b6676020 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private const int animation_duration = 200; private const int drawable_judgement_size = 8; - [SettingSource("Judgement count", "Number of displayed judgements")] + [SettingSource("Judgement count", "The number of displayed judgements")] public BindableNumber JudgementCount { get; } = new BindableNumber(20) { MinValue = 1, @@ -28,23 +28,26 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Precision = 1 }; - [SettingSource("Spacing", "Space between each displayed judgement")] - public BindableNumber HitShapeSpacing { get; } = new BindableNumber(2) + [SettingSource("Judgement spacing", "The space between each displayed judgement")] + public BindableNumber JudgementSpacing { get; } = new BindableNumber(2) { MinValue = 0, MaxValue = 10, Precision = 0.1f }; - [SettingSource("Shape", "The shape of each displayed judgement")] - public Bindable HitShape { get; } = new Bindable(); + [SettingSource("Judgement shape", "The shape of each displayed judgement")] + public Bindable JudgementShape { get; } = new Bindable(); private readonly JudgementFlow judgementsFlow; public ColourHitErrorMeter() { AutoSizeAxes = Axes.Both; - InternalChild = judgementsFlow = new JudgementFlow(); + InternalChild = judgementsFlow = new JudgementFlow + { + Shape = { BindTarget = JudgementShape } + }; } protected override void OnNewJudgement(JudgementResult judgement) @@ -58,18 +61,19 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters protected override void LoadComplete() { base.LoadComplete(); - HitShapeSpacing.BindValueChanged(_ => + + JudgementSpacing.BindValueChanged(_ => { - judgementsFlow.Height = JudgementCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; - judgementsFlow.Spacing = new Vector2(0, HitShapeSpacing.Value); + judgementsFlow.Height = JudgementCount.Value * (drawable_judgement_size + JudgementSpacing.Value) - JudgementSpacing.Value; + judgementsFlow.Spacing = new Vector2(0, JudgementSpacing.Value); }, true); + JudgementCount.BindValueChanged(_ => { //Used to clear out the overflowing judgement children when the value is lowered judgementsFlow.RemoveAll(_ => true, true); - judgementsFlow.Height = JudgementCount.Value * (drawable_judgement_size + HitShapeSpacing.Value) - HitShapeSpacing.Value; + judgementsFlow.Height = JudgementCount.Value * (drawable_judgement_size + JudgementSpacing.Value) - JudgementSpacing.Value; }, true); - HitShape.BindValueChanged(_ => judgementsFlow.Shape.Value = HitShape.Value, true); } public override void Clear() => judgementsFlow.Clear(); From 0f663deda068ec41c2f5a5ef49e35d80d4c262e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 15:24:57 +0900 Subject: [PATCH 1294/2686] Fix changing shape causing alpha to be permanently reset to zero --- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 48b6676020..83830a73eb 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -112,6 +112,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private readonly Color4 colour; + private Container content = null!; + public HitErrorShape(Color4 colour, int size) { this.colour = colour; @@ -122,33 +124,29 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { base.LoadComplete(); + Child = content = new Container + { + RelativeSizeAxes = Axes.Both, + Colour = colour + }; + Shape.BindValueChanged(shape => { switch (shape.NewValue) { case ShapeStyle.Circle: - Child = new Circle - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Colour = colour - }; + content.Child = new Circle { RelativeSizeAxes = Axes.Both }; break; case ShapeStyle.Square: - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Colour = colour - }; + content.Child = new Box { RelativeSizeAxes = Axes.Both }; break; } }, true); - Child.FadeInFromZero(animation_duration, Easing.OutQuint); - Child.MoveToY(-DrawSize.Y); - Child.MoveToY(0, animation_duration, Easing.OutQuint); + content.FadeInFromZero(animation_duration, Easing.OutQuint); + content.MoveToY(-DrawSize.Y); + content.MoveToY(0, animation_duration, Easing.OutQuint); } public void Remove() From 26d98323ff88b318de252e7e72539169f01f9d26 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 15:45:23 +0900 Subject: [PATCH 1295/2686] Fix bindable flow, code quality, everything --- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 67 +++++++++++-------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 83830a73eb..530743137d 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -24,8 +24,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public BindableNumber JudgementCount { get; } = new BindableNumber(20) { MinValue = 1, - MaxValue = 30, - Precision = 1 + MaxValue = 50, }; [SettingSource("Judgement spacing", "The space between each displayed judgement")] @@ -46,7 +45,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters AutoSizeAxes = Axes.Both; InternalChild = judgementsFlow = new JudgementFlow { - Shape = { BindTarget = JudgementShape } + JudgementShape = { BindTarget = JudgementShape }, + JudgementSpacing = { BindTarget = JudgementSpacing }, + JudgementCount = { BindTarget = JudgementCount } }; } @@ -55,25 +56,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters if (!judgement.Type.IsScorable() || judgement.Type.IsBonus()) return; - judgementsFlow.Push(GetColourForHitResult(judgement.Type), JudgementCount.Value); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - JudgementSpacing.BindValueChanged(_ => - { - judgementsFlow.Height = JudgementCount.Value * (drawable_judgement_size + JudgementSpacing.Value) - JudgementSpacing.Value; - judgementsFlow.Spacing = new Vector2(0, JudgementSpacing.Value); - }, true); - - JudgementCount.BindValueChanged(_ => - { - //Used to clear out the overflowing judgement children when the value is lowered - judgementsFlow.RemoveAll(_ => true, true); - judgementsFlow.Height = JudgementCount.Value * (drawable_judgement_size + JudgementSpacing.Value) - JudgementSpacing.Value; - }, true); + judgementsFlow.Push(GetColourForHitResult(judgement.Type)); } public override void Clear() => judgementsFlow.Clear(); @@ -82,7 +65,11 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); - public readonly Bindable Shape = new Bindable(); + public readonly Bindable JudgementShape = new Bindable(); + + public readonly Bindable JudgementSpacing = new Bindable(); + + public readonly Bindable JudgementCount = new Bindable(); public JudgementFlow() { @@ -92,15 +79,41 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters LayoutEasing = Easing.OutQuint; } - public void Push(Color4 colour, int maxErrorShapeCount) + protected override void LoadComplete() + { + base.LoadComplete(); + + JudgementCount.BindValueChanged(count => + { + removeExtraJudgements(); + updateMetrics(); + }); + + JudgementSpacing.BindValueChanged(_ => updateMetrics(), true); + } + + public void Push(Color4 colour) { Add(new HitErrorShape(colour, drawable_judgement_size) { - Shape = { BindTarget = Shape }, + Shape = { BindTarget = JudgementShape }, }); - if (Children.Count > maxErrorShapeCount) - Children.FirstOrDefault(c => !c.IsRemoved)?.Remove(); + removeExtraJudgements(); + } + + private void removeExtraJudgements() + { + var remainingChildren = Children.Where(c => !c.IsRemoved); + + while (remainingChildren.Count() > JudgementCount.Value) + remainingChildren.First().Remove(); + } + + private void updateMetrics() + { + Height = JudgementCount.Value * (drawable_judgement_size + JudgementSpacing.Value) - JudgementSpacing.Value; + Spacing = new Vector2(0, JudgementSpacing.Value); } } From 1ed4b9c11c1ce300022e505ec91c9258fa16b9f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 15:45:30 +0900 Subject: [PATCH 1296/2686] Add more flexibility to test --- .../Visual/Gameplay/TestSceneColourHitErrorMeter.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs index fccbf092fc..a953db4f19 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs @@ -32,11 +32,17 @@ namespace osu.Game.Tests.Visual.Gameplay public TestSceneColourHitErrorMeter() { - AddSliderStep("Manual spacing test", 0, 10, 2, spacing => + AddSliderStep("Judgement spacing", 0, 10, 2, spacing => { if (colourHitErrorMeter.IsNotNull()) colourHitErrorMeter.JudgementSpacing.Value = spacing; }); + + AddSliderStep("Judgement count", 1, 50, 5, spacing => + { + if (colourHitErrorMeter.IsNotNull()) + colourHitErrorMeter.JudgementCount.Value = spacing; + }); } [SetUpSteps] @@ -91,6 +97,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddRepeatStep("Add judgement", applyOneJudgement, 8); AddStep("Change shape square", () => colourHitErrorMeter.JudgementShape.Value = ColourHitErrorMeter.ShapeStyle.Square); AddRepeatStep("Add judgement", applyOneJudgement, 10); + AddStep("Change shape circle", () => colourHitErrorMeter.JudgementShape.Value = ColourHitErrorMeter.ShapeStyle.Circle); } private void applyOneJudgement() From f0dcda9accbf4e67060407ec3c49e4a758953069 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 15:49:02 +0900 Subject: [PATCH 1297/2686] Decrease precision of spacing setting --- osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 530743137d..dadec7c06b 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -32,7 +32,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { MinValue = 0, MaxValue = 10, - Precision = 0.1f }; [SettingSource("Judgement shape", "The shape of each displayed judgement")] From 0458305a23f801928f85f1a587961732adb68d96 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 17:40:19 +0900 Subject: [PATCH 1298/2686] Add argon judgement bubbles --- .../Skinning/Argon/ArgonJudgementPiece.cs | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs index 315b9ec65e..b08b7b4e85 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs @@ -1,14 +1,17 @@ // 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.Allocation; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Rulesets.Scoring; using osuTK; @@ -20,6 +23,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon protected SpriteText JudgementText { get; private set; } = null!; + private RingExplosion? ringExplosion; + [Resolved] private OsuColour colours { get; set; } = null!; @@ -42,10 +47,19 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Origin = Anchor.Centre, Text = Result.GetDescription().ToUpperInvariant(), Colour = colours.ForHitResult(Result), + Blending = BlendingParameters.Additive, Spacing = new Vector2(5, 0), Font = OsuFont.Default.With(size: 20, weight: FontWeight.Bold), - } + }, }; + + if (Result.IsHit()) + { + AddInternal(ringExplosion = new RingExplosion(Result) + { + Colour = colours.ForHitResult(Result), + }); + } } /// @@ -78,8 +92,80 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } this.FadeOutFromOne(800); + + ringExplosion?.PlayAnimation(); } public Drawable? GetAboveHitObjectsProxiedContent() => null; + + private class RingExplosion : CompositeDrawable + { + private readonly float travel = 52; + + public RingExplosion(HitResult result) + { + const float thickness = 4; + + const float small_size = 9; + const float large_size = 14; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Blending = BlendingParameters.Additive; + + int countSmall = 0; + int countLarge = 0; + + switch (result) + { + case HitResult.Meh: + countSmall = 3; + travel *= 0.3f; + break; + + case HitResult.Ok: + case HitResult.Good: + countSmall = 4; + travel *= 0.6f; + break; + + case HitResult.Great: + case HitResult.Perfect: + countSmall = 4; + countLarge = 4; + break; + } + + for (int i = 0; i < countSmall; i++) + AddInternal(new RingPiece(thickness) { Size = new Vector2(small_size) }); + + for (int i = 0; i < countLarge; i++) + AddInternal(new RingPiece(thickness) { Size = new Vector2(large_size) }); + } + + public void PlayAnimation() + { + foreach (var c in InternalChildren) + { + const float start_position_ratio = 0.3f; + + float direction = RNG.NextSingle(0, 360); + float distance = RNG.NextSingle(travel / 2, travel); + + c.MoveTo(new Vector2( + MathF.Cos(direction) * distance * start_position_ratio, + MathF.Sin(direction) * distance * start_position_ratio + )); + + c.MoveTo(new Vector2( + MathF.Cos(direction) * distance, + MathF.Sin(direction) * distance + ), 600, Easing.OutQuint); + } + + this.FadeOutFromOne(1000, Easing.OutQuint); + } + } } } From b321afc3a67da245eb23e7052b02e07defb5a433 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 18:00:02 +0900 Subject: [PATCH 1299/2686] Update framework --- osu.Android.props | 2 +- osu.Game/OsuGame.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 77c29a5d6e..dd263d6aaa 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 9a63ccbf48..7e6bd7c7be 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1041,7 +1041,7 @@ namespace osu.Game Logger.NewEntry += entry => { - if (entry.Level < LogLevel.Important || !entry.LoggerName.Equals(ITabletHandler.LOGGER_NAME, StringComparison.OrdinalIgnoreCase)) + if (entry.Level < LogLevel.Important || entry.Target != LoggingTarget.Input || !entry.Message.StartsWith(@"[Tablet]", StringComparison.Ordinal)) return; if (entry.Level == LogLevel.Error) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 29e690a024..c4e2a5168e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 83410b08f6..622efcd63d 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -82,7 +82,7 @@ - + From 68015ef10c14ec9f21dfc3fa3718a71a1ec22aa1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 18:12:28 +0900 Subject: [PATCH 1300/2686] Fix argon reverse arrow becoming white after switching skins --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index 3f13fe135e..9d44db3614 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon }; accentColour = hitObject.AccentColour.GetBoundCopy(); - accentColour.BindValueChanged(accent => icon.Colour = accent.NewValue.Darken(4)); + accentColour.BindValueChanged(accent => icon.Colour = accent.NewValue.Darken(4), true); } } } From fa3f53f39f59439a011f19a1886105ad91152810 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 22 Sep 2022 12:37:21 +0300 Subject: [PATCH 1301/2686] Remove tablet prefix from error notification --- osu.Game/OsuGame.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 7e6bd7c7be..1f0c27b286 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1037,18 +1037,21 @@ namespace osu.Game private void forwardTabletLogsToNotifications() { + const string tablet_prefix = @"[Tablet] "; bool notifyOnWarning = true; Logger.NewEntry += entry => { - if (entry.Level < LogLevel.Important || entry.Target != LoggingTarget.Input || !entry.Message.StartsWith(@"[Tablet]", StringComparison.Ordinal)) + if (entry.Level < LogLevel.Important || entry.Target != LoggingTarget.Input || !entry.Message.StartsWith(tablet_prefix, StringComparison.Ordinal)) return; + string message = entry.Message.Replace(tablet_prefix, string.Empty); + if (entry.Level == LogLevel.Error) { Schedule(() => Notifications.Post(new SimpleNotification { - Text = $"Encountered tablet error: \"{entry.Message}\"", + Text = $"Encountered tablet error: \"{message}\"", Icon = FontAwesome.Solid.PenSquare, IconColour = Colours.RedDark, })); From ea7c5458fe091c61ca854be4640b48b4d3e5fd78 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 18:43:41 +0900 Subject: [PATCH 1302/2686] Fix sprite dropdown not showing resources from non-legacy skins during gameplay --- .../Skinning/Legacy/LegacyNewStyleSpinner.cs | 2 +- osu.Game/Skinning/ISkinTransformer.cs | 17 +++++++++++++++++ osu.Game/Skinning/LegacySkinTransformer.cs | 5 +---- osu.Game/Skinning/SkinnableSprite.cs | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Skinning/ISkinTransformer.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs index d5cc469ca9..22944becf3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs @@ -82,7 +82,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy var topProvider = source.FindProvider(s => s.GetTexture("spinner-top") != null); - if (topProvider is LegacySkinTransformer transformer && !(transformer.Skin is DefaultLegacySkin)) + if (topProvider is ISkinTransformer transformer && !(transformer.Skin is DefaultLegacySkin)) { AddInternal(ApproachCircle = new Sprite { diff --git a/osu.Game/Skinning/ISkinTransformer.cs b/osu.Game/Skinning/ISkinTransformer.cs new file mode 100644 index 0000000000..f985b8afcd --- /dev/null +++ b/osu.Game/Skinning/ISkinTransformer.cs @@ -0,0 +1,17 @@ +// 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.Skinning +{ + /// + /// A skin transformer takes in an and applies transformations to it. + /// The most common use case is allowing individual rulesets to add skinnable components without directly coupling to underlying skins. + /// + public interface ISkinTransformer : ISkin + { + /// + /// The original skin that is being transformed. + /// + ISkin Skin { get; } + } +} diff --git a/osu.Game/Skinning/LegacySkinTransformer.cs b/osu.Game/Skinning/LegacySkinTransformer.cs index 8f2526db37..353ee067d1 100644 --- a/osu.Game/Skinning/LegacySkinTransformer.cs +++ b/osu.Game/Skinning/LegacySkinTransformer.cs @@ -18,11 +18,8 @@ namespace osu.Game.Skinning /// /// Transformer used to handle support of legacy features for individual rulesets. /// - public abstract class LegacySkinTransformer : ISkin + public abstract class LegacySkinTransformer : ISkinTransformer { - /// - /// The which is being transformed. - /// [NotNull] public ISkin Skin { get; } diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index f8a9aaa6fb..5a39121b16 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -100,7 +100,7 @@ namespace osu.Game.Skinning { foreach (var skin in skins) { - if (skin is LegacySkinTransformer transformer && isUserSkin(transformer.Skin)) + if (skin is ISkinTransformer transformer && isUserSkin(transformer.Skin)) return transformer.Skin; if (isUserSkin(skin)) From f8e9a960ba1bc1756185eabee09c1b2201f4da99 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 18:44:04 +0900 Subject: [PATCH 1303/2686] Fix argon skin not forwarding resource lookups to user backing --- .../Skinning/Argon/OsuArgonSkinTransformer.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 8a1bf00877..1a569edc3e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -11,10 +11,13 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class OsuArgonSkinTransformer : ISkin + public class OsuArgonSkinTransformer : ISkinTransformer { + public ISkin Skin { get; } + public OsuArgonSkinTransformer(ISkin skin) { + Skin = skin; } public Drawable? GetDrawableComponent(ISkinComponent component) @@ -55,15 +58,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon return null; } - public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) - { - return null; - } + public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Skin.GetTexture(componentName, wrapModeS, wrapModeT); - public ISample? GetSample(ISampleInfo sampleInfo) - { - return null; - } + public ISample? GetSample(ISampleInfo sampleInfo) => Skin.GetSample(sampleInfo); public IBindable? GetConfig(TLookup lookup) where TLookup : notnull where TValue : notnull { From 74aefdc5bd690574d3d9ca369cbde4355595f28c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 18:50:19 +0900 Subject: [PATCH 1304/2686] Move basic transformer behaviour to base `abstract` class --- .../Skinning/Argon/OsuArgonSkinTransformer.cs | 23 +++---------- osu.Game/Skinning/LegacySkinTransformer.cs | 29 +++-------------- osu.Game/Skinning/SkinTransformer.cs | 32 +++++++++++++++++++ 3 files changed, 41 insertions(+), 43 deletions(-) create mode 100644 osu.Game/Skinning/SkinTransformer.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 1a569edc3e..3e5bfd25b5 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -1,26 +1,20 @@ // 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.Audio.Sample; -using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Textures; -using osu.Game.Audio; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class OsuArgonSkinTransformer : ISkinTransformer + public class OsuArgonSkinTransformer : SkinTransformer { - public ISkin Skin { get; } - public OsuArgonSkinTransformer(ISkin skin) + : base(skin) { - Skin = skin; } - public Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinComponent component) { switch (component) { @@ -55,16 +49,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon break; } - return null; - } - - public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Skin.GetTexture(componentName, wrapModeS, wrapModeT); - - public ISample? GetSample(ISampleInfo sampleInfo) => Skin.GetSample(sampleInfo); - - public IBindable? GetConfig(TLookup lookup) where TLookup : notnull where TValue : notnull - { - return null; + return base.GetDrawableComponent(component); } } } diff --git a/osu.Game/Skinning/LegacySkinTransformer.cs b/osu.Game/Skinning/LegacySkinTransformer.cs index 353ee067d1..2de1564a5c 100644 --- a/osu.Game/Skinning/LegacySkinTransformer.cs +++ b/osu.Game/Skinning/LegacySkinTransformer.cs @@ -1,14 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using System; -using JetBrains.Annotations; using osu.Framework.Audio.Sample; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Textures; using osu.Game.Audio; using osu.Game.Rulesets.Objects.Legacy; using static osu.Game.Skinning.SkinConfiguration; @@ -18,24 +11,14 @@ namespace osu.Game.Skinning /// /// Transformer used to handle support of legacy features for individual rulesets. /// - public abstract class LegacySkinTransformer : ISkinTransformer + public abstract class LegacySkinTransformer : SkinTransformer { - [NotNull] - public ISkin Skin { get; } - - protected LegacySkinTransformer([NotNull] ISkin skin) + protected LegacySkinTransformer(ISkin skin) + : base(skin) { - Skin = skin ?? throw new ArgumentNullException(nameof(skin)); } - public virtual Drawable GetDrawableComponent(ISkinComponent component) => Skin.GetDrawableComponent(component); - - public Texture GetTexture(string componentName) => GetTexture(componentName, default, default); - - public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) - => Skin.GetTexture(componentName, wrapModeS, wrapModeT); - - public virtual ISample GetSample(ISampleInfo sampleInfo) + public override ISample? GetSample(ISampleInfo sampleInfo) { if (!(sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacySample)) return Skin.GetSample(sampleInfo); @@ -44,9 +27,7 @@ namespace osu.Game.Skinning if (legacySample.IsLayered && playLayeredHitSounds?.Value == false) return new SampleVirtual(); - return Skin.GetSample(sampleInfo); + return base.GetSample(sampleInfo); } - - public virtual IBindable GetConfig(TLookup lookup) => Skin.GetConfig(lookup); } } diff --git a/osu.Game/Skinning/SkinTransformer.cs b/osu.Game/Skinning/SkinTransformer.cs new file mode 100644 index 0000000000..4da60f1e43 --- /dev/null +++ b/osu.Game/Skinning/SkinTransformer.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 System; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; +using osu.Game.Audio; + +namespace osu.Game.Skinning +{ + public abstract class SkinTransformer : ISkinTransformer + { + public ISkin Skin { get; } + + protected SkinTransformer(ISkin skin) + { + Skin = skin ?? throw new ArgumentNullException(nameof(skin)); + } + + public virtual Drawable? GetDrawableComponent(ISkinComponent component) => Skin.GetDrawableComponent(component); + + public virtual Texture? GetTexture(string componentName) => GetTexture(componentName, default, default); + + public virtual Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Skin.GetTexture(componentName, wrapModeS, wrapModeT); + + public virtual ISample? GetSample(ISampleInfo sampleInfo) => Skin.GetSample(sampleInfo); + + public virtual IBindable? GetConfig(TLookup lookup) where TLookup : notnull where TValue : notnull => Skin.GetConfig(lookup); + } +} From 794a1319546163d2aa91b08a90d2a800f82393c1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 22 Sep 2022 13:17:01 +0300 Subject: [PATCH 1305/2686] Update method name and conditions --- osu.Game/OsuGame.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1f0c27b286..ff974820a7 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -188,7 +188,7 @@ namespace osu.Game { this.args = args; - forwardRuntimeLogsToNotifications(); + forwardGeneralLogsToNotifications(); forwardTabletLogsToNotifications(); SentryLogger = new SentryLogger(this); @@ -994,7 +994,7 @@ namespace osu.Game overlay.Depth = (float)-Clock.CurrentTime; } - private void forwardRuntimeLogsToNotifications() + private void forwardGeneralLogsToNotifications() { int recentLogCount = 0; @@ -1002,7 +1002,7 @@ namespace osu.Game Logger.NewEntry += entry => { - if (entry.Level < LogLevel.Important || entry.Target == null) return; + if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database) return; const int short_term_display_limit = 3; From fd92bcdff255bfcf69d1dab1f54fdc4fc9b4fec2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 22 Sep 2022 13:21:27 +0300 Subject: [PATCH 1306/2686] Ignore case sensitivity during message comparison Co-authored-by: Dan Balasescu --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ff974820a7..474c855c3d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1042,7 +1042,7 @@ namespace osu.Game Logger.NewEntry += entry => { - if (entry.Level < LogLevel.Important || entry.Target != LoggingTarget.Input || !entry.Message.StartsWith(tablet_prefix, StringComparison.Ordinal)) + if (entry.Level < LogLevel.Important || entry.Target != LoggingTarget.Input || !entry.Message.StartsWith(tablet_prefix, StringComparison.OrdinalIgnoreCase)) return; string message = entry.Message.Replace(tablet_prefix, string.Empty); From 4528c1037b4fb5541364b54cf1a20c699e19fed3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 22 Sep 2022 19:26:12 +0900 Subject: [PATCH 1307/2686] Resolve CI inspections --- .../Mods/TestSceneOsuModDifficultyAdjust.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs index e5b7208da6..88b6b9dd56 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; -using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; From 5243ff3c2252b8a3bf37580018c8b7d753a1a6b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 19:16:49 +0900 Subject: [PATCH 1308/2686] Add argon combo colours I'm 99% sure these are just test colours flyte was using, but they look good so let's go with them. I've added two new colours to increase the default combo colour rotation to 6. The initial ordering still matches, for whatever that's worth. --- osu.Game/Skinning/ArgonSkin.cs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 2c17b28b01..010e2175e1 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -44,6 +44,28 @@ namespace osu.Game.Skinning : base(skin, resources) { this.resources = resources; + + Configuration.CustomComboColours = new List + { + // Standard combo progression order is green - blue - red - yellow. + // But for whatever reason, this starts from index 1, not 0. + // + // We've added two new combo colours in argon, so to ensure the initial rotation matches, + // this same progression is in slots 1 - 4. + + // Orange + new Color4(241, 116, 0, 255), + // Green + new Color4(0, 241, 53, 255), + // Blue + new Color4(0, 82, 241, 255), + // Red + new Color4(241, 0, 0, 255), + // Yellow + new Color4(232, 235, 0, 255), + // Purple + new Color4(92, 0, 241, 255), + }; } public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Textures?.Get(componentName, wrapModeS, wrapModeT); From 8f7a306d81a721878c7be093e17445e57f4ed3de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 19:53:16 +0900 Subject: [PATCH 1309/2686] Inline comment regarding margin necessity --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index c4d81e7e2a..05a04c3bae 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -96,6 +96,13 @@ namespace osu.Game.Screens.Play.HUD int displayCount = Math.Min(Flow.Count, maxPanels); Height = displayCount * (GameplayLeaderboardScore.PANEL_HEIGHT + Flow.Spacing.Y); + // Add extra margin space to flow equal to height of leaderboard. + // This ensures the content is always on screen, but also accounts for the fact that scroll operations + // without animation were actually forcing the local score to a location it can't usually reside at. + // + // Basically, the local score was in the scroll extension region (due to always trying to scroll the + // local player to the middle of the display, but there being no other content below the local player + // to scroll up by). Flow.Margin = new MarginPadding { Bottom = Height }; requiresScroll = displayCount != Flow.Count; From 7508592789b08cb27097449c36b0f78d32061dfe Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 22 Sep 2022 19:56:24 +0900 Subject: [PATCH 1310/2686] Clean up some checks --- osu.Game/Online/Leaderboards/Leaderboard.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index d5834c4329..569015dcd3 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -169,7 +169,7 @@ namespace osu.Game.Online.Leaderboards throw new InvalidOperationException($"State {state} cannot be set by a leaderboard implementation."); } - Debug.Assert(scores.Any() != true); + Debug.Assert(scores.Any()); setState(state); } @@ -258,7 +258,7 @@ namespace osu.Game.Online.Leaderboards .Expire(); scoreFlowContainer = null; - if (scores.Any() != true) + if (scores.Any()) { setState(LeaderboardState.NoScores); return; From 8875f7ee4334fba722fd5999083ee6e485c99f2b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 20:06:24 +0900 Subject: [PATCH 1311/2686] Add very basic follow point implementation for argon skin This is just something to look better than the glowing mess which triangles fallback was providing. This element hasn't been designed yet, so I'm just filling in with something amicable for the time being. --- .../Skinning/Argon/ArgonFollowPoint.cs | 39 +++++++++++++++++++ .../Skinning/Argon/OsuArgonSkinTransformer.cs | 3 ++ 2 files changed, 42 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowPoint.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowPoint.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowPoint.cs new file mode 100644 index 0000000000..47dae3c30a --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowPoint.cs @@ -0,0 +1,39 @@ +// 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.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonFollowPoint : CompositeDrawable + { + public ArgonFollowPoint() + { + Blending = BlendingParameters.Additive; + + Colour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")); + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.ChevronRight, + Size = new Vector2(8), + Colour = OsuColour.Gray(0.2f), + }, + new SpriteIcon + { + Icon = FontAwesome.Solid.ChevronRight, + Size = new Vector2(8), + X = 4, + }, + }; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 3e5bfd25b5..9ce4323c35 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -44,6 +44,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon case OsuSkinComponents.ReverseArrow: return new ArgonReverseArrow(); + + case OsuSkinComponents.FollowPoint: + return new ArgonFollowPoint(); } break; From 37e25792443331c9dc8cbcdd0217273c11c36b83 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 20:35:26 +0900 Subject: [PATCH 1312/2686] Fix reversed checks --- osu.Game/Online/Leaderboards/Leaderboard.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 569015dcd3..206c15afde 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -169,7 +169,7 @@ namespace osu.Game.Online.Leaderboards throw new InvalidOperationException($"State {state} cannot be set by a leaderboard implementation."); } - Debug.Assert(scores.Any()); + Debug.Assert(!scores.Any()); setState(state); } @@ -258,7 +258,7 @@ namespace osu.Game.Online.Leaderboards .Expire(); scoreFlowContainer = null; - if (scores.Any()) + if (!scores.Any()) { setState(LeaderboardState.NoScores); return; From a2ff31f37d73f55e449f17cf33f144de624923cd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 20:43:38 +0900 Subject: [PATCH 1313/2686] Fix failing test --- osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 182cc51572..cca87d42a1 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -250,11 +250,9 @@ namespace osu.Game.Rulesets.Catch.Tests [Test] public void TestHitLightingColour() { - var fruitColour = SkinConfiguration.DefaultComboColours[1]; AddStep("enable hit lighting", () => config.SetValue(OsuSetting.HitLighting, true)); AddStep("catch fruit", () => attemptCatch(new Fruit())); - AddAssert("correct hit lighting colour", () => - catcher.ChildrenOfType().First()?.Entry?.ObjectColour == fruitColour); + AddAssert("correct hit lighting colour", () => catcher.ChildrenOfType().First()?.Entry?.ObjectColour == this.ChildrenOfType().First().AccentColour.Value); } [Test] From 7527d815e83cbc3745c876d8115154df28f3aea4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 22 Sep 2022 20:58:23 +0900 Subject: [PATCH 1314/2686] Remove unused using --- osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index cca87d42a1..2dc99077d3 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -21,7 +21,6 @@ using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; using osu.Game.Tests.Visual; using osuTK; From 6a0047b7a224dee2b012ffc922c8d73a2c2a55f6 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 22 Sep 2022 21:01:23 +0900 Subject: [PATCH 1315/2686] Update location of FullscreenCapability bindable --- .../Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 4 ++-- osu.Game/Screens/Utility/LatencyCertifierScreen.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 28642f12a1..c64a3101b7 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -73,8 +73,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics windowModes.BindTo(host.Window.SupportedWindowModes); } - if (host.Window is WindowsWindow windowsWindow) - fullscreenCapability.BindTo(windowsWindow.FullscreenCapability); + if (host.Renderer is IWindowsRenderer windowsRenderer) + fullscreenCapability.BindTo(windowsRenderer.FullscreenCapability); Children = new Drawable[] { diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index c9d4dc7811..bacaccd68e 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -261,8 +261,8 @@ namespace osu.Game.Screens.Utility string exclusive = "unknown"; - if (host.Window is WindowsWindow windowsWindow) - exclusive = windowsWindow.FullscreenCapability.ToString(); + if (host.Renderer is IWindowsRenderer windowsRenderer) + exclusive = windowsRenderer.FullscreenCapability.ToString(); statusText.Clear(); From e95758cfcd630170fb24f860800b9a13f9983661 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 22 Sep 2022 20:39:46 +0900 Subject: [PATCH 1316/2686] Add basic "argon" cursor --- .../Skinning/Argon/ArgonCursor.cs | 80 +++++++++++++++++++ .../Skinning/Argon/ArgonCursorTrail.cs | 29 +++++++ .../Skinning/Argon/OsuArgonSkinTransformer.cs | 6 ++ 3 files changed, 115 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursor.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursorTrail.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursor.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursor.cs new file mode 100644 index 0000000000..446f3c83ae --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursor.cs @@ -0,0 +1,80 @@ +// 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.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Osu.UI.Cursor; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonCursor : OsuCursorSprite + { + public ArgonCursor() + { + RelativeSizeAxes = Axes.Both; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + InternalChildren = new[] + { + ExpandTarget = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + BorderThickness = 6, + BorderColour = ColourInfo.GradientVertical(Colour4.FromHex("FC618F"), Colour4.FromHex("BB1A41")), + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.4f, + Colour = Colour4.FromHex("FC618F").Darken(0.6f), + }, + new CircularContainer + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + BorderThickness = 2, + BorderColour = Color4.White.Opacity(0.8f), + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + }, + }, + }, + }, + }, + new Circle + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.2f), + Colour = new Color4(255, 255, 255, 255), + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Radius = 20, + Colour = new Color4(171, 255, 255, 100), + }, + }, + }; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursorTrail.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursorTrail.cs new file mode 100644 index 0000000000..9bb3122a3b --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursorTrail.cs @@ -0,0 +1,29 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Textures; +using osu.Game.Rulesets.Osu.UI.Cursor; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonCursorTrail : CursorTrail + { + protected override float IntervalMultiplier => 0.4f; + + protected override float FadeExponent => 4; + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + Texture = textures.Get(@"Cursor/cursortrail"); + Scale = new Vector2(0.8f / Texture.ScaleAdjust); + + Blending = BlendingParameters.Additive; + + Alpha = 0.8f; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 9ce4323c35..ead49a8af2 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -47,6 +47,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon case OsuSkinComponents.FollowPoint: return new ArgonFollowPoint(); + + case OsuSkinComponents.Cursor: + return new ArgonCursor(); + + case OsuSkinComponents.CursorTrail: + return new ArgonCursorTrail(); } break; From 3811ea113d993b9e2705cc3ed93a22b6d2d5cd01 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Sep 2022 00:53:52 +0900 Subject: [PATCH 1317/2686] Adjust argon animations a bit --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 0479b3ff3e..ffdcba3cdb 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon const double fade_out_time = 800; const double flash_in_duration = 150; - const double resize_duration = 300; + const double resize_duration = 400; const float shrink_size = 0.8f; @@ -165,13 +165,19 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon // The outer gradient is resize with a slight delay from the border. // This is to give it a bomb-like effect, with the border "triggering" its animation when getting close. using (BeginDelayedSequence(flash_in_duration / 12)) + { outerGradient.ResizeTo(outerGradient.Size * shrink_size, resize_duration, Easing.OutElasticHalf); + outerGradient + .FadeColour(Color4.White, 80) + .Then() + .FadeOut(flash_in_duration); + } // The flash layer starts white to give the wanted brightness, but is almost immediately // recoloured to the accent colour. This would more correctly be done with two layers (one for the initial flash) // but works well enough with the colour fade. flash.FadeTo(1, flash_in_duration, Easing.OutQuint); - flash.FlashColour(Color4.White, flash_in_duration, Easing.OutQuint); + flash.FlashColour(accentColour.Value, fade_out_time, Easing.OutQuint); this.FadeOut(fade_out_time, Easing.OutQuad); break; From e9c3478f69359f861ecadc1524461b8ffb735826 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 22 Sep 2022 20:07:40 +0300 Subject: [PATCH 1318/2686] Add very basic "argon" spinner --- .../Skinning/Argon/ArgonSpinner.cs | 146 +++++++++++ .../Skinning/Argon/ArgonSpinnerDisc.cs | 247 ++++++++++++++++++ .../Skinning/Argon/ArgonSpinnerTicks.cs | 61 +++++ .../Skinning/Argon/OsuArgonSkinTransformer.cs | 3 + 4 files changed, 457 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerTicks.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs new file mode 100644 index 0000000000..f9b2f84984 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs @@ -0,0 +1,146 @@ +// 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.Globalization; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonSpinner : CompositeDrawable + { + private DrawableSpinner drawableSpinner = null!; + + private OsuSpriteText bonusCounter = null!; + + private Container spmContainer = null!; + private OsuSpriteText spmCounter = null!; + + [BackgroundDependencyLoader] + private void load(DrawableHitObject drawableHitObject) + { + RelativeSizeAxes = Axes.Both; + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + drawableSpinner = (DrawableSpinner)drawableHitObject; + + InternalChildren = new Drawable[] + { + bonusCounter = new OsuSpriteText + { + Alpha = 0, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Default.With(size: 24), + Y = -120, + }, + new ArgonSpinnerDisc + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + bonusCounter = new OsuSpriteText + { + Alpha = 0, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Default.With(size: 28, weight: FontWeight.Bold), + Y = -120, + }, + spmContainer = new Container + { + Alpha = 0f, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Y = 100, + Children = new[] + { + spmCounter = new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = @"0", + Font = OsuFont.Default.With(size: 28, weight: FontWeight.SemiBold) + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = @"SPINS PER MINUTE", + Font = OsuFont.Default.With(size: 16, weight: FontWeight.SemiBold), + Y = 30 + } + } + } + }; + } + + private IBindable gainedBonus = null!; + private IBindable spinsPerMinute = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + gainedBonus = drawableSpinner.GainedBonus.GetBoundCopy(); + gainedBonus.BindValueChanged(bonus => + { + bonusCounter.Text = bonus.NewValue.ToString(NumberFormatInfo.InvariantInfo); + bonusCounter.FadeOutFromOne(1500); + bonusCounter.ScaleTo(1.5f).Then().ScaleTo(1f, 1000, Easing.OutQuint); + }); + + spinsPerMinute = drawableSpinner.SpinsPerMinute.GetBoundCopy(); + spinsPerMinute.BindValueChanged(spm => + { + spmCounter.Text = Math.Truncate(spm.NewValue).ToString(@"#0"); + }, true); + + drawableSpinner.ApplyCustomUpdateState += updateStateTransforms; + updateStateTransforms(drawableSpinner, drawableSpinner.State.Value); + } + + protected override void Update() + { + base.Update(); + + if (!spmContainer.IsPresent && drawableSpinner.Result?.TimeStarted != null) + fadeCounterOnTimeStart(); + } + + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) + { + if (!(drawableHitObject is DrawableSpinner)) + return; + + fadeCounterOnTimeStart(); + } + + private void fadeCounterOnTimeStart() + { + if (drawableSpinner.Result?.TimeStarted is double startTime) + { + using (BeginAbsoluteSequence(startTime)) + spmContainer.FadeIn(drawableSpinner.HitObject.TimeFadeIn); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (drawableSpinner.IsNotNull()) + drawableSpinner.ApplyCustomUpdateState -= updateStateTransforms; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs new file mode 100644 index 0000000000..a6211ecb01 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -0,0 +1,247 @@ +// 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.Diagnostics; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Skinning.Default; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonSpinnerDisc : CompositeDrawable + { + private const float initial_scale = 1.3f; + private const float idle_alpha = 0.2f; + private const float tracking_alpha = 0.4f; + + private const float idle_centre_size = 80f; + private const float tracking_centre_size = 40f; + + private DrawableSpinner drawableSpinner = null!; + + private readonly BindableBool complete = new BindableBool(); + + private int wholeRotationCount; + + private bool checkNewRotationCount + { + get + { + int rotations = (int)(drawableSpinner.Result.RateAdjustedRotation / 360); + + if (wholeRotationCount == rotations) return false; + + wholeRotationCount = rotations; + return true; + } + } + + private Container disc = null!; + private Container centre = null!; + private CircularContainer fill = null!; + + [BackgroundDependencyLoader] + private void load(DrawableHitObject drawableHitObject) + { + drawableSpinner = (DrawableSpinner)drawableHitObject; + + // we are slightly bigger than our parent, to clip the top and bottom of the circle + // this should probably be revisited when scaled spinners are a thing. + Scale = new Vector2(initial_scale); + + InternalChildren = new Drawable[] + { + disc = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + fill = new CircularContainer + { + Name = @"Fill", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Colour4.FromHex("FC618F").Opacity(1f), + Radius = 40, + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0f, + AlwaysPresent = true, + } + }, + new CircularContainer + { + Name = @"Ring", + Masking = true, + BorderColour = Color4.White, + BorderThickness = 5, + RelativeSizeAxes = Axes.Both, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + } + }, + new ArgonSpinnerTicks(), + } + }, + centre = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(idle_centre_size), + Children = new[] + { + new RingPiece(10) + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.8f), + }, + new RingPiece(3) + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(1f), + } + }, + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + drawableSpinner.ApplyCustomUpdateState += updateStateTransforms; + + updateStateTransforms(drawableSpinner, drawableSpinner.State.Value); + } + + protected override void Update() + { + base.Update(); + + complete.Value = Time.Current >= drawableSpinner.Result.TimeCompleted; + + if (complete.Value) + { + if (checkNewRotationCount) + { + fill.FinishTransforms(false, nameof(Alpha)); + fill + .FadeTo(tracking_alpha + 0.2f, 60, Easing.OutExpo) + .Then() + .FadeTo(tracking_alpha, 250, Easing.OutQuint); + } + } + else + { + fill.Alpha = (float)Interpolation.Damp(fill.Alpha, drawableSpinner.RotationTracker.Tracking ? tracking_alpha : idle_alpha, 0.98f, (float)Math.Abs(Clock.ElapsedFrameTime)); + } + + if (centre.Width == idle_centre_size && drawableSpinner.Result?.TimeStarted != null) + updateCentrePieceSize(); + + const float initial_fill_scale = 0.1f; + float targetScale = initial_fill_scale + (0.98f - initial_fill_scale) * drawableSpinner.Progress; + + fill.Scale = new Vector2((float)Interpolation.Lerp(fill.Scale.X, targetScale, Math.Clamp(Math.Abs(Time.Elapsed) / 100, 0, 1))); + disc.Rotation = drawableSpinner.RotationTracker.Rotation; + } + + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) + { + if (!(drawableHitObject is DrawableSpinner)) + return; + + Spinner spinner = drawableSpinner.HitObject; + + using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt)) + { + this.ScaleTo(initial_scale); + this.RotateTo(0); + + using (BeginDelayedSequence(spinner.TimePreempt / 2)) + { + // constant ambient rotation to give the spinner "spinning" character. + this.RotateTo((float)(25 * spinner.Duration / 2000), spinner.TimePreempt + spinner.Duration); + } + + using (BeginDelayedSequence(spinner.TimePreempt + spinner.Duration + drawableHitObject.Result.TimeOffset)) + { + switch (state) + { + case ArmedState.Hit: + this.ScaleTo(initial_scale * 1.2f, 320, Easing.Out); + this.RotateTo(Rotation + 180, 320); + break; + + case ArmedState.Miss: + this.ScaleTo(initial_scale * 0.8f, 320, Easing.In); + break; + } + } + } + + using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt)) + { + centre.ScaleTo(0); + disc.ScaleTo(0); + + using (BeginDelayedSequence(spinner.TimePreempt / 2)) + { + centre.ScaleTo(0.3f, spinner.TimePreempt / 4, Easing.OutQuint); + disc.ScaleTo(0.2f, spinner.TimePreempt / 4, Easing.OutQuint); + + using (BeginDelayedSequence(spinner.TimePreempt / 2)) + { + centre.ScaleTo(0.8f, spinner.TimePreempt / 2, Easing.OutQuint); + disc.ScaleTo(1, spinner.TimePreempt / 2, Easing.OutQuint); + } + } + } + + if (drawableSpinner.Result?.TimeStarted != null) + updateCentrePieceSize(); + } + + private void updateCentrePieceSize() + { + Debug.Assert(drawableSpinner.Result?.TimeStarted != null); + + Spinner spinner = drawableSpinner.HitObject; + + using (BeginAbsoluteSequence(drawableSpinner.Result.TimeStarted.Value)) + centre.ResizeTo(new Vector2(tracking_centre_size), spinner.TimePreempt / 2, Easing.OutQuint); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (drawableSpinner.IsNotNull()) + drawableSpinner.ApplyCustomUpdateState -= updateStateTransforms; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerTicks.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerTicks.cs new file mode 100644 index 0000000000..0203432088 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerTicks.cs @@ -0,0 +1,61 @@ +// 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.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonSpinnerTicks : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load() + { + Origin = Anchor.Centre; + Anchor = Anchor.Centre; + RelativeSizeAxes = Axes.Both; + + const float count = 25; + + for (float i = 0; i < count; i++) + { + AddInternal(new CircularContainer + { + RelativePositionAxes = Axes.Both, + Masking = true, + CornerRadius = 5, + BorderColour = Color4.White, + BorderThickness = 2f, + Size = new Vector2(30, 5), + Origin = Anchor.Centre, + Position = new Vector2( + 0.5f + MathF.Sin(i / count * 2 * MathF.PI) / 2 * 0.75f, + 0.5f + MathF.Cos(i / count * 2 * MathF.PI) / 2 * 0.75f + ), + Rotation = -i / count * 360 - 120, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Colour4.White.Opacity(0.2f), + Radius = 30, + }, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + } + } + }); + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 3e5bfd25b5..ba79d94937 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -42,6 +42,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon case OsuSkinComponents.SliderScorePoint: return new ArgonSliderScorePoint(); + case OsuSkinComponents.SpinnerBody: + return new ArgonSpinner(); + case OsuSkinComponents.ReverseArrow: return new ArgonReverseArrow(); } From 49af80e17b099e02cb9a99b5f0b11dee7f1fba57 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 22 Sep 2022 20:39:13 +0300 Subject: [PATCH 1319/2686] Remove 1.3x scale and adjust metrics with it --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs | 4 ++-- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs index f9b2f84984..95438e9588 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs @@ -55,14 +55,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = OsuFont.Default.With(size: 28, weight: FontWeight.Bold), - Y = -120, + Y = -100, }, spmContainer = new Container { Alpha = 0f, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Y = 100, + Y = 60, Children = new[] { spmCounter = new OsuSpriteText diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs index a6211ecb01..4669b5b913 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { public class ArgonSpinnerDisc : CompositeDrawable { - private const float initial_scale = 1.3f; + private const float initial_scale = 1f; private const float idle_alpha = 0.2f; private const float tracking_alpha = 0.4f; From a771d4031f5f7cf579167512ed35f3d99be800a8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 22 Sep 2022 21:27:06 +0300 Subject: [PATCH 1320/2686] Separate triangles-specific test steps to own scene --- .../TestSceneSpinnerRotation.cs | 13 -- .../TestSceneTrianglesSpinnerRotation.cs | 149 ++++++++++++++++++ 2 files changed, 149 insertions(+), 13 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneTrianglesSpinnerRotation.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index c01b2576e8..5fa4e24f5e 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -7,7 +7,6 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Beatmaps; @@ -43,7 +42,6 @@ namespace osu.Game.Rulesets.Osu.Tests => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager); private DrawableSpinner drawableSpinner = null!; - private SpriteIcon spinnerSymbol => drawableSpinner.ChildrenOfType().Single(); [SetUpSteps] public override void SetUpSteps() @@ -77,7 +75,6 @@ namespace osu.Game.Rulesets.Osu.Tests { double finalCumulativeTrackerRotation = 0; double finalTrackerRotation = 0, trackerRotationTolerance = 0; - double finalSpinnerSymbolRotation = 0, spinnerSymbolRotationTolerance = 0; addSeekStep(spinner_start_time + 5000); AddStep("retrieve disc rotation", () => @@ -85,11 +82,6 @@ namespace osu.Game.Rulesets.Osu.Tests finalTrackerRotation = drawableSpinner.RotationTracker.Rotation; trackerRotationTolerance = Math.Abs(finalTrackerRotation * 0.05f); }); - AddStep("retrieve spinner symbol rotation", () => - { - finalSpinnerSymbolRotation = spinnerSymbol.Rotation; - spinnerSymbolRotationTolerance = Math.Abs(finalSpinnerSymbolRotation * 0.05f); - }); AddStep("retrieve cumulative disc rotation", () => finalCumulativeTrackerRotation = drawableSpinner.Result.RateAdjustedRotation); addSeekStep(spinner_start_time + 2500); @@ -98,8 +90,6 @@ namespace osu.Game.Rulesets.Osu.Tests // due to the exponential damping applied we're allowing a larger margin of error of about 10% // (5% relative to the final rotation value, but we're half-way through the spin). () => drawableSpinner.RotationTracker.Rotation, () => Is.EqualTo(finalTrackerRotation / 2).Within(trackerRotationTolerance)); - AddAssert("symbol rotation rewound", - () => spinnerSymbol.Rotation, () => Is.EqualTo(finalSpinnerSymbolRotation / 2).Within(spinnerSymbolRotationTolerance)); AddAssert("is cumulative rotation rewound", // cumulative rotation is not damped, so we're treating it as the "ground truth" and allowing a comparatively smaller margin of error. () => drawableSpinner.Result.RateAdjustedRotation, () => Is.EqualTo(finalCumulativeTrackerRotation / 2).Within(100)); @@ -107,8 +97,6 @@ namespace osu.Game.Rulesets.Osu.Tests addSeekStep(spinner_start_time + 5000); AddAssert("is disc rotation almost same", () => drawableSpinner.RotationTracker.Rotation, () => Is.EqualTo(finalTrackerRotation).Within(trackerRotationTolerance)); - AddAssert("is symbol rotation almost same", - () => spinnerSymbol.Rotation, () => Is.EqualTo(finalSpinnerSymbolRotation).Within(spinnerSymbolRotationTolerance)); AddAssert("is cumulative rotation almost same", () => drawableSpinner.Result.RateAdjustedRotation, () => Is.EqualTo(finalCumulativeTrackerRotation).Within(100)); } @@ -122,7 +110,6 @@ namespace osu.Game.Rulesets.Osu.Tests addSeekStep(5000); AddAssert("disc spin direction correct", () => clockwise ? drawableSpinner.RotationTracker.Rotation > 0 : drawableSpinner.RotationTracker.Rotation < 0); - AddAssert("spinner symbol direction correct", () => clockwise ? spinnerSymbol.Rotation > 0 : spinnerSymbol.Rotation < 0); } private Replay flip(Replay scoreReplay) => new Replay diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTrianglesSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTrianglesSpinnerRotation.cs new file mode 100644 index 0000000000..80e3af6cc0 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTrianglesSpinnerRotation.cs @@ -0,0 +1,149 @@ +// 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.Graphics.Sprites; +using osu.Framework.Testing; +using osu.Framework.Timing; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.Replays; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Replays; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.Replays; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Skinning; +using osu.Game.Storyboards; +using osu.Game.Tests.Visual; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneTrianglesSpinnerRotation : TestSceneOsuPlayer + { + private const double spinner_start_time = 100; + private const double spinner_duration = 6000; + + [Resolved] + private SkinManager skinManager { get; set; } = null!; + + [Resolved] + private AudioManager audioManager { get; set; } = null!; + + protected override bool Autoplay => true; + + protected override TestPlayer CreatePlayer(Ruleset ruleset) => new ScoreExposedPlayer(); + + protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null) + => new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager); + + private DrawableSpinner drawableSpinner = null!; + private SpriteIcon spinnerSymbol => drawableSpinner.ChildrenOfType().Single(); + + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("set triangles skin", () => skinManager.CurrentSkinInfo.Value = TrianglesSkin.CreateInfo().ToLiveUnmanaged()); + + AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning); + AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)Player.DrawableRuleset.Playfield.AllHitObjects.First()); + } + + [Test] + public void TestSymbolMiddleRewindingRotation() + { + double finalSpinnerSymbolRotation = 0, spinnerSymbolRotationTolerance = 0; + + addSeekStep(spinner_start_time + 5000); + AddStep("retrieve spinner symbol rotation", () => + { + finalSpinnerSymbolRotation = spinnerSymbol.Rotation; + spinnerSymbolRotationTolerance = Math.Abs(finalSpinnerSymbolRotation * 0.05f); + }); + + addSeekStep(spinner_start_time + 2500); + AddAssert("symbol rotation rewound", + () => spinnerSymbol.Rotation, () => Is.EqualTo(finalSpinnerSymbolRotation / 2).Within(spinnerSymbolRotationTolerance)); + + addSeekStep(spinner_start_time + 5000); + AddAssert("is symbol rotation almost same", + () => spinnerSymbol.Rotation, () => Is.EqualTo(finalSpinnerSymbolRotation).Within(spinnerSymbolRotationTolerance)); + } + + [Test] + public void TestSymbolRotationDirection([Values(true, false)] bool clockwise) + { + if (clockwise) + transformReplay(flip); + + addSeekStep(5000); + AddAssert("spinner symbol direction correct", () => clockwise ? spinnerSymbol.Rotation > 0 : spinnerSymbol.Rotation < 0); + } + + private Replay flip(Replay scoreReplay) => new Replay + { + Frames = scoreReplay + .Frames + .Cast() + .Select(replayFrame => + { + var flippedPosition = new Vector2(OsuPlayfield.BASE_SIZE.X - replayFrame.Position.X, replayFrame.Position.Y); + return new OsuReplayFrame(replayFrame.Time, flippedPosition, replayFrame.Actions.ToArray()); + }) + .Cast() + .ToList() + }; + + private void addSeekStep(double time) + { + AddStep($"seek to {time}", () => Player.GameplayClockContainer.Seek(time)); + AddUntilStep("wait for seek to finish", () => Player.DrawableRuleset.FrameStableClock.CurrentTime, () => Is.EqualTo(time).Within(100)); + } + + private void transformReplay(Func replayTransformation) => AddStep("set replay", () => + { + var drawableRuleset = this.ChildrenOfType().Single(); + var score = drawableRuleset.ReplayScore; + var transformedScore = new Score + { + ScoreInfo = score.ScoreInfo, + Replay = replayTransformation.Invoke(score.Replay) + }; + drawableRuleset.SetReplayScore(transformedScore); + }); + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap + { + HitObjects = new List + { + new Spinner + { + Position = new Vector2(256, 192), + StartTime = spinner_start_time, + Duration = spinner_duration + }, + } + }; + + private class ScoreExposedPlayer : TestPlayer + { + public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; + + public ScoreExposedPlayer() + : base(false, false) + { + } + } + } +} From d538295ad5712af0d7124ac4131e383219845459 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Thu, 22 Sep 2022 23:04:43 +0200 Subject: [PATCH 1321/2686] Add `TestSceneOsuModRandom` --- .../Mods/TestSceneOsuModRandom.cs | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRandom.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRandom.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRandom.cs new file mode 100644 index 0000000000..c24ba6d530 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRandom.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.Collections.Generic; +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Osu.Objects; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Tests.Mods +{ + public class TestSceneOsuModRandom : OsuModTestScene + { + [TestCase(1)] + [TestCase(7)] + [TestCase(10)] + public void TestDefaultBeatmap(float angleSharpness) => CreateModTest(new ModTestData + { + Mod = new OsuModRandom + { + AngleSharpness = { Value = angleSharpness } + }, + Autoplay = true, + PassCondition = () => true + }); + + [TestCase(1)] + [TestCase(7)] + [TestCase(10)] + public void TestJumpBeatmap(float angleSharpness) => CreateModTest(new ModTestData + { + Mod = new OsuModRandom + { + AngleSharpness = { Value = angleSharpness } + }, + Beatmap = jumpBeatmap, + Autoplay = true, + PassCondition = () => true + }); + + [TestCase(1)] + [TestCase(7)] + [TestCase(10)] + public void TestStreamBeatmap(float angleSharpness) => CreateModTest(new ModTestData + { + Mod = new OsuModRandom + { + AngleSharpness = { Value = angleSharpness } + }, + Beatmap = streamBeatmap, + Autoplay = true, + PassCondition = () => true + }); + + private OsuBeatmap jumpBeatmap => + createHitCircleBeatmap(new[] { 100, 200, 300, 400 }, 8, 300, 2 * 300); + + private OsuBeatmap streamBeatmap => + createHitCircleBeatmap(new[] { 10, 20, 30, 40, 50, 60, 70, 80 }, 16, 150, 4 * 150); + + private OsuBeatmap createHitCircleBeatmap(IEnumerable spacings, int objectsPerSpacing, int interval, int beatLength) + { + var controlPointInfo = new ControlPointInfo(); + controlPointInfo.Add(0, new TimingControlPoint + { + Time = 0, + BeatLength = beatLength + }); + + var beatmap = new OsuBeatmap + { + BeatmapInfo = new BeatmapInfo + { + StackLeniency = 0, + Difficulty = new BeatmapDifficulty + { + ApproachRate = 8.5f + } + }, + ControlPointInfo = controlPointInfo + }; + + foreach (int spacing in spacings) + { + for (int i = 0; i < objectsPerSpacing; i++) + { + beatmap.HitObjects.Add(new HitCircle + { + StartTime = interval * beatmap.HitObjects.Count, + Position = beatmap.HitObjects.Count % 2 == 0 ? Vector2.Zero : new Vector2(spacing, 0), + NewCombo = i == 0 + }); + } + } + + return beatmap; + } + } +} From a65a76f7de5de1f3f298359cdcbd99b3d2c20069 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Sep 2022 20:05:12 +0900 Subject: [PATCH 1322/2686] Fix off-thread drawable mutation in multiplayer settings overlay when an error occurs Closes #20413. --- .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 75bd6eb04d..15138b18b0 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -424,7 +424,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private void hideError() => ErrorText.FadeOut(50); - private void onSuccess(Room room) + private void onSuccess(Room room) => Schedule(() => { Debug.Assert(applyingSettingsOperation != null); @@ -432,9 +432,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match applyingSettingsOperation.Dispose(); applyingSettingsOperation = null; - } + }); - private void onError(string text) + private void onError(string text) => Schedule(() => { Debug.Assert(applyingSettingsOperation != null); @@ -455,7 +455,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match applyingSettingsOperation.Dispose(); applyingSettingsOperation = null; - } + }); } public class CreateOrUpdateButton : TriangleButton From 4e9053b0996fb2714a041196e58fa300d9a4df21 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Sep 2022 20:10:57 +0900 Subject: [PATCH 1323/2686] Fix crash when storyboard attempts to play at main menu --- .../Drawables/DrawableStoryboardAnimation.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index 369a3ee7ba..d1dc2b5d83 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; -using osu.Game.Screens.Play; +using osu.Game.Beatmaps; using osu.Game.Skinning; using osuTK; @@ -91,6 +91,9 @@ namespace osu.Game.Storyboards.Drawables [Resolved] private ISkinSource skin { get; set; } + [Resolved] + private IBeatSyncProvider beatSyncProvider { get; set; } + [BackgroundDependencyLoader] private void load(TextureStore textureStore, Storyboard storyboard) { @@ -116,9 +119,6 @@ namespace osu.Game.Storyboards.Drawables Animation.ApplyTransforms(this); } - [Resolved] - private IGameplayClock gameplayClock { get; set; } - protected override void LoadComplete() { base.LoadComplete(); @@ -128,7 +128,7 @@ namespace osu.Game.Storyboards.Drawables // // In the case of storyboard animations, we want to synchronise with game time perfectly // so let's get a correct time based on gameplay clock and earliest transform. - PlaybackPosition = gameplayClock.CurrentTime - Animation.EarliestTransformTime; + PlaybackPosition = (beatSyncProvider?.Clock?.CurrentTime ?? Clock.CurrentTime) - Animation.EarliestTransformTime; } private void skinSourceChanged() From 0fa5e1b28e0e8d9b00ebe6d85fd6517b958a5656 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Sep 2022 20:18:44 +0900 Subject: [PATCH 1324/2686] Fix intermittent leaderboard crash due to request finishing after drawable is disposed --- osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 0f6ac2b455..ffb13dc458 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -153,10 +153,11 @@ namespace osu.Game.Screens.Select.Leaderboards var req = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods); - req.Success += r => SetScores( + // Schedule is required to avoid potential object disposed exception when LoadComponentAsync is eventually called. + req.Success += r => Schedule(() => SetScores( scoreManager.OrderByTotalScore(r.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))), r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo) - ); + )); return req; } From 965d0603ce4346f6be847568336eff24c4b469e0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Sep 2022 21:11:25 +0900 Subject: [PATCH 1325/2686] Fix slider tick colour not being applied properly --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs index 1ab546b613..4c6b9a2f17 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon }; accentColour = hitObject.AccentColour.GetBoundCopy(); - accentColour.BindValueChanged(accent => BorderColour = accent.NewValue); + accentColour.BindValueChanged(accent => BorderColour = accent.NewValue, true); } } } From 0e38ff07c74de55cfc640361f51b8ea5658171d9 Mon Sep 17 00:00:00 2001 From: NullifiedJosh <86538544+NullifiedJosh@users.noreply.github.com> Date: Fri, 23 Sep 2022 20:19:56 +0800 Subject: [PATCH 1326/2686] Check if relax is one of the mods, if so hide. --- osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index ef2936ac94..07968e4bee 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -4,6 +4,7 @@ #nullable disable using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Input; using osu.Game.Beatmaps; @@ -26,9 +27,15 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool UserScrollSpeedAdjustment => false; + private bool showMobileMapper = true; + public DrawableCatchRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) { + // Check if mods have RelaxMod instance + if (mods.OfType().Any()) + showMobileMapper = false; + Direction.Value = ScrollingDirection.Down; TimeRange.Value = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450); } @@ -36,7 +43,8 @@ namespace osu.Game.Rulesets.Catch.UI [BackgroundDependencyLoader] private void load() { - KeyBindingInputManager.Add(new CatchTouchInputMapper()); + if (showMobileMapper) + KeyBindingInputManager.Add(new CatchTouchInputMapper()); } protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay); From 4bd92b89bcee77c01a7050648020518018e3f8e8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 23 Sep 2022 16:29:19 +0300 Subject: [PATCH 1327/2686] Change test scene to ensure progress notification is closed on completion --- .../Visual/UserInterface/TestSceneNotificationOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index b314d95597..47958f4a41 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -465,7 +465,7 @@ namespace osu.Game.Tests.Visual.UserInterface { base.Update(); - progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed); + progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed && n.WasClosed); if (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3) { From cdc3afac88b3ac203ab6999ce2c8dbdc37906909 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 23 Sep 2022 16:30:07 +0300 Subject: [PATCH 1328/2686] Fix update progress notification not closing on completion --- osu.Game/Updater/UpdateManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index 100464029b..7b540cb564 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -156,6 +156,7 @@ namespace osu.Game.Updater switch (State) { case ProgressNotificationState.Cancelled: + case ProgressNotificationState.Completed: base.Close(runFlingAnimation); break; } From 835cae30872e3ffa5f196dd3ffcd9ec7347609b8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 23 Sep 2022 17:06:55 +0300 Subject: [PATCH 1329/2686] Remove null conditional --- osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index d1dc2b5d83..07e1e86617 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -128,7 +128,7 @@ namespace osu.Game.Storyboards.Drawables // // In the case of storyboard animations, we want to synchronise with game time perfectly // so let's get a correct time based on gameplay clock and earliest transform. - PlaybackPosition = (beatSyncProvider?.Clock?.CurrentTime ?? Clock.CurrentTime) - Animation.EarliestTransformTime; + PlaybackPosition = (beatSyncProvider.Clock?.CurrentTime ?? Clock.CurrentTime) - Animation.EarliestTransformTime; } private void skinSourceChanged() From 6c8e587344581907013d223200c9b4dd3b10e96e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 24 Sep 2022 21:52:16 +0300 Subject: [PATCH 1330/2686] Move margin value to constant --- osu.Game/Overlays/NowPlayingOverlay.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 6eddc7da83..687731d068 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -38,6 +38,7 @@ namespace osu.Game.Overlays private const float transition_length = 800; private const float progress_height = 10; private const float bottom_black_area_height = 55; + private const float margin = 10; private Drawable background; private ProgressBar progressBar; @@ -69,7 +70,7 @@ namespace osu.Game.Overlays public NowPlayingOverlay() { Width = 400; - Margin = new MarginPadding(10); + Margin = new MarginPadding(margin); } [BackgroundDependencyLoader] @@ -194,7 +195,7 @@ namespace osu.Game.Overlays LoadComponentAsync(playlist = new PlaylistOverlay { RelativeSizeAxes = Axes.X, - Y = player_height + 10, + Y = player_height + margin, }, _ => { dragContainer.Add(playlist); From 5d0b2d34c9289eb79a26aa58e238ee24c56e14f0 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 24 Sep 2022 23:35:06 +0300 Subject: [PATCH 1331/2686] Make playlist to always be in screen bounds --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 5 ++-- osu.Game/Overlays/NowPlayingOverlay.cs | 27 +++++++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 9fe2fd5279..63f1aa248c 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -8,6 +8,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; @@ -24,7 +25,7 @@ namespace osu.Game.Overlays.Music public class PlaylistOverlay : VisibilityContainer { private const float transition_duration = 600; - private const float playlist_height = 510; + public const float PLAYLIST_HEIGHT = 510; private readonly BindableList> beatmapSets = new BindableList>(); @@ -130,7 +131,7 @@ namespace osu.Game.Overlays.Music filter.Search.HoldFocus = true; Schedule(() => filter.Search.TakeFocus()); - this.ResizeTo(new Vector2(1, playlist_height), transition_duration, Easing.OutQuint); + this.ResizeTo(new Vector2(1, RelativeSizeAxes.HasFlagFast(Axes.Y) ? 1f : PLAYLIST_HEIGHT), transition_duration, Easing.OutQuint); this.FadeIn(transition_duration, Easing.OutQuint); } diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 687731d068..900b4bebf0 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -54,6 +54,7 @@ namespace osu.Game.Overlays private Container dragContainer; private Container playerContainer; + private Container playlistContainer; protected override string PopInSampleName => "UI/now-playing-pop-in"; protected override string PopOutSampleName => "UI/now-playing-pop-out"; @@ -83,7 +84,6 @@ namespace osu.Game.Overlays Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, Children = new Drawable[] { playerContainer = new Container @@ -183,8 +183,13 @@ namespace osu.Game.Overlays } }, }, + playlistContainer = new Container + { + RelativeSizeAxes = Axes.X, + Y = player_height + margin, + } } - } + }, }; } @@ -194,11 +199,10 @@ namespace osu.Game.Overlays { LoadComponentAsync(playlist = new PlaylistOverlay { - RelativeSizeAxes = Axes.X, - Y = player_height + margin, + RelativeSizeAxes = Axes.Both, }, _ => { - dragContainer.Add(playlist); + playlistContainer.Add(playlist); playlist.State.BindValueChanged(s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint), true); @@ -243,7 +247,18 @@ namespace osu.Game.Overlays { base.UpdateAfterChildren(); - Height = dragContainer.Height; + playlistContainer.Height = MathF.Min(Parent.DrawHeight - margin * 3 - player_height, PlaylistOverlay.PLAYLIST_HEIGHT); + + float height = player_height; + + if (playlist != null) + { + height += playlist.DrawHeight; + if (playlist.State.Value == Visibility.Visible) + height += margin; + } + + Height = dragContainer.Height = height; } protected override void Update() From 38f0524e88168b5ef0d175207fd938eb2251ea4b Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 25 Sep 2022 18:00:28 +0200 Subject: [PATCH 1332/2686] build: harden ci.yml permissions Signed-off-by: Alex --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 082e0d247c..33ec3d6602 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +permissions: + contents: read # to fetch code (actions/checkout) + jobs: inspect-code: name: Code Quality From 90dd3c3020c5df90fb48980a4fb9de03dd3b9d52 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 25 Sep 2022 18:03:13 +0200 Subject: [PATCH 1333/2686] build: harden report-nunit.yml permissions Signed-off-by: Alex --- .github/workflows/report-nunit.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/report-nunit.yml b/.github/workflows/report-nunit.yml index 358cbda17a..bfc9620174 100644 --- a/.github/workflows/report-nunit.yml +++ b/.github/workflows/report-nunit.yml @@ -8,8 +8,12 @@ on: workflows: ["Continuous Integration"] types: - completed +permissions: {} jobs: annotate: + permissions: + checks: write # to create checks (dorny/test-reporter) + name: Annotate CI run with test results runs-on: ubuntu-latest if: ${{ github.event.workflow_run.conclusion != 'cancelled' }} From 68f62ca9cd653f0e9175be716ebd2ac492c3b6f7 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 25 Sep 2022 18:04:27 +0200 Subject: [PATCH 1334/2686] build: harden sentry-release.yml permissions Signed-off-by: Alex --- .github/workflows/sentry-release.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/sentry-release.yml b/.github/workflows/sentry-release.yml index 442b97c473..cce3f23e5f 100644 --- a/.github/workflows/sentry-release.yml +++ b/.github/workflows/sentry-release.yml @@ -5,6 +5,9 @@ on: tags: - '*' +permissions: + contents: read # to fetch code (actions/checkout) + jobs: sentry_release: runs-on: ubuntu-latest From 537796c3a17fb049a4b417c1f6835e4ffd35d208 Mon Sep 17 00:00:00 2001 From: o-dasher <88356162+o-dasher@users.noreply.github.com> Date: Sun, 25 Sep 2022 15:49:22 -0400 Subject: [PATCH 1335/2686] Cleanup mod bindings --- .../Mods/CatchModFlashlight.cs | 8 +------ .../Mods/CatchModNoScope.cs | 4 +--- .../Mods/ManiaModFlashlight.cs | 10 ++------- osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs | 4 +--- .../Mods/OsuModFlashlight.cs | 10 ++------- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 4 +--- osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs | 4 +--- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 4 +--- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 6 +---- .../Mods/TaikoModFlashlight.cs | 10 ++------- osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs | 14 +++--------- osu.Game/Rulesets/Mods/ModDoubleTime.cs | 4 +--- osu.Game/Rulesets/Mods/ModHalfTime.cs | 4 +--- osu.Game/Rulesets/Mods/ModMuted.cs | 22 ++++--------------- osu.Game/Rulesets/Mods/ModRandom.cs | 6 +---- osu.Game/Rulesets/Mods/ModTimeRamp.cs | 4 +--- osu.Game/Rulesets/Mods/ModWindDown.cs | 14 +++--------- osu.Game/Rulesets/Mods/ModWindUp.cs | 14 +++--------- 18 files changed, 30 insertions(+), 116 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index abe391ba4e..e8b126cfed 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs @@ -21,17 +21,11 @@ namespace osu.Game.Rulesets.Catch.Mods { MinValue = 0.5f, MaxValue = 1.5f, - Default = 1f, - Value = 1f, Precision = 0.1f }; [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")] - public override BindableBool ComboBasedSize { get; } = new BindableBool - { - Default = true, - Value = true - }; + public override BindableBool ComboBasedSize { get; } = new BindableBool(true); public override float DefaultFlashlightSize => 350; diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs index 9038153e20..1b781b032c 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs @@ -22,10 +22,8 @@ namespace osu.Game.Rulesets.Catch.Mods "The combo count at which the catcher becomes completely hidden", SettingControlType = typeof(SettingsSlider) )] - public override BindableInt HiddenComboCount { get; } = new BindableInt + public override BindableInt HiddenComboCount { get; } = new BindableInt(10) { - Default = 10, - Value = 10, MinValue = 0, MaxValue = 50, }; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs index 8ef5bfd94c..72ea1a2431 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs @@ -18,21 +18,15 @@ namespace osu.Game.Rulesets.Mania.Mods public override Type[] IncompatibleMods => new[] { typeof(ModHidden) }; [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")] - public override BindableFloat SizeMultiplier { get; } = new BindableFloat + public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1) { MinValue = 0.5f, MaxValue = 3f, - Default = 1f, - Value = 1f, Precision = 0.1f }; [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")] - public override BindableBool ComboBasedSize { get; } = new BindableBool - { - Default = false, - Value = false - }; + public override BindableBool ComboBasedSize { get; } = new BindableBool(); public override float DefaultFlashlightSize => 50; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs index e624660410..b2980f5311 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs @@ -19,12 +19,10 @@ namespace osu.Game.Rulesets.Osu.Mods public override LocalisableString Description => "Hit them at the right size!"; [SettingSource("Starting Size", "The initial size multiplier applied to all objects.")] - public override BindableNumber StartScale { get; } = new BindableFloat + public override BindableNumber StartScale { get; } = new BindableFloat(2) { MinValue = 1f, MaxValue = 25f, - Default = 2f, - Value = 2f, Precision = 0.1f, }; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index e5a458488e..7b34fe05a9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -33,21 +33,15 @@ namespace osu.Game.Rulesets.Osu.Mods }; [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")] - public override BindableFloat SizeMultiplier { get; } = new BindableFloat + public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1) { MinValue = 0.5f, MaxValue = 2f, - Default = 1f, - Value = 1f, Precision = 0.1f }; [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")] - public override BindableBool ComboBasedSize { get; } = new BindableBool - { - Default = true, - Value = true - }; + public override BindableBool ComboBasedSize { get; } = new BindableBool(true); public override float DefaultFlashlightSize => 180; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index b77c887cd3..b49257e289 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -19,12 +19,10 @@ namespace osu.Game.Rulesets.Osu.Mods public override LocalisableString Description => "Hit them at the right size!"; [SettingSource("Starting Size", "The initial size multiplier applied to all objects.")] - public override BindableNumber StartScale { get; } = new BindableFloat + public override BindableNumber StartScale { get; } = new BindableFloat(0.5f) { MinValue = 0f, MaxValue = 0.99f, - Default = 0.5f, - Value = 0.5f, Precision = 0.01f, }; } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs index 817f7b599c..84538cec30 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs @@ -27,10 +27,8 @@ namespace osu.Game.Rulesets.Osu.Mods "The combo count at which the cursor becomes completely hidden", SettingControlType = typeof(SettingsSlider) )] - public override BindableInt HiddenComboCount { get; } = new BindableInt + public override BindableInt HiddenComboCount { get; } = new BindableInt(10) { - Default = 10, - Value = 10, MinValue = 0, MaxValue = 50, }; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 78c7aa53f4..618fcfe05d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -29,10 +29,8 @@ namespace osu.Game.Rulesets.Osu.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTarget)).ToArray(); [SettingSource("Angle sharpness", "How sharp angles should be", SettingControlType = typeof(SettingsSlider))] - public BindableFloat AngleSharpness { get; } = new BindableFloat + public BindableFloat AngleSharpness { get; } = new BindableFloat(7) { - Default = 7, - Value = 7, MinValue = 1, MaxValue = 10, Precision = 0.1f diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 861ad80b7f..406968ba08 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -53,11 +53,7 @@ namespace osu.Game.Rulesets.Osu.Mods }).ToArray(); [SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))] - public Bindable Seed { get; } = new Bindable - { - Default = null, - Value = null - }; + public Bindable Seed { get; } = new Bindable(); [SettingSource("Metronome ticks", "Whether a metronome beat should play in the background")] public Bindable Metronome { get; } = new BindableBool(true); diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 66616486df..05baf88a33 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -18,21 +18,15 @@ namespace osu.Game.Rulesets.Taiko.Mods public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1; [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")] - public override BindableFloat SizeMultiplier { get; } = new BindableFloat + public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1) { MinValue = 0.5f, MaxValue = 1.5f, - Default = 1f, - Value = 1f, Precision = 0.1f }; [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")] - public override BindableBool ComboBasedSize { get; } = new BindableBool - { - Default = true, - Value = true - }; + public override BindableBool ComboBasedSize { get; } = new BindableBool(true); public override float DefaultFlashlightSize => 250; diff --git a/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs b/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs index 697b303689..e7127abcf0 100644 --- a/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs +++ b/osu.Game/Rulesets/Mods/ModAdaptiveSpeed.cs @@ -36,32 +36,24 @@ namespace osu.Game.Rulesets.Mods public override Type[] IncompatibleMods => new[] { typeof(ModRateAdjust), typeof(ModTimeRamp), typeof(ModAutoplay) }; [SettingSource("Initial rate", "The starting speed of the track")] - public BindableNumber InitialRate { get; } = new BindableDouble + public BindableNumber InitialRate { get; } = new BindableDouble(1) { MinValue = 0.5, MaxValue = 2, - Default = 1, - Value = 1, Precision = 0.01 }; [SettingSource("Adjust pitch", "Should pitch be adjusted with speed")] - public BindableBool AdjustPitch { get; } = new BindableBool - { - Default = true, - Value = true - }; + public BindableBool AdjustPitch { get; } = new BindableBool(true); /// /// The instantaneous rate of the track. /// Every frame this mod will attempt to smoothly adjust this to meet . /// - public BindableNumber SpeedChange { get; } = new BindableDouble + public BindableNumber SpeedChange { get; } = new BindableDouble(1) { MinValue = min_allowable_rate, MaxValue = max_allowable_rate, - Default = 1, - Value = 1 }; // The two constants below denote the maximum allowable range of rates that `SpeedChange` can take. diff --git a/osu.Game/Rulesets/Mods/ModDoubleTime.cs b/osu.Game/Rulesets/Mods/ModDoubleTime.cs index d8a41ae658..9e4469bf25 100644 --- a/osu.Game/Rulesets/Mods/ModDoubleTime.cs +++ b/osu.Game/Rulesets/Mods/ModDoubleTime.cs @@ -18,12 +18,10 @@ namespace osu.Game.Rulesets.Mods public override LocalisableString Description => "Zoooooooooom..."; [SettingSource("Speed increase", "The actual increase to apply")] - public override BindableNumber SpeedChange { get; } = new BindableDouble + public override BindableNumber SpeedChange { get; } = new BindableDouble(1.5) { MinValue = 1.01, MaxValue = 2, - Default = 1.5, - Value = 1.5, Precision = 0.01, }; } diff --git a/osu.Game/Rulesets/Mods/ModHalfTime.cs b/osu.Game/Rulesets/Mods/ModHalfTime.cs index 8d8b97e79e..7d858dca6f 100644 --- a/osu.Game/Rulesets/Mods/ModHalfTime.cs +++ b/osu.Game/Rulesets/Mods/ModHalfTime.cs @@ -18,12 +18,10 @@ namespace osu.Game.Rulesets.Mods public override LocalisableString Description => "Less zoom..."; [SettingSource("Speed decrease", "The actual decrease to apply")] - public override BindableNumber SpeedChange { get; } = new BindableDouble + public override BindableNumber SpeedChange { get; } = new BindableDouble(0.75) { MinValue = 0.5, MaxValue = 0.99, - Default = 0.75, - Value = 0.75, Precision = 0.01, }; } diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 9735d6b536..05ecd37000 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -36,34 +36,20 @@ namespace osu.Game.Rulesets.Mods private readonly BindableNumber currentCombo = new BindableInt(); [SettingSource("Enable metronome", "Add a metronome beat to help you keep track of the rhythm.")] - public BindableBool EnableMetronome { get; } = new BindableBool - { - Default = true, - Value = true - }; + public BindableBool EnableMetronome { get; } = new BindableBool(true); [SettingSource("Final volume at combo", "The combo count at which point the track reaches its final volume.", SettingControlType = typeof(SettingsSlider))] - public BindableInt MuteComboCount { get; } = new BindableInt + public BindableInt MuteComboCount { get; } = new BindableInt(100) { - Default = 100, - Value = 100, MinValue = 0, MaxValue = 500, }; [SettingSource("Start muted", "Increase volume as combo builds.")] - public BindableBool InverseMuting { get; } = new BindableBool - { - Default = false, - Value = false - }; + public BindableBool InverseMuting { get; } = new BindableBool(); [SettingSource("Mute hit sounds", "Hit sounds are also muted alongside the track.")] - public BindableBool AffectsHitSounds { get; } = new BindableBool - { - Default = true, - Value = true - }; + public BindableBool AffectsHitSounds { get; } = new BindableBool(true); protected ModMuted() { diff --git a/osu.Game/Rulesets/Mods/ModRandom.cs b/osu.Game/Rulesets/Mods/ModRandom.cs index 1f7742b075..178b9fb619 100644 --- a/osu.Game/Rulesets/Mods/ModRandom.cs +++ b/osu.Game/Rulesets/Mods/ModRandom.cs @@ -18,10 +18,6 @@ namespace osu.Game.Rulesets.Mods public override double ScoreMultiplier => 1; [SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))] - public Bindable Seed { get; } = new Bindable - { - Default = null, - Value = null - }; + public Bindable Seed { get; } = new Bindable(); } } diff --git a/osu.Game/Rulesets/Mods/ModTimeRamp.cs b/osu.Game/Rulesets/Mods/ModTimeRamp.cs index 72a7f4b9a3..c4cb41fb6a 100644 --- a/osu.Game/Rulesets/Mods/ModTimeRamp.cs +++ b/osu.Game/Rulesets/Mods/ModTimeRamp.cs @@ -39,10 +39,8 @@ namespace osu.Game.Rulesets.Mods private double finalRateTime; private double beginRampTime; - public BindableNumber SpeedChange { get; } = new BindableDouble + public BindableNumber SpeedChange { get; } = new BindableDouble(1) { - Default = 1, - Value = 1, Precision = 0.01, }; diff --git a/osu.Game/Rulesets/Mods/ModWindDown.cs b/osu.Game/Rulesets/Mods/ModWindDown.cs index 22ed7c2efd..15ee37d481 100644 --- a/osu.Game/Rulesets/Mods/ModWindDown.cs +++ b/osu.Game/Rulesets/Mods/ModWindDown.cs @@ -18,31 +18,23 @@ namespace osu.Game.Rulesets.Mods public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleDown; [SettingSource("Initial rate", "The starting speed of the track")] - public override BindableNumber InitialRate { get; } = new BindableDouble + public override BindableNumber InitialRate { get; } = new BindableDouble(1) { MinValue = 0.51, MaxValue = 2, - Default = 1, - Value = 1, Precision = 0.01, }; [SettingSource("Final rate", "The speed increase to ramp towards")] - public override BindableNumber FinalRate { get; } = new BindableDouble + public override BindableNumber FinalRate { get; } = new BindableDouble(0.75) { MinValue = 0.5, MaxValue = 1.99, - Default = 0.75, - Value = 0.75, Precision = 0.01, }; [SettingSource("Adjust pitch", "Should pitch be adjusted with speed")] - public override BindableBool AdjustPitch { get; } = new BindableBool - { - Default = true, - Value = true - }; + public override BindableBool AdjustPitch { get; } = new BindableBool(true); public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindUp)).ToArray(); diff --git a/osu.Game/Rulesets/Mods/ModWindUp.cs b/osu.Game/Rulesets/Mods/ModWindUp.cs index 13ece6d9a3..6d8838c5a5 100644 --- a/osu.Game/Rulesets/Mods/ModWindUp.cs +++ b/osu.Game/Rulesets/Mods/ModWindUp.cs @@ -18,31 +18,23 @@ namespace osu.Game.Rulesets.Mods public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleUp; [SettingSource("Initial rate", "The starting speed of the track")] - public override BindableNumber InitialRate { get; } = new BindableDouble + public override BindableNumber InitialRate { get; } = new BindableDouble(1) { MinValue = 0.5, MaxValue = 1.99, - Default = 1, - Value = 1, Precision = 0.01, }; [SettingSource("Final rate", "The speed increase to ramp towards")] - public override BindableNumber FinalRate { get; } = new BindableDouble + public override BindableNumber FinalRate { get; } = new BindableDouble(1.5) { MinValue = 0.51, MaxValue = 2, - Default = 1.5, - Value = 1.5, Precision = 0.01, }; [SettingSource("Adjust pitch", "Should pitch be adjusted with speed")] - public override BindableBool AdjustPitch { get; } = new BindableBool - { - Default = true, - Value = true - }; + public override BindableBool AdjustPitch { get; } = new BindableBool(true); public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindDown)).ToArray(); From feadac1f790fec56a1954cdab86f4deccfb9d68d Mon Sep 17 00:00:00 2001 From: o-dasher <88356162+o-dasher@users.noreply.github.com> Date: Sun, 25 Sep 2022 16:02:40 -0400 Subject: [PATCH 1336/2686] Cleanup all other leftover binding instantiation --- .../Online/TestAPIModJsonSerialization.cs | 14 +++----------- .../Online/TestAPIModMessagePackSerialization.cs | 14 +++----------- .../Visual/Settings/TestSceneSettingsItem.cs | 12 ++---------- .../Visual/Settings/TestSceneSettingsSource.cs | 6 +----- .../UserInterface/TestSceneExpandingContainer.cs | 8 ++------ .../ControlPoints/DifficultyControlPoint.cs | 1 - .../Beatmaps/ControlPoints/EffectControlPoint.cs | 1 - .../Beatmaps/ControlPoints/SampleControlPoint.cs | 1 - .../Beatmaps/ControlPoints/TimingControlPoint.cs | 1 - .../UI/Scrolling/DrawableScrollingRuleset.cs | 1 - .../Screens/Play/MasterGameplayClockContainer.cs | 1 - .../Play/PlayerSettings/BeatmapOffsetControl.cs | 2 -- .../Play/PlayerSettings/PlaybackSettings.cs | 1 - 13 files changed, 11 insertions(+), 52 deletions(-) diff --git a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs index 17709fb10f..da250c1e05 100644 --- a/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs +++ b/osu.Game.Tests/Online/TestAPIModJsonSerialization.cs @@ -204,31 +204,23 @@ namespace osu.Game.Tests.Online public override double ScoreMultiplier => 1; [SettingSource("Initial rate", "The starting speed of the track")] - public override BindableNumber InitialRate { get; } = new BindableDouble + public override BindableNumber InitialRate { get; } = new BindableDouble(1.5) { MinValue = 1, MaxValue = 2, - Default = 1.5, - Value = 1.5, Precision = 0.01, }; [SettingSource("Final rate", "The speed increase to ramp towards")] - public override BindableNumber FinalRate { get; } = new BindableDouble + public override BindableNumber FinalRate { get; } = new BindableDouble(0.5) { MinValue = 0, MaxValue = 1, - Default = 0.5, - Value = 0.5, Precision = 0.01, }; [SettingSource("Adjust pitch", "Should pitch be adjusted with speed")] - public override BindableBool AdjustPitch { get; } = new BindableBool - { - Default = true, - Value = true - }; + public override BindableBool AdjustPitch { get; } = new BindableBool(true); } private class TestModDifficultyAdjust : ModDifficultyAdjust diff --git a/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs b/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs index b17414e026..1d8cbffcdb 100644 --- a/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs +++ b/osu.Game.Tests/Online/TestAPIModMessagePackSerialization.cs @@ -124,31 +124,23 @@ namespace osu.Game.Tests.Online public override double ScoreMultiplier => 1; [SettingSource("Initial rate", "The starting speed of the track")] - public override BindableNumber InitialRate { get; } = new BindableDouble + public override BindableNumber InitialRate { get; } = new BindableDouble(1.5) { MinValue = 1, MaxValue = 2, - Default = 1.5, - Value = 1.5, Precision = 0.01, }; [SettingSource("Final rate", "The speed increase to ramp towards")] - public override BindableNumber FinalRate { get; } = new BindableDouble + public override BindableNumber FinalRate { get; } = new BindableDouble(0.5) { MinValue = 0, MaxValue = 1, - Default = 0.5, - Value = 0.5, Precision = 0.01, }; [SettingSource("Adjust pitch", "Should pitch be adjusted with speed")] - public override BindableBool AdjustPitch { get; } = new BindableBool - { - Default = true, - Value = true - }; + public override BindableBool AdjustPitch { get; } = new BindableBool(true); } private class TestModEnum : Mod diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs index b3d1966511..6ff53663ba 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs @@ -29,11 +29,7 @@ namespace osu.Game.Tests.Visual.Settings { Child = textBox = new SettingsTextBox { - Current = new Bindable - { - Default = "test", - Value = "test" - } + Current = new Bindable("test") }; }); AddUntilStep("wait for loaded", () => textBox.IsLoaded); @@ -59,11 +55,7 @@ namespace osu.Game.Tests.Visual.Settings { Child = textBox = new SettingsTextBox { - Current = new Bindable - { - Default = "test", - Value = "test" - } + Current = new Bindable("test") }; }); AddUntilStep("wait for loaded", () => textBox.IsLoaded); diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs index dc2a687bd5..3cf6f7febf 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs @@ -67,11 +67,7 @@ namespace osu.Game.Tests.Visual.Settings }; [SettingSource("Sample number textbox", "Textbox number entry", SettingControlType = typeof(SettingsNumberBox))] - public Bindable IntTextBoxBindable { get; } = new Bindable - { - Default = null, - Value = null - }; + public Bindable IntTextBoxBindable { get; } = new Bindable(); } private enum TestEnum diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs index 704185b117..20f173ab04 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs @@ -38,20 +38,16 @@ namespace osu.Game.Tests.Visual.UserInterface { slider1 = new ExpandableSlider> { - Current = new BindableFloat + Current = new BindableFloat(1.0f) { - Default = 1.0f, - MinValue = 1.0f, MaxValue = 10.0f, Precision = 0.01f, }, }, slider2 = new ExpandableSlider { - Current = new BindableDouble + Current = new BindableDouble(1.0) { - Default = 1.0, - MinValue = 1.0, MaxValue = 10.0, Precision = 0.01, }, diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs index c199d1da59..e6f1609d7f 100644 --- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs @@ -24,7 +24,6 @@ namespace osu.Game.Beatmaps.ControlPoints public readonly BindableDouble SliderVelocityBindable = new BindableDouble(1) { Precision = 0.01, - Default = 1, MinValue = 0.1, MaxValue = 10 }; diff --git a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs index ead07b4eaa..7c4313a015 100644 --- a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs @@ -28,7 +28,6 @@ namespace osu.Game.Beatmaps.ControlPoints public readonly BindableDouble ScrollSpeedBindable = new BindableDouble(1) { Precision = 0.01, - Default = 1, MinValue = 0.01, MaxValue = 10 }; diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs index 78dec67937..c454439c5c 100644 --- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs @@ -45,7 +45,6 @@ namespace osu.Game.Beatmaps.ControlPoints { MinValue = 0, MaxValue = 100, - Default = 100 }; /// diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs index 23d4d10fd8..61cc060594 100644 --- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs @@ -49,7 +49,6 @@ namespace osu.Game.Beatmaps.ControlPoints /// public readonly BindableDouble BeatLengthBindable = new BindableDouble(DEFAULT_BEAT_LENGTH) { - Default = DEFAULT_BEAT_LENGTH, MinValue = 6, MaxValue = 60000 }; diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index d8a8a6ccd8..825aba5bc2 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -60,7 +60,6 @@ namespace osu.Game.Rulesets.UI.Scrolling /// protected readonly BindableDouble TimeRange = new BindableDouble(time_span_default) { - Default = time_span_default, MinValue = time_span_min, MaxValue = time_span_max }; diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index 047f25a111..c3c351ac36 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -34,7 +34,6 @@ namespace osu.Game.Screens.Play public readonly BindableNumber UserPlaybackRate = new BindableDouble(1) { - Default = 1, MinValue = 0.5, MaxValue = 2, Precision = 0.1, diff --git a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs index 75da8e7b9d..537f4d811a 100644 --- a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs +++ b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs @@ -31,8 +31,6 @@ namespace osu.Game.Screens.Play.PlayerSettings public BindableDouble Current { get; } = new BindableDouble { - Default = 0, - Value = 0, MinValue = -50, MaxValue = 50, Precision = 0.1, diff --git a/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs b/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs index 12646d656a..14e3123028 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs @@ -17,7 +17,6 @@ namespace osu.Game.Screens.Play.PlayerSettings public readonly Bindable UserPlaybackRate = new BindableDouble(1) { - Default = 1, MinValue = 0.5, MaxValue = 2, Precision = 0.1, From 578f1e1e6c16fbf1001e4b5a8155ff35250fa695 Mon Sep 17 00:00:00 2001 From: o-dasher <88356162+o-dasher@users.noreply.github.com> Date: Sun, 25 Sep 2022 16:28:03 -0400 Subject: [PATCH 1337/2686] Fixes SizeMultiplier binding --- osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index e8b126cfed..41d4590aa8 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Mods public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1; [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")] - public override BindableFloat SizeMultiplier { get; } = new BindableFloat + public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1) { MinValue = 0.5f, MaxValue = 1.5f, From a9318e5c0418eba7867b43732005160e3ab58162 Mon Sep 17 00:00:00 2001 From: o-dasher <88356162+o-dasher@users.noreply.github.com> Date: Sun, 25 Sep 2022 16:31:04 -0400 Subject: [PATCH 1338/2686] Fixes small oversight was applying a value when it wasn't supposed to be applied. --- .../Visual/UserInterface/TestSceneExpandingContainer.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs index 20f173ab04..04ca9accac 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs @@ -38,16 +38,20 @@ namespace osu.Game.Tests.Visual.UserInterface { slider1 = new ExpandableSlider> { - Current = new BindableFloat(1.0f) + Current = new BindableFloat { + Default = 1.0f, + MinValue = 1.0f, MaxValue = 10.0f, Precision = 0.01f, }, }, slider2 = new ExpandableSlider { - Current = new BindableDouble(1.0) + Current = new BindableDouble { + Default = 1.0, + MinValue = 1.0 MaxValue = 10.0, Precision = 0.01, }, From ced72126601f19287be2bbc8bfc52f59be8bd4ea Mon Sep 17 00:00:00 2001 From: o-dasher <88356162+o-dasher@users.noreply.github.com> Date: Sun, 25 Sep 2022 16:33:39 -0400 Subject: [PATCH 1339/2686] Fixes syntax error --- .../Visual/UserInterface/TestSceneExpandingContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs index 04ca9accac..704185b117 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs @@ -51,7 +51,7 @@ namespace osu.Game.Tests.Visual.UserInterface Current = new BindableDouble { Default = 1.0, - MinValue = 1.0 + MinValue = 1.0, MaxValue = 10.0, Precision = 0.01, }, From a7449380cda7920f23cbb6d2f034ec634dcdba16 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 14:11:59 +0900 Subject: [PATCH 1340/2686] Fix osu! slider ticks appearing too late --- osu.Game.Rulesets.Osu/Objects/SliderTick.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs index 569e9b7c1c..676ff62455 100644 --- a/osu.Game.Rulesets.Osu/Objects/SliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/SliderTick.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects // This is so on repeats ticks don't appear too late to be visually processed by the player. offset = 200; else - offset = TimeFadeIn * 0.66f; + offset = TimePreempt * 0.66f; TimePreempt = (StartTime - SpanStartTime) / 2 + offset; } From 82d4689716e81d09c3a58596de54c288fbb45e02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 14:30:31 +0900 Subject: [PATCH 1341/2686] Add failing test showing progress notifications can be flung and cancelled --- .../TestSceneNotificationOverlay.cs | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index b314d95597..895e62d41c 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -107,9 +107,9 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("start drag", () => { - InputManager.MoveMouseTo(notification.ChildrenOfType().Single()); + InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType().Single()); InputManager.PressButton(MouseButton.Left); - InputManager.MoveMouseTo(notification.ChildrenOfType().Single().ScreenSpaceDrawQuad.Centre + new Vector2(-500, 0)); + InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType().Single().ScreenSpaceDrawQuad.Centre + new Vector2(-500, 0)); }); AddStep("fling away", () => @@ -123,6 +123,45 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("unread count zero", () => notificationOverlay.UnreadCount.Value == 0); } + [Test] + public void TestProgressNotificationCantBeFlung() + { + bool activated = false; + ProgressNotification notification = null!; + + AddStep("post", () => + { + activated = false; + notificationOverlay.Post(notification = new ProgressNotification + { + Text = @"Uploading to BSS...", + CompletionText = "Uploaded to BSS!", + Activated = () => activated = true, + }); + + progressingNotifications.Add(notification); + }); + + AddStep("start drag", () => + { + InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType().Single()); + InputManager.PressButton(MouseButton.Left); + InputManager.MoveMouseTo(notificationOverlay.ChildrenOfType().Single().ScreenSpaceDrawQuad.Centre + new Vector2(-500, 0)); + }); + + AddStep("attempt fling", () => + { + InputManager.ReleaseButton(MouseButton.Left); + }); + + AddUntilStep("was not closed", () => !notification.WasClosed); + AddUntilStep("was not cancelled", () => notification.State == ProgressNotificationState.Active); + AddAssert("was not activated", () => !activated); + AddStep("reset mouse position", () => InputManager.MoveMouseTo(Vector2.Zero)); + + AddUntilStep("was completed", () => notification.State == ProgressNotificationState.Completed); + } + [Test] public void TestDismissWithoutActivationCloseButton() { From b6dd8168d29313dafdfaeccc90bb4420896df7a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 14:30:40 +0900 Subject: [PATCH 1342/2686] Fix progress notifications being able to be flung --- osu.Game/Overlays/Notifications/Notification.cs | 4 +++- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index ea654e1272..8be9d2072b 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -68,6 +68,8 @@ namespace osu.Game.Overlays.Notifications public virtual bool Read { get; set; } + protected virtual bool AllowFlingDismiss => true; + public new bool IsDragged => dragContainer.IsDragged; protected virtual IconUsage CloseButtonIcon => FontAwesome.Solid.Check; @@ -315,7 +317,7 @@ namespace osu.Game.Overlays.Notifications protected override void OnDragEnd(DragEndEvent e) { - if (Rotation < -10 || velocity.X < -0.3f) + if (notification.AllowFlingDismiss && (Rotation < -10 || velocity.X < -0.3f)) notification.Close(true); else if (X > 30 || velocity.X > 0.3f) notification.ForwardToOverlay?.Invoke(); diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 61bb22041e..4cf47013bd 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -25,6 +25,8 @@ namespace osu.Game.Overlays.Notifications public Func? CancelRequested { get; set; } + protected override bool AllowFlingDismiss => false; + /// /// The function to post completion notifications back to. /// From 4bd96108c01dc2453f7570475f2a04ac6ac463fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 14:45:17 +0900 Subject: [PATCH 1343/2686] Fix crash on game exit due to incorrect scheduling of realm change handler --- osu.Game/Overlays/FirstRunSetup/ScreenBeatmaps.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenBeatmaps.cs b/osu.Game/Overlays/FirstRunSetup/ScreenBeatmaps.cs index 82f49e0aef..4963de7251 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenBeatmaps.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenBeatmaps.cs @@ -123,7 +123,7 @@ namespace osu.Game.Overlays.FirstRunSetup beatmapSubscription?.Dispose(); } - private void beatmapsChanged(IRealmCollection sender, ChangeSet? changes, Exception error) + private void beatmapsChanged(IRealmCollection sender, ChangeSet? changes, Exception error) => Schedule(() => { currentlyLoadedBeatmaps.Text = FirstRunSetupBeatmapScreenStrings.CurrentlyLoadedBeatmaps(sender.Count); @@ -139,7 +139,7 @@ namespace osu.Game.Overlays.FirstRunSetup currentlyLoadedBeatmaps.ScaleTo(1.1f) .ScaleTo(1, 1500, Easing.OutQuint); } - } + }); private void downloadTutorial() { From c4887269f7b9096e038bd30bd50e2dd6b489e1d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 14:55:23 +0900 Subject: [PATCH 1344/2686] Avoid performing a realm write if there are no changes pending in `RulesetConfigManager` --- osu.Game/Rulesets/Configuration/RulesetConfigManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs b/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs index 5a03d66b84..4ff4f66665 100644 --- a/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs +++ b/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs @@ -58,6 +58,9 @@ namespace osu.Game.Rulesets.Configuration pendingWrites.Clear(); } + if (!changed.Any()) + return true; + realm?.Write(r => { foreach (var c in changed) From 43c16cb613cafcb35c1d862214322aff3e17b875 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 15:10:02 +0900 Subject: [PATCH 1345/2686] Fix potential crash from incorrect drawable mutation in tablet settings display --- .../Settings/Sections/Input/TabletSettings.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 271438ed14..544259ddf1 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -215,21 +215,21 @@ namespace osu.Game.Overlays.Settings.Sections.Input rotation.BindTo(tabletHandler.Rotation); areaOffset.BindTo(tabletHandler.AreaOffset); - areaOffset.BindValueChanged(val => + areaOffset.BindValueChanged(val => Schedule(() => { offsetX.Value = val.NewValue.X; offsetY.Value = val.NewValue.Y; - }, true); + }), true); offsetX.BindValueChanged(val => areaOffset.Value = new Vector2(val.NewValue, areaOffset.Value.Y)); offsetY.BindValueChanged(val => areaOffset.Value = new Vector2(areaOffset.Value.X, val.NewValue)); areaSize.BindTo(tabletHandler.AreaSize); - areaSize.BindValueChanged(val => + areaSize.BindValueChanged(val => Schedule(() => { sizeX.Value = val.NewValue.X; sizeY.Value = val.NewValue.Y; - }, true); + }), true); sizeX.BindValueChanged(val => { @@ -255,7 +255,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input }); tablet.BindTo(tabletHandler.Tablet); - tablet.BindValueChanged(val => + tablet.BindValueChanged(val => Schedule(() => { Scheduler.AddOnce(updateVisibility); @@ -274,7 +274,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input sizeY.Default = sizeY.MaxValue = tab.Size.Y; areaSize.Default = new Vector2(sizeX.Default, sizeY.Default); - }, true); + }), true); } private void updateVisibility() From 4e9b25d8b0828039524974123f48d0215ef12ca2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 15:42:37 +0900 Subject: [PATCH 1346/2686] Move `MusicController` binds to `LoadComplete` for added thread safety --- osu.Game/Overlays/MusicController.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index da87336039..793b7e294f 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -58,12 +58,11 @@ namespace osu.Game.Overlays [Resolved] private RealmAccess realm { get; set; } - [BackgroundDependencyLoader] - private void load() + protected override void LoadComplete() { - // Todo: These binds really shouldn't be here, but are unlikely to cause any issues for now. - // They are placed here for now since some tests rely on setting the beatmap _and_ their hierarchies inside their load(), which runs before the MusicController's load(). - beatmap.BindValueChanged(beatmapChanged, true); + base.LoadComplete(); + + beatmap.BindValueChanged(b => changeBeatmap(b.NewValue), true); mods.BindValueChanged(_ => ResetTrackAdjustments(), true); } @@ -263,8 +262,6 @@ namespace osu.Game.Overlays private IQueryable getBeatmapSets() => realm.Realm.All().Where(s => !s.DeletePending); - private void beatmapChanged(ValueChangedEvent beatmap) => changeBeatmap(beatmap.NewValue); - private void changeBeatmap(WorkingBeatmap newWorking) { // This method can potentially be triggered multiple times as it is eagerly fired in next() / prev() to ensure correct execution order From 32d56fe3a959a40082094b3d9399e178039f8766 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 16:02:33 +0900 Subject: [PATCH 1347/2686] Use request cancellation and `IsDisposed` guard instead of more `Schedule` --- osu.Game/Online/Leaderboards/Leaderboard.cs | 13 +++++++++---- .../Select/Leaderboards/BeatmapLeaderboard.cs | 17 ++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 206c15afde..0f444a368a 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -185,10 +185,15 @@ namespace osu.Game.Online.Leaderboards if (scores != null) this.scores.AddRange(scores); - // Schedule needs to be non-delayed here for the weird logic in refetchScores to work. - // If it is removed, the placeholder will be incorrectly updated to "no scores" rather than "retrieving". - // This whole flow should be refactored in the future. - Scheduler.Add(applyNewScores, false); + // Non-delayed schedule may potentially run inline (due to IsMainThread check passing) after leaderboard is disposed. + // This is guarded against in BeatmapLeaderboard via web request cancellation, but let's be extra safe. + if (!IsDisposed) + { + // Schedule needs to be non-delayed here for the weird logic in refetchScores to work. + // If it is removed, the placeholder will be incorrectly updated to "no scores" rather than "retrieving". + // This whole flow should be refactored in the future. + Scheduler.Add(applyNewScores, false); + } void applyNewScores() { diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index ffb13dc458..50204db2bf 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -89,6 +89,8 @@ namespace osu.Game.Screens.Select.Leaderboards private IDisposable scoreSubscription; + private GetScoresRequest scoreRetrievalRequest; + [BackgroundDependencyLoader] private void load() { @@ -151,15 +153,14 @@ namespace osu.Game.Screens.Select.Leaderboards else if (filterMods) requestMods = mods.Value; - var req = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods); + scoreRetrievalRequest = new GetScoresRequest(fetchBeatmapInfo, fetchRuleset, Scope, requestMods); - // Schedule is required to avoid potential object disposed exception when LoadComponentAsync is eventually called. - req.Success += r => Schedule(() => SetScores( - scoreManager.OrderByTotalScore(r.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))), - r.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo) - )); + scoreRetrievalRequest.Success += response => SetScores( + scoreManager.OrderByTotalScore(response.Scores.Select(s => s.ToScoreInfo(rulesets, fetchBeatmapInfo))), + response.UserScore?.CreateScoreInfo(rulesets, fetchBeatmapInfo) + ); - return req; + return scoreRetrievalRequest; } protected override LeaderboardScore CreateDrawableScore(ScoreInfo model, int index) => new LeaderboardScore(model, index, IsOnlineScope) @@ -219,7 +220,9 @@ namespace osu.Game.Screens.Select.Leaderboards protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); + scoreSubscription?.Dispose(); + scoreRetrievalRequest?.Cancel(); } } } From a1297af4410beba1dc8d1c5a24e9165eeea01b06 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 16:12:47 +0900 Subject: [PATCH 1348/2686] Apply NRT to base `Leaderboard` classes --- .../SongSelect/TestSceneBeatmapLeaderboard.cs | 13 ++++------ osu.Game/Online/Leaderboards/Leaderboard.cs | 24 ++++++++----------- .../Leaderboards/UserTopScoreContainer.cs | 10 ++++---- 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 07da1790c8..1839821bb5 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -36,10 +34,9 @@ namespace osu.Game.Tests.Visual.SongSelect [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay; - private ScoreManager scoreManager; - - private RulesetStore rulesetStore; - private BeatmapManager beatmapManager; + private ScoreManager scoreManager = null!; + private RulesetStore rulesetStore = null!; + private BeatmapManager beatmapManager = null!; protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { @@ -74,7 +71,7 @@ namespace osu.Game.Tests.Visual.SongSelect [Test] public void TestLocalScoresDisplay() { - BeatmapInfo beatmapInfo = null; + BeatmapInfo beatmapInfo = null!; AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local); @@ -387,7 +384,7 @@ namespace osu.Game.Tests.Visual.SongSelect private class FailableLeaderboard : BeatmapLeaderboard { public new void SetErrorState(LeaderboardState state) => base.SetErrorState(state); - public new void SetScores(IEnumerable scores, ScoreInfo userScore = default) => base.SetScores(scores, userScore); + public new void SetScores(IEnumerable? scores, ScoreInfo? userScore = null) => base.SetScores(scores, userScore); } } } diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 0f444a368a..69b4e5b209 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -1,14 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Development; @@ -54,23 +51,23 @@ namespace osu.Game.Online.Leaderboards private readonly Container placeholderContainer; private readonly UserTopScoreContainer userScoreContainer; - private FillFlowContainer scoreFlowContainer; + private FillFlowContainer? scoreFlowContainer; private readonly LoadingSpinner loading; - private CancellationTokenSource currentFetchCancellationSource; - private CancellationTokenSource currentScoresAsyncLoadCancellationSource; + private CancellationTokenSource? currentFetchCancellationSource; + private CancellationTokenSource? currentScoresAsyncLoadCancellationSource; - private APIRequest fetchScoresRequest; + private APIRequest? fetchScoresRequest; private LeaderboardState state; [Resolved(CanBeNull = true)] - private IAPIProvider api { get; set; } + private IAPIProvider? api { get; set; } private readonly IBindable apiState = new Bindable(); - private TScope scope; + private TScope scope = default!; public TScope Scope { @@ -179,7 +176,7 @@ namespace osu.Game.Online.Leaderboards /// /// The scores to display. /// The user top score, if any. - protected void SetScores(IEnumerable scores, TScoreInfo userScore = default) + protected void SetScores(IEnumerable? scores, TScoreInfo? userScore = default) { this.scores.Clear(); if (scores != null) @@ -213,8 +210,7 @@ namespace osu.Game.Online.Leaderboards /// /// /// An responsible for the fetch operation. This will be queued and performed automatically. - [CanBeNull] - protected abstract APIRequest FetchScores(CancellationToken cancellationToken); + protected abstract APIRequest? FetchScores(CancellationToken cancellationToken); protected abstract LeaderboardScore CreateDrawableScore(TScoreInfo model, int index); @@ -298,7 +294,7 @@ namespace osu.Game.Online.Leaderboards #region Placeholder handling - private Placeholder placeholder; + private Placeholder? placeholder; private void setState(LeaderboardState state) { @@ -325,7 +321,7 @@ namespace osu.Game.Online.Leaderboards placeholder.FadeInFromZero(fade_duration, Easing.OutQuint); } - private Placeholder getPlaceholderFor(LeaderboardState state) + private Placeholder? getPlaceholderFor(LeaderboardState state) { switch (state) { diff --git a/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs b/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs index 2d2d82821c..391e8804f0 100644 --- a/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs +++ b/osu.Game/Online/Leaderboards/UserTopScoreContainer.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. -#nullable disable - using System; using System.Threading; using osu.Framework.Bindables; @@ -18,13 +16,15 @@ namespace osu.Game.Online.Leaderboards { private const int duration = 500; - public Bindable Score = new Bindable(); + public Bindable Score = new Bindable(); private readonly Container scoreContainer; private readonly Func createScoreDelegate; protected override bool StartHidden => true; + private CancellationTokenSource? loadScoreCancellation; + public UserTopScoreContainer(Func createScoreDelegate) { this.createScoreDelegate = createScoreDelegate; @@ -65,9 +65,7 @@ namespace osu.Game.Online.Leaderboards Score.BindValueChanged(onScoreChanged); } - private CancellationTokenSource loadScoreCancellation; - - private void onScoreChanged(ValueChangedEvent score) + private void onScoreChanged(ValueChangedEvent score) { var newScore = score.NewValue; From 5fc836d1f09cebf983313c9b91a5c252890c607a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 16:15:18 +0900 Subject: [PATCH 1349/2686] Apply NRT to `BeatmapLeaderboard` / `MatchLeaderboard` --- .../Match/Components/MatchLeaderboard.cs | 6 ++-- .../Select/Leaderboards/BeatmapLeaderboard.cs | 35 +++++++++---------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs index 64644be965..ee5ee576d8 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.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. -#nullable disable - using System.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -16,7 +14,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components public class MatchLeaderboard : Leaderboard { [Resolved(typeof(Room), nameof(Room.RoomID))] - private Bindable roomId { get; set; } + private Bindable roomId { get; set; } = null!; [BackgroundDependencyLoader] private void load() @@ -33,7 +31,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components protected override bool IsOnlineScope => true; - protected override APIRequest FetchScores(CancellationToken cancellationToken) + protected override APIRequest? FetchScores(CancellationToken cancellationToken) { if (roomId.Value == null) return null; diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 50204db2bf..161d4847bf 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.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. -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics; @@ -25,11 +23,11 @@ namespace osu.Game.Screens.Select.Leaderboards { public class BeatmapLeaderboard : Leaderboard { - public Action ScoreSelected; + public Action? ScoreSelected; - private BeatmapInfo beatmapInfo; + private BeatmapInfo? beatmapInfo; - public BeatmapInfo BeatmapInfo + public BeatmapInfo? BeatmapInfo { get => beatmapInfo; set @@ -70,26 +68,26 @@ namespace osu.Game.Screens.Select.Leaderboards } [Resolved] - private ScoreManager scoreManager { get; set; } + private ScoreManager scoreManager { get; set; } = null!; [Resolved] - private IBindable ruleset { get; set; } + private IBindable ruleset { get; set; } = null!; [Resolved] - private IBindable> mods { get; set; } + private IBindable> mods { get; set; } = null!; [Resolved] - private IAPIProvider api { get; set; } + private IAPIProvider api { get; set; } = null!; [Resolved] - private RulesetStore rulesets { get; set; } + private RulesetStore rulesets { get; set; } = null!; [Resolved] - private RealmAccess realm { get; set; } + private RealmAccess realm { get; set; } = null!; - private IDisposable scoreSubscription; + private IDisposable? scoreSubscription; - private GetScoresRequest scoreRetrievalRequest; + private GetScoresRequest? scoreRetrievalRequest; [BackgroundDependencyLoader] private void load() @@ -104,10 +102,9 @@ namespace osu.Game.Screens.Select.Leaderboards protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local; - protected override APIRequest FetchScores(CancellationToken cancellationToken) + protected override APIRequest? FetchScores(CancellationToken cancellationToken) { var fetchBeatmapInfo = BeatmapInfo; - var fetchRuleset = ruleset.Value ?? fetchBeatmapInfo.Ruleset; if (fetchBeatmapInfo == null) { @@ -115,13 +112,15 @@ namespace osu.Game.Screens.Select.Leaderboards return null; } + var fetchRuleset = ruleset.Value ?? fetchBeatmapInfo.Ruleset; + if (Scope == BeatmapLeaderboardScope.Local) { subscribeToLocalScores(fetchBeatmapInfo, cancellationToken); return null; } - if (api?.IsLoggedIn != true) + if (!api.IsLoggedIn) { SetErrorState(LeaderboardState.NotLoggedIn); return null; @@ -145,7 +144,7 @@ namespace osu.Game.Screens.Select.Leaderboards return null; } - IReadOnlyList requestMods = null; + IReadOnlyList? requestMods = null; if (filterMods && !mods.Value.Any()) // add nomod for the request @@ -186,7 +185,7 @@ namespace osu.Game.Screens.Select.Leaderboards + $" AND {nameof(ScoreInfo.DeletePending)} == false" , beatmapInfo.ID, ruleset.Value.ShortName), localScoresChanged); - void localScoresChanged(IRealmCollection sender, ChangeSet changes, Exception exception) + void localScoresChanged(IRealmCollection sender, ChangeSet? changes, Exception exception) { if (cancellationToken.IsCancellationRequested) return; From 20da1051d9ab2e217f8895d4020683445618aa27 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 16:21:23 +0900 Subject: [PATCH 1350/2686] Apply NRT to `GameplayLeaderboard` hierarchy Just some cleanup work that I wanted to do as part of my last changes. --- .../Spectate/MultiSpectatorLeaderboard.cs | 2 -- .../HUD/MultiplayerGameplayLeaderboard.cs | 27 ++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs index c7af87a91d..4e9ab07e4c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.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. -#nullable disable - using System; using osu.Framework.Timing; using osu.Game.Online.Multiplayer; diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 56756249b3..4201b3f4c9 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.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. -#nullable disable - using System; using System.Collections.Generic; using System.Collections.Specialized; @@ -12,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Graphics; @@ -34,19 +33,20 @@ namespace osu.Game.Screens.Play.HUD public readonly SortedDictionary TeamScores = new SortedDictionary(); [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; [Resolved] - private SpectatorClient spectatorClient { get; set; } + private SpectatorClient spectatorClient { get; set; } = null!; [Resolved] - private MultiplayerClient multiplayerClient { get; set; } + private MultiplayerClient multiplayerClient { get; set; } = null!; [Resolved] - private UserLookupCache userLookupCache { get; set; } + private UserLookupCache userLookupCache { get; set; } = null!; + + private Bindable scoringMode = null!; private readonly MultiplayerRoomUser[] playingUsers; - private Bindable scoringMode; private readonly IBindableList playingUserIds = new BindableList(); @@ -126,14 +126,17 @@ namespace osu.Game.Screens.Play.HUD playingUserIds.BindCollectionChanged(playingUsersChanged); } - protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(IUser user, bool isTracked) + protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(IUser? user, bool isTracked) { var leaderboardScore = base.CreateLeaderboardScoreDrawable(user, isTracked); - if (UserScores[user.OnlineID].Team is int team) + if (user != null) { - leaderboardScore.BackgroundColour = getTeamColour(team).Lighten(1.2f); - leaderboardScore.TextColour = Color4.White; + if (UserScores[user.OnlineID].Team is int team) + { + leaderboardScore.BackgroundColour = getTeamColour(team).Lighten(1.2f); + leaderboardScore.TextColour = Color4.White; + } } return leaderboardScore; @@ -189,7 +192,7 @@ namespace osu.Game.Screens.Play.HUD { base.Dispose(isDisposing); - if (spectatorClient != null) + if (spectatorClient.IsNotNull()) { foreach (var user in playingUsers) spectatorClient.StopWatchingUser(user.UserID); From 0f18bef3f366eff9de289c0eb5bad5a4657867d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 26 Sep 2022 17:59:39 +0900 Subject: [PATCH 1351/2686] Fix incorrect test assumptions --- .../Visual/UserInterface/TestSceneDeleteLocalScore.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index db380cfdb7..c1a9768cf0 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -163,7 +163,7 @@ namespace osu.Game.Tests.Visual.UserInterface InputManager.PressButton(MouseButton.Left); }); - AddUntilStep("wait for fetch", () => leaderboard.Scores != null); + AddUntilStep("wait for fetch", () => leaderboard.Scores.Any()); AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != scoreBeingDeleted.OnlineID)); // "Clean up" @@ -174,7 +174,7 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestDeleteViaDatabase() { AddStep("delete top score", () => scoreManager.Delete(importedScores[0])); - AddUntilStep("wait for fetch", () => leaderboard.Scores != null); + AddUntilStep("wait for fetch", () => leaderboard.Scores.Any()); AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != importedScores[0].OnlineID)); } } From 6e1edc4d8d81ada51e958d5920846790b97cedf3 Mon Sep 17 00:00:00 2001 From: abstrakt Date: Mon, 26 Sep 2022 14:06:35 +0200 Subject: [PATCH 1352/2686] Use the `StackedEndPosition` to determine the jump distance in the `FlashlightEvaluator`. Signed-off-by: abstrakt --- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 2ba856d014..dabbfcd2fb 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (!(currentObj.BaseObject is Spinner)) { - double jumpDistance = (osuHitObject.StackedPosition - currentHitObject.EndPosition).Length; + double jumpDistance = (osuHitObject.StackedPosition - currentHitObject.StackedEndPosition).Length; cumulativeStrainTime += lastObj.StrainTime; From f81107eb5ac7dacb58c2b0955a975e0113eaf5e2 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Mon, 26 Sep 2022 20:07:43 +0800 Subject: [PATCH 1353/2686] add gameplay leaderboard config --- osu.Game/Configuration/OsuConfigManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 54c545e367..8d1de971b3 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -131,6 +131,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true); SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true); SetDefault(OsuSetting.KeyOverlay, false); + SetDefault(OsuSetting.GameplayLeaderboard, true); SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true); SetDefault(OsuSetting.FloatingComments, false); @@ -294,6 +295,7 @@ namespace osu.Game.Configuration LightenDuringBreaks, ShowStoryboard, KeyOverlay, + GameplayLeaderboard, PositionalHitsounds, PositionalHitsoundsLevel, AlwaysPlayFirstComboBreak, From bed25ff60e92b87d212a15281d65556e555e587c Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Mon, 26 Sep 2022 20:08:26 +0800 Subject: [PATCH 1354/2686] add gameplay leaderboard config string --- osu.Game/Localisation/GameplaySettingsStrings.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs index 13cfcc3a19..40f39d927d 100644 --- a/osu.Game/Localisation/GameplaySettingsStrings.cs +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -79,6 +79,11 @@ namespace osu.Game.Localisation ///
public static LocalisableString AlwaysShowKeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay"); + /// + /// "Always show gameplay leaderboard" + /// + public static LocalisableString AlwaysShowGameplayLeaderboard => new TranslatableString(getKey(@"gameplay_leaderboard"), @"Always show gameplay leaderboard"); + /// /// "Always play first combo break sound" /// From dc051a8b7992ebf6f7a7b8f08da6b16ea8b97ee8 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Mon, 26 Sep 2022 20:08:58 +0800 Subject: [PATCH 1355/2686] add gameplay leaderboard config --- osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs index 0893af7d3e..12534c51a8 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs @@ -38,6 +38,12 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay Current = config.GetBindable(OsuSetting.KeyOverlay), Keywords = new[] { "counter" }, }, + new SettingsCheckbox + { + LabelText = GameplaySettingsStrings.AlwaysShowGameplayLeaderboard, + Current = config.GetBindable(OsuSetting.GameplayLeaderboard), + Keywords = new[] { "leaderboard", "score" }, + }, }; } } From ee4d1b2d58cbb2d3c2fa51f65d88eea438f7e070 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Mon, 26 Sep 2022 20:13:07 +0800 Subject: [PATCH 1356/2686] add config visibility --- .../Screens/Play/HUD/GameplayLeaderboard.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 2d816fbd55..b618ce907d 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -3,12 +3,14 @@ using System; using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Caching; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Users; using osuTK; @@ -18,6 +20,10 @@ namespace osu.Game.Screens.Play.HUD { public abstract class GameplayLeaderboard : CompositeDrawable { + + private const int duration = 100; + + private readonly Bindable configVisibility = new Bindable(); private readonly Cached sorting = new Cached(); public Bindable Expanded = new Bindable(); @@ -57,11 +63,19 @@ namespace osu.Game.Screens.Play.HUD }; } + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility); + } + protected override void LoadComplete() { base.LoadComplete(); Scheduler.AddDelayed(sort, 1000, true); + + configVisibility.BindValueChanged(_ => updateVisibility(), true); } /// @@ -193,5 +207,8 @@ namespace osu.Game.Screens.Play.HUD public override bool HandlePositionalInput => false; public override bool HandleNonPositionalInput => false; } + + private void updateVisibility() => + Flow.FadeTo(configVisibility.Value ? 1 : 0, duration); } } From 5c132aadeb4fb60bd4dc0a50e3a9d5872643b0f1 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Mon, 26 Sep 2022 20:15:17 +0800 Subject: [PATCH 1357/2686] add visual test --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 72656c29b1..eb5846669f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -5,12 +5,14 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.PolygonExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Configuration; using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens.Play.HUD; using osuTK; @@ -24,6 +26,8 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly BindableDouble playerScore = new BindableDouble(); + private Bindable configVisibility = new Bindable(); + public TestSceneGameplayLeaderboard() { AddStep("toggle expanded", () => @@ -35,6 +39,12 @@ namespace osu.Game.Tests.Visual.Gameplay AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility); + } + [Test] public void TestLayoutWithManyScores() { @@ -129,6 +139,21 @@ namespace osu.Game.Tests.Visual.Gameplay => AddAssert($"leaderboard height is {panelCount} panels high", () => leaderboard.DrawHeight == (GameplayLeaderboardScore.PANEL_HEIGHT + leaderboard.Spacing) * panelCount); } + [Test] + public void TestVisibility() + { + createLeaderboard(); + addLocalPlayer(); + + AddStep("set visible true", () => configVisibility.Value = true); + AddWaitStep("wait", 1); + AddAssert("is leaderboard fully visible", () => leaderboard.FlowAlpha == 1); + + AddStep("set visible false", () => configVisibility.Value = false); + AddWaitStep("wait", 1); + AddAssert("is leaderboard fully invisible", () => leaderboard.FlowAlpha == 0); + } + private void addLocalPlayer() { AddStep("add local player", () => @@ -163,6 +188,8 @@ namespace osu.Game.Tests.Visual.Gameplay { public float Spacing => Flow.Spacing.Y; + public float FlowAlpha => Flow.Alpha; + public bool CheckPositionByUsername(string username, int? expectedPosition) { var scoreItem = Flow.FirstOrDefault(i => i.User?.Username == username); From 4295d9c169b5b1453162131909c6f58c95ff7cdb Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Mon, 26 Sep 2022 21:11:14 +0800 Subject: [PATCH 1358/2686] revert --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 27 ------------------- .../Screens/Play/HUD/GameplayLeaderboard.cs | 17 ------------ 2 files changed, 44 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index eb5846669f..72656c29b1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -5,14 +5,12 @@ using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.PolygonExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Utils; -using osu.Game.Configuration; using osu.Game.Online.API.Requests.Responses; using osu.Game.Screens.Play.HUD; using osuTK; @@ -26,8 +24,6 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly BindableDouble playerScore = new BindableDouble(); - private Bindable configVisibility = new Bindable(); - public TestSceneGameplayLeaderboard() { AddStep("toggle expanded", () => @@ -39,12 +35,6 @@ namespace osu.Game.Tests.Visual.Gameplay AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility); - } - [Test] public void TestLayoutWithManyScores() { @@ -139,21 +129,6 @@ namespace osu.Game.Tests.Visual.Gameplay => AddAssert($"leaderboard height is {panelCount} panels high", () => leaderboard.DrawHeight == (GameplayLeaderboardScore.PANEL_HEIGHT + leaderboard.Spacing) * panelCount); } - [Test] - public void TestVisibility() - { - createLeaderboard(); - addLocalPlayer(); - - AddStep("set visible true", () => configVisibility.Value = true); - AddWaitStep("wait", 1); - AddAssert("is leaderboard fully visible", () => leaderboard.FlowAlpha == 1); - - AddStep("set visible false", () => configVisibility.Value = false); - AddWaitStep("wait", 1); - AddAssert("is leaderboard fully invisible", () => leaderboard.FlowAlpha == 0); - } - private void addLocalPlayer() { AddStep("add local player", () => @@ -188,8 +163,6 @@ namespace osu.Game.Tests.Visual.Gameplay { public float Spacing => Flow.Spacing.Y; - public float FlowAlpha => Flow.Alpha; - public bool CheckPositionByUsername(string username, int? expectedPosition) { var scoreItem = Flow.FirstOrDefault(i => i.User?.Username == username); diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index b618ce907d..2d816fbd55 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -3,14 +3,12 @@ using System; using System.Linq; -using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Caching; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; -using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Users; using osuTK; @@ -20,10 +18,6 @@ namespace osu.Game.Screens.Play.HUD { public abstract class GameplayLeaderboard : CompositeDrawable { - - private const int duration = 100; - - private readonly Bindable configVisibility = new Bindable(); private readonly Cached sorting = new Cached(); public Bindable Expanded = new Bindable(); @@ -63,19 +57,11 @@ namespace osu.Game.Screens.Play.HUD }; } - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility); - } - protected override void LoadComplete() { base.LoadComplete(); Scheduler.AddDelayed(sort, 1000, true); - - configVisibility.BindValueChanged(_ => updateVisibility(), true); } /// @@ -207,8 +193,5 @@ namespace osu.Game.Screens.Play.HUD public override bool HandlePositionalInput => false; public override bool HandleNonPositionalInput => false; } - - private void updateVisibility() => - Flow.FadeTo(configVisibility.Value ? 1 : 0, duration); } } From 5d18001d7542159c2959ea75499b4ca5b6da8621 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Mon, 26 Sep 2022 21:11:38 +0800 Subject: [PATCH 1359/2686] move config --- .../Screens/Play/HUD/SoloGameplayLeaderboard.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index eff7870d89..fb7e2ff00f 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Configuration; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Users; @@ -13,6 +15,9 @@ namespace osu.Game.Screens.Play.HUD { public class SoloGameplayLeaderboard : GameplayLeaderboard { + private const int duration = 100; + + private readonly Bindable configVisibility = new Bindable(); private readonly IUser trackingUser; public readonly IBindableList Scores = new BindableList(); @@ -31,10 +36,18 @@ namespace osu.Game.Screens.Play.HUD this.trackingUser = trackingUser; } + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility); + } + protected override void LoadComplete() { base.LoadComplete(); Scores.BindCollectionChanged((_, _) => Scheduler.AddOnce(showScores), true); + + configVisibility.BindValueChanged(_ => updateVisibility(), true); } private void showScores() @@ -69,5 +82,8 @@ namespace osu.Game.Screens.Play.HUD // Local score should always show lower than any existing scores in cases of ties. local.DisplayOrder.Value = long.MaxValue; } + + private void updateVisibility() => + Flow.FadeTo(configVisibility.Value ? 1 : 0, duration); } } From 1fab1db145843644699095a4ab319d832c84e5ae Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Mon, 26 Sep 2022 21:11:48 +0800 Subject: [PATCH 1360/2686] move test --- .../TestSceneSoloGameplayLeaderboard.cs | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index ac73e88468..cb48275e21 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -9,11 +9,13 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Configuration; using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; +using osu.Game.Users; namespace osu.Game.Tests.Visual.Gameplay { @@ -24,6 +26,16 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly BindableList scores = new BindableList(); + private Bindable configVisibility = new Bindable(); + + private TestSoloGameplayLeaderboard? testSoloGameplayLeaderboard; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility); + } + [SetUpSteps] public void SetUpSteps() { @@ -37,7 +49,7 @@ namespace osu.Game.Tests.Visual.Gameplay Id = 2, }; - Child = new SoloGameplayLeaderboard(trackingUser) + Child = testSoloGameplayLeaderboard = new TestSoloGameplayLeaderboard(trackingUser) { Scores = { BindTarget = scores }, Anchor = Anchor.Centre, @@ -57,6 +69,18 @@ namespace osu.Game.Tests.Visual.Gameplay AddSliderStep("combo", 0, 1000, 0, v => scoreProcessor.Combo.Value = v); } + [Test] + public void TestVisibility() + { + AddStep("set visible true", () => configVisibility.Value = true); + AddWaitStep("wait", 1); + AddAssert("is leaderboard fully visible", () => testSoloGameplayLeaderboard?.FlowAlpha == 1); + + AddStep("set visible false", () => configVisibility.Value = false); + AddWaitStep("wait", 1); + AddAssert("is leaderboard fully invisible", () => testSoloGameplayLeaderboard?.FlowAlpha == 0); + } + private static List createSampleScores() { return new[] @@ -68,5 +92,13 @@ namespace osu.Game.Tests.Visual.Gameplay new ScoreInfo { User = new APIUser { Username = @"Susko3" }, TotalScore = RNG.Next(500000, 1000000) }, }.Concat(Enumerable.Range(0, 50).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 1000000 - i * 10000 })).ToList(); } + + private class TestSoloGameplayLeaderboard : SoloGameplayLeaderboard + { + public float FlowAlpha => Flow.Alpha; + public TestSoloGameplayLeaderboard(IUser trackingUser) + : base(trackingUser) + { } + } } } From 214a1c2d7fede26719017d7e8dcf73838661d02a Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Mon, 26 Sep 2022 21:26:13 +0800 Subject: [PATCH 1361/2686] code factor --- .../Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index cb48275e21..128e8b6c8a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly BindableList scores = new BindableList(); - private Bindable configVisibility = new Bindable(); + private readonly Bindable configVisibility = new Bindable(); private TestSoloGameplayLeaderboard? testSoloGameplayLeaderboard; @@ -96,9 +96,11 @@ namespace osu.Game.Tests.Visual.Gameplay private class TestSoloGameplayLeaderboard : SoloGameplayLeaderboard { public float FlowAlpha => Flow.Alpha; + public TestSoloGameplayLeaderboard(IUser trackingUser) - : base(trackingUser) - { } + : base(trackingUser) + { + } } } } From 8aff856c793d8078d0217a6a0bf0cab837f37728 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 27 Sep 2022 05:18:13 +0300 Subject: [PATCH 1362/2686] Fix `SkinnableTestScene` sizing logic potentially failing to work --- osu.Game/Tests/Visual/SkinnableTestScene.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index a8193701ef..f8f15e2729 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -140,6 +140,7 @@ namespace osu.Game.Tests.Visual { c.RelativeSizeAxes = Axes.None; c.AutoSizeAxes = Axes.None; + c.Size = Vector2.Zero; c.RelativeSizeAxes = !autoSize ? Axes.Both : Axes.None; c.AutoSizeAxes = autoSize ? Axes.Both : Axes.None; From de6709d12c5cd5f2d7d522d1f074095fe223e6f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 12:46:15 +0900 Subject: [PATCH 1363/2686] Fix `rank_history` serialisation order dependence ```csharp [network] 2022-09-26 18:18:39 [verbose]: Processing response from https://dev.ppy.sh/api/v2/me/ failed with Newtonsoft.Json.JsonSerializationException: Error setting value to 'rankHistory' on 'osu.Game.Online.API.Requests.Responses.APIUser'. [network] 2022-09-26 18:18:39 [verbose]: ---> System.NullReferenceException: Object reference not set to an instance of an object. [network] 2022-09-26 18:18:39 [verbose]: at osu.Game.Online.API.Requests.Responses.APIUser.set_rankHistory(APIRankHistory value) in /tmp/osu/osu.Game/Online/API/Requests/Responses/APIUser.cs:line 231 ``` --- osu.Game/Online/API/Requests/Responses/APIUser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIUser.cs b/osu.Game/Online/API/Requests/Responses/APIUser.cs index 5f843e9a7b..d3ddcffaf5 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUser.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUser.cs @@ -228,7 +228,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"rank_history")] private APIRankHistory rankHistory { - set => statistics.RankHistory = value; + set => Statistics.RankHistory = value; } [JsonProperty("badges")] From bac3108aea03fb72b9ccc146b6cfb7353cf8f63a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 14:29:59 +0900 Subject: [PATCH 1364/2686] Remove unnecessary keywords --- osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs index 12534c51a8..88a27840d8 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs @@ -42,7 +42,6 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { LabelText = GameplaySettingsStrings.AlwaysShowGameplayLeaderboard, Current = config.GetBindable(OsuSetting.GameplayLeaderboard), - Keywords = new[] { "leaderboard", "score" }, }, }; } From 320f134634fa3095c8522abc0b228c22f2671d92 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 14:43:08 +0900 Subject: [PATCH 1365/2686] Use same logic as `KeyCounterDisplay` --- osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs | 9 ++++++++- osu.Game/Screens/Play/ReplayPlayer.cs | 1 + osu.Game/Screens/Play/SoloPlayer.cs | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index fb7e2ff00f..471aaf9a6d 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -31,6 +31,12 @@ namespace osu.Game.Screens.Play.HUD [Resolved] private ScoreManager scoreManager { get; set; } = null!; + /// + /// Whether the leaderboard should be visible regardless of the configuration value. + /// This is true by default, but can be changed. + /// + public readonly Bindable AlwaysVisible = new Bindable(true); + public SoloGameplayLeaderboard(IUser trackingUser) { this.trackingUser = trackingUser; @@ -47,6 +53,7 @@ namespace osu.Game.Screens.Play.HUD base.LoadComplete(); Scores.BindCollectionChanged((_, _) => Scheduler.AddOnce(showScores), true); + AlwaysVisible.BindValueChanged(_ => updateVisibility()); configVisibility.BindValueChanged(_ => updateVisibility(), true); } @@ -84,6 +91,6 @@ namespace osu.Game.Screens.Play.HUD } private void updateVisibility() => - Flow.FadeTo(configVisibility.Value ? 1 : 0, duration); + this.FadeTo(AlwaysVisible.Value || configVisibility.Value ? 1 : 0, duration); } } diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 163b9c593f..5382e283e0 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -62,6 +62,7 @@ namespace osu.Game.Screens.Play protected override GameplayLeaderboard CreateGameplayLeaderboard() => new SoloGameplayLeaderboard(Score.ScoreInfo.User) { + AlwaysVisible = { Value = true }, Scores = { BindTarget = LeaderboardScores } }; diff --git a/osu.Game/Screens/Play/SoloPlayer.cs b/osu.Game/Screens/Play/SoloPlayer.cs index d7730737d6..ee19391b89 100644 --- a/osu.Game/Screens/Play/SoloPlayer.cs +++ b/osu.Game/Screens/Play/SoloPlayer.cs @@ -48,6 +48,7 @@ namespace osu.Game.Screens.Play protected override GameplayLeaderboard CreateGameplayLeaderboard() => new SoloGameplayLeaderboard(Score.ScoreInfo.User) { + AlwaysVisible = { Value = false }, Scores = { BindTarget = LeaderboardScores } }; From 4260ace1a6d24ff2a5282a89d93646b5a75a508a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 14:46:35 +0900 Subject: [PATCH 1366/2686] Fix test coverage --- .../TestSceneSoloGameplayLeaderboard.cs | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index 128e8b6c8a..8e438e98b6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly Bindable configVisibility = new Bindable(); - private TestSoloGameplayLeaderboard? testSoloGameplayLeaderboard; + private SoloGameplayLeaderboard leaderboard = null!; [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -49,11 +49,12 @@ namespace osu.Game.Tests.Visual.Gameplay Id = 2, }; - Child = testSoloGameplayLeaderboard = new TestSoloGameplayLeaderboard(trackingUser) + Child = leaderboard = new SoloGameplayLeaderboard(trackingUser) { Scores = { BindTarget = scores }, Anchor = Anchor.Centre, Origin = Anchor.Centre, + AlwaysVisible = { Value = false }, Expanded = { Value = true }, }; }); @@ -72,13 +73,17 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestVisibility() { - AddStep("set visible true", () => configVisibility.Value = true); - AddWaitStep("wait", 1); - AddAssert("is leaderboard fully visible", () => testSoloGameplayLeaderboard?.FlowAlpha == 1); + AddStep("set config visible true", () => configVisibility.Value = true); + AddUntilStep("leaderboard visible", () => leaderboard.Alpha == 1); - AddStep("set visible false", () => configVisibility.Value = false); - AddWaitStep("wait", 1); - AddAssert("is leaderboard fully invisible", () => testSoloGameplayLeaderboard?.FlowAlpha == 0); + AddStep("set config visible false", () => configVisibility.Value = false); + AddUntilStep("leaderboard not visible", () => leaderboard.Alpha == 0); + + AddStep("set always visible", () => leaderboard.AlwaysVisible.Value = true); + AddUntilStep("leaderboard visible", () => leaderboard.Alpha == 1); + + AddStep("set config visible true", () => configVisibility.Value = true); + AddAssert("leaderboard still visible", () => leaderboard.Alpha == 1); } private static List createSampleScores() @@ -92,15 +97,5 @@ namespace osu.Game.Tests.Visual.Gameplay new ScoreInfo { User = new APIUser { Username = @"Susko3" }, TotalScore = RNG.Next(500000, 1000000) }, }.Concat(Enumerable.Range(0, 50).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 1000000 - i * 10000 })).ToList(); } - - private class TestSoloGameplayLeaderboard : SoloGameplayLeaderboard - { - public float FlowAlpha => Flow.Alpha; - - public TestSoloGameplayLeaderboard(IUser trackingUser) - : base(trackingUser) - { - } - } } } From 87a1e05641d596025c73f3a572560990d391eb69 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 15:06:05 +0900 Subject: [PATCH 1367/2686] Remove unused using statement --- .../Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index 8e438e98b6..6b52e934b7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -15,7 +15,6 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; -using osu.Game.Users; namespace osu.Game.Tests.Visual.Gameplay { From 9dc0eb7fd02a81aebabb36a75c4573be545bf666 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 17:04:56 +0900 Subject: [PATCH 1368/2686] Remove unused static --- .../Edit/Compose/Components/Timeline/TimelineTickDisplay.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs index 076ce224f0..fce73d908f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs @@ -4,7 +4,6 @@ #nullable disable using System; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Caching; @@ -34,8 +33,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline [Resolved] private OsuColour colours { get; set; } - private static readonly int highest_divisor = BindableBeatDivisor.PREDEFINED_DIVISORS.Last(); - public TimelineTickDisplay() { RelativeSizeAxes = Axes.Both; From ccae721af2577dca7141b534204b3c552ec46cc3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 17:05:10 +0900 Subject: [PATCH 1369/2686] Ensure `ZoomableScrollContainer` content isn't shown until zoom is set --- .../Timeline/ZoomableScrollContainer.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index 0fb59a8a1f..839b2b5bad 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -56,7 +56,14 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline protected ZoomableScrollContainer() : base(Direction.Horizontal) { - base.Content.Add(zoomedContent = new Container { RelativeSizeAxes = Axes.Y }); + base.Content.Add(zoomedContent = new Container + { + RelativeSizeAxes = Axes.Y, + // We must hide content until SetupZoom is called. + // If not, a child component that relies on its DrawWidth (via RelativeSizeAxes) may see a very incorrect value + // momentarily, as noticed in the TimelineTickDisplay, which would render thousands of ticks incorrectly. + Alpha = 0, + }); AddLayout(zoomedContentWidthCache); } @@ -94,6 +101,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline maxZoom = maximum; CurrentZoom = zoomTarget = initial; isZoomSetUp = true; + + zoomedContent.Show(); } /// @@ -118,9 +127,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline CurrentZoom = zoomTarget = newZoom; } - protected override void Update() + protected override void UpdateAfterChildren() { - base.Update(); + base.UpdateAfterChildren(); if (!zoomedContentWidthCache.IsValid) updateZoomedContentWidth(); From e227519b093b4b2fb48dab6f5eabdf5364e8fa0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 17:18:45 +0900 Subject: [PATCH 1370/2686] Don't attempt to render timeline ticks until `DrawWidth` is above zero --- .../Timeline/TimelineTickDisplay.cs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs index fce73d908f..9018c95a47 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs @@ -77,20 +77,19 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { base.Update(); - if (timeline != null) + if (timeline == null || !(DrawWidth > 0)) return; + + (float, float) newRange = ( + (ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopLeft).X - PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X, + (ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopRight).X + PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X); + + if (visibleRange != newRange) { - var newRange = ( - (ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopLeft).X - PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X, - (ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopRight).X + PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X); + visibleRange = newRange; - if (visibleRange != newRange) - { - visibleRange = newRange; - - // actual regeneration only needs to occur if we've passed one of the known next min/max tick boundaries. - if (nextMinTick == null || nextMaxTick == null || (visibleRange.min < nextMinTick || visibleRange.max > nextMaxTick)) - tickCache.Invalidate(); - } + // actual regeneration only needs to occur if we've passed one of the known next min/max tick boundaries. + if (nextMinTick == null || nextMaxTick == null || (visibleRange.min < nextMinTick || visibleRange.max > nextMaxTick)) + tickCache.Invalidate(); } if (!tickCache.IsValid) From a9088d9231042d4dccee5a95a96551b66242224c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 17:11:36 +0900 Subject: [PATCH 1371/2686] Add assert/log output when too many ticks are being displayed --- .../Components/Timeline/TimelineTickDisplay.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs index 9018c95a47..251306ee25 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs @@ -4,10 +4,12 @@ #nullable disable using System; +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Caching; using osu.Framework.Graphics; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts; @@ -147,6 +149,20 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } } + if (Children.Count > 512) + { + // There should always be a sanely small number of ticks rendered. + // If this assertion triggers, either the zoom logic is broken or a beatmap is + // probably doing weird things... + // + // Let's hope the latter never happens. + // If it does, we can choose to either fix it or ignore it as an outlier. + string message = $"Timeline is rendering many ticks ({Children.Count})"; + + Logger.Log(message); + Debug.Fail(message); + } + int usedDrawables = drawableIndex; // save a few drawables beyond the currently used for edge cases. From 0296685c74bbc47cebdc9d7c09b91bc10e10ff6f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 17:25:24 +0900 Subject: [PATCH 1372/2686] Start key counter / gameplay leaderboard hidden to avoid initial fade out --- osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs | 3 +++ osu.Game/Screens/Play/KeyCounterDisplay.cs | 1 + 2 files changed, 4 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 471aaf9a6d..53981b9edc 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -53,6 +53,9 @@ namespace osu.Game.Screens.Play.HUD base.LoadComplete(); Scores.BindCollectionChanged((_, _) => Scheduler.AddOnce(showScores), true); + // Alpha will be updated via `updateVisibility` below. + Alpha = 0; + AlwaysVisible.BindValueChanged(_ => updateVisibility()); configVisibility.BindValueChanged(_ => updateVisibility(), true); } diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs index b6094726c0..1b726b0f7b 100644 --- a/osu.Game/Screens/Play/KeyCounterDisplay.cs +++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs @@ -39,6 +39,7 @@ namespace osu.Game.Screens.Play { Direction = FillDirection.Horizontal, AutoSizeAxes = Axes.Both, + Alpha = 0, }; } From c61f5403ab03378cce3013fa40f90714bd26083e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 17:32:30 +0900 Subject: [PATCH 1373/2686] Increase delay back slightly on notifications posting after disabled period --- osu.Game/Overlays/NotificationOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index fad8afd371..8e70f539a5 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -113,7 +113,7 @@ namespace osu.Game.Overlays if (enabled) // we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed. - notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State.Value == Visibility.Visible ? 0 : 100); + notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State.Value == Visibility.Visible ? 0 : 250); else processingPosts = false; } From 461ba64bfafa7c8a629f54e1c0fb4199a2a1790c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 17:32:53 +0900 Subject: [PATCH 1374/2686] Flush toast tray on entering a no-notification section --- osu.Game/Overlays/NotificationOverlay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 8e70f539a5..36548c893c 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -115,7 +115,10 @@ namespace osu.Game.Overlays // we want a slight delay before toggling notifications on to avoid the user becoming overwhelmed. notificationsEnabler = Scheduler.AddDelayed(() => processingPosts = true, State.Value == Visibility.Visible ? 0 : 250); else + { processingPosts = false; + toastTray.FlushAllToasts(); + } } protected override void LoadComplete() From 8b722f88172c20ff806d00a645048b7e9babd25d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 17:41:55 +0900 Subject: [PATCH 1375/2686] Change default skin for new installations to "Argon" Closes #20459. --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 54c545e367..c1d87915ce 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -39,7 +39,7 @@ namespace osu.Game.Configuration { // UI/selection defaults SetDefault(OsuSetting.Ruleset, string.Empty); - SetDefault(OsuSetting.Skin, SkinInfo.TRIANGLES_SKIN.ToString()); + SetDefault(OsuSetting.Skin, SkinInfo.ARGON_SKIN.ToString()); SetDefault(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details); SetDefault(OsuSetting.BeatmapDetailModsFilter, false); From 3ece7205eda7ea1207375f2df4b38bb58918abcc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 17:52:29 +0900 Subject: [PATCH 1376/2686] Fix potential crash when losing network connectivity at online play screen Addresses #20448. --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 61ea7d68ee..7e5d90bd4f 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -105,7 +105,8 @@ namespace osu.Game.Screens.OnlinePlay while (this.IsCurrentScreen()) this.Exit(); } - else + // Also handle the case where a child screen is current (ie. gameplay). + else if (this.GetChildScreen() != null) { this.MakeCurrent(); Schedule(forcefullyExit); From 9c4ae768f16e3d7c0f4c7f57c78480eb92ce34d4 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Tue, 27 Sep 2022 20:08:32 +0900 Subject: [PATCH 1377/2686] show object in timeline before placed just BeginPlacement() --- .../Edit/Blueprints/HitPlacementBlueprint.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs index df1450bf77..08e7e57688 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs @@ -26,6 +26,11 @@ namespace osu.Game.Rulesets.Taiko.Edit.Blueprints Size = new Vector2(TaikoHitObject.DEFAULT_SIZE * TaikoPlayfield.DEFAULT_HEIGHT) }; } + protected override void LoadComplete() + { + base.LoadComplete(); + BeginPlacement(); + } protected override bool OnMouseDown(MouseDownEvent e) { From 58217b68396d00d16b50d6e454320c8795af25ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 20:09:21 +0900 Subject: [PATCH 1378/2686] Fix weird conditional --- .../Edit/Compose/Components/Timeline/TimelineTickDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs index 251306ee25..c1c9b2493b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs @@ -79,7 +79,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { base.Update(); - if (timeline == null || !(DrawWidth > 0)) return; + if (timeline == null || DrawWidth <= 0) return; (float, float) newRange = ( (ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopLeft).X - PointVisualisation.MAX_WIDTH * 2) / DrawWidth * Content.RelativeChildSize.X, From 344015a6e6bec291b9829007938354b0e1474325 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Tue, 27 Sep 2022 20:12:40 +0900 Subject: [PATCH 1379/2686] do not move timeline when EndPlacement --- .../Edit/TaikoHitObjectComposer.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs index 1c1a5c325f..06c982397c 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; +using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Screens.Edit.Compose.Components; @@ -18,6 +19,16 @@ namespace osu.Game.Rulesets.Taiko.Edit { } + public override void EndPlacement(HitObject hitObject, bool commit) + { + EditorBeatmap.PlacementObject.Value = null; + + if (commit) + { + EditorBeatmap.Add(hitObject); + } + } + protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] { new HitCompositionTool(), From da8d94c4b46cf891eef362cb0085e8480998b629 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 27 Sep 2022 20:24:44 +0900 Subject: [PATCH 1380/2686] Fix test failures due to scheduled operations --- .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 15138b18b0..bbdfed0a00 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -54,6 +54,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { private const float disabled_alpha = 0.2f; + public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; + public Action? SettingsApplied; public OsuTextBox NameField = null!; From 1811647e34c7c663b1d94722a02a26cae38a06d5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 27 Sep 2022 20:30:41 +0900 Subject: [PATCH 1381/2686] Make room requests handler handle GetBeatmapRequest --- .../Online/API/Requests/GetBeatmapRequest.cs | 22 +++++---- .../OnlinePlay/TestRoomRequestsHandler.cs | 45 ++++++++++++------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs index efecc0fc25..3383d21dfc 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapRequest.cs @@ -9,27 +9,25 @@ namespace osu.Game.Online.API.Requests { public class GetBeatmapRequest : APIRequest { - private readonly IBeatmapInfo beatmapInfo; - - private readonly string filename; + public readonly IBeatmapInfo BeatmapInfo; + public readonly string Filename; public GetBeatmapRequest(IBeatmapInfo beatmapInfo) { - this.beatmapInfo = beatmapInfo; - - filename = (beatmapInfo as BeatmapInfo)?.Path ?? string.Empty; + BeatmapInfo = beatmapInfo; + Filename = (beatmapInfo as BeatmapInfo)?.Path ?? string.Empty; } protected override WebRequest CreateWebRequest() { var request = base.CreateWebRequest(); - if (beatmapInfo.OnlineID > 0) - request.AddParameter(@"id", beatmapInfo.OnlineID.ToString()); - if (!string.IsNullOrEmpty(beatmapInfo.MD5Hash)) - request.AddParameter(@"checksum", beatmapInfo.MD5Hash); - if (!string.IsNullOrEmpty(filename)) - request.AddParameter(@"filename", filename); + if (BeatmapInfo.OnlineID > 0) + request.AddParameter(@"id", BeatmapInfo.OnlineID.ToString()); + if (!string.IsNullOrEmpty(BeatmapInfo.MD5Hash)) + request.AddParameter(@"checksum", BeatmapInfo.MD5Hash); + if (!string.IsNullOrEmpty(Filename)) + request.AddParameter(@"filename", Filename); return request; } diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs index fa7ade2c07..ef4539ba56 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs @@ -135,25 +135,15 @@ namespace osu.Game.Tests.Visual.OnlinePlay }); return true; + case GetBeatmapRequest getBeatmapRequest: + { + getBeatmapRequest.TriggerSuccess(createResponseBeatmaps(getBeatmapRequest.BeatmapInfo.OnlineID).Single()); + return true; + } + case GetBeatmapsRequest getBeatmapsRequest: { - var result = new List(); - - foreach (int id in getBeatmapsRequest.BeatmapIds) - { - var baseBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineID == id); - - if (baseBeatmap == null) - { - baseBeatmap = new TestBeatmap(new RulesetInfo { OnlineID = 0 }).BeatmapInfo; - baseBeatmap.OnlineID = id; - baseBeatmap.BeatmapSet!.OnlineID = id; - } - - result.Add(OsuTestScene.CreateAPIBeatmap(baseBeatmap)); - } - - getBeatmapsRequest.TriggerSuccess(new GetBeatmapsResponse { Beatmaps = result }); + getBeatmapsRequest.TriggerSuccess(new GetBeatmapsResponse { Beatmaps = createResponseBeatmaps(getBeatmapsRequest.BeatmapIds.ToArray()) }); return true; } @@ -175,6 +165,27 @@ namespace osu.Game.Tests.Visual.OnlinePlay } } + List createResponseBeatmaps(params int[] beatmapIds) + { + var result = new List(); + + foreach (int id in beatmapIds) + { + var baseBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineID == id); + + if (baseBeatmap == null) + { + baseBeatmap = new TestBeatmap(new RulesetInfo { OnlineID = 0 }).BeatmapInfo; + baseBeatmap.OnlineID = id; + baseBeatmap.BeatmapSet!.OnlineID = id; + } + + result.Add(OsuTestScene.CreateAPIBeatmap(baseBeatmap)); + } + + return result; + } + return false; } From ed0752a5f12d29de2ec0e57e7cd9ae25ee0ef729 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 21:55:03 +0900 Subject: [PATCH 1382/2686] Update test assumptions --- osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs index 3757c49f18..010ed23c9b 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs @@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestEditDefaultSkin() { - AddAssert("is default skin", () => skinManager.CurrentSkinInfo.Value.ID == SkinInfo.TRIANGLES_SKIN); + AddAssert("is default skin", () => skinManager.CurrentSkinInfo.Value.ID == SkinInfo.ARGON_SKIN); AddStep("open settings", () => { Game.Settings.Show(); }); @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("open skin editor", () => skinEditor.Show()); // Until step required as the skin editor may take time to load (and an extra scheduled frame for the mutable part). - AddUntilStep("is modified default skin", () => skinManager.CurrentSkinInfo.Value.ID != SkinInfo.TRIANGLES_SKIN); + AddUntilStep("is modified default skin", () => skinManager.CurrentSkinInfo.Value.ID != SkinInfo.ARGON_SKIN); AddAssert("is not protected", () => skinManager.CurrentSkinInfo.Value.PerformRead(s => !s.Protected)); AddUntilStep("export button enabled", () => Game.Settings.ChildrenOfType().SingleOrDefault()?.Enabled.Value == true); From 1721b8e47aad4959d3b20f7516cb151e44938b92 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 27 Sep 2022 16:25:26 +0300 Subject: [PATCH 1383/2686] Add request class --- .../API/Requests/CommentDeleteRequest.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 osu.Game/Online/API/Requests/CommentDeleteRequest.cs diff --git a/osu.Game/Online/API/Requests/CommentDeleteRequest.cs b/osu.Game/Online/API/Requests/CommentDeleteRequest.cs new file mode 100644 index 0000000000..4eb91718fe --- /dev/null +++ b/osu.Game/Online/API/Requests/CommentDeleteRequest.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Net.Http; +using osu.Framework.IO.Network; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class CommentDeleteRequest : APIRequest + { + private readonly long id; + + public CommentDeleteRequest(long id) + { + this.id = id; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Delete; + return req; + } + + protected override string Target => $@"comments/{id}"; + } +} From f3e25eacadc046c96669dab7e5f430b068d851ce Mon Sep 17 00:00:00 2001 From: o-dasher <88356162+o-dasher@users.noreply.github.com> Date: Tue, 27 Sep 2022 09:25:58 -0400 Subject: [PATCH 1384/2686] Removes unnecessary setting sources specifications --- osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs | 3 --- osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs | 7 ------- osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs | 3 --- osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs | 2 -- osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs | 7 ------- osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs | 2 ++ osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs | 3 --- osu.Game/Rulesets/Mods/ModNoScope.cs | 7 +++++++ osu.Game/Rulesets/Mods/ModWindDown.cs | 4 ---- osu.Game/Rulesets/Mods/ModWindUp.cs | 4 ---- 12 files changed, 9 insertions(+), 37 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index 41d4590aa8..1adc969f8f 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs @@ -3,7 +3,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Configuration; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Mods; @@ -16,7 +15,6 @@ namespace osu.Game.Rulesets.Catch.Mods { public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1; - [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")] public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1) { MinValue = 0.5f, @@ -24,7 +22,6 @@ namespace osu.Game.Rulesets.Catch.Mods Precision = 0.1f }; - [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")] public override BindableBool ComboBasedSize { get; } = new BindableBool(true); public override float DefaultFlashlightSize => 350; diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs index 1b781b032c..19b4a39f97 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModNoScope.cs @@ -6,8 +6,6 @@ using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Rulesets.Mods; using osu.Framework.Utils; -using osu.Game.Configuration; -using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.UI; @@ -17,11 +15,6 @@ namespace osu.Game.Rulesets.Catch.Mods { public override LocalisableString Description => "Where's the catcher?"; - [SettingSource( - "Hidden at combo", - "The combo count at which the catcher becomes completely hidden", - SettingControlType = typeof(SettingsSlider) - )] public override BindableInt HiddenComboCount { get; } = new BindableInt(10) { MinValue = 0, diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs index 72ea1a2431..6eaede2112 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs @@ -5,7 +5,6 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Layout; -using osu.Game.Configuration; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mods; using osuTK; @@ -17,7 +16,6 @@ namespace osu.Game.Rulesets.Mania.Mods public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(ModHidden) }; - [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")] public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1) { MinValue = 0.5f, @@ -25,7 +23,6 @@ namespace osu.Game.Rulesets.Mania.Mods Precision = 0.1f }; - [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")] public override BindableBool ComboBasedSize { get; } = new BindableBool(); public override float DefaultFlashlightSize => 50; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs index b2980f5311..f6622c268d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs @@ -4,7 +4,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Configuration; namespace osu.Game.Rulesets.Osu.Mods { @@ -18,7 +17,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override LocalisableString Description => "Hit them at the right size!"; - [SettingSource("Starting Size", "The initial size multiplier applied to all objects.")] public override BindableNumber StartScale { get; } = new BindableFloat(2) { MinValue = 1f, diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index 7b34fe05a9..79f5eed139 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -32,7 +32,6 @@ namespace osu.Game.Rulesets.Osu.Mods Precision = default_follow_delay, }; - [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")] public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1) { MinValue = 0.5f, @@ -40,7 +39,6 @@ namespace osu.Game.Rulesets.Osu.Mods Precision = 0.1f }; - [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")] public override BindableBool ComboBasedSize { get; } = new BindableBool(true); public override float DefaultFlashlightSize => 180; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs index b49257e289..3d066d3ada 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs @@ -4,7 +4,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Configuration; namespace osu.Game.Rulesets.Osu.Mods { @@ -18,7 +17,6 @@ namespace osu.Game.Rulesets.Osu.Mods public override LocalisableString Description => "Hit them at the right size!"; - [SettingSource("Starting Size", "The initial size multiplier applied to all objects.")] public override BindableNumber StartScale { get; } = new BindableFloat(0.5f) { MinValue = 0f, diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs index 84538cec30..2f84c30581 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs @@ -7,8 +7,6 @@ using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Beatmaps; -using osu.Game.Configuration; -using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.UI; @@ -22,11 +20,6 @@ namespace osu.Game.Rulesets.Osu.Mods private PeriodTracker spinnerPeriods = null!; - [SettingSource( - "Hidden at combo", - "The combo count at which the cursor becomes completely hidden", - SettingControlType = typeof(SettingsSlider) - )] public override BindableInt HiddenComboCount { get; } = new BindableInt(10) { MinValue = 0, diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs index 59984f9a7b..6f1206382a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModObjectScaleTween.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; @@ -20,6 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; + [SettingSource("Starting Size", "The initial size multiplier applied to all objects.")] public abstract BindableNumber StartScale { get; } protected virtual float EndScale => 1; diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 05baf88a33..1caacdd1d7 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -4,7 +4,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Layout; -using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.UI; @@ -17,7 +16,6 @@ namespace osu.Game.Rulesets.Taiko.Mods { public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1; - [SettingSource("Flashlight size", "Multiplier applied to the default flashlight size.")] public override BindableFloat SizeMultiplier { get; } = new BindableFloat(1) { MinValue = 0.5f, @@ -25,7 +23,6 @@ namespace osu.Game.Rulesets.Taiko.Mods Precision = 0.1f }; - [SettingSource("Change size based on combo", "Decrease the flashlight size as combo increases.")] public override BindableBool ComboBasedSize { get; } = new BindableBool(true); public override float DefaultFlashlightSize => 250; diff --git a/osu.Game/Rulesets/Mods/ModNoScope.cs b/osu.Game/Rulesets/Mods/ModNoScope.cs index 1b9ce833ad..36fbb88943 100644 --- a/osu.Game/Rulesets/Mods/ModNoScope.cs +++ b/osu.Game/Rulesets/Mods/ModNoScope.cs @@ -6,7 +6,9 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play; @@ -34,6 +36,11 @@ namespace osu.Game.Rulesets.Mods protected float ComboBasedAlpha; + [SettingSource( + "Hidden at combo", + "The combo count at which the cursor becomes completely hidden", + SettingControlType = typeof(SettingsSlider) + )] public abstract BindableInt HiddenComboCount { get; } public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; diff --git a/osu.Game/Rulesets/Mods/ModWindDown.cs b/osu.Game/Rulesets/Mods/ModWindDown.cs index 15ee37d481..35a673093b 100644 --- a/osu.Game/Rulesets/Mods/ModWindDown.cs +++ b/osu.Game/Rulesets/Mods/ModWindDown.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Configuration; namespace osu.Game.Rulesets.Mods { @@ -17,7 +16,6 @@ namespace osu.Game.Rulesets.Mods public override LocalisableString Description => "Sloooow doooown..."; public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleDown; - [SettingSource("Initial rate", "The starting speed of the track")] public override BindableNumber InitialRate { get; } = new BindableDouble(1) { MinValue = 0.51, @@ -25,7 +23,6 @@ namespace osu.Game.Rulesets.Mods Precision = 0.01, }; - [SettingSource("Final rate", "The speed increase to ramp towards")] public override BindableNumber FinalRate { get; } = new BindableDouble(0.75) { MinValue = 0.5, @@ -33,7 +30,6 @@ namespace osu.Game.Rulesets.Mods Precision = 0.01, }; - [SettingSource("Adjust pitch", "Should pitch be adjusted with speed")] public override BindableBool AdjustPitch { get; } = new BindableBool(true); public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindUp)).ToArray(); diff --git a/osu.Game/Rulesets/Mods/ModWindUp.cs b/osu.Game/Rulesets/Mods/ModWindUp.cs index 6d8838c5a5..bbc8382055 100644 --- a/osu.Game/Rulesets/Mods/ModWindUp.cs +++ b/osu.Game/Rulesets/Mods/ModWindUp.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Configuration; namespace osu.Game.Rulesets.Mods { @@ -17,7 +16,6 @@ namespace osu.Game.Rulesets.Mods public override LocalisableString Description => "Can you keep up?"; public override IconUsage? Icon => FontAwesome.Solid.ChevronCircleUp; - [SettingSource("Initial rate", "The starting speed of the track")] public override BindableNumber InitialRate { get; } = new BindableDouble(1) { MinValue = 0.5, @@ -25,7 +23,6 @@ namespace osu.Game.Rulesets.Mods Precision = 0.01, }; - [SettingSource("Final rate", "The speed increase to ramp towards")] public override BindableNumber FinalRate { get; } = new BindableDouble(1.5) { MinValue = 0.51, @@ -33,7 +30,6 @@ namespace osu.Game.Rulesets.Mods Precision = 0.01, }; - [SettingSource("Adjust pitch", "Should pitch be adjusted with speed")] public override BindableBool AdjustPitch { get; } = new BindableBool(true); public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModWindDown)).ToArray(); From 0cffbb756286971645105c3794afd03bca3e4122 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Tue, 27 Sep 2022 16:54:24 +0200 Subject: [PATCH 1385/2686] Clamp `LifetimeStart` of `HitObject`'s to their judgement windows --- .../Objects/Drawables/DrawableHoldNoteTail.cs | 2 +- .../Objects/Drawables/DrawableSpinnerTick.cs | 2 +- .../Objects/Drawables/DrawableDrumRollTick.cs | 2 +- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- .../Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 6 +++++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs index a7bdcd047e..3084f71be2 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables public void UpdateResult() => base.UpdateResult(true); - protected override double MaximumJudgementOffset => base.MaximumJudgementOffset * release_window_lenience; + public override double MaximumJudgementOffset => base.MaximumJudgementOffset * release_window_lenience; protected override void CheckForResult(bool userTriggered, double timeOffset) { diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs index 6a15463a32..4975ca1248 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Origin = Anchor.Centre; } - protected override double MaximumJudgementOffset => DrawableSpinner.HitObject.Duration; + public override double MaximumJudgementOffset => DrawableSpinner.HitObject.Duration; /// /// Apply a judgement result. diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index 705a0a8047..451c5a793b 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables Filled = HitObject.FirstTick }); - protected override double MaximumJudgementOffset => HitObject.HitWindow; + public override double MaximumJudgementOffset => HitObject.HitWindow; protected override void CheckForResult(bool userTriggered, double timeOffset) { diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index e218da918c..dec68a6c22 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -651,7 +651,7 @@ namespace osu.Game.Rulesets.Objects.Drawables /// /// This does not affect the time offset provided to invocations of . /// - protected virtual double MaximumJudgementOffset => HitObject.HitWindows?.WindowFor(HitResult.Miss) ?? 0; + public virtual double MaximumJudgementOffset => HitObject.HitWindows?.WindowFor(HitResult.Miss) ?? 0; /// /// Applies the of this , notifying responders such as diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 0ed3ca1e63..d0aca4e7fc 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using System.Collections.Generic; using System.Diagnostics; using osu.Framework.Allocation; @@ -214,7 +215,10 @@ namespace osu.Game.Rulesets.UI.Scrolling break; } - return scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, originAdjustment, timeRange.Value, scrollLength); + double computedStartTime = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, originAdjustment, timeRange.Value, scrollLength); + + // always load the hitobject before its first judgement offset + return Math.Min(hitObject.HitObject.StartTime - hitObject.MaximumJudgementOffset, computedStartTime); } private void updateLayoutRecursive(DrawableHitObject hitObject) From 710f9e8f588907b61efb5eb4bd5032fc4237a41b Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 27 Sep 2022 18:11:27 +0300 Subject: [PATCH 1386/2686] Setup a test scene --- .../Visual/Online/TestSceneCommentActions.cs | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs new file mode 100644 index 0000000000..2778cb509a --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -0,0 +1,109 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays; +using osu.Game.Overlays.Comments; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneCommentActions : OsuTestScene + { + private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; + + [Cached] + private readonly DialogOverlay dialogOverlay = new DialogOverlay(); + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + + private CommentsContainer commentsContainer = null!; + + [SetUpSteps] + public void SetUp() + { + API.Login("test", "test"); + Schedule(() => + { + if (dialogOverlay.Parent != null) Remove(dialogOverlay, false); + Children = new Container[] + { + new BasicScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = commentsContainer = new CommentsContainer() + }, + dialogOverlay + }; + }); + } + + [Test] + public void TestNonOwnCommentCantBeDeleted() + { + addTestComments(); + } + + [Test] + public void TestDeletion() + { + addTestComments(); + } + + private void addTestComments() + { + CommentBundle cb = new CommentBundle + { + Comments = new List + { + new Comment + { + Id = 1, + Message = "This is our comment", + UserId = API.LocalUser.Value.Id, + CreatedAt = DateTimeOffset.Now, + User = API.LocalUser.Value, + }, + new Comment + { + Id = 2, + Message = "This is a comment by another user", + UserId = API.LocalUser.Value.Id + 1, + CreatedAt = DateTimeOffset.Now, + User = new APIUser + { + Id = API.LocalUser.Value.Id + 1, + Username = "Another user" + } + }, + }, + IncludedComments = new List(), + PinnedComments = new List(), + }; + setUpCommentsResponse(cb); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + } + + private void setUpCommentsResponse(CommentBundle commentBundle) + => AddStep("set up response", () => + { + dummyAPI.HandleRequest = request => + { + if (!(request is GetCommentsRequest getCommentsRequest)) + return false; + + getCommentsRequest.TriggerSuccess(commentBundle); + return true; + }; + }); + } +} From 31a7ba3f9135be69c9de81682585b65ec783f6bc Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 27 Sep 2022 18:23:15 +0300 Subject: [PATCH 1387/2686] Add delete button --- osu.Game/Overlays/Comments/DrawableComment.cs | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 296320ec1b..a0b752b842 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -22,6 +22,8 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; using osu.Framework.Localisation; +using osu.Framework.Logging; +using osu.Game.Online.API; using osu.Game.Overlays.Comments.Buttons; using osu.Game.Resources.Localisation.Web; @@ -59,10 +61,11 @@ namespace osu.Game.Overlays.Comments } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider, IAPIProvider api) { LinkFlowContainer username; FillFlowContainer info; + LinkFlowContainer actions; CommentMarkdownContainer message; GridContainer content; VotePill votePill; @@ -163,16 +166,30 @@ namespace osu.Game.Overlays.Comments DocumentMargin = new MarginPadding(0), DocumentPadding = new MarginPadding(0), }, - info = new FillFlowContainer + new FillFlowContainer { AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(10, 0), - Children = new Drawable[] + Children = new[] { - new DrawableDate(Comment.CreatedAt, 12, false) + info = new FillFlowContainer { - Colour = colourProvider.Foreground1 + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + new DrawableDate(Comment.CreatedAt, 12, false) + { + Colour = colourProvider.Foreground1 + } + } + }, + actions = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) + { + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(10, 0) } } }, @@ -288,6 +305,11 @@ namespace osu.Game.Overlays.Comments votePill.Hide(); } + if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) + { + actions.AddLink("Delete", () => Logger.Log("Attempt to delete a comment", level: LogLevel.Important)); + } + if (Comment.IsTopLevel) { AddInternal(new Box From 60ee813e45e462d354fbfd400818938bf6a0f192 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 27 Sep 2022 18:33:16 +0300 Subject: [PATCH 1388/2686] Implement delete button --- osu.Game/Overlays/Comments/DrawableComment.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index a0b752b842..20869d1250 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -22,9 +22,10 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; using osu.Framework.Localisation; -using osu.Framework.Logging; using osu.Game.Online.API; +using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; +using osu.Game.Overlays.Dialog; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments @@ -61,7 +62,7 @@ namespace osu.Game.Overlays.Comments } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, IAPIProvider api) + private void load(OverlayColourProvider colourProvider, IAPIProvider api, DialogOverlay dialogOverlay) { LinkFlowContainer username; FillFlowContainer info; @@ -307,7 +308,20 @@ namespace osu.Game.Overlays.Comments if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) { - actions.AddLink("Delete", () => Logger.Log("Attempt to delete a comment", level: LogLevel.Important)); + actions.AddLink("Delete", () => + { + dialogOverlay.Push(new ConfirmDialog("Do you really want to delete your comment?", () => + { + var request = new CommentDeleteRequest(Comment.Id); + request.Success += _ => + { + //TODO this is temporary just for testing + content.FadeColour(OsuColour.Gray(0.5f)); + votePill.Hide(); + }; + api.Queue(request); + })); + }); } if (Comment.IsTopLevel) From 5da7cb5397867b99d671d21c81dd395ee270b284 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 27 Sep 2022 19:02:18 +0300 Subject: [PATCH 1389/2686] Make comment ID public for test --- osu.Game/Online/API/Requests/CommentDeleteRequest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/API/Requests/CommentDeleteRequest.cs b/osu.Game/Online/API/Requests/CommentDeleteRequest.cs index 4eb91718fe..4209ff9d30 100644 --- a/osu.Game/Online/API/Requests/CommentDeleteRequest.cs +++ b/osu.Game/Online/API/Requests/CommentDeleteRequest.cs @@ -9,11 +9,11 @@ namespace osu.Game.Online.API.Requests { public class CommentDeleteRequest : APIRequest { - private readonly long id; + public readonly long ID; public CommentDeleteRequest(long id) { - this.id = id; + this.ID = id; } protected override WebRequest CreateWebRequest() @@ -23,6 +23,6 @@ namespace osu.Game.Online.API.Requests return req; } - protected override string Target => $@"comments/{id}"; + protected override string Target => $@"comments/{ID}"; } } From 2f551be1befa1fd1d0c6d8b6387bc023a3fd0efe Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 27 Sep 2022 19:03:02 +0300 Subject: [PATCH 1390/2686] Implement tests --- .../Visual/Online/TestSceneCommentActions.cs | 73 ++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 2778cb509a..dcab92d772 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -3,20 +3,23 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Comments; +using osuTK.Input; namespace osu.Game.Tests.Visual.Online { - public class TestSceneCommentActions : OsuTestScene + public class TestSceneCommentActions : OsuManualInputManagerTestScene { private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; @@ -51,12 +54,80 @@ namespace osu.Game.Tests.Visual.Online public void TestNonOwnCommentCantBeDeleted() { addTestComments(); + + AddAssert("First comment has button", () => + { + var comments = this.ChildrenOfType(); + var ourComment = comments.Single(x => x.Comment.Id == 1); + return ourComment.ChildrenOfType().Any(x => x.Text == "Delete"); + }); + + AddAssert("Second doesn't", () => + { + var comments = this.ChildrenOfType(); + var ourComment = comments.Single(x => x.Comment.Id == 2); + return ourComment.ChildrenOfType().All(x => x.Text != "Delete"); + }); } [Test] public void TestDeletion() { + DrawableComment ourComment = null!; + bool delete = false; + addTestComments(); + AddStep("Comment exists", () => + { + var comments = this.ChildrenOfType(); + ourComment = comments.Single(x => x.Comment.Id == 1); + }); + AddStep("It has delete button", () => + { + var btn = ourComment.ChildrenOfType().Single(x => x.Text == "Delete"); + InputManager.MoveMouseTo(btn); + }); + AddStep("Click delete button", () => + { + InputManager.Click(MouseButton.Left); + }); + AddStep("Setup request handling", () => + { + dummyAPI.HandleRequest = request => + { + if (!(request is CommentDeleteRequest req)) + return false; + + if (req.ID != 1) + return false; + + CommentBundle cb = new CommentBundle + { + Comments = new List + { + new Comment + { + Id = 2, + Message = "This is a comment by another user", + UserId = API.LocalUser.Value.Id + 1, + CreatedAt = DateTimeOffset.Now, + User = new APIUser + { + Id = API.LocalUser.Value.Id + 1, + Username = "Another user" + } + }, + }, + IncludedComments = new List(), + PinnedComments = new List(), + }; + delete = true; + req.TriggerSuccess(cb); + return true; + }; + }); + AddStep("Confirm dialog", () => InputManager.Key(Key.Number1)); + AddUntilStep("Deletion requested", () => delete); } private void addTestComments() From 5282c8b8c65cd3acda6488571c1de0bd903f36a7 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 27 Sep 2022 19:40:18 +0300 Subject: [PATCH 1391/2686] Fix CQ --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 2 +- osu.Game/Online/API/Requests/CommentDeleteRequest.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index dcab92d772..2ffdc3be27 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Online if (!(request is CommentDeleteRequest req)) return false; - if (req.ID != 1) + if (req.CommentId != 1) return false; CommentBundle cb = new CommentBundle diff --git a/osu.Game/Online/API/Requests/CommentDeleteRequest.cs b/osu.Game/Online/API/Requests/CommentDeleteRequest.cs index 4209ff9d30..b150a6d5fc 100644 --- a/osu.Game/Online/API/Requests/CommentDeleteRequest.cs +++ b/osu.Game/Online/API/Requests/CommentDeleteRequest.cs @@ -9,11 +9,11 @@ namespace osu.Game.Online.API.Requests { public class CommentDeleteRequest : APIRequest { - public readonly long ID; + public readonly long CommentId; public CommentDeleteRequest(long id) { - this.ID = id; + CommentId = id; } protected override WebRequest CreateWebRequest() @@ -23,6 +23,6 @@ namespace osu.Game.Online.API.Requests return req; } - protected override string Target => $@"comments/{ID}"; + protected override string Target => $@"comments/{CommentId}"; } } From eae8916e76ac0b0795565fd1d93cdb10a5136e2a Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Tue, 27 Sep 2022 19:52:55 +0200 Subject: [PATCH 1392/2686] Add test --- .../Judgements/TestSceneHitJudgements.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs index a405f0e8ba..d2d5cdb6ac 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using NUnit.Framework; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; @@ -129,5 +130,32 @@ namespace osu.Game.Rulesets.Taiko.Tests.Judgements AssertResult(0, HitResult.Miss); AssertResult(0, HitResult.IgnoreMiss); } + + [Test] + public void TestHighVelocityHit() + { + const double hit_time = 1000; + + var beatmap = CreateBeatmap(new Hit + { + Type = HitType.Centre, + StartTime = hit_time, + }); + + beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 6 }); + beatmap.ControlPointInfo.Add(0, new EffectControlPoint { ScrollSpeed = 10 }); + + var hitWindows = new HitWindows(); + hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); + + PerformTest(new List + { + new TaikoReplayFrame(0), + new TaikoReplayFrame(hit_time - hitWindows.WindowFor(HitResult.Great), TaikoAction.LeftCentre), + }, beatmap); + + AssertJudgementCount(1); + AssertResult(0, HitResult.Ok); + } } } From 4013c96ca556410b3d4feddd729bb37f58ac3aa1 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 27 Sep 2022 22:40:53 +0300 Subject: [PATCH 1393/2686] Fix test failures --- .../Visual/Online/TestSceneCommentActions.cs | 15 +++++++------- .../Online/TestSceneCommentsContainer.cs | 20 ++++++++++++++----- .../Visual/Online/TestSceneDrawableComment.cs | 5 +++++ .../TestSceneOfflineCommentsContainer.cs | 5 +++++ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 2ffdc3be27..88e4d6e83b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -34,9 +34,9 @@ namespace osu.Game.Tests.Visual.Online [SetUpSteps] public void SetUp() { - API.Login("test", "test"); Schedule(() => { + API.Login("test", "test"); if (dialogOverlay.Parent != null) Remove(dialogOverlay, false); Children = new Container[] { @@ -55,11 +55,11 @@ namespace osu.Game.Tests.Visual.Online { addTestComments(); - AddAssert("First comment has button", () => + AddUntilStep("First comment has button", () => { var comments = this.ChildrenOfType(); - var ourComment = comments.Single(x => x.Comment.Id == 1); - return ourComment.ChildrenOfType().Any(x => x.Text == "Delete"); + var ourComment = comments.SingleOrDefault(x => x.Comment.Id == 1); + return ourComment != null && ourComment.ChildrenOfType().Any(x => x.Text == "Delete"); }); AddAssert("Second doesn't", () => @@ -73,14 +73,15 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestDeletion() { - DrawableComment ourComment = null!; + DrawableComment? ourComment = null; bool delete = false; addTestComments(); - AddStep("Comment exists", () => + AddUntilStep("Comment exists", () => { var comments = this.ChildrenOfType(); - ourComment = comments.Single(x => x.Comment.Id == 1); + ourComment = comments.SingleOrDefault(x => x.Comment.Id == 1); + return ourComment != null; }); AddStep("It has delete button", () => { diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index a94b9e61c0..08881e9718 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -25,17 +25,27 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + [Cached] + private readonly DialogOverlay dialogOverlay = new DialogOverlay(); + private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; private CommentsContainer commentsContainer; [SetUp] public void SetUp() => Schedule(() => - Child = new BasicScrollContainer + { + if (dialogOverlay.Parent != null) Remove(dialogOverlay, false); + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Child = commentsContainer = new CommentsContainer() - }); + new BasicScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = commentsContainer = new CommentsContainer() + }, + dialogOverlay + }; + }); [Test] public void TestIdleState() @@ -139,7 +149,7 @@ namespace osu.Game.Tests.Visual.Online }; }); - private CommentBundle getExampleComments(bool withPinned = false) + private static CommentBundle getExampleComments(bool withPinned = false) { var bundle = new CommentBundle { diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs index cab0ffa3ba..7253424984 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -20,11 +20,15 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + [Cached] + private readonly DialogOverlay dialogOverlay = new DialogOverlay(); + private Container container; [SetUp] public void SetUp() => Schedule(() => { + if (dialogOverlay.Parent != null) Remove(dialogOverlay, false); Children = new Drawable[] { new Box @@ -37,6 +41,7 @@ namespace osu.Game.Tests.Visual.Online RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }, + dialogOverlay }; }); diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs index 07ccfcec88..46bbbd635a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -24,17 +24,22 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + [Cached] + private readonly DialogOverlay dialogOverlay = new DialogOverlay(); + private TestCommentsContainer comments; [SetUp] public void SetUp() => Schedule(() => { + if (dialogOverlay.Parent != null) Remove(dialogOverlay, false); Clear(); Add(new BasicScrollContainer { RelativeSizeAxes = Axes.Both, Child = comments = new TestCommentsContainer() }); + Add(dialogOverlay); }); [Test] From 58d9509ce686b5e96c0d592bf93f913b5f0ca2a9 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 27 Sep 2022 22:45:05 +0300 Subject: [PATCH 1394/2686] Apply NRT to `Comment` --- .../Online/API/Requests/Responses/Comment.cs | 16 +++++++--------- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 500c0566e6..907632186c 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.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. -#nullable disable - using Newtonsoft.Json; using System; @@ -16,18 +14,18 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"parent_id")] public long? ParentId { get; set; } - public Comment ParentComment { get; set; } + public Comment? ParentComment { get; set; } [JsonProperty(@"user_id")] public long? UserId { get; set; } - public APIUser User { get; set; } + public APIUser? User { get; set; } [JsonProperty(@"message")] - public string Message { get; set; } + public string Message { get; set; } = null!; [JsonProperty(@"message_html")] - public string MessageHtml { get; set; } + public string? MessageHtml { get; set; } [JsonProperty(@"replies_count")] public int RepliesCount { get; set; } @@ -36,13 +34,13 @@ namespace osu.Game.Online.API.Requests.Responses public int VotesCount { get; set; } [JsonProperty(@"commenatble_type")] - public string CommentableType { get; set; } + public string CommentableType { get; set; } = null!; [JsonProperty(@"commentable_id")] public int CommentableId { get; set; } [JsonProperty(@"legacy_name")] - public string LegacyName { get; set; } + public string? LegacyName { get; set; } [JsonProperty(@"created_at")] public DateTimeOffset CreatedAt { get; set; } @@ -62,7 +60,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"pinned")] public bool Pinned { get; set; } - public APIUser EditedUser { get; set; } + public APIUser? EditedUser { get; set; } public bool IsTopLevel => !ParentId.HasValue; diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 20869d1250..39f46210b0 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -266,7 +266,7 @@ namespace osu.Game.Overlays.Comments else username.AddText(Comment.LegacyName); - if (Comment.EditedAt.HasValue) + if (Comment.EditedAt.HasValue && Comment.EditedUser != null) { var font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular); var colour = colourProvider.Foreground1; From ae0d62838b76b9d451ab5e3f273a7eda74e48358 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 27 Sep 2022 22:46:23 +0300 Subject: [PATCH 1395/2686] Move API and DO to fields --- osu.Game/Overlays/Comments/DrawableComment.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 39f46210b0..03499ad375 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -56,13 +56,19 @@ namespace osu.Game.Overlays.Comments private ChevronButton chevronButton; private DeletedCommentsCounter deletedCommentsCounter; + [Resolved] + private DialogOverlay dialogOverlay { get; set; } + + [Resolved] + private IAPIProvider api { get; set; } + public DrawableComment(Comment comment) { Comment = comment; } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, IAPIProvider api, DialogOverlay dialogOverlay) + private void load(OverlayColourProvider colourProvider) { LinkFlowContainer username; FillFlowContainer info; From 8edb1cb98a45127c2c484001269f87ae2435b6f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Sep 2022 15:57:30 +0900 Subject: [PATCH 1396/2686] Add test coverage of current score staying on screen --- .../Visual/Gameplay/TestSceneGameplayLeaderboard.cs | 10 ++++++++++ osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 13 +++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 72656c29b1..171ae829a9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -58,6 +58,16 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for some scores not masked away", () => leaderboard.ChildrenOfType().Any(s => leaderboard.ScreenSpaceDrawQuad.Contains(s.ScreenSpaceDrawQuad.Centre))); + + AddUntilStep("wait for tracked score fully visible", () => leaderboard.ScreenSpaceDrawQuad.Intersects(leaderboard.TrackedScore!.ScreenSpaceDrawQuad)); + + AddStep("change score to middle", () => playerScore.Value = 1000000); + AddWaitStep("wait for movement", 5); + AddUntilStep("wait for tracked score fully visible", () => leaderboard.ScreenSpaceDrawQuad.Intersects(leaderboard.TrackedScore!.ScreenSpaceDrawQuad)); + + AddStep("change score to first", () => playerScore.Value = 5000000); + AddWaitStep("wait for movement", 5); + AddUntilStep("wait for tracked score fully visible", () => leaderboard.ScreenSpaceDrawQuad.Intersects(leaderboard.TrackedScore!.ScreenSpaceDrawQuad)); } [Test] diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 2d816fbd55..e550c00390 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play.HUD private bool requiresScroll; private readonly OsuScrollContainer scroll; - private GameplayLeaderboardScore? trackedScore; + public GameplayLeaderboardScore? TrackedScore { get; private set; } private const int max_panels = 8; @@ -78,10 +78,10 @@ namespace osu.Game.Screens.Play.HUD if (isTracked) { - if (trackedScore != null) + if (TrackedScore != null) throw new InvalidOperationException("Cannot track more than one score."); - trackedScore = drawable; + TrackedScore = drawable; } drawable.Expanded.BindTo(Expanded); @@ -108,7 +108,7 @@ namespace osu.Game.Screens.Play.HUD public void Clear() { Flow.Clear(); - trackedScore = null; + TrackedScore = null; scroll.ScrollToStart(false); } @@ -119,9 +119,10 @@ namespace osu.Game.Screens.Play.HUD { base.Update(); - if (requiresScroll && trackedScore != null) + if (requiresScroll && TrackedScore != null) { - float scrollTarget = scroll.GetChildPosInContent(trackedScore) + trackedScore.DrawHeight / 2 - scroll.DrawHeight / 2; + float scrollTarget = scroll.GetChildPosInContent(TrackedScore) + TrackedScore.DrawHeight / 2 - scroll.DrawHeight / 2; + scroll.ScrollTo(scrollTarget); } From c8643ed2655afe7d4f7018bc767cc9bd385af5a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Sep 2022 15:34:35 +0900 Subject: [PATCH 1397/2686] Set `ClampExtension` to zero to stop jittering --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index e550c00390..fde895a1ca 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -42,6 +42,7 @@ namespace osu.Game.Screens.Play.HUD { scroll = new InputDisabledScrollContainer { + ClampExtension = 0, RelativeSizeAxes = Axes.Both, Child = Flow = new FillFlowContainer { @@ -92,14 +93,6 @@ namespace osu.Game.Screens.Play.HUD int displayCount = Math.Min(Flow.Count, max_panels); Height = displayCount * (GameplayLeaderboardScore.PANEL_HEIGHT + Flow.Spacing.Y); - // Add extra margin space to flow equal to height of leaderboard. - // This ensures the content is always on screen, but also accounts for the fact that scroll operations - // without animation were actually forcing the local score to a location it can't usually reside at. - // - // Basically, the local score was in the scroll extension region (due to always trying to scroll the - // local player to the middle of the display, but there being no other content below the local player - // to scroll up by). - Flow.Margin = new MarginPadding { Bottom = Height }; requiresScroll = displayCount != Flow.Count; return drawable; From cdcc8494c9cc9e967e89b5fa06eef21bfaa97092 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Sep 2022 16:10:19 +0900 Subject: [PATCH 1398/2686] Fix fade being applied for too long when leaderboard scrolls to start --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 2d816fbd55..226cff9da1 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -130,7 +130,7 @@ namespace osu.Game.Screens.Play.HUD float fadeBottom = scroll.Current + scroll.DrawHeight; float fadeTop = scroll.Current + panel_height; - if (scroll.Current <= 0) fadeTop -= panel_height; + if (scroll.IsScrolledToStart()) fadeTop -= panel_height; if (!scroll.IsScrolledToEnd()) fadeBottom -= panel_height; // logic is mostly shared with Leaderboard, copied here for simplicity. From 4ee435507d3f078a5507faacd002162db922cebe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Sep 2022 17:58:47 +0900 Subject: [PATCH 1399/2686] 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 dd263d6aaa..c33937ad95 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c4e2a5168e..31b17fb8e1 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 622efcd63d..a9a83e2802 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -82,7 +82,7 @@ - + From 636befb499d4307f023d007bcbb9ef40e49a0f61 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 28 Sep 2022 17:49:37 +0300 Subject: [PATCH 1400/2686] Add visual feedback for deleting process --- osu.Game/Overlays/Comments/DrawableComment.cs | 53 +++++++++++++------ 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 03499ad375..f78778b96a 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -22,6 +22,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; using osu.Framework.Localisation; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; @@ -54,6 +55,8 @@ namespace osu.Game.Overlays.Comments private ShowMoreRepliesButton showMoreButton; private ShowRepliesButton showRepliesButton; private ChevronButton chevronButton; + private LinkFlowContainer actionsContainer; + private LoadingSpinner actionsLoading; private DeletedCommentsCounter deletedCommentsCounter; [Resolved] @@ -72,7 +75,6 @@ namespace osu.Game.Overlays.Comments { LinkFlowContainer username; FillFlowContainer info; - LinkFlowContainer actions; CommentMarkdownContainer message; GridContainer content; VotePill votePill; @@ -178,7 +180,7 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(10, 0), - Children = new[] + Children = new Drawable[] { info = new FillFlowContainer { @@ -193,10 +195,16 @@ namespace osu.Game.Overlays.Comments } } }, - actions = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) + actionsContainer = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) { AutoSizeAxes = Axes.Both, Spacing = new Vector2(10, 0) + }, + actionsLoading = new LoadingSpinner + { + Size = new Vector2(12f), + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft } } }, @@ -314,20 +322,7 @@ namespace osu.Game.Overlays.Comments if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) { - actions.AddLink("Delete", () => - { - dialogOverlay.Push(new ConfirmDialog("Do you really want to delete your comment?", () => - { - var request = new CommentDeleteRequest(Comment.Id); - request.Success += _ => - { - //TODO this is temporary just for testing - content.FadeColour(OsuColour.Gray(0.5f)); - votePill.Hide(); - }; - api.Queue(request); - })); - }); + actionsContainer.AddLink("Delete", deleteComment); } if (Comment.IsTopLevel) @@ -359,6 +354,30 @@ namespace osu.Game.Overlays.Comments }; } + private void deleteComment() + { + dialogOverlay.Push(new ConfirmDialog("Do you really want to delete your comment?", () => + { + actionsContainer.Hide(); + actionsLoading.Show(); + var request = new CommentDeleteRequest(Comment.Id); + request.Success += _ => + { + actionsLoading.Hide(); + AutoSizeAxes = Axes.None; + Masking = true; + this.ResizeHeightTo(0, 1000, Easing.Out); + this.FadeOut(1000, Easing.Out).Expire(); + }; + request.Failure += _ => + { + actionsLoading.Hide(); + actionsContainer.Show(); + }; + api.Queue(request); + })); + } + protected override void LoadComplete() { ShowDeleted.BindValueChanged(show => From 965e7bf265b9e73a20c58f19e9ba7259fbe7b3da Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 28 Sep 2022 17:52:12 +0300 Subject: [PATCH 1401/2686] Check local deletion in test --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 88e4d6e83b..e1ac440168 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -129,6 +129,10 @@ namespace osu.Game.Tests.Visual.Online }); AddStep("Confirm dialog", () => InputManager.Key(Key.Number1)); AddUntilStep("Deletion requested", () => delete); + AddUntilStep("Comment is deleted locally", () => + { + return this.ChildrenOfType().SingleOrDefault(x => x.Comment.Id == 1) == null; + }); } private void addTestComments() From 85adfc2df7d931164181e145377a6ced8db2bfb3 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 28 Sep 2022 18:26:36 +0300 Subject: [PATCH 1402/2686] Fix DI type --- .../Visual/Online/TestSceneCommentActions.cs | 71 ++++++++++--------- .../Online/TestSceneCommentsContainer.cs | 2 +- .../Visual/Online/TestSceneDrawableComment.cs | 2 +- .../TestSceneOfflineCommentsContainer.cs | 2 +- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 5 files changed, 41 insertions(+), 38 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index e1ac440168..a58873e457 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Online { private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; - [Cached] + [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay = new DialogOverlay(); [Cached] @@ -137,49 +137,52 @@ namespace osu.Game.Tests.Visual.Online private void addTestComments() { - CommentBundle cb = new CommentBundle + AddStep("set up response", () => { - Comments = new List + CommentBundle cb = new CommentBundle { - new Comment + Comments = new List { - Id = 1, - Message = "This is our comment", - UserId = API.LocalUser.Value.Id, - CreatedAt = DateTimeOffset.Now, - User = API.LocalUser.Value, - }, - new Comment - { - Id = 2, - Message = "This is a comment by another user", - UserId = API.LocalUser.Value.Id + 1, - CreatedAt = DateTimeOffset.Now, - User = new APIUser + new Comment { - Id = API.LocalUser.Value.Id + 1, - Username = "Another user" - } + Id = 1, + Message = "This is our comment", + UserId = API.LocalUser.Value.Id, + CreatedAt = DateTimeOffset.Now, + User = API.LocalUser.Value, + }, + new Comment + { + Id = 2, + Message = "This is a comment by another user", + UserId = API.LocalUser.Value.Id + 1, + CreatedAt = DateTimeOffset.Now, + User = new APIUser + { + Id = API.LocalUser.Value.Id + 1, + Username = "Another user" + } + }, }, - }, - IncludedComments = new List(), - PinnedComments = new List(), - }; - setUpCommentsResponse(cb); + IncludedComments = new List(), + PinnedComments = new List(), + }; + setUpCommentsResponse(cb); + }); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); } private void setUpCommentsResponse(CommentBundle commentBundle) - => AddStep("set up response", () => + { + dummyAPI.HandleRequest = request => { - dummyAPI.HandleRequest = request => - { - if (!(request is GetCommentsRequest getCommentsRequest)) - return false; + if (!(request is GetCommentsRequest getCommentsRequest)) + return false; - getCommentsRequest.TriggerSuccess(commentBundle); - return true; - }; - }); + getCommentsRequest.TriggerSuccess(commentBundle); + return true; + }; + } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 08881e9718..d1624b8220 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - [Cached] + [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay = new DialogOverlay(); private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs index 7253424984..ccbf996c15 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - [Cached] + [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay = new DialogOverlay(); private Container container; diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs index 46bbbd635a..07d491e8e3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); - [Cached] + [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay = new DialogOverlay(); private TestCommentsContainer comments; diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index f78778b96a..15594b2255 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -60,7 +60,7 @@ namespace osu.Game.Overlays.Comments private DeletedCommentsCounter deletedCommentsCounter; [Resolved] - private DialogOverlay dialogOverlay { get; set; } + private IDialogOverlay dialogOverlay { get; set; } [Resolved] private IAPIProvider api { get; set; } From d84c956af9c648966da6a0063c39f63e34805651 Mon Sep 17 00:00:00 2001 From: vun Date: Thu, 29 Sep 2022 15:27:26 +0800 Subject: [PATCH 1403/2686] Refactor to move first-object detection to evaluation --- .../Difficulty/Evaluators/ColourEvaluator.cs | 12 +++++----- .../Colour/Data/AlternatingMonoPattern.cs | 6 +++++ .../Colour/Data/RepeatingHitPatterns.cs | 8 ++++++- .../TaikoColourDifficultyPreprocessor.cs | 23 +++++++++++++------ .../Colour/TaikoDifficultyHitObjectColour.cs | 6 ++--- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 7d88be2f70..36f8babc6b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -54,12 +54,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators TaikoDifficultyHitObjectColour colour = ((TaikoDifficultyHitObject)hitObject).Colour; double difficulty = 0.0d; - if (colour.MonoStreak != null) // Difficulty for MonoStreak - difficulty += EvaluateDifficultyOf(colour.MonoStreak); - if (colour.AlternatingMonoPattern != null) // Difficulty for AlternatingMonoPattern - difficulty += EvaluateDifficultyOf(colour.AlternatingMonoPattern); - if (colour.RepeatingHitPattern != null) // Difficulty for RepeatingHitPattern - difficulty += EvaluateDifficultyOf(colour.RepeatingHitPattern); + if (colour.MonoStreak?.FirstHitObject == hitObject) // Difficulty for MonoStreak + difficulty += EvaluateDifficultyOf(colour.MonoStreak!); + if (colour.AlternatingMonoPattern?.FirstHitObject == hitObject) // Difficulty for AlternatingMonoPattern + difficulty += EvaluateDifficultyOf(colour.AlternatingMonoPattern!); + if (colour.RepeatingHitPattern?.FirstHitObject == hitObject) // Difficulty for RepeatingHitPattern + difficulty += EvaluateDifficultyOf(colour.RepeatingHitPattern!); return difficulty; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs index 7910a8262b..bc6e02319d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { @@ -31,6 +32,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public TaikoDifficultyHitObject FirstHitObject => MonoStreaks[0].FirstHitObject; + /// + /// All s in this . + /// + public IEnumerable AllHitObjects => MonoStreaks.SelectMany(streak => streak.HitObjects); + /// /// Determine if this is a repetition of another . This /// is a strict comparison and is true if and only if the colour sequence is exactly the same. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs index fe0dc6dd9a..9e3d9a21b2 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using System.Collections.Generic; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data @@ -23,10 +24,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data public readonly List AlternatingMonoPatterns = new List(); /// - /// The parent in this + /// The first in this /// public TaikoDifficultyHitObject FirstHitObject => AlternatingMonoPatterns[0].FirstHitObject; + /// + /// All s in this . + /// + public IEnumerable AllHitObjects => AlternatingMonoPatterns.SelectMany(pattern => pattern.AllHitObjects); + /// /// The previous . This is used to determine the repetition interval. /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index d19e05f4e0..500078a879 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -15,18 +15,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour { /// /// Processes and encodes a list of s into a list of s, - /// assigning the appropriate s to each , - /// and pre-evaluating colour difficulty of each . + /// assigning the appropriate s to each . /// public static void ProcessAndAssign(List hitObjects) { List hitPatterns = encode(hitObjects); - // Assign indexing and encoding data to all relevant objects. Only the first note of each encoding type is - // assigned with the relevant encodings. + // Assign indexing and encoding data to all relevant objects. foreach (var repeatingHitPattern in hitPatterns) { - repeatingHitPattern.FirstHitObject.Colour.RepeatingHitPattern = repeatingHitPattern; + foreach (var hitObject in repeatingHitPattern.AllHitObjects) + { + hitObject.Colour.RepeatingHitPattern = repeatingHitPattern; + } // The outermost loop is kept a ForEach loop since it doesn't need index information, and we want to // keep i and j for AlternatingMonoPattern's and MonoStreak's index respectively, to keep it in line with @@ -36,14 +37,22 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour AlternatingMonoPattern monoPattern = repeatingHitPattern.AlternatingMonoPatterns[i]; monoPattern.Parent = repeatingHitPattern; monoPattern.Index = i; - monoPattern.FirstHitObject.Colour.AlternatingMonoPattern = monoPattern; + + foreach (var hitObject in monoPattern.AllHitObjects) + { + hitObject.Colour.AlternatingMonoPattern = monoPattern; + } for (int j = 0; j < monoPattern.MonoStreaks.Count; ++j) { MonoStreak monoStreak = monoPattern.MonoStreaks[j]; monoStreak.Parent = monoPattern; monoStreak.Index = j; - monoStreak.FirstHitObject.Colour.MonoStreak = monoStreak; + + foreach (var hitObject in monoStreak.HitObjects) + { + hitObject.Colour.MonoStreak = monoStreak; + } } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs index 9c147eee9c..84b6871ba7 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs @@ -11,17 +11,17 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour public class TaikoDifficultyHitObjectColour { /// - /// The that encodes this note, only present if this is the first note within a + /// The that encodes this note. /// public MonoStreak? MonoStreak; /// - /// The that encodes this note, only present if this is the first note within a + /// The that encodes this note. /// public AlternatingMonoPattern? AlternatingMonoPattern; /// - /// The that encodes this note, only present if this is the first note within a + /// The that encodes this note. /// public RepeatingHitPatterns? RepeatingHitPattern; } From 09a38fec94b55ed5edd25f36496a4e5de375bf95 Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 30 Sep 2022 09:10:56 +0800 Subject: [PATCH 1404/2686] Implement mono tl nerf for stamina, disable convert specific nerfs --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 25 ++++++++++++++++++- .../Preprocessing/Colour/Data/MonoStreak.cs | 5 ++++ .../Difficulty/TaikoDifficultyCalculator.cs | 9 ------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 49b3ae2e19..9c5251df9b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -24,6 +24,29 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return 30 / interval; } + /// + /// Determines the number of fingers available to hit the current . + /// Any mono notes that is more than 0.5s apart from note of the other colour will be considered to have more + /// than 2 fingers available, since players can move their hand over to hit the same key with multiple fingers. + /// + private static int availableFingersFor(TaikoDifficultyHitObject hitObject) + { + DifficultyHitObject? previousColourChange = hitObject.Colour.MonoStreak?.FirstHitObject.Previous(0); + DifficultyHitObject? nextColourChange = hitObject.Colour.MonoStreak?.LastHitObject.Next(0); + + if (previousColourChange != null && hitObject.StartTime - previousColourChange.StartTime < 300) + { + return 2; + } + + if (nextColourChange != null && nextColourChange.StartTime - hitObject.StartTime < 300) + { + return 2; + } + + return 5; + } + /// /// Evaluates the minimum mechanical stamina required to play the current object. This is calculated using the /// maximum possible interval between two hits using the same key, by alternating 2 keys for each colour. @@ -37,7 +60,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators // Find the previous hit object hit by the current key, which is two notes of the same colour prior. TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; - TaikoDifficultyHitObject? keyPrevious = taikoCurrent.PreviousMono(1); + TaikoDifficultyHitObject? keyPrevious = taikoCurrent.PreviousMono(availableFingersFor(taikoCurrent) - 1); if (keyPrevious == null) { diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs index 174988bed7..c01a0f6686 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/MonoStreak.cs @@ -33,6 +33,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public TaikoDifficultyHitObject FirstHitObject => HitObjects[0]; + /// + /// The last in this . + /// + public TaikoDifficultyHitObject LastHitObject => HitObjects[^1]; + /// /// The hit type of all objects encoded within this /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 2b0b563323..24b5f5939a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -83,15 +83,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double combinedRating = combined.DifficultyValue() * difficulty_multiplier; double starRating = rescale(combinedRating * 1.4); - // TODO: This is temporary measure as we don't detect abuse of multiple-input playstyles of converts within the current system. - if (beatmap.BeatmapInfo.Ruleset.OnlineID == 0) - { - starRating *= 0.925; - // For maps with low colour variance and high stamina requirement, multiple inputs are more likely to be abused. - if (colourRating < 2 && staminaRating > 8) - starRating *= 0.80; - } - HitWindows hitWindows = new TaikoHitWindows(); hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); From 02092ede649fbcb5126c0d48197a1778414c3768 Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 30 Sep 2022 11:42:48 +0800 Subject: [PATCH 1405/2686] Refactor previous and next colour change into TaikoDifficultyHitObjectColour --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 4 ++-- .../Colour/TaikoDifficultyHitObjectColour.cs | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 9c5251df9b..6a07d49f98 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -31,8 +31,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// private static int availableFingersFor(TaikoDifficultyHitObject hitObject) { - DifficultyHitObject? previousColourChange = hitObject.Colour.MonoStreak?.FirstHitObject.Previous(0); - DifficultyHitObject? nextColourChange = hitObject.Colour.MonoStreak?.LastHitObject.Next(0); + DifficultyHitObject? previousColourChange = hitObject.Colour.PreviousColourChange; + DifficultyHitObject? nextColourChange = hitObject.Colour.NextColourChange; if (previousColourChange != null && hitObject.StartTime - previousColourChange.StartTime < 300) { diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs index 84b6871ba7..abf6fb3672 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoDifficultyHitObjectColour.cs @@ -24,5 +24,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour /// The that encodes this note. /// public RepeatingHitPatterns? RepeatingHitPattern; + + /// + /// The closest past that's not the same colour. + /// + public TaikoDifficultyHitObject? PreviousColourChange => MonoStreak?.FirstHitObject.PreviousNote(0); + + /// + /// The closest future that's not the same colour. + /// + public TaikoDifficultyHitObject? NextColourChange => MonoStreak?.LastHitObject.NextNote(0); } } From e6093f94df42cacce79dcd42208989ecbb76bf33 Mon Sep 17 00:00:00 2001 From: vun Date: Fri, 30 Sep 2022 20:56:16 +0800 Subject: [PATCH 1406/2686] Apply nerfs to HD/FL bonuses with converts --- .../Difficulty/TaikoPerformanceCalculator.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 95a1e8bc66..6becfd349d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -41,6 +41,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (totalSuccessfulHits > 0) effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; + // We are disabling some HD and/or FL Bonus for converts for now due to them having low pattern difficulty, and thus being easy to memorize. + bool readingBonusEnabled = score.BeatmapInfo.Ruleset.OnlineID == 1; + double multiplier = 1.13; if (score.Mods.Any(m => m is ModHidden)) @@ -49,8 +52,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModEasy)) multiplier *= 0.975; - double difficultyValue = computeDifficultyValue(score, taikoAttributes); - double accuracyValue = computeAccuracyValue(score, taikoAttributes); + double difficultyValue = computeDifficultyValue(score, taikoAttributes, readingBonusEnabled); + double accuracyValue = computeAccuracyValue(score, taikoAttributes, readingBonusEnabled); double totalValue = Math.Pow( Math.Pow(difficultyValue, 1.1) + @@ -66,7 +69,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty }; } - private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes) + private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool readingBonusEnabled) { double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.115) - 4.0, 2.25) / 1150.0; @@ -78,19 +81,19 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModEasy)) difficultyValue *= 0.985; - if (score.Mods.Any(m => m is ModHidden)) + if (score.Mods.Any(m => m is ModHidden) && readingBonusEnabled) difficultyValue *= 1.025; if (score.Mods.Any(m => m is ModHardRock)) difficultyValue *= 1.050; - if (score.Mods.Any(m => m is ModFlashlight)) + if (score.Mods.Any(m => m is ModFlashlight) && readingBonusEnabled) difficultyValue *= 1.050 * lengthBonus; return difficultyValue * Math.Pow(score.Accuracy, 2.0); } - private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes) + private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool readingBonusEnabled) { if (attributes.GreatHitWindow <= 0) return 0; @@ -100,8 +103,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); accuracyValue *= lengthBonus; - // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values - if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden)) + // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values. + if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden) && readingBonusEnabled) accuracyValue *= Math.Max(1.050, 1.075 * lengthBonus); return accuracyValue; From a276e400333517524a2c4c6ea14dce891c24480d Mon Sep 17 00:00:00 2001 From: Jay L Date: Sun, 2 Oct 2022 09:05:58 +1000 Subject: [PATCH 1407/2686] reintroduce fl bonus to converts --- .../Difficulty/TaikoPerformanceCalculator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 6becfd349d..fe3dd1fad1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModHardRock)) difficultyValue *= 1.050; - if (score.Mods.Any(m => m is ModFlashlight) && readingBonusEnabled) + if (score.Mods.Any(m => m is ModFlashlight)) difficultyValue *= 1.050 * lengthBonus; return difficultyValue * Math.Pow(score.Accuracy, 2.0); @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); accuracyValue *= lengthBonus; - // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values. + // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values. if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden) && readingBonusEnabled) accuracyValue *= Math.Max(1.050, 1.075 * lengthBonus); From 4b562f782f35327e5e13f928aebe79c0836535eb Mon Sep 17 00:00:00 2001 From: Jay L Date: Sun, 2 Oct 2022 15:28:39 +1000 Subject: [PATCH 1408/2686] decrease finger count --- .idea/.idea.osu/.idea/discord.xml | 7 +++++++ .../Difficulty/Evaluators/StaminaEvaluator.cs | 2 +- .../Difficulty/TaikoPerformanceCalculator.cs | 16 ++++++++-------- 3 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 .idea/.idea.osu/.idea/discord.xml diff --git a/.idea/.idea.osu/.idea/discord.xml b/.idea/.idea.osu/.idea/discord.xml new file mode 100644 index 0000000000..30bab2abb1 --- /dev/null +++ b/.idea/.idea.osu/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 6a07d49f98..3585393bbb 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return 2; } - return 5; + return 4; } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index fe3dd1fad1..63c18e5709 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; // We are disabling some HD and/or FL Bonus for converts for now due to them having low pattern difficulty, and thus being easy to memorize. - bool readingBonusEnabled = score.BeatmapInfo.Ruleset.OnlineID == 1; + bool rulesetTaiko = score.BeatmapInfo.Ruleset.OnlineID == 1; double multiplier = 1.13; @@ -52,8 +52,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModEasy)) multiplier *= 0.975; - double difficultyValue = computeDifficultyValue(score, taikoAttributes, readingBonusEnabled); - double accuracyValue = computeAccuracyValue(score, taikoAttributes, readingBonusEnabled); + double difficultyValue = computeDifficultyValue(score, taikoAttributes, rulesetTaiko); + double accuracyValue = computeAccuracyValue(score, taikoAttributes, rulesetTaiko); double totalValue = Math.Pow( Math.Pow(difficultyValue, 1.1) + @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty }; } - private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool readingBonusEnabled) + private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool rulesetTaiko) { double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.115) - 4.0, 2.25) / 1150.0; @@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModEasy)) difficultyValue *= 0.985; - if (score.Mods.Any(m => m is ModHidden) && readingBonusEnabled) + if (score.Mods.Any(m => m is ModHidden) && rulesetTaiko) difficultyValue *= 1.025; if (score.Mods.Any(m => m is ModHardRock)) @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty return difficultyValue * Math.Pow(score.Accuracy, 2.0); } - private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool readingBonusEnabled) + private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool rulesetTaiko) { if (attributes.GreatHitWindow <= 0) return 0; @@ -104,8 +104,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty accuracyValue *= lengthBonus; // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values. - if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden) && readingBonusEnabled) - accuracyValue *= Math.Max(1.050, 1.075 * lengthBonus); + if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden) && rulesetTaiko) + accuracyValue *= Math.Max(1.0, 1.1 * lengthBonus); return accuracyValue; } From 6752655b5a181b05065d22a0e13da3714a5ba588 Mon Sep 17 00:00:00 2001 From: Jay L Date: Sun, 2 Oct 2022 16:08:14 +1000 Subject: [PATCH 1409/2686] xml, remove speedbonus cap --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 6 ++---- .../Difficulty/TaikoPerformanceCalculator.cs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 3585393bbb..3326d72588 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -16,10 +16,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// The interval between the current and previous note hit using the same key. private static double speedBonus(double interval) { - // Cap to 600bpm 1/4, 25ms note interval, 50ms key interval - // Interval will be capped at a very small value to avoid infinite/negative speed bonuses. - // TODO - This is a temporary measure as we need to implement methods of detecting playstyle-abuse of SpeedBonus. - interval = Math.Max(interval, 50); + // Interval is capped at a very small value to prevent infinite values. + interval = Math.Max(interval, 1); return 30 / interval; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 63c18e5709..b9a9dacddc 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (totalSuccessfulHits > 0) effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; - // We are disabling some HD and/or FL Bonus for converts for now due to them having low pattern difficulty, and thus being easy to memorize. + // TODO: The detection of rulesets is temporary until the leftover old skills have been reworked. bool rulesetTaiko = score.BeatmapInfo.Ruleset.OnlineID == 1; double multiplier = 1.13; From 2493468800a3bd2371d70fd8ad1aa03ec8903ebb Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Sun, 2 Oct 2022 18:40:31 +0800 Subject: [PATCH 1410/2686] display highest combo instead of current combo --- osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 53981b9edc..ab3cf2950c 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Play.HUD local.TotalScore.BindTarget = scoreProcessor.TotalScore; local.Accuracy.BindTarget = scoreProcessor.Accuracy; - local.Combo.BindTarget = scoreProcessor.Combo; + local.Combo.BindTarget = scoreProcessor.HighestCombo; // Local score should always show lower than any existing scores in cases of ties. local.DisplayOrder.Value = long.MaxValue; From b6701dd57892f4f585adb1494388768538fb69cc Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 2 Oct 2022 15:29:53 +0300 Subject: [PATCH 1411/2686] Add failing test case --- .../Gameplay/TestSceneStoryboardWithOutro.cs | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs index e2c825df0b..a26a7e97be 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs @@ -32,6 +32,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected new OutroPlayer Player => (OutroPlayer)base.Player; + private double currentBeatmapDuration; private double currentStoryboardDuration; private bool showResults = true; @@ -45,7 +46,8 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("enable storyboard", () => LocalConfig.SetValue(OsuSetting.ShowStoryboard, true)); AddStep("set dim level to 0", () => LocalConfig.SetValue(OsuSetting.DimLevel, 0)); AddStep("reset fail conditions", () => currentFailConditions = (_, _) => false); - AddStep("set storyboard duration to 2s", () => currentStoryboardDuration = 2000); + AddStep("set beatmap duration to 0s", () => currentBeatmapDuration = 0); + AddStep("set storyboard duration to 8s", () => currentStoryboardDuration = 8000); AddStep("set ShowResults = true", () => showResults = true); } @@ -151,6 +153,24 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("player exited", () => Stack.CurrentScreen == null); } + [Test] + public void TestPerformExitAfterOutro() + { + CreateTest(() => + { + AddStep("set beatmap duration to 4s", () => currentBeatmapDuration = 4000); + AddStep("set storyboard duration to 1s", () => currentStoryboardDuration = 1000); + }); + + AddUntilStep("storyboard ends", () => Player.GameplayClockContainer.CurrentTime >= currentStoryboardDuration); + AddStep("exit via pause", () => Player.ExitViaPause()); + AddAssert("player paused", () => !Player.IsResuming); + + AddStep("resume player", () => Player.Resume()); + AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value); + AddUntilStep("wait for score shown", () => Player.IsScoreShown); + } + protected override bool AllowFail => true; protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); @@ -160,7 +180,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { var beatmap = new Beatmap(); - beatmap.HitObjects.Add(new HitCircle()); + beatmap.HitObjects.Add(new HitCircle { StartTime = currentBeatmapDuration }); return beatmap; } @@ -189,7 +209,7 @@ namespace osu.Game.Tests.Visual.Gameplay private event Func failConditions; public OutroPlayer(Func failConditions, bool showResults = true) - : base(false, showResults) + : base(showResults: showResults) { this.failConditions = failConditions; } From 59728b0ccb78fc7394cc15016cfe1c55fa45884b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 2 Oct 2022 15:30:06 +0300 Subject: [PATCH 1412/2686] Fix results display delegate potentially cancelled while not exiting --- osu.Game/Screens/Play/Player.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index e31e18046e..9bc784411a 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -566,9 +566,6 @@ namespace osu.Game.Screens.Play /// protected void PerformExit(bool showDialogFirst) { - // if an exit has been requested, cancel any pending completion (the user has shown intention to exit). - resultsDisplayDelegate?.Cancel(); - // there is a chance that an exit request occurs after the transition to results has already started. // even in such a case, the user has shown intent, so forcefully return to this screen (to proceed with the upwards exit process). if (!this.IsCurrentScreen()) @@ -603,6 +600,9 @@ namespace osu.Game.Screens.Play } } + // if an exit has been requested, cancel any pending completion (the user has shown intention to exit). + resultsDisplayDelegate?.Cancel(); + // The actual exit is performed if // - the pause / fail dialog was not requested // - the pause / fail dialog was requested but is already displayed (user showing intention to exit). From a810afafb39752affe1e8f59deef4afc36ed095e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 2 Oct 2022 15:37:56 +0300 Subject: [PATCH 1413/2686] Reschedule results display delegate to avoid potential softlocks in the future --- osu.Game/Screens/Play/Player.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 9bc784411a..7721d5b912 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -780,19 +780,11 @@ namespace osu.Game.Screens.Play /// /// /// A final display will only occur once all work is completed in . This means that even after calling this method, the results screen will never be shown until ScoreProcessor.HasCompleted becomes . - /// - /// Calling this method multiple times will have no effect. /// /// Whether a minimum delay () should be added before the screen is displayed. private void progressToResults(bool withDelay) { - if (resultsDisplayDelegate != null) - // Note that if progressToResults is called one withDelay=true and then withDelay=false, this no-delay timing will not be - // accounted for. shouldn't be a huge concern (a user pressing the skip button after a results progression has already been queued - // may take x00 more milliseconds than expected in the very rare edge case). - // - // If required we can handle this more correctly by rescheduling here. - return; + resultsDisplayDelegate?.Cancel(); double delay = withDelay ? RESULTS_DISPLAY_DELAY : 0; From c933b62df63ccd4b6fdf78e49622748902e2723c Mon Sep 17 00:00:00 2001 From: vun Date: Mon, 3 Oct 2022 14:16:53 +0800 Subject: [PATCH 1414/2686] Correct xmldoc --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 3326d72588..55dce4e9b3 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -24,8 +24,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// /// Determines the number of fingers available to hit the current . - /// Any mono notes that is more than 0.5s apart from note of the other colour will be considered to have more - /// than 2 fingers available, since players can move their hand over to hit the same key with multiple fingers. + /// Any mono notes that is more than 300ms apart from a colour change will be considered to have more than 2 + /// fingers available, since players can hit the same key with multiple fingers. /// private static int availableFingersFor(TaikoDifficultyHitObject hitObject) { From 25976e1f105ab36e185fa9ee8d274e20c2a733d7 Mon Sep 17 00:00:00 2001 From: vun Date: Mon, 3 Oct 2022 14:20:01 +0800 Subject: [PATCH 1415/2686] Correct xmldocs --- .../Difficulty/Evaluators/StaminaEvaluator.cs | 11 ++++++----- osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs | 3 --- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 55dce4e9b3..59b61f47d1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -11,9 +11,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators public class StaminaEvaluator { /// - /// Applies a speed bonus dependent on the time since the last hit performed using this key. + /// Applies a speed bonus dependent on the time since the last hit performed using this finger. /// - /// The interval between the current and previous note hit using the same key. + /// The interval between the current and previous note hit using the same finger. private static double speedBonus(double interval) { // Interval is capped at a very small value to prevent infinite values. @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// /// Evaluates the minimum mechanical stamina required to play the current object. This is calculated using the - /// maximum possible interval between two hits using the same key, by alternating 2 keys for each colour. + /// maximum possible interval between two hits using the same key, by alternating available fingers for each colour. /// public static double EvaluateDifficultyOf(DifficultyHitObject current) { @@ -56,13 +56,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators return 0.0; } - // Find the previous hit object hit by the current key, which is two notes of the same colour prior. + // Find the previous hit object hit by the current finger, which is n notes prior, n being the number of + // available fingers. TaikoDifficultyHitObject taikoCurrent = (TaikoDifficultyHitObject)current; TaikoDifficultyHitObject? keyPrevious = taikoCurrent.PreviousMono(availableFingersFor(taikoCurrent) - 1); if (keyPrevious == null) { - // There is no previous hit object hit by the current key + // There is no previous hit object hit by the current finger return 0.0; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 344004bcf6..d04c028fec 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -13,9 +13,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// /// Calculates the stamina coefficient of taiko difficulty. /// - /// - /// The reference play style chosen uses two hands, with full alternating (the hand changes after every hit). - /// public class Stamina : StrainDecaySkill { protected override double SkillMultiplier => 1.1; From 7e578f868c6eed983485c29f99874d786714720c Mon Sep 17 00:00:00 2001 From: Jay L Date: Mon, 3 Oct 2022 16:55:11 +1000 Subject: [PATCH 1416/2686] remove idea plugin xml --- .idea/.idea.osu/.idea/discord.xml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .idea/.idea.osu/.idea/discord.xml diff --git a/.idea/.idea.osu/.idea/discord.xml b/.idea/.idea.osu/.idea/discord.xml deleted file mode 100644 index 30bab2abb1..0000000000 --- a/.idea/.idea.osu/.idea/discord.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file From 492f26c8328a4562b249911cd2810be2d3f99f28 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Oct 2022 16:56:32 +0900 Subject: [PATCH 1417/2686] Update test step in line with new combo source --- .../Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index 6b52e934b7..c852685b74 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddSliderStep("score", 0, 1000000, 500000, v => scoreProcessor.TotalScore.Value = v); AddSliderStep("accuracy", 0f, 1f, 0.5f, v => scoreProcessor.Accuracy.Value = v); - AddSliderStep("combo", 0, 1000, 0, v => scoreProcessor.Combo.Value = v); + AddSliderStep("combo", 0, 1000, 0, v => scoreProcessor.HighestCombo.Value = v); } [Test] From c4dd23ed15c2818f9aab44361e0f1981e57ad901 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Oct 2022 17:22:30 +0900 Subject: [PATCH 1418/2686] Log token retrieval failures even when gameplay is allowed to continue --- osu.Game/Screens/Play/SubmittingPlayer.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index be77304076..85d1ecea6b 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -76,6 +76,7 @@ namespace osu.Game.Screens.Play req.Success += r => { + Logger.Log($"Score submission token retrieved ({r.ID})"); token = r.ID; tcs.SetResult(true); }; @@ -104,6 +105,12 @@ namespace osu.Game.Screens.Play this.Exit(); }); } + else + { + // Gameplay is allowed to continue, but we still should keep track of the error. + // In the future, this should be visible to the user in some way. + Logger.Log($"Score submission token retrieval failed ({exception.Message})"); + } tcs.SetResult(false); } From 65369e96ebf1ee90e5a74dba974a79824b8e54f3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Oct 2022 17:29:46 +0900 Subject: [PATCH 1419/2686] Ensure token retrieval failure logic only runs once --- osu.Game/Screens/Play/SubmittingPlayer.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index 85d1ecea6b..d56b9c23c8 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -92,6 +92,11 @@ namespace osu.Game.Screens.Play void handleTokenFailure(Exception exception) { + // This method may be invoked multiple times due to the Task.Wait call above. + // We only really care about the first error. + if (!tcs.TrySetResult(false)) + return; + if (HandleTokenRetrievalFailure(exception)) { if (string.IsNullOrEmpty(exception.Message)) @@ -111,8 +116,6 @@ namespace osu.Game.Screens.Play // In the future, this should be visible to the user in some way. Logger.Log($"Score submission token retrieval failed ({exception.Message})"); } - - tcs.SetResult(false); } } From 42aac16b377b7b8ab52fba8107a84a5d13fa87c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Oct 2022 18:12:36 +0900 Subject: [PATCH 1420/2686] Adjust leaderboard score panels sizing based on accuracy/combo width --- .../TestSceneSoloGameplayLeaderboard.cs | 3 +- .../Play/HUD/GameplayLeaderboardScore.cs | 44 +++++++++++++++---- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index c852685b74..60ed0012ae 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -66,7 +66,8 @@ namespace osu.Game.Tests.Visual.Gameplay { AddSliderStep("score", 0, 1000000, 500000, v => scoreProcessor.TotalScore.Value = v); AddSliderStep("accuracy", 0f, 1f, 0.5f, v => scoreProcessor.Accuracy.Value = v); - AddSliderStep("combo", 0, 1000, 0, v => scoreProcessor.HighestCombo.Value = v); + AddSliderStep("combo", 0, 10000, 0, v => scoreProcessor.HighestCombo.Value = v); + AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value); } [Test] diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 29354e610d..548dd2a5bb 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -39,8 +40,6 @@ namespace osu.Game.Screens.Play.HUD private const float rank_text_width = 35f; - private const float score_components_width = 85f; - private const float avatar_size = 25f; private const double panel_transition_duration = 500; @@ -161,7 +160,7 @@ namespace osu.Game.Screens.Play.HUD { new Dimension(GridSizeMode.Absolute, rank_text_width), new Dimension(), - new Dimension(GridSizeMode.AutoSize, maxSize: score_components_width), + new Dimension(GridSizeMode.AutoSize), }, Content = new[] { @@ -286,8 +285,19 @@ namespace osu.Game.Screens.Play.HUD LoadComponentAsync(new DrawableAvatar(User), avatarContainer.Add); TotalScore.BindValueChanged(v => scoreText.Text = v.NewValue.ToString("N0"), true); - Accuracy.BindValueChanged(v => accuracyText.Text = v.NewValue.FormatAccuracy(), true); - Combo.BindValueChanged(v => comboText.Text = $"{v.NewValue}x", true); + + Accuracy.BindValueChanged(v => + { + accuracyText.Text = v.NewValue.FormatAccuracy(); + updateDetailsWidth(); + }, true); + + Combo.BindValueChanged(v => + { + comboText.Text = $"{v.NewValue}x"; + updateDetailsWidth(); + }, true); + HasQuit.BindValueChanged(_ => updateState()); } @@ -303,13 +313,10 @@ namespace osu.Game.Screens.Play.HUD private void changeExpandedState(ValueChangedEvent expanded) { - scoreComponents.ClearTransforms(); - if (expanded.NewValue) { gridContainer.ResizeWidthTo(regular_width, panel_transition_duration, Easing.OutQuint); - scoreComponents.ResizeWidthTo(score_components_width, panel_transition_duration, Easing.OutQuint); scoreComponents.FadeIn(panel_transition_duration, Easing.OutQuint); usernameText.FadeIn(panel_transition_duration, Easing.OutQuint); @@ -318,13 +325,32 @@ namespace osu.Game.Screens.Play.HUD { gridContainer.ResizeWidthTo(compact_width, panel_transition_duration, Easing.OutQuint); - scoreComponents.ResizeWidthTo(0, panel_transition_duration, Easing.OutQuint); scoreComponents.FadeOut(text_transition_duration, Easing.OutQuint); usernameText.FadeOut(text_transition_duration, Easing.OutQuint); } + + updateDetailsWidth(); } + private float? scoreComponentsTargetWidth; + + // Schedule required to get correct DrawWidth from text after updates. + private void updateDetailsWidth() => SchedulerAfterChildren.AddOnce(() => + { + const float score_components_min_width = 88f; + + float newWidth = Expanded.Value + ? Math.Max(score_components_min_width, comboText.DrawWidth + accuracyText.DrawWidth + 25) + : 0; + + if (scoreComponentsTargetWidth == newWidth) + return; + + scoreComponentsTargetWidth = newWidth; + scoreComponents.ResizeWidthTo(newWidth, panel_transition_duration, Easing.OutQuint); + }); + private void updateState() { bool widthExtension = false; From d9f678d94220e8a3adefc9e058a521263d0fca9e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Oct 2022 18:16:54 +0900 Subject: [PATCH 1421/2686] Change song select random key binding to not handle key repeat --- osu.Game/Screens/Select/FooterButtonRandom.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs index 1f56915f62..aad7fdff39 100644 --- a/osu.Game/Screens/Select/FooterButtonRandom.cs +++ b/osu.Game/Screens/Select/FooterButtonRandom.cs @@ -138,7 +138,8 @@ namespace osu.Game.Screens.Select return false; } - TriggerClick(); + if (!e.Repeat) + TriggerClick(); return true; } From 0df217d85caf46e9dfaf1d9d9126b541a8a95034 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 3 Oct 2022 18:24:56 +0900 Subject: [PATCH 1422/2686] Add ability to adjust flashlight smoothness --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 6d7706cde2..7ed73b3163 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -201,6 +201,20 @@ namespace osu.Game.Rulesets.Mods } } + private float flashlightSmoothness = 1.1f; + + public float FlashlightSmoothness + { + get => flashlightSmoothness; + set + { + if (flashlightSmoothness == value) return; + + flashlightSmoothness = value; + Invalidate(Invalidation.DrawNode); + } + } + private class FlashlightDrawNode : DrawNode { protected new Flashlight Source => (Flashlight)base.Source; @@ -210,6 +224,7 @@ namespace osu.Game.Rulesets.Mods private Vector2 flashlightPosition; private Vector2 flashlightSize; private float flashlightDim; + private float flashlightSmoothness; private IVertexBatch? quadBatch; private Action? addAction; @@ -228,6 +243,7 @@ namespace osu.Game.Rulesets.Mods flashlightPosition = Vector2Extensions.Transform(Source.FlashlightPosition, DrawInfo.Matrix); flashlightSize = Source.FlashlightSize * DrawInfo.Matrix.ExtractScale().Xy; flashlightDim = Source.FlashlightDim; + flashlightSmoothness = Source.flashlightSmoothness; } public override void Draw(IRenderer renderer) @@ -249,6 +265,7 @@ namespace osu.Game.Rulesets.Mods shader.GetUniform("flashlightPos").UpdateValue(ref flashlightPosition); shader.GetUniform("flashlightSize").UpdateValue(ref flashlightSize); shader.GetUniform("flashlightDim").UpdateValue(ref flashlightDim); + shader.GetUniform("flashlightSmoothness").UpdateValue(ref flashlightSmoothness); renderer.DrawQuad(renderer.WhitePixel, screenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: addAction); From 47781a8f94ae17baf44dda250e32bfdfad7eecd6 Mon Sep 17 00:00:00 2001 From: vun Date: Mon, 3 Oct 2022 17:31:45 +0800 Subject: [PATCH 1423/2686] Fix code inspect issues and SR test cases --- .../TaikoDifficultyCalculatorTest.cs | 8 ++++---- .../Difficulty/Evaluators/StaminaEvaluator.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs index 425f72cadc..5685ac0f60 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs @@ -16,13 +16,13 @@ namespace osu.Game.Rulesets.Taiko.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; - [TestCase(3.1098944660126882d, 200, "diffcalc-test")] - [TestCase(3.1098944660126882d, 200, "diffcalc-test-strong")] + [TestCase(3.0920212594351191d, 200, "diffcalc-test")] + [TestCase(3.0920212594351191d, 200, "diffcalc-test-strong")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(4.0974106752474251d, 200, "diffcalc-test")] - [TestCase(4.0974106752474251d, 200, "diffcalc-test-strong")] + [TestCase(4.0789820318081444d, 200, "diffcalc-test")] + [TestCase(4.0789820318081444d, 200, "diffcalc-test-strong")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime()); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs index 59b61f47d1..84d5de4c63 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/StaminaEvaluator.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators /// /// Determines the number of fingers available to hit the current . - /// Any mono notes that is more than 300ms apart from a colour change will be considered to have more than 2 + /// Any mono notes that is more than 300ms apart from a colour change will be considered to have more than 2 /// fingers available, since players can hit the same key with multiple fingers. /// private static int availableFingersFor(TaikoDifficultyHitObject hitObject) From 8598eb29f8393106b1dbea30c9b1b8fbdddd3418 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 3 Oct 2022 18:26:35 +0900 Subject: [PATCH 1424/2686] Adjust flashlight to closely match classic --- osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index 79f5eed139..66f367c79b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override BindableBool ComboBasedSize { get; } = new BindableBool(true); - public override float DefaultFlashlightSize => 180; + public override float DefaultFlashlightSize => 200; private OsuFlashlight flashlight = null!; @@ -63,6 +63,7 @@ namespace osu.Game.Rulesets.Osu.Mods followDelay = modFlashlight.FollowDelay.Value; FlashlightSize = new Vector2(0, GetSizeFor(0)); + FlashlightSmoothness = 1.4f; } public void OnSliderTrackingChange(ValueChangedEvent e) From deae7cff60efdf4e58bbdcae9c7121565d575d2a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 3 Oct 2022 18:38:29 +0900 Subject: [PATCH 1425/2686] Adjust flashliht scaling to match classic --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 7ed73b3163..a594363d4c 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -151,9 +151,9 @@ namespace osu.Game.Rulesets.Mods if (comboBasedSize) { if (combo >= 200) - size *= 0.8f; + size *= 0.625f; else if (combo >= 100) - size *= 0.9f; + size *= 0.8125f; } return size; From 13ee5c179ea2dd338b3f9ef0001b4bb8a8941b90 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Oct 2022 18:42:40 +0900 Subject: [PATCH 1426/2686] Add missing parenthesis in log message --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 59c0af1533..8a42fef43d 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -563,7 +563,7 @@ namespace osu.Game PerformFromScreen(screen => { - Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset} to match score"); + Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset} to match score)"); Ruleset.Value = databasedScore.ScoreInfo.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap); From 7fbbe88c8ea945dfd8aa4b51091c354074e2a2d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Oct 2022 20:24:09 +0900 Subject: [PATCH 1427/2686] Add test coverage of song select score presentation failures --- .../Navigation/TestScenePresentScore.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs index 5e76fe1519..003cec0d07 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs @@ -9,8 +9,10 @@ using NUnit.Framework; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Online.API; using osu.Game.Rulesets; +using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; @@ -92,6 +94,31 @@ namespace osu.Game.Tests.Visual.Navigation returnToMenu(); } + [Test] + public void TestFromSongSelectWithFilter([Values] ScorePresentType type) + { + AddStep("enter song select", () => Game.ChildrenOfType().Single().OnSolo.Invoke()); + AddUntilStep("song select is current", () => Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect && songSelect.BeatmapSetsLoaded); + + AddStep("filter to nothing", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).FilterControl.CurrentTextSearch.Value = "fdsajkl;fgewq"); + AddUntilStep("wait for no results", () => Beatmap.IsDefault); + + var firstImport = importScore(1, new CatchRuleset().RulesetInfo); + presentAndConfirm(firstImport, type); + } + + [Test] + public void TestFromSongSelectWithConvertRulesetChange([Values] ScorePresentType type) + { + AddStep("enter song select", () => Game.ChildrenOfType().Single().OnSolo.Invoke()); + AddUntilStep("song select is current", () => Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect && songSelect.BeatmapSetsLoaded); + + AddStep("set convert to false", () => Game.LocalConfig.SetValue(OsuSetting.ShowConvertedBeatmaps, false)); + + var firstImport = importScore(1, new CatchRuleset().RulesetInfo); + presentAndConfirm(firstImport, type); + } + [Test] public void TestFromSongSelect([Values] ScorePresentType type) { From 332d63b53bee3d5ea18a4e7853aee834674d5039 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Oct 2022 20:04:37 +0900 Subject: [PATCH 1428/2686] Always return to main menu before attempting to present a score from import --- osu.Game/OsuGame.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 8a42fef43d..6359ed3e27 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -561,6 +561,8 @@ namespace osu.Game return; } + // This should be able to be performed from song select, but that is disabled for now + // due to the weird decoupled ruleset logic (which can cause a crash in certain filter scenarios). PerformFromScreen(screen => { Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset} to match score)"); @@ -578,7 +580,7 @@ namespace osu.Game screen.Push(new SoloResultsScreen(databasedScore.ScoreInfo, false)); break; } - }, validScreens: new[] { typeof(PlaySongSelect) }); + }); } public override Task Import(params ImportTask[] imports) From dfb143ec0bb1483c61b8a7d72812b535ba241466 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 3 Oct 2022 21:14:57 +0900 Subject: [PATCH 1429/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index dd263d6aaa..102d368095 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c4e2a5168e..9cc4f3fbab 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 622efcd63d..cc922d304f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + From e98b4b4fbd81273091472ef13dd30f8b8d0e0688 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Mon, 3 Oct 2022 23:14:21 +0200 Subject: [PATCH 1430/2686] Make `updateDisplayModeDropdowns` regular method --- .../Sections/Graphics/LayoutSettings.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 28642f12a1..f3483478ff 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -202,19 +202,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics // initial update bypasses transforms updateScalingModeVisibility(); - void updateDisplayModeDropdowns() - { - if (resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen) - resolutionDropdown.Show(); - else - resolutionDropdown.Hide(); - - if (displayDropdown.Items.Count() > 1) - displayDropdown.Show(); - else - displayDropdown.Hide(); - } - void updateScalingModeVisibility() { if (scalingMode.Value == ScalingMode.Off) @@ -225,6 +212,19 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } } + private void updateDisplayModeDropdowns() + { + if (resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen) + resolutionDropdown.Show(); + else + resolutionDropdown.Hide(); + + if (displayDropdown.Items.Count() > 1) + displayDropdown.Show(); + else + displayDropdown.Hide(); + } + private void updateScreenModeWarning() { if (RuntimeInfo.OS == RuntimeInfo.Platform.macOS) From 31fefc1ee2d07bf1b137d9bc3822f84bb6a8495b Mon Sep 17 00:00:00 2001 From: Susko3 Date: Mon, 3 Oct 2022 23:23:02 +0200 Subject: [PATCH 1431/2686] Add nullable annotation to `LayoutSettings` --- .../Sections/Graphics/LayoutSettings.cs | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index f3483478ff..dbedd01125 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.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. -#nullable disable - using System; using System.Drawing; using System.Linq; @@ -29,31 +27,31 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { protected override LocalisableString Header => GraphicsSettingsStrings.LayoutHeader; - private FillFlowContainer> scalingSettings; + private FillFlowContainer> scalingSettings = null!; private readonly Bindable currentDisplay = new Bindable(); private readonly IBindableList windowModes = new BindableList(); - private Bindable scalingMode; - private Bindable sizeFullscreen; + private Bindable scalingMode = null!; + private Bindable sizeFullscreen = null!; private readonly BindableList resolutions = new BindableList(new[] { new Size(9999, 9999) }); private readonly IBindable fullscreenCapability = new Bindable(FullscreenCapability.Capable); [Resolved] - private OsuGameBase game { get; set; } + private OsuGameBase game { get; set; } = null!; [Resolved] - private GameHost host { get; set; } + private GameHost host { get; set; } = null!; - private SettingsDropdown resolutionDropdown; - private SettingsDropdown displayDropdown; - private SettingsDropdown windowModeDropdown; + private SettingsDropdown resolutionDropdown = null!; + private SettingsDropdown displayDropdown = null!; + private SettingsDropdown windowModeDropdown = null!; - private Bindable scalingPositionX; - private Bindable scalingPositionY; - private Bindable scalingSizeX; - private Bindable scalingSizeY; + private Bindable scalingPositionX = null!; + private Bindable scalingPositionY = null!; + private Bindable scalingSizeX = null!; + private Bindable scalingSizeY = null!; private const int transition_duration = 400; @@ -280,7 +278,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics }; } - private Drawable preview; + private Drawable? preview; private void showPreview() { From efc9bed4f062010097e9a8a13deb2b3856c7822b Mon Sep 17 00:00:00 2001 From: Susko3 Date: Mon, 3 Oct 2022 23:52:04 +0200 Subject: [PATCH 1432/2686] Use `IWindow.DisplaysChanged` to update displays --- .../Sections/Graphics/LayoutSettings.cs | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index dbedd01125..42edd49a47 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Drawing; using System.Linq; using osu.Framework; @@ -44,6 +45,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics [Resolved] private GameHost host { get; set; } = null!; + private IWindow? window; + private SettingsDropdown resolutionDropdown = null!; private SettingsDropdown displayDropdown = null!; private SettingsDropdown windowModeDropdown = null!; @@ -58,6 +61,8 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics [BackgroundDependencyLoader] private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, GameHost host) { + window = host.Window; + scalingMode = osuConfig.GetBindable(OsuSetting.Scaling); sizeFullscreen = config.GetBindable(FrameworkSetting.SizeFullscreen); scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX); @@ -65,10 +70,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics scalingPositionX = osuConfig.GetBindable(OsuSetting.ScalingPositionX); scalingPositionY = osuConfig.GetBindable(OsuSetting.ScalingPositionY); - if (host.Window != null) + if (window != null) { - currentDisplay.BindTo(host.Window.CurrentDisplayBindable); - windowModes.BindTo(host.Window.SupportedWindowModes); + currentDisplay.BindTo(window.CurrentDisplayBindable); + windowModes.BindTo(window.SupportedWindowModes); + window.DisplaysChanged += onDisplaysChanged; } if (host.Window is WindowsWindow windowsWindow) @@ -85,7 +91,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics displayDropdown = new DisplaySettingsDropdown { LabelText = GraphicsSettingsStrings.Display, - Items = host.Window?.Displays, + Items = window?.Displays, Current = currentDisplay, }, resolutionDropdown = new ResolutionSettingsDropdown @@ -210,6 +216,15 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } } + private void onDisplaysChanged(IEnumerable displays) + { + Scheduler.AddOnce(d => + { + displayDropdown.Items = d; + updateDisplayModeDropdowns(); + }, displays); + } + private void updateDisplayModeDropdowns() { if (resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen) @@ -289,6 +304,14 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics preview.Expire(); } + protected override void Dispose(bool isDisposing) + { + if (window != null) + window.DisplaysChanged -= onDisplaysChanged; + + base.Dispose(isDisposing); + } + private class ScalingPreview : ScalingContainer { public ScalingPreview() From 929eb8559e9101e1ce1ba6a2249d15c9531d17d0 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 3 Oct 2022 16:02:33 -0700 Subject: [PATCH 1433/2686] Fix `LegacySmoke` alpha calculations --- .../Skinning/Legacy/LegacySmoke.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index f02c20fefb..b8d70c1c6d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -67,6 +67,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected new LegacySmoke Source => (LegacySmoke)base.Source; private double initialFadeOutDurationTrunc; + private double firstVisiblePointTime; + private double initialFadeOutTime; private double reFadeInTime; private double finalFadeOutTime; @@ -83,20 +85,22 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { base.ApplyState(); - initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); rotationSeed = Source.RotationSeed; - rotationRNG = new Random(rotationSeed); - initialFadeOutTime = Math.Min(CurrentTime, SmokeEndTime); - reFadeInTime = re_fade_in_speed * (CurrentTime - SmokeEndTime) + SmokeEndTime - initialFadeOutDurationTrunc; - finalFadeOutTime = final_fade_out_speed * (CurrentTime - SmokeEndTime) + SmokeEndTime - initialFadeOutDurationTrunc * (1 + 1 / re_fade_in_speed); + + initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); + firstVisiblePointTime = SmokeEndTime - initialFadeOutDurationTrunc; + + initialFadeOutTime = CurrentTime; + reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / re_fade_in_speed); + finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / final_fade_out_speed); } protected override Color4 PointColour(SmokePoint point) { var color = Color4.White; - double timeDoingInitialFadeOut = initialFadeOutTime - point.Time; + double timeDoingInitialFadeOut = Math.Min(initialFadeOutTime, SmokeEndTime) - point.Time; if (timeDoingInitialFadeOut > 0) { @@ -106,8 +110,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (color.A > 0) { - double timeDoingReFadeIn = reFadeInTime - point.Time; - double timeDoingFinalFadeOut = finalFadeOutTime - point.Time; + double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed; + double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; if (timeDoingFinalFadeOut > 0) { From c1da3bc9cf831b35f368bb54c64e84bdede47339 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 3 Oct 2022 16:03:37 -0700 Subject: [PATCH 1434/2686] Remove skinnable parents at the same time as their smoke children --- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index 2b5bddf959..f8551e46e9 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Game.Rulesets.Osu.Skinning; using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osuTK; @@ -44,6 +45,9 @@ namespace osu.Game.Rulesets.Osu.UI { isSmoking = false; SmokeEnded?.Invoke(Time.Current); + + foreach (SkinnableDrawable skinnable in Children) + skinnable.LifetimeEnd = skinnable.Drawable.LifetimeEnd; } } From 343bdaa98efbc457ba5383fe4c488c0ba1297f7a Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 3 Oct 2022 16:07:39 -0700 Subject: [PATCH 1435/2686] Remove unnecessary `IsActive` variable --- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index 4d2a193a8a..fae875eedb 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -40,7 +40,6 @@ namespace osu.Game.Rulesets.Osu.Skinning protected double SmokeEndTime { get; private set; } = double.MaxValue; protected virtual float PointInterval => Radius * 7f / 8; - protected bool IsActive { get; private set; } protected readonly List SmokePoints = new List(); @@ -73,7 +72,6 @@ namespace osu.Game.Rulesets.Osu.Skinning { smokeContainer.SmokeMoved += onSmokeMoved; smokeContainer.SmokeEnded += onSmokeEnded; - IsActive = true; onSmokeMoved(smokeContainer.LastMousePosition, Time.Current); } @@ -87,9 +85,6 @@ namespace osu.Game.Rulesets.Osu.Skinning private void onSmokeMoved(Vector2 position, double time) { - if (!IsActive) - return; - lastPosition ??= position; float delta = (position - (Vector2)lastPosition).LengthFast; @@ -137,10 +132,12 @@ namespace osu.Game.Rulesets.Osu.Skinning private void onSmokeEnded(double time) { - if (!IsActive) - return; + if (smokeContainer != null) + { + smokeContainer.SmokeMoved -= onSmokeMoved; + smokeContainer.SmokeEnded -= onSmokeEnded; + } - IsActive = false; SmokeEndTime = time; } From ccef189b81569aa25b0d2ce26c03039be9a7aeea Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 3 Oct 2022 18:19:05 -0700 Subject: [PATCH 1436/2686] Add barebones test for smoke --- .../metrics-skin/cursor-smoke@2x.png | Bin 0 -> 251 bytes .../Resources/old-skin/cursor-smoke.png | Bin 0 -> 2249 bytes osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs | 97 ++++++++++++++++++ osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 4 +- 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/metrics-skin/cursor-smoke@2x.png create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/old-skin/cursor-smoke.png create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/metrics-skin/cursor-smoke@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/metrics-skin/cursor-smoke@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b1380a47a47f4e1b293237f24f54606600a72964 GIT binary patch literal 251 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85p>QL70(Y)*K0--~>+>$B>G+x3d-b7z}wDZvFm0znsl}FGJhS zNhUL2p0i9pQWN3LxM3Pof-dWUsCWMx?mqphHvMN5)mND^EPTSXYMH5sl2F_0v2 ik^M!U07BoXGyGz#Jf&%6Kd%7Y#^CAd=d#Wzp$PzN-cP*% literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/cursor-smoke.png b/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/cursor-smoke.png new file mode 100644 index 0000000000000000000000000000000000000000..5f7beae4e9dddd9493c3353ae209ea8c5679ca9c GIT binary patch literal 2249 zcmaJ@dstFw8b=WE5?-g&a_UIUrk21_P#{rJyk$6wkeA0z2~L6v2f2unsYJGBUdqyL zZaHPsWz*WG)y%Z1p3K=*9L+4Z)~skMt(nrwQmZ|fHS@>1=Xt*Ko%efw@9+J+m+yJb zw%C{my!AqB6bglpiez(<9WX6R3*@cTYF{CnnUWh3f@(ClJw*)jbQXt&LjAqcW?Fzn zY%6(Wk`jfoy=q!!*Wu$L6bcg{;U%gPIcpd~SV|O#;PntOS1L!)C{#dDu3R9@gjB$K zC|x3B5`JsFL;xfrCLw{!A#>!RkXRC_RY39D7@km@DWr=CL4kPdfLsQ`Aca%{AXl0t zQ!;Xygc)K6@@+aM5r7$pDw9cInIZy-oLC?fRzLuiNc9$yeL%pUP6VkGItZ==e8`|L z2_%zz=-wd6p!hRDKVbGDAmIQYKq1<|;IhMK!yy)vAXcg53=&DB(GWGhL|Bnd0_k)* ziR?r2@$p6w-pV|gN|5Uu9Cnqz(gxp535y70;2d+DpL6uZkckn zUP$FgxdJ%}B$7?3eFkzk{~s!qenBf$T!CjX)7p9X5?6qzW*3Lt$M zXOs2iNB~|kI_SoTe&JDmzk1_NDjuE@XWxeb? zFd!}ejosVpZ!wOG%i;a@)pZ^2;KFNGm#rMCzmqhM-f0`vPNH*CS0uId48}Jk^EV#4 zbEL&{QRVf?1qnmH5V7M&dc}E<)IRO@DYib83svpK=Z4ao-VOPU9)K;Ink#6Qzr1!H zlU;NeF|@(IKJVIaRng^#jlPW6wQo18a?{@8Mx5h$d~?dxt~&WN6?;~G%8GrNj_tfe zzwLB)zDuhk0R7rHd~~=bO?ZZ?11P)r#_qGa@+RzKv~VM4S)r{x&7ow#<*+}l(4xeB zEaFA8=4n*x_YEg?F7!gXNQwT^<~vhUu-Q>so9AuEC-)qlJ-fXy7M{{(t`DiZrPDlb zFhi%R@4BQ|(l!O0U*%E73*|=RS+U=hHVwYW6FZ^XY_r6AUo+gn*V|V2A8w}KT@v8p zkurWi9|#-BKJQuKj4r6%ExDGkg6t7qy{_!hWJ^(f-x13tmiC8N(+gJy?{JNGvcqZ2 zOLv{d-&jpSw<*ErWSHM;J=*r;iMo!{W-ZK*Uy&UOU1RlL6Xu&)dy~;VhfZ>RU-}As z(>BB|69p~uAhtB`EBAPzts@3n_m>2ECE||hQ#W(F8BbaL>q-umKZx#@)W)NQHl68a zxy`}7aX(J4((BE(1=$A9Ta2&3s=@4>i$VTs%+s+hdTNK^C#%QHZkCoZU7y*o?>lPi zA5PWP=NJp-wc~5iiwJ9|p5%$9q91BTT>3hriu=npiH+f^t`5IpsAfC%lf?w;xd4yM9-hOI$o_@jD9zP8yOxP78RZ8ykxTuA6Z`3 zpZKu=fQZDnb|)82D`BnS&*RSfDf(5YomKO0Fs%G00r|oqOZGIUsPl&I%F-1Nddy|9 zna9WSfp7Z5iumR4H~y*Bny=y=ACC#ylAnJU_ZN(zYw+vii;Ny6!C&9nqYu>;>{;+S zKe~(>J^U|@PF8KPNa5vmK!-1Q66<6iL_3gqlc3$^o$oB7Q_Z5BoxuMy2~ zJTJ;Jz8^)oPHd@NtEFky8}B4b>K3O@Sd`-3i+=*qk>i7kb=Ihsz0*@?-6IF4&}`m? z50l-&o)!5_=`^p<59f;AM&q7L%^u5c!L^NTBzY%+kAB{o9QT%5|FJvxoZ4T$W~2wx ze1EwPf3xz5@sO|5E4gCR%Y|ci%f`7y@eQnh3|Bey9@Aa3?snU=TSKiw(QigL^bADr zqh|zXbCb32x%+A9epyueL{wzw4>e`=yMmhCup`U&jwTGfKJmsGvuA#KUz%M@!prGX zr58_m#tu~PxaYiCgGps`OV{qtFJS&{JH{*>#`YZ!Jf)%9YjUj29{|g{XbHV@s literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs new file mode 100644 index 0000000000..ce1cab3b9b --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs @@ -0,0 +1,97 @@ +// 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 NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Input.Events; +using osu.Framework.Input.States; +using osu.Framework.Testing.Input; +using osu.Game.Rulesets.Osu.UI; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneSmoke : OsuSkinnableTestScene + { + [Test] + public void TestSmoking() + { + AddStep("Create smoke", () => + { + SetContents(_ => + { + return new SmokingInputManager + { + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.95f), + Child = new TestSmokeContainer { RelativeSizeAxes = Axes.Both }, + }; + }); + }); + } + + private const double spin_duration = 5_000; + private const float spin_angle = 4 * MathF.PI; + + private class SmokingInputManager : ManualInputManager + { + private double? startTime; + + public SmokingInputManager() + { + UseParentInput = false; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + MoveMouseTo(ToScreenSpace(DrawSize / 2)); + } + + protected override void Update() + { + base.Update(); + + startTime ??= Time.Current; + + float fraction = (float)((Time.Current - startTime) / spin_duration); + + float angle = fraction * spin_angle; + float radius = fraction * Math.Min(DrawSize.X, DrawSize.Y) / 2; + + Vector2 pos = radius * new Vector2(MathF.Cos(angle), MathF.Sin(angle)) + DrawSize / 2; + MoveMouseTo(ToScreenSpace(pos)); + } + } + + private class TestSmokeContainer : SmokeContainer + { + private double? startTime; + private bool isPressing; + private bool isFinished; + + protected override void Update() + { + base.Update(); + + startTime ??= Time.Current; + + if (!isPressing && !isFinished && Time.Current > startTime + 0.1) + { + OnPressed(new KeyBindingPressEvent(new InputState(), OsuAction.Smoke)); + isPressing = true; + isFinished = false; + } + + if (isPressing && Time.Current > startTime + spin_duration) + { + OnReleased(new KeyBindingReleaseEvent(new InputState(), OsuAction.Smoke)); + isPressing = false; + isFinished = true; + } + } + } + } +} diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index f8551e46e9..449dd920d6 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -using osu.Game.Rulesets.Osu.Skinning; +using osu.Framework.Logging; using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osuTK; @@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Osu.UI { if (e.Action == OsuAction.Smoke) { + Logger.Log("holy moly"); + isSmoking = true; AddInternal(new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Smoke), _ => new DefaultSmoke())); From eaab0deef32f037a2de634c8eb0406d95cc601c8 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 3 Oct 2022 19:20:51 -0700 Subject: [PATCH 1437/2686] Fix InspectCode issues --- osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs | 11 ++++------- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 6 +++++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs index ce1cab3b9b..82417d09a7 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs @@ -19,14 +19,11 @@ namespace osu.Game.Rulesets.Osu.Tests { AddStep("Create smoke", () => { - SetContents(_ => + SetContents(_ => new SmokingInputManager { - return new SmokingInputManager - { - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.95f), - Child = new TestSmokeContainer { RelativeSizeAxes = Axes.Both }, - }; + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.95f), + Child = new TestSmokeContainer { RelativeSizeAxes = Axes.Both }, }); }); } diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index 449dd920d6..e139e16ff2 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; @@ -48,8 +49,11 @@ namespace osu.Game.Rulesets.Osu.UI isSmoking = false; SmokeEnded?.Invoke(Time.Current); - foreach (SkinnableDrawable skinnable in Children) + foreach (Drawable child in Children) + { + var skinnable = (SkinnableDrawable)child; skinnable.LifetimeEnd = skinnable.Drawable.LifetimeEnd; + } } } From 97207c11f55f5a0f464a67c7543c312e2b81ee7c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 18:52:21 +0900 Subject: [PATCH 1438/2686] Add base transformer for osu!mania argon skin --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 4 +++ .../Argon/ManiaArgonSkinTransformer.cs | 35 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 061dedb07a..c6b20b1baf 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -26,6 +26,7 @@ using osu.Game.Rulesets.Mania.Edit.Setup; using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Scoring; +using osu.Game.Rulesets.Mania.Skinning.Argon; using osu.Game.Rulesets.Mania.Skinning.Legacy; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; @@ -68,6 +69,9 @@ namespace osu.Game.Rulesets.Mania { case LegacySkin: return new ManiaLegacySkinTransformer(skin, beatmap); + + case ArgonSkin: + return new ManiaArgonSkinTransformer(skin); } return null; diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs new file mode 100644 index 0000000000..67dd484923 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -0,0 +1,35 @@ +// 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.Graphics; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Mania.Skinning.Argon +{ + public class ManiaArgonSkinTransformer : SkinTransformer + { + public ManiaArgonSkinTransformer(ISkin skin) + : base(skin) + { + } + + public override Drawable? GetDrawableComponent(ISkinComponent component) + { + switch (component) + { + case ManiaSkinComponent maniaComponent: + switch (maniaComponent.Component) + { + case ManiaSkinComponents.KeyArea: + return new ArgonKeyArea(); + + // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. + } + + break; + } + + return base.GetDrawableComponent(component); + } + } +} From 326a3e65834a3950ccd49c361e17cac6a88f5ed5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 18:52:35 +0900 Subject: [PATCH 1439/2686] Add TODO in osu! argon transformer regarding missing components --- osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 7bc6723afb..3794350f6a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -56,6 +56,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon case OsuSkinComponents.CursorTrail: return new ArgonCursorTrail(); + + // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. } break; From 83e7cc1e09b45adcd1454f63d74b0dd9c5e5c6d1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 18:52:43 +0900 Subject: [PATCH 1440/2686] Add argon key area --- .../Skinning/Argon/ArgonKeyArea.cs | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs new file mode 100644 index 0000000000..055c21390c --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -0,0 +1,167 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.UI.Scrolling; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Skinning.Argon +{ + public class ArgonKeyArea : CompositeDrawable, IKeyBindingHandler + { + private const float key_icon_size = 10; + + private readonly IBindable direction = new Bindable(); + + private Container directionContainer = null!; + private Container keyIcon = null!; + private Drawable gradient = null!; + + [Resolved] + private Column column { get; set; } = null!; + + public ArgonKeyArea() + { + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(IScrollingInfo scrollingInfo) + { + const float icon_circle_size = 8; + const float icon_spacing = 8; + const float icon_vertical_offset = 20; + + InternalChild = directionContainer = new Container + { + RelativeSizeAxes = Axes.X, + Height = Stage.HIT_TARGET_POSITION, + Children = new[] + { + gradient = new Box + { + Name = "Key gradient", + RelativeSizeAxes = Axes.Both, + Alpha = 0.5f + }, + keyIcon = new Container + { + Name = "Icons", + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Children = new[] + { + new Circle + { + Y = icon_vertical_offset, + Size = new Vector2(icon_circle_size), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Blending = BlendingParameters.Additive, + Colour = column.AccentColour, + Masking = true, + }, + new Circle + { + X = -icon_spacing, + Y = icon_vertical_offset + icon_spacing * 1.2f, + Size = new Vector2(icon_circle_size), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Blending = BlendingParameters.Additive, + Colour = column.AccentColour, + Masking = true, + }, + new Circle + { + X = icon_spacing, + Y = icon_vertical_offset + icon_spacing * 1.2f, + Size = new Vector2(icon_circle_size), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Blending = BlendingParameters.Additive, + Colour = column.AccentColour, + Masking = true, + } + } + }, + } + }; + + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(onDirectionChanged, true); + } + + private void onDirectionChanged(ValueChangedEvent direction) + { + switch (direction.NewValue) + { + case ScrollingDirection.Up: + directionContainer.Scale = new Vector2(1, -1); + directionContainer.Anchor = Anchor.TopLeft; + directionContainer.Origin = Anchor.BottomLeft; + gradient.Colour = ColourInfo.GradientVertical(Color4.Black, Color4.Black.Opacity(0)); + break; + + case ScrollingDirection.Down: + directionContainer.Scale = new Vector2(1, 1); + directionContainer.Anchor = Anchor.BottomLeft; + directionContainer.Origin = Anchor.BottomLeft; + gradient.Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0), Color4.Black); + break; + } + } + + public bool OnPressed(KeyBindingPressEvent e) + { + if (e.Action == column.Action.Value) + { + foreach (var circle in keyIcon.Children) + { + circle.ScaleTo(1.1f, 50, Easing.OutQuint); + + circle.FadeColour(Color4.White, 50, Easing.OutQuint); + circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Color4.White.Opacity(0.05f), + Radius = 10, + }, 50, Easing.OutQuint); + } + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + if (e.Action == column.Action.Value) + { + foreach (var circle in keyIcon.Children) + { + circle.ScaleTo(1f, 125, Easing.OutQuint); + + circle.FadeColour(column.AccentColour, 200, Easing.OutQuint); + circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Color4.White.Opacity(0), + Radius = 10, + }, 200, Easing.OutQuint); + } + } + } + } +} From 4718f4ac249017a695c5421fbc9e3c3ac1897228 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 19:13:37 +0900 Subject: [PATCH 1441/2686] Add second icon and improve glow effect --- .../Skinning/Argon/ArgonKeyArea.cs | 66 ++++++++++++------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index 055c21390c..1bda832b76 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -1,11 +1,11 @@ // 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.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; @@ -20,13 +20,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { public class ArgonKeyArea : CompositeDrawable, IKeyBindingHandler { - private const float key_icon_size = 10; - private readonly IBindable direction = new Bindable(); private Container directionContainer = null!; - private Container keyIcon = null!; - private Drawable gradient = null!; + private Container keyIcon = null!; + private Drawable background = null!; [Resolved] private Column column { get; set; } = null!; @@ -40,8 +38,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon private void load(IScrollingInfo scrollingInfo) { const float icon_circle_size = 8; - const float icon_spacing = 8; - const float icon_vertical_offset = 20; + const float icon_spacing = 7; + const float icon_vertical_offset = -30; InternalChild = directionContainer = new Container { @@ -49,13 +47,13 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Height = Stage.HIT_TARGET_POSITION, Children = new[] { - gradient = new Box + background = new Box { Name = "Key gradient", RelativeSizeAxes = Axes.Both, - Alpha = 0.5f + Colour = column.AccentColour.Darken(0.6f), }, - keyIcon = new Container + keyIcon = new Container { Name = "Icons", RelativeSizeAxes = Axes.Both, @@ -67,8 +65,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { Y = icon_vertical_offset, Size = new Vector2(icon_circle_size), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, Blending = BlendingParameters.Additive, Colour = column.AccentColour, Masking = true, @@ -78,8 +76,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon X = -icon_spacing, Y = icon_vertical_offset + icon_spacing * 1.2f, Size = new Vector2(icon_circle_size), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, Blending = BlendingParameters.Additive, Colour = column.AccentColour, Masking = true, @@ -89,11 +87,30 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon X = icon_spacing, Y = icon_vertical_offset + icon_spacing * 1.2f, Size = new Vector2(icon_circle_size), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, Blending = BlendingParameters.Additive, Colour = column.AccentColour, Masking = true, + }, + new CircularContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Y = -icon_vertical_offset, + Size = new Vector2(22, 14), + Masking = true, + BorderThickness = 4, + BorderColour = Color4.White, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true, + }, + }, } } }, @@ -112,14 +129,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon directionContainer.Scale = new Vector2(1, -1); directionContainer.Anchor = Anchor.TopLeft; directionContainer.Origin = Anchor.BottomLeft; - gradient.Colour = ColourInfo.GradientVertical(Color4.Black, Color4.Black.Opacity(0)); break; case ScrollingDirection.Down: directionContainer.Scale = new Vector2(1, 1); directionContainer.Anchor = Anchor.BottomLeft; directionContainer.Origin = Anchor.BottomLeft; - gradient.Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0), Color4.Black); break; } } @@ -128,7 +143,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { if (e.Action == column.Action.Value) { - foreach (var circle in keyIcon.Children) + foreach (var circle in keyIcon.Children.OfType()) { circle.ScaleTo(1.1f, 50, Easing.OutQuint); @@ -136,8 +151,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters { Type = EdgeEffectType.Glow, - Colour = Color4.White.Opacity(0.05f), - Radius = 10, + Colour = Color4.White.Opacity(circle is Circle ? 0.05f : 0.2f), + Radius = 40, }, 50, Easing.OutQuint); } } @@ -149,16 +164,19 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { if (e.Action == column.Action.Value) { - foreach (var circle in keyIcon.Children) + foreach (var circle in keyIcon.Children.OfType()) { circle.ScaleTo(1f, 125, Easing.OutQuint); - circle.FadeColour(column.AccentColour, 200, Easing.OutQuint); + // TODO: temp lol + if (circle is Circle) + circle.FadeColour(column.AccentColour, 200, Easing.OutQuint); + circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters { Type = EdgeEffectType.Glow, Colour = Color4.White.Opacity(0), - Radius = 10, + Radius = 30, }, 200, Easing.OutQuint); } } From d32eb6456112ef071fc5ccfc98ea74ba2f4e8007 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 19:32:58 +0900 Subject: [PATCH 1442/2686] Adjust colour application to stay around a bit longer --- .../Skinning/Argon/ArgonKeyArea.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index 1bda832b76..63e00041b8 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -143,9 +143,13 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { if (e.Action == column.Action.Value) { + background + .FadeColour(column.AccentColour.Lighten(0.3f), 50, Easing.OutQuint).Then() + .FadeColour(column.AccentColour, 100, Easing.OutQuint); + foreach (var circle in keyIcon.Children.OfType()) { - circle.ScaleTo(1.1f, 50, Easing.OutQuint); + circle.ScaleTo(0.9f, 50, Easing.OutQuint); circle.FadeColour(Color4.White, 50, Easing.OutQuint); circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters @@ -164,20 +168,22 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { if (e.Action == column.Action.Value) { + background.FadeColour(column.AccentColour.Darken(0.6f), 800, Easing.OutQuint); + foreach (var circle in keyIcon.Children.OfType()) { - circle.ScaleTo(1f, 125, Easing.OutQuint); + circle.ScaleTo(1f, 200, Easing.OutQuint); // TODO: temp lol if (circle is Circle) - circle.FadeColour(column.AccentColour, 200, Easing.OutQuint); + circle.FadeColour(column.AccentColour, 800, Easing.OutQuint); circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters { Type = EdgeEffectType.Glow, Colour = Color4.White.Opacity(0), Radius = 30, - }, 200, Easing.OutQuint); + }, 800, Easing.OutQuint); } } } From 36e2f5c512783d9f542f23fb4e7a4b69efceaa59 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 27 Sep 2022 19:48:27 +0900 Subject: [PATCH 1443/2686] Add argon hit target pieces --- .../Skinning/Argon/ArgonHitTarget.cs | 33 +++++++++++++++++++ .../Skinning/Argon/ArgonKeyArea.cs | 27 +++++++++++++-- .../Argon/ManiaArgonSkinTransformer.cs | 3 ++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs new file mode 100644 index 0000000000..6518607c9d --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs @@ -0,0 +1,33 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Mania.Skinning.Default; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Skinning.Argon +{ + public class ArgonHitTarget : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.X; + Height = DefaultNotePiece.NOTE_HEIGHT; + + InternalChildren = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.3f, + Blending = BlendingParameters.Additive, + Colour = Color4.White + }, + }; + } + } +} diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index 63e00041b8..f2acc61416 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Game.Graphics; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; using osuTK; @@ -26,6 +27,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon private Container keyIcon = null!; private Drawable background = null!; + private Circle hitTargetLine = null!; + [Resolved] private Column column { get; set; } = null!; @@ -61,6 +64,15 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Origin = Anchor.TopCentre, Children = new[] { + hitTargetLine = new Circle() + { + RelativeSizeAxes = Axes.X, + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Colour = OsuColour.Gray(196 / 255f), + Height = 4, + Masking = true, + }, new Circle { Y = icon_vertical_offset, @@ -149,13 +161,18 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon foreach (var circle in keyIcon.Children.OfType()) { - circle.ScaleTo(0.9f, 50, Easing.OutQuint); + if (circle != hitTargetLine) + circle.ScaleTo(0.9f, 50, Easing.OutQuint); circle.FadeColour(Color4.White, 50, Easing.OutQuint); + + // TODO: VERY TMPOERAOIRY. + float f = circle == hitTargetLine ? 0.2f : (circle is Circle ? 0.05f : 0.2f); + circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters { Type = EdgeEffectType.Glow, - Colour = Color4.White.Opacity(circle is Circle ? 0.05f : 0.2f), + Colour = Color4.White.Opacity(f), Radius = 40, }, 50, Easing.OutQuint); } @@ -175,7 +192,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon circle.ScaleTo(1f, 200, Easing.OutQuint); // TODO: temp lol - if (circle is Circle) + if (circle == hitTargetLine) + { + circle.FadeColour(OsuColour.Gray(196 / 255f), 800, Easing.OutQuint); + } + else if (circle is Circle) circle.FadeColour(column.AccentColour, 800, Easing.OutQuint); circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index 67dd484923..dab71a65c3 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -20,6 +20,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon case ManiaSkinComponent maniaComponent: switch (maniaComponent.Component) { + case ManiaSkinComponents.HitTarget: + return new ArgonHitTarget(); + case ManiaSkinComponents.KeyArea: return new ArgonKeyArea(); From 21620bee1adce55fb12a6b9b65f7f0ad4ed0e675 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 4 Oct 2022 14:58:00 +0900 Subject: [PATCH 1444/2686] Attempt to fix deadlock in test --- ...stSceneOnlinePlayBeatmapAvailabilityTracker.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs index 3f20f843a7..e7590df3e0 100644 --- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Threading; -using System.Threading.Tasks; using JetBrains.Annotations; using NUnit.Framework; using osu.Framework.Allocation; @@ -78,7 +77,7 @@ namespace osu.Game.Tests.Online } }; - beatmaps.AllowImport = new TaskCompletionSource(); + beatmaps.AllowImport.Reset(); testBeatmapFile = TestResources.GetQuickTestBeatmapForImport(); @@ -132,7 +131,7 @@ namespace osu.Game.Tests.Online AddStep("finish download", () => ((TestDownloadRequest)beatmapDownloader.GetExistingDownload(testBeatmapSet))!.TriggerSuccess(testBeatmapFile)); addAvailabilityCheckStep("state importing", BeatmapAvailability.Importing); - AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true)); + AddStep("allow importing", () => beatmaps.AllowImport.Set()); AddUntilStep("wait for import", () => beatmaps.CurrentImport != null); AddUntilStep("ensure beatmap available", () => beatmaps.IsAvailableLocally(testBeatmapSet)); addAvailabilityCheckStep("state is locally available", BeatmapAvailability.LocallyAvailable); @@ -141,7 +140,7 @@ namespace osu.Game.Tests.Online [Test] public void TestTrackerRespectsSoftDeleting() { - AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true)); + AddStep("allow importing", () => beatmaps.AllowImport.Set()); AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely()); addAvailabilityCheckStep("state locally available", BeatmapAvailability.LocallyAvailable); @@ -155,7 +154,7 @@ namespace osu.Game.Tests.Online [Test] public void TestTrackerRespectsChecksum() { - AddStep("allow importing", () => beatmaps.AllowImport.SetResult(true)); + AddStep("allow importing", () => beatmaps.AllowImport.Set()); AddStep("import beatmap", () => beatmaps.Import(testBeatmapFile).WaitSafely()); addAvailabilityCheckStep("initially locally available", BeatmapAvailability.LocallyAvailable); @@ -202,7 +201,7 @@ namespace osu.Game.Tests.Online private class TestBeatmapManager : BeatmapManager { - public TaskCompletionSource AllowImport = new TaskCompletionSource(); + public readonly ManualResetEventSlim AllowImport = new ManualResetEventSlim(); public Live CurrentImport { get; private set; } @@ -229,7 +228,9 @@ namespace osu.Game.Tests.Online public override Live ImportModel(BeatmapSetInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) { - testBeatmapManager.AllowImport.Task.WaitSafely(); + if (!testBeatmapManager.AllowImport.Wait(TimeSpan.FromSeconds(10), cancellationToken)) + throw new TimeoutException("Timeout waiting for import to be allowed."); + return (testBeatmapManager.CurrentImport = base.ImportModel(item, archive, batchImport, cancellationToken)); } } From 5d80950eaf51f01f37471bf59f46f27f67d4f809 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 4 Oct 2022 14:01:36 +0900 Subject: [PATCH 1445/2686] Compute lifetime from entry in scrolling container --- .../Scrolling/ScrollingHitObjectContainer.cs | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index d0aca4e7fc..b012abb6b5 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -5,10 +5,10 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Primitives; using osu.Framework.Layout; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -127,6 +127,16 @@ namespace osu.Game.Rulesets.UI.Scrolling private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight; + public override void Add(HitObjectLifetimeEntry entry) + { + // Scroll info is not available until loaded. + // The lifetime of all entries will be updated in the first Update. + if (IsLoaded) + setComputedLifetimeStart(entry); + + base.Add(entry); + } + protected override void AddDrawable(HitObjectLifetimeEntry entry, DrawableHitObject drawable) { base.AddDrawable(entry, drawable); @@ -145,7 +155,6 @@ namespace osu.Game.Rulesets.UI.Scrolling private void invalidateHitObject(DrawableHitObject hitObject) { - hitObject.LifetimeStart = computeOriginAdjustedLifetimeStart(hitObject); layoutComputed.Remove(hitObject); } @@ -157,10 +166,8 @@ namespace osu.Game.Rulesets.UI.Scrolling layoutComputed.Clear(); - // Reset lifetime to the conservative estimation. - // If a drawable becomes alive by this lifetime, its lifetime will be updated to a more precise lifetime in the next update. foreach (var entry in Entries) - entry.SetInitialLifetime(); + setComputedLifetimeStart(entry); scrollingInfo.Algorithm.Reset(); @@ -187,38 +194,46 @@ namespace osu.Game.Rulesets.UI.Scrolling } } - private double computeOriginAdjustedLifetimeStart(DrawableHitObject hitObject) + /// + /// Get a conservative maximum bounding box of a corresponding to . + /// It is used to calculate when the hit object appears. + /// + protected virtual RectangleF GetConservativeBoundingBox(HitObjectLifetimeEntry entry) => new RectangleF().Inflate(100); + + private double computeDisplayStartTime(HitObjectLifetimeEntry entry) { - // Origin position may be relative to the parent size - Debug.Assert(hitObject.Parent != null); + RectangleF boundingBox = GetConservativeBoundingBox(entry); + float startOffset = 0; - float originAdjustment = 0.0f; - - // calculate the dimension of the part of the hitobject that should already be visible - // when the hitobject origin first appears inside the scrolling container switch (direction.Value) { - case ScrollingDirection.Up: - originAdjustment = hitObject.OriginPosition.Y; + case ScrollingDirection.Right: + startOffset = boundingBox.Right; break; case ScrollingDirection.Down: - originAdjustment = hitObject.DrawHeight - hitObject.OriginPosition.Y; + startOffset = boundingBox.Bottom; break; case ScrollingDirection.Left: - originAdjustment = hitObject.OriginPosition.X; + startOffset = -boundingBox.Left; break; - case ScrollingDirection.Right: - originAdjustment = hitObject.DrawWidth - hitObject.OriginPosition.X; + case ScrollingDirection.Up: + startOffset = -boundingBox.Top; break; } - double computedStartTime = scrollingInfo.Algorithm.GetDisplayStartTime(hitObject.HitObject.StartTime, originAdjustment, timeRange.Value, scrollLength); + return scrollingInfo.Algorithm.GetDisplayStartTime(entry.HitObject.StartTime, startOffset, timeRange.Value, scrollLength); + } + + private void setComputedLifetimeStart(HitObjectLifetimeEntry entry) + { + double computedStartTime = computeDisplayStartTime(entry); // always load the hitobject before its first judgement offset - return Math.Min(hitObject.HitObject.StartTime - hitObject.MaximumJudgementOffset, computedStartTime); + double judgementOffset = entry.HitObject.HitWindows?.WindowFor(Scoring.HitResult.Miss) ?? 0; + entry.LifetimeStart = Math.Min(entry.HitObject.StartTime - judgementOffset, computedStartTime); } private void updateLayoutRecursive(DrawableHitObject hitObject) From 781f5420b0d1aa0a1f359c0f74e59a2787851ce8 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 4 Oct 2022 15:17:11 +0900 Subject: [PATCH 1446/2686] Add test for scrolling hit object lifetime --- .../Gameplay/TestSceneScrollingHitObjects.cs | 70 +++++++++++++++---- .../UI/Scrolling/ScrollingPlayfield.cs | 4 +- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs index 8a4818d2f8..98afbe92b1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs @@ -11,8 +11,10 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Threading; +using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Configuration; using osu.Game.Rulesets.Mods; @@ -167,14 +169,39 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("add control points", () => addControlPoints(testControlPoints, Time.Current)); } - private void addHitObject(double time) + [Test] + public void TestVeryFlowScroll() + { + const double long_time_range = 100000; + var manualClock = new ManualClock(); + + AddStep("set manual clock", () => + { + manualClock.CurrentTime = 0; + scrollContainers.ForEach(c => c.Clock = new FramedClock(manualClock)); + + setScrollAlgorithm(ScrollVisualisationMethod.Constant); + scrollContainers.ForEach(c => c.TimeRange = long_time_range); + }); + + AddStep("add hit objects", () => + { + addHitObject(long_time_range); + addHitObject(long_time_range + 100, 250); + }); + + AddAssert("hit objects are alive", () => playfields.All(p => p.HitObjectContainer.AliveObjects.Count() == 2)); + } + + private void addHitObject(double time, float size = 75) { playfields.ForEach(p => { - var hitObject = new TestDrawableHitObject(time); - setAnchor(hitObject, p); + var hitObject = new TestHitObject(size) { StartTime = time }; + var drawable = new TestDrawableHitObject(hitObject); - p.Add(hitObject); + setAnchor(drawable, p); + p.Add(drawable); }); } @@ -248,6 +275,8 @@ namespace osu.Game.Tests.Visual.Gameplay } }; } + + protected override ScrollingHitObjectContainer CreateScrollingHitObjectContainer() => new TestScrollingHitObjectContainer(); } private class TestDrawableControlPoint : DrawableHitObject @@ -281,22 +310,39 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class TestDrawableHitObject : DrawableHitObject + private class TestHitObject : HitObject { - public TestDrawableHitObject(double time) - : base(new HitObject { StartTime = time, HitWindows = HitWindows.Empty }) - { - Origin = Anchor.Custom; - OriginPosition = new Vector2(75 / 4.0f); + public readonly float Size; - AutoSizeAxes = Axes.Both; + public TestHitObject(float size) + { + Size = size; + } + } + + private class TestDrawableHitObject : DrawableHitObject + { + public TestDrawableHitObject(TestHitObject hitObject) + : base(hitObject) + { + Origin = Anchor.Centre; + Size = new Vector2(hitObject.Size); AddInternal(new Box { - Size = new Vector2(75), + RelativeSizeAxes = Axes.Both, Colour = new Color4(RNG.NextSingle(), RNG.NextSingle(), RNG.NextSingle(), 1) }); } } + + private class TestScrollingHitObjectContainer : ScrollingHitObjectContainer + { + protected override RectangleF GetConservativeBoundingBox(HitObjectLifetimeEntry entry) + { + var hitObject = (TestHitObject)entry.HitObject; + return new RectangleF().Inflate(hitObject.Size / 2); + } + } } } diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index 078f06b745..34e5b7f9de 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -38,6 +38,8 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public virtual Vector2 ScreenSpacePositionAtTime(double time) => HitObjectContainer.ScreenSpacePositionAtTime(time); - protected sealed override HitObjectContainer CreateHitObjectContainer() => new ScrollingHitObjectContainer(); + protected sealed override HitObjectContainer CreateHitObjectContainer() => CreateScrollingHitObjectContainer(); + + protected virtual ScrollingHitObjectContainer CreateScrollingHitObjectContainer() => new ScrollingHitObjectContainer(); } } From 1cccd03480dcf9c54031ac564a0e947ecb76d56e Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 4 Oct 2022 15:03:04 +0900 Subject: [PATCH 1447/2686] Fix scrolling nested hit object lifetime not set --- osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index b012abb6b5..37da157cc1 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -251,8 +251,9 @@ namespace osu.Game.Rulesets.UI.Scrolling { updateLayoutRecursive(obj); - // Nested hitobjects don't need to scroll, but they do need accurate positions + // Nested hitobjects don't need to scroll, but they do need accurate positions and start lifetime updatePosition(obj, hitObject.HitObject.StartTime); + setComputedLifetimeStart(obj.Entry); } } From 2aa4d21c757c84dd4ddefffd3620b326f7b6b0d8 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 4 Oct 2022 15:08:53 +0900 Subject: [PATCH 1448/2686] Remove code that is not needed anymore --- osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs | 4 ---- .../Objects/Drawables/DrawableManiaHitObject.cs | 4 ---- 2 files changed, 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs index 6020348938..a607ed572d 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs @@ -54,10 +54,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables } } - protected override void UpdateInitialTransforms() - { - } - protected override void UpdateStartTimeStateTransforms() => this.FadeOut(150); } } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index bcc10ab7bc..6cd39d835d 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -23,10 +23,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables protected readonly IBindable Direction = new Bindable(); - // Leaving the default (10s) makes hitobjects not appear, as this offset is used for the initial state transforms. - // Calculated as DrawableManiaRuleset.MAX_TIME_RANGE + some additional allowance for velocity < 1. - protected override double InitialLifetimeOffset => 30000; - [Resolved(canBeNull: true)] private ManiaPlayfield playfield { get; set; } From 1ffa0afafc2663b780f93a48cca3d048d601daf0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 16:05:36 +0900 Subject: [PATCH 1449/2686] Tweak visuals and fix up code quality --- .../Skinning/Argon/ArgonKeyArea.cs | 189 ++++++++++-------- 1 file changed, 107 insertions(+), 82 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index f2acc61416..0153cdbd68 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -1,7 +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 System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -24,11 +23,13 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon private readonly IBindable direction = new Bindable(); private Container directionContainer = null!; - private Container keyIcon = null!; private Drawable background = null!; private Circle hitTargetLine = null!; + private Container bottomIcon = null!; + private CircularContainer topIcon = null!; + [Resolved] private Column column { get; set; } = null!; @@ -56,56 +57,58 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon RelativeSizeAxes = Axes.Both, Colour = column.AccentColour.Darken(0.6f), }, - keyIcon = new Container + hitTargetLine = new Circle + { + RelativeSizeAxes = Axes.X, + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Colour = OsuColour.Gray(196 / 255f), + Height = 4, + Masking = true, + }, + new Container { Name = "Icons", RelativeSizeAxes = Axes.Both, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Children = new[] + Children = new Drawable[] { - hitTargetLine = new Circle() + bottomIcon = new Container { - RelativeSizeAxes = Axes.X, - Anchor = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, - Colour = OsuColour.Gray(196 / 255f), - Height = 4, - Masking = true, - }, - new Circle - { + Blending = BlendingParameters.Additive, + Colour = column.AccentColour, Y = icon_vertical_offset, - Size = new Vector2(icon_circle_size), - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre, - Blending = BlendingParameters.Additive, - Colour = column.AccentColour, - Masking = true, + Children = new[] + { + new Circle + { + Size = new Vector2(icon_circle_size), + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + }, + new Circle + { + X = -icon_spacing, + Y = icon_spacing * 1.2f, + Size = new Vector2(icon_circle_size), + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + }, + new Circle + { + X = icon_spacing, + Y = icon_spacing * 1.2f, + Size = new Vector2(icon_circle_size), + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + }, + } }, - new Circle - { - X = -icon_spacing, - Y = icon_vertical_offset + icon_spacing * 1.2f, - Size = new Vector2(icon_circle_size), - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre, - Blending = BlendingParameters.Additive, - Colour = column.AccentColour, - Masking = true, - }, - new Circle - { - X = icon_spacing, - Y = icon_vertical_offset + icon_spacing * 1.2f, - Size = new Vector2(icon_circle_size), - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre, - Blending = BlendingParameters.Additive, - Colour = column.AccentColour, - Masking = true, - }, - new CircularContainer + topIcon = new CircularContainer { Anchor = Anchor.TopCentre, Origin = Anchor.Centre, @@ -153,29 +156,41 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon public bool OnPressed(KeyBindingPressEvent e) { - if (e.Action == column.Action.Value) + if (e.Action != column.Action.Value) return false; + + const double lighting_fade_in_duration = 50; + Color4 lightingColour = column.AccentColour.Lighten(0.9f); + + background + .FadeColour(column.AccentColour.Lighten(0.4f), 40).Then() + .FadeColour(column.AccentColour, 150, Easing.OutQuint); + + hitTargetLine.FadeColour(Color4.White, lighting_fade_in_duration, Easing.OutQuint); + hitTargetLine.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters { - background - .FadeColour(column.AccentColour.Lighten(0.3f), 50, Easing.OutQuint).Then() - .FadeColour(column.AccentColour, 100, Easing.OutQuint); + Type = EdgeEffectType.Glow, + Colour = lightingColour.Opacity(0.7f), + Radius = 20, + }, lighting_fade_in_duration, Easing.OutQuint); - foreach (var circle in keyIcon.Children.OfType()) + topIcon.ScaleTo(0.9f, lighting_fade_in_duration, Easing.OutQuint); + topIcon.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = lightingColour.Opacity(0.1f), + Radius = 20, + }, lighting_fade_in_duration, Easing.OutQuint); + + bottomIcon.FadeColour(Color4.White, lighting_fade_in_duration, Easing.OutQuint); + + foreach (var circle in bottomIcon) + { + circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters { - if (circle != hitTargetLine) - circle.ScaleTo(0.9f, 50, Easing.OutQuint); - - circle.FadeColour(Color4.White, 50, Easing.OutQuint); - - // TODO: VERY TMPOERAOIRY. - float f = circle == hitTargetLine ? 0.2f : (circle is Circle ? 0.05f : 0.2f); - - circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = Color4.White.Opacity(f), - Radius = 40, - }, 50, Easing.OutQuint); - } + Type = EdgeEffectType.Glow, + Colour = lightingColour.Opacity(0.3f), + Radius = 60, + }, lighting_fade_in_duration, Easing.OutQuint); } return false; @@ -183,29 +198,39 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon public void OnReleased(KeyBindingReleaseEvent e) { - if (e.Action == column.Action.Value) + if (e.Action != column.Action.Value) return; + + const double lighting_fade_out_duration = 300; + Color4 lightingColour = column.AccentColour.Lighten(0.9f).Opacity(0); + + background.FadeColour(column.AccentColour.Darken(0.6f), lighting_fade_out_duration, Easing.OutQuint); + + topIcon.ScaleTo(1f, 200, Easing.OutQuint); + topIcon.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters { - background.FadeColour(column.AccentColour.Darken(0.6f), 800, Easing.OutQuint); + Type = EdgeEffectType.Glow, + Colour = lightingColour, + Radius = 20, + }, lighting_fade_out_duration, Easing.OutQuint); - foreach (var circle in keyIcon.Children.OfType()) + hitTargetLine.FadeColour(OsuColour.Gray(196 / 255f), lighting_fade_out_duration, Easing.OutQuint); + hitTargetLine.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = lightingColour, + Radius = 30, + }, lighting_fade_out_duration, Easing.OutQuint); + + bottomIcon.FadeColour(column.AccentColour, lighting_fade_out_duration, Easing.OutQuint); + + foreach (var circle in bottomIcon) + { + circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters { - circle.ScaleTo(1f, 200, Easing.OutQuint); - - // TODO: temp lol - if (circle == hitTargetLine) - { - circle.FadeColour(OsuColour.Gray(196 / 255f), 800, Easing.OutQuint); - } - else if (circle is Circle) - circle.FadeColour(column.AccentColour, 800, Easing.OutQuint); - - circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = Color4.White.Opacity(0), - Radius = 30, - }, 800, Easing.OutQuint); - } + Type = EdgeEffectType.Glow, + Colour = lightingColour, + Radius = 30, + }, lighting_fade_out_duration, Easing.OutQuint); } } } From 15d159a97e05b80445bc2e50161b448d827f96d4 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 4 Oct 2022 16:10:18 +0900 Subject: [PATCH 1450/2686] Fix tests --- .../Objects/Drawables/DrawableHoldNoteHead.cs | 8 -------- .../Visual/Gameplay/TestSceneScrollingHitObjects.cs | 6 ++++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs index d374e935ec..66cc93b033 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs @@ -30,14 +30,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables public bool UpdateResult() => base.UpdateResult(true); - protected override void UpdateInitialTransforms() - { - base.UpdateInitialTransforms(); - - // This hitobject should never expire, so this is just a safe maximum. - LifetimeEnd = LifetimeStart + 30000; - } - protected override void UpdateHitStateTransforms(ArmedState state) { // suppress the base call explicitly. diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs index 98afbe92b1..156a1ee34a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs @@ -340,8 +340,10 @@ namespace osu.Game.Tests.Visual.Gameplay { protected override RectangleF GetConservativeBoundingBox(HitObjectLifetimeEntry entry) { - var hitObject = (TestHitObject)entry.HitObject; - return new RectangleF().Inflate(hitObject.Size / 2); + if (entry.HitObject is TestHitObject testObject) + return new RectangleF().Inflate(testObject.Size / 2); + + return base.GetConservativeBoundingBox(entry); } } } From 345430ab39d45f7d47231b080472bb660c364e0a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 16:15:24 +0900 Subject: [PATCH 1451/2686] Fix argon hit target area not being aligned correctly --- .../Skinning/Argon/ArgonHitTarget.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs index 6518607c9d..4750118583 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs @@ -2,18 +2,22 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Mania.Skinning.Default; +using osu.Game.Rulesets.UI.Scrolling; using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { public class ArgonHitTarget : CompositeDrawable { + private readonly IBindable direction = new Bindable(); + [BackgroundDependencyLoader] - private void load() + private void load(IScrollingInfo scrollingInfo) { RelativeSizeAxes = Axes.X; Height = DefaultNotePiece.NOTE_HEIGHT; @@ -28,6 +32,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Colour = Color4.White }, }; + + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(onDirectionChanged, true); + } + + private void onDirectionChanged(ValueChangedEvent direction) + { + Anchor = Origin = direction.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; } } } From b0a948df459440dc7aefcf661e446a3eefe732bd Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 4 Oct 2022 00:17:00 -0700 Subject: [PATCH 1452/2686] Move `LegacySmoke` animation implementation to `Smoke` --- WeatherConfig.dat | 3 + .../Skinning/Default/DefaultSmoke.cs | 52 ------- .../Skinning/Legacy/LegacySmoke.cs | 144 +----------------- .../Legacy/OsuLegacySkinTransformer.cs | 2 +- osu.Game.Rulesets.Osu/Skinning/Smoke.cs | 127 +++++++++++++-- 5 files changed, 121 insertions(+), 207 deletions(-) create mode 100644 WeatherConfig.dat diff --git a/WeatherConfig.dat b/WeatherConfig.dat new file mode 100644 index 0000000000..88a312bf91 --- /dev/null +++ b/WeatherConfig.dat @@ -0,0 +1,3 @@ +5363943 +La Jolla,US +F diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs index 65ae490882..c3bc04a858 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -1,65 +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; -using osuTK; -using osuTK.Graphics; - namespace osu.Game.Rulesets.Osu.Skinning.Default { public class DefaultSmoke : Smoke { - private const double fade_out_delay = 8000; - private const double fade_out_speed = 3; - private const double fade_out_duration = 50; - private const float alpha = 0.5f; - - public override double LifetimeEnd => SmokeEndTime + fade_out_delay + fade_out_duration + (SmokeEndTime - SmokeStartTime) / fade_out_speed; - public DefaultSmoke() { Radius = 2; } - - protected override DrawNode CreateDrawNode() => new DefaultSmokeDrawNode(this); - - private class DefaultSmokeDrawNode : SmokeDrawNode - { - private double fadeOutTime; - - public DefaultSmokeDrawNode(ITexturedShaderDrawable source) - : base(source) - { - } - - public override void ApplyState() - { - base.ApplyState(); - - fadeOutTime = SmokeStartTime + fade_out_speed * (CurrentTime - (SmokeEndTime + fade_out_delay)); - } - - protected override Color4 PointColour(SmokePoint point) - { - var color = Color4.White; - color.A = alpha; - - double timeDoingFadeOut = fadeOutTime - point.Time; - - if (timeDoingFadeOut > 0) - { - float fraction = Math.Clamp((float)(1 - (timeDoingFadeOut / fade_out_duration)), 0, 1); - fraction = MathF.Pow(fraction, 5); - color.A *= fraction; - } - - return color; - } - - protected override float PointScale(SmokePoint point) => 1f; - - protected override Vector2 PointDirection(SmokePoint point) => point.Direction; - } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs index b8d70c1c6d..89e90cd4c8 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs @@ -1,157 +1,19 @@ // 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; -using osu.Framework.Utils; +using osu.Framework.Allocation; using osu.Game.Skinning; -using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacySmoke : Smoke { - // fade values - private const double initial_fade_out_duration = 4000; - - private const double re_fade_in_speed = 3; - private const double re_fade_in_duration = 50; - - private const double final_fade_out_speed = 2; - private const double final_fade_out_duration = 8000; - - private const float initial_alpha = 0.6f; - private const float re_fade_in_alpha = 1f; - - // scale values - private const double scale_duration = 1200; - - private const float initial_scale = 0.65f; - private const float final_scale = 1f; - - // rotation values - private const double rotation_duration = 500; - - private const float max_rotation = 0.25f; - - protected int RotationSeed { get; set; } = RNG.Next(); - - public override double LifetimeEnd - { - get - { - double initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); - return SmokeEndTime + final_fade_out_duration + initialFadeOutDurationTrunc / re_fade_in_speed + initialFadeOutDurationTrunc / final_fade_out_speed; - } - } - - private readonly ISkin skin; - - public LegacySmoke(ISkin skin) - { - this.skin = skin; - } - - protected override void LoadComplete() + [BackgroundDependencyLoader] + private void load(ISkinSource skin) { base.LoadComplete(); Texture = skin.GetTexture("cursor-smoke"); } - - protected override DrawNode CreateDrawNode() => new LegacySmokeDrawNode(this); - - protected class LegacySmokeDrawNode : SmokeDrawNode - { - protected new LegacySmoke Source => (LegacySmoke)base.Source; - - private double initialFadeOutDurationTrunc; - private double firstVisiblePointTime; - - private double initialFadeOutTime; - private double reFadeInTime; - private double finalFadeOutTime; - - private int rotationSeed; - private Random rotationRNG = new Random(); - - public LegacySmokeDrawNode(ITexturedShaderDrawable source) - : base(source) - { - } - - public override void ApplyState() - { - base.ApplyState(); - - rotationSeed = Source.RotationSeed; - rotationRNG = new Random(rotationSeed); - - initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); - firstVisiblePointTime = SmokeEndTime - initialFadeOutDurationTrunc; - - initialFadeOutTime = CurrentTime; - reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / re_fade_in_speed); - finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / final_fade_out_speed); - } - - protected override Color4 PointColour(SmokePoint point) - { - var color = Color4.White; - - double timeDoingInitialFadeOut = Math.Min(initialFadeOutTime, SmokeEndTime) - point.Time; - - if (timeDoingInitialFadeOut > 0) - { - float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); - color.A = (1 - fraction) * initial_alpha; - } - - if (color.A > 0) - { - double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed; - double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; - - if (timeDoingFinalFadeOut > 0) - { - float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); - fraction = MathF.Pow(fraction, 5); - color.A = (1 - fraction) * re_fade_in_alpha; - } - else if (timeDoingReFadeIn > 0) - { - float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1); - fraction = 1 - MathF.Pow(1 - fraction, 5); - color.A = fraction * (re_fade_in_alpha - color.A) + color.A; - } - } - - return color; - } - - protected override float PointScale(SmokePoint point) - { - double timeDoingScale = CurrentTime - point.Time; - float fraction = Math.Clamp((float)(timeDoingScale / scale_duration), 0, 1); - fraction = 1 - MathF.Pow(1 - fraction, 5); - return fraction * (final_scale - initial_scale) + initial_scale; - } - - protected override Vector2 PointDirection(SmokePoint point) - { - float initialAngle = MathF.Atan2(point.Direction.Y, point.Direction.X); - float finalAngle = initialAngle + nextRotation(); - - double timeDoingRotation = CurrentTime - point.Time; - float fraction = Math.Clamp((float)(timeDoingRotation / rotation_duration), 0, 1); - fraction = 1 - MathF.Pow(1 - fraction, 5); - float angle = fraction * (finalAngle - initialAngle) + initialAngle; - - return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); - } - - private float nextRotation() => max_rotation * ((float)rotationRNG.NextDouble() * 2 - 1); - } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index a9186f821e..d44d2b031a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy case OsuSkinComponents.Smoke: if (GetTexture("cursor-smoke") != null) - return new LegacySmoke(this); + return new LegacySmoke(); return null; diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs index fae875eedb..5d2aa2b1f6 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Smoke.cs @@ -25,6 +25,15 @@ namespace osu.Game.Rulesets.Osu.Skinning public IShader? TextureShader { get; private set; } public IShader? RoundedTextureShader { get; private set; } + public override double LifetimeEnd + { + get + { + double initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); + return SmokeEndTime + final_fade_out_duration + initialFadeOutDurationTrunc / re_fade_in_speed + initialFadeOutDurationTrunc / final_fade_out_speed; + } + } + private float? radius; protected float Radius @@ -39,21 +48,45 @@ namespace osu.Game.Rulesets.Osu.Skinning protected double SmokeEndTime { get; private set; } = double.MaxValue; - protected virtual float PointInterval => Radius * 7f / 8; - protected readonly List SmokePoints = new List(); + protected virtual float PointInterval => Radius * 7f / 8; + private float totalDistance; private Vector2? lastPosition; + private SmokeContainer? smokeContainer; private const int max_point_count = 18_000; - [Resolved(CanBeNull = true)] - private SmokeContainer? smokeContainer { get; set; } + // fade anim values + private const double initial_fade_out_duration = 4000; + + private const double re_fade_in_speed = 3; + private const double re_fade_in_duration = 50; + + private const double final_fade_out_speed = 2; + private const double final_fade_out_duration = 8000; + + private const float initial_alpha = 0.6f; + private const float re_fade_in_alpha = 1f; + + private readonly int rotationSeed = RNG.Next(); + + // scale anim values + private const double scale_duration = 1200; + + private const float initial_scale = 0.65f; + private const float final_scale = 1f; + + // rotation anim values + private const double rotation_duration = 500; + + private const float max_rotation = 0.25f; [BackgroundDependencyLoader] - private void load(ShaderManager shaders) + private void load(SmokeContainer container, ShaderManager shaders) { + smokeContainer = container; RoundedTextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE); } @@ -128,8 +161,6 @@ namespace osu.Game.Rulesets.Osu.Skinning onSmokeEnded(time); } - public abstract override double LifetimeEnd { get; } - private void onSmokeEnded(double time) { if (smokeContainer != null) @@ -141,7 +172,7 @@ namespace osu.Game.Rulesets.Osu.Skinning SmokeEndTime = time; } - protected abstract override DrawNode CreateDrawNode(); + protected override DrawNode CreateDrawNode() => new SmokeDrawNode(this); protected override void Update() { @@ -181,7 +212,7 @@ namespace osu.Game.Rulesets.Osu.Skinning } } - protected abstract class SmokeDrawNode : TexturedShaderDrawNode + protected class SmokeDrawNode : TexturedShaderDrawNode { protected new Smoke Source => (Smoke)base.Source; @@ -195,7 +226,17 @@ namespace osu.Game.Rulesets.Osu.Skinning private Vector2 drawSize; private Texture? texture; - protected SmokeDrawNode(ITexturedShaderDrawable source) + // anim calculation vars (color, scale, direction) + private double initialFadeOutDurationTrunc; + private double firstVisiblePointTime; + + private double initialFadeOutTime; + private double reFadeInTime; + private double finalFadeOutTime; + + private Random rotationRNG = new Random(); + + public SmokeDrawNode(ITexturedShaderDrawable source) : base(source) { } @@ -214,6 +255,15 @@ namespace osu.Game.Rulesets.Osu.Skinning SmokeStartTime = Source.SmokeStartTime; SmokeEndTime = Source.SmokeEndTime; CurrentTime = Source.Clock.CurrentTime; + + rotationRNG = new Random(Source.rotationSeed); + + initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); + firstVisiblePointTime = SmokeEndTime - initialFadeOutDurationTrunc; + + initialFadeOutTime = CurrentTime; + reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / re_fade_in_speed); + finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / final_fade_out_speed); } public sealed override void Draw(IRenderer renderer) @@ -246,11 +296,62 @@ namespace osu.Game.Rulesets.Osu.Skinning ? ((SRGBColour)DrawColourInfo.Colour).Linear : DrawColourInfo.Colour.Interpolate(Vector2.Divide(localPos, drawSize)).Linear; - protected abstract Color4 PointColour(SmokePoint point); + protected virtual Color4 PointColour(SmokePoint point) + { + var color = Color4.White; - protected abstract float PointScale(SmokePoint point); + double timeDoingInitialFadeOut = Math.Min(initialFadeOutTime, SmokeEndTime) - point.Time; - protected abstract Vector2 PointDirection(SmokePoint point); + if (timeDoingInitialFadeOut > 0) + { + float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); + color.A = (1 - fraction) * initial_alpha; + } + + if (color.A > 0) + { + double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed; + double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; + + if (timeDoingFinalFadeOut > 0) + { + float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); + fraction = MathF.Pow(fraction, 5); + color.A = (1 - fraction) * re_fade_in_alpha; + } + else if (timeDoingReFadeIn > 0) + { + float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1); + fraction = 1 - MathF.Pow(1 - fraction, 5); + color.A = fraction * (re_fade_in_alpha - color.A) + color.A; + } + } + + return color; + } + + protected virtual float PointScale(SmokePoint point) + { + double timeDoingScale = CurrentTime - point.Time; + float fraction = Math.Clamp((float)(timeDoingScale / scale_duration), 0, 1); + fraction = 1 - MathF.Pow(1 - fraction, 5); + return fraction * (final_scale - initial_scale) + initial_scale; + } + + protected virtual Vector2 PointDirection(SmokePoint point) + { + float initialAngle = MathF.Atan2(point.Direction.Y, point.Direction.X); + float finalAngle = initialAngle + nextRotation(); + + double timeDoingRotation = CurrentTime - point.Time; + float fraction = Math.Clamp((float)(timeDoingRotation / rotation_duration), 0, 1); + fraction = 1 - MathF.Pow(1 - fraction, 5); + float angle = fraction * (finalAngle - initialAngle) + initialAngle; + + return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); + } + + private float nextRotation() => max_rotation * ((float)rotationRNG.NextDouble() * 2 - 1); private void drawPointQuad(SmokePoint point, RectangleF textureRect) { From 395ab5889220b3d705441871904cbbfe5b7ca907 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 16:17:38 +0900 Subject: [PATCH 1453/2686] Attempt to fix code style infractions --- .../Skinning/Argon/ManiaArgonSkinTransformer.cs | 3 +-- .../Skinning/Argon/OsuArgonSkinTransformer.cs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index dab71a65c3..ec6aaf2ef7 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -18,6 +18,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon switch (component) { case ManiaSkinComponent maniaComponent: + // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (maniaComponent.Component) { case ManiaSkinComponents.HitTarget: @@ -25,8 +26,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon case ManiaSkinComponents.KeyArea: return new ArgonKeyArea(); - - // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. } break; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 3794350f6a..bf507db50c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -22,6 +22,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon return new ArgonJudgementPiece(resultComponent.Component); case OsuSkinComponent osuComponent: + // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (osuComponent.Component) { case OsuSkinComponents.HitCircle: @@ -56,8 +57,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon case OsuSkinComponents.CursorTrail: return new ArgonCursorTrail(); - - // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. } break; From 33f33a684571833115a3e0bd581bbc34f1e253d4 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 4 Oct 2022 00:53:03 -0700 Subject: [PATCH 1454/2686] Remove things that should've been removed before push --- WeatherConfig.dat | 3 --- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 3 --- 2 files changed, 6 deletions(-) delete mode 100644 WeatherConfig.dat diff --git a/WeatherConfig.dat b/WeatherConfig.dat deleted file mode 100644 index 88a312bf91..0000000000 --- a/WeatherConfig.dat +++ /dev/null @@ -1,3 +0,0 @@ -5363943 -La Jolla,US -F diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index e139e16ff2..4984dc1ad1 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -using osu.Framework.Logging; using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osuTK; @@ -31,8 +30,6 @@ namespace osu.Game.Rulesets.Osu.UI { if (e.Action == OsuAction.Smoke) { - Logger.Log("holy moly"); - isSmoking = true; AddInternal(new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Smoke), _ => new DefaultSmoke())); From c2956c6e1e9e64a1154040550e36ef5042f7adbf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 17:28:15 +0900 Subject: [PATCH 1455/2686] Add osu! hit object dim Stable would dim objects when they can't be hit (ie. the "miss" window is not active yet). This was never implemented in lazer, and causes quite large visual differences. No one has mentioned this yet, but it will definitely be one of those missing pieces which makes lazer feel different to stable. --- .../Objects/Drawables/DrawableOsuHitObject.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 6f4ca30bd0..26518e0a27 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -11,7 +11,9 @@ using osu.Framework.Graphics.Primitives; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Scoring; using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -64,6 +66,21 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables ScaleBindable.UnbindFrom(HitObject.ScaleBindable); } + protected override void UpdateInitialTransforms() + { + base.UpdateInitialTransforms(); + + double missWindow = HitObject.HitWindows.WindowFor(HitResult.Miss); + + // Of note, no one noticed this was missing for years, but it definitely feels like it should still exist. + // For now this is applied across all skins, and matches stable. + // For simplicity, dim colour is applied to the DrawableHitObject itself. + // We may need to make a nested container setup if this even causes a usage conflict (ie. with a mod). + this.FadeColour(new Color4(195, 195, 195, 255)); + using (BeginDelayedSequence(InitialLifetimeOffset - missWindow)) + this.FadeColour(Color4.White, 100); + } + protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; private OsuInputManager osuActionInputManager; From 41082ab9286921be507a3b4a82d0cc95e69b9438 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 4 Oct 2022 18:21:29 +0900 Subject: [PATCH 1456/2686] Fix misplaced parenthesis --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 6359ed3e27..939d3a63ed 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -565,7 +565,7 @@ namespace osu.Game // due to the weird decoupled ruleset logic (which can cause a crash in certain filter scenarios). PerformFromScreen(screen => { - Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset} to match score)"); + Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset}) to match score"); Ruleset.Value = databasedScore.ScoreInfo.Ruleset; Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap); From 7293ad751ee92a3d8d3d4f5dd95d6f2260794c69 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 4 Oct 2022 18:59:33 +0900 Subject: [PATCH 1457/2686] Update packages --- 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 77c29a5d6e..c33937ad95 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 29e690a024..31b17fb8e1 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 83410b08f6..a9a83e2802 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -82,7 +82,7 @@ - + From 44b99444a7720533a3240dc174a3d4165ff893b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 13:42:04 +0900 Subject: [PATCH 1458/2686] Hide approach circles immediate on successful hit --- .../Objects/Drawables/DrawableHitCircle.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index c5992b359d..23db29b9a6 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -204,12 +204,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables // todo: temporary / arbitrary, used for lifetime optimisation. this.Delay(800).FadeOut(); - // in the case of an early state change, the fade should be expedited to the current point in time. - if (HitStateUpdateTime < HitObject.StartTime) - ApproachCircle.FadeOut(50); - switch (state) { + default: + ApproachCircle.FadeOut(); + break; + case ArmedState.Idle: HitArea.HitAction = null; break; From e06ece7531c11c4f9a8717b1bb5f70338a27fbc3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 14:15:54 +0900 Subject: [PATCH 1459/2686] Update framework --- osu.Android.props | 2 +- osu.Desktop/OsuGameDesktop.cs | 7 ++++--- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index c33937ad95..6ad810483b 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index d9ad95f96a..3ee1b3da30 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -137,12 +137,13 @@ namespace osu.Desktop { base.SetHost(host); - var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"); - var desktopWindow = (SDL2DesktopWindow)host.Window; + var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"); + if (iconStream != null) + desktopWindow.SetIconFromStream(iconStream); + desktopWindow.CursorState |= CursorState.Hidden; - desktopWindow.SetIconFromStream(iconStream); desktopWindow.Title = Name; desktopWindow.DragDrop += f => fileDrop(new[] { f }); } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 31b17fb8e1..df7bfab17a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index a9a83e2802..9e2568bf7e 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + @@ -82,7 +82,7 @@ - + From 276021dd85f2abe7774f5a91e474e0f7307b55fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 14:20:01 +0900 Subject: [PATCH 1460/2686] Remove now unnecessary `ScheduleAfterChildren` --- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 548dd2a5bb..2eec8253b3 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -335,8 +335,7 @@ namespace osu.Game.Screens.Play.HUD private float? scoreComponentsTargetWidth; - // Schedule required to get correct DrawWidth from text after updates. - private void updateDetailsWidth() => SchedulerAfterChildren.AddOnce(() => + private void updateDetailsWidth() { const float score_components_min_width = 88f; @@ -349,7 +348,7 @@ namespace osu.Game.Screens.Play.HUD scoreComponentsTargetWidth = newWidth; scoreComponents.ResizeWidthTo(newWidth, panel_transition_duration, Easing.OutQuint); - }); + } private void updateState() { From 56d424003d240863894829e9241ad1b9b18a290a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 14:25:04 +0900 Subject: [PATCH 1461/2686] Fix sliders not dimming correctly due to modified miss window --- .../Objects/Drawables/DrawableOsuHitObject.cs | 6 ++---- osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs | 9 ++++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 26518e0a27..2935791cde 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Primitives; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Judgements; -using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.Osu.Scoring; using osuTK; using osuTK.Graphics; @@ -70,14 +70,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.UpdateInitialTransforms(); - double missWindow = HitObject.HitWindows.WindowFor(HitResult.Miss); - // Of note, no one noticed this was missing for years, but it definitely feels like it should still exist. // For now this is applied across all skins, and matches stable. // For simplicity, dim colour is applied to the DrawableHitObject itself. // We may need to make a nested container setup if this even causes a usage conflict (ie. with a mod). this.FadeColour(new Color4(195, 195, 195, 255)); - using (BeginDelayedSequence(InitialLifetimeOffset - missWindow)) + using (BeginDelayedSequence(InitialLifetimeOffset - OsuHitWindows.MISS_WINDOW)) this.FadeColour(Color4.White, 100); } diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs b/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs index 05fbac625e..6f55e1790f 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs @@ -1,20 +1,23 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Scoring { public class OsuHitWindows : HitWindows { + /// + /// osu! ruleset has a fixed miss window regardless of difficulty settings. + /// + public const double MISS_WINDOW = 400; + private static readonly DifficultyRange[] osu_ranges = { new DifficultyRange(HitResult.Great, 80, 50, 20), new DifficultyRange(HitResult.Ok, 140, 100, 60), new DifficultyRange(HitResult.Meh, 200, 150, 100), - new DifficultyRange(HitResult.Miss, 400, 400, 400), + new DifficultyRange(HitResult.Miss, MISS_WINDOW, MISS_WINDOW, MISS_WINDOW), }; public override bool IsHitResultAllowed(HitResult result) From 74db42394a47e11c258abc8417d6076c2f850a66 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 14:31:12 +0900 Subject: [PATCH 1462/2686] Silence unobserved exceptions in `BeginPlayingInternal` Closes #20526. --- osu.Game/Online/Spectator/OnlineSpectatorClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Spectator/OnlineSpectatorClient.cs b/osu.Game/Online/Spectator/OnlineSpectatorClient.cs index a012bf49b6..48d5c0bea9 100644 --- a/osu.Game/Online/Spectator/OnlineSpectatorClient.cs +++ b/osu.Game/Online/Spectator/OnlineSpectatorClient.cs @@ -1,9 +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; using System.Diagnostics; using System.Threading.Tasks; -using Microsoft.AspNetCore.SignalR; using Microsoft.AspNetCore.SignalR.Client; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -58,7 +58,7 @@ namespace osu.Game.Online.Spectator { await connection.InvokeAsync(nameof(ISpectatorServer.BeginPlaySession), state); } - catch (HubException exception) + catch (Exception exception) { if (exception.GetHubExceptionMessage() == HubClientConnector.SERVER_SHUTDOWN_MESSAGE) { From 52002d91dd578efcd216930adab12546ab0c13d9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 17:48:56 +0900 Subject: [PATCH 1463/2686] Only apply dim at top level objects --- .../Objects/Drawables/DrawableOsuHitObject.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index 2935791cde..d9d0d28477 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -70,13 +70,17 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.UpdateInitialTransforms(); - // Of note, no one noticed this was missing for years, but it definitely feels like it should still exist. - // For now this is applied across all skins, and matches stable. - // For simplicity, dim colour is applied to the DrawableHitObject itself. - // We may need to make a nested container setup if this even causes a usage conflict (ie. with a mod). - this.FadeColour(new Color4(195, 195, 195, 255)); - using (BeginDelayedSequence(InitialLifetimeOffset - OsuHitWindows.MISS_WINDOW)) - this.FadeColour(Color4.White, 100); + // Dim should only be applied at a top level, as it will be implicitly applied to nested objects. + if (ParentHitObject == null) + { + // Of note, no one noticed this was missing for years, but it definitely feels like it should still exist. + // For now this is applied across all skins, and matches stable. + // For simplicity, dim colour is applied to the DrawableHitObject itself. + // We may need to make a nested container setup if this even causes a usage conflict (ie. with a mod). + this.FadeColour(new Color4(195, 195, 195, 255)); + using (BeginDelayedSequence(InitialLifetimeOffset - OsuHitWindows.MISS_WINDOW)) + this.FadeColour(Color4.White, 100); + } } protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt; From 04abb2ce8f1723fbf342d7cb215eea0d20d221bb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 18:26:17 +0900 Subject: [PATCH 1464/2686] Update default cursor smoke implementation to use a texture --- osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs index c3bc04a858..1b7a39aa30 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs @@ -1,13 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Framework.Graphics.Textures; + namespace osu.Game.Rulesets.Osu.Skinning.Default { public class DefaultSmoke : Smoke { - public DefaultSmoke() + [BackgroundDependencyLoader] + private void load(TextureStore textures) { - Radius = 2; + // ISkinSource doesn't currently fallback to global textures. + // We might want to change this in the future if the intention is to allow the user to skin this as per legacy skins. + Texture = textures.Get("Gameplay/osu/cursor-smoke"); } } } From 1e5ff2679b3ba6b00b6e858561f5707e85cdd56d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 18:27:51 +0900 Subject: [PATCH 1465/2686] Rename classes to better emphasise that `Smoke` is a single trail segment --- osu.Game.Rulesets.Osu/OsuSkinComponents.cs | 2 +- .../Default/{DefaultSmoke.cs => DefaultSmokeSegment.cs} | 2 +- .../Legacy/{LegacySmoke.cs => LegacySmokeSegment.cs} | 2 +- .../Skinning/Legacy/OsuLegacySkinTransformer.cs | 4 ++-- osu.Game.Rulesets.Osu/Skinning/{Smoke.cs => SmokeSegment.cs} | 4 ++-- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 5 ++++- 6 files changed, 11 insertions(+), 8 deletions(-) rename osu.Game.Rulesets.Osu/Skinning/Default/{DefaultSmoke.cs => DefaultSmokeSegment.cs} (92%) rename osu.Game.Rulesets.Osu/Skinning/Legacy/{LegacySmoke.cs => LegacySmokeSegment.cs} (90%) rename osu.Game.Rulesets.Osu/Skinning/{Smoke.cs => SmokeSegment.cs} (99%) diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs index 11daa26072..3ee30ff7dc 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu SliderBall, SliderBody, SpinnerBody, - Smoke, + SmokeTrail, ApproachCircle, } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmokeSegment.cs similarity index 92% rename from osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs rename to osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmokeSegment.cs index 1b7a39aa30..27a2dc3960 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmokeSegment.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class DefaultSmoke : Smoke + public class DefaultSmokeSegment : SmokeSegment { [BackgroundDependencyLoader] private void load(TextureStore textures) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmokeSegment.cs similarity index 90% rename from osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs rename to osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmokeSegment.cs index 89e90cd4c8..c9c7e86e86 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmokeSegment.cs @@ -6,7 +6,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacySmoke : Smoke + public class LegacySmokeSegment : SmokeSegment { [BackgroundDependencyLoader] private void load(ISkinSource skin) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index d44d2b031a..4d12b85770 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -106,9 +106,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return null; - case OsuSkinComponents.Smoke: + case OsuSkinComponents.SmokeTrail: if (GetTexture("cursor-smoke") != null) - return new LegacySmoke(); + return new LegacySmokeSegment(); return null; diff --git a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs similarity index 99% rename from osu.Game.Rulesets.Osu/Skinning/Smoke.cs rename to osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 5d2aa2b1f6..948ec972a3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Smoke.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning { - public abstract class Smoke : Drawable, ITexturedShaderDrawable + public abstract class SmokeSegment : Drawable, ITexturedShaderDrawable { public IShader? TextureShader { get; private set; } public IShader? RoundedTextureShader { get; private set; } @@ -214,7 +214,7 @@ namespace osu.Game.Rulesets.Osu.Skinning protected class SmokeDrawNode : TexturedShaderDrawNode { - protected new Smoke Source => (Smoke)base.Source; + protected new SmokeSegment Source => (SmokeSegment)base.Source; protected double SmokeStartTime { get; private set; } protected double SmokeEndTime { get; private set; } diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index 4984dc1ad1..d26d45c3d7 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -14,6 +14,9 @@ using osuTK; namespace osu.Game.Rulesets.Osu.UI { + /// + /// Manages smoke trails generated from user input. + /// [Cached] public class SmokeContainer : Container, IRequireHighFrequencyMousePosition, IKeyBindingHandler { @@ -31,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.UI if (e.Action == OsuAction.Smoke) { isSmoking = true; - AddInternal(new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Smoke), _ => new DefaultSmoke())); + AddInternal(new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SmokeTrail), _ => new DefaultSmokeSegment())); return true; } From 6628ab5190409e93dd4fb46f57ac0877c1d27905 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 18:37:09 +0900 Subject: [PATCH 1466/2686] Refactor to avoid DI / event flow There's always one active smoke segment and it's the direct child of `SmokeContainer`. This can be simplified as such. --- .../Skinning/SmokeSegment.cs | 36 +++---------------- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 25 ++++++------- 2 files changed, 14 insertions(+), 47 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 948ec972a3..245026dc0b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; -using osu.Game.Rulesets.Osu.UI; using osuTK; using osuTK.Graphics; @@ -54,7 +53,6 @@ namespace osu.Game.Rulesets.Osu.Skinning private float totalDistance; private Vector2? lastPosition; - private SmokeContainer? smokeContainer; private const int max_point_count = 18_000; @@ -84,9 +82,8 @@ namespace osu.Game.Rulesets.Osu.Skinning private const float max_rotation = 0.25f; [BackgroundDependencyLoader] - private void load(SmokeContainer container, ShaderManager shaders) + private void load(ShaderManager shaders) { - smokeContainer = container; RoundedTextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE); } @@ -100,14 +97,6 @@ namespace osu.Game.Rulesets.Osu.Skinning SmokeStartTime = Time.Current; totalDistance = PointInterval; - - if (smokeContainer != null) - { - smokeContainer.SmokeMoved += onSmokeMoved; - smokeContainer.SmokeEnded += onSmokeEnded; - - onSmokeMoved(smokeContainer.LastMousePosition, Time.Current); - } } private Vector2 nextPointDirection() @@ -116,7 +105,7 @@ namespace osu.Game.Rulesets.Osu.Skinning return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); } - private void onSmokeMoved(Vector2 position, double time) + public void AddPosition(Vector2 position, double time) { lastPosition ??= position; @@ -158,17 +147,11 @@ namespace osu.Game.Rulesets.Osu.Skinning lastPosition = position; if (SmokePoints.Count >= max_point_count) - onSmokeEnded(time); + FinishDrawing(time); } - private void onSmokeEnded(double time) + public void FinishDrawing(double time) { - if (smokeContainer != null) - { - smokeContainer.SmokeMoved -= onSmokeMoved; - smokeContainer.SmokeEnded -= onSmokeEnded; - } - SmokeEndTime = time; } @@ -181,17 +164,6 @@ namespace osu.Game.Rulesets.Osu.Skinning Invalidate(Invalidation.DrawNode); } - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (smokeContainer != null) - { - smokeContainer.SmokeMoved -= onSmokeMoved; - smokeContainer.SmokeEnded -= onSmokeEnded; - } - } - protected struct SmokePoint { public Vector2 Position; diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index d26d45c3d7..c00493e087 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -1,13 +1,12 @@ // 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.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Game.Rulesets.Osu.Skinning; using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osuTK; @@ -17,15 +16,11 @@ namespace osu.Game.Rulesets.Osu.UI /// /// Manages smoke trails generated from user input. /// - [Cached] public class SmokeContainer : Container, IRequireHighFrequencyMousePosition, IKeyBindingHandler { - public event Action? SmokeMoved; - public event Action? SmokeEnded; - public Vector2 LastMousePosition; - private bool isSmoking; + private SkinnableDrawable? currentSegment; public override bool ReceivePositionalInputAt(Vector2 _) => true; @@ -33,21 +28,22 @@ namespace osu.Game.Rulesets.Osu.UI { if (e.Action == OsuAction.Smoke) { - isSmoking = true; - AddInternal(new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SmokeTrail), _ => new DefaultSmokeSegment())); - + AddInternal(currentSegment = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SmokeTrail), _ => new DefaultSmokeSegment())); + addPosition(LastMousePosition, Time.Current); return true; } return false; } + private void addPosition(Vector2 position, double timeCurrent) => (currentSegment?.Drawable as SmokeSegment)?.AddPosition(position, timeCurrent); + public void OnReleased(KeyBindingReleaseEvent e) { if (e.Action == OsuAction.Smoke) { - isSmoking = false; - SmokeEnded?.Invoke(Time.Current); + (currentSegment?.Drawable as SmokeSegment)?.FinishDrawing(Time.Current); + currentSegment = null; foreach (Drawable child in Children) { @@ -59,11 +55,10 @@ namespace osu.Game.Rulesets.Osu.UI protected override bool OnMouseMove(MouseMoveEvent e) { - if (isSmoking) - SmokeMoved?.Invoke(e.MousePosition, Time.Current); + if (currentSegment != null) + addPosition(e.MousePosition, Time.Current); LastMousePosition = e.MousePosition; - return base.OnMouseMove(e); } } From 71edd314b1785106be7b55c3ed638c6571d70521 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 18:51:02 +0900 Subject: [PATCH 1467/2686] Simplify `SmokeContainer` lifetime logic --- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 31 +++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index c00493e087..5999abc1bf 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -1,7 +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.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; @@ -18,9 +17,9 @@ namespace osu.Game.Rulesets.Osu.UI /// public class SmokeContainer : Container, IRequireHighFrequencyMousePosition, IKeyBindingHandler { - public Vector2 LastMousePosition; + private SkinnableDrawable? currentSegmentSkinnable; - private SkinnableDrawable? currentSegment; + private Vector2 lastMousePosition; public override bool ReceivePositionalInputAt(Vector2 _) => true; @@ -28,38 +27,38 @@ namespace osu.Game.Rulesets.Osu.UI { if (e.Action == OsuAction.Smoke) { - AddInternal(currentSegment = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SmokeTrail), _ => new DefaultSmokeSegment())); - addPosition(LastMousePosition, Time.Current); + AddInternal(currentSegmentSkinnable = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SmokeTrail), _ => new DefaultSmokeSegment())); + + // Add initial position immediately. + addPosition(); return true; } return false; } - private void addPosition(Vector2 position, double timeCurrent) => (currentSegment?.Drawable as SmokeSegment)?.AddPosition(position, timeCurrent); - public void OnReleased(KeyBindingReleaseEvent e) { if (e.Action == OsuAction.Smoke) { - (currentSegment?.Drawable as SmokeSegment)?.FinishDrawing(Time.Current); - currentSegment = null; - - foreach (Drawable child in Children) + if (currentSegmentSkinnable?.Drawable is SmokeSegment segment) { - var skinnable = (SkinnableDrawable)child; - skinnable.LifetimeEnd = skinnable.Drawable.LifetimeEnd; + segment.FinishDrawing(Time.Current); + + currentSegmentSkinnable.LifetimeEnd = segment.LifetimeEnd; + currentSegmentSkinnable = null; } } } protected override bool OnMouseMove(MouseMoveEvent e) { - if (currentSegment != null) - addPosition(e.MousePosition, Time.Current); + lastMousePosition = e.MousePosition; + addPosition(); - LastMousePosition = e.MousePosition; return base.OnMouseMove(e); } + + private void addPosition() => (currentSegmentSkinnable?.Drawable as SmokeSegment)?.AddPosition(lastMousePosition, Time.Current); } } From 91d877e8931da7e4d738a57189dbb5a1e4b60902 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 18:52:01 +0900 Subject: [PATCH 1468/2686] Set `LifetimeEnd` once rather than computing on every access --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 245026dc0b..18e0bc5baa 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -24,15 +24,6 @@ namespace osu.Game.Rulesets.Osu.Skinning public IShader? TextureShader { get; private set; } public IShader? RoundedTextureShader { get; private set; } - public override double LifetimeEnd - { - get - { - double initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); - return SmokeEndTime + final_fade_out_duration + initialFadeOutDurationTrunc / re_fade_in_speed + initialFadeOutDurationTrunc / final_fade_out_speed; - } - } - private float? radius; protected float Radius @@ -153,6 +144,9 @@ namespace osu.Game.Rulesets.Osu.Skinning public void FinishDrawing(double time) { SmokeEndTime = time; + + double initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); + LifetimeEnd = SmokeEndTime + final_fade_out_duration + initialFadeOutDurationTrunc / re_fade_in_speed + initialFadeOutDurationTrunc / final_fade_out_speed; } protected override DrawNode CreateDrawNode() => new SmokeDrawNode(this); From bd82dfc333cce808d06df5001c9e28ba387c589d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 18:53:07 +0900 Subject: [PATCH 1469/2686] Remove custom radius implementation --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 18e0bc5baa..09cbc1af1d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -24,13 +24,7 @@ namespace osu.Game.Rulesets.Osu.Skinning public IShader? TextureShader { get; private set; } public IShader? RoundedTextureShader { get; private set; } - private float? radius; - - protected float Radius - { - get => radius ?? Texture?.DisplayWidth * 0.165f ?? 3; - set => radius = value; - } + protected float Radius => Texture?.DisplayWidth * 0.165f ?? 3; protected Texture? Texture { get; set; } From 8f0ef99e10670d92855848f0318ca1b98eee8db1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 18:54:14 +0900 Subject: [PATCH 1470/2686] Privatise some fields --- .../Skinning/SmokeSegment.cs | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 09cbc1af1d..99196f6967 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -21,24 +21,6 @@ namespace osu.Game.Rulesets.Osu.Skinning { public abstract class SmokeSegment : Drawable, ITexturedShaderDrawable { - public IShader? TextureShader { get; private set; } - public IShader? RoundedTextureShader { get; private set; } - - protected float Radius => Texture?.DisplayWidth * 0.165f ?? 3; - - protected Texture? Texture { get; set; } - - protected double SmokeStartTime { get; private set; } = double.MinValue; - - protected double SmokeEndTime { get; private set; } = double.MaxValue; - - protected readonly List SmokePoints = new List(); - - protected virtual float PointInterval => Radius * 7f / 8; - - private float totalDistance; - private Vector2? lastPosition; - private const int max_point_count = 18_000; // fade anim values @@ -66,6 +48,24 @@ namespace osu.Game.Rulesets.Osu.Skinning private const float max_rotation = 0.25f; + public IShader? TextureShader { get; private set; } + public IShader? RoundedTextureShader { get; private set; } + + protected Texture? Texture { get; set; } + + private float radius => Texture?.DisplayWidth * 0.165f ?? 3; + + protected readonly List SmokePoints = new List(); + + private float pointInterval => radius * 7f / 8; + + private double smokeStartTime { get; set; } = double.MinValue; + + private double smokeEndTime { get; set; } = double.MaxValue; + + private float totalDistance; + private Vector2? lastPosition; + [BackgroundDependencyLoader] private void load(ShaderManager shaders) { @@ -79,9 +79,9 @@ namespace osu.Game.Rulesets.Osu.Skinning RelativeSizeAxes = Axes.Both; - SmokeStartTime = Time.Current; + smokeStartTime = Time.Current; - totalDistance = PointInterval; + totalDistance = pointInterval; } private Vector2 nextPointDirection() @@ -96,15 +96,15 @@ namespace osu.Game.Rulesets.Osu.Skinning float delta = (position - (Vector2)lastPosition).LengthFast; totalDistance += delta; - int count = (int)(totalDistance / PointInterval); + int count = (int)(totalDistance / pointInterval); if (count > 0) { Vector2 increment = position - (Vector2)lastPosition; increment.NormalizeFast(); - Vector2 pointPos = (PointInterval - (totalDistance - delta)) * increment + (Vector2)lastPosition; - increment *= PointInterval; + Vector2 pointPos = (pointInterval - (totalDistance - delta)) * increment + (Vector2)lastPosition; + increment *= pointInterval; if (SmokePoints.Count > 0 && SmokePoints[^1].Time > time) { @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Osu.Skinning SmokePoints.RemoveRange(index, SmokePoints.Count - index); } - totalDistance %= PointInterval; + totalDistance %= pointInterval; for (int i = 0; i < count; i++) { @@ -137,10 +137,10 @@ namespace osu.Game.Rulesets.Osu.Skinning public void FinishDrawing(double time) { - SmokeEndTime = time; + smokeEndTime = time; - double initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); - LifetimeEnd = SmokeEndTime + final_fade_out_duration + initialFadeOutDurationTrunc / re_fade_in_speed + initialFadeOutDurationTrunc / final_fade_out_speed; + double initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, smokeEndTime - smokeStartTime); + LifetimeEnd = smokeEndTime + final_fade_out_duration + initialFadeOutDurationTrunc / re_fade_in_speed + initialFadeOutDurationTrunc / final_fade_out_speed; } protected override DrawNode CreateDrawNode() => new SmokeDrawNode(this); @@ -208,12 +208,12 @@ namespace osu.Game.Rulesets.Osu.Skinning points.Clear(); points.AddRange(Source.SmokePoints); - radius = Source.Radius; + radius = Source.radius; drawSize = Source.DrawSize; texture = Source.Texture; - SmokeStartTime = Source.SmokeStartTime; - SmokeEndTime = Source.SmokeEndTime; + SmokeStartTime = Source.smokeStartTime; + SmokeEndTime = Source.smokeEndTime; CurrentTime = Source.Clock.CurrentTime; rotationRNG = new Random(Source.rotationSeed); From 64858cfb8e2dabab010f9fab666cf1cf5b0ed9f8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 18:55:49 +0900 Subject: [PATCH 1471/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index fd57862c4d..8f83c9730b 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9cc4f3fbab..434db87a80 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index cc922d304f..f395eab23c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + From 234c6ac7998fbc6742503e1a589536255554e56a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 5 Oct 2022 20:21:15 +0900 Subject: [PATCH 1472/2686] Pin taiko PP calculator accuracy to osu-stable values --- .../Difficulty/TaikoPerformanceCalculator.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 95a1e8bc66..dc7bad2f75 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private int countOk; private int countMeh; private int countMiss; + private double accuracy; private double effectiveMissCount; @@ -36,6 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countOk = score.Statistics.GetValueOrDefault(HitResult.Ok); countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); + accuracy = customAccuracy; // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000. if (totalSuccessfulHits > 0) @@ -87,7 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModFlashlight)) difficultyValue *= 1.050 * lengthBonus; - return difficultyValue * Math.Pow(score.Accuracy, 2.0); + return difficultyValue * Math.Pow(accuracy, 2.0); } private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes) @@ -95,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (attributes.GreatHitWindow <= 0) return 0; - double accuracyValue = Math.Pow(60.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 8.0) * Math.Pow(attributes.StarRating, 0.4) * 27.0; + double accuracyValue = Math.Pow(60.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(accuracy, 8.0) * Math.Pow(attributes.StarRating, 0.4) * 27.0; double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); accuracyValue *= lengthBonus; @@ -110,5 +112,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private int totalHits => countGreat + countOk + countMeh + countMiss; private int totalSuccessfulHits => countGreat + countOk + countMeh; + + private double customAccuracy => totalHits > 0 ? (countGreat * 300 + countOk * 150) / (totalHits * 300.0) : 0; } } From 8d29e9e76bc781d8814e70a7a1f0317cfe7a2920 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 5 Oct 2022 20:23:59 +0900 Subject: [PATCH 1473/2686] Move selection logic from DragBox to BlueprintContainer --- .../Compose/Components/BlueprintContainer.cs | 49 +++++++------------ .../Edit/Compose/Components/DragBox.cs | 46 +++-------------- .../Timeline/TimelineBlueprintContainer.cs | 12 +++-- .../Components/Timeline/TimelineDragBox.cs | 16 +----- 4 files changed, 34 insertions(+), 89 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 8b38d9c612..787959d214 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; @@ -13,11 +12,9 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Primitives; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osuTK; using osuTK.Input; @@ -79,7 +76,7 @@ namespace osu.Game.Screens.Edit.Compose.Components AddRangeInternal(new[] { - DragBox = CreateDragBox(selectBlueprintsFromDragRectangle), + DragBox = CreateDragBox(), SelectionHandler, SelectionBlueprints = CreateSelectionBlueprintContainer(), SelectionHandler.CreateProxy(), @@ -101,7 +98,7 @@ namespace osu.Game.Screens.Edit.Compose.Components [CanBeNull] protected virtual SelectionBlueprint CreateBlueprintFor(T item) => null; - protected virtual DragBox CreateDragBox(Action performSelect) => new DragBox(performSelect); + protected virtual DragBox CreateDragBox() => new DragBox(); /// /// Whether this component is in a state where items outside a drag selection should be deselected. If false, selection will only be added to. @@ -183,13 +180,9 @@ namespace osu.Game.Screens.Edit.Compose.Components return true; } - if (DragBox.HandleDrag(e)) - { - DragBox.Show(); - return true; - } - - return false; + DragBox.HandleDrag(e); + DragBox.Show(); + return true; } protected override void OnDrag(DragEvent e) @@ -198,7 +191,10 @@ namespace osu.Game.Screens.Edit.Compose.Components return; if (DragBox.State == Visibility.Visible) + { DragBox.HandleDrag(e); + UpdateSelectionFromDragBox(); + } moveCurrentSelection(e); } @@ -214,8 +210,7 @@ namespace osu.Game.Screens.Edit.Compose.Components changeHandler?.EndChange(); } - if (DragBox.State == Visibility.Visible) - DragBox.Hide(); + DragBox.Hide(); } /// @@ -380,28 +375,20 @@ namespace osu.Game.Screens.Edit.Compose.Components } /// - /// Select all masks in a given rectangle selection area. + /// Select all blueprints in a selection area specified by . /// - /// The rectangle to perform a selection on in screen-space coordinates. - private void selectBlueprintsFromDragRectangle(RectangleF rect) + protected virtual void UpdateSelectionFromDragBox() { + var quad = DragBox.Box.ScreenSpaceDrawQuad; + foreach (var blueprint in SelectionBlueprints) { - // only run when utmost necessary to avoid unnecessary rect computations. - bool isValidForSelection() => blueprint.IsAlive && blueprint.IsPresent && rect.Contains(blueprint.ScreenSpaceSelectionPoint); + if (blueprint.IsSelected && !AllowDeselectionDuringDrag) + continue; - switch (blueprint.State) - { - case SelectionState.NotSelected: - if (isValidForSelection()) - blueprint.Select(); - break; - - case SelectionState.Selected: - if (AllowDeselectionDuringDrag && !isValidForSelection()) - blueprint.Deselect(); - break; - } + bool shouldBeSelected = blueprint.IsAlive && blueprint.IsPresent && quad.Contains(blueprint.ScreenSpaceSelectionPoint); + if (blueprint.IsSelected != shouldBeSelected) + blueprint.ToggleSelection(); } } diff --git a/osu.Game/Screens/Edit/Compose/Components/DragBox.cs b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs index 838562719d..905d47533a 100644 --- a/osu.Game/Screens/Edit/Compose/Components/DragBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs @@ -8,7 +8,6 @@ using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Layout; @@ -21,18 +20,13 @@ namespace osu.Game.Screens.Edit.Compose.Components /// public class DragBox : CompositeDrawable, IStateful { - protected readonly Action PerformSelection; - - protected Drawable Box; + public Drawable Box { get; private set; } /// /// Creates a new . /// - /// A delegate that performs drag selection. - public DragBox(Action performSelection) + public DragBox() { - PerformSelection = performSelection; - RelativeSizeAxes = Axes.Both; AlwaysPresent = true; Alpha = 0; @@ -46,30 +40,14 @@ namespace osu.Game.Screens.Edit.Compose.Components protected virtual Drawable CreateBox() => new BoxWithBorders(); - private RectangleF? dragRectangle; - /// /// Handle a forwarded mouse event. /// /// The mouse event. - /// Whether the event should be handled and blocking. - public virtual bool HandleDrag(MouseButtonEvent e) + public virtual void HandleDrag(MouseButtonEvent e) { - var dragPosition = e.ScreenSpaceMousePosition; - var dragStartPosition = e.ScreenSpaceMouseDownPosition; - - var dragQuad = new Quad(dragStartPosition.X, dragStartPosition.Y, dragPosition.X - dragStartPosition.X, dragPosition.Y - dragStartPosition.Y); - - // We use AABBFloat instead of RectangleF since it handles negative sizes for us - var rec = dragQuad.AABBFloat; - dragRectangle = rec; - - var topLeft = ToLocalSpace(rec.TopLeft); - var bottomRight = ToLocalSpace(rec.BottomRight); - - Box.Position = topLeft; - Box.Size = bottomRight - topLeft; - return true; + Box.Position = Vector2.ComponentMin(e.MouseDownPosition, e.MousePosition); + Box.Size = Vector2.ComponentMax(e.MouseDownPosition, e.MousePosition) - Box.Position; } private Visibility state; @@ -87,19 +65,7 @@ namespace osu.Game.Screens.Edit.Compose.Components } } - protected override void Update() - { - base.Update(); - - if (dragRectangle != null) - PerformSelection?.Invoke(dragRectangle.Value); - } - - public override void Hide() - { - State = Visibility.Hidden; - dragRectangle = null; - } + public override void Hide() => State = Visibility.Hidden; public override void Show() => State = Visibility.Visible; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 590f92d281..da80ed5ad6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -13,7 +13,6 @@ using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Utils; @@ -65,7 +64,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline protected override void LoadComplete() { base.LoadComplete(); - DragBox.Alpha = 0; placement = Beatmap.PlacementObject.GetBoundCopy(); placement.ValueChanged += placementChanged; @@ -93,6 +91,14 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline protected override Container> CreateSelectionBlueprintContainer() => new TimelineSelectionBlueprintContainer { RelativeSizeAxes = Axes.Both }; + protected override bool OnDragStart(DragStartEvent e) + { + if (!base.ReceivePositionalInputAt(e.ScreenSpaceMouseDownPosition)) + return false; + + return base.OnDragStart(e); + } + protected override void OnDrag(DragEvent e) { handleScrollViaDrag(e); @@ -169,7 +175,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline }; } - protected override DragBox CreateDragBox(Action performSelect) => new TimelineDragBox(performSelect); + protected override DragBox CreateDragBox() => new TimelineDragBox(); private void handleScrollViaDrag(DragEvent e) { diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs index c026c169d6..8b901c8958 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs @@ -6,7 +6,6 @@ using System; using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Utils; @@ -24,24 +23,14 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline [Resolved] private Timeline timeline { get; set; } - public TimelineDragBox(Action performSelect) - : base(performSelect) - { - } - protected override Drawable CreateBox() => new Box { RelativeSizeAxes = Axes.Y, Alpha = 0.3f }; - public override bool HandleDrag(MouseButtonEvent e) + public override void HandleDrag(MouseButtonEvent e) { - // The dragbox should only be active if the mouseDownPosition.Y is within this drawable's bounds. - float localY = ToLocalSpace(e.ScreenSpaceMouseDownPosition).Y; - if (DrawRectangle.Top > localY || DrawRectangle.Bottom < localY) - return false; - selectionStart ??= e.MouseDownPosition.X / timeline.CurrentZoom; // only calculate end when a transition is not in progress to avoid bouncing. @@ -49,7 +38,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline selectionEnd = e.MousePosition.X / timeline.CurrentZoom; updateDragBoxPosition(); - return true; } private void updateDragBoxPosition() @@ -68,8 +56,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline // we don't care about where the hitobjects are vertically. in cases like stacking display, they may be outside the box without this adjustment. boxScreenRect.Y -= boxScreenRect.Height; boxScreenRect.Height *= 2; - - PerformSelection?.Invoke(boxScreenRect); } public override void Hide() From 0ffde02f79e8d67538e941e312abfa1611e5e712 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 5 Oct 2022 20:43:02 +0900 Subject: [PATCH 1474/2686] Use hit object time for timeline selection --- .../Compose/Components/Timeline/Timeline.cs | 18 ++++++-- .../Timeline/TimelineBlueprintContainer.cs | 24 ++++++++++- .../Components/Timeline/TimelineDragBox.cs | 42 ++++++------------- 3 files changed, 49 insertions(+), 35 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 721f0c4e3b..a73ada76f5 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -304,10 +304,20 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline /// public double VisibleRange => editorClock.TrackLength / Zoom; - public SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition, SnapType snapType = SnapType.All) => - new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(screenSpacePosition)))); + public double TimeAtPosition(float x) + { + return x / Content.DrawWidth * editorClock.TrackLength; + } - private double getTimeFromPosition(Vector2 localPosition) => - (localPosition.X / Content.DrawWidth) * editorClock.TrackLength; + public float PositionAtTime(double time) + { + return (float)(time / editorClock.TrackLength * Content.DrawWidth); + } + + public SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition, SnapType snapType = SnapType.All) + { + double time = TimeAtPosition(Content.ToLocalSpace(screenSpacePosition).X); + return new SnapResult(screenSpacePosition, beatSnapProvider.SnapTime(time)); + } } } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index da80ed5ad6..05897e6d97 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -175,7 +175,29 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline }; } - protected override DragBox CreateDragBox() => new TimelineDragBox(); + protected sealed override DragBox CreateDragBox() => new TimelineDragBox(); + + protected override void UpdateSelectionFromDragBox() + { + var dragBox = (TimelineDragBox)DragBox; + double minTime = dragBox.MinTime; + double maxTime = dragBox.MaxTime; + Console.WriteLine($"{minTime}, {maxTime}"); + + // TODO: performance + foreach (var hitObject in Beatmap.HitObjects) + { + bool shouldBeSelected = minTime <= hitObject.StartTime && hitObject.StartTime <= maxTime; + bool isSelected = SelectedItems.Contains(hitObject); + if (isSelected != shouldBeSelected) + { + if (!isSelected) + SelectedItems.Add(hitObject); + else + SelectedItems.Remove(hitObject); + } + } + } private void handleScrollViaDrag(DragEvent e) { diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs index 8b901c8958..4b16848c58 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs @@ -14,11 +14,13 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class TimelineDragBox : DragBox { - // the following values hold the start and end X positions of the drag box in the timeline's local space, - // but with zoom unapplied in order to be able to compensate for positional changes - // while the timeline is being zoomed in/out. - private float? selectionStart; - private float selectionEnd; + public double MinTime => Math.Min(startTime.Value, endTime); + + public double MaxTime => Math.Max(startTime.Value, endTime); + + private double? startTime; + + private double endTime; [Resolved] private Timeline timeline { get; set; } @@ -31,37 +33,17 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public override void HandleDrag(MouseButtonEvent e) { - selectionStart ??= e.MouseDownPosition.X / timeline.CurrentZoom; + startTime ??= timeline.TimeAtPosition(e.MouseDownPosition.X); + endTime = timeline.TimeAtPosition(e.MousePosition.X); - // only calculate end when a transition is not in progress to avoid bouncing. - if (Precision.AlmostEquals(timeline.CurrentZoom, timeline.Zoom)) - selectionEnd = e.MousePosition.X / timeline.CurrentZoom; - - updateDragBoxPosition(); - } - - private void updateDragBoxPosition() - { - if (selectionStart == null) - return; - - float rescaledStart = selectionStart.Value * timeline.CurrentZoom; - float rescaledEnd = selectionEnd * timeline.CurrentZoom; - - Box.X = Math.Min(rescaledStart, rescaledEnd); - Box.Width = Math.Abs(rescaledStart - rescaledEnd); - - var boxScreenRect = Box.ScreenSpaceDrawQuad.AABBFloat; - - // we don't care about where the hitobjects are vertically. in cases like stacking display, they may be outside the box without this adjustment. - boxScreenRect.Y -= boxScreenRect.Height; - boxScreenRect.Height *= 2; + Box.X = timeline.PositionAtTime(MinTime); + Box.Width = timeline.PositionAtTime(MaxTime) - Box.X; } public override void Hide() { base.Hide(); - selectionStart = null; + startTime = null; } } } From 0613388aaa8bb5ae656d1237816e898c5f59b855 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 5 Oct 2022 20:48:35 +0900 Subject: [PATCH 1475/2686] Make sure all selected items get deleted --- osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs | 2 +- osu.Game/Screens/Edit/EditorBeatmap.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 8419d3b380..269c19f846 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -305,7 +305,7 @@ namespace osu.Game.Screens.Edit.Compose.Components protected void DeleteSelected() { - DeleteItems(selectedBlueprints.Select(b => b.Item)); + DeleteItems(SelectedItems.ToArray()); } #endregion diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 16c0064e80..839535b99f 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -352,6 +352,8 @@ namespace osu.Game.Screens.Edit var updates = batchPendingUpdates.ToArray(); batchPendingUpdates.Clear(); + foreach (var h in deletes) SelectedHitObjects.Remove(h); + foreach (var h in deletes) HitObjectRemoved?.Invoke(h); foreach (var h in inserts) HitObjectAdded?.Invoke(h); foreach (var h in updates) HitObjectUpdated?.Invoke(h); From 00b3d97f69abaaed8a29cca1770aca91966e6fc6 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 5 Oct 2022 21:26:00 +0900 Subject: [PATCH 1476/2686] Improve timeline selection performance But selecting a large number of hit objects is still very slow because all DHOs must be added and also `AddBlueprintFor` has quadratic behaviors --- .../Compose/Components/BlueprintContainer.cs | 10 ++++++++-- .../Timeline/TimelineBlueprintContainer.cs | 18 ++++-------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 787959d214..da7a8e662b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -58,13 +58,19 @@ namespace osu.Game.Screens.Edit.Compose.Components { case NotifyCollectionChangedAction.Add: foreach (object o in args.NewItems) - SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Select(); + { + if (blueprintMap.TryGetValue((T)o, out var blueprint)) + blueprint.Select(); + } break; case NotifyCollectionChangedAction.Remove: foreach (object o in args.OldItems) - SelectionBlueprints.FirstOrDefault(b => b.Item == o)?.Deselect(); + { + if (blueprintMap.TryGetValue((T)o, out var blueprint)) + blueprint.Deselect(); + } break; } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 05897e6d97..2d6dc797ca 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -182,21 +182,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline var dragBox = (TimelineDragBox)DragBox; double minTime = dragBox.MinTime; double maxTime = dragBox.MaxTime; - Console.WriteLine($"{minTime}, {maxTime}"); - // TODO: performance - foreach (var hitObject in Beatmap.HitObjects) - { - bool shouldBeSelected = minTime <= hitObject.StartTime && hitObject.StartTime <= maxTime; - bool isSelected = SelectedItems.Contains(hitObject); - if (isSelected != shouldBeSelected) - { - if (!isSelected) - SelectedItems.Add(hitObject); - else - SelectedItems.Remove(hitObject); - } - } + SelectedItems.RemoveAll(hitObject => !shouldBeSelected(hitObject)); + SelectedItems.AddRange(Beatmap.HitObjects.Except(SelectedItems).Where(hitObject => shouldBeSelected(hitObject))); + + bool shouldBeSelected(HitObject hitObject) => minTime <= hitObject.StartTime && hitObject.StartTime <= maxTime; } private void handleScrollViaDrag(DragEvent e) From 3108c42ecea1e08ac5a66e98ab7f798c42757fd6 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 5 Oct 2022 22:04:43 +0900 Subject: [PATCH 1477/2686] Fix inspect issues --- .../Timeline/TimelineBlueprintContainer.cs | 3 +-- .../Compose/Components/Timeline/TimelineDragBox.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 2d6dc797ca..04575e55b1 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; @@ -184,7 +183,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline double maxTime = dragBox.MaxTime; SelectedItems.RemoveAll(hitObject => !shouldBeSelected(hitObject)); - SelectedItems.AddRange(Beatmap.HitObjects.Except(SelectedItems).Where(hitObject => shouldBeSelected(hitObject))); + SelectedItems.AddRange(Beatmap.HitObjects.Except(SelectedItems).Where(shouldBeSelected)); bool shouldBeSelected(HitObject hitObject) => minTime <= hitObject.StartTime && hitObject.StartTime <= maxTime; } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs index 4b16848c58..65d9293b7e 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs @@ -8,20 +8,17 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; -using osu.Framework.Utils; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { public class TimelineDragBox : DragBox { - public double MinTime => Math.Min(startTime.Value, endTime); + public double MinTime { get; private set; } - public double MaxTime => Math.Max(startTime.Value, endTime); + public double MaxTime { get; private set; } private double? startTime; - private double endTime; - [Resolved] private Timeline timeline { get; set; } @@ -34,7 +31,10 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public override void HandleDrag(MouseButtonEvent e) { startTime ??= timeline.TimeAtPosition(e.MouseDownPosition.X); - endTime = timeline.TimeAtPosition(e.MousePosition.X); + double endTime = timeline.TimeAtPosition(e.MousePosition.X); + + MinTime = Math.Min(startTime.Value, endTime); + MaxTime = Math.Max(startTime.Value, endTime); Box.X = timeline.PositionAtTime(MinTime); Box.Width = timeline.PositionAtTime(MaxTime) - Box.X; From 6753f6b01ab353baaa6575400d074292e2831705 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 5 Oct 2022 22:14:11 +0900 Subject: [PATCH 1478/2686] Move `AllowDeselectionDuringDrag` down Because it is now ignored in the timeline implementation anyways --- .../Edit/Compose/Components/ComposeBlueprintContainer.cs | 2 ++ .../Screens/Edit/Compose/Components/EditorBlueprintContainer.cs | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 4c37d200bc..43ead88d54 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -83,6 +83,8 @@ namespace osu.Game.Screens.Edit.Compose.Components } } + protected override bool AllowDeselectionDuringDrag => !EditorClock.IsRunning; + protected override void TransferBlueprintFor(HitObject hitObject, DrawableHitObject drawableObject) { base.TransferBlueprintFor(hitObject, drawableObject); diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs index 6a4fe27f04..879ac58887 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs @@ -66,8 +66,6 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override IEnumerable> SortForMovement(IReadOnlyList> blueprints) => blueprints.OrderBy(b => b.Item.StartTime); - protected override bool AllowDeselectionDuringDrag => !EditorClock.IsRunning; - protected override bool ApplySnapResult(SelectionBlueprint[] blueprints, SnapResult result) { if (!base.ApplySnapResult(blueprints, result)) From b0213c29e98b3b59efdb16c3ff6457c592f5385b Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 5 Oct 2022 22:19:22 +0900 Subject: [PATCH 1479/2686] Use mid time instead of start time It is closer to the old blueprint-based behavior --- .../Components/Timeline/TimelineBlueprintContainer.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 04575e55b1..08682ae05f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -185,7 +185,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline SelectedItems.RemoveAll(hitObject => !shouldBeSelected(hitObject)); SelectedItems.AddRange(Beatmap.HitObjects.Except(SelectedItems).Where(shouldBeSelected)); - bool shouldBeSelected(HitObject hitObject) => minTime <= hitObject.StartTime && hitObject.StartTime <= maxTime; + bool shouldBeSelected(HitObject hitObject) + { + double midTime = (hitObject.StartTime + hitObject.GetEndTime()) / 2; + return minTime <= midTime && midTime <= maxTime; + } } private void handleScrollViaDrag(DragEvent e) From 2a7476cc4a820015898ac9104bacde3e0dc8e10d Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 5 Oct 2022 23:29:45 +0900 Subject: [PATCH 1480/2686] Add test for timeline drag selection --- .../Editing/TestSceneTimelineSelection.cs | 63 +++++++++++++++++-- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs index 7e0981ce69..a4f4c375bf 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs @@ -29,16 +29,18 @@ namespace osu.Game.Tests.Visual.Editing private TimelineBlueprintContainer blueprintContainer => Editor.ChildrenOfType().First(); + private Vector2 getPosition(HitObject hitObject) => + blueprintContainer.SelectionBlueprints.First(s => s.Item == hitObject).ScreenSpaceDrawQuad.Centre; + + private Vector2 getMiddlePosition(HitObject hitObject1, HitObject hitObject2) => + (getPosition(hitObject1) + getPosition(hitObject2)) / 2; + private void moveMouseToObject(Func targetFunc) { AddStep("move mouse to object", () => { - var pos = blueprintContainer.SelectionBlueprints - .First(s => s.Item == targetFunc()) - .ChildrenOfType() - .First().ScreenSpaceDrawQuad.Centre; - - InputManager.MoveMouseTo(pos); + var hitObject = targetFunc(); + InputManager.MoveMouseTo(getPosition(hitObject)); }); } @@ -262,6 +264,55 @@ namespace osu.Game.Tests.Visual.Editing AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft)); } + [Test] + public void TestBasicDragSelection() + { + var addedObjects = new[] + { + new HitCircle { StartTime = 0 }, + new HitCircle { StartTime = 500, Position = new Vector2(100) }, + new HitCircle { StartTime = 1000, Position = new Vector2(200) }, + new HitCircle { StartTime = 1500, Position = new Vector2(300) }, + }; + AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects)); + + AddStep("move mouse", () => InputManager.MoveMouseTo(getMiddlePosition(addedObjects[0], addedObjects[1]))); + AddStep("mouse down", () => InputManager.PressButton(MouseButton.Left)); + + AddStep("drag to select", () => InputManager.MoveMouseTo(getMiddlePosition(addedObjects[2], addedObjects[3]))); + assertSelectionIs(new[] { addedObjects[1], addedObjects[2] }); + + AddStep("drag to deselect", () => InputManager.MoveMouseTo(getMiddlePosition(addedObjects[1], addedObjects[2]))); + assertSelectionIs(new[] { addedObjects[1] }); + + AddStep("mouse up", () => InputManager.ReleaseButton(MouseButton.Left)); + assertSelectionIs(new[] { addedObjects[1] }); + } + + [Test] + public void TestFastDragSelection() + { + var addedObjects = new[] + { + new HitCircle { StartTime = 0 }, + new HitCircle { StartTime = 500 }, + new HitCircle { StartTime = 20000, Position = new Vector2(100) }, + new HitCircle { StartTime = 31000, Position = new Vector2(200) }, + new HitCircle { StartTime = 60000, Position = new Vector2(300) }, + }; + + AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects)); + + AddStep("move mouse", () => InputManager.MoveMouseTo(getMiddlePosition(addedObjects[0], addedObjects[1]))); + AddStep("mouse down", () => InputManager.PressButton(MouseButton.Left)); + AddStep("start drag", () => InputManager.MoveMouseTo(getPosition(addedObjects[1]))); + + AddStep("jump editor clock", () => EditorClock.Seek(30000)); + AddStep("jump editor clock", () => EditorClock.Seek(60000)); + AddStep("end drag", () => InputManager.ReleaseButton(MouseButton.Left)); + assertSelectionIs(addedObjects.Skip(1)); + } + private void assertSelectionIs(IEnumerable hitObjects) => AddAssert("correct hitobjects selected", () => EditorBeatmap.SelectedHitObjects.OrderBy(h => h.StartTime).SequenceEqual(hitObjects)); } From 2c0cd9ea526137ac675457936abe8224f3bcc8fc Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Wed, 5 Oct 2022 19:09:34 -0700 Subject: [PATCH 1481/2686] Add more smoke tests --- osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs | 68 +++++++++++++++---- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs index 82417d09a7..1cb64b71fc 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Framework.Input.States; +using osu.Framework.Logging; using osu.Framework.Testing.Input; using osu.Game.Rulesets.Osu.UI; using osuTK; @@ -17,22 +19,57 @@ namespace osu.Game.Rulesets.Osu.Tests [Test] public void TestSmoking() { - AddStep("Create smoke", () => + addStep("Create short smoke", 2_000); + addStep("Create medium smoke", 5_000); + addStep("Create long smoke", 10_000); + } + + private void addStep(string stepName, double duration) + { + var smokeContainers = new List(); + + AddStep(stepName, () => { - SetContents(_ => new SmokingInputManager + smokeContainers.Clear(); + SetContents(_ => { - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.95f), - Child = new TestSmokeContainer { RelativeSizeAxes = Axes.Both }, + smokeContainers.Add(new TestSmokeContainer + { + Duration = duration, + RelativeSizeAxes = Axes.Both + }); + + return new SmokingInputManager + { + Duration = duration, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.95f), + Child = smokeContainers[^1], + }; }); }); + + AddUntilStep("Until skinnable expires", () => + { + if (smokeContainers.Count == 0) + return false; + + Logger.Log("How many: " + smokeContainers.Count); + + foreach (var smokeContainer in smokeContainers) + { + if (smokeContainer.Children.Count != 0) + return false; + } + + return true; + }); } - private const double spin_duration = 5_000; - private const float spin_angle = 4 * MathF.PI; - private class SmokingInputManager : ManualInputManager { + public double Duration { get; init; } + private double? startTime; public SmokingInputManager() @@ -51,9 +88,11 @@ namespace osu.Game.Rulesets.Osu.Tests { base.Update(); + const float spin_angle = 4 * MathF.PI; + startTime ??= Time.Current; - float fraction = (float)((Time.Current - startTime) / spin_duration); + float fraction = (float)((Time.Current - startTime) / Duration); float angle = fraction * spin_angle; float radius = fraction * Math.Min(DrawSize.X, DrawSize.Y) / 2; @@ -65,24 +104,27 @@ namespace osu.Game.Rulesets.Osu.Tests private class TestSmokeContainer : SmokeContainer { - private double? startTime; + public double Duration { get; init; } + private bool isPressing; private bool isFinished; + private double? startTime; + protected override void Update() { base.Update(); - startTime ??= Time.Current; + startTime ??= Time.Current + 0.1; - if (!isPressing && !isFinished && Time.Current > startTime + 0.1) + if (!isPressing && !isFinished && Time.Current > startTime) { OnPressed(new KeyBindingPressEvent(new InputState(), OsuAction.Smoke)); isPressing = true; isFinished = false; } - if (isPressing && Time.Current > startTime + spin_duration) + if (isPressing && Time.Current > startTime + Duration) { OnReleased(new KeyBindingReleaseEvent(new InputState(), OsuAction.Smoke)); isPressing = false; From 49e023f8613d44ab03e40fda8236e4bbb0d5e774 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Wed, 5 Oct 2022 19:11:38 -0700 Subject: [PATCH 1482/2686] Rename `OsuSkinComponents.SmokeTrail` to `CursorSmoke` --- osu.Game.Rulesets.Osu/OsuSkinComponents.cs | 2 +- .../Skinning/Legacy/OsuLegacySkinTransformer.cs | 2 +- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs index 3ee30ff7dc..4248cce55a 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu SliderBall, SliderBody, SpinnerBody, - SmokeTrail, + CursorSmoke, ApproachCircle, } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 4d12b85770..b778bc21d1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return null; - case OsuSkinComponents.SmokeTrail: + case OsuSkinComponents.CursorSmoke: if (GetTexture("cursor-smoke") != null) return new LegacySmokeSegment(); diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index 5999abc1bf..84596c6d72 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.UI { if (e.Action == OsuAction.Smoke) { - AddInternal(currentSegmentSkinnable = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SmokeTrail), _ => new DefaultSmokeSegment())); + AddInternal(currentSegmentSkinnable = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorSmoke), _ => new DefaultSmokeSegment())); // Add initial position immediately. addPosition(); From 9d54467145af496dab6d9f6a38517b4e1903ceaa Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Wed, 5 Oct 2022 19:13:06 -0700 Subject: [PATCH 1483/2686] Make smoke skinnable lifetime more robust --- .../Skinning/SmokeSegment.cs | 2 +- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 21 +++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 99196f6967..6c998e244c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Osu.Skinning RelativeSizeAxes = Axes.Both; - smokeStartTime = Time.Current; + LifetimeStart = smokeStartTime = Time.Current; totalDistance = pointInterval; } diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index 84596c6d72..beba834e88 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -1,6 +1,8 @@ // 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; using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; @@ -17,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.UI /// public class SmokeContainer : Container, IRequireHighFrequencyMousePosition, IKeyBindingHandler { - private SkinnableDrawable? currentSegmentSkinnable; + private SmokeSkinnableDrawable? currentSegmentSkinnable; private Vector2 lastMousePosition; @@ -27,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.UI { if (e.Action == OsuAction.Smoke) { - AddInternal(currentSegmentSkinnable = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorSmoke), _ => new DefaultSmokeSegment())); + AddInternal(currentSegmentSkinnable = new SmokeSkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorSmoke), _ => new DefaultSmokeSegment())); // Add initial position immediately. addPosition(); @@ -44,8 +46,6 @@ namespace osu.Game.Rulesets.Osu.UI if (currentSegmentSkinnable?.Drawable is SmokeSegment segment) { segment.FinishDrawing(Time.Current); - - currentSegmentSkinnable.LifetimeEnd = segment.LifetimeEnd; currentSegmentSkinnable = null; } } @@ -60,5 +60,18 @@ namespace osu.Game.Rulesets.Osu.UI } private void addPosition() => (currentSegmentSkinnable?.Drawable as SmokeSegment)?.AddPosition(lastMousePosition, Time.Current); + + private class SmokeSkinnableDrawable : SkinnableDrawable + { + public override bool RemoveWhenNotAlive => true; + + public override double LifetimeStart => Drawable.LifetimeStart; + public override double LifetimeEnd => Drawable.LifetimeEnd; + + public SmokeSkinnableDrawable(ISkinComponent component, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) + : base(component, defaultImplementation, confineMode) + { + } + } } } From 0d448e6cc898e181ab65f31280e3be15ee761f42 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 6 Oct 2022 13:50:56 +0900 Subject: [PATCH 1484/2686] Fix items without blueprints are not deselected --- .../Compose/Components/BlueprintContainer.cs | 18 +++++++----------- .../Components/EditorBlueprintContainer.cs | 4 ++-- .../Skinning/Editor/SkinBlueprintContainer.cs | 6 ++++++ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index da7a8e662b..8aecc75824 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Edit.Compose.Components }; SelectionHandler = CreateSelectionHandler(); - SelectionHandler.DeselectAll = deselectAll; + SelectionHandler.DeselectAll = DeselectAll; SelectionHandler.SelectedItems.BindTo(SelectedItems); AddRangeInternal(new[] @@ -145,7 +145,7 @@ namespace osu.Game.Screens.Edit.Compose.Components if (endClickSelection(e) || ClickedBlueprint != null) return true; - deselectAll(); + DeselectAll(); return true; } @@ -234,7 +234,7 @@ namespace osu.Game.Screens.Edit.Compose.Components if (!SelectionHandler.SelectedBlueprints.Any()) return false; - deselectAll(); + DeselectAll(); return true; } @@ -399,18 +399,14 @@ namespace osu.Game.Screens.Edit.Compose.Components } /// - /// Selects all s. + /// Select all currently-present items. /// - protected virtual void SelectAll() - { - // Scheduled to allow the change in lifetime to take place. - Schedule(() => SelectionBlueprints.ToList().ForEach(m => m.Select())); - } + protected abstract void SelectAll(); /// - /// Deselects all selected s. + /// Deselect all selected items. /// - private void deselectAll() => SelectionHandler.SelectedBlueprints.ToList().ForEach(m => m.Deselect()); + protected void DeselectAll() => SelectedItems.Clear(); protected virtual void OnBlueprintSelected(SelectionBlueprint blueprint) { diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs index 879ac58887..6682748253 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs @@ -131,8 +131,8 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override void SelectAll() { Composer.Playfield.KeepAllAlive(); - - base.SelectAll(); + SelectedItems.Clear(); + SelectedItems.AddRange(Beatmap.HitObjects); } protected override void OnBlueprintSelected(SelectionBlueprint blueprint) diff --git a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs index 5a1ef34151..97522ddff8 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs +++ b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs @@ -117,6 +117,12 @@ namespace osu.Game.Skinning.Editor return false; } + protected override void SelectAll() + { + SelectedItems.Clear(); + SelectedItems.AddRange(targetComponents.SelectMany(list => list)); + } + /// /// Move the current selection spatially by the specified delta, in screen coordinates (ie. the same coordinates as the blueprints). /// From 29cc55463268c40b688d1125ea7b69886c046135 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 6 Oct 2022 13:59:54 +0900 Subject: [PATCH 1485/2686] Ensure blueprint is added for selected hit object --- .../Components/Timeline/TimelineBlueprintContainer.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 08682ae05f..31990bfd35 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -183,7 +183,12 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline double maxTime = dragBox.MaxTime; SelectedItems.RemoveAll(hitObject => !shouldBeSelected(hitObject)); - SelectedItems.AddRange(Beatmap.HitObjects.Except(SelectedItems).Where(shouldBeSelected)); + + foreach (var hitObject in Beatmap.HitObjects.Except(SelectedItems).Where(shouldBeSelected)) + { + Composer.Playfield.SetKeepAlive(hitObject, true); + SelectedItems.Add(hitObject); + } bool shouldBeSelected(HitObject hitObject) { From 0ade0492526b184b14f64e59a66e88a71fc1e5d3 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 6 Oct 2022 14:02:49 +0900 Subject: [PATCH 1486/2686] Add test for selected hit object blueprint --- osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs index a4f4c375bf..54ad4e25e4 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs @@ -311,6 +311,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("jump editor clock", () => EditorClock.Seek(60000)); AddStep("end drag", () => InputManager.ReleaseButton(MouseButton.Left)); assertSelectionIs(addedObjects.Skip(1)); + AddAssert("all blueprints are present", () => blueprintContainer.SelectionBlueprints.Count == EditorBeatmap.SelectedHitObjects.Count); } private void assertSelectionIs(IEnumerable hitObjects) From e8cd9a5d110d05d200a4c5c33e9fc01e48360552 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 6 Oct 2022 17:26:03 +0900 Subject: [PATCH 1487/2686] Allow arbitrary height catch editor Useful because can see more notes at once. --- ...CatchEditorPlayfieldAdjustmentContainer.cs | 49 +++++++++++++++++++ .../Edit/CatchHitObjectComposer.cs | 5 +- .../Edit/DrawableCatchEditorRuleset.cs | 10 ++++ osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 6 +++ .../UI/DrawableCatchRuleset.cs | 4 +- 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfieldAdjustmentContainer.cs diff --git a/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfieldAdjustmentContainer.cs new file mode 100644 index 0000000000..0a0f91c781 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfieldAdjustmentContainer.cs @@ -0,0 +1,49 @@ +// 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; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.UI; +using osuTK; + +namespace osu.Game.Rulesets.Catch.Edit +{ + public class CatchEditorPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer + { + protected override Container Content => content; + private readonly Container content; + + public CatchEditorPlayfieldAdjustmentContainer() + { + Anchor = Anchor.TopCentre; + Origin = Anchor.TopCentre; + Size = new Vector2(0.8f, 0.9f); + + InternalChild = new ScalingContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Child = content = new Container { RelativeSizeAxes = Axes.Both }, + }; + } + + private class ScalingContainer : Container + { + public ScalingContainer() + { + RelativeSizeAxes = Axes.Y; + Width = CatchPlayfield.WIDTH; + } + + protected override void Update() + { + base.Update(); + + Scale = new Vector2(Math.Min(Parent.ChildSize.X / CatchPlayfield.WIDTH, Parent.ChildSize.Y / CatchPlayfield.HEIGHT)); + Height = 1 / Scale.Y; + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index f31dc3ef9c..6a32de1995 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -51,7 +51,10 @@ namespace osu.Game.Rulesets.Catch.Edit LayerBelowRuleset.Add(new PlayfieldBorder { - RelativeSizeAxes = Axes.Both, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = CatchPlayfield.HEIGHT, PlayfieldBorderStyle = { Value = PlayfieldBorderStyle.Corners } }); diff --git a/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs b/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs index c81afafae5..4f62a912e0 100644 --- a/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs +++ b/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs @@ -18,6 +18,16 @@ namespace osu.Game.Rulesets.Catch.Edit { } + protected override void Update() + { + base.Update(); + + double gamePlayTimeRange = GetTimeRange(Beatmap.Difficulty.ApproachRate); + TimeRange.Value = gamePlayTimeRange * (Playfield.DrawHeight / CatchPlayfield.HEIGHT); + } + protected override Playfield CreatePlayfield() => new CatchEditorPlayfield(Beatmap.Difficulty); + + public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new CatchEditorPlayfieldAdjustmentContainer(); } } diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index dad22fbe69..ce000b0fad 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -23,6 +23,12 @@ namespace osu.Game.Rulesets.Catch.UI ///
public const float WIDTH = 512; + /// + /// The height of the playfield. + /// This doesn't include the catcher area. + /// + public const float HEIGHT = 384; + /// /// The center position of the playfield. /// diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index ef2936ac94..a1fbe7df38 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.UI : base(ruleset, beatmap, mods) { Direction.Value = ScrollingDirection.Down; - TimeRange.Value = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450); + TimeRange.Value = GetTimeRange(beatmap.Difficulty.ApproachRate); } [BackgroundDependencyLoader] @@ -39,6 +39,8 @@ namespace osu.Game.Rulesets.Catch.UI KeyBindingInputManager.Add(new CatchTouchInputMapper()); } + protected double GetTimeRange(float approachRate) => IBeatmapDifficultyInfo.DifficultyRange(approachRate, 1800, 1200, 450); + protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay); protected override ReplayRecorder CreateReplayRecorder(Score score) => new CatchReplayRecorder(score, (CatchPlayfield)Playfield); From 9247ff3e0a0e66248ca489b99eb3115cd8bd7da9 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 6 Oct 2022 18:06:16 +0900 Subject: [PATCH 1488/2686] Allow changing scrolling speed in catch editor Scroll speed is not saved and doesn't affect gameplay. It is purely a feature for a better visualization. It is currently bind to scroll speed increase/decrease. Default F3/F4 crashes with editor shortcuts so it has to be changed. --- .../Edit/CatchHitObjectComposer.cs | 29 ++++++++++++++++++- .../Edit/DrawableCatchEditorRuleset.cs | 6 +++- .../Edit/DistancedHitObjectComposer.cs | 4 +-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 6a32de1995..bc49deedae 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -12,8 +12,10 @@ using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Input; +using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; +using osu.Game.Input.Bindings; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Edit; @@ -37,6 +39,12 @@ namespace osu.Game.Rulesets.Catch.Edit private InputManager inputManager; + private readonly BindableDouble timeRangeMultiplier = new BindableDouble(1) + { + MinValue = 1, + MaxValue = 10, + }; + public CatchHitObjectComposer(CatchRuleset ruleset) : base(ruleset) { @@ -80,8 +88,27 @@ namespace osu.Game.Rulesets.Catch.Edit updateDistanceSnapGrid(); } + public override bool OnPressed(KeyBindingPressEvent e) + { + switch (e.Action) + { + case GlobalAction.IncreaseScrollSpeed: + this.TransformBindableTo(timeRangeMultiplier, timeRangeMultiplier.Value - 1, 200, Easing.OutQuint); + break; + + case GlobalAction.DecreaseScrollSpeed: + this.TransformBindableTo(timeRangeMultiplier, timeRangeMultiplier.Value + 1, 200, Easing.OutQuint); + break; + } + + return base.OnPressed(e); + } + protected override DrawableRuleset CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) => - new DrawableCatchEditorRuleset(ruleset, beatmap, mods); + new DrawableCatchEditorRuleset(ruleset, beatmap, mods) + { + TimeRangeMultiplier = { BindTarget = timeRangeMultiplier, } + }; protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] { diff --git a/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs b/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs index 4f62a912e0..67238f66d4 100644 --- a/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs +++ b/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs @@ -4,6 +4,7 @@ #nullable disable using System.Collections.Generic; +using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Mods; @@ -13,6 +14,8 @@ namespace osu.Game.Rulesets.Catch.Edit { public class DrawableCatchEditorRuleset : DrawableCatchRuleset { + public readonly BindableDouble TimeRangeMultiplier = new BindableDouble(1); + public DrawableCatchEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) { @@ -23,7 +26,8 @@ namespace osu.Game.Rulesets.Catch.Edit base.Update(); double gamePlayTimeRange = GetTimeRange(Beatmap.Difficulty.ApproachRate); - TimeRange.Value = gamePlayTimeRange * (Playfield.DrawHeight / CatchPlayfield.HEIGHT); + float playfieldStretch = Playfield.DrawHeight / CatchPlayfield.HEIGHT; + TimeRange.Value = gamePlayTimeRange * TimeRangeMultiplier.Value * playfieldStretch; } protected override Playfield CreatePlayfield() => new CatchEditorPlayfield(Beatmap.Difficulty); diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index 4726211666..3246f6e352 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Edit } } - public bool OnPressed(KeyBindingPressEvent e) + public virtual bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) { @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Edit return false; } - public void OnReleased(KeyBindingReleaseEvent e) + public virtual void OnReleased(KeyBindingReleaseEvent e) { } From 0f6a6287f246f974a9e21304846c6b0083d8d343 Mon Sep 17 00:00:00 2001 From: NullifiedJosh <86538544+NullifiedJosh@users.noreply.github.com> Date: Thu, 6 Oct 2022 18:17:33 +0800 Subject: [PATCH 1489/2686] Fix bugs and add test --- .../TestSceneDrawableCatchRuleset.cs | 59 +++++++++++++++++++ .../UI/DrawableCatchRuleset.cs | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs new file mode 100644 index 0000000000..b826a064e6 --- /dev/null +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs @@ -0,0 +1,59 @@ +// 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.Logging; +using osu.Framework.Testing; +using osu.Game.Rulesets.Catch.Beatmaps; +using osu.Game.Rulesets.Catch.Mods; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Mods; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Catch.Tests +{ + [TestFixture] + public class TestSceneDrawableCatchRulesetWithRelax : OsuTestScene + { + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create drawable ruleset with relax mod", () => + { + Child = new DrawableCatchRuleset(new CatchRuleset(), new CatchBeatmap(), new List() { + new CatchModRelax() + }); + }); + AddUntilStep("wait for load", () => Child.IsLoaded); + } + + [Test] + public void TestBasic() + { + AddAssert("check if touch catcher is showing", () => this.ChildrenOfType().Any() == false); + } + } + + [TestFixture] + public class TestSceneDrawableCatchRulesetWithoutRelax : OsuTestScene + { + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create drawable ruleset without relax mod", () => + { + Child = new DrawableCatchRuleset(new CatchRuleset(), new CatchBeatmap(), new List()); + }); + AddUntilStep("wait for load", () => Child.IsLoaded); + Logger.Log("Ready"); + } + + [Test] + public void TestBasic() + { + AddAssert("check if touch catcher is showing", () => this.ChildrenOfType().Any()); + } + } +} diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index 07968e4bee..dfa6126d3f 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.UI : base(ruleset, beatmap, mods) { // Check if mods have RelaxMod instance - if (mods.OfType().Any()) + if (mods != null && mods.OfType().Any()) showMobileMapper = false; Direction.Value = ScrollingDirection.Down; From 6543171169b37a79b3b6ddb192dcd15b4332f4a5 Mon Sep 17 00:00:00 2001 From: NullifiedJosh <86538544+NullifiedJosh@users.noreply.github.com> Date: Thu, 6 Oct 2022 18:30:49 +0800 Subject: [PATCH 1490/2686] Fix formating. --- .../TestSceneDrawableCatchRuleset.cs | 38 +++++-------------- .../UI/DrawableCatchRuleset.cs | 2 +- 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs index b826a064e6..8b794fd919 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using osu.Framework.Logging; using osu.Framework.Testing; using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Catch.Mods; @@ -15,45 +14,28 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] - public class TestSceneDrawableCatchRulesetWithRelax : OsuTestScene + public class TestSceneDrawableCatchRuleset : OsuTestScene { - [SetUpSteps] - public void SetUpSteps() - { - AddStep("create drawable ruleset with relax mod", () => - { - Child = new DrawableCatchRuleset(new CatchRuleset(), new CatchBeatmap(), new List() { - new CatchModRelax() - }); - }); - AddUntilStep("wait for load", () => Child.IsLoaded); - } - [Test] - public void TestBasic() - { - AddAssert("check if touch catcher is showing", () => this.ChildrenOfType().Any() == false); - } - } - - [TestFixture] - public class TestSceneDrawableCatchRulesetWithoutRelax : OsuTestScene - { - [SetUpSteps] - public void SetUpSteps() + public void TestWithoutRelax() { AddStep("create drawable ruleset without relax mod", () => { Child = new DrawableCatchRuleset(new CatchRuleset(), new CatchBeatmap(), new List()); }); AddUntilStep("wait for load", () => Child.IsLoaded); - Logger.Log("Ready"); + AddAssert("check if touch catcher is showing", () => this.ChildrenOfType().Any()); } [Test] - public void TestBasic() + public void TestWithRelax() { - AddAssert("check if touch catcher is showing", () => this.ChildrenOfType().Any()); + AddStep("create drawable ruleset with relax mod", () => + { + Child = new DrawableCatchRuleset(new CatchRuleset(), new CatchBeatmap(), new List { new CatchModRelax() }); + }); + AddUntilStep("wait for load", () => Child.IsLoaded); + AddAssert("check if touch catcher is showing", () => this.ChildrenOfType().Any() == false); } } } diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index dfa6126d3f..ce1fa963e7 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool UserScrollSpeedAdjustment => false; - private bool showMobileMapper = true; + private readonly bool showMobileMapper = true; public DrawableCatchRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) From ea4dbc8c0f3ef669d86439a9b1a368c213d39a26 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 6 Oct 2022 19:46:10 +0900 Subject: [PATCH 1491/2686] Fix mania hold note head disappears --- .../Objects/Drawables/DrawableHoldNoteHead.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs index 66cc93b033..ac646ea427 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs @@ -36,6 +36,9 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables // the hold note head should never change its visual state on its own due to the "freezing" mechanic // (when hit, it remains visible in place at the judgement line; when dropped, it will scroll past the line). // it will be hidden along with its parenting hold note when required. + + // Set `LifetimeEnd` explicitly to a non-`double.MaxValue` because otherwise this DHO is automatically expired. + LifetimeEnd = double.PositiveInfinity; } public override bool OnPressed(KeyBindingPressEvent e) => false; // Handled by the hold note From 994db55b6d542c187d96d6905552f79d2a352d6a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 02:19:43 +0900 Subject: [PATCH 1492/2686] Simplify check conditionals --- osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index ce1fa963e7..27f7886d79 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -27,15 +27,9 @@ namespace osu.Game.Rulesets.Catch.UI protected override bool UserScrollSpeedAdjustment => false; - private readonly bool showMobileMapper = true; - public DrawableCatchRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) { - // Check if mods have RelaxMod instance - if (mods != null && mods.OfType().Any()) - showMobileMapper = false; - Direction.Value = ScrollingDirection.Down; TimeRange.Value = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450); } @@ -43,7 +37,8 @@ namespace osu.Game.Rulesets.Catch.UI [BackgroundDependencyLoader] private void load() { - if (showMobileMapper) + // With relax mod, input maps directly to x position and left/right buttons are not used. + if (!Mods.Any(m => m is ModRelax)) KeyBindingInputManager.Add(new CatchTouchInputMapper()); } From f3262103c44ad9d430e8e3883ccb490c0916e23e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 02:21:31 +0900 Subject: [PATCH 1493/2686] Move test into existing catch touch test scene --- .../TestSceneCatchTouchInput.cs | 35 +++++++++++++--- .../TestSceneDrawableCatchRuleset.cs | 41 ------------------- 2 files changed, 29 insertions(+), 47 deletions(-) delete mode 100644 osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs index cbf6e8f202..cf6a8169c4 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs @@ -1,10 +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 System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Testing; +using osu.Game.Rulesets.Catch.Beatmaps; +using osu.Game.Rulesets.Catch.Mods; using osu.Game.Rulesets.Catch.UI; +using osu.Game.Rulesets.Mods; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests @@ -12,11 +17,11 @@ namespace osu.Game.Rulesets.Catch.Tests [TestFixture] public class TestSceneCatchTouchInput : OsuTestScene { - private CatchTouchInputMapper catchTouchInputMapper = null!; - - [SetUpSteps] - public void SetUpSteps() + [Test] + public void TestBasic() { + CatchTouchInputMapper catchTouchInputMapper = null!; + AddStep("create input overlay", () => { Child = new CatchInputManager(new CatchRuleset().RulesetInfo) @@ -32,12 +37,30 @@ namespace osu.Game.Rulesets.Catch.Tests } }; }); + + AddStep("show overlay", () => catchTouchInputMapper.Show()); } [Test] - public void TestBasic() + public void TestWithoutRelax() { - AddStep("show overlay", () => catchTouchInputMapper.Show()); + AddStep("create drawable ruleset without relax mod", () => + { + Child = new DrawableCatchRuleset(new CatchRuleset(), new CatchBeatmap(), new List()); + }); + AddUntilStep("wait for load", () => Child.IsLoaded); + AddAssert("check touch input is shown", () => this.ChildrenOfType().Any()); + } + + [Test] + public void TestWithRelax() + { + AddStep("create drawable ruleset with relax mod", () => + { + Child = new DrawableCatchRuleset(new CatchRuleset(), new CatchBeatmap(), new List { new CatchModRelax() }); + }); + AddUntilStep("wait for load", () => Child.IsLoaded); + AddAssert("check touch input is not shown", () => !this.ChildrenOfType().Any()); } } } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs deleted file mode 100644 index 8b794fd919..0000000000 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableCatchRuleset.cs +++ /dev/null @@ -1,41 +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.Collections.Generic; -using System.Linq; -using NUnit.Framework; -using osu.Framework.Testing; -using osu.Game.Rulesets.Catch.Beatmaps; -using osu.Game.Rulesets.Catch.Mods; -using osu.Game.Rulesets.Catch.UI; -using osu.Game.Rulesets.Mods; -using osu.Game.Tests.Visual; - -namespace osu.Game.Rulesets.Catch.Tests -{ - [TestFixture] - public class TestSceneDrawableCatchRuleset : OsuTestScene - { - [Test] - public void TestWithoutRelax() - { - AddStep("create drawable ruleset without relax mod", () => - { - Child = new DrawableCatchRuleset(new CatchRuleset(), new CatchBeatmap(), new List()); - }); - AddUntilStep("wait for load", () => Child.IsLoaded); - AddAssert("check if touch catcher is showing", () => this.ChildrenOfType().Any()); - } - - [Test] - public void TestWithRelax() - { - AddStep("create drawable ruleset with relax mod", () => - { - Child = new DrawableCatchRuleset(new CatchRuleset(), new CatchBeatmap(), new List { new CatchModRelax() }); - }); - AddUntilStep("wait for load", () => Child.IsLoaded); - AddAssert("check if touch catcher is showing", () => this.ChildrenOfType().Any() == false); - } - } -} From 6164e0896a8ec69e87329f790e22624bba85225d Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 7 Oct 2022 10:46:07 +0900 Subject: [PATCH 1494/2686] Don't reselect already selected items in SelectAll --- .../Edit/Compose/Components/EditorBlueprintContainer.cs | 3 +-- osu.Game/Skinning/Editor/SkinBlueprintContainer.cs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs index 6682748253..6adaeb1a83 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs @@ -131,8 +131,7 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override void SelectAll() { Composer.Playfield.KeepAllAlive(); - SelectedItems.Clear(); - SelectedItems.AddRange(Beatmap.HitObjects); + SelectedItems.AddRange(Beatmap.HitObjects.Except(SelectedItems).ToArray()); } protected override void OnBlueprintSelected(SelectionBlueprint blueprint) diff --git a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs index 97522ddff8..2937b62eec 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs +++ b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs @@ -119,8 +119,7 @@ namespace osu.Game.Skinning.Editor protected override void SelectAll() { - SelectedItems.Clear(); - SelectedItems.AddRange(targetComponents.SelectMany(list => list)); + SelectedItems.AddRange(targetComponents.SelectMany(list => list).Except(SelectedItems).ToArray()); } /// From b27e70ca479e622b12046722d8832b8d0ee81b63 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 6 Oct 2022 21:11:00 -0700 Subject: [PATCH 1495/2686] Fix language settings dropdown not updating when changing language in first run setup --- .../Settings/Sections/General/LanguageSettings.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs index 63f0dec953..0f77e6609b 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs @@ -44,9 +44,12 @@ namespace osu.Game.Overlays.Settings.Sections.General }, }; - if (!LanguageExtensions.TryParseCultureCode(frameworkLocale.Value, out var locale)) - locale = Language.en; - languageSelection.Current.Value = locale; + frameworkLocale.BindValueChanged(locale => + { + if (!LanguageExtensions.TryParseCultureCode(locale.NewValue, out var language)) + language = Language.en; + languageSelection.Current.Value = language; + }, true); languageSelection.Current.BindValueChanged(val => frameworkLocale.Value = val.NewValue.ToCultureCode()); } From 7385ef3e1b033c37bc4bec0737ac446efe4eaa60 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 7 Oct 2022 14:26:19 +0900 Subject: [PATCH 1496/2686] Extract combo scale to virtual function --- osu.Game/Rulesets/Mods/ModFlashlight.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index a594363d4c..69937a0fba 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -149,16 +149,21 @@ namespace osu.Game.Rulesets.Mods float size = defaultFlashlightSize * sizeMultiplier; if (comboBasedSize) - { - if (combo >= 200) - size *= 0.625f; - else if (combo >= 100) - size *= 0.8125f; - } + size *= GetComboScaleFor(combo); return size; } + protected virtual float GetComboScaleFor(int combo) + { + if (combo >= 200) + return 0.625f; + if (combo >= 100) + return 0.8125f; + + return 1.0f; + } + private Vector2 flashlightPosition; protected Vector2 FlashlightPosition From c6b5fdc7d0cdab0d41cc9e41cf9e509433633427 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 7 Oct 2022 14:34:48 +0900 Subject: [PATCH 1497/2686] Adjust catch flashlight to closely match classic --- osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index 1adc969f8f..ff957b9b73 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Catch.Mods public override BindableBool ComboBasedSize { get; } = new BindableBool(true); - public override float DefaultFlashlightSize => 350; + public override float DefaultFlashlightSize => 325; protected override Flashlight CreateFlashlight() => new CatchFlashlight(this, playfield); @@ -44,7 +44,19 @@ namespace osu.Game.Rulesets.Catch.Mods : base(modFlashlight) { this.playfield = playfield; + FlashlightSize = new Vector2(0, GetSizeFor(0)); + FlashlightSmoothness = 1.4f; + } + + protected override float GetComboScaleFor(int combo) + { + if (combo >= 200) + return 0.770f; + if (combo >= 100) + return 0.885f; + + return 1.0f; } protected override void Update() From 5f3b58b7e009a0ed5c7d1028a01d89c7e754a2f4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 7 Oct 2022 14:44:45 +0900 Subject: [PATCH 1498/2686] Adjust taiko flashlight to closely match classic --- osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 1caacdd1d7..fca69e86cc 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Mods public override BindableBool ComboBasedSize { get; } = new BindableBool(true); - public override float DefaultFlashlightSize => 250; + public override float DefaultFlashlightSize => 200; protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, playfield); @@ -46,7 +46,9 @@ namespace osu.Game.Rulesets.Taiko.Mods : base(modFlashlight) { this.taikoPlayfield = taikoPlayfield; + FlashlightSize = getSizeFor(0); + FlashlightSmoothness = 1.4f; AddLayout(flashlightProperties); } From df3ad618e15782e28b08fa4271aa1e79560de6b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 17:49:00 +0900 Subject: [PATCH 1499/2686] Move `ColumnType` to constructor --- .../Editor/ManiaPlacementBlueprintTestScene.cs | 3 ++- .../Skinning/ColumnTestContainer.cs | 3 +-- osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs | 3 ++- .../TestSceneDrawableManiaHitObject.cs | 3 ++- osu.Game.Rulesets.Mania/Beatmaps/ColumnType.cs | 2 -- osu.Game.Rulesets.Mania/UI/Column.cs | 13 ++++++------- osu.Game.Rulesets.Mania/UI/Stage.cs | 5 ++--- 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs index 6e6e83f9cf..d6dd2664bc 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; @@ -34,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor { scrollingInfo = ((ScrollingTestContainer)HitObjectContainer).ScrollingInfo; - Add(column = new Column(0) + Add(column = new Column(0, ColumnType.Even) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs index 1a3513d46c..33166c5aeb 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs @@ -28,11 +28,10 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning { InternalChildren = new[] { - this.column = new Column(column) + this.column = new Column(column, column % 2 == 0 ? ColumnType.Even : ColumnType.Odd) { Action = { Value = action }, AccentColour = Color4.Orange, - ColumnType = column % 2 == 0 ? ColumnType.Even : ColumnType.Odd, Alpha = showColumn ? 1 : 0 }, content = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs index 2922d18713..ab2f63339f 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs @@ -11,6 +11,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; @@ -84,7 +85,7 @@ namespace osu.Game.Rulesets.Mania.Tests private Drawable createColumn(ScrollingDirection direction, ManiaAction action, int index) { - var column = new Column(index) + var column = new Column(index, ColumnType.Even) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs index 223f8dae44..b9b28eb19f 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs @@ -9,6 +9,7 @@ using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; @@ -35,7 +36,7 @@ namespace osu.Game.Rulesets.Mania.Tests RelativeSizeAxes = Axes.Y, TimeRange = 2000, Clock = new FramedClock(clock), - Child = column = new Column(0) + Child = column = new Column(0, ColumnType.Even) { Action = { Value = ManiaAction.Key1 }, Height = 0.85f, diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ColumnType.cs b/osu.Game.Rulesets.Mania/Beatmaps/ColumnType.cs index 0114987e3c..8f904530bc 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ColumnType.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ColumnType.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. -#nullable disable - namespace osu.Game.Rulesets.Mania.Beatmaps { public enum ColumnType diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index deb1b155b5..361210ff1d 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -46,9 +46,14 @@ namespace osu.Game.Rulesets.Mania.UI private readonly GameplaySampleTriggerSource sampleTriggerSource; - public Column(int index) + public readonly ColumnType ColumnType; + + public Color4 AccentColour { get; set; } + + public Column(int index, ColumnType columnType) { Index = index; + ColumnType = columnType; RelativeSizeAxes = Axes.Y; Width = COLUMN_WIDTH; @@ -92,12 +97,6 @@ namespace osu.Game.Rulesets.Mania.UI NewResult += OnNewResult; } - public ColumnType ColumnType { get; set; } - - public bool IsSpecial => ColumnType == ColumnType.Special; - - public Color4 AccentColour { get; set; } - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index c578bbb703..29dacc5094 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -120,13 +120,12 @@ namespace osu.Game.Rulesets.Mania.UI { var columnType = definition.GetTypeOfColumn(i); - var column = new Column(firstColumnIndex + i) + var column = new Column(firstColumnIndex + i, columnType) { RelativeSizeAxes = Axes.Both, - Width = 1, - ColumnType = columnType, AccentColour = columnColours[columnType], Action = { Value = columnType == ColumnType.Special ? specialColumnStartAction++ : normalColumnStartAction++ } + Width = 1, }; topLevelContainer.Add(column.TopLevelContainer.CreateProxy()); From 7796a4c1097c0de6e780f282db5883a49357aa18 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 18:24:49 +0900 Subject: [PATCH 1500/2686] Cache `StageDefinition` for consumption (and remove `ColumnType`) --- .../ManiaPlacementBlueprintTestScene.cs | 3 +- ...nTypeTest.cs => ManiaSpecialColumnTest.cs} | 34 +++++++++---------- .../Skinning/ColumnTestContainer.cs | 5 ++- .../TestSceneColumn.cs | 3 +- .../TestSceneDrawableManiaHitObject.cs | 3 +- .../Beatmaps/ColumnType.cs | 12 ------- .../Beatmaps/StageDefinition.cs | 19 ++--------- osu.Game.Rulesets.Mania/ManiaSkinComponent.cs | 4 +-- .../Legacy/LegacyManiaColumnElement.cs | 21 +++++------- .../Legacy/ManiaLegacySkinTransformer.cs | 2 +- osu.Game.Rulesets.Mania/UI/Column.cs | 13 +++---- osu.Game.Rulesets.Mania/UI/Stage.cs | 27 +++++++++------ 12 files changed, 61 insertions(+), 85 deletions(-) rename osu.Game.Rulesets.Mania.Tests/{ManiaColumnTypeTest.cs => ManiaSpecialColumnTest.cs} (53%) delete mode 100644 osu.Game.Rulesets.Mania/Beatmaps/ColumnType.cs diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs index d6dd2664bc..976efc51b2 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; @@ -35,7 +34,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor { scrollingInfo = ((ScrollingTestContainer)HitObjectContainer).ScrollingInfo; - Add(column = new Column(0, ColumnType.Even) + Add(column = new Column(0, false) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaColumnTypeTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs similarity index 53% rename from osu.Game.Rulesets.Mania.Tests/ManiaColumnTypeTest.cs rename to osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs index e53deb5269..c83e8a51ed 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaColumnTypeTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs @@ -10,43 +10,43 @@ using NUnit.Framework; namespace osu.Game.Rulesets.Mania.Tests { [TestFixture] - public class ManiaColumnTypeTest + public class ManiaSpecialColumnTest { [TestCase(new[] { - ColumnType.Special + true }, 1)] [TestCase(new[] { - ColumnType.Odd, - ColumnType.Even, - ColumnType.Even, - ColumnType.Odd + false, + false, + false, + false }, 4)] [TestCase(new[] { - ColumnType.Odd, - ColumnType.Even, - ColumnType.Odd, - ColumnType.Special, - ColumnType.Odd, - ColumnType.Even, - ColumnType.Odd + false, + false, + false, + true, + false, + false, + false }, 7)] - public void Test(IEnumerable expected, int columns) + public void Test(IEnumerable special, int columns) { var definition = new StageDefinition { Columns = columns }; var results = getResults(definition); - Assert.AreEqual(expected, results); + Assert.AreEqual(special, results); } - private IEnumerable getResults(StageDefinition definition) + private IEnumerable getResults(StageDefinition definition) { for (int i = 0; i < definition.Columns; i++) - yield return definition.GetTypeOfColumn(i); + yield return definition.IsSpecialColumn(i); } } } diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs index 33166c5aeb..b8d1313af5 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs @@ -24,11 +24,14 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [Cached] private readonly Column column; + [Cached] + private readonly StageDefinition stageDefinition = new StageDefinition { Columns = 1 }; + public ColumnTestContainer(int column, ManiaAction action, bool showColumn = false) { InternalChildren = new[] { - this.column = new Column(column, column % 2 == 0 ? ColumnType.Even : ColumnType.Odd) + this.column = new Column(column, false) { Action = { Value = action }, AccentColour = Color4.Orange, diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs index ab2f63339f..8fff87ae78 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs @@ -11,7 +11,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; @@ -85,7 +84,7 @@ namespace osu.Game.Rulesets.Mania.Tests private Drawable createColumn(ScrollingDirection direction, ManiaAction action, int index) { - var column = new Column(index, ColumnType.Even) + var column = new Column(index, false) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs index b9b28eb19f..bd34f1ef11 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs @@ -9,7 +9,6 @@ using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; @@ -36,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Tests RelativeSizeAxes = Axes.Y, TimeRange = 2000, Clock = new FramedClock(clock), - Child = column = new Column(0, ColumnType.Even) + Child = column = new Column(0, false) { Action = { Value = ManiaAction.Key1 }, Height = 0.85f, diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ColumnType.cs b/osu.Game.Rulesets.Mania/Beatmaps/ColumnType.cs deleted file mode 100644 index 8f904530bc..0000000000 --- a/osu.Game.Rulesets.Mania/Beatmaps/ColumnType.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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.Mania.Beatmaps -{ - public enum ColumnType - { - Even, - Odd, - Special - } -} diff --git a/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs b/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs index 54e2d4686f..08ee97b32b 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Beatmaps @@ -11,7 +10,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// /// Defines properties for each stage in a . /// - public struct StageDefinition + public class StageDefinition { /// /// The number of s which this stage contains. @@ -23,20 +22,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// /// The 0-based column index. /// Whether the column is a special column. - public readonly bool IsSpecialColumn(int column) => Columns % 2 == 1 && column == Columns / 2; - - /// - /// Get the type of column given a column index. - /// - /// The 0-based column index. - /// The type of the column. - public readonly ColumnType GetTypeOfColumn(int column) - { - if (IsSpecialColumn(column)) - return ColumnType.Special; - - int distanceToEdge = Math.Min(column, (Columns - 1) - column); - return distanceToEdge % 2 == 0 ? ColumnType.Odd : ColumnType.Even; - } + public bool IsSpecialColumn(int column) => Columns % 2 == 1 && column == Columns / 2; } } diff --git a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs b/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs index 21b362df00..6d0eb15b64 100644 --- a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs +++ b/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs @@ -15,14 +15,14 @@ namespace osu.Game.Rulesets.Mania /// The intended for this component. /// May be null if the component is not a direct member of a . /// - public readonly StageDefinition? StageDefinition; + public readonly StageDefinition StageDefinition; /// /// Creates a new . /// /// The component. /// The intended for this component. May be null if the component is not a direct member of a . - public ManiaSkinComponent(ManiaSkinComponents component, StageDefinition? stageDefinition = null) + public ManiaSkinComponent(ManiaSkinComponents component, StageDefinition stageDefinition = null) : base(component) { StageDefinition = stageDefinition; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs index ab953ccfb9..e227c80845 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; @@ -20,6 +21,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy [Resolved] protected Column Column { get; private set; } + [Resolved] + private StageDefinition stage { get; set; } + /// /// The column type identifier to use for texture lookups, in the case of no user-provided configuration. /// @@ -28,19 +32,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy [BackgroundDependencyLoader] private void load() { - switch (Column.ColumnType) + if (Column.IsSpecial) + FallbackColumnIndex = "S"; + else { - case ColumnType.Special: - FallbackColumnIndex = "S"; - break; - - case ColumnType.Odd: - FallbackColumnIndex = "1"; - break; - - case ColumnType.Even: - FallbackColumnIndex = "2"; - break; + int distanceToEdge = Math.Min(Column.Index, (stage.Columns - 1) - Column.Index); + FallbackColumnIndex = distanceToEdge % 2 == 0 ? "1" : "2"; } } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index dd5baa8150..a1b196e53e 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy case ManiaSkinComponents.StageBackground: Debug.Assert(maniaComponent.StageDefinition != null); - return new LegacyStageBackground(maniaComponent.StageDefinition.Value); + return new LegacyStageBackground(maniaComponent.StageDefinition); case ManiaSkinComponents.StageForeground: return new LegacyStageForeground(); diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 361210ff1d..57ada84767 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -6,7 +6,6 @@ using osuTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -18,7 +17,6 @@ using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.UI; @@ -26,7 +24,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mania.UI { [Cached] - public class Column : ScrollingPlayfield, IKeyBindingHandler, IHasAccentColour + public class Column : ScrollingPlayfield, IKeyBindingHandler { public const float COLUMN_WIDTH = 80; public const float SPECIAL_COLUMN_WIDTH = 70; @@ -46,14 +44,17 @@ namespace osu.Game.Rulesets.Mania.UI private readonly GameplaySampleTriggerSource sampleTriggerSource; - public readonly ColumnType ColumnType; + /// + /// Whether this is a special (ie. scratch) column. + /// + public readonly bool IsSpecial; public Color4 AccentColour { get; set; } - public Column(int index, ColumnType columnType) + public Column(int index, bool isSpecial) { Index = index; - ColumnType = columnType; + IsSpecial = isSpecial; RelativeSizeAxes = Axes.Y; Width = COLUMN_WIDTH; diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index 29dacc5094..9e51ed84db 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; @@ -19,7 +20,6 @@ using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.UI { @@ -28,6 +28,9 @@ namespace osu.Game.Rulesets.Mania.UI ///
public class Stage : ScrollingPlayfield { + [Cached] + public readonly StageDefinition Definition; + public const float COLUMN_SPACING = 1; public const float HIT_TARGET_POSITION = 110; @@ -40,12 +43,12 @@ namespace osu.Game.Rulesets.Mania.UI private readonly Drawable barLineContainer; - private readonly Dictionary columnColours = new Dictionary - { - { ColumnType.Even, new Color4(6, 84, 0, 255) }, - { ColumnType.Odd, new Color4(94, 0, 57, 255) }, - { ColumnType.Special, new Color4(0, 48, 63, 255) } - }; + // private readonly Dictionary columnColours = new Dictionary + // { + // { ColumnType.Even, new Color4(6, 84, 0, 255) }, + // { ColumnType.Odd, new Color4(94, 0, 57, 255) }, + // { ColumnType.Special, new Color4(0, 48, 63, 255) } + // }; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Columns.Any(c => c.ReceivePositionalInputAt(screenSpacePos)); @@ -54,6 +57,7 @@ namespace osu.Game.Rulesets.Mania.UI public Stage(int firstColumnIndex, StageDefinition definition, ref ManiaAction normalColumnStartAction, ref ManiaAction specialColumnStartAction) { this.firstColumnIndex = firstColumnIndex; + Definition = definition; Name = "Stage"; @@ -118,14 +122,15 @@ namespace osu.Game.Rulesets.Mania.UI for (int i = 0; i < definition.Columns; i++) { - var columnType = definition.GetTypeOfColumn(i); + bool isSpecial = definition.IsSpecialColumn(i); - var column = new Column(firstColumnIndex + i, columnType) + var column = new Column(firstColumnIndex + i, isSpecial) { RelativeSizeAxes = Axes.Both, - AccentColour = columnColours[columnType], - Action = { Value = columnType == ColumnType.Special ? specialColumnStartAction++ : normalColumnStartAction++ } Width = 1, + // TODO: reimplement this somewhere. + //AccentColour = columnColours[isSpecial], + Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ } }; topLevelContainer.Add(column.TopLevelContainer.CreateProxy()); From 46c3cfe54d6a772b82c0a76f969627b3c408f30b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 18:26:27 +0900 Subject: [PATCH 1501/2686] Remove `StageDefinition` flow in `ManiaSkinComponent` --- .../Skinning/TestSceneStageBackground.cs | 3 +-- .../Skinning/TestSceneStageForeground.cs | 3 +-- osu.Game.Rulesets.Mania/ManiaSkinComponent.cs | 12 +----------- .../Skinning/Legacy/LegacyStageBackground.cs | 7 ++----- .../Skinning/Legacy/ManiaLegacySkinTransformer.cs | 4 +--- osu.Game.Rulesets.Mania/UI/Stage.cs | 4 ++-- 6 files changed, 8 insertions(+), 25 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs index 687b3a747d..0744d7e2e7 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Skinning; @@ -16,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground, stageDefinition: new StageDefinition { Columns = 4 }), + SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground()) { Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs index 6cbc172755..979c90c802 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Tests.Skinning @@ -15,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground, stageDefinition: new StageDefinition { Columns = 4 }), _ => null) + SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground), _ => null) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs b/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs index 6d0eb15b64..f05edb4677 100644 --- a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs +++ b/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs @@ -3,29 +3,19 @@ #nullable disable -using osu.Game.Rulesets.Mania.Beatmaps; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania { public class ManiaSkinComponent : GameplaySkinComponent { - /// - /// The intended for this component. - /// May be null if the component is not a direct member of a . - /// - public readonly StageDefinition StageDefinition; - /// /// Creates a new . /// /// The component. - /// The intended for this component. May be null if the component is not a direct member of a . - public ManiaSkinComponent(ManiaSkinComponents component, StageDefinition stageDefinition = null) + public ManiaSkinComponent(ManiaSkinComponents component) : base(component) { - StageDefinition = stageDefinition; } protected override string RulesetPrefix => ManiaRuleset.SHORT_NAME; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs index 740ccbfe27..d039551cd7 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs @@ -18,20 +18,17 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyStageBackground : CompositeDrawable { - private readonly StageDefinition stageDefinition; - private Drawable leftSprite; private Drawable rightSprite; private ColumnFlow columnBackgrounds; - public LegacyStageBackground(StageDefinition stageDefinition) + public LegacyStageBackground() { - this.stageDefinition = stageDefinition; RelativeSizeAxes = Axes.Both; } [BackgroundDependencyLoader] - private void load(ISkinSource skin) + private void load(ISkinSource skin, StageDefinition stageDefinition) { string leftImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LeftStageImage)?.Value ?? "mania-stage-left"; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index a1b196e53e..5ecdf988f9 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -113,8 +112,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy return new LegacyHitExplosion(); case ManiaSkinComponents.StageBackground: - Debug.Assert(maniaComponent.StageDefinition != null); - return new LegacyStageBackground(maniaComponent.StageDefinition); + return new LegacyStageBackground(); case ManiaSkinComponents.StageForeground: return new LegacyStageForeground(); diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index 9e51ed84db..a19d423e69 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.UI AutoSizeAxes = Axes.X, Children = new Drawable[] { - new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground, stageDefinition: definition), _ => new DefaultStageBackground()) + new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground()) { RelativeSizeAxes = Axes.Both }, @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Mania.UI RelativeSizeAxes = Axes.Y, } }, - new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground, stageDefinition: definition), _ => null) + new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground), _ => null) { RelativeSizeAxes = Axes.Both }, From 9c979044dcd93f53cb86be594b8b6da3f382761c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 19:27:16 +0900 Subject: [PATCH 1502/2686] Move `AccentColour` assignment to inside `Column` --- osu.Game.Rulesets.Mania/UI/Column.cs | 42 ++++++++++++++++++---------- osu.Game.Rulesets.Mania/UI/Stage.cs | 2 -- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 57ada84767..c0739f5ec3 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -3,23 +3,24 @@ #nullable disable -using osuTK.Graphics; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Objects.Drawables; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Utils; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI.Components; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; -using osu.Game.Rulesets.Mania.Objects; -using osu.Game.Rulesets.Mania.Objects.Drawables; -using osu.Game.Rulesets.UI; +using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.UI { @@ -37,12 +38,12 @@ namespace osu.Game.Rulesets.Mania.UI public readonly Bindable Action = new Bindable(); public readonly ColumnHitObjectArea HitObjectArea; - internal readonly Container TopLevelContainer; - private readonly DrawablePool hitExplosionPool; + internal readonly Container TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }; + private DrawablePool hitExplosionPool; private readonly OrderedHitPolicy hitPolicy; public Container UnderlayElements => HitObjectArea.UnderlayElements; - private readonly GameplaySampleTriggerSource sampleTriggerSource; + private GameplaySampleTriggerSource sampleTriggerSource; /// /// Whether this is a special (ie. scratch) column. @@ -59,6 +60,21 @@ namespace osu.Game.Rulesets.Mania.UI RelativeSizeAxes = Axes.Y; Width = COLUMN_WIDTH; + hitPolicy = new OrderedHitPolicy(HitObjectContainer); + HitObjectArea = new ColumnHitObjectArea(HitObjectContainer) { RelativeSizeAxes = Axes.Both }; + } + + [BackgroundDependencyLoader] + private void load(ISkinSource skin) + { + // TODO: reimplement this somewhere. + AccentColour = skin.GetConfig() + var ballColour = skin.GetConfig(OsuSkinColour.SliderBall)?.Value ?? Color4.White; + + //AccentColour = columnColours[isSpecial], + foreach (var obj in HitObjectContainer.Objects) + obj.AccentColour.Value = AccentColour; + Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both @@ -70,18 +86,16 @@ namespace osu.Game.Rulesets.Mania.UI sampleTriggerSource = new GameplaySampleTriggerSource(HitObjectContainer), // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements background.CreateProxy(), - HitObjectArea = new ColumnHitObjectArea(HitObjectContainer) { RelativeSizeAxes = Axes.Both }, + HitObjectArea, new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) { RelativeSizeAxes = Axes.Both }, background, - TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both }, + TopLevelContainer, new ColumnTouchInputArea(this) }; - hitPolicy = new OrderedHitPolicy(HitObjectContainer); - TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy()); RegisterPool(10, 50); diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index a19d423e69..52c8829df3 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -128,8 +128,6 @@ namespace osu.Game.Rulesets.Mania.UI { RelativeSizeAxes = Axes.Both, Width = 1, - // TODO: reimplement this somewhere. - //AccentColour = columnColours[isSpecial], Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ } }; From 5c48d8931ad8dc5e7ba36cd06bcaf84052a77615 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 19:42:43 +0900 Subject: [PATCH 1503/2686] Add `StageDefinition` to `ManiaSkinConfigurationLookup` and make column background colour lookup work --- .../Argon/ManiaArgonSkinTransformer.cs | 24 +++++++++++++++++++ .../Legacy/HitTargetInsetContainer.cs | 5 ++-- .../Skinning/Legacy/LegacyColumnBackground.cs | 5 ++-- .../Skinning/Legacy/LegacyHitTarget.cs | 9 +++---- .../Legacy/LegacyManiaColumnElement.cs | 2 +- .../Legacy/LegacyManiaJudgementPiece.cs | 5 ++-- .../Skinning/Legacy/LegacyNotePiece.cs | 5 ++-- .../Skinning/Legacy/LegacyStageBackground.cs | 14 +++++------ .../Skinning/Legacy/LegacyStageForeground.cs | 5 ++-- .../Legacy/ManiaLegacySkinTransformer.cs | 6 ++--- .../Skinning/ManiaSkinConfigExtensions.cs | 8 ++++--- .../Skinning/ManiaSkinConfigurationLookup.cs | 16 +++++++++---- osu.Game.Rulesets.Mania/UI/Column.cs | 9 ++++--- osu.Game.Rulesets.Mania/UI/ColumnFlow.cs | 4 ++-- .../UI/Components/HitObjectArea.cs | 6 ++++- 15 files changed, 83 insertions(+), 40 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index ec6aaf2ef7..57a317e87d 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -1,8 +1,11 @@ // 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.Framework.Graphics; +using osu.Framework.Utils; using osu.Game.Skinning; +using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { @@ -33,5 +36,26 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon return base.GetDrawableComponent(component); } + + public override IBindable? GetConfig(TLookup lookup) + { + if (lookup is ManiaSkinConfigurationLookup maniaLookup) + { + switch (maniaLookup.Lookup) + { + case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: + if (maniaLookup.StageDefinition.IsSpecialColumn(maniaLookup.ColumnIndex ?? 0)) + return SkinUtils.As(new Bindable(Color4.Yellow)); + + // TODO: Add actual colours. + return SkinUtils.As(new Bindable(new Color4(RNG.NextSingle() * 0.5f, RNG.NextSingle() * 0.5f, RNG.NextSingle() * 0.5f, 1))); + } + + return base.GetConfig(new LegacyManiaSkinConfigurationLookup(maniaLookup.StageDefinition.Columns, maniaLookup.Lookup, + maniaLookup.ColumnIndex)); + } + + return base.GetConfig(lookup); + } } } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs index 362a265789..de6d048295 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; @@ -30,9 +31,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, IScrollingInfo scrollingInfo) + private void load(ISkinSource skin, IScrollingInfo scrollingInfo, StageDefinition stageDefinition) { - hitPosition = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.HitPosition)?.Value ?? Stage.HIT_TARGET_POSITION; + hitPosition = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.HitPosition, stageDefinition)?.Value ?? Stage.HIT_TARGET_POSITION; direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(onDirectionChanged, true); diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs index f35cedab08..08fa9b9a73 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; @@ -30,9 +31,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, IScrollingInfo scrollingInfo) + private void load(ISkinSource skin, IScrollingInfo scrollingInfo, StageDefinition stageDefinition) { - string lightImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LightImage)?.Value + string lightImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LightImage, stageDefinition)?.Value ?? "mania-stage-light"; float lightPosition = GetColumnSkinConfig(skin, LegacyManiaSkinConfigurationLookups.LightPosition)?.Value diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs index 611dac30b3..9819f09e10 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; @@ -23,15 +24,15 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy private Container directionContainer; [BackgroundDependencyLoader] - private void load(ISkinSource skin, IScrollingInfo scrollingInfo) + private void load(ISkinSource skin, IScrollingInfo scrollingInfo, StageDefinition stageDefinition) { - string targetImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.HitTargetImage)?.Value + string targetImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.HitTargetImage, stageDefinition)?.Value ?? "mania-stage-hint"; - bool showJudgementLine = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ShowJudgementLine)?.Value + bool showJudgementLine = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ShowJudgementLine, stageDefinition)?.Value ?? true; - Color4 lineColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.JudgementLineColour)?.Value + Color4 lineColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.JudgementLineColour, stageDefinition)?.Value ?? Color4.White; InternalChild = directionContainer = new Container diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs index e227c80845..cfebad4add 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs @@ -42,6 +42,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } protected IBindable GetColumnSkinConfig(ISkin skin, LegacyManiaSkinConfigurationLookups lookup) - => skin.GetManiaSkinConfig(lookup, Column.Index); + => skin.GetManiaSkinConfig(lookup, stage, Column.Index); } } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs index d09a73a693..f9653dab15 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; @@ -32,9 +33,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin) + private void load(ISkinSource skin, StageDefinition stageDefinition) { - float? scorePosition = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ScorePosition)?.Value; + float? scorePosition = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ScorePosition, stageDefinition)?.Value; if (scorePosition != null) scorePosition -= Stage.HIT_TARGET_POSITION + 150; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs index 41e149ea2f..779e1a152c 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; @@ -35,9 +36,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, IScrollingInfo scrollingInfo) + private void load(ISkinSource skin, IScrollingInfo scrollingInfo, StageDefinition stageDefinition) { - minimumColumnWidth = skin.GetConfig(new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.MinimumColumnWidth))?.Value; + minimumColumnWidth = skin.GetConfig(new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.MinimumColumnWidth, stageDefinition))?.Value; InternalChild = directionContainer = new Container { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs index d039551cd7..01c2b599fa 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs @@ -30,10 +30,10 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy [BackgroundDependencyLoader] private void load(ISkinSource skin, StageDefinition stageDefinition) { - string leftImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LeftStageImage)?.Value + string leftImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LeftStageImage, stageDefinition)?.Value ?? "mania-stage-left"; - string rightImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.RightStageImage)?.Value + string rightImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.RightStageImage, stageDefinition)?.Value ?? "mania-stage-right"; InternalChildren = new[] @@ -91,16 +91,16 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin) + private void load(ISkinSource skin, StageDefinition stageDefinition) { - float leftLineWidth = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LeftLineWidth, columnIndex)?.Value ?? 1; - float rightLineWidth = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.RightLineWidth, columnIndex)?.Value ?? 1; + float leftLineWidth = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LeftLineWidth, stageDefinition, columnIndex)?.Value ?? 1; + float rightLineWidth = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.RightLineWidth, stageDefinition, columnIndex)?.Value ?? 1; bool hasLeftLine = leftLineWidth > 0; bool hasRightLine = (rightLineWidth > 0 && skin.GetConfig(SkinConfiguration.LegacySetting.Version)?.Value >= 2.4m) || isLastColumn; - Color4 lineColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnLineColour, columnIndex)?.Value ?? Color4.White; - Color4 backgroundColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, columnIndex)?.Value ?? Color4.Black; + Color4 lineColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnLineColour, stageDefinition, columnIndex)?.Value ?? Color4.White; + Color4 backgroundColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, stageDefinition, columnIndex)?.Value ?? Color4.Black; InternalChildren = new Drawable[] { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs index f7c611d551..57b76c5402 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; @@ -25,9 +26,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, IScrollingInfo scrollingInfo) + private void load(ISkinSource skin, IScrollingInfo scrollingInfo, StageDefinition stageDefinition) { - string bottomImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.BottomStageImage)?.Value + string bottomImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.BottomStageImage, stageDefinition)?.Value ?? "mania-stage-bottom"; sprite = skin.GetAnimation(bottomImage, true, true)?.With(d => diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 5ecdf988f9..352b205c0b 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy isLegacySkin = new Lazy(() => GetConfig(SkinConfiguration.LegacySetting.Version) != null); hasKeyTexture = new Lazy(() => { - string keyImage = this.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.KeyImage, 0)?.Value ?? "mania-key1"; + string keyImage = this.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.KeyImage, new StageDefinition(), 0)?.Value ?? "mania-key1"; return this.GetAnimation(keyImage, true, true) != null; }); } @@ -130,7 +130,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy if (!hit_result_mapping.ContainsKey(result)) return null; - string filename = this.GetManiaSkinConfig(hit_result_mapping[result])?.Value + string filename = this.GetManiaSkinConfig(hit_result_mapping[result], new StageDefinition())?.Value ?? default_hit_result_skin_filenames[result]; var animation = this.GetAnimation(filename, true, true); @@ -149,7 +149,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy public override IBindable GetConfig(TLookup lookup) { if (lookup is ManiaSkinConfigurationLookup maniaLookup) - return base.GetConfig(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.TargetColumn)); + return base.GetConfig(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.ColumnIndex)); return base.GetConfig(lookup); } diff --git a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs index 4d0c321116..541b679043 100644 --- a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs +++ b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs @@ -4,6 +4,7 @@ #nullable disable using osu.Framework.Bindables; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Skinning @@ -15,9 +16,10 @@ namespace osu.Game.Rulesets.Mania.Skinning /// /// The skin from which configuration is retrieved. /// The value to retrieve. - /// If not null, denotes the index of the column to which the entry applies. - public static IBindable GetManiaSkinConfig(this ISkin skin, LegacyManiaSkinConfigurationLookups lookup, int? index = null) + /// The stage definition. + /// If not null, denotes the index of the column to which the entry applies. + public static IBindable GetManiaSkinConfig(this ISkin skin, LegacyManiaSkinConfigurationLookups lookup, StageDefinition stageDefinition, int? columnIndex = null) => skin.GetConfig( - new ManiaSkinConfigurationLookup(lookup, index)); + new ManiaSkinConfigurationLookup(lookup, stageDefinition, columnIndex)); } } diff --git a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs index e9005a3da0..8008c988d4 100644 --- a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs +++ b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs @@ -3,6 +3,7 @@ #nullable disable +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.UI; using osu.Game.Skinning; @@ -15,21 +16,28 @@ namespace osu.Game.Rulesets.Mania.Skinning ///
public readonly LegacyManiaSkinConfigurationLookups Lookup; + /// + /// The stage containing the component which is performing this lookup. + /// + public readonly StageDefinition StageDefinition; + /// /// The intended index for the configuration. /// May be null if the configuration does not apply to a . /// - public readonly int? TargetColumn; + public readonly int? ColumnIndex; /// /// Creates a new . /// /// The lookup value. - /// The intended index for the configuration. May be null if the configuration does not apply to a . - public ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups lookup, int? targetColumn = null) + /// The stage definition. + /// The intended index for the configuration. May be null if the configuration does not apply to a . + public ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups lookup, StageDefinition stageDefinition, int? columnIndex = null) { Lookup = lookup; - TargetColumn = targetColumn; + StageDefinition = stageDefinition; + ColumnIndex = columnIndex; } } } diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index c0739f5ec3..75d6d4c206 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -10,10 +10,11 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -using osu.Framework.Utils; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.Mania.Skinning; using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; @@ -65,11 +66,9 @@ namespace osu.Game.Rulesets.Mania.UI } [BackgroundDependencyLoader] - private void load(ISkinSource skin) + private void load(ISkinSource skin, StageDefinition stageDefinition) { - // TODO: reimplement this somewhere. - AccentColour = skin.GetConfig() - var ballColour = skin.GetConfig(OsuSkinColour.SliderBall)?.Value ?? Color4.White; + AccentColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, stageDefinition, Index)?.Value ?? Color4.Black; //AccentColour = columnColours[isSpecial], foreach (var obj in HitObjectContainer.Objects) diff --git a/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs b/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs index 871ec9f1a3..bde2308635 100644 --- a/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs +++ b/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs @@ -65,14 +65,14 @@ namespace osu.Game.Rulesets.Mania.UI if (i > 0) { float spacing = currentSkin.GetConfig( - new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnSpacing, i - 1)) + new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnSpacing, stageDefinition, i - 1)) ?.Value ?? Stage.COLUMN_SPACING; columns[i].Margin = new MarginPadding { Left = spacing }; } float? width = currentSkin.GetConfig( - new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnWidth, i)) + new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnWidth, stageDefinition, i)) ?.Value; if (width == null) diff --git a/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs index 7f4b8eacde..69bf146951 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Skinning; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; @@ -19,6 +20,9 @@ namespace osu.Game.Rulesets.Mania.UI.Components protected readonly IBindable Direction = new Bindable(); public readonly HitObjectContainer HitObjectContainer; + [Resolved] + private StageDefinition stageDefinition { get; set; } + public HitObjectArea(HitObjectContainer hitObjectContainer) { InternalChild = new Container @@ -49,7 +53,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components protected virtual void UpdateHitPosition() { float hitPosition = CurrentSkin.GetConfig( - new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.HitPosition))?.Value + new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.HitPosition, stageDefinition))?.Value ?? Stage.HIT_TARGET_POSITION; Padding = Direction.Value == ScrollingDirection.Up From 1a0b953846f2ac67acfd93f228cc64e7efcd666d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 19:49:07 +0900 Subject: [PATCH 1504/2686] Remove unnecessary `Beatmap` parameter in `ManiaLegacySkinTransformer` --- .../Skinning/ColumnTestContainer.cs | 2 +- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- .../Skinning/Legacy/ManiaLegacySkinTransformer.cs | 11 +++-------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs index b8d1313af5..8f6a8c42b1 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning private readonly Column column; [Cached] - private readonly StageDefinition stageDefinition = new StageDefinition { Columns = 1 }; + private readonly StageDefinition stageDefinition = new StageDefinition { Columns = 2 }; public ColumnTestContainer(int column, ManiaAction action, bool showColumn = false) { diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index c6b20b1baf..746dda6733 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Mania switch (skin) { case LegacySkin: - return new ManiaLegacySkinTransformer(skin, beatmap); + return new ManiaLegacySkinTransformer(skin); case ArgonSkin: return new ManiaArgonSkinTransformer(skin); diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 352b205c0b..0a59c10b5f 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -9,7 +9,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Audio; -using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Scoring; @@ -19,8 +18,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class ManiaLegacySkinTransformer : LegacySkinTransformer { - private readonly ManiaBeatmap beatmap; - /// /// Mapping of to their corresponding /// value. @@ -59,15 +56,13 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy /// private readonly Lazy hasKeyTexture; - public ManiaLegacySkinTransformer(ISkin skin, IBeatmap beatmap) + public ManiaLegacySkinTransformer(ISkin skin) : base(skin) { - this.beatmap = (ManiaBeatmap)beatmap; - isLegacySkin = new Lazy(() => GetConfig(SkinConfiguration.LegacySetting.Version) != null); hasKeyTexture = new Lazy(() => { - string keyImage = this.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.KeyImage, new StageDefinition(), 0)?.Value ?? "mania-key1"; + string keyImage = this.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.KeyImage, new StageDefinition { Columns = 1 }, 0)?.Value ?? "mania-key1"; return this.GetAnimation(keyImage, true, true) != null; }); } @@ -149,7 +144,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy public override IBindable GetConfig(TLookup lookup) { if (lookup is ManiaSkinConfigurationLookup maniaLookup) - return base.GetConfig(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.ColumnIndex)); + return base.GetConfig(new LegacyManiaSkinConfigurationLookup(maniaLookup.StageDefinition.Columns, maniaLookup.Lookup, maniaLookup.ColumnIndex)); return base.GetConfig(lookup); } From 5fe9b953a526447234ed3d83017bc8f259e99e7a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 4 Oct 2022 19:50:55 +0900 Subject: [PATCH 1505/2686] Add back triangles column colours via a transformer --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 4 ++ .../Argon/ManiaArgonSkinTransformer.cs | 3 -- .../Default/ManiaTrianglesSkinTransformer.cs | 42 +++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Skinning/Default/ManiaTrianglesSkinTransformer.cs diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 746dda6733..7be4243ad6 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -27,6 +27,7 @@ using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Skinning.Argon; +using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.Mania.Skinning.Legacy; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; @@ -67,6 +68,9 @@ namespace osu.Game.Rulesets.Mania { switch (skin) { + case TrianglesSkin: + return new ManiaTrianglesSkinTransformer(skin); + case LegacySkin: return new ManiaLegacySkinTransformer(skin); diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index 57a317e87d..ea34d8d4c5 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -50,9 +50,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon // TODO: Add actual colours. return SkinUtils.As(new Bindable(new Color4(RNG.NextSingle() * 0.5f, RNG.NextSingle() * 0.5f, RNG.NextSingle() * 0.5f, 1))); } - - return base.GetConfig(new LegacyManiaSkinConfigurationLookup(maniaLookup.StageDefinition.Columns, maniaLookup.Lookup, - maniaLookup.ColumnIndex)); } return base.GetConfig(lookup); diff --git a/osu.Game.Rulesets.Mania/Skinning/Default/ManiaTrianglesSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Default/ManiaTrianglesSkinTransformer.cs new file mode 100644 index 0000000000..88f1f6ed26 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Default/ManiaTrianglesSkinTransformer.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 System; +using osu.Framework.Bindables; +using osu.Game.Skinning; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Skinning.Default +{ + public class ManiaTrianglesSkinTransformer : SkinTransformer + { + public ManiaTrianglesSkinTransformer(ISkin skin) + : base(skin) + { + } + + private readonly Color4 colourEven = new Color4(6, 84, 0, 255); + private readonly Color4 colourOdd = new Color4(94, 0, 57, 255); + private readonly Color4 colourSpecial = new Color4(0, 48, 63, 255); + + public override IBindable? GetConfig(TLookup lookup) + { + if (lookup is ManiaSkinConfigurationLookup maniaLookup) + { + switch (maniaLookup.Lookup) + { + case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: + int column = maniaLookup.ColumnIndex ?? 0; + + if (maniaLookup.StageDefinition.IsSpecialColumn(column)) + return SkinUtils.As(new Bindable(colourSpecial)); + + int distanceToEdge = Math.Min(column, (maniaLookup.StageDefinition.Columns - 1) - column); + return SkinUtils.As(new Bindable(distanceToEdge % 2 == 0 ? colourOdd : colourEven)); + } + } + + return base.GetConfig(lookup); + } + } +} From 2ae1aef0be4252e8b3bc98d61eea057ad7083d14 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 19:14:31 +0900 Subject: [PATCH 1506/2686] Move column initialisation to ctor and fix remaining tests --- .../Editor/ManiaPlacementBlueprintTestScene.cs | 4 ++++ .../Editor/ManiaSelectionBlueprintTestScene.cs | 2 +- .../Editor/TestSceneManiaBeatSnapGrid.cs | 6 +++--- .../Editor/TestSceneManiaComposeScreen.cs | 2 +- .../Editor/TestSceneManiaHitObjectComposer.cs | 2 +- .../ManiaLegacyReplayTest.cs | 6 +++--- .../ManiaSpecialColumnTest.cs | 5 +---- .../Mods/TestSceneManiaModHoldOff.cs | 2 +- .../Skinning/ColumnTestContainer.cs | 2 +- .../Skinning/ManiaSkinnableTestScene.cs | 4 ++++ .../Skinning/TestSceneBarLine.cs | 2 +- .../Skinning/TestScenePlayfield.cs | 6 +++--- .../Skinning/TestSceneStage.cs | 2 +- .../TestSceneAutoGeneration.cs | 14 +++++++------- osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs | 4 ++++ .../TestSceneDrawableManiaHitObject.cs | 5 +++++ .../TestSceneOutOfOrderHits.cs | 2 +- osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs | 2 +- .../TestSceneTimingBasedNoteColouring.cs | 2 +- .../Beatmaps/ManiaBeatmapConverter.cs | 4 ++-- .../Beatmaps/StageDefinition.cs | 11 ++++++++++- .../Skinning/Legacy/ManiaLegacySkinTransformer.cs | 4 ++-- 22 files changed, 58 insertions(+), 35 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs index 976efc51b2..a759e95d17 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; @@ -30,6 +31,9 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor [Cached(typeof(IScrollingInfo))] private IScrollingInfo scrollingInfo; + [Cached] + private readonly StageDefinition stage = new StageDefinition(5); + protected ManiaPlacementBlueprintTestScene() { scrollingInfo = ((ScrollingTestContainer)HitObjectContainer).ScrollingInfo; diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs index 679a15e8cb..4cadcf138b 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor protected ManiaSelectionBlueprintTestScene(int columns) { - var stageDefinitions = new List { new StageDefinition { Columns = columns } }; + var stageDefinitions = new List { new StageDefinition(columns) }; base.Content.Child = scrollingTestContainer = new ScrollingTestContainer(ScrollingDirection.Up) { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs index ec96205067..ef140995ec 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor private ScrollingTestContainer.TestScrollingInfo scrollingInfo = new ScrollingTestContainer.TestScrollingInfo(); [Cached(typeof(EditorBeatmap))] - private EditorBeatmap editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition()) + private EditorBeatmap editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition(2)) { BeatmapInfo = { @@ -56,8 +56,8 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor { Playfield = new ManiaPlayfield(new List { - new StageDefinition { Columns = 4 }, - new StageDefinition { Columns = 3 } + new StageDefinition(4), + new StageDefinition(3) }) { Clock = new FramedClock(new StopwatchClock()) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs index e96a186ae4..e082b90d3b 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor { AddStep("setup compose screen", () => { - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 4 }) + var beatmap = new ManiaBeatmap(new StageDefinition(4)) { BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo }, }; diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs index fcc9e2e6c3..a3985be936 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs @@ -205,7 +205,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor { InternalChildren = new Drawable[] { - EditorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 }) + EditorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition(4)) { BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo } }), diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaLegacyReplayTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaLegacyReplayTest.cs index b64006316e..7d1a934456 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaLegacyReplayTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaLegacyReplayTest.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Tests [TestCase(ManiaAction.Key8)] public void TestEncodeDecodeSingleStage(params ManiaAction[] actions) { - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 9 }); + var beatmap = new ManiaBeatmap(new StageDefinition(9)); var frame = new ManiaReplayFrame(0, actions); var legacyFrame = frame.ToLegacy(beatmap); @@ -38,8 +38,8 @@ namespace osu.Game.Rulesets.Mania.Tests [TestCase(ManiaAction.Key8)] public void TestEncodeDecodeDualStage(params ManiaAction[] actions) { - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 5 }); - beatmap.Stages.Add(new StageDefinition { Columns = 5 }); + var beatmap = new ManiaBeatmap(new StageDefinition(5)); + beatmap.Stages.Add(new StageDefinition(5)); var frame = new ManiaReplayFrame(0, actions); var legacyFrame = frame.ToLegacy(beatmap); diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs index c83e8a51ed..3bd654e75e 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaSpecialColumnTest.cs @@ -35,10 +35,7 @@ namespace osu.Game.Rulesets.Mania.Tests }, 7)] public void Test(IEnumerable special, int columns) { - var definition = new StageDefinition - { - Columns = columns - }; + var definition = new StageDefinition(columns); var results = getResults(definition); Assert.AreEqual(special, results); } diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs index 7970d5b594..d27a79c41d 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Mods private static ManiaBeatmap createRawBeatmap() { - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 }); + var beatmap = new ManiaBeatmap(new StageDefinition(1)); beatmap.ControlPointInfo.Add(0.0, new TimingControlPoint { BeatLength = 1000 }); // Set BPM to 60 // Add test hit objects diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs index 8f6a8c42b1..6fdf32dfbe 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning private readonly Column column; [Cached] - private readonly StageDefinition stageDefinition = new StageDefinition { Columns = 2 }; + private readonly StageDefinition stageDefinition = new StageDefinition(5); public ColumnTestContainer(int column, ManiaAction action, bool showColumn = false) { diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs index 9f235689b4..2c5535a65f 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs @@ -9,6 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling.Algorithms; using osu.Game.Tests.Visual; @@ -24,6 +25,9 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [Cached(Type = typeof(IScrollingInfo))] private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo(); + [Cached] + private readonly StageDefinition stage = new StageDefinition(4); + protected override Ruleset CreateRulesetForSkinProvider() => new ManiaRuleset(); protected ManiaSkinnableTestScene() diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs index ff557638a9..1bfe55b074 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning { var stageDefinitions = new List { - new StageDefinition { Columns = 4 }, + new StageDefinition(4), }; SetContents(_ => new ManiaPlayfield(stageDefinitions).With(s => diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs index 62dadbc3dd..9817719c94 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning { stageDefinitions = new List { - new StageDefinition { Columns = 2 } + new StageDefinition(2) }; SetContents(_ => new ManiaPlayfield(stageDefinitions)); @@ -36,8 +36,8 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning { stageDefinitions = new List { - new StageDefinition { Columns = 2 }, - new StageDefinition { Columns = 2 } + new StageDefinition(2), + new StageDefinition(2) }; SetContents(_ => new ManiaPlayfield(stageDefinitions)); diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs index f3f1b9416f..07aa0b845f 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning return new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4) { - Child = new Stage(0, new StageDefinition { Columns = 4 }, ref normalAction, ref specialAction) + Child = new Stage(0, new StageDefinition(4), ref normalAction, ref specialAction) }; }); } diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs index 21ec85bbe6..3abeb8a5f6 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Tests // | - | // | | - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 }); + var beatmap = new ManiaBeatmap(new StageDefinition(1)); beatmap.HitObjects.Add(new Note { StartTime = 1000 }); var generated = new ManiaAutoGenerator(beatmap).Generate(); @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mania.Tests // | * | // | | - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 }); + var beatmap = new ManiaBeatmap(new StageDefinition(1)); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); var generated = new ManiaAutoGenerator(beatmap).Generate(); @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mania.Tests // | - | - | // | | | - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 }); + var beatmap = new ManiaBeatmap(new StageDefinition(2)); beatmap.HitObjects.Add(new Note { StartTime = 1000 }); beatmap.HitObjects.Add(new Note { StartTime = 1000, Column = 1 }); @@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Mania.Tests // | * | * | // | | | - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 }); + var beatmap = new ManiaBeatmap(new StageDefinition(2)); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000, Column = 1 }); @@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.Mania.Tests // | - | | // | | | - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 }); + var beatmap = new ManiaBeatmap(new StageDefinition(2)); beatmap.HitObjects.Add(new Note { StartTime = 1000 }); beatmap.HitObjects.Add(new Note { StartTime = 2000, Column = 1 }); @@ -142,7 +142,7 @@ namespace osu.Game.Rulesets.Mania.Tests // | * | | // | | | - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 }); + var beatmap = new ManiaBeatmap(new StageDefinition(2)); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); beatmap.HitObjects.Add(new HoldNote { StartTime = 2000, Duration = 2000, Column = 1 }); @@ -169,7 +169,7 @@ namespace osu.Game.Rulesets.Mania.Tests // | * | | // | | | - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 }); + var beatmap = new ManiaBeatmap(new StageDefinition(2)); beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 }); beatmap.HitObjects.Add(new Note { StartTime = 3000, Column = 1 }); diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs index 8fff87ae78..3bac3c7650 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs @@ -11,6 +11,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; @@ -28,6 +29,9 @@ namespace osu.Game.Rulesets.Mania.Tests [Cached(typeof(IReadOnlyList))] private IReadOnlyList mods { get; set; } = Array.Empty(); + [Cached] + private readonly StageDefinition stage = new StageDefinition(1); + private readonly List columns = new List(); public TestSceneColumn() diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs index bd34f1ef11..ea033082a7 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs @@ -4,11 +4,13 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.UI; @@ -24,6 +26,9 @@ namespace osu.Game.Rulesets.Mania.Tests private Column column; + [Cached] + private readonly StageDefinition stage = new StageDefinition(1); + [SetUp] public void SetUp() => Schedule(() => { diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs index a563dc3106..1f139b5b78 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs @@ -141,7 +141,7 @@ namespace osu.Game.Rulesets.Mania.Tests { AddStep("load player", () => { - Beatmap.Value = CreateWorkingBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 }) + Beatmap.Value = CreateWorkingBeatmap(new ManiaBeatmap(new StageDefinition(4)) { HitObjects = hitObjects, BeatmapInfo = diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs index cf8947c1ed..6387dac957 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs @@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Mania.Tests { var specialAction = ManiaAction.Special1; - var stage = new Stage(0, new StageDefinition { Columns = 2 }, ref action, ref specialAction); + var stage = new Stage(0, new StageDefinition(2), ref action, ref specialAction); stages.Add(stage); return new ScrollingTestContainer(direction) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs index e84d02775a..9f2e3d2502 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs @@ -85,7 +85,7 @@ namespace osu.Game.Rulesets.Mania.Tests { const double beat_length = 500; - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 }) + var beatmap = new ManiaBeatmap(new StageDefinition(1)) { HitObjects = { diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs index 90cd7f57b5..632b7cdcc7 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs @@ -93,10 +93,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps protected override Beatmap CreateBeatmap() { - beatmap = new ManiaBeatmap(new StageDefinition { Columns = TargetColumns }, originalTargetColumns); + beatmap = new ManiaBeatmap(new StageDefinition(TargetColumns), originalTargetColumns); if (Dual) - beatmap.Stages.Add(new StageDefinition { Columns = TargetColumns }); + beatmap.Stages.Add(new StageDefinition(TargetColumns)); return beatmap; } diff --git a/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs b/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs index 08ee97b32b..898b558eb3 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/StageDefinition.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Beatmaps @@ -15,7 +16,15 @@ namespace osu.Game.Rulesets.Mania.Beatmaps /// /// The number of s which this stage contains. /// - public int Columns; + public readonly int Columns; + + public StageDefinition(int columns) + { + if (columns < 1) + throw new ArgumentException("Column count must be above zero.", nameof(columns)); + + Columns = columns; + } /// /// Whether the column index is a special column for this stage. diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 0a59c10b5f..1c06f3cffb 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy isLegacySkin = new Lazy(() => GetConfig(SkinConfiguration.LegacySetting.Version) != null); hasKeyTexture = new Lazy(() => { - string keyImage = this.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.KeyImage, new StageDefinition { Columns = 1 }, 0)?.Value ?? "mania-key1"; + string keyImage = this.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.KeyImage, new StageDefinition(1), 0)?.Value ?? "mania-key1"; return this.GetAnimation(keyImage, true, true) != null; }); } @@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy if (!hit_result_mapping.ContainsKey(result)) return null; - string filename = this.GetManiaSkinConfig(hit_result_mapping[result], new StageDefinition())?.Value + string filename = this.GetManiaSkinConfig(hit_result_mapping[result], new StageDefinition(1))?.Value ?? default_hit_result_skin_filenames[result]; var animation = this.GetAnimation(filename, true, true); From 3947011baf594cec7b6f7ab4984f22d75e5305b9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 19:21:38 +0900 Subject: [PATCH 1507/2686] Fix regression in legacy dual stage handling logic --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 6 +++--- .../Skinning/Legacy/ManiaLegacySkinTransformer.cs | 9 +++++++-- .../Skinning/LegacyManiaSkinConfigurationLookup.cs | 12 +++++++----- osu.Game/Skinning/LegacySkin.cs | 4 ++-- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 7be4243ad6..9d2182f276 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -71,11 +71,11 @@ namespace osu.Game.Rulesets.Mania case TrianglesSkin: return new ManiaTrianglesSkinTransformer(skin); - case LegacySkin: - return new ManiaLegacySkinTransformer(skin); - case ArgonSkin: return new ManiaArgonSkinTransformer(skin); + + case LegacySkin: + return new ManiaLegacySkinTransformer(skin, beatmap); } return null; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 1c06f3cffb..5a0478f025 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -9,6 +9,7 @@ using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Audio; +using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Scoring; @@ -56,9 +57,13 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy /// private readonly Lazy hasKeyTexture; - public ManiaLegacySkinTransformer(ISkin skin) + private readonly ManiaBeatmap beatmap; + + public ManiaLegacySkinTransformer(ISkin skin, IBeatmap beatmap) : base(skin) { + this.beatmap = (ManiaBeatmap)beatmap; + isLegacySkin = new Lazy(() => GetConfig(SkinConfiguration.LegacySetting.Version) != null); hasKeyTexture = new Lazy(() => { @@ -144,7 +149,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy public override IBindable GetConfig(TLookup lookup) { if (lookup is ManiaSkinConfigurationLookup maniaLookup) - return base.GetConfig(new LegacyManiaSkinConfigurationLookup(maniaLookup.StageDefinition.Columns, maniaLookup.Lookup, maniaLookup.ColumnIndex)); + return base.GetConfig(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.ColumnIndex)); return base.GetConfig(lookup); } diff --git a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs index 45454be4a5..8e786c96d9 100644 --- a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs +++ b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs @@ -1,19 +1,21 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - namespace osu.Game.Skinning { public class LegacyManiaSkinConfigurationLookup { - public readonly int Keys; + /// + /// Total columns across all stages. + /// + public readonly int TotalColumns; + public readonly LegacyManiaSkinConfigurationLookups Lookup; public readonly int? TargetColumn; - public LegacyManiaSkinConfigurationLookup(int keys, LegacyManiaSkinConfigurationLookups lookup, int? targetColumn = null) + public LegacyManiaSkinConfigurationLookup(int totalColumns, LegacyManiaSkinConfigurationLookups lookup, int? targetColumn = null) { - Keys = keys; + TotalColumns = totalColumns; Lookup = lookup; TargetColumn = targetColumn; } diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 1e096702b3..e1a630b643 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -128,8 +128,8 @@ namespace osu.Game.Skinning private IBindable? lookupForMania(LegacyManiaSkinConfigurationLookup maniaLookup) { - if (!maniaConfigurations.TryGetValue(maniaLookup.Keys, out var existing)) - maniaConfigurations[maniaLookup.Keys] = existing = new LegacyManiaSkinConfiguration(maniaLookup.Keys); + if (!maniaConfigurations.TryGetValue(maniaLookup.TotalColumns, out var existing)) + maniaConfigurations[maniaLookup.TotalColumns] = existing = new LegacyManiaSkinConfiguration(maniaLookup.TotalColumns); switch (maniaLookup.Lookup) { From 276395f1afebe3902aa57245a4ccddd65b52d1cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 19:51:18 +0900 Subject: [PATCH 1508/2686] Fix column colour not updating on skin change --- osu.Game.Rulesets.Mania/UI/Column.cs | 31 +++++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 75d6d4c206..8c50ab919b 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -65,14 +65,17 @@ namespace osu.Game.Rulesets.Mania.UI HitObjectArea = new ColumnHitObjectArea(HitObjectContainer) { RelativeSizeAxes = Axes.Both }; } - [BackgroundDependencyLoader] - private void load(ISkinSource skin, StageDefinition stageDefinition) - { - AccentColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, stageDefinition, Index)?.Value ?? Color4.Black; + [Resolved] + private ISkinSource skin { get; set; } - //AccentColour = columnColours[isSpecial], - foreach (var obj in HitObjectContainer.Objects) - obj.AccentColour.Value = AccentColour; + [Resolved] + private StageDefinition stageDefinition { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + skin.SourceChanged += onSourceChanged; + onSourceChanged(); Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { @@ -104,13 +107,25 @@ namespace osu.Game.Rulesets.Mania.UI RegisterPool(50, 250); } + private void onSourceChanged() + { + AccentColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, stageDefinition, Index)?.Value ?? Color4.Black; + foreach (var obj in HitObjectContainer.Objects) + obj.AccentColour.Value = AccentColour; + } + protected override void LoadComplete() { base.LoadComplete(); - NewResult += OnNewResult; } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + skin.SourceChanged += onSourceChanged; + } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); From 532d101080e04405149a43c873f99aa4ba10dd5e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 19:58:39 +0900 Subject: [PATCH 1509/2686] Remove unused class --- .../UI/Components/ColumnBackground.cs | 110 ------------------ 1 file changed, 110 deletions(-) delete mode 100644 osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs deleted file mode 100644 index 5bd2d3ab48..0000000000 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Rulesets.UI.Scrolling; -using osuTK.Graphics; - -namespace osu.Game.Rulesets.Mania.UI.Components -{ - public class ColumnBackground : CompositeDrawable, IKeyBindingHandler, IHasAccentColour - { - private readonly IBindable action = new Bindable(); - - private Box background; - private Box backgroundOverlay; - - private readonly IBindable direction = new Bindable(); - - [BackgroundDependencyLoader] - private void load(IBindable action, IScrollingInfo scrollingInfo) - { - this.action.BindTo(action); - - InternalChildren = new[] - { - background = new Box - { - Name = "Background", - RelativeSizeAxes = Axes.Both, - }, - backgroundOverlay = new Box - { - Name = "Background Gradient Overlay", - RelativeSizeAxes = Axes.Both, - Height = 0.5f, - Blending = BlendingParameters.Additive, - Alpha = 0 - } - }; - - direction.BindTo(scrollingInfo.Direction); - direction.BindValueChanged(dir => - { - backgroundOverlay.Anchor = backgroundOverlay.Origin = dir.NewValue == ScrollingDirection.Up ? Anchor.TopLeft : Anchor.BottomLeft; - updateColours(); - }, true); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - updateColours(); - } - - private Color4 accentColour; - - public Color4 AccentColour - { - get => accentColour; - set - { - if (accentColour == value) - return; - - accentColour = value; - - updateColours(); - } - } - - private void updateColours() - { - if (!IsLoaded) - return; - - background.Colour = AccentColour.Darken(5); - - var brightPoint = AccentColour.Opacity(0.6f); - var dimPoint = AccentColour.Opacity(0); - - backgroundOverlay.Colour = ColourInfo.GradientVertical( - direction.Value == ScrollingDirection.Up ? brightPoint : dimPoint, - direction.Value == ScrollingDirection.Up ? dimPoint : brightPoint); - } - - public bool OnPressed(KeyBindingPressEvent e) - { - if (e.Action == action.Value) - backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint); - return false; - } - - public void OnReleased(KeyBindingReleaseEvent e) - { - if (e.Action == action.Value) - backgroundOverlay.FadeTo(0, 250, Easing.OutQuint); - } - } -} From 6b79f164612c9d4a9608650d4954d82e06b84773 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 20:02:02 +0900 Subject: [PATCH 1510/2686] Make `Column.AccentColour` bindable --- .../ManiaPlacementBlueprintTestScene.cs | 2 +- .../Skinning/ColumnTestContainer.cs | 2 +- .../TestSceneColumn.cs | 2 +- .../TestSceneDrawableManiaHitObject.cs | 2 +- .../Skinning/Argon/ArgonKeyArea.cs | 23 +++--- osu.Game.Rulesets.Mania/UI/Column.cs | 15 ++-- .../UI/Components/DefaultColumnBackground.cs | 12 +++- .../UI/Components/DefaultHitTarget.cs | 16 +++-- .../UI/Components/DefaultKeyArea.cs | 20 ++++-- .../UI/DefaultHitExplosion.cs | 71 ++++++++++--------- 10 files changed, 101 insertions(+), 64 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs index a759e95d17..0e4f612999 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor { Anchor = Anchor.Centre, Origin = Anchor.Centre, - AccentColour = Color4.OrangeRed, + AccentColour = { Value = Color4.OrangeRed }, Clock = new FramedClock(new StopwatchClock()), // No scroll }); } diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs index 6fdf32dfbe..cefcce8319 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning this.column = new Column(column, false) { Action = { Value = action }, - AccentColour = Color4.Orange, + AccentColour = { Value = Color4.Orange }, Alpha = showColumn ? 1 : 0 }, content = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs index 3bac3c7650..83491b6fe9 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Mania.Tests Anchor = Anchor.Centre, Origin = Anchor.Centre, Height = 0.85f, - AccentColour = Color4.OrangeRed, + AccentColour = { Value = Color4.OrangeRed }, Action = { Value = action }, }; diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs index ea033082a7..d273f5cb35 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Mania.Tests { Action = { Value = ManiaAction.Key1 }, Height = 0.85f, - AccentColour = Color4.Gray + AccentColour = { Value = Color4.Gray }, }, }; }); diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index 0153cdbd68..9d16e84f1e 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon private Container bottomIcon = null!; private CircularContainer topIcon = null!; + private Bindable accentColour = null!; + [Resolved] private Column column { get; set; } = null!; @@ -55,7 +57,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { Name = "Key gradient", RelativeSizeAxes = Axes.Both, - Colour = column.AccentColour.Darken(0.6f), }, hitTargetLine = new Circle { @@ -80,7 +81,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, Blending = BlendingParameters.Additive, - Colour = column.AccentColour, Y = icon_vertical_offset, Children = new[] { @@ -134,6 +134,13 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(onDirectionChanged, true); + + accentColour = column.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(colour => + { + background.Colour = colour.NewValue.Darken(0.6f); + bottomIcon.Colour = colour.NewValue; + }, true); } private void onDirectionChanged(ValueChangedEvent direction) @@ -159,11 +166,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon if (e.Action != column.Action.Value) return false; const double lighting_fade_in_duration = 50; - Color4 lightingColour = column.AccentColour.Lighten(0.9f); + Color4 lightingColour = accentColour.Value.Lighten(0.9f); background - .FadeColour(column.AccentColour.Lighten(0.4f), 40).Then() - .FadeColour(column.AccentColour, 150, Easing.OutQuint); + .FadeColour(accentColour.Value.Lighten(0.4f), 40).Then() + .FadeColour(accentColour.Value, 150, Easing.OutQuint); hitTargetLine.FadeColour(Color4.White, lighting_fade_in_duration, Easing.OutQuint); hitTargetLine.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters @@ -201,9 +208,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon if (e.Action != column.Action.Value) return; const double lighting_fade_out_duration = 300; - Color4 lightingColour = column.AccentColour.Lighten(0.9f).Opacity(0); + Color4 lightingColour = accentColour.Value.Lighten(0.9f).Opacity(0); - background.FadeColour(column.AccentColour.Darken(0.6f), lighting_fade_out_duration, Easing.OutQuint); + background.FadeColour(accentColour.Value.Darken(0.6f), lighting_fade_out_duration, Easing.OutQuint); topIcon.ScaleTo(1f, 200, Easing.OutQuint); topIcon.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters @@ -221,7 +228,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Radius = 30, }, lighting_fade_out_duration, Easing.OutQuint); - bottomIcon.FadeColour(column.AccentColour, lighting_fade_out_duration, Easing.OutQuint); + bottomIcon.FadeColour(accentColour.Value, lighting_fade_out_duration, Easing.OutQuint); foreach (var circle in bottomIcon) { diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 8c50ab919b..81d9ae28ab 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Mania.UI ///
public readonly bool IsSpecial; - public Color4 AccentColour { get; set; } + public readonly Bindable AccentColour = new Bindable(Color4.Black); public Column(int index, bool isSpecial) { @@ -77,6 +77,13 @@ namespace osu.Game.Rulesets.Mania.UI skin.SourceChanged += onSourceChanged; onSourceChanged(); + AccentColour.BindValueChanged(colour => + { + // Manual transfer as hit objects may be moved between column and unbinding is non-trivial. + foreach (var obj in HitObjectContainer.Objects) + obj.AccentColour.Value = colour.NewValue; + }, true); + Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both @@ -109,9 +116,7 @@ namespace osu.Game.Rulesets.Mania.UI private void onSourceChanged() { - AccentColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, stageDefinition, Index)?.Value ?? Color4.Black; - foreach (var obj in HitObjectContainer.Objects) - obj.AccentColour.Value = AccentColour; + AccentColour.Value = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, stageDefinition, Index)?.Value ?? Color4.Black; } protected override void LoadComplete() @@ -139,7 +144,7 @@ namespace osu.Game.Rulesets.Mania.UI DrawableManiaHitObject maniaObject = (DrawableManiaHitObject)drawableHitObject; - maniaObject.AccentColour.Value = AccentColour; + maniaObject.AccentColour.Value = AccentColour.Value; maniaObject.CheckHittable = hitPolicy.IsHittable; } diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs index 39d17db6be..3680e7ea0a 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs @@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components [Resolved] private Column column { get; set; } + private Bindable accentColour; + public DefaultColumnBackground() { RelativeSizeAxes = Axes.Both; @@ -55,9 +57,13 @@ namespace osu.Game.Rulesets.Mania.UI.Components } }; - background.Colour = column.AccentColour.Darken(5); - brightColour = column.AccentColour.Opacity(0.6f); - dimColour = column.AccentColour.Opacity(0); + accentColour = column.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(colour => + { + background.Colour = colour.NewValue.Darken(5); + brightColour = colour.NewValue.Opacity(0.6f); + dimColour = colour.NewValue.Opacity(0); + }, true); direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(onDirectionChanged, true); diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs index 53fa86125f..97aa897782 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs @@ -25,6 +25,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components private Container hitTargetLine; private Drawable hitTargetBar; + private Bindable accentColour; + [Resolved] private Column column { get; set; } @@ -54,12 +56,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components }, }; - hitTargetLine.EdgeEffect = new EdgeEffectParameters + accentColour = column.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(colour => { - Type = EdgeEffectType.Glow, - Radius = 5, - Colour = column.AccentColour.Opacity(0.5f), - }; + hitTargetLine.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Radius = 5, + Colour = colour.NewValue.Opacity(0.5f), + }; + }, true); direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(onDirectionChanged, true); diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs index 5a0fab2ff4..6196850f91 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs @@ -30,6 +30,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components private Container keyIcon; private Drawable gradient; + private Bindable accentColour; + [Resolved] private Column column { get; set; } @@ -75,15 +77,19 @@ namespace osu.Game.Rulesets.Mania.UI.Components } }; - keyIcon.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Radius = 5, - Colour = column.AccentColour.Opacity(0.5f), - }; - direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(onDirectionChanged, true); + + accentColour = column.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(colour => + { + keyIcon.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Radius = 5, + Colour = colour.NewValue.Opacity(0.5f), + }; + }); } private void onDirectionChanged(ValueChangedEvent direction) diff --git a/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs index e83cd10d2d..59716ee3e2 100644 --- a/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs @@ -32,6 +32,10 @@ namespace osu.Game.Rulesets.Mania.UI private CircularContainer largeFaint; private CircularContainer mainGlow1; + private CircularContainer mainGlow2; + private CircularContainer mainGlow3; + + private Bindable accentColour; public DefaultHitExplosion() { @@ -48,8 +52,6 @@ namespace osu.Game.Rulesets.Mania.UI const float roundness = 80; const float initial_height = 10; - var colour = Interpolation.ValueAt(0.4f, column.AccentColour, Color4.White, 0, 1); - InternalChildren = new Drawable[] { largeFaint = new CircularContainer @@ -61,13 +63,6 @@ namespace osu.Game.Rulesets.Mania.UI // we want our size to be very small so the glow dominates it. Size = new Vector2(default_large_faint_size), Blending = BlendingParameters.Additive, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = Interpolation.ValueAt(0.1f, column.AccentColour, Color4.White, 0, 1).Opacity(0.3f), - Roundness = 160, - Radius = 200, - }, }, mainGlow1 = new CircularContainer { @@ -76,15 +71,8 @@ namespace osu.Game.Rulesets.Mania.UI RelativeSizeAxes = Axes.Both, Masking = true, Blending = BlendingParameters.Additive, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = Interpolation.ValueAt(0.6f, column.AccentColour, Color4.White, 0, 1), - Roundness = 20, - Radius = 50, - }, }, - new CircularContainer + mainGlow2 = new CircularContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -93,15 +81,8 @@ namespace osu.Game.Rulesets.Mania.UI Size = new Vector2(0.01f, initial_height), Blending = BlendingParameters.Additive, Rotation = RNG.NextSingle(-angle_variance, angle_variance), - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = colour, - Roundness = roundness, - Radius = 40, - }, }, - new CircularContainer + mainGlow3 = new CircularContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -110,18 +91,44 @@ namespace osu.Game.Rulesets.Mania.UI Size = new Vector2(0.01f, initial_height), Blending = BlendingParameters.Additive, Rotation = RNG.NextSingle(-angle_variance, angle_variance), - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = colour, - Roundness = roundness, - Radius = 40, - }, } }; direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(onDirectionChanged, true); + + accentColour = column.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(colour => + { + largeFaint.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Interpolation.ValueAt(0.1f, colour.NewValue, Color4.White, 0, 1).Opacity(0.3f), + Roundness = 160, + Radius = 200, + }; + mainGlow1.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Interpolation.ValueAt(0.6f, colour.NewValue, Color4.White, 0, 1), + Roundness = 20, + Radius = 50, + }; + mainGlow2.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Interpolation.ValueAt(0.4f, colour.NewValue, Color4.White, 0, 1), + Roundness = roundness, + Radius = 40, + }; + mainGlow3.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Interpolation.ValueAt(0.4f, colour.NewValue, Color4.White, 0, 1), + Roundness = roundness, + Radius = 40, + }; + }, true); } private void onDirectionChanged(ValueChangedEvent direction) From 4a127f5d8123d5ed782505c1f3d9ae8ae5817a23 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 5 Oct 2022 22:41:20 +0900 Subject: [PATCH 1511/2686] Fix classic skin colours sourcing from triangles defaults --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 3 ++ .../Legacy/ManiaClassicSkinTransformer.cs | 38 +++++++++++++++++++ .../Legacy/ManiaLegacySkinTransformer.cs | 17 ++++++++- 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaClassicSkinTransformer.cs diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 9d2182f276..c4a8b7c8fa 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -74,6 +74,9 @@ namespace osu.Game.Rulesets.Mania case ArgonSkin: return new ManiaArgonSkinTransformer(skin); + case DefaultLegacySkin: + return new ManiaClassicSkinTransformer(skin, beatmap); + case LegacySkin: return new ManiaLegacySkinTransformer(skin, beatmap); } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaClassicSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaClassicSkinTransformer.cs new file mode 100644 index 0000000000..e57927897c --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaClassicSkinTransformer.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.Framework.Bindables; +using osu.Game.Beatmaps; +using osu.Game.Skinning; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Skinning.Legacy +{ + public class ManiaClassicSkinTransformer : ManiaLegacySkinTransformer + { + public ManiaClassicSkinTransformer(ISkin skin, IBeatmap beatmap) + : base(skin, beatmap) + { + } + + public override IBindable GetConfig(TLookup lookup) + { + if (lookup is ManiaSkinConfigurationLookup maniaLookup) + { + var baseLookup = base.GetConfig(lookup); + + if (baseLookup != null) + return baseLookup; + + // default provisioning. + switch (maniaLookup.Lookup) + { + case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: + return SkinUtils.As(new Bindable(Color4.Black)); + } + } + + return base.GetConfig(lookup); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 5a0478f025..759a1c2b38 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -8,12 +8,14 @@ using System.Collections.Generic; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; +using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { @@ -149,7 +151,20 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy public override IBindable GetConfig(TLookup lookup) { if (lookup is ManiaSkinConfigurationLookup maniaLookup) - return base.GetConfig(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.ColumnIndex)); + { + var legacyLookup = + base.GetConfig(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.ColumnIndex)); + + if (legacyLookup != null) + return legacyLookup; + + // default legacy fallback. + switch (maniaLookup.Lookup) + { + case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: + return SkinUtils.As(new Bindable(Color4.Black)); + } + } return base.GetConfig(lookup); } From 0d21c0e49c682040034b97ee640cfbcbf6252403 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 14:10:39 +0900 Subject: [PATCH 1512/2686] Remove `StageDefinition` from configuration lookups I added this for future usage, but it turns out I can get the definitions directly from `ManiaBeatmap`. --- .../Skinning/Legacy/HitTargetInsetContainer.cs | 5 ++--- .../Skinning/Legacy/LegacyColumnBackground.cs | 5 ++--- .../Skinning/Legacy/LegacyHitTarget.cs | 9 ++++----- .../Skinning/Legacy/LegacyManiaColumnElement.cs | 2 +- .../Skinning/Legacy/LegacyManiaJudgementPiece.cs | 5 ++--- .../Skinning/Legacy/LegacyNotePiece.cs | 5 ++--- .../Skinning/Legacy/LegacyStageBackground.cs | 14 +++++++------- .../Skinning/Legacy/LegacyStageForeground.cs | 5 ++--- .../Skinning/Legacy/ManiaLegacySkinTransformer.cs | 4 ++-- .../Skinning/ManiaSkinConfigExtensions.cs | 6 ++---- .../Skinning/ManiaSkinConfigurationLookup.cs | 10 +--------- osu.Game.Rulesets.Mania/UI/ColumnFlow.cs | 4 ++-- .../UI/Components/HitObjectArea.cs | 6 +----- 13 files changed, 30 insertions(+), 50 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs index de6d048295..362a265789 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; @@ -31,9 +30,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, IScrollingInfo scrollingInfo, StageDefinition stageDefinition) + private void load(ISkinSource skin, IScrollingInfo scrollingInfo) { - hitPosition = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.HitPosition, stageDefinition)?.Value ?? Stage.HIT_TARGET_POSITION; + hitPosition = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.HitPosition)?.Value ?? Stage.HIT_TARGET_POSITION; direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(onDirectionChanged, true); diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs index 08fa9b9a73..f35cedab08 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; @@ -31,9 +30,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, IScrollingInfo scrollingInfo, StageDefinition stageDefinition) + private void load(ISkinSource skin, IScrollingInfo scrollingInfo) { - string lightImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LightImage, stageDefinition)?.Value + string lightImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LightImage)?.Value ?? "mania-stage-light"; float lightPosition = GetColumnSkinConfig(skin, LegacyManiaSkinConfigurationLookups.LightPosition)?.Value diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs index 9819f09e10..611dac30b3 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; @@ -24,15 +23,15 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy private Container directionContainer; [BackgroundDependencyLoader] - private void load(ISkinSource skin, IScrollingInfo scrollingInfo, StageDefinition stageDefinition) + private void load(ISkinSource skin, IScrollingInfo scrollingInfo) { - string targetImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.HitTargetImage, stageDefinition)?.Value + string targetImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.HitTargetImage)?.Value ?? "mania-stage-hint"; - bool showJudgementLine = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ShowJudgementLine, stageDefinition)?.Value + bool showJudgementLine = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ShowJudgementLine)?.Value ?? true; - Color4 lineColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.JudgementLineColour, stageDefinition)?.Value + Color4 lineColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.JudgementLineColour)?.Value ?? Color4.White; InternalChild = directionContainer = new Container diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs index cfebad4add..e227c80845 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs @@ -42,6 +42,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } protected IBindable GetColumnSkinConfig(ISkin skin, LegacyManiaSkinConfigurationLookups lookup) - => skin.GetManiaSkinConfig(lookup, stage, Column.Index); + => skin.GetManiaSkinConfig(lookup, Column.Index); } } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs index f9653dab15..d09a73a693 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; @@ -33,9 +32,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, StageDefinition stageDefinition) + private void load(ISkinSource skin) { - float? scorePosition = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ScorePosition, stageDefinition)?.Value; + float? scorePosition = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ScorePosition)?.Value; if (scorePosition != null) scorePosition -= Stage.HIT_TARGET_POSITION + 150; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs index 779e1a152c..41e149ea2f 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; @@ -36,9 +35,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, IScrollingInfo scrollingInfo, StageDefinition stageDefinition) + private void load(ISkinSource skin, IScrollingInfo scrollingInfo) { - minimumColumnWidth = skin.GetConfig(new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.MinimumColumnWidth, stageDefinition))?.Value; + minimumColumnWidth = skin.GetConfig(new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.MinimumColumnWidth))?.Value; InternalChild = directionContainer = new Container { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs index 01c2b599fa..d039551cd7 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs @@ -30,10 +30,10 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy [BackgroundDependencyLoader] private void load(ISkinSource skin, StageDefinition stageDefinition) { - string leftImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LeftStageImage, stageDefinition)?.Value + string leftImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LeftStageImage)?.Value ?? "mania-stage-left"; - string rightImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.RightStageImage, stageDefinition)?.Value + string rightImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.RightStageImage)?.Value ?? "mania-stage-right"; InternalChildren = new[] @@ -91,16 +91,16 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, StageDefinition stageDefinition) + private void load(ISkinSource skin) { - float leftLineWidth = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LeftLineWidth, stageDefinition, columnIndex)?.Value ?? 1; - float rightLineWidth = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.RightLineWidth, stageDefinition, columnIndex)?.Value ?? 1; + float leftLineWidth = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.LeftLineWidth, columnIndex)?.Value ?? 1; + float rightLineWidth = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.RightLineWidth, columnIndex)?.Value ?? 1; bool hasLeftLine = leftLineWidth > 0; bool hasRightLine = (rightLineWidth > 0 && skin.GetConfig(SkinConfiguration.LegacySetting.Version)?.Value >= 2.4m) || isLastColumn; - Color4 lineColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnLineColour, stageDefinition, columnIndex)?.Value ?? Color4.White; - Color4 backgroundColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, stageDefinition, columnIndex)?.Value ?? Color4.Black; + Color4 lineColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnLineColour, columnIndex)?.Value ?? Color4.White; + Color4 backgroundColour = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, columnIndex)?.Value ?? Color4.Black; InternalChildren = new Drawable[] { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs index 57b76c5402..f7c611d551 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Skinning; using osuTK; @@ -26,9 +25,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ISkinSource skin, IScrollingInfo scrollingInfo, StageDefinition stageDefinition) + private void load(ISkinSource skin, IScrollingInfo scrollingInfo) { - string bottomImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.BottomStageImage, stageDefinition)?.Value + string bottomImage = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.BottomStageImage)?.Value ?? "mania-stage-bottom"; sprite = skin.GetAnimation(bottomImage, true, true)?.With(d => diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 759a1c2b38..8dc81f2101 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy isLegacySkin = new Lazy(() => GetConfig(SkinConfiguration.LegacySetting.Version) != null); hasKeyTexture = new Lazy(() => { - string keyImage = this.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.KeyImage, new StageDefinition(1), 0)?.Value ?? "mania-key1"; + string keyImage = this.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.KeyImage, 0)?.Value ?? "mania-key1"; return this.GetAnimation(keyImage, true, true) != null; }); } @@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy if (!hit_result_mapping.ContainsKey(result)) return null; - string filename = this.GetManiaSkinConfig(hit_result_mapping[result], new StageDefinition(1))?.Value + string filename = this.GetManiaSkinConfig(hit_result_mapping[result])?.Value ?? default_hit_result_skin_filenames[result]; var animation = this.GetAnimation(filename, true, true); diff --git a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs index 541b679043..e22bf63049 100644 --- a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs +++ b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs @@ -4,7 +4,6 @@ #nullable disable using osu.Framework.Bindables; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Skinning @@ -16,10 +15,9 @@ namespace osu.Game.Rulesets.Mania.Skinning ///
/// The skin from which configuration is retrieved. /// The value to retrieve. - /// The stage definition. /// If not null, denotes the index of the column to which the entry applies. - public static IBindable GetManiaSkinConfig(this ISkin skin, LegacyManiaSkinConfigurationLookups lookup, StageDefinition stageDefinition, int? columnIndex = null) + public static IBindable GetManiaSkinConfig(this ISkin skin, LegacyManiaSkinConfigurationLookups lookup, int? columnIndex = null) => skin.GetConfig( - new ManiaSkinConfigurationLookup(lookup, stageDefinition, columnIndex)); + new ManiaSkinConfigurationLookup(lookup, columnIndex)); } } diff --git a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs index 8008c988d4..4ec18f9b01 100644 --- a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs +++ b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs @@ -3,7 +3,6 @@ #nullable disable -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.UI; using osu.Game.Skinning; @@ -16,11 +15,6 @@ namespace osu.Game.Rulesets.Mania.Skinning ///
public readonly LegacyManiaSkinConfigurationLookups Lookup; - /// - /// The stage containing the component which is performing this lookup. - /// - public readonly StageDefinition StageDefinition; - /// /// The intended index for the configuration. /// May be null if the configuration does not apply to a . @@ -31,12 +25,10 @@ namespace osu.Game.Rulesets.Mania.Skinning /// Creates a new . /// /// The lookup value. - /// The stage definition. /// The intended index for the configuration. May be null if the configuration does not apply to a . - public ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups lookup, StageDefinition stageDefinition, int? columnIndex = null) + public ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups lookup, int? columnIndex = null) { Lookup = lookup; - StageDefinition = stageDefinition; ColumnIndex = columnIndex; } } diff --git a/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs b/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs index bde2308635..871ec9f1a3 100644 --- a/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs +++ b/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs @@ -65,14 +65,14 @@ namespace osu.Game.Rulesets.Mania.UI if (i > 0) { float spacing = currentSkin.GetConfig( - new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnSpacing, stageDefinition, i - 1)) + new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnSpacing, i - 1)) ?.Value ?? Stage.COLUMN_SPACING; columns[i].Margin = new MarginPadding { Left = spacing }; } float? width = currentSkin.GetConfig( - new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnWidth, stageDefinition, i)) + new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.ColumnWidth, i)) ?.Value; if (width == null) diff --git a/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs index 69bf146951..7f4b8eacde 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Skinning; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; @@ -20,9 +19,6 @@ namespace osu.Game.Rulesets.Mania.UI.Components protected readonly IBindable Direction = new Bindable(); public readonly HitObjectContainer HitObjectContainer; - [Resolved] - private StageDefinition stageDefinition { get; set; } - public HitObjectArea(HitObjectContainer hitObjectContainer) { InternalChild = new Container @@ -53,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components protected virtual void UpdateHitPosition() { float hitPosition = CurrentSkin.GetConfig( - new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.HitPosition, stageDefinition))?.Value + new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.HitPosition))?.Value ?? Stage.HIT_TARGET_POSITION; Padding = Direction.Value == ScrollingDirection.Up From 13e0a59f707e38144bdfc709121f220f1196b360 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 14:19:00 +0900 Subject: [PATCH 1513/2686] Add note about why `LegacyManiaSkinConfigurationLookup` exist --- osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs index 8e786c96d9..6f934d1a92 100644 --- a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs +++ b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs @@ -3,6 +3,11 @@ namespace osu.Game.Skinning { + /// + /// This class exists for the explicit purpose of ferrying information from ManiaBeatmap in a way LegacySkin can use it. + /// This is because half of the mania legacy skin implementation is in LegacySkin (osu.Game project) which doesn't have visibility + /// over ManiaBeatmap / StageDefinition. + /// public class LegacyManiaSkinConfigurationLookup { /// @@ -10,9 +15,10 @@ namespace osu.Game.Skinning /// public readonly int TotalColumns; - public readonly LegacyManiaSkinConfigurationLookups Lookup; public readonly int? TargetColumn; + public readonly LegacyManiaSkinConfigurationLookups Lookup; + public LegacyManiaSkinConfigurationLookup(int totalColumns, LegacyManiaSkinConfigurationLookups lookup, int? targetColumn = null) { TotalColumns = totalColumns; From eea3d5adb827c40bbc1c46cb38011623e1e32a5a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 14:26:29 +0900 Subject: [PATCH 1514/2686] Standardise column index naming and xmldoc --- .../Skinning/ManiaSkinConfigurationLookup.cs | 3 +- .../LegacyManiaSkinConfigurationLookup.cs | 11 +++- osu.Game/Skinning/LegacySkin.cs | 64 +++++++++---------- 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs index 4ec18f9b01..59188f02f9 100644 --- a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs +++ b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs @@ -16,8 +16,9 @@ namespace osu.Game.Rulesets.Mania.Skinning public readonly LegacyManiaSkinConfigurationLookups Lookup; /// - /// The intended index for the configuration. + /// The column which is being looked up. /// May be null if the configuration does not apply to a . + /// Note that this is the absolute index across all stages. /// public readonly int? ColumnIndex; diff --git a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs index 6f934d1a92..c9e96ab3f1 100644 --- a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs +++ b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs @@ -15,15 +15,20 @@ namespace osu.Game.Skinning ///
public readonly int TotalColumns; - public readonly int? TargetColumn; + /// + /// The column which is being looked up. + /// May be null if the configuration does not apply to a specific column. + /// Note that this is the absolute index across all stages. + /// + public readonly int? ColumnIndex; public readonly LegacyManiaSkinConfigurationLookups Lookup; - public LegacyManiaSkinConfigurationLookup(int totalColumns, LegacyManiaSkinConfigurationLookups lookup, int? targetColumn = null) + public LegacyManiaSkinConfigurationLookup(int totalColumns, LegacyManiaSkinConfigurationLookups lookup, int? columnIndex = null) { TotalColumns = totalColumns; Lookup = lookup; - TargetColumn = targetColumn; + ColumnIndex = columnIndex; } } diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index e1a630b643..646746a0f3 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -134,12 +134,12 @@ namespace osu.Game.Skinning switch (maniaLookup.Lookup) { case LegacyManiaSkinConfigurationLookups.ColumnWidth: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(new Bindable(existing.ColumnWidth[maniaLookup.TargetColumn.Value])); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(new Bindable(existing.ColumnWidth[maniaLookup.ColumnIndex.Value])); case LegacyManiaSkinConfigurationLookups.ColumnSpacing: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(new Bindable(existing.ColumnSpacing[maniaLookup.TargetColumn.Value])); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(new Bindable(existing.ColumnSpacing[maniaLookup.ColumnIndex.Value])); case LegacyManiaSkinConfigurationLookups.HitPosition: return SkinUtils.As(new Bindable(existing.HitPosition)); @@ -157,15 +157,15 @@ namespace osu.Game.Skinning return SkinUtils.As(getManiaImage(existing, "LightingN")); case LegacyManiaSkinConfigurationLookups.ExplosionScale: - Debug.Assert(maniaLookup.TargetColumn != null); + Debug.Assert(maniaLookup.ColumnIndex != null); if (GetConfig(SkinConfiguration.LegacySetting.Version)?.Value < 2.5m) return SkinUtils.As(new Bindable(1)); - if (existing.ExplosionWidth[maniaLookup.TargetColumn.Value] != 0) - return SkinUtils.As(new Bindable(existing.ExplosionWidth[maniaLookup.TargetColumn.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); + if (existing.ExplosionWidth[maniaLookup.ColumnIndex.Value] != 0) + return SkinUtils.As(new Bindable(existing.ExplosionWidth[maniaLookup.ColumnIndex.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); - return SkinUtils.As(new Bindable(existing.ColumnWidth[maniaLookup.TargetColumn.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); + return SkinUtils.As(new Bindable(existing.ColumnWidth[maniaLookup.ColumnIndex.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); case LegacyManiaSkinConfigurationLookups.ColumnLineColour: return SkinUtils.As(getCustomColour(existing, "ColourColumnLine")); @@ -174,53 +174,53 @@ namespace osu.Game.Skinning return SkinUtils.As(getCustomColour(existing, "ColourJudgementLine")); case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(getCustomColour(existing, $"Colour{maniaLookup.TargetColumn + 1}")); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(getCustomColour(existing, $"Colour{maniaLookup.ColumnIndex + 1}")); case LegacyManiaSkinConfigurationLookups.ColumnLightColour: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(getCustomColour(existing, $"ColourLight{maniaLookup.TargetColumn + 1}")); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(getCustomColour(existing, $"ColourLight{maniaLookup.ColumnIndex + 1}")); case LegacyManiaSkinConfigurationLookups.MinimumColumnWidth: return SkinUtils.As(new Bindable(existing.MinimumColumnWidth)); case LegacyManiaSkinConfigurationLookups.NoteImage: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}")); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.ColumnIndex}")); case LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}H")); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.ColumnIndex}H")); case LegacyManiaSkinConfigurationLookups.HoldNoteTailImage: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}T")); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.ColumnIndex}T")); case LegacyManiaSkinConfigurationLookups.HoldNoteBodyImage: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.TargetColumn}L")); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(getManiaImage(existing, $"NoteImage{maniaLookup.ColumnIndex}L")); case LegacyManiaSkinConfigurationLookups.HoldNoteLightImage: return SkinUtils.As(getManiaImage(existing, "LightingL")); case LegacyManiaSkinConfigurationLookups.HoldNoteLightScale: - Debug.Assert(maniaLookup.TargetColumn != null); + Debug.Assert(maniaLookup.ColumnIndex != null); if (GetConfig(SkinConfiguration.LegacySetting.Version)?.Value < 2.5m) return SkinUtils.As(new Bindable(1)); - if (existing.HoldNoteLightWidth[maniaLookup.TargetColumn.Value] != 0) - return SkinUtils.As(new Bindable(existing.HoldNoteLightWidth[maniaLookup.TargetColumn.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); + if (existing.HoldNoteLightWidth[maniaLookup.ColumnIndex.Value] != 0) + return SkinUtils.As(new Bindable(existing.HoldNoteLightWidth[maniaLookup.ColumnIndex.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); - return SkinUtils.As(new Bindable(existing.ColumnWidth[maniaLookup.TargetColumn.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); + return SkinUtils.As(new Bindable(existing.ColumnWidth[maniaLookup.ColumnIndex.Value] / LegacyManiaSkinConfiguration.DEFAULT_COLUMN_SIZE)); case LegacyManiaSkinConfigurationLookups.KeyImage: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(getManiaImage(existing, $"KeyImage{maniaLookup.TargetColumn}")); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(getManiaImage(existing, $"KeyImage{maniaLookup.ColumnIndex}")); case LegacyManiaSkinConfigurationLookups.KeyImageDown: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(getManiaImage(existing, $"KeyImage{maniaLookup.TargetColumn}D")); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(getManiaImage(existing, $"KeyImage{maniaLookup.ColumnIndex}D")); case LegacyManiaSkinConfigurationLookups.LeftStageImage: return SkinUtils.As(getManiaImage(existing, "StageLeft")); @@ -238,12 +238,12 @@ namespace osu.Game.Skinning return SkinUtils.As(getManiaImage(existing, "StageHint")); case LegacyManiaSkinConfigurationLookups.LeftLineWidth: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(new Bindable(existing.ColumnLineWidth[maniaLookup.TargetColumn.Value])); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(new Bindable(existing.ColumnLineWidth[maniaLookup.ColumnIndex.Value])); case LegacyManiaSkinConfigurationLookups.RightLineWidth: - Debug.Assert(maniaLookup.TargetColumn != null); - return SkinUtils.As(new Bindable(existing.ColumnLineWidth[maniaLookup.TargetColumn.Value + 1])); + Debug.Assert(maniaLookup.ColumnIndex != null); + return SkinUtils.As(new Bindable(existing.ColumnLineWidth[maniaLookup.ColumnIndex.Value + 1])); case LegacyManiaSkinConfigurationLookups.Hit0: case LegacyManiaSkinConfigurationLookups.Hit50: From dee01abab18c293eebb3320013bd2badbc9a531e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 14:51:17 +0900 Subject: [PATCH 1515/2686] Add method to get stage from column index --- osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs | 14 ++++++++++++++ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 4 ++-- .../Skinning/Argon/ManiaArgonSkinTransformer.cs | 12 ++++++++++-- .../Default/ManiaTrianglesSkinTransformer.cs | 13 ++++++++++--- .../Skinning/Legacy/ManiaLegacySkinTransformer.cs | 1 - osu.Game.Rulesets.Mania/UI/Column.cs | 6 +----- 6 files changed, 37 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs index 4879ce6748..b5655a4579 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmap.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using System.Collections.Generic; using System.Linq; using osu.Game.Beatmaps; @@ -60,5 +61,18 @@ namespace osu.Game.Rulesets.Mania.Beatmaps }, }; } + + public StageDefinition GetStageForColumnIndex(int column) + { + foreach (var stage in Stages) + { + if (column < stage.Columns) + return stage; + + column -= stage.Columns; + } + + throw new ArgumentOutOfRangeException(nameof(column), "Provided index exceeds all available stages"); + } } } diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index c4a8b7c8fa..6162184c9a 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -69,10 +69,10 @@ namespace osu.Game.Rulesets.Mania switch (skin) { case TrianglesSkin: - return new ManiaTrianglesSkinTransformer(skin); + return new ManiaTrianglesSkinTransformer(skin, beatmap); case ArgonSkin: - return new ManiaArgonSkinTransformer(skin); + return new ManiaArgonSkinTransformer(skin, beatmap); case DefaultLegacySkin: return new ManiaClassicSkinTransformer(skin, beatmap); diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index ea34d8d4c5..80dc3978df 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -4,6 +4,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Skinning; using osuTK.Graphics; @@ -11,9 +13,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { public class ManiaArgonSkinTransformer : SkinTransformer { - public ManiaArgonSkinTransformer(ISkin skin) + private readonly ManiaBeatmap beatmap; + + public ManiaArgonSkinTransformer(ISkin skin, IBeatmap beatmap) : base(skin) { + this.beatmap = (ManiaBeatmap)beatmap; } public override Drawable? GetDrawableComponent(ISkinComponent component) @@ -44,7 +49,10 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon switch (maniaLookup.Lookup) { case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: - if (maniaLookup.StageDefinition.IsSpecialColumn(maniaLookup.ColumnIndex ?? 0)) + int column = maniaLookup.ColumnIndex ?? 0; + var stage = beatmap.GetStageForColumnIndex(column); + + if (stage.IsSpecialColumn(column)) return SkinUtils.As(new Bindable(Color4.Yellow)); // TODO: Add actual colours. diff --git a/osu.Game.Rulesets.Mania/Skinning/Default/ManiaTrianglesSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Default/ManiaTrianglesSkinTransformer.cs index 88f1f6ed26..eb51179cea 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Default/ManiaTrianglesSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Default/ManiaTrianglesSkinTransformer.cs @@ -3,6 +3,8 @@ using System; using osu.Framework.Bindables; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Skinning; using osuTK.Graphics; @@ -10,9 +12,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default { public class ManiaTrianglesSkinTransformer : SkinTransformer { - public ManiaTrianglesSkinTransformer(ISkin skin) + private readonly ManiaBeatmap beatmap; + + public ManiaTrianglesSkinTransformer(ISkin skin, IBeatmap beatmap) : base(skin) { + this.beatmap = (ManiaBeatmap)beatmap; } private readonly Color4 colourEven = new Color4(6, 84, 0, 255); @@ -28,10 +33,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: int column = maniaLookup.ColumnIndex ?? 0; - if (maniaLookup.StageDefinition.IsSpecialColumn(column)) + var stage = beatmap.GetStageForColumnIndex(column); + + if (stage.IsSpecialColumn(column)) return SkinUtils.As(new Bindable(colourSpecial)); - int distanceToEdge = Math.Min(column, (maniaLookup.StageDefinition.Columns - 1) - column); + int distanceToEdge = Math.Min(column, (stage.Columns - 1) - column); return SkinUtils.As(new Bindable(distanceToEdge % 2 == 0 ? colourOdd : colourEven)); } } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 8dc81f2101..31cfcf9e16 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 81d9ae28ab..a622b8a155 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics.Pooling; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; using osu.Game.Rulesets.Mania.Skinning; @@ -68,9 +67,6 @@ namespace osu.Game.Rulesets.Mania.UI [Resolved] private ISkinSource skin { get; set; } - [Resolved] - private StageDefinition stageDefinition { get; set; } - [BackgroundDependencyLoader] private void load() { @@ -116,7 +112,7 @@ namespace osu.Game.Rulesets.Mania.UI private void onSourceChanged() { - AccentColour.Value = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, stageDefinition, Index)?.Value ?? Color4.Black; + AccentColour.Value = skin.GetManiaSkinConfig(LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour, Index)?.Value ?? Color4.Black; } protected override void LoadComplete() From 9a92ff1681066b8ea9dfdb030b8674c5d241e79a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 16:24:43 +0900 Subject: [PATCH 1516/2686] Fix `SourceChanged` unbind directionality and add null check --- osu.Game.Rulesets.Mania/UI/Column.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index a622b8a155..89413f0f1b 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -124,7 +124,9 @@ namespace osu.Game.Rulesets.Mania.UI protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - skin.SourceChanged += onSourceChanged; + + if (skin != null) + skin.SourceChanged -= onSourceChanged; } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) From f1ea61b1a2bd1d277c9efa277075dd5e5d0a15df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 17:36:06 +0900 Subject: [PATCH 1517/2686] Remove unused colour code --- osu.Game.Rulesets.Mania/UI/Stage.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index 52c8829df3..c4cbb74e57 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -43,13 +43,6 @@ namespace osu.Game.Rulesets.Mania.UI private readonly Drawable barLineContainer; - // private readonly Dictionary columnColours = new Dictionary - // { - // { ColumnType.Even, new Color4(6, 84, 0, 255) }, - // { ColumnType.Odd, new Color4(94, 0, 57, 255) }, - // { ColumnType.Special, new Color4(0, 48, 63, 255) } - // }; - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Columns.Any(c => c.ReceivePositionalInputAt(screenSpacePos)); private readonly int firstColumnIndex; From 6f8533ef6bc78450ef48fc74c3b64c0c8ea85102 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 16:51:41 +0900 Subject: [PATCH 1518/2686] Remove pointless colour specifications in test scenes --- osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs | 2 -- .../Skinning/ManiaHitObjectTestScene.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs index cefcce8319..d3e90170b2 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.UI; -using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Tests.Skinning { @@ -34,7 +33,6 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning this.column = new Column(column, false) { Action = { Value = action }, - AccentColour = { Value = Color4.Orange }, Alpha = showColumn ? 1 : 0 }, content = new ManiaInputManager(new ManiaRuleset().RulesetInfo, 4) diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs index fd82041ad8..75175c43d8 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs @@ -61,7 +61,6 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning c.Add(CreateHitObject().With(h => { h.HitObject.StartTime = Time.Current + 5000; - h.AccentColour.Value = Color4.Orange; })); }) }, From c1cb62cc35d75588f7462edceba8252762e3dc68 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 16:54:08 +0900 Subject: [PATCH 1519/2686] Add basic argon note piece --- .../Skinning/Argon/ArgonHitTarget.cs | 3 +- .../Skinning/Argon/ArgonNotePiece.cs | 110 ++++++++++++++++++ .../Argon/ManiaArgonSkinTransformer.cs | 4 + 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs index 4750118583..7d7ef4a15e 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs @@ -6,7 +6,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.UI.Scrolling; using osuTK.Graphics; @@ -20,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon private void load(IScrollingInfo scrollingInfo) { RelativeSizeAxes = Axes.X; - Height = DefaultNotePiece.NOTE_HEIGHT; + Height = ArgonNotePiece.NOTE_HEIGHT; InternalChildren = new[] { diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs new file mode 100644 index 0000000000..f560d2676c --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs @@ -0,0 +1,110 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI.Scrolling; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Skinning.Argon +{ + internal class ArgonNotePiece : CompositeDrawable + { + public const float NOTE_HEIGHT = 42; + + public const float CORNER_RADIUS = 3; + + private readonly IBindable direction = new Bindable(); + private readonly IBindable accentColour = new Bindable(); + + private readonly Box colouredBox; + private readonly Box shadow; + + public ArgonNotePiece() + { + RelativeSizeAxes = Axes.X; + Height = NOTE_HEIGHT; + + CornerRadius = CORNER_RADIUS; + Masking = true; + + InternalChildren = new Drawable[] + { + shadow = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.Both, + Height = 0.82f, + Masking = true, + CornerRadius = CORNER_RADIUS, + Children = new Drawable[] + { + colouredBox = new Box + { + RelativeSizeAxes = Axes.Both, + } + } + }, + new Circle + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + Height = CORNER_RADIUS * 2, + }, + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Y = 4, + Icon = FontAwesome.Solid.AngleDown, + Size = new Vector2(20), + Scale = new Vector2(1, 0.7f) + } + }; + } + + [BackgroundDependencyLoader(true)] + private void load(IScrollingInfo scrollingInfo, DrawableHitObject? drawableObject) + { + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(onDirectionChanged, true); + + if (drawableObject != null) + { + accentColour.BindTo(drawableObject.AccentColour); + accentColour.BindValueChanged(onAccentChanged, true); + } + } + + private void onDirectionChanged(ValueChangedEvent direction) + { + colouredBox.Anchor = colouredBox.Origin = direction.NewValue == ScrollingDirection.Up + ? Anchor.TopCentre + : Anchor.BottomCentre; + } + + private void onAccentChanged(ValueChangedEvent accent) + { + colouredBox.Colour = ColourInfo.GradientVertical( + accent.NewValue.Lighten(0.1f), + accent.NewValue + ); + + shadow.Colour = accent.NewValue.Darken(0.5f); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index 80dc3978df..d280a16113 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -29,6 +29,10 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (maniaComponent.Component) { + case ManiaSkinComponents.HoldNoteHead: + case ManiaSkinComponents.Note: + return new ArgonNotePiece(); + case ManiaSkinComponents.HitTarget: return new ArgonHitTarget(); From a10f9ebfa5b71039da9083464bf55f77d7784be3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 16:54:32 +0900 Subject: [PATCH 1520/2686] Update argon colours to roughly match design spec --- .../Argon/ManiaArgonSkinTransformer.cs | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index d280a16113..4843621a1e 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -3,7 +3,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Skinning; @@ -56,11 +55,49 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon int column = maniaLookup.ColumnIndex ?? 0; var stage = beatmap.GetStageForColumnIndex(column); - if (stage.IsSpecialColumn(column)) - return SkinUtils.As(new Bindable(Color4.Yellow)); + Color4 colour; - // TODO: Add actual colours. - return SkinUtils.As(new Bindable(new Color4(RNG.NextSingle() * 0.5f, RNG.NextSingle() * 0.5f, RNG.NextSingle() * 0.5f, 1))); + if (stage.IsSpecialColumn(column)) + colour = new Color4(159, 101, 255, 255); + else + { + switch (column % 8) + { + default: + colour = new Color4(240, 216, 0, 255); + break; + + case 1: + colour = new Color4(240, 101, 0, 255); + break; + + case 2: + colour = new Color4(240, 0, 130, 255); + break; + + case 3: + colour = new Color4(192, 0, 240, 255); + break; + + case 4: + colour = new Color4(178, 0, 240, 255); + break; + + case 5: + colour = new Color4(0, 96, 240, 255); + break; + + case 6: + colour = new Color4(0, 226, 240, 255); + break; + + case 7: + colour = new Color4(0, 240, 96, 255); + break; + } + } + + return SkinUtils.As(new Bindable(colour)); } } From 6c0923ec1aa421b3dc4252e8327ae1eb27005b37 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 16:54:47 +0900 Subject: [PATCH 1521/2686] Add argon hold note pieces --- .../Skinning/Argon/ArgonHoldBodyPiece.cs | 90 ++++++++++++++++++ .../Skinning/Argon/ArgonHoldNoteTailPiece.cs | 91 +++++++++++++++++++ .../Argon/ManiaArgonSkinTransformer.cs | 6 ++ 3 files changed, 187 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs create mode 100644 osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs new file mode 100644 index 0000000000..10d5a4d267 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs @@ -0,0 +1,90 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.Objects.Drawables; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Skinning.Argon +{ + /// + /// Represents length-wise portion of a hold note. + /// + public class ArgonHoldBodyPiece : CompositeDrawable + { + protected readonly Bindable AccentColour = new Bindable(); + protected readonly IBindable IsHitting = new Bindable(); + + private Drawable background = null!; + private Box foreground = null!; + + public ArgonHoldBodyPiece() + { + Blending = BlendingParameters.Additive; + RelativeSizeAxes = Axes.Both; + + // Without this, the width of the body will be slightly larger than the head/tail. + Masking = true; + CornerRadius = ArgonNotePiece.CORNER_RADIUS; + } + + [BackgroundDependencyLoader(true)] + private void load(DrawableHitObject? drawableObject) + { + InternalChildren = new[] + { + background = new Box { RelativeSizeAxes = Axes.Both }, + foreground = new Box + { + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive, + Alpha = 0, + }, + }; + + if (drawableObject != null) + { + var holdNote = (DrawableHoldNote)drawableObject; + + AccentColour.BindTo(drawableObject.AccentColour); + IsHitting.BindTo(holdNote.IsHitting); + } + + AccentColour.BindValueChanged(colour => + { + background.Colour = colour.NewValue.Opacity(0.2f); + foreground.Colour = colour.NewValue.Opacity(0.1f); + }, true); + + IsHitting.BindValueChanged(hitting => + { + const float animation_length = 50; + + foreground.ClearTransforms(); + + if (hitting.NewValue) + { + // wait for the next sync point + double synchronisedOffset = animation_length * 2 - Time.Current % (animation_length * 2); + + using (foreground.BeginDelayedSequence(synchronisedOffset)) + { + foreground.FadeTo(1, animation_length).Then() + .FadeTo(0, animation_length) + .Loop(); + } + } + else + { + foreground.FadeOut(animation_length); + } + }); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs new file mode 100644 index 0000000000..e1068c6cd8 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI.Scrolling; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Skinning.Argon +{ + internal class ArgonHoldNoteTailPiece : CompositeDrawable + { + private readonly IBindable direction = new Bindable(); + private readonly IBindable accentColour = new Bindable(); + + private readonly Box colouredBox; + private readonly Box shadow; + + public ArgonHoldNoteTailPiece() + { + RelativeSizeAxes = Axes.X; + Height = ArgonNotePiece.NOTE_HEIGHT; + + CornerRadius = ArgonNotePiece.CORNER_RADIUS; + Masking = true; + + InternalChildren = new Drawable[] + { + shadow = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Height = 0.82f, + Masking = true, + CornerRadius = ArgonNotePiece.CORNER_RADIUS, + Children = new Drawable[] + { + colouredBox = new Box + { + RelativeSizeAxes = Axes.Both, + } + } + }, + new Circle + { + RelativeSizeAxes = Axes.X, + Height = ArgonNotePiece.CORNER_RADIUS * 2, + }, + }; + } + + [BackgroundDependencyLoader(true)] + private void load(IScrollingInfo scrollingInfo, DrawableHitObject? drawableObject) + { + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(onDirectionChanged, true); + + if (drawableObject != null) + { + accentColour.BindTo(drawableObject.AccentColour); + accentColour.BindValueChanged(onAccentChanged, true); + } + } + + private void onDirectionChanged(ValueChangedEvent direction) + { + colouredBox.Anchor = colouredBox.Origin = direction.NewValue == ScrollingDirection.Up + ? Anchor.TopCentre + : Anchor.BottomCentre; + } + + private void onAccentChanged(ValueChangedEvent accent) + { + colouredBox.Colour = ColourInfo.GradientVertical( + accent.NewValue, + accent.NewValue.Darken(0.1f) + ); + + shadow.Colour = accent.NewValue.Darken(0.5f); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index 4843621a1e..c2b258c57c 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -28,6 +28,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (maniaComponent.Component) { + case ManiaSkinComponents.HoldNoteBody: + return new ArgonHoldBodyPiece(); + + case ManiaSkinComponents.HoldNoteTail: + return new ArgonHoldNoteTailPiece(); + case ManiaSkinComponents.HoldNoteHead: case ManiaSkinComponents.Note: return new ArgonNotePiece(); From 4cb07b88390fcbba3f4f786b075748dd5aad1700 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 17:46:54 +0900 Subject: [PATCH 1522/2686] Specify column widths for argon --- .../Skinning/Argon/ManiaArgonSkinTransformer.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index c2b258c57c..9123fa44d7 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -55,11 +55,17 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { if (lookup is ManiaSkinConfigurationLookup maniaLookup) { + int column = maniaLookup.ColumnIndex ?? 0; + var stage = beatmap.GetStageForColumnIndex(column); + switch (maniaLookup.Lookup) { + case LegacyManiaSkinConfigurationLookups.ColumnWidth: + return SkinUtils.As(new Bindable( + stage.IsSpecialColumn(column) ? 80 : 60 + )); + case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: - int column = maniaLookup.ColumnIndex ?? 0; - var stage = beatmap.GetStageForColumnIndex(column); Color4 colour; From a543222a2b2653045882c9b9e0ef58be7e8b723e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 18:03:48 +0900 Subject: [PATCH 1523/2686] Add ability to pad stage vertically --- .../Argon/ManiaArgonSkinTransformer.cs | 4 +++ osu.Game.Rulesets.Mania/UI/ColumnFlow.cs | 2 ++ osu.Game.Rulesets.Mania/UI/Stage.cs | 32 +++++++++++++++++++ .../LegacyManiaSkinConfigurationLookup.cs | 2 ++ 4 files changed, 40 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index 9123fa44d7..9ed324793b 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -60,6 +60,10 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon switch (maniaLookup.Lookup) { + case LegacyManiaSkinConfigurationLookups.StagePaddingBottom: + case LegacyManiaSkinConfigurationLookups.StagePaddingTop: + return SkinUtils.As(new Bindable(30)); + case LegacyManiaSkinConfigurationLookups.ColumnWidth: return SkinUtils.As(new Bindable( stage.IsSpecialColumn(column) ? 80 : 60 diff --git a/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs b/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs index 871ec9f1a3..9b3f6d7033 100644 --- a/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs +++ b/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs @@ -36,6 +36,8 @@ namespace osu.Game.Rulesets.Mania.UI AutoSizeAxes = Axes.X; + Masking = true; + InternalChild = columns = new FillFlowContainer { RelativeSizeAxes = Axes.Y, diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index c4cbb74e57..1273cb3d32 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.Mania.Skinning; using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -130,6 +131,37 @@ namespace osu.Game.Rulesets.Mania.UI } } + private ISkinSource currentSkin; + + [BackgroundDependencyLoader] + private void load(ISkinSource skin) + { + currentSkin = skin; + + skin.SourceChanged += onSkinChanged; + onSkinChanged(); + } + + private void onSkinChanged() + { + float paddingTop = currentSkin.GetConfig(new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.StagePaddingTop))?.Value ?? 0; + float paddingBottom = currentSkin.GetConfig(new ManiaSkinConfigurationLookup(LegacyManiaSkinConfigurationLookups.StagePaddingBottom))?.Value ?? 0; + + Padding = new MarginPadding + { + Top = paddingTop, + Bottom = paddingBottom, + }; + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (currentSkin != null) + currentSkin.SourceChanged -= onSkinChanged; + } + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs index c9e96ab3f1..3ec0ee6006 100644 --- a/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs +++ b/osu.Game/Skinning/LegacyManiaSkinConfigurationLookup.cs @@ -42,6 +42,8 @@ namespace osu.Game.Skinning HitPosition, ScorePosition, LightPosition, + StagePaddingTop, + StagePaddingBottom, HitTargetImage, ShowJudgementLine, KeyImage, From 59bbbf1c087b54f13d1e72a7c46defc0dde3c8f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 18:07:56 +0900 Subject: [PATCH 1524/2686] Improve colours and hit metrics on key area --- .../Skinning/Argon/ArgonHitTarget.cs | 3 ++ .../Skinning/Argon/ArgonKeyArea.cs | 30 ++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs index 7d7ef4a15e..9e449623d5 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs @@ -21,6 +21,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon RelativeSizeAxes = Axes.X; Height = ArgonNotePiece.NOTE_HEIGHT; + Masking = true; + CornerRadius = ArgonNotePiece.CORNER_RADIUS; + InternalChildren = new[] { new Box diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index 9d16e84f1e..eef7e2ff7c 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -12,6 +12,7 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.UI.Scrolling; using osuTK; using osuTK.Graphics; @@ -53,18 +54,24 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Height = Stage.HIT_TARGET_POSITION, Children = new[] { - background = new Box + new Container { - Name = "Key gradient", + Masking = true, RelativeSizeAxes = Axes.Both, + CornerRadius = ArgonNotePiece.CORNER_RADIUS, + Child = background = new Box + { + Name = "Key gradient", + RelativeSizeAxes = Axes.Both, + }, }, hitTargetLine = new Circle { RelativeSizeAxes = Axes.X, Anchor = Anchor.TopCentre, - Origin = Anchor.Centre, + Origin = Anchor.BottomCentre, Colour = OsuColour.Gray(196 / 255f), - Height = 4, + Height = ArgonNotePiece.CORNER_RADIUS * 2, Masking = true, }, new Container @@ -137,10 +144,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon accentColour = column.AccentColour.GetBoundCopy(); accentColour.BindValueChanged(colour => - { - background.Colour = colour.NewValue.Darken(0.6f); - bottomIcon.Colour = colour.NewValue; - }, true); + { + background.Colour = colour.NewValue.Darken(1f); + bottomIcon.Colour = colour.NewValue; + }, + true); } private void onDirectionChanged(ValueChangedEvent direction) @@ -169,8 +177,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Color4 lightingColour = accentColour.Value.Lighten(0.9f); background - .FadeColour(accentColour.Value.Lighten(0.4f), 40).Then() - .FadeColour(accentColour.Value, 150, Easing.OutQuint); + .FadeColour(accentColour.Value, 40).Then() + .FadeColour(accentColour.Value.Darken(0.4f), 150, Easing.OutQuint); hitTargetLine.FadeColour(Color4.White, lighting_fade_in_duration, Easing.OutQuint); hitTargetLine.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters @@ -225,7 +233,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { Type = EdgeEffectType.Glow, Colour = lightingColour, - Radius = 30, + Radius = 25, }, lighting_fade_out_duration, Easing.OutQuint); bottomIcon.FadeColour(accentColour.Value, lighting_fade_out_duration, Easing.OutQuint); From f3e3ee81cbda6f9968896c31a172943e01ec2486 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 18:12:55 +0900 Subject: [PATCH 1525/2686] Add column and stage background to argon skin --- .../Skinning/Argon/ArgonColumnBackground.cs | 101 ++++++++++++++++++ .../Skinning/Argon/ArgonStageBackground.cs | 16 +++ .../Argon/ManiaArgonSkinTransformer.cs | 6 ++ 3 files changed, 123 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs create mode 100644 osu.Game.Rulesets.Mania/Skinning/Argon/ArgonStageBackground.cs diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs new file mode 100644 index 0000000000..c6377f9152 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs @@ -0,0 +1,101 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.UI.Scrolling; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Skinning.Argon +{ + public class ArgonColumnBackground : CompositeDrawable, IKeyBindingHandler + { + private readonly IBindable direction = new Bindable(); + + private Color4 brightColour; + private Color4 dimColour; + + private Box background = null!; + private Box backgroundOverlay = null!; + + [Resolved] + private Column column { get; set; } = null!; + + private Bindable accentColour = null!; + + public ArgonColumnBackground() + { + RelativeSizeAxes = Axes.Both; + + Masking = true; + CornerRadius = ArgonNotePiece.CORNER_RADIUS; + } + + [BackgroundDependencyLoader] + private void load(IScrollingInfo scrollingInfo) + { + InternalChildren = new[] + { + background = new Box + { + Name = "Background", + RelativeSizeAxes = Axes.Both, + }, + backgroundOverlay = new Box + { + Name = "Background Gradient Overlay", + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Blending = BlendingParameters.Additive, + Alpha = 0 + } + }; + + accentColour = column.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(colour => + { + background.Colour = colour.NewValue.Darken(5); + brightColour = colour.NewValue.Opacity(0.6f); + dimColour = colour.NewValue.Opacity(0); + }, true); + + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(onDirectionChanged, true); + } + + private void onDirectionChanged(ValueChangedEvent direction) + { + if (direction.NewValue == ScrollingDirection.Up) + { + backgroundOverlay.Anchor = backgroundOverlay.Origin = Anchor.TopLeft; + backgroundOverlay.Colour = ColourInfo.GradientVertical(brightColour, dimColour); + } + else + { + backgroundOverlay.Anchor = backgroundOverlay.Origin = Anchor.BottomLeft; + backgroundOverlay.Colour = ColourInfo.GradientVertical(dimColour, brightColour); + } + } + + public bool OnPressed(KeyBindingPressEvent e) + { + if (e.Action == column.Action.Value) + backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint); + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + if (e.Action == column.Action.Value) + backgroundOverlay.FadeTo(0, 250, Easing.OutQuint); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonStageBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonStageBackground.cs new file mode 100644 index 0000000000..1881695b14 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonStageBackground.cs @@ -0,0 +1,16 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Rulesets.Mania.Skinning.Argon +{ + public class ArgonStageBackground : CompositeDrawable + { + public ArgonStageBackground() + { + RelativeSizeAxes = Axes.Both; + } + } +} diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index 9ed324793b..45ee25e388 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -28,6 +28,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (maniaComponent.Component) { + case ManiaSkinComponents.StageBackground: + return new ArgonStageBackground(); + + case ManiaSkinComponents.ColumnBackground: + return new ArgonColumnBackground(); + case ManiaSkinComponents.HoldNoteBody: return new ArgonHoldBodyPiece(); From 258c93557408a5aefaa8bc473c64cea7e582c532 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 18:29:07 +0900 Subject: [PATCH 1526/2686] Remove key area background (the column background is enough to work well) --- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index eef7e2ff7c..72f5f81890 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -12,7 +12,6 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Rulesets.Mania.UI; -using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.UI.Scrolling; using osuTK; using osuTK.Graphics; @@ -62,6 +61,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Child = background = new Box { Name = "Key gradient", + Alpha = 0, + Blending = BlendingParameters.Additive, RelativeSizeAxes = Axes.Both, }, }, @@ -177,8 +178,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Color4 lightingColour = accentColour.Value.Lighten(0.9f); background - .FadeColour(accentColour.Value, 40).Then() - .FadeColour(accentColour.Value.Darken(0.4f), 150, Easing.OutQuint); + .FadeTo(1, 40).Then() + .FadeTo(0.8f, 150, Easing.OutQuint); hitTargetLine.FadeColour(Color4.White, lighting_fade_in_duration, Easing.OutQuint); hitTargetLine.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters @@ -218,7 +219,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon const double lighting_fade_out_duration = 300; Color4 lightingColour = accentColour.Value.Lighten(0.9f).Opacity(0); - background.FadeColour(accentColour.Value.Darken(0.6f), lighting_fade_out_duration, Easing.OutQuint); + background.FadeTo(0, lighting_fade_out_duration, Easing.OutQuint); topIcon.ScaleTo(1f, 200, Easing.OutQuint); topIcon.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters From b95743092d2e95110f5bf4379c20b29335f569ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 20:51:28 +0900 Subject: [PATCH 1527/2686] Add argon hit explosion --- .../Skinning/Argon/ArgonHitExplosion.cs | 99 +++++++++++++++++++ .../Argon/ManiaArgonSkinTransformer.cs | 3 + 2 files changed, 102 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs new file mode 100644 index 0000000000..132ef0d528 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs @@ -0,0 +1,99 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mania.UI; +using osu.Game.Rulesets.UI.Scrolling; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Skinning.Argon +{ + public class ArgonHitExplosion : CompositeDrawable, IHitExplosion + { + private const float default_large_faint_size = 0.8f; + + public override bool RemoveWhenNotAlive => true; + + [Resolved] + private Column column { get; set; } = null!; + + private readonly IBindable direction = new Bindable(); + + private Container largeFaint = null!; + + private Bindable accentColour = null!; + + public ArgonHitExplosion() + { + Origin = Anchor.Centre; + + RelativeSizeAxes = Axes.X; + Height = ArgonNotePiece.NOTE_HEIGHT; + } + + [BackgroundDependencyLoader] + private void load(IScrollingInfo scrollingInfo) + { + InternalChildren = new Drawable[] + { + largeFaint = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = ArgonNotePiece.CORNER_RADIUS, + Blending = BlendingParameters.Additive, + Child = new Box + { + Colour = Color4.White, + RelativeSizeAxes = Axes.Both, + }, + }, + }; + + direction.BindTo(scrollingInfo.Direction); + direction.BindValueChanged(onDirectionChanged, true); + + accentColour = column.AccentColour.GetBoundCopy(); + accentColour.BindValueChanged(colour => + { + largeFaint.Colour = Interpolation.ValueAt(0.8f, colour.NewValue, Color4.White, 0, 1); + + largeFaint.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = colour.NewValue, + Roundness = 40, + Radius = 60, + }; + }, true); + } + + private void onDirectionChanged(ValueChangedEvent direction) + { + if (direction.NewValue == ScrollingDirection.Up) + { + Anchor = Anchor.TopCentre; + Y = ArgonNotePiece.NOTE_HEIGHT / 2; + } + else + { + Anchor = Anchor.BottomCentre; + Y = -ArgonNotePiece.NOTE_HEIGHT / 2; + } + } + + public void Animate(JudgementResult result) + { + this.FadeOutFromOne(PoolableHitExplosion.DURATION, Easing.Out); + } + } +} diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index 45ee25e388..37ab958eee 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -49,6 +49,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon case ManiaSkinComponents.KeyArea: return new ArgonKeyArea(); + + case ManiaSkinComponents.HitExplosion: + return new ArgonHitExplosion(); } break; From e4e4c1b66169d842babd595697a70a7db0514f36 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 21:39:29 +0900 Subject: [PATCH 1528/2686] Add very temporary mania judgement display for argon skin --- .../Skinning/Argon/ArgonJudgementPiece.cs | 193 ++++++++++++++++++ .../Argon/ManiaArgonSkinTransformer.cs | 4 + 2 files changed, 197 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs new file mode 100644 index 0000000000..e7dfec256d --- /dev/null +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs @@ -0,0 +1,193 @@ +// 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.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Mania.Skinning.Argon +{ + public class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + { + protected readonly HitResult Result; + + protected SpriteText JudgementText { get; private set; } = null!; + + private RingExplosion? ringExplosion; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + public ArgonJudgementPiece(HitResult result) + { + Result = result; + Origin = Anchor.Centre; + Y = 160; + } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + JudgementText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = Result.GetDescription().ToUpperInvariant(), + Colour = colours.ForHitResult(Result), + Blending = BlendingParameters.Additive, + Spacing = new Vector2(10, 0), + Font = OsuFont.Default.With(size: 28, weight: FontWeight.Regular), + }, + }; + + if (Result.IsHit()) + { + AddInternal(ringExplosion = new RingExplosion(Result) + { + Colour = colours.ForHitResult(Result), + }); + } + } + + /// + /// Plays the default animation for this judgement piece. + /// + /// + /// The base implementation only handles fade (for all result types) and misses. + /// Individual rulesets are recommended to implement their appropriate hit animations. + /// + public virtual void PlayAnimation() + { + switch (Result) + { + default: + JudgementText + .ScaleTo(Vector2.One) + .ScaleTo(new Vector2(1.4f), 1800, Easing.OutQuint); + break; + + case HitResult.Miss: + this.ScaleTo(1.6f); + this.ScaleTo(1, 100, Easing.In); + + this.MoveTo(Vector2.Zero); + this.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint); + + this.RotateTo(0); + this.RotateTo(40, 800, Easing.InQuint); + break; + } + + this.FadeOutFromOne(800); + + ringExplosion?.PlayAnimation(); + } + + public Drawable? GetAboveHitObjectsProxiedContent() => null; + + private class RingExplosion : CompositeDrawable + { + private readonly float travel = 52; + + public RingExplosion(HitResult result) + { + const float thickness = 4; + + const float small_size = 9; + const float large_size = 14; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Blending = BlendingParameters.Additive; + + int countSmall = 0; + int countLarge = 0; + + switch (result) + { + case HitResult.Meh: + countSmall = 3; + travel *= 0.3f; + break; + + case HitResult.Ok: + case HitResult.Good: + countSmall = 4; + travel *= 0.6f; + break; + + case HitResult.Great: + case HitResult.Perfect: + countSmall = 4; + countLarge = 4; + break; + } + + for (int i = 0; i < countSmall; i++) + AddInternal(new RingPiece(thickness) { Size = new Vector2(small_size) }); + + for (int i = 0; i < countLarge; i++) + AddInternal(new RingPiece(thickness) { Size = new Vector2(large_size) }); + } + + public void PlayAnimation() + { + foreach (var c in InternalChildren) + { + const float start_position_ratio = 0.3f; + + float direction = RNG.NextSingle(0, 360); + float distance = RNG.NextSingle(travel / 2, travel); + + c.MoveTo(new Vector2( + MathF.Cos(direction) * distance * start_position_ratio, + MathF.Sin(direction) * distance * start_position_ratio + )); + + c.MoveTo(new Vector2( + MathF.Cos(direction) * distance, + MathF.Sin(direction) * distance + ), 600, Easing.OutQuint); + } + + this.FadeOutFromOne(1000, Easing.OutQuint); + } + + public class RingPiece : CircularContainer + { + public RingPiece(float thickness = 9) + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Masking = true; + BorderThickness = thickness; + BorderColour = Color4.White; + + Child = new Box + { + AlwaysPresent = true, + Alpha = 0, + RelativeSizeAxes = Axes.Both + }; + } + } + } + } +} diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index 37ab958eee..cf08f7ea3e 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -5,6 +5,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; using osuTK.Graphics; @@ -24,6 +25,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { switch (component) { + case GameplaySkinComponent resultComponent: + return new ArgonJudgementPiece(resultComponent.Component); + case ManiaSkinComponent maniaComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (maniaComponent.Component) From 6d14ccb8e0bbeba807255e423f1e9030d6bee39b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 21:46:02 +0900 Subject: [PATCH 1529/2686] Make special key slightly wider --- .../Skinning/Argon/ManiaArgonSkinTransformer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index cf08f7ea3e..93c3a94316 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon case LegacyManiaSkinConfigurationLookups.ColumnWidth: return SkinUtils.As(new Bindable( - stage.IsSpecialColumn(column) ? 80 : 60 + stage.IsSpecialColumn(column) ? 120 : 60 )); case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: From e81f550150438741a9da4ee7e26a7899b9d9b673 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 19:35:01 +0900 Subject: [PATCH 1530/2686] Fix hit explosions not being cleaned up correctly when rewinding --- osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs b/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs index 28509d1f4e..a7b94f9f22 100644 --- a/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs @@ -42,6 +42,8 @@ namespace osu.Game.Rulesets.Mania.UI { base.PrepareForUse(); + LifetimeStart = Time.Current; + (skinnableExplosion?.Drawable as IHitExplosion)?.Animate(Result); this.Delay(DURATION).Then().Expire(); From 207c76bdecc83879384a52ee3fcc7d579bc2a7eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 6 Oct 2022 20:17:35 +0900 Subject: [PATCH 1531/2686] Fix column lighting and key area not handling rewind correctly --- osu.Game.Rulesets.Mania/UI/Column.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 89413f0f1b..61585b2e5b 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Platform; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; @@ -68,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.UI private ISkinSource skin { get; set; } [BackgroundDependencyLoader] - private void load() + private void load(GameHost host) { skin.SourceChanged += onSourceChanged; onSourceChanged(); @@ -82,7 +83,10 @@ namespace osu.Game.Rulesets.Mania.UI Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + // This is pretty dodgy (and will cause weirdness when pausing gameplay) but is better than completely broken rewind. + Clock = host.UpdateThread.Clock, + ProcessCustomClock = false, }; InternalChildren = new[] @@ -94,7 +98,10 @@ namespace osu.Game.Rulesets.Mania.UI HitObjectArea, new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + // This is pretty dodgy (and will cause weirdness when pausing gameplay) but is better than completely broken rewind. + Clock = host.UpdateThread.Clock, + ProcessCustomClock = false, }, background, TopLevelContainer, From 98b578e8e6f37e389dc9ee3bfcc0602e9946cc24 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 16:12:10 +0900 Subject: [PATCH 1532/2686] Remove left-over incorrect fallback logic This was moved to `ManiaClassicSkinTransformer`. --- .../Skinning/Legacy/ManiaLegacySkinTransformer.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 31cfcf9e16..1d39721a2b 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -14,7 +14,6 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; -using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { @@ -151,18 +150,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { if (lookup is ManiaSkinConfigurationLookup maniaLookup) { - var legacyLookup = - base.GetConfig(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.ColumnIndex)); - - if (legacyLookup != null) - return legacyLookup; - - // default legacy fallback. - switch (maniaLookup.Lookup) - { - case LegacyManiaSkinConfigurationLookups.ColumnBackgroundColour: - return SkinUtils.As(new Bindable(Color4.Black)); - } + return base.GetConfig(new LegacyManiaSkinConfigurationLookup(beatmap.TotalColumns, maniaLookup.Lookup, maniaLookup.ColumnIndex)); } return base.GetConfig(lookup); From c7405d1c1cc8ddcb0bf0a32799e115992318ae3f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 17:00:10 +0900 Subject: [PATCH 1533/2686] Add missing immediate application of `AccentColour` in `DefaultKeyArea` Co-authored-by: Dan Balasescu --- osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs index 6196850f91..600c9feb73 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs @@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components Radius = 5, Colour = colour.NewValue.Opacity(0.5f), }; - }); + }, true); } private void onDirectionChanged(ValueChangedEvent direction) From 4b772643e98999f04ad5b1cf927f5c64c4c84c1b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 18:25:07 +0900 Subject: [PATCH 1534/2686] Use bindable flow for transfer of accent colour from columns to hit objects This fixes the case where changing a skin during gameplay runtime does not correctly convey colour information to off-screen `DrawableHitObject`s. --- osu.Game.Rulesets.Mania/UI/Column.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 89413f0f1b..c6bb3910e2 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -73,13 +73,6 @@ namespace osu.Game.Rulesets.Mania.UI skin.SourceChanged += onSourceChanged; onSourceChanged(); - AccentColour.BindValueChanged(colour => - { - // Manual transfer as hit objects may be moved between column and unbinding is non-trivial. - foreach (var obj in HitObjectContainer.Objects) - obj.AccentColour.Value = colour.NewValue; - }, true); - Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both @@ -142,7 +135,7 @@ namespace osu.Game.Rulesets.Mania.UI DrawableManiaHitObject maniaObject = (DrawableManiaHitObject)drawableHitObject; - maniaObject.AccentColour.Value = AccentColour.Value; + maniaObject.AccentColour.BindTo(AccentColour); maniaObject.CheckHittable = hitPolicy.IsHittable; } From 52ad766f86c933c4621e5fac1dc423227273dded Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 18:25:54 +0900 Subject: [PATCH 1535/2686] Remove manual binding of nested objects in `DrawableManiaHitObject` This is now handled by `Column` itself. Leaving the logic here as well will cause a circular bindable flow and stack overflow. --- .../Objects/Drawables/DrawableManiaHitObject.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 6cd39d835d..73dc937a00 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -65,22 +65,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Direction.BindValueChanged(OnDirectionChanged, true); } - protected override void OnApply() - { - base.OnApply(); - - if (ParentHitObject != null) - AccentColour.BindTo(ParentHitObject.AccentColour); - } - - protected override void OnFree() - { - base.OnFree(); - - if (ParentHitObject != null) - AccentColour.UnbindFrom(ParentHitObject.AccentColour); - } - protected virtual void OnDirectionChanged(ValueChangedEvent e) { Anchor = Origin = e.NewValue == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; From a8742f0cc31ba72e19e3d82d840cbcaf2acb5b55 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 18:46:26 +0900 Subject: [PATCH 1536/2686] Adjust out-of-the-box background dim back down to 70% It was previously bumped from 60% to 80%, but I've recently felt that this is too high as a default, and takes away from storyboards and video backgrounds. --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index e3bfb6b1e9..1378e1691a 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -120,7 +120,7 @@ namespace osu.Game.Configuration // Gameplay SetDefault(OsuSetting.PositionalHitsounds, true); // replaced by level setting below, can be removed 20220703. SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1); - SetDefault(OsuSetting.DimLevel, 0.8, 0, 1, 0.01); + SetDefault(OsuSetting.DimLevel, 0.7, 0, 1, 0.01); SetDefault(OsuSetting.BlurLevel, 0, 0, 1, 0.01); SetDefault(OsuSetting.LightenDuringBreaks, true); From 58eaa18725f4535e9b3eb7d785803863b0bac393 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 18:44:16 +0900 Subject: [PATCH 1537/2686] Add transparency to column backgrounds --- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs index c6377f9152..bfa3b34890 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon accentColour = column.AccentColour.GetBoundCopy(); accentColour.BindValueChanged(colour => { - background.Colour = colour.NewValue.Darken(5); + background.Colour = colour.NewValue.Darken(3).Opacity(0.6f); brightColour = colour.NewValue.Opacity(0.6f); dimColour = colour.NewValue.Opacity(0); }, true); From f9b4f491a69fca8e49fa780a1a3da3fbeeec45d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 18:44:24 +0900 Subject: [PATCH 1538/2686] Increase overall corner radius slightly --- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs index f560d2676c..454a6b012b 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { public const float NOTE_HEIGHT = 42; - public const float CORNER_RADIUS = 3; + public const float CORNER_RADIUS = 3.4f; private readonly IBindable direction = new Bindable(); private readonly IBindable accentColour = new Bindable(); From 12e9686092704b5e21f5020396d2d20e9d7162de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 18:44:29 +0900 Subject: [PATCH 1539/2686] Increase column spacing --- .../Skinning/Argon/ManiaArgonSkinTransformer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index 93c3a94316..27926c11eb 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -73,6 +73,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon switch (maniaLookup.Lookup) { + case LegacyManiaSkinConfigurationLookups.ColumnSpacing: + return SkinUtils.As(new Bindable(2)); + case LegacyManiaSkinConfigurationLookups.StagePaddingBottom: case LegacyManiaSkinConfigurationLookups.StagePaddingTop: return SkinUtils.As(new Bindable(30)); From e4657a7a3d0784afea6b56fd1f206addf2f9af0c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 19:02:08 +0900 Subject: [PATCH 1540/2686] Fix argon key area lighting being hidden by other columns in one direction --- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs | 2 -- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs index 132ef0d528..af179d5580 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs @@ -17,8 +17,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { public class ArgonHitExplosion : CompositeDrawable, IHitExplosion { - private const float default_large_faint_size = 0.8f; - public override bool RemoveWhenNotAlive => true; [Resolved] diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index 72f5f81890..073b9af307 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -150,6 +150,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon bottomIcon.Colour = colour.NewValue; }, true); + + // Yes, proxy everything. + column.TopLevelContainer.Add(CreateProxy()); } private void onDirectionChanged(ValueChangedEvent direction) From a4f827c7fd22f892612171e42c9dd8f5e06bd223 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 19:02:15 +0900 Subject: [PATCH 1541/2686] Remove broken `KeyArea` test scene Use `TestSceneStage` instead. --- .../Skinning/TestSceneKeyArea.cs | 51 ------------------- 1 file changed, 51 deletions(-) delete mode 100644 osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneKeyArea.cs diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneKeyArea.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneKeyArea.cs deleted file mode 100644 index bbbd7edb7b..0000000000 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneKeyArea.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. - -#nullable disable - -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Rulesets.Mania.UI.Components; -using osu.Game.Skinning; -using osuTK; - -namespace osu.Game.Rulesets.Mania.Tests.Skinning -{ - public class TestSceneKeyArea : ManiaSkinnableTestScene - { - [BackgroundDependencyLoader] - private void load() - { - SetContents(_ => new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.8f), - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new ColumnTestContainer(0, ManiaAction.Key1) - { - RelativeSizeAxes = Axes.Both, - Width = 0.5f, - Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) - { - RelativeSizeAxes = Axes.Both - }, - }, - new ColumnTestContainer(1, ManiaAction.Key2) - { - RelativeSizeAxes = Axes.Both, - Width = 0.5f, - Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) - { - RelativeSizeAxes = Axes.Both - }, - }, - } - }); - } - } -} From 551b7f0d1c0e43ecf1e50dd6c66e219c40953a11 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 19:08:55 +0900 Subject: [PATCH 1542/2686] Fix corner radius visible below hit target line --- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index 073b9af307..dd6aeadd65 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -50,7 +50,10 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon InternalChild = directionContainer = new Container { RelativeSizeAxes = Axes.X, - Height = Stage.HIT_TARGET_POSITION, + // Ensure the area is tall enough to put the target line in the correct location. + // This is to also allow the main background component to overlap the target line + // and avoid an inner corner radius being shown below the target line. + Height = Stage.HIT_TARGET_POSITION + ArgonNotePiece.CORNER_RADIUS * 2, Children = new[] { new Container @@ -70,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { RelativeSizeAxes = Axes.X, Anchor = Anchor.TopCentre, - Origin = Anchor.BottomCentre, + Origin = Anchor.TopCentre, Colour = OsuColour.Gray(196 / 255f), Height = ArgonNotePiece.CORNER_RADIUS * 2, Masking = true, From 08c3f3ae6df6387210d8255dff878256293f8699 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 19:27:00 +0900 Subject: [PATCH 1543/2686] Adjust lighting and timing of key area in general --- .../Skinning/Argon/ArgonKeyArea.cs | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index dd6aeadd65..badca71f36 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.UI.Scrolling; @@ -65,7 +66,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { Name = "Key gradient", Alpha = 0, - Blending = BlendingParameters.Additive, RelativeSizeAxes = Axes.Both, }, }, @@ -149,7 +149,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon accentColour = column.AccentColour.GetBoundCopy(); accentColour.BindValueChanged(colour => { - background.Colour = colour.NewValue.Darken(1f); + background.Colour = colour.NewValue.Darken(0.2f); bottomIcon.Colour = colour.NewValue; }, true); @@ -180,18 +180,19 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { if (e.Action != column.Action.Value) return false; - const double lighting_fade_in_duration = 50; - Color4 lightingColour = accentColour.Value.Lighten(0.9f); + const double lighting_fade_in_duration = 70; + Color4 lightingColour = getLightingColour(); background - .FadeTo(1, 40).Then() - .FadeTo(0.8f, 150, Easing.OutQuint); + .FadeTo(1, lighting_fade_in_duration, Easing.OutQuint) + .Then() + .FadeTo(0.6f, 500, Easing.In); hitTargetLine.FadeColour(Color4.White, lighting_fade_in_duration, Easing.OutQuint); hitTargetLine.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters { Type = EdgeEffectType.Glow, - Colour = lightingColour.Opacity(0.7f), + Colour = lightingColour.Opacity(0.4f), Radius = 20, }, lighting_fade_in_duration, Easing.OutQuint); @@ -210,7 +211,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon circle.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters { Type = EdgeEffectType.Glow, - Colour = lightingColour.Opacity(0.3f), + Colour = lightingColour.Opacity(0.2f), Radius = 60, }, lighting_fade_in_duration, Easing.OutQuint); } @@ -222,10 +223,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { if (e.Action != column.Action.Value) return; - const double lighting_fade_out_duration = 300; - Color4 lightingColour = accentColour.Value.Lighten(0.9f).Opacity(0); + const double lighting_fade_out_duration = 800; - background.FadeTo(0, lighting_fade_out_duration, Easing.OutQuint); + Color4 lightingColour = getLightingColour().Opacity(0); + + // background fades out faster than lighting elements to give better definition to the player. + background.FadeTo(0.3f, 50, Easing.OutQuint) + .Then() + .FadeOut(lighting_fade_out_duration, Easing.OutQuint); topIcon.ScaleTo(1f, 200, Easing.OutQuint); topIcon.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters @@ -255,5 +260,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon }, lighting_fade_out_duration, Easing.OutQuint); } } + + private Color4 getLightingColour() => Interpolation.ValueAt(0.2f, accentColour.Value, Color4.White, 0, 1); } } From c518fbf44a2bb03719fd2331c06bc3ca8cc52f76 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 19:31:23 +0900 Subject: [PATCH 1544/2686] Adjust argon hold bodies to better define away from the stage background --- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs index 10d5a4d267..7fbaf8ba64 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon AccentColour.BindValueChanged(colour => { - background.Colour = colour.NewValue.Opacity(0.2f); + background.Colour = colour.NewValue.Darken(1.5f); foreground.Colour = colour.NewValue.Opacity(0.1f); }, true); From 8101eea50dedc0a23bdd8bf63b12343be0bab97f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 20:04:39 +0900 Subject: [PATCH 1545/2686] Fix first glow of key area elements not working due to missing type --- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index badca71f36..98e46c1eac 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -77,6 +77,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Colour = OsuColour.Gray(196 / 255f), Height = ArgonNotePiece.CORNER_RADIUS * 2, Masking = true, + EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow }, }, new Container { @@ -100,6 +101,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Size = new Vector2(icon_circle_size), Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, + EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow }, }, new Circle { @@ -108,6 +110,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Size = new Vector2(icon_circle_size), Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, + EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow }, }, new Circle { @@ -116,6 +119,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Size = new Vector2(icon_circle_size), Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, + EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow }, }, } }, @@ -128,6 +132,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Masking = true, BorderThickness = 4, BorderColour = Color4.White, + EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow }, Children = new Drawable[] { new Box From d5490523ea8dd4a8f6d16541ff9ef61bc6d75efb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 20:05:08 +0900 Subject: [PATCH 1546/2686] Adjust hold notes further --- .../Skinning/Argon/ArgonHoldBodyPiece.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs index 7fbaf8ba64..c4b2181879 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.Objects.Drawables; using osuTK.Graphics; @@ -16,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon /// /// Represents length-wise portion of a hold note. /// - public class ArgonHoldBodyPiece : CompositeDrawable + public class ArgonHoldBodyPiece : CompositeDrawable, IHoldNoteBody { protected readonly Bindable AccentColour = new Bindable(); protected readonly IBindable IsHitting = new Bindable(); @@ -26,7 +27,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon public ArgonHoldBodyPiece() { - Blending = BlendingParameters.Additive; RelativeSizeAxes = Axes.Both; // Without this, the width of the body will be slightly larger than the head/tail. @@ -52,14 +52,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { var holdNote = (DrawableHoldNote)drawableObject; - AccentColour.BindTo(drawableObject.AccentColour); + AccentColour.BindTo(holdNote.AccentColour); IsHitting.BindTo(holdNote.IsHitting); } AccentColour.BindValueChanged(colour => { background.Colour = colour.NewValue.Darken(1.5f); - foreground.Colour = colour.NewValue.Opacity(0.1f); + foreground.Colour = colour.NewValue.Opacity(0.2f); }, true); IsHitting.BindValueChanged(hitting => @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon using (foreground.BeginDelayedSequence(synchronisedOffset)) { foreground.FadeTo(1, animation_length).Then() - .FadeTo(0, animation_length) + .FadeTo(0.5f, animation_length) .Loop(); } } @@ -86,5 +86,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon } }); } + + public void Recycle() + { + foreground.ClearTransforms(); + foreground.Alpha = 0; + } } } From 589b764b77803f65f5807b1cabd4efefd73a9de6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 20:30:38 +0900 Subject: [PATCH 1547/2686] Final tweaks because I don't know when to stop --- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index 98e46c1eac..7670c9bdf2 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -189,9 +189,10 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Color4 lightingColour = getLightingColour(); background + .FlashColour(accentColour.Value.Lighten(0.8f), 200, Easing.OutQuint) .FadeTo(1, lighting_fade_in_duration, Easing.OutQuint) .Then() - .FadeTo(0.6f, 500, Easing.In); + .FadeTo(0.8f, 500); hitTargetLine.FadeColour(Color4.White, lighting_fade_in_duration, Easing.OutQuint); hitTargetLine.TransformTo(nameof(EdgeEffect), new EdgeEffectParameters From 588713497ddab075e99ae4dd123d0a7c82a4bce8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 20:43:26 +0900 Subject: [PATCH 1548/2686] Attempt to make hold notes more legible at low background dims --- .../Skinning/Argon/ArgonColumnBackground.cs | 2 +- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs index bfa3b34890..598a765d3c 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon accentColour = column.AccentColour.GetBoundCopy(); accentColour.BindValueChanged(colour => { - background.Colour = colour.NewValue.Darken(3).Opacity(0.6f); + background.Colour = colour.NewValue.Darken(3).Opacity(0.8f); brightColour = colour.NewValue.Opacity(0.6f); dimColour = colour.NewValue.Opacity(0); }, true); diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs index c4b2181879..757190c4ae 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs @@ -32,6 +32,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon // Without this, the width of the body will be slightly larger than the head/tail. Masking = true; CornerRadius = ArgonNotePiece.CORNER_RADIUS; + Blending = BlendingParameters.Additive; } [BackgroundDependencyLoader(true)] @@ -58,7 +59,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon AccentColour.BindValueChanged(colour => { - background.Colour = colour.NewValue.Darken(1.5f); + background.Colour = colour.NewValue.Darken(1.2f); foreground.Colour = colour.NewValue.Opacity(0.2f); }, true); From e1e12f41e94c2fe7909048867ca217a414bbae51 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 21:00:02 +0900 Subject: [PATCH 1549/2686] Add more comprehensive inline comment --- osu.Game.Rulesets.Mania/UI/Column.cs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index be26c41ceb..3d46bdaa7b 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -71,15 +71,14 @@ namespace osu.Game.Rulesets.Mania.UI [BackgroundDependencyLoader] private void load(GameHost host) { + SkinnableDrawable keyArea; + skin.SourceChanged += onSourceChanged; onSourceChanged(); Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both, - // This is pretty dodgy (and will cause weirdness when pausing gameplay) but is better than completely broken rewind. - Clock = host.UpdateThread.Clock, - ProcessCustomClock = false, }; InternalChildren = new[] @@ -89,18 +88,18 @@ namespace osu.Game.Rulesets.Mania.UI // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements background.CreateProxy(), HitObjectArea, - new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) + keyArea = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) { RelativeSizeAxes = Axes.Both, - // This is pretty dodgy (and will cause weirdness when pausing gameplay) but is better than completely broken rewind. - Clock = host.UpdateThread.Clock, - ProcessCustomClock = false, }, background, TopLevelContainer, new ColumnTouchInputArea(this) }; + applyGameWideClock(background); + applyGameWideClock(keyArea); + TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy()); RegisterPool(10, 50); @@ -108,6 +107,18 @@ namespace osu.Game.Rulesets.Mania.UI RegisterPool(10, 50); RegisterPool(10, 50); RegisterPool(50, 250); + + // Some elements don't handle rewind correctly and fixing them is non-trivial. + // In the future we need a better solution to this, but as a temporary work-around, give these components the game-wide + // clock so they don't need to worry about rewind. + // This only works because they handle OnPressed/OnReleased which results in a correct state while rewinding. + // + // This is kinda dodgy (and will cause weirdness when pausing gameplay) but is better than completely broken rewind. + void applyGameWideClock(Drawable drawable) + { + drawable.Clock = host.UpdateThread.Clock; + drawable.ProcessCustomClock = false; + } } private void onSourceChanged() From 072b64b8d4d7cc68002e4caaafba18512ae19a65 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 21:16:11 +0900 Subject: [PATCH 1550/2686] Update all dependencies --- ...su.Game.Rulesets.EmptyFreeform.Tests.csproj | 4 ++-- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 4 ++-- ...u.Game.Rulesets.EmptyScrolling.Tests.csproj | 4 ++-- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 4 ++-- osu.Game.Benchmarks/osu.Game.Benchmarks.csproj | 4 ++-- .../osu.Game.Rulesets.Catch.Tests.csproj | 4 ++-- .../osu.Game.Rulesets.Mania.Tests.csproj | 4 ++-- .../osu.Game.Rulesets.Osu.Tests.csproj | 4 ++-- .../osu.Game.Rulesets.Taiko.Tests.csproj | 4 ++-- osu.Game.Tests/osu.Game.Tests.csproj | 6 +++--- .../osu.Game.Tournament.Tests.csproj | 4 ++-- osu.Game/osu.Game.csproj | 18 +++++++++--------- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj index b8604169aa..936808f38b 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj @@ -9,9 +9,9 @@ false - + - + diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 4117452579..35e7742172 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -9,9 +9,9 @@ false - + - + diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj index 0b119c8680..c1044965b5 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj @@ -9,9 +9,9 @@ false - + - + diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 4117452579..35e7742172 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -9,9 +9,9 @@ false - + - + diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj index 36ffd3b5b6..d62d422f33 100644 --- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj +++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj @@ -7,9 +7,9 @@ - + - + diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index d45f8a9692..c9db824615 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -1,9 +1,9 @@  - + - + WinExe diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index 2951076591..0d7b03d830 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -1,9 +1,9 @@  - + - + WinExe diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index c2973644cf..1eb1c85d93 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -1,10 +1,10 @@  - + - + WinExe diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index e8eaff4368..38e61f5624 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -1,9 +1,9 @@  - + - + WinExe diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 2572864e09..bdf8cc5136 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -1,11 +1,11 @@  - - + + - + diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index 5512b26863..bdef46a6b2 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -4,9 +4,9 @@ osu.Game.Tournament.Tests.TournamentTestRunner - + - + WinExe diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 26738673c8..efdb6c6995 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,15 +18,15 @@ - + - + - - - - + + + + @@ -34,13 +34,13 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - + From cac5e734951d96101b931eb044bcc6811783a1c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 21:28:25 +0900 Subject: [PATCH 1551/2686] Update props references --- osu.Android.props | 2 +- osu.iOS.props | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index c0be002bb5..2a678f1c61 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -56,6 +56,6 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index af1e21edab..47872e4ff7 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -83,10 +83,10 @@ - + - + From cff38e532a6be67e444b12df77dbfd5faabc90a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 7 Oct 2022 22:56:38 +0900 Subject: [PATCH 1552/2686] Attempt to remove console output --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33ec3d6602..56b3ebe87b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,7 +88,7 @@ jobs: run: dotnet build -c Debug -warnaserror osu.Desktop.slnf - name: Test - run: dotnet test $pwd/**/*.Tests/bin/Debug/*/*.Tests.dll --logger "trx;LogFileName=TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}.trx" + run: dotnet test $pwd/**/*.Tests/bin/Debug/*/*.Tests.dll --logger "trx;LogFileName=TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}.trx" -- NUnit.ConsoleOut=0 shell: pwsh # Attempt to upload results even if test fails. From 903c8612c89565f7ba25c337304abef567ed75db Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Fri, 7 Oct 2022 20:34:31 +0200 Subject: [PATCH 1553/2686] Move endTime to next timing point --- osu.Game/Rulesets/Objects/BarLineGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/BarLineGenerator.cs b/osu.Game/Rulesets/Objects/BarLineGenerator.cs index dec81d9bbd..2a2aaaecba 100644 --- a/osu.Game/Rulesets/Objects/BarLineGenerator.cs +++ b/osu.Game/Rulesets/Objects/BarLineGenerator.cs @@ -43,7 +43,7 @@ namespace osu.Game.Rulesets.Objects int currentBeat = 0; // Stop on the beat before the next timing point, or if there is no next timing point stop slightly past the last object - double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time - currentTimingPoint.BeatLength : lastHitTime + currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; + double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time : lastHitTime + currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; double barLength = currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; From 63ffaa69292afc14bfd9c8b4174b11b39cd620de Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Fri, 7 Oct 2022 20:38:32 +0200 Subject: [PATCH 1554/2686] Respect OmitFirstBarLine effect --- osu.Game/Rulesets/Objects/BarLineGenerator.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Objects/BarLineGenerator.cs b/osu.Game/Rulesets/Objects/BarLineGenerator.cs index 2a2aaaecba..85bff630e3 100644 --- a/osu.Game/Rulesets/Objects/BarLineGenerator.cs +++ b/osu.Game/Rulesets/Objects/BarLineGenerator.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -33,6 +31,7 @@ namespace osu.Game.Rulesets.Objects double lastHitTime = 1 + lastObject.GetEndTime(); var timingPoints = beatmap.ControlPointInfo.TimingPoints; + var effectPoints = beatmap.ControlPointInfo.EffectPoints; if (timingPoints.Count == 0) return; @@ -40,14 +39,22 @@ namespace osu.Game.Rulesets.Objects for (int i = 0; i < timingPoints.Count; i++) { TimingControlPoint currentTimingPoint = timingPoints[i]; + EffectControlPoint? currentEffectPoint = effectPoints.FirstOrDefault(p => p.Time == currentTimingPoint.Time); int currentBeat = 0; // Stop on the beat before the next timing point, or if there is no next timing point stop slightly past the last object double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time : lastHitTime + currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; + double startTime = currentTimingPoint.Time; + double barLength = currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; - for (double t = currentTimingPoint.Time; Precision.DefinitelyBigger(endTime, t); t += barLength, currentBeat++) + if (currentEffectPoint != null && currentEffectPoint.OmitFirstBarLine) + { + startTime += barLength; + } + + for (double t = startTime; Precision.DefinitelyBigger(endTime, t); t += barLength, currentBeat++) { double roundedTime = Math.Round(t, MidpointRounding.AwayFromZero); From f889f0df364614214445733214d68ad94bc94416 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Fri, 7 Oct 2022 20:41:45 +0200 Subject: [PATCH 1555/2686] Add tests for the BarLineGenerator --- .../TestSceneBarLineGeneration.cs | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs new file mode 100644 index 0000000000..4bff9c9646 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs @@ -0,0 +1,87 @@ +// 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 NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public class TestSceneBarLineGeneration : OsuTestScene + { + [Test] + public void TestCloseBarLineGeneration() + { + const double start_time = 1000; + + var beatmap = new Beatmap + { + HitObjects = + { + new Hit + { + Type = HitType.Centre, + StartTime = start_time + } + }, + BeatmapInfo = + { + Difficulty = new BeatmapDifficulty { SliderTickRate = 4 }, + Ruleset = new TaikoRuleset().RulesetInfo + }, + }; + + beatmap.ControlPointInfo.Add(start_time, new TimingControlPoint()); + beatmap.ControlPointInfo.Add(start_time + 1, new TimingControlPoint()); + + var barlines = new BarLineGenerator(beatmap).BarLines; + + AddAssert("first barline generated", () => barlines.Any(b => b.StartTime == start_time)); + AddAssert("second barline generated", () => barlines.Any(b => b.StartTime == start_time + 1)); + } + + [Test] + public void TestOmitBarLineEffectPoint() + { + const double start_time = 1000; + const double beat_length = 500; + + const int time_signature_numerator = 4; + + var beatmap = new Beatmap + { + HitObjects = + { + new Hit + { + Type = HitType.Centre, + StartTime = start_time + } + }, + BeatmapInfo = + { + Difficulty = new BeatmapDifficulty { SliderTickRate = 4 }, + Ruleset = new TaikoRuleset().RulesetInfo + }, + }; + + beatmap.ControlPointInfo.Add(start_time, new TimingControlPoint + { + BeatLength = beat_length, + TimeSignature = new TimeSignature(time_signature_numerator) + }); + + beatmap.ControlPointInfo.Add(start_time, new EffectControlPoint { OmitFirstBarLine = true }); + + var barlines = new BarLineGenerator(beatmap).BarLines; + + AddAssert("first barline ommited", () => !barlines.Any(b => b.StartTime == start_time)); + AddAssert("second barline generated", () => barlines.Any(b => b.StartTime == start_time + (beat_length * time_signature_numerator))); + } + } +} From 9d45f1ec12747df117d44b3a2b870ed20f709dc3 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Fri, 7 Oct 2022 22:08:12 +0200 Subject: [PATCH 1556/2686] Fix code style --- osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs index 4bff9c9646..095fddc33f 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Taiko.Tests }, }; - beatmap.ControlPointInfo.Add(start_time, new TimingControlPoint + beatmap.ControlPointInfo.Add(start_time, new TimingControlPoint { BeatLength = beat_length, TimeSignature = new TimeSignature(time_signature_numerator) @@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Taiko.Tests var barlines = new BarLineGenerator(beatmap).BarLines; - AddAssert("first barline ommited", () => !barlines.Any(b => b.StartTime == start_time)); + AddAssert("first barline ommited", () => barlines.All(b => b.StartTime != start_time)); AddAssert("second barline generated", () => barlines.Any(b => b.StartTime == start_time + (beat_length * time_signature_numerator))); } } From abf56c27a10abb47a360ecdfb15f2302bbd64f54 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 8 Oct 2022 17:11:09 +0300 Subject: [PATCH 1557/2686] Do not requere dialog overlay --- .../Online/TestSceneCommentsContainer.cs | 14 +-- .../Visual/Online/TestSceneDrawableComment.cs | 5 -- .../TestSceneOfflineCommentsContainer.cs | 4 - osu.Game/Overlays/Comments/DrawableComment.cs | 85 ++++++++++--------- 4 files changed, 50 insertions(+), 58 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index d1624b8220..49e16d9281 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -25,9 +25,6 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - [Cached(typeof(IDialogOverlay))] - private readonly DialogOverlay dialogOverlay = new DialogOverlay(); - private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; private CommentsContainer commentsContainer; @@ -35,15 +32,10 @@ namespace osu.Game.Tests.Visual.Online [SetUp] public void SetUp() => Schedule(() => { - if (dialogOverlay.Parent != null) Remove(dialogOverlay, false); - Children = new Drawable[] + Child = new BasicScrollContainer { - new BasicScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = commentsContainer = new CommentsContainer() - }, - dialogOverlay + RelativeSizeAxes = Axes.Both, + Child = commentsContainer = new CommentsContainer() }; }); diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs index ccbf996c15..cab0ffa3ba 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -20,15 +20,11 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - [Cached(typeof(IDialogOverlay))] - private readonly DialogOverlay dialogOverlay = new DialogOverlay(); - private Container container; [SetUp] public void SetUp() => Schedule(() => { - if (dialogOverlay.Parent != null) Remove(dialogOverlay, false); Children = new Drawable[] { new Box @@ -41,7 +37,6 @@ namespace osu.Game.Tests.Visual.Online RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }, - dialogOverlay }; }); diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs index 07d491e8e3..6cd6b25c14 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -24,22 +24,18 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); - [Cached(typeof(IDialogOverlay))] - private readonly DialogOverlay dialogOverlay = new DialogOverlay(); private TestCommentsContainer comments; [SetUp] public void SetUp() => Schedule(() => { - if (dialogOverlay.Parent != null) Remove(dialogOverlay, false); Clear(); Add(new BasicScrollContainer { RelativeSizeAxes = Axes.Both, Child = comments = new TestCommentsContainer() }); - Add(dialogOverlay); }); [Test] diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 15594b2255..87545ee6a3 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.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. -#nullable disable - using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osu.Game.Graphics; @@ -35,7 +33,7 @@ namespace osu.Game.Overlays.Comments { private const int avatar_size = 40; - public Action RepliesRequested; + public Action RepliesRequested = null!; public readonly Comment Comment; @@ -49,21 +47,21 @@ namespace osu.Game.Overlays.Comments private int currentPage; - private FillFlowContainer childCommentsVisibilityContainer; - private FillFlowContainer childCommentsContainer; - private LoadRepliesButton loadRepliesButton; - private ShowMoreRepliesButton showMoreButton; - private ShowRepliesButton showRepliesButton; - private ChevronButton chevronButton; - private LinkFlowContainer actionsContainer; - private LoadingSpinner actionsLoading; - private DeletedCommentsCounter deletedCommentsCounter; + private FillFlowContainer childCommentsVisibilityContainer = null!; + private FillFlowContainer childCommentsContainer = null!; + private LoadRepliesButton loadRepliesButton = null!; + private ShowMoreRepliesButton showMoreButton = null!; + private ShowRepliesButton showRepliesButton = null!; + private ChevronButton chevronButton = null!; + private LinkFlowContainer actionsContainer = null!; + private LoadingSpinner actionsLoading = null!; + private DeletedCommentsCounter deletedCommentsCounter = null!; + + [Resolved(canBeNull: true)] + private IDialogOverlay? dialogOverlay { get; set; } [Resolved] - private IDialogOverlay dialogOverlay { get; set; } - - [Resolved] - private IAPIProvider api { get; set; } + private IAPIProvider api { get; set; } = null!; public DrawableComment(Comment comment) { @@ -278,7 +276,7 @@ namespace osu.Game.Overlays.Comments if (Comment.UserId.HasValue) username.AddUserLink(Comment.User); else - username.AddText(Comment.LegacyName); + username.AddText(Comment.LegacyName!); if (Comment.EditedAt.HasValue && Comment.EditedUser != null) { @@ -354,28 +352,39 @@ namespace osu.Game.Overlays.Comments }; } + /** + * Invokes comment deletion with confirmation. + */ private void deleteComment() { - dialogOverlay.Push(new ConfirmDialog("Do you really want to delete your comment?", () => + if (dialogOverlay == null) + deleteCommentRequest(); + else + dialogOverlay.Push(new ConfirmDialog("Do you really want to delete your comment?", deleteCommentRequest)); + } + + /** + * Invokes comment deletion directly. + */ + private void deleteCommentRequest() + { + actionsContainer.Hide(); + actionsLoading.Show(); + var request = new CommentDeleteRequest(Comment.Id); + request.Success += _ => { - actionsContainer.Hide(); - actionsLoading.Show(); - var request = new CommentDeleteRequest(Comment.Id); - request.Success += _ => - { - actionsLoading.Hide(); - AutoSizeAxes = Axes.None; - Masking = true; - this.ResizeHeightTo(0, 1000, Easing.Out); - this.FadeOut(1000, Easing.Out).Expire(); - }; - request.Failure += _ => - { - actionsLoading.Hide(); - actionsContainer.Show(); - }; - api.Queue(request); - })); + actionsLoading.Hide(); + AutoSizeAxes = Axes.None; + Masking = true; + this.ResizeHeightTo(0, 1000, Easing.Out); + this.FadeOut(1000, Easing.Out).Expire(); + }; + request.Failure += _ => + { + actionsLoading.Hide(); + actionsContainer.Show(); + }; + api.Queue(request); } protected override void LoadComplete() @@ -486,7 +495,7 @@ namespace osu.Game.Overlays.Comments { public LocalisableString TooltipText => getParentMessage(); - private readonly Comment parentComment; + private readonly Comment? parentComment; public ParentUsername(Comment comment) { @@ -506,7 +515,7 @@ namespace osu.Game.Overlays.Comments new OsuSpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = parentComment?.User?.Username ?? parentComment?.LegacyName + Text = parentComment?.User?.Username ?? parentComment?.LegacyName! } }; } From 4e7c30504f2af736806c4839ea42df0c56e6b965 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 8 Oct 2022 17:15:10 +0300 Subject: [PATCH 1558/2686] Schedule action buttons visibility changes --- osu.Game/Overlays/Comments/DrawableComment.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 87545ee6a3..3cb7db0ec2 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -352,9 +352,9 @@ namespace osu.Game.Overlays.Comments }; } - /** - * Invokes comment deletion with confirmation. - */ + /// + /// Invokes comment deletion with confirmation. + /// private void deleteComment() { if (dialogOverlay == null) @@ -363,27 +363,27 @@ namespace osu.Game.Overlays.Comments dialogOverlay.Push(new ConfirmDialog("Do you really want to delete your comment?", deleteCommentRequest)); } - /** - * Invokes comment deletion directly. - */ + /// + /// Invokes comment deletion directly. + /// private void deleteCommentRequest() { actionsContainer.Hide(); actionsLoading.Show(); var request = new CommentDeleteRequest(Comment.Id); - request.Success += _ => + request.Success += _ => Schedule(() => { actionsLoading.Hide(); AutoSizeAxes = Axes.None; Masking = true; this.ResizeHeightTo(0, 1000, Easing.Out); this.FadeOut(1000, Easing.Out).Expire(); - }; - request.Failure += _ => + }); + request.Failure += _ => Schedule(() => { actionsLoading.Hide(); actionsContainer.Show(); - }; + }); api.Queue(request); } From c11258a7e9075a6ca818178365446a3d4024108c Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 8 Oct 2022 17:20:25 +0300 Subject: [PATCH 1559/2686] Tidy up test reloading --- .../Visual/Online/TestSceneCommentActions.cs | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index a58873e457..51ae8efba7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -9,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -21,6 +22,8 @@ namespace osu.Game.Tests.Visual.Online { public class TestSceneCommentActions : OsuManualInputManagerTestScene { + private Container content = null!; + protected override Container Content => content; private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; [Cached(typeof(IDialogOverlay))] @@ -31,22 +34,26 @@ namespace osu.Game.Tests.Visual.Online private CommentsContainer commentsContainer = null!; + [BackgroundDependencyLoader] + private void load() + { + base.Content.AddRange(new Drawable[] + { + content = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both + }, + dialogOverlay + }); + } + [SetUpSteps] public void SetUp() { Schedule(() => { API.Login("test", "test"); - if (dialogOverlay.Parent != null) Remove(dialogOverlay, false); - Children = new Container[] - { - new BasicScrollContainer - { - RelativeSizeAxes = Axes.Both, - Child = commentsContainer = new CommentsContainer() - }, - dialogOverlay - }; + Child = commentsContainer = new CommentsContainer(); }); } From 6e82ffbc6f2d762277ac872376fb0731a9ecc60c Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 8 Oct 2022 17:41:51 +0300 Subject: [PATCH 1560/2686] Add check for spinner --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 51ae8efba7..8f9e2f6ba4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -136,6 +137,7 @@ namespace osu.Game.Tests.Visual.Online }); AddStep("Confirm dialog", () => InputManager.Key(Key.Number1)); AddUntilStep("Deletion requested", () => delete); + AddAssert("Loading spinner shown", () => commentsContainer.ChildrenOfType().Any(d => d.IsPresent)); AddUntilStep("Comment is deleted locally", () => { return this.ChildrenOfType().SingleOrDefault(x => x.Comment.Id == 1) == null; From b6972004609d613e4f33e21734ff6a3b4f13a9a1 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 8 Oct 2022 18:41:08 +0300 Subject: [PATCH 1561/2686] Properly modify comment visual state on deletion --- osu.Game/Overlays/Comments/DrawableComment.cs | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 3cb7db0ec2..00a832cac8 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -47,6 +47,11 @@ namespace osu.Game.Overlays.Comments private int currentPage; + /// + /// Local field for tracking comment state. Initialized from Comment.IsDeleted, may change when deleting was requested by user. + /// + public bool WasDeleted { get; protected set; } + private FillFlowContainer childCommentsVisibilityContainer = null!; private FillFlowContainer childCommentsContainer = null!; private LoadRepliesButton loadRepliesButton = null!; @@ -56,6 +61,9 @@ namespace osu.Game.Overlays.Comments private LinkFlowContainer actionsContainer = null!; private LoadingSpinner actionsLoading = null!; private DeletedCommentsCounter deletedCommentsCounter = null!; + private OsuSpriteText deletedLabel = null!; + private GridContainer content = null!; + private VotePill votePill = null!; [Resolved(canBeNull: true)] private IDialogOverlay? dialogOverlay { get; set; } @@ -74,8 +82,6 @@ namespace osu.Game.Overlays.Comments LinkFlowContainer username; FillFlowContainer info; CommentMarkdownContainer message; - GridContainer content; - VotePill votePill; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -158,9 +164,9 @@ namespace osu.Game.Overlays.Comments }, Comment.Pinned ? new PinnedCommentNotice() : Empty(), new ParentUsername(Comment), - new OsuSpriteText + deletedLabel = new OsuSpriteText { - Alpha = Comment.IsDeleted ? 1 : 0, + Alpha = 0f, Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), Text = CommentsStrings.Deleted } @@ -312,11 +318,9 @@ namespace osu.Game.Overlays.Comments if (Comment.HasMessage) message.Text = Comment.Message; - if (Comment.IsDeleted) - { - content.FadeColour(OsuColour.Gray(0.5f)); - votePill.Hide(); - } + WasDeleted = Comment.IsDeleted; + if (WasDeleted) + makeDeleted(); if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) { @@ -352,6 +356,17 @@ namespace osu.Game.Overlays.Comments }; } + /// + /// Transforms some comment's components to show it as deleted. Invoked both from loading and deleting. + /// + private void makeDeleted() + { + deletedLabel.Alpha = 1f; + content.FadeColour(OsuColour.Gray(0.5f)); + votePill.Hide(); + actionsContainer.Expire(); + } + /// /// Invokes comment deletion with confirmation. /// @@ -374,10 +389,10 @@ namespace osu.Game.Overlays.Comments request.Success += _ => Schedule(() => { actionsLoading.Hide(); - AutoSizeAxes = Axes.None; - Masking = true; - this.ResizeHeightTo(0, 1000, Easing.Out); - this.FadeOut(1000, Easing.Out).Expire(); + makeDeleted(); + WasDeleted = true; + if (!ShowDeleted.Value) + Hide(); }); request.Failure += _ => Schedule(() => { @@ -391,7 +406,7 @@ namespace osu.Game.Overlays.Comments { ShowDeleted.BindValueChanged(show => { - if (Comment.IsDeleted) + if (WasDeleted) this.FadeTo(show.NewValue ? 1 : 0); }, true); childrenExpanded.BindValueChanged(expanded => childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0), true); From c384093802edbbe0147a66a226125c6b02638a9f Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 8 Oct 2022 18:53:41 +0300 Subject: [PATCH 1562/2686] Update main test and add failure scenario test --- .../Visual/Online/TestSceneCommentActions.cs | 52 ++++++++++++++++++- osu.Game/Overlays/Comments/DrawableComment.cs | 1 + 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 8f9e2f6ba4..11210db8a9 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -140,7 +140,57 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Loading spinner shown", () => commentsContainer.ChildrenOfType().Any(d => d.IsPresent)); AddUntilStep("Comment is deleted locally", () => { - return this.ChildrenOfType().SingleOrDefault(x => x.Comment.Id == 1) == null; + return this.ChildrenOfType().Single(x => x.Comment.Id == 1).WasDeleted; + }); + } + + [Test] + public void TestDeletionFail() + { + DrawableComment? ourComment = null; + bool delete = false; + + addTestComments(); + AddUntilStep("Comment exists", () => + { + var comments = this.ChildrenOfType(); + ourComment = comments.SingleOrDefault(x => x.Comment.Id == 1); + return ourComment != null; + }); + AddStep("It has delete button", () => + { + var btn = ourComment.ChildrenOfType().Single(x => x.Text == "Delete"); + InputManager.MoveMouseTo(btn); + }); + AddStep("Click delete button", () => + { + InputManager.Click(MouseButton.Left); + }); + AddStep("Setup request handling", () => + { + dummyAPI.HandleRequest = request => + { + if (request is not CommentDeleteRequest req) + return false; + + req.TriggerFailure(new Exception()); + delete = true; + return false; + }; + }); + AddStep("Confirm dialog", () => InputManager.Key(Key.Number1)); + AddUntilStep("Deletion requested", () => delete); + AddUntilStep("Comment is available", () => + { + return !this.ChildrenOfType().Single(x => x.Comment.Id == 1).WasDeleted; + }); + AddAssert("Loading spinner hidden", () => + { + return ourComment.ChildrenOfType().All(d => !d.IsPresent); + }); + AddAssert("Actions available", () => + { + return ourComment.ChildrenOfType().Single(x => x.Name == @"Actions buttons").IsPresent; }); } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 00a832cac8..105618c728 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -201,6 +201,7 @@ namespace osu.Game.Overlays.Comments }, actionsContainer = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) { + Name = @"Actions buttons", AutoSizeAxes = Axes.Both, Spacing = new Vector2(10, 0) }, From e7b1f369a32fe42e5b1ef31d6b448c95cab6c1f1 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 8 Oct 2022 18:55:58 +0300 Subject: [PATCH 1563/2686] Revert unwanted changes in other tests --- osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs | 6 ++---- .../Visual/Online/TestSceneOfflineCommentsContainer.cs | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 49e16d9281..a94b9e61c0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -31,13 +31,11 @@ namespace osu.Game.Tests.Visual.Online [SetUp] public void SetUp() => Schedule(() => - { Child = new BasicScrollContainer { RelativeSizeAxes = Axes.Both, Child = commentsContainer = new CommentsContainer() - }; - }); + }); [Test] public void TestIdleState() @@ -141,7 +139,7 @@ namespace osu.Game.Tests.Visual.Online }; }); - private static CommentBundle getExampleComments(bool withPinned = false) + private CommentBundle getExampleComments(bool withPinned = false) { var bundle = new CommentBundle { diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs index 6cd6b25c14..07ccfcec88 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -24,7 +24,6 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); - private TestCommentsContainer comments; [SetUp] From ff14453c2ba7e289e518586b2b97092d4355f761 Mon Sep 17 00:00:00 2001 From: pfg Date: Sat, 8 Oct 2022 12:42:29 -0400 Subject: [PATCH 1564/2686] Preserve collections when saving a beatmap --- osu.Game/Beatmaps/BeatmapManager.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 2c6edb64f8..1c9933387c 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -17,6 +17,7 @@ using osu.Framework.IO.Stores; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps.Formats; +using osu.Game.Collections; using osu.Game.Database; using osu.Game.Extensions; using osu.Game.IO.Archives; @@ -311,6 +312,8 @@ namespace osu.Game.Beatmaps if (existingFileInfo != null) DeleteFile(setInfo, existingFileInfo); + string? oldMd5Hash = beatmapInfo.MD5Hash; + beatmapInfo.MD5Hash = stream.ComputeMD5Hash(); beatmapInfo.Hash = stream.ComputeSHA2Hash(); @@ -327,6 +330,12 @@ namespace osu.Game.Beatmaps setInfo.CopyChangesToRealm(liveBeatmapSet); + foreach (var collection in r.All()) + { + if (collection.BeatmapMD5Hashes.Remove(oldMd5Hash)) + collection.BeatmapMD5Hashes.Add(beatmapInfo.MD5Hash); + } + ProcessBeatmap?.Invoke((liveBeatmapSet, false)); }); } From edec61372450df63efb434a40b90329c1dfb26f4 Mon Sep 17 00:00:00 2001 From: pfg Date: Sat, 8 Oct 2022 13:58:42 -0400 Subject: [PATCH 1565/2686] Remove unnecessary '?' --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 1c9933387c..71cafd46c0 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -312,7 +312,7 @@ namespace osu.Game.Beatmaps if (existingFileInfo != null) DeleteFile(setInfo, existingFileInfo); - string? oldMd5Hash = beatmapInfo.MD5Hash; + string oldMd5Hash = beatmapInfo.MD5Hash; beatmapInfo.MD5Hash = stream.ComputeMD5Hash(); beatmapInfo.Hash = stream.ComputeSHA2Hash(); From 098a56a78494613413471ecdde26aef5f827ee48 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 8 Oct 2022 21:24:57 +0300 Subject: [PATCH 1566/2686] Add custom container extension support --- .../Containers/Markdown/OsuMarkdownContainer.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs index 62fefe201d..3855ed6d4e 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs @@ -5,6 +5,7 @@ using Markdig; using Markdig.Extensions.AutoLinks; +using Markdig.Extensions.CustomContainers; using Markdig.Extensions.EmphasisExtras; using Markdig.Extensions.Footnotes; using Markdig.Extensions.Tables; @@ -32,6 +33,12 @@ namespace osu.Game.Graphics.Containers.Markdown /// protected virtual bool Autolinks => false; + /// + /// Allows this markdown container to parse custom containers (used for flags and infoboxes). + /// + /// + protected virtual bool CustomContainers => false; + public OsuMarkdownContainer() { LineSpacing = 21; @@ -107,6 +114,9 @@ namespace osu.Game.Graphics.Containers.Markdown if (Autolinks) pipeline = pipeline.UseAutoLinks(); + if (CustomContainers) + pipeline.UseCustomContainers(); + return pipeline.Build(); } } From a9aba743514d13de403b6685d1475afa914beb63 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 8 Oct 2022 21:26:20 +0300 Subject: [PATCH 1567/2686] Add markdown country flag support --- .../Markdown/OsuMarkdownTextFlowContainer.cs | 27 +++++++++++++++++++ .../Wiki/Markdown/WikiMarkdownContainer.cs | 7 +++++ 2 files changed, 34 insertions(+) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs index db8abfb269..fb8f13ab84 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs @@ -3,6 +3,9 @@ #nullable disable +using System; +using System.Linq; +using Markdig.Extensions.CustomContainers; using Markdig.Syntax.Inlines; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -11,6 +14,9 @@ using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Overlays; +using osu.Game.Users; +using osu.Game.Users.Drawables; +using osuTK; namespace osu.Game.Graphics.Containers.Markdown { @@ -33,6 +39,27 @@ namespace osu.Game.Graphics.Containers.Markdown protected override SpriteText CreateEmphasisedSpriteText(bool bold, bool italic) => CreateSpriteText().With(t => t.Font = t.Font.With(weight: bold ? FontWeight.Bold : FontWeight.Regular, italics: italic)); + protected override void AddCustomComponent(CustomContainerInline inline) + { + if (!(inline.FirstChild is LiteralInline literal)) + { + base.AddCustomComponent(inline); + return; + } + + string[] attributes = literal.Content.ToString().Trim(' ', '{', '}').Split(); + string flagAttribute = attributes.SingleOrDefault(a => a.StartsWith(@"flag", StringComparison.Ordinal)); + + if (flagAttribute == null) + { + base.AddCustomComponent(inline); + return; + } + + string flag = flagAttribute.Split('=').Last().Trim('"'); + AddDrawable(new DrawableFlag(Enum.Parse(flag)) { Size = new Vector2(20, 15) }); + } + private class OsuMarkdownInlineCode : Container { [Resolved] diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index 4f1083a75c..15c455416c 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -4,6 +4,7 @@ #nullable disable using System.Linq; +using Markdig.Extensions.CustomContainers; using Markdig.Extensions.Yaml; using Markdig.Syntax; using Markdig.Syntax.Inlines; @@ -16,6 +17,7 @@ namespace osu.Game.Overlays.Wiki.Markdown public class WikiMarkdownContainer : OsuMarkdownContainer { protected override bool Footnotes => true; + protected override bool CustomContainers => true; public string CurrentPath { @@ -26,6 +28,11 @@ namespace osu.Game.Overlays.Wiki.Markdown { switch (markdownObject) { + case CustomContainer: + // infoboxes are parsed into CustomContainer objects, but we don't have support for infoboxes yet. + // todo: add support for infobox. + break; + case YamlFrontMatterBlock yamlFrontMatterBlock: container.Add(new WikiNoticeContainer(yamlFrontMatterBlock)); break; From 13083813bdbdaf6c39520fb3e5467c3f10e9e8b2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 8 Oct 2022 21:26:42 +0300 Subject: [PATCH 1568/2686] Update hardcoded article page --- osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs index 558bff2f3c..27cd74bb1f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs @@ -100,7 +100,7 @@ namespace osu.Game.Tests.Visual.Online Locale = "en", Subtitle = "Article styling criteria", Markdown = - "# Formatting\n\n*For the writing standards, see: [Article style criteria/Writing](../Writing)*\n\n*Notice: This article uses [RFC 2119](https://tools.ietf.org/html/rfc2119 \"IETF Tools\") to describe requirement levels.*\n\n## Locales\n\nListed below are the properly-supported locales for the wiki:\n\n| File Name | Locale Name | Native Script |\n| :-- | :-- | :-- |\n| `en.md` | English | English |\n| `ar.md` | Arabic | اَلْعَرَبِيَّةُ |\n| `be.md` | Belarusian | Беларуская мова |\n| `bg.md` | Bulgarian | Български |\n| `cs.md` | Czech | Česky |\n| `da.md` | Danish | Dansk |\n| `de.md` | German | Deutsch |\n| `gr.md` | Greek | Ελληνικά |\n| `es.md` | Spanish | Español |\n| `fi.md` | Finnish | Suomi |\n| `fr.md` | French | Français |\n| `hu.md` | Hungarian | Magyar |\n| `id.md` | Indonesian | Bahasa Indonesia |\n| `it.md` | Italian | Italiano |\n| `ja.md` | Japanese | 日本語 |\n| `ko.md` | Korean | 한국어 |\n| `nl.md` | Dutch | Nederlands |\n| `no.md` | Norwegian | Norsk |\n| `pl.md` | Polish | Polski |\n| `pt.md` | Portuguese | Português |\n| `pt-br.md` | Brazilian Portuguese | Português (Brasil) |\n| `ro.md` | Romanian | Română |\n| `ru.md` | Russian | Русский |\n| `sk.md` | Slovak | Slovenčina |\n| `sv.md` | Swedish | Svenska |\n| `th.md` | Thai | ไทย |\n| `tr.md` | Turkish | Türkçe |\n| `uk.md` | Ukrainian | Українська мова |\n| `vi.md` | Vietnamese | Tiếng Việt |\n| `zh.md` | Chinese (Simplified) | 简体中文 |\n| `zh-tw.md` | Traditional Chinese (Taiwan) | 繁體中文(台灣) |\n\n*Note: The website will give readers their selected language's version of an article. If it is not available, the English version will be given.*\n\n### Content parity\n\nTranslations are subject to strict content parity with their English article, in the sense that they must have the same message, regardless of grammar and syntax. Any changes to the translations' meanings must be accompanied by equivalent changes to the English article.\n\nThere are some cases where the content is allowed to differ:\n\n- Articles originally written in a language other than English (in this case, English should act as the translation)\n- Explanations of English words that are common terms in the osu! community\n- External links\n- Tags\n- Subcommunity-specific explanations\n\n## Front matter\n\nFront matter must be placed at the very top of the file. It is written in [YAML](https://en.wikipedia.org/wiki/YAML#Example \"YAML Wikipedia article\") and describes additional information about the article. This must be surrounded by three hyphens (`---`) on the lines above and below it, and an empty line must follow it before the title heading.\n\n### Articles that need help\n\n*Note: Avoid translating English articles with this tag. In addition to this, this tag should be added when the translation needs its own clean up.*\n\nThe `needs_cleanup` tag may be added to articles that need rewriting or formatting help. It is also acceptable to open an issue on GitHub for this purpose. This tag must be written as shown below:\n\n```yaml\nneeds_cleanup: true\n```\n\nWhen adding this tag to an article, [comments](#comments) should also be added to explain what needs to be done to remove the tag.\n\n### Outdated articles\n\n*Note: Avoid translating English articles with this tag. If the English article has this tag, the translation must also have this tag.*\n\nTranslated articles that are outdated must use the `outdated` tag when the English variant is updated. English articles may also become outdated when the content they contain is misleading or no longer relevant. This tag must be written as shown below:\n\n```yaml\noutdated: true\n```\n\nWhen adding this tag to an article, [comments](#comments) should also be added to explain what needs to be updated to remove the tag.\n\n### Tagging articles\n\nTags help the website's search engine query articles better. Tags should be written in the same language as the article and include the original list of tags. Tags should use lowercase letters where applicable.\n\nFor example, an article called \"Beatmap discussion\" may include the following tags:\n\n```yaml\ntags:\n - beatmap discussions\n - modding V2\n - MV2\n```\n\n### Translations without reviews\n\n*Note: Wiki maintainers will determine and apply this mark prior to merging.*\n\nSometimes, translations are added to the wiki without review from other native speakers of the language. In this case, the `no_native_review` mark is added to let future translators know that it may need to be checked again. This tag must be written as shown below:\n\n```yaml\nno_native_review: true\n```\n\n## Article naming\n\n*See also: [Folder names](#folder-names) and [Titles](#titles)*\n\nArticle titles should be singular and use sentence case. See [Wikipedia's naming conventions article](https://en.wikipedia.org/wiki/Wikipedia:Naming_conventions_(plurals) \"Wikipedia\") for more details.\n\nArticle titles should match the folder name it is in (spaces may replace underscores (`_`) where appropriate). If the folder name changes, the article title should be changed to match it and vice versa.\n\n---\n\nContest and tournament articles are an exception. The folder name must use abbreviations, acronyms, or initialisms. The article's title must be the full name of the contest or tournament.\n\n## Folder and file structure\n\n### Folder names\n\n*See also: [Article naming](#article-naming)*\n\nFolder names must be in English and use sentence case.\n\nFolder names must only use these characters:\n\n- uppercase and lowercase letters\n- numbers\n- underscores (`_`)\n- hyphens (`-`)\n- exclamation marks (`!`)\n\n### Article file names\n\nThe file name of an article can be found in the `File Name` column of the [locales section](#locales). The location of a translated article must be placed in the same folder as the English article.\n\n### Index articles\n\nAn index article must be created if the folder is intended to only hold other articles. Index articles must contain a list of articles that are inside its own folder. They may also contain other information, such as a lead paragraph or descriptions of the linked articles.\n\n### Disambiguation articles\n\n[Disambiguation](/wiki/Disambiguation) articles must be placed in the `/wiki/Disambiguation` folder. The main page must be updated to include the disambiguation article. Refer to [Disambiguation/Mod](/wiki/Disambiguation/Mod) as an example.\n\nRedirects must be updated to have the ambiguous keyword(s) redirect to the disambiguation article.\n\nArticles linked from a disambiguation article must have a [For other uses](#for-other-uses) hatnote.\n\n## HTML\n\nHTML must not be used, with exception for [comments](#comments). The structure of the article must be redone if HTML is used.\n\n### Comments\n\nHTML comments should be used for marking to-dos, but may also be used to annotate text. They should be on their own line, but can be placed inline in a paragraph. If placed inline, the start of the comment must not have a space.\n\nBad example:\n\n```markdown\nHTML comments should be used for marking to-dos or annotate text.\n```\n\nGood example:\n\n```markdown\nHTML comments should be used for marking to-dos or annotate text.\n```\n\n## Editing\n\n### End of line sequence\n\n*Caution: Uploading Markdown files using `CRLF` (carriage return and line feed) via GitHub will result in those files using `CRLF`. To prevent this, set the line ending to `LF` (line feed) before uploading.*\n\nMarkdown files must be checked in using the `LF` end of line sequence.\n\n### Escaping\n\nMarkdown syntax should be escaped as needed. However, article titles are parsed as plain text and so must not be escaped.\n\n### Paragraphs\n\nEach paragraph must be followed by one empty line.\n\n### Line breaks\n\nLine breaks must use a backslash (`\\`).\n\nLine breaks must be used sparingly.\n\n## Hatnote\n\n*Not to be confused with [Notice](#notice).*\n\nHatnotes are short notes placed at the top of an article or section to help readers navigate to related articles or inform them about related topics.\n\nHatnotes must be italicised and be placed immediately after the heading. If multiple hatnotes are used, they must be on the same paragraph separated with a line break.\n\n### Main page\n\n*Main page* hatnotes direct the reader to the main article of a topic. When this hatnote is used, it implies that the section it is on is a summary of what the linked page is about. This hatnote should have only one link. These must be formatted as follows:\n\n```markdown\n*Main page: {article}*\n\n*Main pages: {article} and {article}*\n```\n\n### See also\n\n*See also* hatnotes suggest to readers other points of interest from a given article or section. These must be formatted as follows:\n\n```markdown\n*See also: {article}*\n\n*See also: {article} and {article}*\n```\n\n### For see\n\n*For see* hatnotes are similar to *see also* hatnotes, but are generally more descriptive and direct. This hatnote may use more than one link if necessary. These must be formatted as follows:\n\n```markdown\n*For {description}, see: {article}`*\n\n*For {description}, see: {article} and {article}`*\n```\n\n### Not to be confused with\n\n*Not to be confused with* hatnotes help distinguish ambiguous or misunderstood article titles or sections. This hatnote may use more than one link if necessary. These must be formatted as follows:\n\n```markdown\n*Not to be confused with {article}.*\n\n*Not to be confused with {article} or {article}.*\n```\n\n### For other uses\n\n*For other uses* hatnotes are similar to *not to be confused with* hatnotes, but links directly to the [disambiguation article](#disambiguation-articles). This hatnote must only link to the disambiguation article. These must be formatted as follows:\n\n```markdown\n*For other uses, see {disambiguation article}.*\n```\n\n## Notice\n\n*Not to be confused with [Hatnote](#hatnote).*\n\nA notice should be placed where appropriate in a section, but must start off the paragraph and use italics. Notices may contain bolding where appropriate, but should be kept to a minimum. Notices must be written as complete sentences. Thus, unlike most [hatnotes](#hatnotes), must use a full stop (`.`) or an exclamation mark (`!`) if appropriate. Anything within the same paragraph of a notice must also be italicised. These must be formatted as follows:\n\n```markdown\n*Note: {note}.*\n\n*Notice: {notice}.*\n\n*Caution: {caution}.*\n\n*Warning: {warning}.*\n```\n\n- `Note` should be used for factual or trivial details.\n- `Notice` should be used for reminders or to draw attention to something that the reader should be made aware of.\n- `Caution` should be used to warn the reader to avoid unintended consequences.\n- `Warning` should be used to warn the reader that action may be taken against them.\n\n## Emphasising\n\n### Bold\n\nBold must use double asterisks (`**`).\n\nLead paragraphs may bold the first occurrence of the article's title.\n\n### Italics\n\nItalics must use single asterisks (`*`).\n\nNames of work or video games should be italicised. osu!—the game—is exempt from this.\n\nThe first occurrence of an abbreviation, acronym, or initialism may be italicised.\n\nItalics may also be used to provide emphasis or help with readability.\n\n## Headings\n\nAll headings must use sentence case.\n\nHeadings must use the [ATX (hash) style](https://github.github.com/gfm/#atx-headings \"GitHub\") and must have an empty line before and after the heading. The title heading is an exception when it is on the first line. If this is the case, there only needs to be an empty line after the title heading.\n\nHeadings must not exceed a heading level of 5 and must not be used to style or format text.\n\n### Titles\n\n*See also: [Article naming](#article-naming)*\n\n*Caution: Titles are parsed as plain text; they must not be escaped.*\n\nThe first heading in all articles must be a level 1 heading, being the article's title. All headings afterwards must be [section headings](#sections). Titles must not contain formatting, links, or images.\n\nThe title heading must be on the first line, unless [front matter](#front-matter) is being used. If that is the case, the title heading must go after it and have an empty line before the title heading.\n\n### Sections\n\nSection headings must use levels 2 to 5. The section heading proceeding the [title heading](#titles) must be a level 2 heading. Unlike titles, section headings may have small image icons.\n\nSection headings must not skip a heading level (i.e. do not go from a level 2 heading to a level 4 heading) and must not contain formatting or links.\n\n*Notice: On the website, heading levels 4 and 5 will not appear in the table of contents. They cannot be linked to directly either.*\n\n## Lists\n\nLists should not go over 4 levels of indentation and should not have an empty line in between each item.\n\nFor nested lists, bullets or numbers must align with the item content of their parent lists.\n\nThe following example was done incorrectly (take note of the spacing before the bullet):\n\n```markdown\n1. Fly a kite\n - Don't fly a kite if it's raining\n```\n\nThe following example was done correctly:\n\n```markdown\n1. Fly a kite\n - Don't fly a kite if it's raining\n```\n\n### Bulleted\n\nBulleted lists must use a hyphen (`-`). These must then be followed by one space. (Example shown below.)\n\n```markdown\n- osu!\n - Hit circle\n - Combo number\n - Approach circle\n - Slider\n - Hit circles\n - Slider body\n - Slider ticks\n - Spinner\n- osu!taiko\n```\n\n### Numbered\n\nThe numbers in a numbered list must be incremented to represent their step.\n\n```markdown\n1. Download the osu! installer.\n2. Run the installer.\n 1. To change the installation location, click the text underneath the progression bar.\n 2. The installer will prompt for a new location, choose the installation folder.\n3. osu! will start up once installation is complete.\n4. Sign in.\n```\n\n### Mixed\n\nCombining both bulleted and numbered lists should be done sparingly.\n\n```markdown\n1. Download a skin from the forums.\n2. Load the skin file into osu!.\n - If the file is a `.zip`, unzip it and move the contents into the `Skins/` folder (found in your osu! installation folder).\n - If the file is a `.osk`, open it on your desktop or drag-and-drop it into the game client.\n3. Open osu!, if it is not opened, and select the skin in the options.\n - This may have been completed if you opened the `.osk` file or drag-and-dropped it into the game client.\n```\n\n## Code\n\nThe markup for code is a grave mark (`` ` ``). To put grave marks in code, use double grave marks instead. If the grave mark is at the start or end, pad it with one space. (Example shown below.)\n\n```markdown\n`` ` ``\n`` `Space` ``\n```\n\n### Keyboard keys\n\n*Notice: When denoting the letter itself, and not the keyboard key, use quotation marks instead.*\n\nWhen representing keyboard keys, use capital letters for single characters and title case for modifiers. Use the plus symbol (`+`) (without code) to represent key combinations. (Example shown below.)\n\n```markdown\npippi is spelt with a lowercase \"p\" like peppy.\n\nPress `Ctrl` + `O` to open the open dialog.\n```\n\nWhen representing a space or the spacebar, use `` `Space` ``.\n\n### Button and menu text\n\nWhen copying the text from a menu or button, the letter casing should be copied as it appears. (Example shown below.)\n\n```markdown\nThe `osu!direct` button is visible in the main menu on the right side, if you have an active osu!supporter tag.\n```\n\n### Folder and directory names\n\nWhen copying the name of a folder or directory, the letter casing should be copied as it appears, but prefer lowercased paths when possible. Directory paths must not be absolute (i.e. do not start the directory name from the drive letter or from the root folder). (Example shown below.)\n\n```markdown\nosu! is installed in the `AppData/Local` folder by default, unless specified otherwise during installation.\n```\n\n### Keywords and commands\n\nWhen copying a keyword or command, the letter casing should be copied as it appears or how someone normally would type it. If applicable, prefer lowercase letters. (Example shown below.)\n\n```markdown\nAs of now, the `Name` and `Author` commands in the skin configuration file (`skin.ini`) do nothing.\n```\n\n### File names\n\nWhen copying the name of a file, the letter casing should be copied as it appears. If applicable, prefer lowercase letters. (Example shown below.)\n\n```markdown\nTo play osu!, double click the `osu!.exe` icon.\n```\n\n### File extensions\n\n*Notice: File formats (not to be confused with file extensions) must be written in capital letters without the prefixed fullstop (`.`).*\n\nFile extensions must be prefixed with a fullstop (`.`) and be followed by the file extension in lowercase letters. (Example shown below.)\n\n```markdown\nThe JPG (or JPEG) file format has the `.jpg` (or `.jpeg`) extension.\n```\n\n### Chat channels\n\nWhen copying the name of a chat channel, start it with a hash (`#`), followed by the channel name in lowercase letters. (Example shown below.)\n\n```markdown\n`#lobby` is where you can advertise your multi room.\n```\n\n## Preformatted text (code blocks)\n\n*Notice: Syntax highlighting for preformatted text is not implemented on the website yet.*\n\nPreformatted text (also known as code blocks) must be fenced using three grave marks. They should set the language identifier for syntax highlighting.\n\n## Links\n\nThere are two types of links: inline and reference. Inline has two styles.\n\nThe following is an example of both inline styles:\n\n```markdown\n[Game Modifiers](/wiki/Game_Modifiers)\n\n\n```\n\nThe following is an example of the reference style:\n\n```markdown\n[Game Modifiers][game mods link]\n\n[game mods link]: /wiki/Game_Modifiers\n```\n\n---\n\nLinks must use the inline style if they are only referenced once. The inline angle brackets style should be avoided. References to reference links must be placed at the bottom of the article.\n\n### Internal links\n\n*Note: Internal links refer to links that stay inside the `https://osu.ppy.sh/` domain.*\n\n#### Wiki links\n\nAll links that point to an wiki article should start with `/wiki/` followed by the path to get to the article you are targeting. Relative links may also be used. Some examples include the following:\n\n```markdown\n[FAQ](/wiki/FAQ)\n[pippi](/wiki/Mascots#-pippi)\n[Beatmaps](../)\n[Pattern](./Pattern)\n```\n\nWiki links must not use redirects and must not have a trailing forward slash (`/`).\n\nBad examples include the following:\n\n```markdown\n[Article styling criteria](/wiki/ASC)\n[Developers](/wiki/Developers/)\n[Developers](/wiki/Developers/#game-client-developers)\n```\n\nGood examples include the following:\n\n```markdown\n[Article styling criteria](/wiki/Article_styling_criteria)\n[Developers](/wiki/Developers)\n[Developers](/wiki/Developers#game-client-developers)\n```\n\n##### Sub-article links\n\nWiki links that point to a sub-article should include the parent article's folder name in its link text. See the following example:\n\n```markdown\n*See also: [Beatmap Editor/Design](/wiki/Beatmap_Editor/Design)*\n```\n\n##### Section links\n\n*Notice: On the website, heading levels 4 and 5 are not given the id attribute. This means that they can not be linked to directly.*\n\nWiki links that point to a section of an article may use the section sign symbol (`§`). See the following example:\n\n```markdown\n*For timing rules, see: [Ranking Criteria § Timing](/wiki/Ranking_Criteria#timing)*\n```\n\n#### Other osu! links\n\nThe URL from the address bar of your web browser should be copied as it is when linking to other osu! web pages. The `https://osu.ppy.sh` part of the URL must be kept.\n\n##### User profiles\n\nAll usernames must be linked on first occurrence. Other occurrences are optional, but must be consistent throughout the entire article for all usernames. If it is difficult to determine the user's id, it may be skipped over.\n\nWhen linking to a user profile, the user's id number must be used. Use the new website (`https://osu.ppy.sh/users/{username})`) to get the user's id.\n\nThe link text of the user link should be the user's current name.\n\n##### Difficulties\n\nWhenever linking to a single difficulty, use this format as the link text:\n\n```\n{artist} - {title} ({creator}) [{difficuty_name}]\n```\n\nThe link must actually link to that difficulty. Beatmap difficulty URLs must be formatted as follows:\n\n```\nhttps://osu.ppy.sh/beatmapsets/{BeatmapSetID}#{mode}/{BeatmapID}\n```\n\nThe difficulty name may be left outside of the link text, but doing so must be consistent throughout the entire article.\n\n##### Beatmaps\n\nWhenever linking to a beatmap, use this format as the link text:\n\n```\n{artist} - {title} ({creator})\n```\n\nAll beatmap URLs must be formatted as follows:\n\n```\nhttps://osu.ppy.sh/beatmapsets/{BeatmapSetID}\n```\n\n### External links\n\n*Notice: External links refers to links that go outside the `https://osu.ppy.sh/` domain.*\n\nThe `https` protocol must be used, unless the site does not support it. External links must be a clean and direct link to a reputable source. The link text should be the title of the page it is linking to. The URL from the address bar of your web browser should be copied as it is when linking to other external pages.\n\nThere are no visual differences between external and osu! web links. Due to this, the website name should be included in the title text. See the following example:\n\n```markdown\n*For more information about music theory, see: [Music theory](https://en.wikipedia.org/wiki/Music_theory \"Wikipedia\")*\n```\n\n## Images\n\nThere are two types of image links: inline and reference. Examples:\n\n**Inline style:**\n\n```markdown\n![](/wiki/shared/flag/AU.gif)\n```\n\n**Reference style:**\n\n```markdown\n![][flag_AU]\n\n[flag_AU]: /wiki/shared/flag/AU.gif\n```\n\nImages should use the inline linking style. References to reference links must be placed at the bottom of the article.\n\nImages must be placed in a folder named `img`, located in the article's folder. Images that are used in multiple articles should be stored in the `/wiki/shared/` folder.\n\n### Image caching\n\nImages on the website are cached for up to 60 days. The cached image is matched with the image link's URL.\n\nWhen updating an image, either change the image's name or append a query string to the URL. In both cases, all translations linking to the updated image should also be updated.\n\n### Formats and quality\n\nImages should use the JPG format at quality 8 (80 or 80%, depending on the program). If the image contains transparency or has text that must be readable, use the PNG format instead. If the image contains an animation, the GIF format can be used; however, this should be used sparingly as these may take longer to load or can be bigger then the [max file size](#file-size).\n\n### File size\n\nImages must be under 1 megabyte, otherwise they will fail to load. Downscaling and using JPG at 80% is almost always under the size limit.\n\nAll images should be optimised as much as possible. Use [jpeg-archive](https://github.com/danielgtaylor/jpeg-archive \"GitHub\") to compress JPEG images. For consistency, use the following command for jpeg-archive:\n\n```sh\njpeg-recompress -am smallfry \n```\n\nWhere `` is the file name to be compressed and `` is the compressed file name.\n\n### File names\n\n*Notice: File extensions must use lowercase letters, otherwise they will fail to load!*\n\nUse hyphens (`-`) when spacing words. When naming an image, the file name should be meaningful or descriptive but short.\n\n### Formatting and positioning\n\n*Note: It is currently not possible to float an image or have text wrap around it.*\n\nImages on the website will be centred when it is on a single line, by themself. Otherwise, they will be positioned inline with the paragraph. The following example will place the image in the center:\n\n```markdown\nInstalling osu! is easy. First, download the installer from the download page.\n\n![](img/download-page.jpg)\n\nThen locate the installer and run it.\n```\n\n### Alt text\n\nImages should have alt text unless it is for decorative purposes.\n\n### Captions\n\nImages are given captions on the website if they fulfill these conditions:\n\n1. The image is by itself.\n2. The image is not inside a heading.\n3. The image has title text.\n\nCaptions are assumed via the title text, which must be in plain text. Images with captions are also centred with the image on the website.\n\n### Max image width\n\nThe website's max image width is the width of the article body. Images should be no wider than 800 pixels.\n\n### Annotating images\n\nWhen annotating images, use *Torus Regular*. For Chinese, Korean, Japanese characters, use *Microsoft YaHei*.\n\nAnnotating images should be avoided, as it is difficult for translators (and other editors) to edit them.\n\n#### Translating annotated images\n\nWhen translating annotated images, the localised image version must be placed in the same directory as the original version (i.e. the English version). The filename of a localised image version must start with the original version's name, followed by a hyphen, followed by the locale name (in capital letters). See the following examples:\n\n- `hardrock-mod-vs-easy-mod.jpg` for English\n- `hardrock-mod-vs-easy-mod-DE.jpg` for German\n- `hardrock-mod-vs-easy-mod-ZH-TW.jpg` for Traditional Chinese\n\n### Screenshots of gameplay\n\nAll screenshots of gameplay must be done in the stable build, unless it is for a specific feature that is unavailable in the stable build. You should use the in-game screenshot feature (`F12`).\n\n#### Game client settings\n\n*Note: If you do not want to change your current settings for the wiki, you can move your `osu!..cfg` out of the osu! folder and move it back later.*\n\nYou must set these settings before taking a screenshot of the game client (settings not stated below are assumed to be at their defaults):\n\n- Select language: `English`\n- Prefer metadata in original language: `Enabled`\n- Resolution: `1280x720`\n- Fullscreen mode: `Disabled`\n- Parallax: `Disabled`\n- Menu tips: `Disabled`\n- Seasonal backgrounds: `Never`\n- Always show key overlay: `Enabled`\n- Current skin: `Default` (first option)\n\n*Notice to translators: If you are translating an article containing screenshots of the game, you may set the game client's language to the language you are translating in.*\n\n### Image links\n\nImages must not be part of a link text.\n\nFlag icons next to user links must be separate from the link text. See the following example:\n\n```markdown\n![][flag_AU] [peppy](https://osu.ppy.sh/users/2)\n```\n\n### Flag icons\n\n*For a list of flag icons, see: [issue \\#328](https://github.com/ppy/osu-wiki/issues/328 \"GitHub\")*\n\nThe flag icons use the two letter code (in all capital letters) and end with `.gif`. When adding a flag inline, use this format:\n\n```markdown\n![](/wiki/shared/flag/xx.gif)\n```\n\nWhere `xx` is the [ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 \"Wikipedia\") two-lettered country code for the flag.\n\nThe full country name should be added in the title text. The country code in the alternate text is optional, but must be applied to all flag icons in the article.\n\n## Tables\n\nTables on the website only support headings along the first row.\n\nTables must not be beautified (do not pad cells with extra spaces to make their widths uniform). They must have a vertical bar (`|`) on the left and right sides and the text of each cell must be padded with one space on both sides. Empty cells must use a vertical bar (`|`) followed by two spaces then another vertical bar (`|`).\n\nThe delimiter row (the next line after the table heading) must use only three characters per column (and be padded with a space on both sides), which must look like one of the following:\n\n- `:--` (for left align)\n- `:-:` (for centre align)\n- `--:` (for right align)\n\n---\n\nThe following is an example of what a table should look like:\n\n```markdown\n| Team \"Picturesque\" Red | Score | Team \"Statuesque\" Blue | Average Beatmap Stars |\n| :-- | :-: | --: | :-- |\n| **peppy** | 5 - 2 | pippi | 9.3 stars |\n| Aiko | 1 - 6 | **Alisa** | 4.2 stars |\n| Ryūta | 3 - 4 | **Yuzu** | 5.1 stars |\n| **Taikonator** | 7 - 0 | Tama | 13.37 stars |\n| Maria | No Contest | Mocha | |\n```\n\n## Blockquotes\n\nThe blockquote is limited to quoting text from someone. It must not be used to format text otherwise.\n\n## Thematic breaks\n\nThe thematic break (also known as the horizontal rule or line) should be used sparingly. A few uses of the thematic break may include (but is not limited to):\n\n- separating images from text\n- separating multiple images that follow one another\n- shifting the topic within a section\n\nThese must have an empty line before and after the markup. Thematic breaks must use only three hyphens, as depicted below:\n\n```markdown\n---\n```\n" + "# Formatting\n\n*For the writing standards, see: [Article style criteria/Writing](../Writing)*\\\n*Notice: This article uses [RFC 2119](https://tools.ietf.org/html/rfc2119) to describe requirement levels.*\n\n## Locales\n\nListed below are the properly-supported locales for the wiki:\n\n| File Name | Locale Name | Native Script |\n| :-- | :-- | :-- |\n| `en.md` | English | English |\n| `ar.md` | Arabic | \u0627\u064e\u0644\u0652\u0639\u064e\u0631\u064e\u0628\u0650\u064a\u064e\u0651\u0629\u064f |\n| `be.md` | Belarusian | \u0411\u0435\u043b\u0430\u0440\u0443\u0441\u043a\u0430\u044f \u043c\u043e\u0432\u0430 |\n| `bg.md` | Bulgarian | \u0411\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438 |\n| `cs.md` | Czech | \u010cesky |\n| `da.md` | Danish | Dansk |\n| `de.md` | German | Deutsch |\n| `el.md` | Greek | \u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac |\n| `es.md` | Spanish | Espa\u00f1ol |\n| `fi.md` | Finnish | Suomi |\n| `fr.md` | French | Fran\u00e7ais |\n| `hu.md` | Hungarian | Magyar |\n| `id.md` | Indonesian | Bahasa Indonesia |\n| `it.md` | Italian | Italiano |\n| `ja.md` | Japanese | \u65e5\u672c\u8a9e |\n| `ko.md` | Korean | \ud55c\uad6d\uc5b4 |\n| `nl.md` | Dutch | Nederlands |\n| `no.md` | Norwegian | Norsk |\n| `pl.md` | Polish | Polski |\n| `pt.md` | Portuguese | Portugu\u00eas |\n| `pt-br.md` | Brazilian Portuguese | Portugu\u00eas (Brasil) |\n| `ro.md` | Romanian | Rom\u00e2n\u0103 |\n| `ru.md` | Russian | \u0420\u0443\u0441\u0441\u043a\u0438\u0439 |\n| `sk.md` | Slovak | Sloven\u010dina |\n| `sv.md` | Swedish | Svenska |\n| `th.md` | Thai | \u0e44\u0e17\u0e22 |\n| `tr.md` | Turkish | T\u00fcrk\u00e7e |\n| `uk.md` | Ukrainian | \u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430 \u043c\u043e\u0432\u0430 |\n| `vi.md` | Vietnamese | Ti\u1ebfng Vi\u1ec7t |\n| `zh.md` | Chinese (Simplified) | \u7b80\u4f53\u4e2d\u6587 |\n| `zh-tw.md` | Traditional Chinese (Taiwan) | \u7e41\u9ad4\u4e2d\u6587\uff08\u53f0\u7063\uff09 |\n\n*Note: The website will give readers their selected language's version of an article. If it is not available, the English version will be given.*\n\n## Front matter\n\nFront matter must be placed at the very top of the file. It is written in [YAML](https://en.wikipedia.org/wiki/YAML#Example) and describes additional information about the article. This must be surrounded by three hyphens (`---`) on the lines above and below it, and an empty line must follow it before the title heading.\n\n### Articles that need help\n\n*Note: Avoid translating English articles with this tag. In addition to this, this tag should be added when the translation needs its own clean up.*\n\nThe `needs_cleanup` tag may be added to articles that need rewriting or formatting help. It is also acceptable to open an issue on GitHub for this purpose. This tag must be written as shown below:\n\n```yaml\nneeds_cleanup: true\n```\n\nWhen adding this tag to an article, [comments](#comments) should also be added to explain what needs to be done to remove the tag.\n\n### Outdated articles\n\n*Note: Avoid translating English articles with this tag. If the English article has this tag, the translation must also have this tag.*\n\nEnglish articles may become outdated when the content they contain is misleading or no longer relevant. These should receive an `outdated` tag, which must be written as shown below:\n\n```yaml\noutdated: true\n```\n\nWhen adding this tag to an article, [comments](#comments) should also be added to explain what needs to be updated to remove the tag.\n\n### Outdated translations\n\nTranslated articles that are outdated must use the `outdated_translation` tag when the English variant is updated, except for minor wording, grammar changes, and the like, that do not affect the meaning of the article.\n\n```yaml\noutdated_translation: true\n```\n\nWhen outdating translations, they must also receive an `outdated_since` tag that points to the first commit where the English version is updated.\n\n```yaml\noutdated_since: 29eac89cd535f8b071ca000af8fe4f0be22bdc9b\n```\n\n### Tagging articles\n\nTags help the website's search engine query articles better. Tags should be written in the same language as the article and include the original list of tags. Tags should use lowercase letters where applicable.\n\nFor example, an article called \"Beatmap discussion\" may include the following tags:\n\n```yaml\ntags:\n - beatmap discussions\n - modding V2\n - MV2\n```\n\n### Translations without reviews\n\n*Note: Wiki maintainers will determine and apply this mark prior to merging.*\n\nSometimes, translations are added to the wiki without review from other native speakers of the language. In this case, the `no_native_review` mark is added to let future translators know that it may need to be checked again. This tag must be written as shown below:\n\n```yaml\nno_native_review: true\n```\n\n## Article naming\n\n*See also: [Folder names](#folder-names) and [Titles](#titles)*\n\nArticle titles should be singular and use sentence case. See [Wikipedia's naming conventions article](https://en.wikipedia.org/wiki/Wikipedia:Naming_conventions_(plurals)) for more details.\n\nArticle titles should match the folder name it is in (spaces may replace underscores (`_`) where appropriate). If the folder name changes, the article title should be changed to match it and vice versa.\n\n---\n\nContest and tournament articles are an exception. The folder name must use abbreviations, acronyms, or initialisms. The article's title must be the full name of the contest or tournament.\n\n## Folder and file structure\n\n### Folder names\n\n*See also: [Article naming](#article-naming)*\n\nFolder names must be in English and use sentence case.\n\nFolder names must only use these characters:\n\n- uppercase and lowercase letters\n- numbers\n- underscores (`_`)\n- hyphens (`-`)\n- exclamation marks (`!`)\n\n### Article file names\n\nThe file name of an article can be found in the `File Name` column of the [locales section](#locales). The location of a translated article must be placed in the same folder as the English article.\n\n### Index articles\n\nAn index article must be created if the folder is intended to only hold other articles. Index articles must contain a list of articles that are inside its own folder. They may also contain other information, such as a lead paragraph or descriptions of the linked articles.\n\n### Disambiguation articles\n\n[Disambiguation](/wiki/Disambiguation) articles must be placed in the `/wiki/Disambiguation` folder. The main page must be updated to include the disambiguation article. Refer to [Disambiguation/Mod](/wiki/Disambiguation/Mod) as an example.\n\nRedirects must be updated to have the ambiguous keyword(s) redirect to the disambiguation article.\n\nArticles linked from a disambiguation article must have a [For other uses](#for-other-uses) hatnote.\n\n## HTML\n\nHTML must not be used, with exception for [comments](#comments). The structure of the article must be redone if HTML is used.\n\n### Comments\n\nHTML comments should be used for marking to-dos, but may also be used to annotate text. They should be on their own line, but can be placed inline in a paragraph. If placed inline, the start of the comment must not have a space.\n\nBad example:\n\n```markdown\nHTML comments should be used for marking to-dos or annotate text.\n```\n\nGood example:\n\n```markdown\nHTML comments should be used for marking to-dos or annotate text.\n```\n\n## Editing\n\n### End of line sequence\n\n*Caution: Uploading Markdown files using `CRLF` (carriage return and line feed) via GitHub will result in those files using `CRLF`. To prevent this, set the line ending to `LF` (line feed) before uploading.*\n\nMarkdown files must be checked in using the `LF` end of line sequence.\n\n### Escaping\n\nMarkdown syntax should be escaped as needed. However, article titles are parsed as plain text and so must not be escaped.\n\n### Paragraphs\n\nEach paragraph must be followed by one empty line.\n\n### Line breaks\n\nLine breaks must use a backslash (`\\`).\n\nLine breaks must be used sparingly.\n\n## Hatnote\n\n*Not to be confused with [Notice](#notice).*\n\nHatnotes are short notes placed at the top of an article or section to help readers navigate to related articles or inform them about related topics.\n\nHatnotes must be italicised and be placed immediately after the heading. If multiple hatnotes are used, they must be on the same paragraph separated with a line break.\n\n### Main page\n\n*Main page* hatnotes direct the reader to the main article of a topic. When this hatnote is used, it implies that the section it is on is a summary of what the linked page is about. This hatnote should have only one link. These must be formatted as follows:\n\n```markdown\n*Main page: {article}*\n\n*Main pages: {article} and {article}*\n```\n\n### See also\n\n*See also* hatnotes suggest to readers other points of interest from a given article or section. These must be formatted as follows:\n\n```markdown\n*See also: {article}*\n\n*See also: {article} and {article}*\n```\n\n### For see\n\n*For see* hatnotes are similar to *see also* hatnotes, but are generally more descriptive and direct. This hatnote may use more than one link if necessary. These must be formatted as follows:\n\n```markdown\n*For {description}, see: {article}*\n\n*For {description}, see: {article} and {article}*\n```\n\n### Not to be confused with\n\n*Not to be confused with* hatnotes help distinguish ambiguous or misunderstood article titles or sections. This hatnote may use more than one link if necessary. These must be formatted as follows:\n\n```markdown\n*Not to be confused with {article}.*\n\n*Not to be confused with {article} or {article}.*\n```\n\n### For other uses\n\n*For other uses* hatnotes are similar to *not to be confused with* hatnotes, but links directly to the [disambiguation article](#disambiguation-articles). This hatnote must only link to the disambiguation article. These must be formatted as follows:\n\n```markdown\n*For other uses, see {disambiguation article}.*\n```\n\n## Notice\n\n*Not to be confused with [Hatnote](#hatnote).*\n\nA notice should be placed where appropriate in a section, but must start off the paragraph and use italics. Notices may contain bolding where appropriate, but should be kept to a minimum. Notices must be written as complete sentences. Thus, unlike most [hatnotes](#hatnote), notices must use a full stop (`.`) or an exclamation mark (`!`) if appropriate. Anything within the same paragraph of a notice must also be italicised. These must be formatted as follows:\n\n```markdown\n*Note: {note}.*\n\n*Notice: {notice}.*\n\n*Caution: {caution}.*\n\n*Warning: {warning}.*\n```\n\n- `Note` should be used for factual or trivial details.\n- `Notice` should be used for reminders or to draw attention to something that the reader should be made aware of.\n- `Caution` should be used to warn the reader to avoid unintended consequences.\n- `Warning` should be used to warn the reader that action may be taken against them.\n\n## Stacked hatnotes and notices\n\nMultiple hatnotes and notices may be stacked when necessary. When doing this, they must be stacked without blank lines and use trailing backslashes:\n\n```markdown\n*Warning: {warning}.*\\\n*See also: {article}*\n```\n\nIn many cases, it may be more fitting to embed extraneous hatnotes or notices into paragraph text instead of stacking many of them.\n\n## Emphasising\n\n### Bolding\n\nBold text must use double asterisks (`**`).\n\nLead paragraphs may bold the first occurrence of the article's title.\n\n### Italics\n\nItalics must use single asterisks (`*`).\n\nThe first occurrence of an abbreviation, acronym, or initialism may be italicised.\n\nItalics may also be used to provide emphasis or help with readability.\n\nNames of work or video games should be italicised. osu! \u2014 the game \u2014 is exempt from this.\n\nAs an example, when referring to songs in the format of `{artist} - {title}`, the whole part is a reference to the work and should therefore be italicised:\n\n```markdown\n*cYsmix - triangles* is a one of the three intro songs that can be heard when starting the game client.\n```\n\nArtist names are otherwise generally not italicised. This means that in free-form references, only the title should be italicised, because the artist name is then not part of the name of the work:\n\n```markdown\n*Blue Zenith* by xi is an infamous song in the osu! community due to a famous score set by a top player on a certain beatmap.\n```\n\n### Emphasis and links\n\nLinked text appears in a different colour which already provides emphasis, and therefore does not need further emphasis:\n\n```markdown\n[Camellia - OOPARTS](https://cametek.bandcamp.com/track/parts) is an example of a song officially created specifically for osu!, otherwise known as an *osu! original*, since it was specifically commissioned for the osu! World Cup 2020 tiebreaker.\n```\n\nThis however does not apply if the referenced work is not the only part of the link:\n\n```markdown\n[Voltaeyx's beatmap of *TheFatRat - Mayday (feat. Laura Brehm)*](https://osu.ppy.sh/beatmapsets/756794) amassed considerable popularity in 2018 due to its unique overlapping slider patterns.\n```\n\nThe above type of construction should be used sparingly, and must not be used in places with many links, such as tables or lists.\n\n## Headings\n\nAll headings must use sentence case.\n\nHeadings must use the [ATX (hash) style](https://github.github.com/gfm/#atx-headings) and must have an empty line before and after the heading. The title heading is an exception when it is on the first line. If this is the case, there only needs to be an empty line after the title heading.\n\nHeadings must not exceed a heading level of 5 and must not be used to style or format text.\n\n### Titles\n\n*See also: [Article naming](#article-naming)*\\\n*Caution: Titles are parsed as plain text; they must not be escaped.*\n\nThe first heading in all articles must be a level 1 heading, being the article's title. All headings afterwards must be [section headings](#sections). Titles must not contain formatting, links, or images.\n\nThe title heading must be on the first line, unless [front matter](#front-matter) is being used. If that is the case, the title heading must go after it and have an empty line before the title heading.\n\n### Sections\n\nSection headings must use levels 2 to 5. The section heading proceeding the [title heading](#titles) must be a level 2 heading. Unlike titles, section headings may have small image icons.\n\nSection headings must not skip a heading level (i.e. do not go from a level 2 heading to a level 4 heading) and must not contain formatting or links.\n\n*Notice: On the website, heading levels 4 and 5 will not appear in the table of contents.*\n\n### Custom identifiers\n\nIt is possible to redefine a section's identifier, which is used for linking to it directly. Custom identifiers should be used in case the automatically generated ones are too long or contain tricky punctuation marks or images:\n\n\n\n```markdown\n## My cooldown has passed. How do I appeal? {#appeal}\n\n## Common restriction reasons and cooldowns {#common-reasons}\n\n## Ideas for a multiplayer match {id=\u0438\u0434\u0435\u0438-\u0434\u043b\u044f-\u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440\u0430} \n```\n\nThis feature can also be used for tagging a specific part of the article which doesn't have a heading. Use it sparingly:\n\n```markdown\n> That's it! You're well on your way to becoming an osu! rhythm champion!\n{#tutorial-quote}\n```\n\n## Lists\n\nLists should not go over 4 levels of indentation and should not have an empty line in between each item.\n\nFor nested lists, bullets or numbers must align with the item content of their parent lists.\n\nThe following example was done incorrectly (take note of the spacing before the bullet):\n\n```markdown\n1. Fly a kite\n - Don't fly a kite if it's raining\n```\n\nThe following example was done correctly:\n\n```markdown\n1. Fly a kite\n - Don't fly a kite if it's raining\n```\n\n### Bulleted\n\nBulleted lists must use a hyphen (`-`). These must then be followed by one space. (Example shown below.)\n\n```markdown\n- osu!\n - Hit circle\n - Combo number\n - Approach circle\n - Slider\n - Hit circles\n - Slider body\n - Slider ticks\n - Spinner\n- osu!taiko\n```\n\n### Numbered\n\nThe numbers in a numbered list must be incremented to represent their step.\n\n```markdown\n1. Download the osu! installer.\n2. Run the installer.\n 1. To change the installation location, click the text underneath the progression bar.\n 2. The installer will prompt for a new location, choose the installation folder.\n3. osu! will start up once installation is complete.\n4. Sign in.\n```\n\n### Mixed\n\nCombining both bulleted and numbered lists should be done sparingly.\n\n```markdown\n1. Download a skin from the forums.\n2. Load the skin file into osu!.\n - If the file is a `.zip`, unzip it and move the contents into the `Skins/` folder (found in your osu! installation folder).\n - If the file is a `.osk`, open it on your desktop or drag-and-drop it into the game client.\n3. Open osu!, if it is not opened, and select the skin in the options.\n - This may have been completed if you opened the `.osk` file or drag-and-dropped it into the game client.\n```\n\n## Code\n\nThe markup for code is a grave mark (`` ` ``). To put grave marks in code, use double grave marks instead. If the grave mark is at the start or end, pad it with one space. (Example shown below.)\n\n```markdown\n`` ` ``\n`` `Space` ``\n```\n\n### Keyboard keys\n\n*Notice: When denoting the letter itself, and not the keyboard key, use quotation marks instead.*\n\nWhen representing keyboard keys, use capital letters for single characters and title case for modifiers. Use the plus symbol (`+`) (without code) to represent key combinations. (Example shown below.)\n\n```markdown\npippi is spelt with a lowercase \"p\" like peppy.\n\nPress `Ctrl` + `O` to open the open dialog.\n```\n\nWhen representing a space or the spacebar, use `` `Space` ``.\n\n### Button and menu text\n\nWhen copying the text from a menu or button, the letter casing should be copied as it appears. (Example shown below.)\n\n```markdown\nThe `osu!direct` button is visible in the main menu on the right side, if you have an active osu!supporter tag.\n```\n\n### Folder and directory names\n\nWhen copying the name of a folder or directory, the letter casing should be copied as it appears, but prefer lowercased paths when possible. Directory paths must not be absolute (i.e. do not start the directory name from the drive letter or from the root folder). (Example shown below.)\n\n```markdown\nosu! is installed in the `AppData/Local` folder by default, unless specified otherwise during installation.\n```\n\n### Keywords and commands\n\nWhen copying a keyword or command, the letter casing should be copied as it appears or how someone normally would type it. If applicable, prefer lowercase letters. (Example shown below.)\n\n```markdown\nAs of now, the `Name` and `Author` commands in the skin configuration file (`skin.ini`) do nothing.\n```\n\n### File names\n\nWhen copying the name of a file, the letter casing should be copied as it appears. If applicable, prefer lowercase letters. (Example shown below.)\n\n```markdown\nTo play osu!, double click the `osu!.exe` icon.\n```\n\n### File extensions\n\n*Notice: File formats (not to be confused with file extensions) must be written in capital letters without the prefixed fullstop (`.`).*\n\nFile extensions must be prefixed with a fullstop (`.`) and be followed by the file extension in lowercase letters. (Example shown below.)\n\n```markdown\nThe JPG (or JPEG) file format has the `.jpg` (or `.jpeg`) extension.\n```\n\n### Chat channels\n\nWhen copying the name of a chat channel, start it with a hash (`#`), followed by the channel name in lowercase letters. (Example shown below.)\n\n```markdown\n`#lobby` is where you can advertise your multi room.\n```\n\n## Preformatted text (code blocks)\n\n*Notice: Syntax highlighting for preformatted text is not implemented on the website yet.*\n\nPreformatted text (also known as code blocks) must be fenced using three grave marks. They should set the language identifier for syntax highlighting.\n\n## Links\n\n*See also: [Footnotes](#footnotes)*\n\nThere are two types of links: inline and reference. Inline has two styles.\n\nThe following is an example of both inline styles:\n\n```markdown\n[Game modifier](/wiki/Game_modifier)\n\n\n```\n\nThe following is an example of the reference style:\n\n```markdown\n[Game modifier][game mods link]\n\n[game mods link]: /wiki/Game_modifier\n```\n\n---\n\nLinks must use the inline style if they are only referenced once. The inline angle brackets style should be avoided. References to reference links must be placed at the bottom of the article.\n\n### Internal links\n\n*Note: Internal links refer to links that stay inside the `https://osu.ppy.sh/` domain.*\n\n#### Wiki links\n\nAll links that point to an wiki article should start with `/wiki/` followed by the path to get to the article you are targeting. Relative links may also be used. Some examples include the following:\n\n```markdown\n[FAQ](/wiki/FAQ)\n[pippi](/wiki/Mascots#pippi)\n[Beatmaps](../)\n[Pattern](./Pattern)\n```\n\nWiki links must not use redirects and must not have a trailing forward slash (`/`).\n\nBad examples include the following:\n\n```markdown\n[Article styling criteria](/wiki/ASC)\n[Developers](/wiki/Developers/)\n[Developers](/wiki/Developers/#game-client-developers)\n```\n\nGood examples include the following:\n\n```markdown\n[Article styling criteria](/wiki/Article_styling_criteria)\n[Developers](/wiki/People/The_Team/Developers)\n[Developers](/wiki/People/The_Team/Developers#game-client-developers)\n```\n\n##### Sub-article links\n\nWiki links that point to a sub-article should include the parent article's folder name in its link text. See the following example:\n\n```markdown\n*See also: [Beatmap Editor/Design](/wiki/Client/Beatmap_editor/Design)*\n```\n\n##### Section links\n\n*Notice: On the website, heading levels 4 and 5 are not given the id attribute. This means that they can not be linked to directly.*\n\nWiki links that point to a section of an article may use the section sign symbol (`\u00a7`). See the following example:\n\n```markdown\n*For timing rules, see: [Ranking Criteria \u00a7 Timing](/wiki/Ranking_Criteria#timing)*\n```\n\n#### Other osu! links\n\nThe URL from the address bar of your web browser should be copied as it is when linking to other osu! web pages. The `https://osu.ppy.sh` part of the URL must be kept.\n\n##### User profiles\n\nAll usernames must be linked on first occurrence. Other occurrences are optional, but must be consistent throughout the entire article for all usernames. If it is difficult to determine the user's id, it may be skipped over.\n\nWhen linking to a user profile, the user's id number must be used. Use the new website (`https://osu.ppy.sh/users/{username})`) to get the user's id.\n\nThe link text of the user link should be the user's current name.\n\n##### Difficulties\n\nWhenever linking to a single difficulty, use this format as the link text:\n\n```\n{artist} - {title} ({creator}) [{difficulty_name}]\n```\n\nThe link must actually link to that difficulty. Beatmap difficulty URLs must be formatted as follows:\n\n```\nhttps://osu.ppy.sh/beatmapsets/{BeatmapSetID}#{mode}/{BeatmapID}\n```\n\nThe difficulty name may be left outside of the link text, but doing so must be consistent throughout the entire article.\n\n##### Beatmaps\n\nWhenever linking to a beatmap, use this format as the link text:\n\n```\n{artist} - {title} ({creator})\n```\n\nAll beatmap URLs must be formatted as follows:\n\n```\nhttps://osu.ppy.sh/beatmapsets/{BeatmapSetID}\n```\n\n### External links\n\n*Notice: External links refers to links that go outside the `https://osu.ppy.sh/` domain.*\n\nThe `https` protocol must be used, unless the site does not support it. External links must be a clean and direct link to a reputable source. The URL from the address bar of your web browser should be copied as it is when linking to other external pages.\n\nThere are no visual differences between external and osu! web links. Due to this, the website name should be included in the title text. See the following example:\n\n```markdown\n*For more information about music theory, see: [Music theory](https://en.wikipedia.org/wiki/Music_theory)*\n```\n\n## Images\n\nThere are two types of image links: inline and reference. Examples:\n\n**Inline style:**\n\n```markdown\n![Gold crown](/wiki/shared/crown-gold.png \"1st place\")\n```\n\n**Reference style:**\n\n```markdown\n![Gold crown][GCrown]\n\n[GCrown]: /wiki/shared/crown-gold.png \"1st place\"\n```\n\nImages should use the inline linking style. Reference link definitions must be placed at the bottom of the article.\n\nAll block images on the page (that have nothing else on the same line) are combined into a single gallery, which can be navigated using arrow icons on both sides of the screen, keyboard shortcuts, or screen swipes on mobile devices.\n\n### Alternative and title text\n\nThe text in the first pair of square brackets (*alternative text*) should describe the image literally. It is used by screen readers or when the image fails to load. It can be omitted if it is identical to the title text or if the image is included only for decorative purposes.\n\nThe text in the quotation marks (*title text*) should give additional context to the image or indicate its meaning. It is displayed as a tooltip when hovering over the image and used as a caption if applicable. It does not support any markdown formatting.\n\n### Display\n\nIf an image is the sole content of a paragraph, it displays as a centred block. Otherwise, it flows with the surrounding inline text.\n\nBlock images with title text display the title text as a caption below the image. Avoid adding [HTML comment](#comments) or any other text on the same line as the image, as this will cause the caption not to be rendered.\n\nBlock images are commonly paired with [infobox](#infoboxes) formatting to reduce their initial size and float them to the side of other content:\n\n```markdown\n::: Infobox\n![](img/mod-response.png \"An example of a response to a mod\")\n:::\n```\n\n### Image caching\n\nImages on the website are cached for up to 60 days. The cached image is matched with the image link's URL.\n\nWhen updating an image, either change the image's name or append a query string to the URL. In both cases, all translations linking to the updated image should also be updated.\n\n### Formats and quality\n\nImages should use the JPG format at quality 8 (80 or 80%, depending on the program). If the image contains transparency or has text that must be readable, use the PNG format instead. If the image contains an animation, the GIF format can be used; however, this should be used sparingly as these may take longer to load or can be bigger then the [max file size](#file-size).\n\n### File size\n\nImages must be under 1 megabyte, otherwise they will fail to load. Downscaling and using JPG at 80% is almost always under the size limit.\n\nAll images should be optimised as much as possible. Use [jpeg-archive](https://github.com/danielgtaylor/jpeg-archive) to compress JPEG images. For consistency, use the following command for jpeg-archive:\n\n```sh\njpeg-recompress -am smallfry \n```\n\nWhere `` is the file name to be compressed and `` is the compressed file name.\n\n### File names\n\n*Notice: File extensions must use lowercase letters, otherwise they will fail to load!*\n\nUse hyphens (`-`) when spacing words. When naming an image, the file name should be meaningful or descriptive but short.\n\nImages must be placed in a folder named `img` under the article's folder. Images that are used in multiple articles should be stored in the `/wiki/shared` folder.\n\n### Max image width\n\nThe website's max image width is the width of the article body. Images should be no wider than 800 pixels.\n\n### Annotating images\n\nWhen annotating images, use *Torus Regular*. For Chinese, Korean, Japanese characters, use *Microsoft YaHei*.\n\nAnnotating images should be avoided, as it is difficult for translators (and other editors) to edit them.\n\n#### Translating annotated images\n\nWhen translating annotated images, the localised image version must be placed in the same directory as the original version (i.e. the English version). The filename of a localised image version must start with the original version's name, followed by a hyphen, followed by the locale name (in capital letters). See the following examples:\n\n- `hardrock-mod-vs-easy-mod.jpg` for English\n- `hardrock-mod-vs-easy-mod-DE.jpg` for German\n- `hardrock-mod-vs-easy-mod-ZH-TW.jpg` for Traditional Chinese\n\n### Screenshots of gameplay\n\nAll screenshots of gameplay must be done in the stable build, unless it is for a specific feature that is unavailable in the stable build. You should use the in-game screenshot feature (`F12`).\n\n#### Game client settings\n\n*Note: If you do not want to change your current settings for the wiki, you can move your `osu!..cfg` out of the osu! folder and move it back later.*\n\nYou must set these settings before taking a screenshot of the game client (settings not stated below are assumed to be at their defaults):\n\n- Select language: `English`\n- Prefer metadata in original language: `Enabled`\n- Resolution: `1280x720`\n- Fullscreen mode: `Disabled`\n- Parallax: `Disabled`\n- Menu tips: `Disabled`\n- Seasonal backgrounds: `Never`\n- Always show key overlay: `Enabled`\n- Current skin: `Default` (first option)\n\n*Notice to translators: If you are translating an article containing screenshots of the game, you may set the game client's language to the language you are translating in.*\n\n### Image links\n\nImages must not be part of a link text.\n\n## Flag icons\n\nThe flag icons use the two letter code (in all capital letters) to match a certain territory. When adding a flag inline, use this format:\n\n```markdown\n::{ flag=XX }::\n```\n\nWhere `XX` is the [ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) two-lettered country code for the flag.\n\n## Tables\n\nTables on the website only support headings along the first row.\n\nTables must not be beautified (do not pad cells with extra spaces to make their widths uniform). They must have a vertical bar (`|`) on the left and right sides and the text of each cell must be padded with one space on both sides. Empty cells must use a vertical bar (`|`) followed by two spaces then another vertical bar (`|`).\n\nThe delimiter row (the next line after the table heading) must use only three characters per column (and be padded with a space on both sides), which must look like one of the following:\n\n- `:--` (for left align)\n- `:-:` (for centre align)\n- `--:` (for right align)\n\n---\n\nThe following is an example of what a table should look like:\n\n```markdown\n| Team \"Picturesque\" Red | Score | Team \"Statuesque\" Blue | Average Beatmap Stars |\n| :-- | :-: | --: | :-- |\n| **peppy** | 5 - 2 | pippi | 9.3 stars |\n| Aiko | 1 - 6 | **Alisa** | 4.2 stars |\n| Ry\u016bta | 3 - 4 | **Yuzu** | 5.1 stars |\n| **Taikonator** | 7 - 0 | Tama | 13.37 stars |\n| Maria | No Contest | Mocha | |\n```\n\n## Infoboxes\n\nAn infobox is a fixed-width block which is aligned to the right side of the article. It may contain a relevant image, which explains the surrounding text, or a block of navigation that links to other articles from the same category.\n\nExample use, rendered on the right:\n\n\n\n::: Infobox\n![](/wiki/shared/mods/SD.png \"Sudden Death mod icon\")\n:::\n\n```markdown\n::: Infobox\n![](/wiki/shared/mods/SD.png \"Sudden Death mod icon\")\n:::\n```\n\nInfoboxes should be used with caution in the following cases:\n\n- Short sections: the next section's heading appears below any infoboxes, leaving a large gap after the text.\n- Several images at once: instead, use individual infoboxes for better design.\n\n## Footnotes\n\nFootnotes are short notes located at the end of the page. They are used for citing sources, or providing background information that would otherwise disrupt the flow of the article. Footnotes may contain text formatting and links.\n\nIn the osu! wiki, footnotes are implemented using special syntax (`[^identifier]`). Footnotes can use any identifier, but they will automatically be rendered as superscripts with increasing numbers in order of their first appearance. Translations must not modify identifiers of footnotes.\n\nFootnote references are placed directly after the words, phrases, or sentences they explain, with no space in between. These references must be placed after punctuation, except for parentheses, when they pertain to the contents inside, and dashes.\n\nThe footnotes themselves must be placed in a separate second-level heading at the end of the article. Depending on the content, the heading used may be `References`, `Notes`, or `Notes and references`.\n\nCorrect usage examples:\n\n```markdown\nThe osu! wiki is a project that was meant to replace the old FAQ system.[^wiki-faq] It was named after the rhythm game osu![^osu] and the largest open online encyclopedia, Wikipedia. From the very start, it had attracted skillful translators[^wiki-tl] and editors.\n\n## References\n\n[^wiki-faq]: https://osu.ppy.sh/community/forums/topics/68525\n[^wiki-tl]: https://osu.ppy.sh/community/forums/posts/1177500\n[^osu]: https://osu.ppy.sh/community/forums/posts/1178153\n```\n\n### Citations\n\nCitations, or references, are used to identify a source of information. Citations via footnotes should be preferred over inline links.\n\nReferences should whenever applicable specify author, date, service/platform, and title. The exact format may vary depending on the referenced material with a preference for brevity.\n\nExamples:\n\n```markdown\nThe first version of the osu!api was made available on July 2, 2013.[^api-first-usage] It had received critical acclaim from users.[^api-praise] A new version of API, released several years later, contains many more capabilities.[^api-v2-2020] Endpoint versioning is common among web APIs.[^web-api]\n\n## References\n\n[^api-first-usage]: [Forum thread by peppy (2013-07-02) \"osu!api open beta\"](https://osu.ppy.sh/community/forums/posts/2403913)\n[^api-praise]: [Forum post by Menchi (2013-11-02) in \"osu!api open beta\"](https://osu.ppy.sh/community/forums/posts/2662247)\n[^api-v2-2020]: [Tweet by @ppy (2020-03-20)](https://twitter.com/ppy/status/1263083636363948032)\n[^web-api]: [\"Web API\" on Wikipedia](https://en.wikipedia.org/wiki/Web_API)\n```\n\n### Notes\n\nFootnotes may be used for storing explanations or tangential remarks which cannot be inlined without worsening the article's readability, or are less significant than the article itself. Such footnotes may use free-form text.\n\nExample:\n\n```markdown\nA tournament must not be organised and run by an inexperienced team of unaccomplished and irreputable staff.[^staff]\n\n## Notes\n\n[^staff]: An *inexperienced* staff member is loosely defined as someone who has been playing osu! for less than an hour in total.\n```\n\n## Blockquotes\n\nThe blockquote is limited to [quoting someone or something](/wiki/Article_styling_criteria/Writing#block-quotation). It must not be used to format text otherwise.\n\n```markdown\n> plz enjoy game\n\n\u2014rrtyui\n```\n\n## Thematic breaks\n\nThe thematic break (also known as the horizontal rule or line) should be used sparingly. A few uses of the thematic break may include (but is not limited to):\n\n- separating images from text\n- separating multiple images that follow one another\n- shifting the topic within a section\n\nThese must have an empty line before and after the markup. Thematic breaks must use only three hyphens, as depicted below:\n\n```markdown\n---\n```\n" }; // From https://osu.ppy.sh/api/v2/wiki/en/Article_styling_criteria From 0309751d551afdec7467b6811fff8f330a5619fe Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 8 Oct 2022 21:50:31 +0300 Subject: [PATCH 1569/2686] Add test coverage --- .../Visual/Online/TestSceneWikiMarkdownContainer.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 39432ee059..31a866b8f5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -189,6 +189,16 @@ Line after image"; }); } + [Test] + public void TestFlag() + { + AddStep("Add flag", () => + { + markdownContainer.CurrentPath = @"https://dev.ppy.sh"; + markdownContainer.Text = "::{flag=\"AU\"}::"; + }); + } + private class TestMarkdownContainer : WikiMarkdownContainer { public LinkInline Link; From b22e201289ec3e82e0742c8837ca9528060ce92f Mon Sep 17 00:00:00 2001 From: OliBomby Date: Sat, 8 Oct 2022 23:43:23 +0200 Subject: [PATCH 1570/2686] Fixed stream convert float precision edge case --- .../Editor/TestSceneSliderStreamConversion.cs | 31 +++++++++++++++++++ .../Sliders/SliderSelectionBlueprint.cs | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs index 51871dd9e5..0601dc6068 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs @@ -148,6 +148,37 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor }); } + [Test] + public void TestFloatEdgeCaseConversion() + { + Slider slider = null; + + AddStep("select first slider", () => + { + slider = (Slider)EditorBeatmap.HitObjects.First(h => h is Slider); + EditorClock.Seek(slider.StartTime); + EditorBeatmap.SelectedHitObjects.Add(slider); + }); + + AddStep("change to these specific circumstances", () => + { + EditorBeatmap.Difficulty.SliderMultiplier = 1; + var timingPoint = EditorBeatmap.ControlPointInfo.TimingPointAt(slider.StartTime); + timingPoint.BeatLength = 352.941176470588; + slider.Path.ControlPoints[^1].Position = new Vector2(-110, 16); + slider.Path.ExpectedDistance.Value = 100; + }); + + convertToStream(); + + AddAssert("stream created", () => streamCreatedFor(slider, + (time: 0, pathPosition: 0), + (time: 0.25, pathPosition: 0.25), + (time: 0.5, pathPosition: 0.5), + (time: 0.75, pathPosition: 0.75), + (time: 1, pathPosition: 1))); + } + private bool streamCreatedFor(Slider slider, params (double time, double pathPosition)[] expectedCircles) { if (EditorBeatmap.HitObjects.Contains(slider)) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 7c289b5b05..265a1d21b1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -342,7 +342,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders double positionWithRepeats = (time - HitObject.StartTime) / HitObject.Duration * HitObject.SpanCount(); double pathPosition = positionWithRepeats - (int)positionWithRepeats; // every second span is in the reverse direction - need to reverse the path position. - if (Precision.AlmostBigger(positionWithRepeats % 2, 1)) + if (positionWithRepeats % 2 >= 1) pathPosition = 1 - pathPosition; Vector2 position = HitObject.Position + HitObject.Path.PositionAt(pathPosition); From 122064d03fcdb4fa65dd7ccbbb20eebd4148a33e Mon Sep 17 00:00:00 2001 From: vun Date: Sun, 9 Oct 2022 07:09:05 +0800 Subject: [PATCH 1571/2686] Minor refactoring to reduce amount of looping --- .../Colour/Data/AlternatingMonoPattern.cs | 6 ------ .../Colour/Data/RepeatingHitPatterns.cs | 6 ------ .../Colour/TaikoColourDifficultyPreprocessor.cs | 12 ++---------- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs index bc6e02319d..7910a8262b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/AlternatingMonoPattern.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Linq; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data { @@ -32,11 +31,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data ///
public TaikoDifficultyHitObject FirstHitObject => MonoStreaks[0].FirstHitObject; - /// - /// All s in this . - /// - public IEnumerable AllHitObjects => MonoStreaks.SelectMany(streak => streak.HitObjects); - /// /// Determine if this is a repetition of another . This /// is a strict comparison and is true if and only if the colour sequence is exactly the same. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs index 9e3d9a21b2..468a9ab876 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/Data/RepeatingHitPatterns.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; using System.Collections.Generic; namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data @@ -28,11 +27,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour.Data /// public TaikoDifficultyHitObject FirstHitObject => AlternatingMonoPatterns[0].FirstHitObject; - /// - /// All s in this . - /// - public IEnumerable AllHitObjects => AlternatingMonoPatterns.SelectMany(pattern => pattern.AllHitObjects); - /// /// The previous . This is used to determine the repetition interval. /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs index 500078a879..18a299ae92 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Colour/TaikoColourDifficultyPreprocessor.cs @@ -24,11 +24,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour // Assign indexing and encoding data to all relevant objects. foreach (var repeatingHitPattern in hitPatterns) { - foreach (var hitObject in repeatingHitPattern.AllHitObjects) - { - hitObject.Colour.RepeatingHitPattern = repeatingHitPattern; - } - // The outermost loop is kept a ForEach loop since it doesn't need index information, and we want to // keep i and j for AlternatingMonoPattern's and MonoStreak's index respectively, to keep it in line with // documentation. @@ -38,11 +33,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour monoPattern.Parent = repeatingHitPattern; monoPattern.Index = i; - foreach (var hitObject in monoPattern.AllHitObjects) - { - hitObject.Colour.AlternatingMonoPattern = monoPattern; - } - for (int j = 0; j < monoPattern.MonoStreaks.Count; ++j) { MonoStreak monoStreak = monoPattern.MonoStreaks[j]; @@ -51,6 +41,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Colour foreach (var hitObject in monoStreak.HitObjects) { + hitObject.Colour.RepeatingHitPattern = repeatingHitPattern; + hitObject.Colour.AlternatingMonoPattern = monoPattern; hitObject.Colour.MonoStreak = monoStreak; } } From e0904e263f4c976e24277c19f380650fb025499f Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Sun, 9 Oct 2022 11:25:47 +0200 Subject: [PATCH 1572/2686] Fix legacy BpmMultiplier clamp value --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 9c066ada08..360a91a7e5 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -178,7 +178,7 @@ namespace osu.Game.Beatmaps.Formats : this() { // Note: In stable, the division occurs on floats, but with compiler optimisations turned on actually seems to occur on doubles via some .NET black magic (possibly inlining?). - BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 1000) / 100.0 : 1; GenerateTicks = !double.IsNaN(beatLength); } From c89a55043e68e7af3b8a656d803e5e54568d4b60 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 9 Oct 2022 15:28:12 +0300 Subject: [PATCH 1573/2686] Fix smoke being blocked with "Relax" mod enabled --- osu.Game.Rulesets.Osu/OsuInputManager.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index dec965e567..c86609abd7 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -3,8 +3,10 @@ #nullable disable +using System; using System.Collections.Generic; using System.ComponentModel; +using System.Linq; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; @@ -60,17 +62,14 @@ namespace osu.Game.Rulesets.Osu { public bool AllowUserPresses = true; + private static readonly OsuAction[] all_actions = (OsuAction[])Enum.GetValues(typeof(OsuAction)); + + protected override IEnumerable BlockedActions => !AllowUserPresses ? all_actions.Where(a => a != OsuAction.Smoke) : Enumerable.Empty(); + public OsuKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique) { } - - protected override bool Handle(UIEvent e) - { - if (!AllowUserPresses) return false; - - return base.Handle(e); - } } } From 2d4f390372b9624fdd35dc148b599c25cef5f65d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 9 Oct 2022 17:14:16 +0300 Subject: [PATCH 1574/2686] Remove non-smoke key bindings on "Relax" mod instead --- .../ManiaInputTestScene.cs | 4 +++- osu.Game.Rulesets.Osu/OsuInputManager.cs | 24 +++++++++++++++---- .../Bindings/DatabasedKeyBindingContainer.cs | 6 ++--- osu.Game/Rulesets/UI/RulesetInputManager.cs | 4 ++-- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs b/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs index eb380c07a6..e456659ac4 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs @@ -3,9 +3,11 @@ #nullable disable +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; +using osu.Game.Input.Bindings; using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests @@ -37,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.Tests { } - protected override void ReloadMappings() + protected override void ReloadMappings(IQueryable realmKeyBindings) { KeyBindings = DefaultKeyBindings; } diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index c86609abd7..14b1c0f1a5 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -11,6 +10,7 @@ using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Input.StateChanges.Events; +using osu.Game.Input.Bindings; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu @@ -60,16 +60,30 @@ namespace osu.Game.Rulesets.Osu private class OsuKeyBindingContainer : RulesetKeyBindingContainer { - public bool AllowUserPresses = true; + private bool allowUserPresses = true; - private static readonly OsuAction[] all_actions = (OsuAction[])Enum.GetValues(typeof(OsuAction)); - - protected override IEnumerable BlockedActions => !AllowUserPresses ? all_actions.Where(a => a != OsuAction.Smoke) : Enumerable.Empty(); + public bool AllowUserPresses + { + get => allowUserPresses; + set + { + allowUserPresses = value; + ReloadMappings(); + } + } public OsuKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique) { } + + protected override void ReloadMappings(IQueryable realmKeyBindings) + { + base.ReloadMappings(realmKeyBindings); + + if (!AllowUserPresses) + KeyBindings = KeyBindings.Where(b => b.GetAction() == OsuAction.Smoke).ToList(); + } } } diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs index 14a041b459..4f079ab435 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs @@ -55,13 +55,13 @@ namespace osu.Game.Input.Bindings { // The first fire of this is a bit redundant as this is being called in base.LoadComplete, // but this is safest in case the subscription is restored after a context recycle. - reloadMappings(sender.AsQueryable()); + ReloadMappings(sender.AsQueryable()); }); base.LoadComplete(); } - protected override void ReloadMappings() => reloadMappings(queryRealmKeyBindings(realm.Realm)); + protected sealed override void ReloadMappings() => ReloadMappings(queryRealmKeyBindings(realm.Realm)); private IQueryable queryRealmKeyBindings(Realm realm) { @@ -70,7 +70,7 @@ namespace osu.Game.Input.Bindings .Where(b => b.RulesetName == rulesetName && b.Variant == variant); } - private void reloadMappings(IQueryable realmKeyBindings) + protected virtual void ReloadMappings(IQueryable realmKeyBindings) { var defaults = DefaultKeyBindings.ToList(); diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 1a97153f2f..64ac021204 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -230,9 +230,9 @@ namespace osu.Game.Rulesets.UI { } - protected override void ReloadMappings() + protected override void ReloadMappings(IQueryable realmKeyBindings) { - base.ReloadMappings(); + base.ReloadMappings(realmKeyBindings); KeyBindings = KeyBindings.Where(b => RealmKeyBindingStore.CheckValidForGameplay(b.KeyCombination)).ToList(); } From f219c0886d5875ba1e4632704f8f85741222b079 Mon Sep 17 00:00:00 2001 From: pfg Date: Sun, 9 Oct 2022 10:19:21 -0400 Subject: [PATCH 1575/2686] Add a test for realm preservation --- .../Beatmaps/WorkingBeatmapManagerTest.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs index f14288e7ba..8e8d45937a 100644 --- a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs +++ b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs @@ -9,8 +9,10 @@ using osu.Framework.Extensions; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Collections; using osu.Game.Database; using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; using osu.Game.Tests.Resources; using osu.Game.Tests.Visual; @@ -96,5 +98,39 @@ namespace osu.Game.Tests.Beatmaps var second = beatmaps.GetWorkingBeatmap(beatmap, true); Assert.That(first, Is.Not.SameAs(second)); }); + + [Test] + public void TestSavePreservesCollections() => AddStep("run test", () => + { + var beatmap = Realm.Run(r => r.Find(importedSet.Beatmaps.First().ID).Detach()); + + var map = beatmaps.GetWorkingBeatmap(beatmap); + + Assert.That(map.BeatmapInfo.BeatmapSet?.Files, Has.Count.GreaterThan(0)); + + string initialHash = map.BeatmapInfo.MD5Hash; + + var preserveCollection = new BeatmapCollection("test save preserves collection"); + preserveCollection.BeatmapMD5Hashes.Add(initialHash); + var noNewCollection = new BeatmapCollection("test save does not introduce new collection"); + Realm.Write(r => + { + r.Add(preserveCollection); + r.Add(noNewCollection); + }); + + Assert.That(preserveCollection.BeatmapMD5Hashes, Does.Contain(initialHash)); + Assert.That(noNewCollection.BeatmapMD5Hashes, Does.Not.Contain(initialHash)); + + beatmaps.Save(map.BeatmapInfo, map.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); + + string finalHash = map.BeatmapInfo.MD5Hash; + + Assert.That(finalHash, Is.Not.SameAs(initialHash)); + + Assert.That(preserveCollection.BeatmapMD5Hashes, Does.Not.Contain(initialHash)); + Assert.That(preserveCollection.BeatmapMD5Hashes, Does.Contain(finalHash)); + Assert.That(noNewCollection.BeatmapMD5Hashes, Does.Not.Contain(finalHash)); + }); } } From 5d2e3dcf4af4adac45faa2265bce4e25e5701037 Mon Sep 17 00:00:00 2001 From: "D.Headley" Date: Sun, 9 Oct 2022 22:52:54 +0200 Subject: [PATCH 1576/2686] Remove leftover Enum --- osu.Game/Skinning/HUDSkinComponents.cs | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 osu.Game/Skinning/HUDSkinComponents.cs diff --git a/osu.Game/Skinning/HUDSkinComponents.cs b/osu.Game/Skinning/HUDSkinComponents.cs deleted file mode 100644 index 586882d790..0000000000 --- a/osu.Game/Skinning/HUDSkinComponents.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -namespace osu.Game.Skinning -{ - public enum HUDSkinComponents - { - ComboCounter, - ScoreCounter, - AccuracyCounter, - HealthDisplay, - SongProgress, - BarHitErrorMeter, - ColourHitErrorMeter, - } -} From 0b5f8e1c93e47176ad132ea79a62da4db4c419fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Oct 2022 13:12:12 +0900 Subject: [PATCH 1577/2686] Remove duplicated colour in osu!mania argon skin column colouring There will probably be more change to colours, but let's just fix this for now. --- .../Argon/ManiaArgonSkinTransformer.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index 27926c11eb..ae313e0b91 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.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 osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Beatmaps; @@ -89,13 +90,15 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon Color4 colour; + const int total_colours = 7; + if (stage.IsSpecialColumn(column)) colour = new Color4(159, 101, 255, 255); else { - switch (column % 8) + switch (column % total_colours) { - default: + case 0: colour = new Color4(240, 216, 0, 255); break; @@ -112,20 +115,19 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon break; case 4: - colour = new Color4(178, 0, 240, 255); - break; - - case 5: colour = new Color4(0, 96, 240, 255); break; - case 6: + case 5: colour = new Color4(0, 226, 240, 255); break; - case 7: + case 6: colour = new Color4(0, 240, 96, 255); break; + + default: + throw new ArgumentOutOfRangeException(); } } From 26a473e85e7958ba9fd93d85ec5700d000e57e10 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Oct 2022 14:24:32 +0900 Subject: [PATCH 1578/2686] Update resources (fixes osu!mania flashlight crash) --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 2a678f1c61..692e817f8f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index efdb6c6995..35fdb82230 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 47872e4ff7..105a20c9a4 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + From 33620b7bd62a90249dc2c81cbc0763bfdc0015cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Oct 2022 15:24:17 +0900 Subject: [PATCH 1579/2686] Fix slider ball facing incorrect direction during rewinding in editor Closes https://github.com/ppy/osu/issues/20648. --- .../Objects/Drawables/DrawableSliderBall.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs index 6bfb4e8aae..a2fe623897 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs @@ -186,17 +186,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private Vector2? lastPosition; + private bool rewinding; + public void UpdateProgress(double completionProgress) { Position = drawableSlider.HitObject.CurvePositionAt(completionProgress); var diff = lastPosition.HasValue ? lastPosition.Value - Position : Position - drawableSlider.HitObject.CurvePositionAt(completionProgress + 0.01f); + if (Clock.ElapsedFrameTime != 0) + rewinding = Clock.ElapsedFrameTime < 0; + // Ensure the value is substantially high enough to allow for Atan2 to get a valid angle. if (diff.LengthFast < 0.01f) return; - ball.Rotation = -90 + (float)(-Math.Atan2(diff.X, diff.Y) * 180 / Math.PI); + ball.Rotation = -90 + (float)(-Math.Atan2(diff.X, diff.Y) * 180 / Math.PI) + (rewinding ? 180 : 0); lastPosition = Position; } } From 7726dda97568e71e13cf3c9068e3e50c2bbe3696 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Oct 2022 15:31:45 +0900 Subject: [PATCH 1580/2686] Remove whitespace --- osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs index 8e8d45937a..006326fd3c 100644 --- a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs +++ b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs @@ -121,7 +121,7 @@ namespace osu.Game.Tests.Beatmaps Assert.That(preserveCollection.BeatmapMD5Hashes, Does.Contain(initialHash)); Assert.That(noNewCollection.BeatmapMD5Hashes, Does.Not.Contain(initialHash)); - + beatmaps.Save(map.BeatmapInfo, map.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); string finalHash = map.BeatmapInfo.MD5Hash; From 5a5f3af27d3aa3392f1a45a5388c575c3494c389 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Oct 2022 15:42:08 +0900 Subject: [PATCH 1581/2686] Rename property and add xmldoc --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 6 +++-- osu.Game.Rulesets.Osu/OsuInputManager.cs | 28 +++++++++++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index fac1cbfd47..753de6231a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -20,7 +20,9 @@ namespace osu.Game.Rulesets.Osu.Mods public class OsuModRelax : ModRelax, IUpdatableByPlayfield, IApplicableToDrawableRuleset, IApplicableToPlayer { public override LocalisableString Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things."; - public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot), typeof(OsuModMagnetised), typeof(OsuModAlternate), typeof(OsuModSingleTap) }).ToArray(); + + public override Type[] IncompatibleMods => + base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot), typeof(OsuModMagnetised), typeof(OsuModAlternate), typeof(OsuModSingleTap) }).ToArray(); /// /// How early before a hitobject's start time to trigger a hit. @@ -51,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.Mods return; } - osuInputManager.AllowUserPresses = false; + osuInputManager.AllowGameplayInputs = false; } public void Update(Playfield playfield) diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 14b1c0f1a5..1e59e19246 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -19,9 +19,16 @@ namespace osu.Game.Rulesets.Osu { public IEnumerable PressedActions => KeyBindingContainer.PressedActions; - public bool AllowUserPresses + /// + /// Whether gameplay input buttons should be allowed. + /// Defaults to true, generally used for mods like Relax which turn off main inputs. + /// + /// + /// Of note, auxiliary inputs like the "smoke" key are left usable. + /// + public bool AllowGameplayInputs { - set => ((OsuKeyBindingContainer)KeyBindingContainer).AllowUserPresses = value; + set => ((OsuKeyBindingContainer)KeyBindingContainer).AllowGameplayInputs = value; } /// @@ -60,14 +67,21 @@ namespace osu.Game.Rulesets.Osu private class OsuKeyBindingContainer : RulesetKeyBindingContainer { - private bool allowUserPresses = true; + private bool allowGameplayInputs = true; - public bool AllowUserPresses + /// + /// Whether gameplay input buttons should be allowed. + /// Defaults to true, generally used for mods like Relax which turn off main inputs. + /// + /// + /// Of note, auxiliary inputs like the "smoke" key are left usable. + /// + public bool AllowGameplayInputs { - get => allowUserPresses; + get => allowGameplayInputs; set { - allowUserPresses = value; + allowGameplayInputs = value; ReloadMappings(); } } @@ -81,7 +95,7 @@ namespace osu.Game.Rulesets.Osu { base.ReloadMappings(realmKeyBindings); - if (!AllowUserPresses) + if (!AllowGameplayInputs) KeyBindings = KeyBindings.Where(b => b.GetAction() == OsuAction.Smoke).ToList(); } } From f6a8cc3f32d4acfdb2253f593679ab83583d8c6e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Oct 2022 16:05:38 +0900 Subject: [PATCH 1582/2686] Add test showing broken input in HUD overlay when hidden --- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index da6604a653..a984f508ea 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -16,6 +16,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Skinning; using osu.Game.Tests.Gameplay; @@ -148,6 +149,42 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent); } + [Test] + public void TestInputDoesntWorkWhenHUDHidden() + { + SongProgressBar getSongProgress() => hudOverlay.ChildrenOfType().Single(); + + bool seeked = false; + + createNew(); + + AddStep("bind seek", () => + { + seeked = false; + + var progress = getSongProgress(); + + progress.ShowHandle = true; + progress.OnSeek += _ => seeked = true; + }); + + AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false); + AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent); + + AddStep("attempt seek", () => + { + InputManager.MoveMouseTo(getSongProgress()); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("seek not performed", () => !seeked); + + AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true); + + AddStep("attempt seek", () => InputManager.Click(MouseButton.Left)); + AddAssert("seek performed", () => seeked); + } + [Test] public void TestHiddenHUDDoesntBlockComponentUpdates() { From 20adc522b9e7e054483c6387ff9f21d64f4367f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Oct 2022 15:57:41 +0900 Subject: [PATCH 1583/2686] Fix HUD components being interactive even when the HUD is visually hidden --- osu.Game/Screens/Play/HUDOverlay.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 3fbb051c3b..7833c2d7fa 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -39,6 +39,10 @@ namespace osu.Game.Screens.Play /// public float BottomScoringElementsHeight { get; private set; } + // HUD uses AlwaysVisible on child components so they can be in an updated state for next display. + // Without blocking input, this would also allow them to be interacted with in such a state. + public override bool PropagatePositionalInputSubTree => ShowHud.Value; + public readonly KeyCounterDisplay KeyCounter; public readonly ModDisplay ModDisplay; public readonly HoldForMenuButton HoldToQuit; From b783fdf667d03aa6cddc3ccf1fffa704e7552c3b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Oct 2022 16:20:17 +0900 Subject: [PATCH 1584/2686] Fix clicking a leaderboard score at song select transtiioning briefly to main menu - Regressed in #20567. - Closes #20651. --- osu.Game/OsuGame.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 939d3a63ed..1716e48395 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -563,6 +563,15 @@ namespace osu.Game // This should be able to be performed from song select, but that is disabled for now // due to the weird decoupled ruleset logic (which can cause a crash in certain filter scenarios). + // + // As a special case, if the beatmap and ruleset already match, allow immediately displaying the score from song select. + // This is guaranteed to not crash, and feels better from a user's perspective (ie. if they are clicking a score in the + // song select leaderboard). + IEnumerable validScreens = + Beatmap.Value.BeatmapInfo.Equals(databasedBeatmap) && Ruleset.Value.Equals(databasedScore.ScoreInfo.Ruleset) + ? new[] { typeof(SongSelect) } + : Array.Empty(); + PerformFromScreen(screen => { Logger.Log($"{nameof(PresentScore)} updating beatmap ({databasedBeatmap}) and ruleset ({databasedScore.ScoreInfo.Ruleset}) to match score"); @@ -580,7 +589,7 @@ namespace osu.Game screen.Push(new SoloResultsScreen(databasedScore.ScoreInfo, false)); break; } - }); + }, validScreens: validScreens); } public override Task Import(params ImportTask[] imports) From f8036658c701e3f85b808c1b121ec9f35d50b0f0 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Mon, 10 Oct 2022 09:36:18 +0200 Subject: [PATCH 1585/2686] Move clamps directly to the usages in the conversion algorithm --- .../Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs | 2 +- osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 2bdd0e16ad..89b52a3c75 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; + beatLength = timingPoint.BeatLength * Math.Min(legacyDifficultyPoint.BpmMultiplier, 10); else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 524565a863..33f1535437 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; + beatLength = timingPoint.BeatLength * Math.Min(legacyDifficultyPoint.BpmMultiplier, 10); else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 360a91a7e5..9c066ada08 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -178,7 +178,7 @@ namespace osu.Game.Beatmaps.Formats : this() { // Note: In stable, the division occurs on floats, but with compiler optimisations turned on actually seems to occur on doubles via some .NET black magic (possibly inlining?). - BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 1000) / 100.0 : 1; + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; GenerateTicks = !double.IsNaN(beatLength); } From eae32ca4839c3779176a69a0099a257e8f789192 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Mon, 10 Oct 2022 09:39:40 +0200 Subject: [PATCH 1586/2686] Switch `DefinitelyBigger` to `AlmostBigger` to account for fp errors --- osu.Game/Rulesets/Objects/BarLineGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/BarLineGenerator.cs b/osu.Game/Rulesets/Objects/BarLineGenerator.cs index 85bff630e3..58d00801a5 100644 --- a/osu.Game/Rulesets/Objects/BarLineGenerator.cs +++ b/osu.Game/Rulesets/Objects/BarLineGenerator.cs @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Objects startTime += barLength; } - for (double t = startTime; Precision.DefinitelyBigger(endTime, t); t += barLength, currentBeat++) + for (double t = startTime; Precision.AlmostBigger(endTime, t); t += barLength, currentBeat++) { double roundedTime = Math.Round(t, MidpointRounding.AwayFromZero); From 28185178d60ab2ff188fc15d7ebd417ff9aacdfa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 10 Oct 2022 16:51:50 +0900 Subject: [PATCH 1587/2686] Add support for weird storyboards which have backwards events Closes https://github.com/ppy/osu/issues/20632. Not adding test coverage because this is just weird. --- osu.Game/Storyboards/CommandTimeline.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Storyboards/CommandTimeline.cs b/osu.Game/Storyboards/CommandTimeline.cs index 4d0da9597b..d1a1edcd03 100644 --- a/osu.Game/Storyboards/CommandTimeline.cs +++ b/osu.Game/Storyboards/CommandTimeline.cs @@ -27,7 +27,10 @@ namespace osu.Game.Storyboards public void Add(Easing easing, double startTime, double endTime, T startValue, T endValue) { if (endTime < startTime) - return; + { + (startTime, endTime) = (endTime, startTime); + (startValue, endValue) = (endValue, startValue); + } commands.Add(new TypedCommand { Easing = easing, StartTime = startTime, EndTime = endTime, StartValue = startValue, EndValue = endValue }); From d389808427e6d693240df30a8412f432e0b08a1f Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Mon, 10 Oct 2022 14:00:26 +0200 Subject: [PATCH 1588/2686] Make effect point search more efficient --- osu.Game/Rulesets/Objects/BarLineGenerator.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Objects/BarLineGenerator.cs b/osu.Game/Rulesets/Objects/BarLineGenerator.cs index 58d00801a5..9105a78741 100644 --- a/osu.Game/Rulesets/Objects/BarLineGenerator.cs +++ b/osu.Game/Rulesets/Objects/BarLineGenerator.cs @@ -31,7 +31,6 @@ namespace osu.Game.Rulesets.Objects double lastHitTime = 1 + lastObject.GetEndTime(); var timingPoints = beatmap.ControlPointInfo.TimingPoints; - var effectPoints = beatmap.ControlPointInfo.EffectPoints; if (timingPoints.Count == 0) return; @@ -39,14 +38,13 @@ namespace osu.Game.Rulesets.Objects for (int i = 0; i < timingPoints.Count; i++) { TimingControlPoint currentTimingPoint = timingPoints[i]; - EffectControlPoint? currentEffectPoint = effectPoints.FirstOrDefault(p => p.Time == currentTimingPoint.Time); + EffectControlPoint? currentEffectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTimingPoint.Time); int currentBeat = 0; - // Stop on the beat before the next timing point, or if there is no next timing point stop slightly past the last object + // Stop on the next timing point, or if there is no next timing point stop slightly past the last object double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time : lastHitTime + currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; double startTime = currentTimingPoint.Time; - double barLength = currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; if (currentEffectPoint != null && currentEffectPoint.OmitFirstBarLine) From e3b405cc23e51de735d49110358f3e739c677321 Mon Sep 17 00:00:00 2001 From: NotGumballer91 <64581009+NotGumballer91@users.noreply.github.com> Date: Mon, 10 Oct 2022 21:02:23 +0800 Subject: [PATCH 1589/2686] Update IWorkingBeatmap.cs --- osu.Game/Beatmaps/IWorkingBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/IWorkingBeatmap.cs b/osu.Game/Beatmaps/IWorkingBeatmap.cs index a39766abe1..cf72a611e5 100644 --- a/osu.Game/Beatmaps/IWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/IWorkingBeatmap.cs @@ -134,6 +134,6 @@ namespace osu.Game.Beatmaps /// /// Reads the correct track restart point from beatmap metadata and sets looping to enabled. /// - void PrepareTrackForPreview(bool looping); + void PrepareTrackForPreview(bool looping, int priorToPreview = 0); } } From 749dc400627d45d8c6a8f101f8c573e6e961b0fd Mon Sep 17 00:00:00 2001 From: NotGumballer91 <64581009+NotGumballer91@users.noreply.github.com> Date: Mon, 10 Oct 2022 21:03:11 +0800 Subject: [PATCH 1590/2686] Update WorkingBeatmap.cs --- osu.Game/Beatmaps/WorkingBeatmap.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 0a51c843cd..8bd0f4b14b 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -110,10 +110,10 @@ namespace osu.Game.Beatmaps public Track LoadTrack() => track = GetBeatmapTrack() ?? GetVirtualTrack(1000); - public void PrepareTrackForPreview(bool looping) + public void PrepareTrackForPreview(bool looping, int priorToPreview = 2000) { Track.Looping = looping; - Track.RestartPoint = Metadata.PreviewTime; + Track.RestartPoint = Metadata.PreviewTime - priorToPreview; if (Track.RestartPoint == -1) { From 9a3689b6e96acdef198a57c981b12b1267039934 Mon Sep 17 00:00:00 2001 From: NotGumballer91 <64581009+NotGumballer91@users.noreply.github.com> Date: Mon, 10 Oct 2022 21:04:14 +0800 Subject: [PATCH 1591/2686] Update IntroCircles.cs --- osu.Game/Screens/Menu/IntroCircles.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index 7a4bdb231f..a69f2c8a65 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Menu protected override string BeatmapFile => "circles.osz"; - public const double TRACK_START_DELAY = 600; + public const double TRACK_START_DELAY = 1200; private const double delay_for_menu = 2900; From 5a4196fd51f4631ee60a94e856fa82bc9bdcdc20 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Mon, 10 Oct 2022 15:34:29 +0200 Subject: [PATCH 1592/2686] Make `currentEffectPoint` non-nullable --- osu.Game/Rulesets/Objects/BarLineGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/BarLineGenerator.cs b/osu.Game/Rulesets/Objects/BarLineGenerator.cs index 9105a78741..c2709db747 100644 --- a/osu.Game/Rulesets/Objects/BarLineGenerator.cs +++ b/osu.Game/Rulesets/Objects/BarLineGenerator.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects for (int i = 0; i < timingPoints.Count; i++) { TimingControlPoint currentTimingPoint = timingPoints[i]; - EffectControlPoint? currentEffectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTimingPoint.Time); + EffectControlPoint currentEffectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTimingPoint.Time); int currentBeat = 0; // Stop on the next timing point, or if there is no next timing point stop slightly past the last object @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Objects double startTime = currentTimingPoint.Time; double barLength = currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; - if (currentEffectPoint != null && currentEffectPoint.OmitFirstBarLine) + if (currentEffectPoint.OmitFirstBarLine) { startTime += barLength; } From be5a413753346fcb330bf81c71b40fe9aec83ce0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Oct 2022 01:35:35 +0900 Subject: [PATCH 1593/2686] 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 2a678f1c61..f71adff23b 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index efdb6c6995..cb414ebe31 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 47872e4ff7..32e22d6c6f 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From d700040a0d5da69a5d8e8b7396abc398b90e62fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Oct 2022 01:38:37 +0900 Subject: [PATCH 1594/2686] Make country code parsing resilient to invalid cases --- .../Visual/Online/TestSceneWikiMarkdownContainer.cs | 2 +- .../Containers/Markdown/OsuMarkdownTextFlowContainer.cs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 31a866b8f5..863b352618 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -195,7 +195,7 @@ Line after image"; AddStep("Add flag", () => { markdownContainer.CurrentPath = @"https://dev.ppy.sh"; - markdownContainer.Text = "::{flag=\"AU\"}::"; + markdownContainer.Text = "::{flag=\"AU\"}:: ::{flag=\"ZZ\"}::"; }); } diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs index fb8f13ab84..9d7b47281f 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs @@ -57,7 +57,11 @@ namespace osu.Game.Graphics.Containers.Markdown } string flag = flagAttribute.Split('=').Last().Trim('"'); - AddDrawable(new DrawableFlag(Enum.Parse(flag)) { Size = new Vector2(20, 15) }); + + if (!Enum.TryParse(flag, out var countryCode)) + countryCode = CountryCode.Unknown; + + AddDrawable(new DrawableFlag(countryCode) { Size = new Vector2(20, 15) }); } private class OsuMarkdownInlineCode : Container From 32adc1ec14a558950f0e78e7aec2f6ffda540c48 Mon Sep 17 00:00:00 2001 From: Natelytle Date: Mon, 10 Oct 2022 13:36:52 -0400 Subject: [PATCH 1595/2686] Fix division by 0 --- .../Difficulty/ManiaPerformanceCalculator.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs index a925e7c0ac..5d7fec3ede 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty countOk = score.Statistics.GetValueOrDefault(HitResult.Ok); countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); - scoreAccuracy = customAccuracy; + scoreAccuracy = customAccuracy(); // Arbitrary initial value for scaling pp in order to standardize distributions across game modes. // The specific number has no intrinsic meaning and can be adjusted as needed. @@ -73,6 +73,12 @@ namespace osu.Game.Rulesets.Mania.Difficulty /// /// Accuracy used to weight judgements independently from the score's actual accuracy. /// - private double customAccuracy => (countPerfect * 320 + countGreat * 300 + countGood * 200 + countOk * 100 + countMeh * 50) / (totalHits * 320); + private double customAccuracy() + { + if (totalHits==0) + return 0; + + return (countPerfect * 320 + countGreat * 300 + countGood * 200 + countOk * 100 + countMeh * 50) / (totalHits * 320); + } } } From 430eb44446e22a2e2cca0b9a7f9ab317a6f65c48 Mon Sep 17 00:00:00 2001 From: Natelytle Date: Mon, 10 Oct 2022 13:45:16 -0400 Subject: [PATCH 1596/2686] slight formatting --- .../Difficulty/ManiaPerformanceCalculator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs index 5d7fec3ede..5e10e7a8ec 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs @@ -75,8 +75,8 @@ namespace osu.Game.Rulesets.Mania.Difficulty /// private double customAccuracy() { - if (totalHits==0) - return 0; + if (totalHits == 0) + return 0; return (countPerfect * 320 + countGreat * 300 + countGood * 200 + countOk * 100 + countMeh * 50) / (totalHits * 320); } From 3cd6ce8e3f2ef06f94e9a2711cb7e04cff816f48 Mon Sep 17 00:00:00 2001 From: NotGumballer91 <64581009+NotGumballer91@users.noreply.github.com> Date: Tue, 11 Oct 2022 01:48:55 +0800 Subject: [PATCH 1597/2686] Update WorkingBeatmap.cs --- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 8bd0f4b14b..7eb7852897 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -110,7 +110,7 @@ namespace osu.Game.Beatmaps public Track LoadTrack() => track = GetBeatmapTrack() ?? GetVirtualTrack(1000); - public void PrepareTrackForPreview(bool looping, int priorToPreview = 2000) + public void PrepareTrackForPreview(bool looping, int priorToPreview = 0) { Track.Looping = looping; Track.RestartPoint = Metadata.PreviewTime - priorToPreview; From 8a4f2efa141c47a54dcfb12ae4047d508e7659f4 Mon Sep 17 00:00:00 2001 From: NotGumballer91 <64581009+NotGumballer91@users.noreply.github.com> Date: Tue, 11 Oct 2022 01:49:49 +0800 Subject: [PATCH 1598/2686] Update IntroScreen.cs --- osu.Game/Screens/Menu/IntroScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 409c7d6c8d..42a993ff63 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -278,7 +278,7 @@ namespace osu.Game.Screens.Menu if (!UsingThemedIntro) { - initialBeatmap?.PrepareTrackForPreview(false); + initialBeatmap?.PrepareTrackForPreview(false, 2200); drawableTrack.VolumeTo(0); drawableTrack.Restart(); From ef840e98cf5c75b56d051c489a3179ebbf34c3c2 Mon Sep 17 00:00:00 2001 From: NotGumballer91 <64581009+NotGumballer91@users.noreply.github.com> Date: Tue, 11 Oct 2022 01:49:53 +0800 Subject: [PATCH 1599/2686] Update IntroCircles.cs --- osu.Game/Screens/Menu/IntroCircles.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index a69f2c8a65..97654a81df 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Menu protected override string BeatmapFile => "circles.osz"; - public const double TRACK_START_DELAY = 1200; + public const double TRACK_START_DELAY = 1000; private const double delay_for_menu = 2900; From cc54fc5c1b8d491203e19cbd3e1f05034e121691 Mon Sep 17 00:00:00 2001 From: Natelytle Date: Mon, 10 Oct 2022 13:52:01 -0400 Subject: [PATCH 1600/2686] rename method to reflect being a method --- .../Difficulty/ManiaPerformanceCalculator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs index 5e10e7a8ec..d6c2dc1d9e 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty countOk = score.Statistics.GetValueOrDefault(HitResult.Ok); countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); - scoreAccuracy = customAccuracy(); + scoreAccuracy = calculateCustomAccuracy(); // Arbitrary initial value for scaling pp in order to standardize distributions across game modes. // The specific number has no intrinsic meaning and can be adjusted as needed. @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty /// /// Accuracy used to weight judgements independently from the score's actual accuracy. /// - private double customAccuracy() + private double calculateCustomAccuracy() { if (totalHits == 0) return 0; From de8d4853055c31d43e435a6093a9af00a6c72b24 Mon Sep 17 00:00:00 2001 From: pfg Date: Mon, 10 Oct 2022 21:45:33 -0400 Subject: [PATCH 1601/2686] Move 'transferCollections' to a shared location --- osu.Game/Beatmaps/BeatmapImporter.cs | 8 +------- osu.Game/Beatmaps/BeatmapInfo.cs | 12 ++++++++++++ osu.Game/Beatmaps/BeatmapManager.cs | 6 +----- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index 292caa4397..c4378cda5c 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -146,13 +146,7 @@ namespace osu.Game.Beatmaps if (updatedBeatmap == null) continue; - var collections = realm.All().AsEnumerable().Where(c => c.BeatmapMD5Hashes.Contains(originalBeatmap.MD5Hash)); - - foreach (var c in collections) - { - c.BeatmapMD5Hashes.Remove(originalBeatmap.MD5Hash); - c.BeatmapMD5Hashes.Add(updatedBeatmap.MD5Hash); - } + updatedBeatmap.transferCollectionsFrom(realm, originalBeatmap.MD5Hash); } } diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 32b7f0b29b..61431764f0 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -8,6 +8,7 @@ using JetBrains.Annotations; using Newtonsoft.Json; using osu.Framework.Testing; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Collections; using osu.Game.Database; using osu.Game.Models; using osu.Game.Online.API.Requests.Responses; @@ -213,6 +214,17 @@ namespace osu.Game.Beatmaps return fileHashX == fileHashY; } + public void transferCollectionsFrom(Realm realm, string oldMd5Hash) + { + var collections = realm.All().AsEnumerable().Where(c => c.BeatmapMD5Hashes.Contains(oldMd5Hash)); + + foreach (var c in collections) + { + c.BeatmapMD5Hashes.Remove(oldMd5Hash); + c.BeatmapMD5Hashes.Add(MD5Hash); + } + } + IBeatmapMetadataInfo IBeatmapInfo.Metadata => Metadata; IBeatmapSetInfo? IBeatmapInfo.BeatmapSet => BeatmapSet; IRulesetInfo IBeatmapInfo.Ruleset => Ruleset; diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 71cafd46c0..7db5480128 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -330,11 +330,7 @@ namespace osu.Game.Beatmaps setInfo.CopyChangesToRealm(liveBeatmapSet); - foreach (var collection in r.All()) - { - if (collection.BeatmapMD5Hashes.Remove(oldMd5Hash)) - collection.BeatmapMD5Hashes.Add(beatmapInfo.MD5Hash); - } + beatmapInfo.transferCollectionsFrom(r, oldMd5Hash); ProcessBeatmap?.Invoke((liveBeatmapSet, false)); }); From e619c9c1e6eb1c60302158b21ad0d5b7ff5328af Mon Sep 17 00:00:00 2001 From: pfg Date: Mon, 10 Oct 2022 21:48:41 -0400 Subject: [PATCH 1602/2686] fix style --- osu.Game/Beatmaps/BeatmapImporter.cs | 2 +- osu.Game/Beatmaps/BeatmapInfo.cs | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index c4378cda5c..4f09a73440 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -146,7 +146,7 @@ namespace osu.Game.Beatmaps if (updatedBeatmap == null) continue; - updatedBeatmap.transferCollectionsFrom(realm, originalBeatmap.MD5Hash); + updatedBeatmap.TransferCollectionsFrom(realm, originalBeatmap.MD5Hash); } } diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 61431764f0..42461e863c 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -214,7 +214,7 @@ namespace osu.Game.Beatmaps return fileHashX == fileHashY; } - public void transferCollectionsFrom(Realm realm, string oldMd5Hash) + public void TransferCollectionsFrom(Realm realm, string oldMd5Hash) { var collections = realm.All().AsEnumerable().Where(c => c.BeatmapMD5Hashes.Contains(oldMd5Hash)); diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 7db5480128..9224806301 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -330,7 +330,7 @@ namespace osu.Game.Beatmaps setInfo.CopyChangesToRealm(liveBeatmapSet); - beatmapInfo.transferCollectionsFrom(r, oldMd5Hash); + beatmapInfo.TransferCollectionsFrom(r, oldMd5Hash); ProcessBeatmap?.Invoke((liveBeatmapSet, false)); }); From ed2b39a22012656d03f3238f4f0c422f9fed5af8 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 11 Oct 2022 13:53:18 +0900 Subject: [PATCH 1603/2686] Remove whitespace --- .../Difficulty/ManiaPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs index d6c2dc1d9e..440dec82af 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaPerformanceCalculator.cs @@ -79,6 +79,6 @@ namespace osu.Game.Rulesets.Mania.Difficulty return 0; return (countPerfect * 320 + countGreat * 300 + countGood * 200 + countOk * 100 + countMeh * 50) / (totalHits * 320); - } + } } } From 1a24762f9b75582c0dd0bee7368835c9e04f0730 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 11 Oct 2022 14:11:45 +0900 Subject: [PATCH 1604/2686] Improve drag box selection logic `AllowDeselectionDuringDrag` is remove. Instead, selected hit objects are not automatically deselected when clock is seeked to a later time (the hit object is dead). Update drag box selection even if mouse is not moved (in case clock is running or scroll wheel is used). --- .../Compose/Components/BlueprintContainer.cs | 23 +++++++++++-------- .../Components/ComposeBlueprintContainer.cs | 20 ++++++++++++++-- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 8aecc75824..b15cecd506 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -15,6 +15,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osuTK; using osuTK.Input; @@ -106,11 +107,6 @@ namespace osu.Game.Screens.Edit.Compose.Components protected virtual DragBox CreateDragBox() => new DragBox(); - /// - /// Whether this component is in a state where items outside a drag selection should be deselected. If false, selection will only be added to. - /// - protected virtual bool AllowDeselectionDuringDrag => true; - protected override bool OnMouseDown(MouseDownEvent e) { bool selectionPerformed = performMouseDownActions(e); @@ -389,12 +385,19 @@ namespace osu.Game.Screens.Edit.Compose.Components foreach (var blueprint in SelectionBlueprints) { - if (blueprint.IsSelected && !AllowDeselectionDuringDrag) - continue; + switch (blueprint.State) + { + case SelectionState.Selected: + // Selection is preserved even after blueprint becomes dead. + if (!quad.Contains(blueprint.ScreenSpaceSelectionPoint)) + blueprint.Deselect(); + break; - bool shouldBeSelected = blueprint.IsAlive && blueprint.IsPresent && quad.Contains(blueprint.ScreenSpaceSelectionPoint); - if (blueprint.IsSelected != shouldBeSelected) - blueprint.ToggleSelection(); + case SelectionState.NotSelected: + if (blueprint.IsAlive && blueprint.IsPresent && quad.Contains(blueprint.ScreenSpaceSelectionPoint)) + blueprint.Select(); + break; + } } } diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 43ead88d54..c8870d46a8 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -39,6 +39,8 @@ namespace osu.Game.Screens.Edit.Compose.Components private PlacementBlueprint currentPlacement; private InputManager inputManager; + private DragEvent lastDragEvent; + /// /// Positional input must be received outside the container's bounds, /// in order to handle composer blueprints which are partially offscreen. @@ -83,8 +85,6 @@ namespace osu.Game.Screens.Edit.Compose.Components } } - protected override bool AllowDeselectionDuringDrag => !EditorClock.IsRunning; - protected override void TransferBlueprintFor(HitObject hitObject, DrawableHitObject drawableObject) { base.TransferBlueprintFor(hitObject, drawableObject); @@ -120,6 +120,18 @@ namespace osu.Game.Screens.Edit.Compose.Components return false; } + protected override void OnDrag(DragEvent e) + { + base.OnDrag(e); + lastDragEvent = e; + } + + protected override void OnDragEnd(DragEndEvent e) + { + base.OnDragEnd(e); + lastDragEvent = null; + } + /// /// Move the current selection spatially by the specified delta, in gamefield coordinates (ie. the same coordinates as the blueprints). /// @@ -236,6 +248,10 @@ namespace osu.Game.Screens.Edit.Compose.Components { base.Update(); + // trigger every frame so drags continue to update selection while seeking time. + if (lastDragEvent != null) + OnDrag(lastDragEvent); + if (currentPlacement != null) { switch (currentPlacement.PlacementActive) From 6ab29a62d04b66130928cdb463b7b48424025fb5 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 11 Oct 2022 14:23:17 +0900 Subject: [PATCH 1605/2686] Anchor drag box on time (catch, mania) Not done for taiko because I cannot figure out how it should work with the overlapping scroll algorithm. --- .../Edit/CatchBlueprintContainer.cs | 3 + .../Edit/ManiaBlueprintContainer.cs | 3 + .../Compose/Components/ScrollingDragBox.cs | 63 +++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs diff --git a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs index 58f493b4b8..20d432d62e 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs @@ -5,6 +5,7 @@ using osu.Game.Rulesets.Catch.Edit.Blueprints; using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Screens.Edit.Compose.Components; @@ -36,5 +37,7 @@ namespace osu.Game.Rulesets.Catch.Edit return base.CreateHitObjectBlueprintFor(hitObject); } + + protected sealed override DragBox CreateDragBox() => new ScrollingDragBox((CatchPlayfield)Composer.Playfield); } } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs index ad75afff8e..c3fad1e22b 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs @@ -6,6 +6,7 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Objects; using osu.Game.Screens.Edit.Compose.Components; @@ -33,5 +34,7 @@ namespace osu.Game.Rulesets.Mania.Edit } protected override SelectionHandler CreateSelectionHandler() => new ManiaSelectionHandler(); + + protected sealed override DragBox CreateDragBox() => new ScrollingDragBox((ManiaPlayfield)Composer.Playfield); } } diff --git a/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs b/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs new file mode 100644 index 0000000000..2d2c88247b --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs @@ -0,0 +1,63 @@ +// 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.Input.Events; +using osu.Game.Rulesets.UI.Scrolling; + +namespace osu.Game.Screens.Edit.Compose.Components +{ + /// + /// A that scrolls along with the scrolling playfield. + /// + public class ScrollingDragBox : DragBox + { + public double MinTime { get; private set; } + + public double MaxTime { get; private set; } + + private double? startTime; + + private readonly ScrollingPlayfield playfield; + + public ScrollingDragBox(ScrollingPlayfield playfield) + { + this.playfield = playfield; + } + + public override void HandleDrag(MouseButtonEvent e) + { + base.HandleDrag(e); + + startTime ??= playfield.TimeAtScreenSpacePosition(e.ScreenSpaceMouseDownPosition); + double endTime = playfield.TimeAtScreenSpacePosition(e.ScreenSpaceMousePosition); + + MinTime = Math.Min(startTime.Value, endTime); + MaxTime = Math.Max(startTime.Value, endTime); + + var startPos = ToLocalSpace(playfield.ScreenSpacePositionAtTime(startTime.Value)); + var endPos = ToLocalSpace(playfield.ScreenSpacePositionAtTime(endTime)); + + switch (playfield.ScrollingInfo.Direction.Value) + { + case ScrollingDirection.Up: + case ScrollingDirection.Down: + Box.Y = Math.Min(startPos.Y, endPos.Y); + Box.Height = Math.Max(startPos.Y, endPos.Y) - Box.Y; + break; + + case ScrollingDirection.Left: + case ScrollingDirection.Right: + Box.X = Math.Min(startPos.X, endPos.X); + Box.Width = Math.Max(startPos.X, endPos.X) - Box.X; + break; + } + } + + public override void Hide() + { + base.Hide(); + startTime = null; + } + } +} From a44ba579c5c39f8878e3f93f51614a270a13fc66 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Oct 2022 11:29:17 +0900 Subject: [PATCH 1606/2686] Fix beatmap update button not respecting user "prefer no video" setting Closes #20701. --- osu.Game/Database/ModelDownloader.cs | 2 +- .../Screens/Select/Carousel/UpdateBeatmapSetButton.cs | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index 877c90a534..6cba8fe819 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -45,7 +45,7 @@ namespace osu.Game.Database public bool Download(T model, bool minimiseDownloadSize = false) => Download(model, minimiseDownloadSize, null); - public void DownloadAsUpdate(TModel originalModel) => Download(originalModel, false, originalModel); + public void DownloadAsUpdate(TModel originalModel, bool minimiseDownloadSize) => Download(originalModel, minimiseDownloadSize, originalModel); protected bool Download(T model, bool minimiseDownloadSize, TModel? originalModel) { diff --git a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs b/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs index 3c4ed4734b..023d3627b0 100644 --- a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs +++ b/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs @@ -2,12 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -43,11 +45,15 @@ namespace osu.Game.Screens.Select.Carousel Origin = Anchor.CentreLeft; } + private Bindable preferNoVideo = null!; + [BackgroundDependencyLoader] - private void load() + private void load(OsuConfigManager config) { const float icon_size = 14; + preferNoVideo = config.GetBindable(OsuSetting.PreferNoVideo); + Content.Anchor = Anchor.CentreLeft; Content.Origin = Anchor.CentreLeft; @@ -104,7 +110,7 @@ namespace osu.Game.Screens.Select.Carousel return; } - beatmapDownloader.DownloadAsUpdate(beatmapSetInfo); + beatmapDownloader.DownloadAsUpdate(beatmapSetInfo, preferNoVideo.Value); attachExistingDownload(); }; } From 6f6290a21a51477dfb1546d0305afcb7b8ea5c07 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Oct 2022 15:37:22 +0900 Subject: [PATCH 1607/2686] Use async flow for storing key binding changes to realm --- .../Overlays/Settings/Sections/Input/KeyBindingRow.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 9ff47578e9..2fea2e34b2 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -387,14 +387,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (bindTarget != null) bindTarget.IsBinding = true; } - private void updateStoreFromButton(KeyButton button) - { - realm.Run(r => - { - var binding = r.Find(((IHasGuidPrimaryKey)button.KeyBinding).ID); - r.Write(() => binding.KeyCombinationString = button.KeyBinding.KeyCombinationString); - }); - } + private void updateStoreFromButton(KeyButton button) => + realm.WriteAsync(r => r.Find(button.KeyBinding.ID).KeyCombinationString = button.KeyBinding.KeyCombinationString); private void updateIsDefaultValue() { From eba3d37a1197e0a4accfac3d69c1330d316f351c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Oct 2022 15:50:02 +0900 Subject: [PATCH 1608/2686] Add xmldoc and simplify calling --- osu.Game/Beatmaps/BeatmapImporter.cs | 9 +++------ osu.Game/Beatmaps/BeatmapInfo.cs | 12 +++++++++--- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index 4f09a73440..bcb1d7f961 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -141,12 +141,9 @@ namespace osu.Game.Beatmaps // Handle collections using permissive difficulty name to track difficulties. foreach (var originalBeatmap in original.Beatmaps) { - var updatedBeatmap = updated.Beatmaps.FirstOrDefault(b => b.DifficultyName == originalBeatmap.DifficultyName); - - if (updatedBeatmap == null) - continue; - - updatedBeatmap.TransferCollectionsFrom(realm, originalBeatmap.MD5Hash); + updated.Beatmaps + .FirstOrDefault(b => b.DifficultyName == originalBeatmap.DifficultyName)? + .TransferCollectionReferences(realm, originalBeatmap.MD5Hash); } } diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 42461e863c..6f9df1ba7f 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -214,13 +214,19 @@ namespace osu.Game.Beatmaps return fileHashX == fileHashY; } - public void TransferCollectionsFrom(Realm realm, string oldMd5Hash) + /// + /// When updating a beatmap, its hashes will change. Collections currently track beatmaps by hash, so they need to be updated. + /// This method will handle updating + /// + /// A realm instance in an active write transaction. + /// The previous MD5 hash of the beatmap before update. + public void TransferCollectionReferences(Realm realm, string previousMD5Hash) { - var collections = realm.All().AsEnumerable().Where(c => c.BeatmapMD5Hashes.Contains(oldMd5Hash)); + var collections = realm.All().AsEnumerable().Where(c => c.BeatmapMD5Hashes.Contains(previousMD5Hash)); foreach (var c in collections) { - c.BeatmapMD5Hashes.Remove(oldMd5Hash); + c.BeatmapMD5Hashes.Remove(previousMD5Hash); c.BeatmapMD5Hashes.Add(MD5Hash); } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 9224806301..8ea22e5d67 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -330,7 +330,7 @@ namespace osu.Game.Beatmaps setInfo.CopyChangesToRealm(liveBeatmapSet); - beatmapInfo.TransferCollectionsFrom(r, oldMd5Hash); + beatmapInfo.TransferCollectionReferences(r, oldMd5Hash); ProcessBeatmap?.Invoke((liveBeatmapSet, false)); }); From ece42de408544565821121591a953813a6fba5aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Oct 2022 15:53:48 +0900 Subject: [PATCH 1609/2686] Fix variable naming in test --- .../Beatmaps/WorkingBeatmapManagerTest.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs index 006326fd3c..4ef466efbf 100644 --- a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs +++ b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs @@ -104,15 +104,17 @@ namespace osu.Game.Tests.Beatmaps { var beatmap = Realm.Run(r => r.Find(importedSet.Beatmaps.First().ID).Detach()); - var map = beatmaps.GetWorkingBeatmap(beatmap); + var working = beatmaps.GetWorkingBeatmap(beatmap); - Assert.That(map.BeatmapInfo.BeatmapSet?.Files, Has.Count.GreaterThan(0)); + Assert.That(working.BeatmapInfo.BeatmapSet?.Files, Has.Count.GreaterThan(0)); - string initialHash = map.BeatmapInfo.MD5Hash; + string initialHash = working.BeatmapInfo.MD5Hash; - var preserveCollection = new BeatmapCollection("test save preserves collection"); + var preserveCollection = new BeatmapCollection("test contained"); preserveCollection.BeatmapMD5Hashes.Add(initialHash); - var noNewCollection = new BeatmapCollection("test save does not introduce new collection"); + + var noNewCollection = new BeatmapCollection("test not contained"); + Realm.Write(r => { r.Add(preserveCollection); @@ -122,9 +124,9 @@ namespace osu.Game.Tests.Beatmaps Assert.That(preserveCollection.BeatmapMD5Hashes, Does.Contain(initialHash)); Assert.That(noNewCollection.BeatmapMD5Hashes, Does.Not.Contain(initialHash)); - beatmaps.Save(map.BeatmapInfo, map.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); + beatmaps.Save(working.BeatmapInfo, working.GetPlayableBeatmap(new OsuRuleset().RulesetInfo)); - string finalHash = map.BeatmapInfo.MD5Hash; + string finalHash = working.BeatmapInfo.MD5Hash; Assert.That(finalHash, Is.Not.SameAs(initialHash)); From 9bab02fab4a4fc9df3c6037394f2a8fba5f1edf3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Oct 2022 16:23:05 +0900 Subject: [PATCH 1610/2686] Remove unused using statement --- osu.Game/Beatmaps/BeatmapManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 8ea22e5d67..befc56d244 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -17,7 +17,6 @@ using osu.Framework.IO.Stores; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps.Formats; -using osu.Game.Collections; using osu.Game.Database; using osu.Game.Extensions; using osu.Game.IO.Archives; From f060e6a780c43057eea6cab2e140c8b6ca8da26e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Oct 2022 16:31:37 +0900 Subject: [PATCH 1611/2686] Implement hold "sliding" samples in osu!mania --- .../Objects/Drawables/DrawableHoldNote.cs | 45 +++++++++++++++++++ osu.Game.Rulesets.Osu/Objects/Slider.cs | 15 ------- osu.Game/Rulesets/Objects/HitObject.cs | 16 +++++++ 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 19792086a7..48647f9f5f 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -4,12 +4,14 @@ #nullable disable using System; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Game.Audio; using osu.Game.Rulesets.Mania.Skinning.Default; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -38,6 +40,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables private Container tailContainer; private Container tickContainer; + private PausableSkinnableSound slidingSample; + /// /// Contains the size of the hold note covering the whole head/tail bounds. The size of this container changes as the hold note is being pressed. /// @@ -108,6 +112,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables }, tickContainer = new Container { RelativeSizeAxes = Axes.Both }, tailContainer = new Container { RelativeSizeAxes = Axes.Both }, + slidingSample = new PausableSkinnableSound { Looping = true } }); maskedContents.AddRange(new[] @@ -118,6 +123,13 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables }); } + protected override void LoadComplete() + { + base.LoadComplete(); + + isHitting.BindValueChanged(updateSlidingSample, true); + } + protected override void OnApply() { base.OnApply(); @@ -322,5 +334,38 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables HoldStartTime = null; isHitting.Value = false; } + + protected override void LoadSamples() + { + // Note: base.LoadSamples() isn't called since the slider plays the tail's hitsounds for the time being. + + if (HitObject.SampleControlPoint == null) + { + throw new InvalidOperationException($"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}." + + $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}."); + } + + slidingSample.Samples = HitObject.CreateSlidingSamples().Select(s => HitObject.SampleControlPoint.ApplyTo(s)).Cast().ToArray(); + } + + public override void StopAllSamples() + { + base.StopAllSamples(); + slidingSample?.Stop(); + } + + private void updateSlidingSample(ValueChangedEvent tracking) + { + if (tracking.NewValue) + slidingSample?.Play(); + else + slidingSample?.Stop(); + } + + protected override void OnFree() + { + slidingSample.Samples = null; + base.OnFree(); + } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index e3c1b1e168..6c2be8a49a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -34,21 +34,6 @@ namespace osu.Game.Rulesets.Osu.Objects public override IList AuxiliarySamples => CreateSlidingSamples().Concat(TailSamples).ToArray(); - public IList CreateSlidingSamples() - { - var slidingSamples = new List(); - - var normalSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL); - if (normalSample != null) - slidingSamples.Add(normalSample.With("sliderslide")); - - var whistleSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_WHISTLE); - if (whistleSample != null) - slidingSamples.Add(whistleSample.With("sliderwhistle")); - - return slidingSamples; - } - private readonly Cached endPositionCache = new Cached(); public override Vector2 EndPosition => endPositionCache.IsValid ? endPositionCache.Value : endPositionCache.Value = Position + this.CurvePositionAt(1); diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index d20e0616e5..0f79e58201 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using System.Threading; using JetBrains.Annotations; using Newtonsoft.Json; @@ -198,6 +199,21 @@ namespace osu.Game.Rulesets.Objects ///
[NotNull] protected virtual HitWindows CreateHitWindows() => new HitWindows(); + + public IList CreateSlidingSamples() + { + var slidingSamples = new List(); + + var normalSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL); + if (normalSample != null) + slidingSamples.Add(normalSample.With("sliderslide")); + + var whistleSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_WHISTLE); + if (whistleSample != null) + slidingSamples.Add(whistleSample.With("sliderwhistle")); + + return slidingSamples; + } } public static class HitObjectExtensions From f41b79688f184ab9182ef4ffde6e7ce8bd797bfc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Oct 2022 16:54:41 +0900 Subject: [PATCH 1612/2686] Avoid casting by accepting all `Playfield`s but throwing on a bad choice --- osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs | 3 +-- osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs | 3 +-- osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs | 5 +++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs index 20d432d62e..a0a11424d0 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs @@ -5,7 +5,6 @@ using osu.Game.Rulesets.Catch.Edit.Blueprints; using osu.Game.Rulesets.Catch.Objects; -using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Screens.Edit.Compose.Components; @@ -38,6 +37,6 @@ namespace osu.Game.Rulesets.Catch.Edit return base.CreateHitObjectBlueprintFor(hitObject); } - protected sealed override DragBox CreateDragBox() => new ScrollingDragBox((CatchPlayfield)Composer.Playfield); + protected sealed override DragBox CreateDragBox() => new ScrollingDragBox(Composer.Playfield); } } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs index c3fad1e22b..f438d6497c 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs @@ -6,7 +6,6 @@ using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Mania.Edit.Blueprints; using osu.Game.Rulesets.Mania.Objects; -using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Objects; using osu.Game.Screens.Edit.Compose.Components; @@ -35,6 +34,6 @@ namespace osu.Game.Rulesets.Mania.Edit protected override SelectionHandler CreateSelectionHandler() => new ManiaSelectionHandler(); - protected sealed override DragBox CreateDragBox() => new ScrollingDragBox((ManiaPlayfield)Composer.Playfield); + protected sealed override DragBox CreateDragBox() => new ScrollingDragBox(Composer.Playfield); } } diff --git a/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs b/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs index 2d2c88247b..58bfaf56ff 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Input.Events; +using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Screens.Edit.Compose.Components @@ -20,9 +21,9 @@ namespace osu.Game.Screens.Edit.Compose.Components private readonly ScrollingPlayfield playfield; - public ScrollingDragBox(ScrollingPlayfield playfield) + public ScrollingDragBox(Playfield playfield) { - this.playfield = playfield; + this.playfield = playfield as ScrollingPlayfield ?? throw new ArgumentException("Playfield must be of type {nameof(ScrollingPlayfield)} to use this class.", nameof(playfield)); } public override void HandleDrag(MouseButtonEvent e) From 5baad52a9ef8ab064633bc4a76f3eced160a246c Mon Sep 17 00:00:00 2001 From: NotGumballer91 <64581009+NotGumballer91@users.noreply.github.com> Date: Tue, 11 Oct 2022 16:15:56 +0800 Subject: [PATCH 1613/2686] Fix unintended delay on osu!theme --- osu.Game/Screens/Menu/IntroCircles.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index 97654a81df..7a4bdb231f 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Menu protected override string BeatmapFile => "circles.osz"; - public const double TRACK_START_DELAY = 1000; + public const double TRACK_START_DELAY = 600; private const double delay_for_menu = 2900; From d18466d7406244f1f76f4c83f5a417c869eb26ce Mon Sep 17 00:00:00 2001 From: NotGumballer91 <64581009+NotGumballer91@users.noreply.github.com> Date: Tue, 11 Oct 2022 16:16:57 +0800 Subject: [PATCH 1614/2686] Fix delay inconsistency in IntroCircles.cs --- osu.Game/Screens/Menu/IntroScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 42a993ff63..435c02de96 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -278,11 +278,11 @@ namespace osu.Game.Screens.Menu if (!UsingThemedIntro) { - initialBeatmap?.PrepareTrackForPreview(false, 2200); + initialBeatmap?.PrepareTrackForPreview(false, 2600); drawableTrack.VolumeTo(0); drawableTrack.Restart(); - drawableTrack.VolumeTo(1, 2200, Easing.InCubic); + drawableTrack.VolumeTo(1, 2600, Easing.InCubic); } else { From 390ff8b9da93841a0dc78577f50959158d9a5bed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 11 Oct 2022 17:33:44 +0900 Subject: [PATCH 1615/2686] Reduce the scope of realm transactions during import operations --- .../Database/RealmArchiveModelImporter.cs | 45 ++++++++++++------- osu.Game/Database/RealmFileStore.cs | 6 +-- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index f1bc0bfe0e..0286815569 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -294,15 +294,38 @@ namespace osu.Game.Database // Log output here will be missing a valid hash in non-batch imports. LogForModel(item, $@"Beginning import from {archive?.Name ?? "unknown"}..."); + List files = new List(); + + if (archive != null) + { + // Import files to the disk store. + // We intentionally delay adding to realm to avoid blocking on a write during disk operations. + foreach (var filenames in getShortenedFilenames(archive)) + { + using (Stream s = archive.GetStream(filenames.original)) + files.Add(new RealmNamedFileUsage(Files.Add(s, realm, false), filenames.shortened)); + } + } + + using (var transaction = realm.BeginWrite()) + { + // Add all files to realm in one go. + // This is done ahead of the main transaction to ensure we can correctly cleanup the files, even if the import fails. + foreach (var file in files) + { + if (!file.File.IsManaged) + realm.Add(file.File, true); + } + + transaction.Commit(); + } + + item.Files.AddRange(files); + item.Hash = ComputeHash(item); + // TODO: do we want to make the transaction this local? not 100% sure, will need further investigation. using (var transaction = realm.BeginWrite()) { - if (archive != null) - // TODO: look into rollback of file additions (or delayed commit). - item.Files.AddRange(createFileInfos(archive, Files, realm)); - - item.Hash = ComputeHash(item); - // TODO: we may want to run this outside of the transaction. Populate(item, archive, realm, cancellationToken); @@ -425,16 +448,6 @@ namespace osu.Game.Database { var fileInfos = new List(); - // import files to manager - foreach (var filenames in getShortenedFilenames(reader)) - { - using (Stream s = reader.GetStream(filenames.original)) - { - var item = new RealmNamedFileUsage(files.Add(s, realm), filenames.shortened); - fileInfos.Add(item); - } - } - return fileInfos; } diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index ecb152c45c..036b15ea17 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -40,8 +40,8 @@ namespace osu.Game.Database ///
/// The file data stream. /// The realm instance to add to. Should already be in a transaction. - /// - public RealmFile Add(Stream data, Realm realm) + /// Whether the should immediately be added to the underlying realm. If false is provided here, the instance must be manually added. + public RealmFile Add(Stream data, Realm realm, bool addToRealm = true) { string hash = data.ComputeSHA2Hash(); @@ -52,7 +52,7 @@ namespace osu.Game.Database if (!checkFileExistsAndMatchesHash(file)) copyToStore(file, data); - if (!file.IsManaged) + if (addToRealm && !file.IsManaged) realm.Add(file); return file; From 9b45a9cf76c4e50c8f821b495e8cb39715dc7550 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 11 Oct 2022 16:20:57 +0300 Subject: [PATCH 1616/2686] Rename various cursor symbols - `IProvideCursor.MenuCursor` -> `IProvideCursor.Cursor` - `MenuCursor` -> `MenuCursorContainer --- .../TestSceneZoomableScrollContainer.cs | 2 +- .../Visual/UserInterface/TestSceneCursors.cs | 50 +++++++++---------- .../Graphics/Cursor/GlobalCursorDisplay.cs | 16 +++--- osu.Game/Graphics/Cursor/IProvideCursor.cs | 4 +- .../{MenuCursor.cs => MenuCursorContainer.cs} | 2 +- osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 +- osu.Game/Screens/Utility/LatencyArea.cs | 8 +-- 7 files changed, 43 insertions(+), 41 deletions(-) rename osu.Game/Graphics/Cursor/{MenuCursor.cs => MenuCursorContainer.cs} (99%) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs index 1858aee76b..89c5b9b23b 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Editing } } }, - new MenuCursor() + new MenuCursorContainer() }; scrollContainer.Add(innerBox = new Box diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs index bcbe146456..6033fc5871 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs @@ -96,10 +96,10 @@ namespace osu.Game.Tests.Visual.UserInterface private void testUserCursor() { AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0])); - AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].MenuCursor)); - AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].MenuCursor)); + AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].Cursor)); + AddAssert("Check green cursor at mouse", () => checkAtMouse(cursorBoxes[0].Cursor)); AddStep("Move out", moveOut); - AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].MenuCursor)); + AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor)); AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor)); } @@ -111,12 +111,12 @@ namespace osu.Game.Tests.Visual.UserInterface private void testLocalCursor() { AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3])); - AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor)); - AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].MenuCursor)); + AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor)); + AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor)); AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor)); AddAssert("Check global cursor at mouse", () => checkAtMouse(globalCursorDisplay.MenuCursor)); AddStep("Move out", moveOut); - AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor)); + AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor)); AddAssert("Check global cursor visible", () => checkVisible(globalCursorDisplay.MenuCursor)); } @@ -128,12 +128,12 @@ namespace osu.Game.Tests.Visual.UserInterface private void testUserCursorOverride() { AddStep("Move to blue-green boundary", () => InputManager.MoveMouseTo(cursorBoxes[1].ScreenSpaceDrawQuad.BottomRight - new Vector2(10))); - AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].MenuCursor)); - AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].MenuCursor)); - AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].MenuCursor)); + AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor)); + AddAssert("Check green cursor invisible", () => !checkVisible(cursorBoxes[0].Cursor)); + AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor)); AddStep("Move out", moveOut); - AddAssert("Check blue cursor not visible", () => !checkVisible(cursorBoxes[1].MenuCursor)); - AddAssert("Check green cursor not visible", () => !checkVisible(cursorBoxes[0].MenuCursor)); + AddAssert("Check blue cursor not visible", () => !checkVisible(cursorBoxes[1].Cursor)); + AddAssert("Check green cursor not visible", () => !checkVisible(cursorBoxes[0].Cursor)); } /// @@ -143,13 +143,13 @@ namespace osu.Game.Tests.Visual.UserInterface private void testMultipleLocalCursors() { AddStep("Move to yellow-purple boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.BottomRight - new Vector2(10))); - AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor)); - AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].MenuCursor)); - AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor)); - AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].MenuCursor)); + AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor)); + AddAssert("Check purple cursor at mouse", () => checkAtMouse(cursorBoxes[3].Cursor)); + AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor)); + AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].Cursor)); AddStep("Move out", moveOut); - AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].MenuCursor)); - AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor)); + AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor)); + AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor)); } /// @@ -159,13 +159,13 @@ namespace osu.Game.Tests.Visual.UserInterface private void testUserOverrideWithLocal() { AddStep("Move to yellow-blue boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.TopRight - new Vector2(10))); - AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].MenuCursor)); - AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].MenuCursor)); - AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor)); - AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].MenuCursor)); + AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor)); + AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor)); + AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor)); + AddAssert("Check yellow cursor at mouse", () => checkAtMouse(cursorBoxes[5].Cursor)); AddStep("Move out", moveOut); - AddAssert("Check blue cursor invisible", () => !checkVisible(cursorBoxes[1].MenuCursor)); - AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].MenuCursor)); + AddAssert("Check blue cursor invisible", () => !checkVisible(cursorBoxes[1].Cursor)); + AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor)); } /// @@ -191,7 +191,7 @@ namespace osu.Game.Tests.Visual.UserInterface { public bool SmoothTransition; - public CursorContainer MenuCursor { get; } + public CursorContainer Cursor { get; } public bool ProvidingUserCursor { get; } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || (SmoothTransition && !ProvidingUserCursor); @@ -218,7 +218,7 @@ namespace osu.Game.Tests.Visual.UserInterface Origin = Anchor.Centre, Text = providesUserCursor ? "User cursor" : "Local cursor" }, - MenuCursor = new TestCursorContainer + Cursor = new TestCursorContainer { State = { Value = providesUserCursor ? Visibility.Hidden : Visibility.Visible }, } diff --git a/osu.Game/Graphics/Cursor/GlobalCursorDisplay.cs b/osu.Game/Graphics/Cursor/GlobalCursorDisplay.cs index 6613e18cbe..f5429723be 100644 --- a/osu.Game/Graphics/Cursor/GlobalCursorDisplay.cs +++ b/osu.Game/Graphics/Cursor/GlobalCursorDisplay.cs @@ -13,7 +13,7 @@ using osu.Game.Configuration; namespace osu.Game.Graphics.Cursor { /// - /// A container which provides the main . + /// A container which provides the main . /// Also handles cases where a more localised cursor is provided by another component (via ). /// public class GlobalCursorDisplay : Container, IProvideCursor @@ -23,7 +23,9 @@ namespace osu.Game.Graphics.Cursor /// internal bool ShowCursor = true; - public CursorContainer MenuCursor { get; } + CursorContainer IProvideCursor.Cursor => MenuCursor; + + public MenuCursorContainer MenuCursor { get; } public bool ProvidingUserCursor => true; @@ -42,8 +44,8 @@ namespace osu.Game.Graphics.Cursor { AddRangeInternal(new Drawable[] { - MenuCursor = new MenuCursor { State = { Value = Visibility.Hidden } }, - Content = new Container { RelativeSizeAxes = Axes.Both } + Content = new Container { RelativeSizeAxes = Axes.Both }, + MenuCursor = new MenuCursorContainer { State = { Value = Visibility.Hidden } } }); } @@ -64,7 +66,7 @@ namespace osu.Game.Graphics.Cursor if (!hasValidInput || !ShowCursor) { - currentOverrideProvider?.MenuCursor?.Hide(); + currentOverrideProvider?.Cursor?.Hide(); currentOverrideProvider = null; return; } @@ -83,8 +85,8 @@ namespace osu.Game.Graphics.Cursor if (currentOverrideProvider == newOverrideProvider) return; - currentOverrideProvider?.MenuCursor?.Hide(); - newOverrideProvider.MenuCursor?.Show(); + currentOverrideProvider?.Cursor?.Hide(); + newOverrideProvider.Cursor?.Show(); currentOverrideProvider = newOverrideProvider; } diff --git a/osu.Game/Graphics/Cursor/IProvideCursor.cs b/osu.Game/Graphics/Cursor/IProvideCursor.cs index f7f7b75bc8..9f01e5da6d 100644 --- a/osu.Game/Graphics/Cursor/IProvideCursor.cs +++ b/osu.Game/Graphics/Cursor/IProvideCursor.cs @@ -17,10 +17,10 @@ namespace osu.Game.Graphics.Cursor /// The cursor provided by this . /// May be null if no cursor should be visible. /// - CursorContainer MenuCursor { get; } + CursorContainer Cursor { get; } /// - /// Whether should be displayed as the singular user cursor. This will temporarily hide any other user cursor. + /// Whether should be displayed as the singular user cursor. This will temporarily hide any other user cursor. /// This value is checked every frame and may be used to control whether multiple cursors are displayed (e.g. watching replays). /// bool ProvidingUserCursor { get; } diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs similarity index 99% rename from osu.Game/Graphics/Cursor/MenuCursor.cs rename to osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 862a10208c..53c78ad5a2 100644 --- a/osu.Game/Graphics/Cursor/MenuCursor.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Graphics.Cursor { - public class MenuCursor : CursorContainer + public class MenuCursorContainer : CursorContainer { private readonly IBindable screenshotCursorVisibility = new Bindable(true); public override bool IsPresent => screenshotCursorVisibility.Value && base.IsPresent; diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 73acb1759f..bd10bc839c 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -384,7 +384,7 @@ namespace osu.Game.Rulesets.UI // only show the cursor when within the playfield, by default. public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Playfield.ReceivePositionalInputAt(screenSpacePos); - CursorContainer IProvideCursor.MenuCursor => Playfield.Cursor; + CursorContainer IProvideCursor.Cursor => Playfield.Cursor; public override GameplayCursorContainer Cursor => Playfield.Cursor; diff --git a/osu.Game/Screens/Utility/LatencyArea.cs b/osu.Game/Screens/Utility/LatencyArea.cs index c8e0bf93a2..b7d45ba642 100644 --- a/osu.Game/Screens/Utility/LatencyArea.cs +++ b/osu.Game/Screens/Utility/LatencyArea.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.Utility public readonly Bindable VisualMode = new Bindable(); - public CursorContainer? MenuCursor { get; private set; } + public CursorContainer? Cursor { get; private set; } public bool ProvidingUserCursor => IsActiveArea.Value; @@ -91,7 +91,7 @@ namespace osu.Game.Screens.Utility { RelativeSizeAxes = Axes.Both, }, - MenuCursor = new LatencyCursorContainer + Cursor = new LatencyCursorContainer { RelativeSizeAxes = Axes.Both, }, @@ -105,7 +105,7 @@ namespace osu.Game.Screens.Utility { RelativeSizeAxes = Axes.Both, }, - MenuCursor = new LatencyCursorContainer + Cursor = new LatencyCursorContainer { RelativeSizeAxes = Axes.Both, }, @@ -119,7 +119,7 @@ namespace osu.Game.Screens.Utility { RelativeSizeAxes = Axes.Both, }, - MenuCursor = new LatencyCursorContainer + Cursor = new LatencyCursorContainer { RelativeSizeAxes = Axes.Both, }, From 894127a948db0e429265f7d9eaff581dd0a04fd8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 11 Oct 2022 16:21:50 +0300 Subject: [PATCH 1617/2686] Expose bindable for identifying last input source --- osu.Game/Input/OsuUserInputManager.cs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/osu.Game/Input/OsuUserInputManager.cs b/osu.Game/Input/OsuUserInputManager.cs index 7a9002a004..5e700e32de 100644 --- a/osu.Game/Input/OsuUserInputManager.cs +++ b/osu.Game/Input/OsuUserInputManager.cs @@ -3,17 +3,43 @@ #nullable disable +using osu.Framework.Bindables; using osu.Framework.Input; +using osu.Framework.Input.StateChanges.Events; using osuTK.Input; namespace osu.Game.Input { public class OsuUserInputManager : UserInputManager { + /// + /// Whether the last input applied to the game is sourced from mouse. + /// + public IBindable IsMouseInputSource => isMouseInputSource; + + private readonly Bindable isMouseInputSource = new Bindable(); + internal OsuUserInputManager() { } + public override void HandleInputStateChange(InputStateChangeEvent inputStateChange) + { + switch (inputStateChange) + { + case ButtonStateChangeEvent: + case MousePositionChangeEvent: + isMouseInputSource.Value = true; + break; + + default: + isMouseInputSource.Value = false; + break; + } + + base.HandleInputStateChange(inputStateChange); + } + protected override MouseButtonEventManager CreateButtonEventManagerFor(MouseButton button) { switch (button) From 60c92c874469d6006cc193ea70bfd24788ef1082 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 11 Oct 2022 16:22:57 +0300 Subject: [PATCH 1618/2686] Enable NRT on `MenuCursorContainer` --- .../Graphics/Cursor/MenuCursorContainer.cs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 53c78ad5a2..01c8853a04 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -1,10 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -28,17 +25,18 @@ namespace osu.Game.Graphics.Cursor protected override Drawable CreateCursor() => activeCursor = new Cursor(); - private Cursor activeCursor; + private Cursor activeCursor = null!; - private Bindable cursorRotate; private DragRotationState dragRotationState; private Vector2 positionMouseDown; - private Sample tapSample; private Vector2 lastMovePosition; - [BackgroundDependencyLoader(true)] - private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager, AudioManager audio) + private Bindable cursorRotate = null!; + private Sample tapSample = null!; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config, ScreenshotManager? screenshotManager, AudioManager audio) { cursorRotate = config.GetBindable(OsuSetting.CursorRotation); @@ -163,11 +161,11 @@ namespace osu.Game.Graphics.Cursor public class Cursor : Container { - private Container cursorContainer; - private Bindable cursorScale; + private Container cursorContainer = null!; + private Bindable cursorScale = null!; private const float base_scale = 0.15f; - public Sprite AdditiveLayer; + public Sprite AdditiveLayer = null!; public Cursor() { From 0a97ee71a97968dcddb1a8f423b28865a0ef6f67 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 11 Oct 2022 16:23:24 +0300 Subject: [PATCH 1619/2686] Hide menu cursor when non-mouse input is applied --- .../Graphics/Cursor/MenuCursorContainer.cs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 01c8853a04..70fa66b35a 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Configuration; +using osu.Game.Input; using osuTK; namespace osu.Game.Graphics.Cursor @@ -27,14 +28,22 @@ namespace osu.Game.Graphics.Cursor private Cursor activeCursor = null!; + private readonly Container fadeContainer; + + protected override Container Content => fadeContainer; + private DragRotationState dragRotationState; private Vector2 positionMouseDown; - private Vector2 lastMovePosition; private Bindable cursorRotate = null!; private Sample tapSample = null!; + public MenuCursorContainer() + { + InternalChild = fadeContainer = new Container { RelativeSizeAxes = Axes.Both }; + } + [BackgroundDependencyLoader] private void load(OsuConfigManager config, ScreenshotManager? screenshotManager, AudioManager audio) { @@ -46,6 +55,19 @@ namespace osu.Game.Graphics.Cursor tapSample = audio.Samples.Get(@"UI/cursor-tap"); } + [Resolved] + private OsuUserInputManager inputManager { get; set; } = null!; + + private IBindable mouseInputSource = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + mouseInputSource = inputManager.IsMouseInputSource.GetBoundCopy(); + mouseInputSource.BindValueChanged(m => updateInternalVisibilityState(m.NewValue), true); + } + protected override void Update() { base.Update(); @@ -146,6 +168,8 @@ namespace osu.Game.Graphics.Cursor activeCursor.ScaleTo(0.6f, 250, Easing.In); } + private void updateInternalVisibilityState(bool show) => fadeContainer.FadeTo(show ? 1 : 0, 120, Easing.OutQuint); + private void playTapSample(double baseFrequency = 1f) { const float random_range = 0.02f; From fcb9e2cc00894cf686a9fb73cbe27fd8af6dc766 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 11 Oct 2022 22:39:53 +0900 Subject: [PATCH 1620/2686] Refactor blueprint container drag code --- .../Compose/Components/BlueprintContainer.cs | 28 +++++++---- .../Components/ComposeBlueprintContainer.cs | 24 +--------- .../Components/EditorBlueprintContainer.cs | 5 ++ .../Timeline/TimelineBlueprintContainer.cs | 47 ++++++------------- 4 files changed, 38 insertions(+), 66 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index b15cecd506..43ad270c16 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -170,11 +170,15 @@ namespace osu.Game.Screens.Edit.Compose.Components finishSelectionMovement(); } + private MouseButtonEvent lastDragEvent; + protected override bool OnDragStart(DragStartEvent e) { if (e.Button == MouseButton.Right) return false; + lastDragEvent = e; + if (movementBlueprints != null) { isDraggingBlueprint = true; @@ -189,22 +193,14 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override void OnDrag(DragEvent e) { - if (e.Button == MouseButton.Right) - return; - - if (DragBox.State == Visibility.Visible) - { - DragBox.HandleDrag(e); - UpdateSelectionFromDragBox(); - } + lastDragEvent = e; moveCurrentSelection(e); } protected override void OnDragEnd(DragEndEvent e) { - if (e.Button == MouseButton.Right) - return; + lastDragEvent = null; if (isDraggingBlueprint) { @@ -215,6 +211,18 @@ namespace osu.Game.Screens.Edit.Compose.Components DragBox.Hide(); } + protected override void Update() + { + base.Update(); + + if (lastDragEvent != null && DragBox.State == Visibility.Visible) + { + lastDragEvent.Target = this; + DragBox.HandleDrag(lastDragEvent); + UpdateSelectionFromDragBox(); + } + } + /// /// Called whenever a drag operation completes, before any change transaction is committed. /// diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index c8870d46a8..ec07da43a0 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -12,7 +12,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Game.Audio; using osu.Game.Graphics.UserInterface; @@ -37,9 +36,6 @@ namespace osu.Game.Screens.Edit.Compose.Components protected new EditorSelectionHandler SelectionHandler => (EditorSelectionHandler)base.SelectionHandler; private PlacementBlueprint currentPlacement; - private InputManager inputManager; - - private DragEvent lastDragEvent; /// /// Positional input must be received outside the container's bounds, @@ -68,8 +64,6 @@ namespace osu.Game.Screens.Edit.Compose.Components { base.LoadComplete(); - inputManager = GetContainingInputManager(); - Beatmap.HitObjectAdded += hitObjectAdded; // updates to selected are handled for us by SelectionHandler. @@ -120,18 +114,6 @@ namespace osu.Game.Screens.Edit.Compose.Components return false; } - protected override void OnDrag(DragEvent e) - { - base.OnDrag(e); - lastDragEvent = e; - } - - protected override void OnDragEnd(DragEndEvent e) - { - base.OnDragEnd(e); - lastDragEvent = null; - } - /// /// Move the current selection spatially by the specified delta, in gamefield coordinates (ie. the same coordinates as the blueprints). /// @@ -234,7 +216,7 @@ namespace osu.Game.Screens.Edit.Compose.Components private void updatePlacementPosition() { - var snapResult = Composer.FindSnappedPositionAndTime(inputManager.CurrentState.Mouse.Position); + var snapResult = Composer.FindSnappedPositionAndTime(InputManager.CurrentState.Mouse.Position); // if no time was found from positional snapping, we should still quantize to the beat. snapResult.Time ??= Beatmap.SnapTime(EditorClock.CurrentTime, null); @@ -248,10 +230,6 @@ namespace osu.Game.Screens.Edit.Compose.Components { base.Update(); - // trigger every frame so drags continue to update selection while seeking time. - if (lastDragEvent != null) - OnDrag(lastDragEvent); - if (currentPlacement != null) { switch (currentPlacement.PlacementActive) diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs index 6adaeb1a83..7423b368b4 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs @@ -8,6 +8,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; @@ -27,6 +28,8 @@ namespace osu.Game.Screens.Edit.Compose.Components private HitObjectUsageEventBuffer usageEventBuffer; + protected InputManager InputManager { get; private set; } + protected EditorBlueprintContainer(HitObjectComposer composer) { Composer = composer; @@ -42,6 +45,8 @@ namespace osu.Game.Screens.Edit.Compose.Components { base.LoadComplete(); + InputManager = GetContainingInputManager(); + Beatmap.HitObjectAdded += AddBlueprintFor; Beatmap.HitObjectRemoved += RemoveBlueprintFor; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index 31990bfd35..b79c2675c8 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -29,10 +29,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline [Resolved(CanBeNull = true)] private Timeline timeline { get; set; } - private DragEvent lastDragEvent; private Bindable placement; private SelectionBlueprint placementBlueprint; + private bool hitObjectDragged; + /// /// Positional input must be received outside the container's bounds, /// in order to handle timeline blueprints which are stacked offscreen. @@ -98,24 +99,10 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline return base.OnDragStart(e); } - protected override void OnDrag(DragEvent e) - { - handleScrollViaDrag(e); - - base.OnDrag(e); - } - - protected override void OnDragEnd(DragEndEvent e) - { - base.OnDragEnd(e); - lastDragEvent = null; - } - protected override void Update() { - // trigger every frame so drags continue to update selection while playback is scrolling the timeline. - if (lastDragEvent != null) - OnDrag(lastDragEvent); + if (IsDragged || hitObjectDragged) + handleScrollViaDrag(); if (Composer != null && timeline != null) { @@ -170,7 +157,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { return new TimelineHitObjectBlueprint(item) { - OnDragHandled = handleScrollViaDrag, + OnDragHandled = e => hitObjectDragged = e != null, }; } @@ -197,24 +184,18 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } } - private void handleScrollViaDrag(DragEvent e) + private void handleScrollViaDrag() { - lastDragEvent = e; + if (timeline == null) return; - if (lastDragEvent == null) - return; + var timelineQuad = timeline.ScreenSpaceDrawQuad; + float mouseX = InputManager.CurrentState.Mouse.Position.X; - if (timeline != null) - { - var timelineQuad = timeline.ScreenSpaceDrawQuad; - float mouseX = e.ScreenSpaceMousePosition.X; - - // scroll if in a drag and dragging outside visible extents - if (mouseX > timelineQuad.TopRight.X) - timeline.ScrollBy((float)((mouseX - timelineQuad.TopRight.X) / 10 * Clock.ElapsedFrameTime)); - else if (mouseX < timelineQuad.TopLeft.X) - timeline.ScrollBy((float)((mouseX - timelineQuad.TopLeft.X) / 10 * Clock.ElapsedFrameTime)); - } + // scroll if in a drag and dragging outside visible extents + if (mouseX > timelineQuad.TopRight.X) + timeline.ScrollBy((float)((mouseX - timelineQuad.TopRight.X) / 10 * Clock.ElapsedFrameTime)); + else if (mouseX < timelineQuad.TopLeft.X) + timeline.ScrollBy((float)((mouseX - timelineQuad.TopLeft.X) / 10 * Clock.ElapsedFrameTime)); } private class SelectableAreaBackground : CompositeDrawable From 84fdd2e107dc3045a295eef5668bea8cd58e24cd Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 11 Oct 2022 17:16:57 +0300 Subject: [PATCH 1621/2686] Improve flashlight display on break periods --- .../Mods/CatchModFlashlight.cs | 6 +-- .../Mods/ManiaModFlashlight.cs | 6 +-- .../Mods/OsuModFlashlight.cs | 6 +-- .../Mods/TaikoModFlashlight.cs | 12 +++--- osu.Game/Rulesets/Mods/ModFlashlight.cs | 38 ++++++++----------- 5 files changed, 31 insertions(+), 37 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index ff957b9b73..a9e9e8fbd5 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Catch.Mods { this.playfield = playfield; - FlashlightSize = new Vector2(0, GetSizeFor(0)); + FlashlightSize = new Vector2(0, GetSize()); FlashlightSmoothness = 1.4f; } @@ -66,9 +66,9 @@ namespace osu.Game.Rulesets.Catch.Mods FlashlightPosition = playfield.CatcherArea.ToSpaceOfOtherDrawable(playfield.Catcher.DrawPosition, this); } - protected override void OnComboChange(ValueChangedEvent e) + protected override void UpdateFlashlightSize(float size) { - this.TransformTo(nameof(FlashlightSize), new Vector2(0, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION); + this.TransformTo(nameof(FlashlightSize), new Vector2(0, size), FLASHLIGHT_FADE_DURATION); } protected override string FragmentShader => "CircularFlashlight"; diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs index 6eaede2112..947915cdf9 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Mania.Mods public ManiaFlashlight(ManiaModFlashlight modFlashlight) : base(modFlashlight) { - FlashlightSize = new Vector2(DrawWidth, GetSizeFor(0)); + FlashlightSize = new Vector2(DrawWidth, GetSize()); AddLayout(flashlightProperties); } @@ -54,9 +54,9 @@ namespace osu.Game.Rulesets.Mania.Mods } } - protected override void OnComboChange(ValueChangedEvent e) + protected override void UpdateFlashlightSize(float size) { - this.TransformTo(nameof(FlashlightSize), new Vector2(DrawWidth, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION); + this.TransformTo(nameof(FlashlightSize), new Vector2(DrawWidth, size), FLASHLIGHT_FADE_DURATION); } protected override string FragmentShader => "RectangularFlashlight"; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index 66f367c79b..1a86901d9c 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Osu.Mods { followDelay = modFlashlight.FollowDelay.Value; - FlashlightSize = new Vector2(0, GetSizeFor(0)); + FlashlightSize = new Vector2(0, GetSize()); FlashlightSmoothness = 1.4f; } @@ -83,9 +83,9 @@ namespace osu.Game.Rulesets.Osu.Mods return base.OnMouseMove(e); } - protected override void OnComboChange(ValueChangedEvent e) + protected override void UpdateFlashlightSize(float size) { - this.TransformTo(nameof(FlashlightSize), new Vector2(0, GetSizeFor(e.NewValue)), FLASHLIGHT_FADE_DURATION); + this.TransformTo(nameof(FlashlightSize), new Vector2(0, size), FLASHLIGHT_FADE_DURATION); } protected override string FragmentShader => "CircularFlashlight"; diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index fca69e86cc..98f954ad29 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -47,21 +47,21 @@ namespace osu.Game.Rulesets.Taiko.Mods { this.taikoPlayfield = taikoPlayfield; - FlashlightSize = getSizeFor(0); + FlashlightSize = adjustSize(GetSize()); FlashlightSmoothness = 1.4f; AddLayout(flashlightProperties); } - private Vector2 getSizeFor(int combo) + private Vector2 adjustSize(float size) { // Preserve flashlight size through the playfield's aspect adjustment. - return new Vector2(0, GetSizeFor(combo) * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT); + return new Vector2(0, size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT); } - protected override void OnComboChange(ValueChangedEvent e) + protected override void UpdateFlashlightSize(float size) { - this.TransformTo(nameof(FlashlightSize), getSizeFor(e.NewValue), FLASHLIGHT_FADE_DURATION); + this.TransformTo(nameof(FlashlightSize), adjustSize(size), FLASHLIGHT_FADE_DURATION); } protected override string FragmentShader => "CircularFlashlight"; @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Taiko.Mods FlashlightPosition = ToLocalSpace(taikoPlayfield.HitTarget.ScreenSpaceDrawQuad.Centre); ClearTransforms(targetMember: nameof(FlashlightSize)); - FlashlightSize = getSizeFor(Combo.Value); + FlashlightSize = adjustSize(Combo.Value); flashlightProperties.Validate(); } diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 69937a0fba..d58a901154 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -2,7 +2,6 @@ // 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; using osu.Framework.Graphics; @@ -12,7 +11,6 @@ using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Beatmaps.Timing; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.OpenGL.Vertices; @@ -20,6 +18,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; using osu.Game.Scoring; +using osu.Game.Screens.Play; using osuTK; using osuTK.Graphics; @@ -84,8 +83,6 @@ namespace osu.Game.Rulesets.Mods flashlight.Combo.BindTo(Combo); drawableRuleset.KeyBindingInputManager.Add(flashlight); - - flashlight.Breaks = drawableRuleset.Beatmap.Breaks; } protected abstract Flashlight CreateFlashlight(); @@ -100,8 +97,6 @@ namespace osu.Game.Rulesets.Mods public override bool RemoveCompletedTransforms => false; - public List Breaks = new List(); - private readonly float defaultFlashlightSize; private readonly float sizeMultiplier; private readonly bool comboBasedSize; @@ -119,37 +114,36 @@ namespace osu.Game.Rulesets.Mods shader = shaderManager.Load("PositionAndColour", FragmentShader); } + [Resolved] + private Player? player { get; set; } + + private readonly IBindable isBreakTime = new BindableBool(); + protected override void LoadComplete() { base.LoadComplete(); - Combo.ValueChanged += OnComboChange; + Combo.ValueChanged += _ => UpdateFlashlightSize(GetSize()); - using (BeginAbsoluteSequence(0)) + if (player != null) { - foreach (var breakPeriod in Breaks) - { - if (!breakPeriod.HasEffect) - continue; - - if (breakPeriod.Duration < FLASHLIGHT_FADE_DURATION * 2) continue; - - this.Delay(breakPeriod.StartTime + FLASHLIGHT_FADE_DURATION).FadeOutFromOne(FLASHLIGHT_FADE_DURATION); - this.Delay(breakPeriod.EndTime - FLASHLIGHT_FADE_DURATION).FadeInFromZero(FLASHLIGHT_FADE_DURATION); - } + isBreakTime.BindTo(player.IsBreakTime); + isBreakTime.BindValueChanged(_ => UpdateFlashlightSize(GetSize()), true); } } - protected abstract void OnComboChange(ValueChangedEvent e); + protected abstract void UpdateFlashlightSize(float size); protected abstract string FragmentShader { get; } - protected float GetSizeFor(int combo) + protected float GetSize() { float size = defaultFlashlightSize * sizeMultiplier; - if (comboBasedSize) - size *= GetComboScaleFor(combo); + if (isBreakTime.Value) + size *= 2.5f; + else if (comboBasedSize) + size *= GetComboScaleFor(Combo.Value); return size; } From 0a0d6993084ce9f2a9010eea9a00a45c2f03df31 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Tue, 11 Oct 2022 22:43:47 +0200 Subject: [PATCH 1622/2686] Convert slider velocity to scroll speed in taiko beatmap conversion --- .../Beatmaps/TaikoBeatmapConverter.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 524565a863..c1e1052569 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -57,6 +57,29 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps Beatmap converted = base.ConvertBeatmap(original, cancellationToken); + if (original.BeatmapInfo.Ruleset.OnlineID == 0) + { + // Post processing step to transform standard slider velocity changes into scroll speed changes + double lastScrollSpeed = 1; + + foreach (HitObject hitObject in original.HitObjects) + { + double nextScrollSpeed = hitObject.DifficultyControlPoint.SliderVelocity; + + if (!Precision.AlmostEquals(lastScrollSpeed, nextScrollSpeed)) + { + EffectControlPoint currentControlPoint = converted.ControlPointInfo.EffectPointAt(hitObject.StartTime); + + if (Precision.AlmostEquals(currentControlPoint.Time, hitObject.StartTime)) + currentControlPoint.ScrollSpeed = nextScrollSpeed; + else + converted.ControlPointInfo.Add(hitObject.StartTime, new EffectControlPoint { ScrollSpeed = nextScrollSpeed }); + + lastScrollSpeed = nextScrollSpeed; + } + } + } + if (original.BeatmapInfo.Ruleset.OnlineID == 3) { // Post processing step to transform mania hit objects with the same start time into strong hits From 721bfb5369731496147f4fbe7a278b0a789e8dad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 14:46:35 +0900 Subject: [PATCH 1623/2686] Rename parameter to read better --- osu.Game/Beatmaps/IWorkingBeatmap.cs | 2 +- osu.Game/Beatmaps/WorkingBeatmap.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/IWorkingBeatmap.cs b/osu.Game/Beatmaps/IWorkingBeatmap.cs index cf72a611e5..0f0e72b0ac 100644 --- a/osu.Game/Beatmaps/IWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/IWorkingBeatmap.cs @@ -134,6 +134,6 @@ namespace osu.Game.Beatmaps /// /// Reads the correct track restart point from beatmap metadata and sets looping to enabled. /// - void PrepareTrackForPreview(bool looping, int priorToPreview = 0); + void PrepareTrackForPreview(bool looping, double offsetFromPreviewPoint = 0); } } diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 7eb7852897..d788ae5862 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -110,10 +110,10 @@ namespace osu.Game.Beatmaps public Track LoadTrack() => track = GetBeatmapTrack() ?? GetVirtualTrack(1000); - public void PrepareTrackForPreview(bool looping, int priorToPreview = 0) + public void PrepareTrackForPreview(bool looping, double offsetFromPreviewPoint = 0) { Track.Looping = looping; - Track.RestartPoint = Metadata.PreviewTime - priorToPreview; + Track.RestartPoint = Metadata.PreviewTime - offsetFromPreviewPoint; if (Track.RestartPoint == -1) { From db148d145b4e6d8e5f3484033fbadd867d75fb5b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 14:47:15 +0900 Subject: [PATCH 1624/2686] Fix incorrect offset logic for beatmaps without a preview point specified --- osu.Game/Beatmaps/WorkingBeatmap.cs | 4 +++- osu.Game/Screens/Menu/IntroScreen.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index d788ae5862..393c4ba892 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -113,7 +113,7 @@ namespace osu.Game.Beatmaps public void PrepareTrackForPreview(bool looping, double offsetFromPreviewPoint = 0) { Track.Looping = looping; - Track.RestartPoint = Metadata.PreviewTime - offsetFromPreviewPoint; + Track.RestartPoint = Metadata.PreviewTime; if (Track.RestartPoint == -1) { @@ -125,6 +125,8 @@ namespace osu.Game.Beatmaps Track.RestartPoint = 0.4f * Track.Length; } + + Track.RestartPoint += offsetFromPreviewPoint; } /// diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 435c02de96..dcead4a3a8 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -278,7 +278,7 @@ namespace osu.Game.Screens.Menu if (!UsingThemedIntro) { - initialBeatmap?.PrepareTrackForPreview(false, 2600); + initialBeatmap?.PrepareTrackForPreview(false, -2600); drawableTrack.VolumeTo(0); drawableTrack.Restart(); From d6998c810c064ed0b26d3718ac62ffef0d709e77 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 14:50:04 +0900 Subject: [PATCH 1625/2686] Fix incorrect delay for non-theme music on "welcome" intro --- osu.Game/Screens/Menu/IntroWelcome.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroWelcome.cs b/osu.Game/Screens/Menu/IntroWelcome.cs index 9e56a3a0b7..5ae2158172 100644 --- a/osu.Game/Screens/Menu/IntroWelcome.cs +++ b/osu.Game/Screens/Menu/IntroWelcome.cs @@ -78,13 +78,17 @@ namespace osu.Game.Screens.Menu if (reverbChannel != null) intro.LogoVisualisation.AddAmplitudeSource(reverbChannel); - Scheduler.AddDelayed(() => - { + if (!UsingThemedIntro) StartTrack(); - // this classic intro loops forever. + Scheduler.AddDelayed(() => + { if (UsingThemedIntro) + { + StartTrack(); + // this classic intro loops forever. Track.Looping = true; + } const float fade_in_time = 200; From d2d589a15695edab3b1f862b15ef4d27f63808d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 15:11:52 +0900 Subject: [PATCH 1626/2686] Expose HUD state via `Player` --- osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs | 3 ++- osu.Game/Screens/Play/Player.cs | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs index a923aca2c8..2dc9f5f5cb 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs @@ -11,6 +11,7 @@ using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play; using osu.Game.Skinning; using osuTK.Graphics; @@ -41,7 +42,7 @@ namespace osu.Game.Rulesets.Catch.UI } [BackgroundDependencyLoader(true)] - private void load(DrawableRuleset drawableRuleset) + private void load(DrawableRuleset drawableRuleset, HUDOverlay hud) { hudVisibilityMode = config.GetBindable(OsuSetting.HUDVisibilityMode); diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 7721d5b912..68b623b781 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -94,6 +94,11 @@ namespace osu.Game.Screens.Play public int RestartCount; + /// + /// Whether the is currently visible. + /// + public IBindable ShowingOverlayComponents = new Bindable(); + [Resolved] private ScoreManager scoreManager { get; set; } @@ -1015,6 +1020,8 @@ namespace osu.Game.Screens.Play }); HUDOverlay.IsPlaying.BindTo(localUserPlaying); + ShowingOverlayComponents.BindTo(HUDOverlay.ShowHud); + DimmableStoryboard.IsBreakTime.BindTo(breakTracker.IsBreakTime); DimmableStoryboard.StoryboardReplacesBackground.BindTo(storyboardReplacesBackground); From 652bc4ac61568d9a596bee7944248942416aa590 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 15:14:33 +0900 Subject: [PATCH 1627/2686] Update `CatchComboDisplay` implementation to use newly exposed bindable --- .../UI/CatchComboDisplay.cs | 64 +++---------------- 1 file changed, 10 insertions(+), 54 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs index 2dc9f5f5cb..86d4e73144 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs @@ -6,11 +6,9 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Game.Configuration; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osu.Game.Skinning; using osuTK.Graphics; @@ -27,14 +25,7 @@ namespace osu.Game.Rulesets.Catch.UI [CanBeNull] public ICatchComboCounter ComboCounter => Drawable as ICatchComboCounter; - private Bindable hudVisibilityMode = null!; - - private readonly BindableBool replayLoaded = new BindableBool(); - - private readonly BindableBool showCombo = new BindableBool(); - - [Resolved] - private OsuConfigManager config { get; set; } + private readonly IBindable showCombo = new BindableBool(true); public CatchComboDisplay() : base(new CatchSkinComponent(CatchSkinComponents.CatchComboCounter), _ => Empty()) @@ -42,51 +33,18 @@ namespace osu.Game.Rulesets.Catch.UI } [BackgroundDependencyLoader(true)] - private void load(DrawableRuleset drawableRuleset, HUDOverlay hud) + private void load(Player player) { - hudVisibilityMode = config.GetBindable(OsuSetting.HUDVisibilityMode); - - hudVisibilityMode.BindValueChanged(s => + if (player != null) { - updateVisibilityState(); - }); - - if (drawableRuleset != null) - replayLoaded.BindTo(drawableRuleset.HasReplayLoaded); - - replayLoaded.BindValueChanged(s => - { - updateVisibilityState(); - }); - - showCombo.BindValueChanged(s => - { - if (ComboCounter == null) return; - - if (!s.NewValue) + showCombo.BindTo(player.ShowingOverlayComponents); + showCombo.BindValueChanged(s => { - ComboCounter.Hide(); - } - }); - - updateVisibilityState(); - - void updateVisibilityState() - { - switch (hudVisibilityMode.Value) - { - case HUDVisibilityMode.Never: - showCombo.Value = false; - break; - - case HUDVisibilityMode.HideDuringGameplay: - showCombo.Value = replayLoaded.Value; - break; - - case HUDVisibilityMode.Always: - showCombo.Value = true; - break; - } + if (!s.NewValue) + ComboCounter?.Hide(); + else + ComboCounter?.Show(); + }, true); } } @@ -120,8 +78,6 @@ namespace osu.Game.Rulesets.Catch.UI private void updateCombo(int newCombo, Color4? hitObjectColour) { - if (!showCombo.Value) return; - currentCombo = newCombo; ComboCounter?.UpdateCombo(newCombo, hitObjectColour); } From 2e3e4ac5be0f4e14b2b740a42de9013bcd4a7e4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 15:14:54 +0900 Subject: [PATCH 1628/2686] Update `CatchComboDisplay` to use NRT --- osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs index 86d4e73144..b2b77b8f11 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Rulesets.Catch.Objects.Drawables; @@ -22,8 +19,7 @@ namespace osu.Game.Rulesets.Catch.UI { private int currentCombo; - [CanBeNull] - public ICatchComboCounter ComboCounter => Drawable as ICatchComboCounter; + public ICatchComboCounter? ComboCounter => Drawable as ICatchComboCounter; private readonly IBindable showCombo = new BindableBool(true); @@ -33,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.UI } [BackgroundDependencyLoader(true)] - private void load(Player player) + private void load(Player? player) { if (player != null) { From ea3d08d5a0160f495e98da0ffdd96b76aaa918fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 15:22:46 +0900 Subject: [PATCH 1629/2686] Fix collision of external hide with internal logic in `LegacyCatchComboCounter` --- osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs index b2b77b8f11..a804caa542 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; @@ -34,13 +35,7 @@ namespace osu.Game.Rulesets.Catch.UI if (player != null) { showCombo.BindTo(player.ShowingOverlayComponents); - showCombo.BindValueChanged(s => - { - if (!s.NewValue) - ComboCounter?.Hide(); - else - ComboCounter?.Show(); - }, true); + showCombo.BindValueChanged(s => this.FadeTo(s.NewValue ? 1 : 0, HUDOverlay.FADE_DURATION, HUDOverlay.FADE_EASING), true); } } From f3e85d2302775bf41401d85a1b1292bcfba738c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 15:25:16 +0900 Subject: [PATCH 1630/2686] Fix initial state being wrong due to `BindValueChanged` call in BDL load --- osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs index a804caa542..a5b7d8d0af 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs @@ -29,9 +29,13 @@ namespace osu.Game.Rulesets.Catch.UI { } - [BackgroundDependencyLoader(true)] - private void load(Player? player) + [Resolved(canBeNull: true)] + private Player? player { get; set; } + + protected override void LoadComplete() { + base.LoadComplete(); + if (player != null) { showCombo.BindTo(player.ShowingOverlayComponents); From 9d0ae3f0ca956bead9d33821f5b8917af18d1bf5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 15:32:24 +0900 Subject: [PATCH 1631/2686] Update test scene to work with new data source --- .../TestSceneComboCounter.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs index f39af76a2d..f3161f32be 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs @@ -4,14 +4,16 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Utils; -using osu.Game.Configuration; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; +using osu.Game.Screens.Play; +using osu.Game.Tests.Visual; using osuTK; using osuTK.Graphics; @@ -19,16 +21,19 @@ namespace osu.Game.Rulesets.Catch.Tests { public class TestSceneComboCounter : CatchSkinnableTestScene { - private OsuConfigManager localConfig = null!; - private ScoreProcessor scoreProcessor = null!; private Color4 judgedObjectColour = Color4.White; + private readonly Bindable showHud = new Bindable(true); + [BackgroundDependencyLoader] private void load() { - Dependencies.Cache(localConfig = new OsuConfigManager(LocalStorage)); + Dependencies.CacheAs(new TestPlayer + { + ShowingOverlayComponents = { BindTarget = showHud }, + }); } [SetUp] @@ -36,7 +41,7 @@ namespace osu.Game.Rulesets.Catch.Tests { scoreProcessor = new ScoreProcessor(new CatchRuleset()); - localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always); + showHud.Value = true; SetContents(_ => new CatchComboDisplay { @@ -62,10 +67,10 @@ namespace osu.Game.Rulesets.Catch.Tests ); }); - AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never)); + AddStep("set hud to never show", () => showHud.Value = false); AddRepeatStep("perform hit", () => performJudgement(HitResult.Great), 5); - AddStep("set hud to show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always)); + AddStep("set hud to show", () => showHud.Value = true); AddRepeatStep("perform hit", () => performJudgement(HitResult.Great), 5); } From e43c8e84b022c31b18d11b08611dc371985b99f6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 15:43:05 +0900 Subject: [PATCH 1632/2686] Use `Show` instead of `Alpha=1` --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 105618c728..193d15064a 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -362,7 +362,7 @@ namespace osu.Game.Overlays.Comments /// private void makeDeleted() { - deletedLabel.Alpha = 1f; + deletedLabel.Show(); content.FadeColour(OsuColour.Gray(0.5f)); votePill.Hide(); actionsContainer.Expire(); From 00d83980566a2d044255fdbd3da806dd7a74bacc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 15:47:28 +0900 Subject: [PATCH 1633/2686] Update test scene to allow seeing loading spinner --- .../Visual/Online/TestSceneCommentActions.cs | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 11210db8a9..af6f8ba97c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -78,11 +80,12 @@ namespace osu.Game.Tests.Visual.Online }); } + private ManualResetEventSlim deletionPerformed = new ManualResetEventSlim(); + [Test] public void TestDeletion() { DrawableComment? ourComment = null; - bool delete = false; addTestComments(); AddUntilStep("Comment exists", () => @@ -102,6 +105,8 @@ namespace osu.Game.Tests.Visual.Online }); AddStep("Setup request handling", () => { + deletionPerformed.Reset(); + dummyAPI.HandleRequest = request => { if (!(request is CommentDeleteRequest req)) @@ -130,18 +135,23 @@ namespace osu.Game.Tests.Visual.Online IncludedComments = new List(), PinnedComments = new List(), }; - delete = true; - req.TriggerSuccess(cb); + + Task.Run(() => + { + deletionPerformed.Wait(10000); + req.TriggerSuccess(cb); + }); + return true; }; }); AddStep("Confirm dialog", () => InputManager.Key(Key.Number1)); - AddUntilStep("Deletion requested", () => delete); + AddAssert("Loading spinner shown", () => commentsContainer.ChildrenOfType().Any(d => d.IsPresent)); - AddUntilStep("Comment is deleted locally", () => - { - return this.ChildrenOfType().Single(x => x.Comment.Id == 1).WasDeleted; - }); + + AddStep("Complete request", () => deletionPerformed.Set()); + + AddUntilStep("Comment is deleted locally", () => this.ChildrenOfType().Single(x => x.Comment.Id == 1).WasDeleted); } [Test] From b72c8970ebf9a2f790968822c4462fb1c7aeb1f8 Mon Sep 17 00:00:00 2001 From: Dario Headley Date: Wed, 12 Oct 2022 09:39:57 +0200 Subject: [PATCH 1634/2686] Max Combo Counter added --- .../TestSceneSkinnableComboCounter.cs | 1 + .../Play/HUD/ComboCounters/ComboCounter.cs | 26 ++++++ .../DefaultComboCounter.cs | 25 ++---- .../HUD/ComboCounters/LongestComboCounter.cs | 85 +++++++++++++++++++ osu.Game/Skinning/ArgonSkin.cs | 1 + osu.Game/Skinning/TrianglesSkin.cs | 1 + 6 files changed, 119 insertions(+), 20 deletions(-) create mode 100644 osu.Game/Screens/Play/HUD/ComboCounters/ComboCounter.cs rename osu.Game/Screens/Play/HUD/{ => ComboCounters}/DefaultComboCounter.cs (61%) create mode 100644 osu.Game/Screens/Play/HUD/ComboCounters/LongestComboCounter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs index ef56f456ea..d234d6b8b7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs @@ -10,6 +10,7 @@ using osu.Framework.Testing; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.HUD.ComboCounters; using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay diff --git a/osu.Game/Screens/Play/HUD/ComboCounters/ComboCounter.cs b/osu.Game/Screens/Play/HUD/ComboCounters/ComboCounter.cs new file mode 100644 index 0000000000..9bd08f3930 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ComboCounters/ComboCounter.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System; +using osu.Game.Graphics.UserInterface; +using osu.Game.Skinning; + +namespace osu.Game.Screens.Play.HUD.ComboCounters +{ + public abstract class ComboCounter : RollingCounter, ISkinnableDrawable + { + public bool UsesFixedAnchor { get; set; } + + protected ComboCounter() + { + Current.Value = DisplayedCount = 0; + } + + protected override double GetProportionalDuration(int currentValue, int newValue) + { + return Math.Abs(currentValue - newValue) * RollingDuration * 100.0f; + } + } +} diff --git a/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs b/osu.Game/Screens/Play/HUD/ComboCounters/DefaultComboCounter.cs similarity index 61% rename from osu.Game/Screens/Play/HUD/DefaultComboCounter.cs rename to osu.Game/Screens/Play/HUD/ComboCounters/DefaultComboCounter.cs index 1f14811169..a612f042f5 100644 --- a/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/ComboCounters/DefaultComboCounter.cs @@ -3,27 +3,17 @@ #nullable disable -using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Scoring; -using osu.Game.Skinning; -namespace osu.Game.Screens.Play.HUD +namespace osu.Game.Screens.Play.HUD.ComboCounters { - public class DefaultComboCounter : RollingCounter, ISkinnableDrawable + public class DefaultComboCounter : ComboCounter { - public bool UsesFixedAnchor { get; set; } - - public DefaultComboCounter() - { - Current.Value = DisplayedCount = 0; - } - [BackgroundDependencyLoader] private void load(OsuColour colours, ScoreProcessor scoreProcessor) { @@ -31,17 +21,12 @@ namespace osu.Game.Screens.Play.HUD Current.BindTo(scoreProcessor.Combo); } + protected override OsuSpriteText CreateSpriteText() + => base.CreateSpriteText().With(s => s.Font = s.Font.With(size: 20f)); + protected override LocalisableString FormatCount(int count) { return $@"{count}x"; } - - protected override double GetProportionalDuration(int currentValue, int newValue) - { - return Math.Abs(currentValue - newValue) * RollingDuration * 100.0f; - } - - protected override OsuSpriteText CreateSpriteText() - => base.CreateSpriteText().With(s => s.Font = s.Font.With(size: 20f)); } } diff --git a/osu.Game/Screens/Play/HUD/ComboCounters/LongestComboCounter.cs b/osu.Game/Screens/Play/HUD/ComboCounters/LongestComboCounter.cs new file mode 100644 index 0000000000..b6be42764a --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ComboCounters/LongestComboCounter.cs @@ -0,0 +1,85 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Scoring; +using osuTK; + +namespace osu.Game.Screens.Play.HUD.ComboCounters +{ + public class LongestComboCounter : ComboCounter + { + [BackgroundDependencyLoader] + private void load(OsuColour colours, ScoreProcessor scoreProcessor) + { + Colour = colours.YellowLighter; + Current.BindTo(scoreProcessor.HighestCombo); + } + + protected override IHasText CreateText() => new TextComponent(); + + private class TextComponent : CompositeDrawable, IHasText + { + public LocalisableString Text + { + get => text.Text; + set => text.Text = $"{value}x"; + } + + private readonly OsuSpriteText text; + + public TextComponent() + { + AutoSizeAxes = Axes.Both; + + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(2), + Children = new Drawable[] + { + text = new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = OsuFont.Numeric.With(size: 20) + }, + new FillFlowContainer + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Direction = FillDirection.Vertical, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + Font = OsuFont.Numeric.With(size: 8), + Text = @"longest", + }, + new OsuSpriteText + { + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + Font = OsuFont.Numeric.With(size: 8), + Text = @"combo", + Padding = new MarginPadding { Bottom = 3f } + } + } + } + } + }; + } + } + } +} diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 010e2175e1..006f6b4e46 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -15,6 +15,7 @@ using osu.Game.Beatmaps.Formats; using osu.Game.Extensions; using osu.Game.IO; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.HUD.ComboCounters; using osu.Game.Screens.Play.HUD.HitErrorMeters; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 2c70963524..84b39f2768 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -16,6 +16,7 @@ using osu.Game.Beatmaps.Formats; using osu.Game.Extensions; using osu.Game.IO; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.HUD.ComboCounters; using osu.Game.Screens.Play.HUD.HitErrorMeters; using osuTK; using osuTK.Graphics; From 1c93551590a6e02bd231b858079570cb7a0c96f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 17:07:13 +0900 Subject: [PATCH 1635/2686] Remove completely incorrect check before applying ruleset transformer --- osu.Game/Skinning/RulesetSkinProvidingContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs index 6ad5d64e4b..7267ebd92d 100644 --- a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs +++ b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs @@ -41,7 +41,7 @@ namespace osu.Game.Skinning Ruleset = ruleset; Beatmap = beatmap; - InternalChild = new BeatmapSkinProvidingContainer(beatmapSkin is LegacySkin ? GetRulesetTransformedSkin(beatmapSkin) : beatmapSkin) + InternalChild = new BeatmapSkinProvidingContainer(GetRulesetTransformedSkin(beatmapSkin)) { Child = Content = new Container { From fd20515a6d21e501133b32a8170fd7d441abdb89 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 17:28:06 +0900 Subject: [PATCH 1636/2686] Don't throw if `LegacySkin` doesn't have a transformer encapsulating it This allows for more flexibility in lookups. --- osu.Game/Skinning/LegacySkin.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 646746a0f3..eaca0de11a 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -389,18 +389,17 @@ namespace osu.Game.Skinning if (particle != null) return new LegacyJudgementPieceNew(resultComponent.Component, createDrawable, particle); - else - return new LegacyJudgementPieceOld(resultComponent.Component, createDrawable); + + return new LegacyJudgementPieceOld(resultComponent.Component, createDrawable); } return null; case SkinnableSprite.SpriteComponent sprite: return this.GetAnimation(sprite.LookupName, false, false); - - default: - throw new UnsupportedSkinComponentException(component); } + + return null; } private Texture? getParticleTexture(HitResult result) From 8bf4ca4b53c28bf8f666877c69fcaa37bad0c2a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 17:47:20 +0900 Subject: [PATCH 1637/2686] Add legacy skin fallback when beatmap skin is providing resources --- .../Skinning/Legacy/CatchLegacySkinTransformer.cs | 6 +++++- .../Skinning/Legacy/ManiaLegacySkinTransformer.cs | 2 ++ .../Skinning/Legacy/OsuLegacySkinTransformer.cs | 2 ++ .../Skinning/Legacy/TaikoLegacySkinTransformer.cs | 9 +++++++-- .../Skinning/BeatmapSkinProvidingContainer.cs | 15 ++++++++++++++- osu.Game/Skinning/LegacySkinTransformer.cs | 5 +++++ 6 files changed, 35 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index c06d9f520f..a73b34c9b6 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -13,6 +13,10 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { public class CatchLegacySkinTransformer : LegacySkinTransformer { + public override bool IsProvidingLegacyResources => base.IsProvidingLegacyResources || hasPear; + + private bool hasPear => GetTexture("fruit-pear") != null; + /// /// For simplicity, let's use legacy combo font texture existence as a way to identify legacy skins from default. /// @@ -49,7 +53,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy switch (catchSkinComponent.Component) { case CatchSkinComponents.Fruit: - if (GetTexture("fruit-pear") != null) + if (hasPear) return new LegacyFruitPiece(); return null; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 1d39721a2b..a07dbea368 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -19,6 +19,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class ManiaLegacySkinTransformer : LegacySkinTransformer { + public override bool IsProvidingLegacyResources => base.IsProvidingLegacyResources || hasKeyTexture.Value; + /// /// Mapping of to their corresponding /// value. diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index b778bc21d1..856ccb5044 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -13,6 +13,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class OsuLegacySkinTransformer : LegacySkinTransformer { + public override bool IsProvidingLegacyResources => base.IsProvidingLegacyResources || hasHitCircle.Value; + private readonly Lazy hasHitCircle; /// diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 992316ca53..020cdab4dc 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -14,8 +14,13 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class TaikoLegacySkinTransformer : LegacySkinTransformer { + public override bool IsProvidingLegacyResources => base.IsProvidingLegacyResources || hasHitCircle || hasBarLeft; + private readonly Lazy hasExplosion; + private bool hasHitCircle => GetTexture("taikohitcircle") != null; + private bool hasBarLeft => GetTexture("taiko-bar-left") != null; + public TaikoLegacySkinTransformer(ISkin skin) : base(skin) { @@ -42,14 +47,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy return null; case TaikoSkinComponents.InputDrum: - if (GetTexture("taiko-bar-left") != null) + if (hasBarLeft) return new LegacyInputDrum(); return null; case TaikoSkinComponents.CentreHit: case TaikoSkinComponents.RimHit: - if (GetTexture("taikohitcircle") != null) + if (hasHitCircle) return new LegacyHit(taikoComponent.Component); return null; diff --git a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs index abc7b61036..f0caef9fa1 100644 --- a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs +++ b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs @@ -67,9 +67,12 @@ namespace osu.Game.Skinning return sampleInfo is StoryboardSampleInfo || beatmapHitsounds.Value; } + private readonly ISkin skin; + public BeatmapSkinProvidingContainer(ISkin skin) : base(skin) { + this.skin = skin; } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -84,11 +87,21 @@ namespace osu.Game.Skinning } [BackgroundDependencyLoader] - private void load() + private void load(SkinManager skins) { beatmapSkins.BindValueChanged(_ => TriggerSourceChanged()); beatmapColours.BindValueChanged(_ => TriggerSourceChanged()); beatmapHitsounds.BindValueChanged(_ => TriggerSourceChanged()); + + // If the beatmap skin looks to have skinnable resources, add the default classic skin as a fallback opportunity. + if (skin is LegacySkinTransformer legacySkin && legacySkin.IsProvidingLegacyResources) + { + SetSources(new[] + { + skin, + skins.DefaultClassicSkin + }); + } } } } diff --git a/osu.Game/Skinning/LegacySkinTransformer.cs b/osu.Game/Skinning/LegacySkinTransformer.cs index 2de1564a5c..367e5bae01 100644 --- a/osu.Game/Skinning/LegacySkinTransformer.cs +++ b/osu.Game/Skinning/LegacySkinTransformer.cs @@ -13,6 +13,11 @@ namespace osu.Game.Skinning /// public abstract class LegacySkinTransformer : SkinTransformer { + /// + /// Whether the skin being transformed is able to provide legacy resources for the ruleset. + /// + public virtual bool IsProvidingLegacyResources => this.HasFont(LegacyFont.Combo); + protected LegacySkinTransformer(ISkin skin) : base(skin) { From e2c80f09dacc27e16a83f2cf5b0dbed82b75ae26 Mon Sep 17 00:00:00 2001 From: "D.Headley" Date: Wed, 12 Oct 2022 11:05:22 +0200 Subject: [PATCH 1638/2686] Remove unnecesary directive --- osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs index d234d6b8b7..57d52243ba 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD.ComboCounters; using osu.Game.Skinning; From df0501235d21dee2e24c9801b099bf27a4e97725 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Wed, 12 Oct 2022 11:14:01 +0200 Subject: [PATCH 1639/2686] Introduce `BpmMultiplierMania`, remove after the fact clamps --- .../Legacy/DistanceObjectPatternGenerator.cs | 2 +- .../Beatmaps/TaikoBeatmapConverter.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs index 89b52a3c75..2bdd0e16ad 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - beatLength = timingPoint.BeatLength * Math.Min(legacyDifficultyPoint.BpmMultiplier, 10); + beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 33f1535437..524565a863 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - beatLength = timingPoint.BeatLength * Math.Min(legacyDifficultyPoint.BpmMultiplier, 10); + beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 9c066ada08..03819af149 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -168,6 +168,13 @@ namespace osu.Game.Beatmaps.Formats /// public double BpmMultiplier { get; private set; } + /// + /// Legacy BPM multiplier that introduces floating-point errors for rulesets that depend on it. + /// This is to be used for taiko and mania specific beatmaps. + /// DO NOT USE THIS UNLESS 100% SURE. + /// + public double BpmMultiplierMania { get; private set; } + /// /// Whether or not slider ticks should be generated at this control point. /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). @@ -178,7 +185,8 @@ namespace osu.Game.Beatmaps.Formats : this() { // Note: In stable, the division occurs on floats, but with compiler optimisations turned on actually seems to occur on doubles via some .NET black magic (possibly inlining?). - BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 1000) / 100.0 : 1; + BpmMultiplierMania = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; GenerateTicks = !double.IsNaN(beatLength); } @@ -196,6 +204,7 @@ namespace osu.Game.Beatmaps.Formats base.CopyFrom(other); BpmMultiplier = ((LegacyDifficultyControlPoint)other).BpmMultiplier; + BpmMultiplierMania = ((LegacyDifficultyControlPoint)other).BpmMultiplierMania; GenerateTicks = ((LegacyDifficultyControlPoint)other).GenerateTicks; } @@ -206,10 +215,11 @@ namespace osu.Game.Beatmaps.Formats public bool Equals(LegacyDifficultyControlPoint? other) => base.Equals(other) && BpmMultiplier == other.BpmMultiplier + && BpmMultiplierMania == other.BpmMultiplierMania && GenerateTicks == other.GenerateTicks; // ReSharper disable twice NonReadonlyMemberInGetHashCode - public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier, GenerateTicks); + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier, BpmMultiplierMania, GenerateTicks); } internal class LegacySampleControlPoint : SampleControlPoint, IEquatable From 2579ed46ce552c3c610f5bacb8359e0f764616df Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Wed, 12 Oct 2022 11:22:54 +0200 Subject: [PATCH 1640/2686] Select multiplier per mode --- .../Beatmaps/TaikoBeatmapConverter.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 524565a863..613c41a59a 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -162,7 +162,14 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; + { + double bpmMultiplier; + if (beatmap.BeatmapInfo.OnlineID == 1 || beatmap.BeatmapInfo.OnlineID == 3) + bpmMultiplier = legacyDifficultyPoint.BpmMultiplierMania; + else + bpmMultiplier = legacyDifficultyPoint.BpmMultiplier; + beatLength = timingPoint.BeatLength * bpmMultiplier; + } else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; From 19f3810020f53ebf9ac206fbb562f04a14dcb8ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 18:50:40 +0900 Subject: [PATCH 1641/2686] Revert namespace change Let's not --- .../Visual/Gameplay/TestSceneSkinnableComboCounter.cs | 2 +- osu.Game/Screens/Play/HUD/{ComboCounters => }/ComboCounter.cs | 4 +--- .../Play/HUD/{ComboCounters => }/DefaultComboCounter.cs | 4 +--- .../Play/HUD/{ComboCounters => }/LongestComboCounter.cs | 4 +--- osu.Game/Skinning/ArgonSkin.cs | 1 - osu.Game/Skinning/TrianglesSkin.cs | 1 - 6 files changed, 4 insertions(+), 12 deletions(-) rename osu.Game/Screens/Play/HUD/{ComboCounters => }/ComboCounter.cs (90%) rename osu.Game/Screens/Play/HUD/{ComboCounters => }/DefaultComboCounter.cs (92%) rename osu.Game/Screens/Play/HUD/{ComboCounters => }/LongestComboCounter.cs (97%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs index 57d52243ba..ef56f456ea 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.Play.HUD.ComboCounters; +using osu.Game.Screens.Play.HUD; using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay diff --git a/osu.Game/Screens/Play/HUD/ComboCounters/ComboCounter.cs b/osu.Game/Screens/Play/HUD/ComboCounter.cs similarity index 90% rename from osu.Game/Screens/Play/HUD/ComboCounters/ComboCounter.cs rename to osu.Game/Screens/Play/HUD/ComboCounter.cs index 9bd08f3930..4179d41646 100644 --- a/osu.Game/Screens/Play/HUD/ComboCounters/ComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/ComboCounter.cs @@ -1,13 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Game.Graphics.UserInterface; using osu.Game.Skinning; -namespace osu.Game.Screens.Play.HUD.ComboCounters +namespace osu.Game.Screens.Play.HUD { public abstract class ComboCounter : RollingCounter, ISkinnableDrawable { diff --git a/osu.Game/Screens/Play/HUD/ComboCounters/DefaultComboCounter.cs b/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs similarity index 92% rename from osu.Game/Screens/Play/HUD/ComboCounters/DefaultComboCounter.cs rename to osu.Game/Screens/Play/HUD/DefaultComboCounter.cs index a612f042f5..0c9c363280 100644 --- a/osu.Game/Screens/Play/HUD/ComboCounters/DefaultComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultComboCounter.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; @@ -10,7 +8,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Scoring; -namespace osu.Game.Screens.Play.HUD.ComboCounters +namespace osu.Game.Screens.Play.HUD { public class DefaultComboCounter : ComboCounter { diff --git a/osu.Game/Screens/Play/HUD/ComboCounters/LongestComboCounter.cs b/osu.Game/Screens/Play/HUD/LongestComboCounter.cs similarity index 97% rename from osu.Game/Screens/Play/HUD/ComboCounters/LongestComboCounter.cs rename to osu.Game/Screens/Play/HUD/LongestComboCounter.cs index b6be42764a..0e7af69af2 100644 --- a/osu.Game/Screens/Play/HUD/ComboCounters/LongestComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/LongestComboCounter.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -13,7 +11,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Scoring; using osuTK; -namespace osu.Game.Screens.Play.HUD.ComboCounters +namespace osu.Game.Screens.Play.HUD { public class LongestComboCounter : ComboCounter { diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 006f6b4e46..010e2175e1 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -15,7 +15,6 @@ using osu.Game.Beatmaps.Formats; using osu.Game.Extensions; using osu.Game.IO; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Play.HUD.ComboCounters; using osu.Game.Screens.Play.HUD.HitErrorMeters; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 84b39f2768..2c70963524 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -16,7 +16,6 @@ using osu.Game.Beatmaps.Formats; using osu.Game.Extensions; using osu.Game.IO; using osu.Game.Screens.Play.HUD; -using osu.Game.Screens.Play.HUD.ComboCounters; using osu.Game.Screens.Play.HUD.HitErrorMeters; using osuTK; using osuTK.Graphics; From f1f323ee82a50c02661de12a39e8ddf76899271e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Oct 2022 18:55:50 +0900 Subject: [PATCH 1642/2686] Add new deserialisation test including longest combo counter --- .../Archives/modified-default-20221012.osk | Bin 0 -> 1209 bytes osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 4 +++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Resources/Archives/modified-default-20221012.osk diff --git a/osu.Game.Tests/Resources/Archives/modified-default-20221012.osk b/osu.Game.Tests/Resources/Archives/modified-default-20221012.osk new file mode 100644 index 0000000000000000000000000000000000000000..74ff4f31d5c506d9c7e9b6d503d3f8149f6eeb9f GIT binary patch literal 1209 zcmWIWW@Zs#U|`^2STM~ew8mlc^mRa95hF;1fuT4%GfyuwFY|1_A=e=X0oUKQM{h_5 zEM9r!+^KV3+8ZV2dT!cbtvoxjDSh(?k2uHXh)TxY{Qp1x_+ME+MfFWoTa@#Kd*00H zqRECYHZq@CCU|zfVT-hapzxf$1+j9BPfZ@!#hKn@@w>6tTXaQj!od>(d_j*`Ch~If zroY>e_^{>Si*5NyUj=)0E2pRxgdecb`gzM(G;i+Ot6Q4(#<)}$zKfrJ=%MuTBc{(1 zE@#Dsetw!%`KR(DQviyexE)#jnt*;;48*)pKV{~n@K$+}S-7&X zig%igy+7?3HPkoGe$o`pbyw*jXRr-kk;p{sTS+1~H&xeG@bDJVITZ^K%RG^HTFl ziovdaJKfR$wt>j;_kTqK&mS!6n7qcr*5OoG=4`RR2Tc|d-?wfp$o=xh!{ze6-!ij8 zvUV`Ev)mAQ`r!ZO`FpsOje{=}aw zx3mq9mKN>2d2i;ODYqEg9BvN+q$_c2O7rc?NKay2j76C702{_4`5 z=6SDzRu=B)j+4-yEB`iq!|eX+a<$4yf|kpsY}yd2z5W>ILjSk+XFqU1t}x!iw^vxa zNxS0N22=BOi~5!a>zc7;J73e-AFwXpcbam-^{V*S#owpAE40!1V_ERj z%s5ki&%*C5?-lQ>$3AkFH*j0eZIaEBZLj>^qITM&mkvjsUz)2d^@sCc#KtE*j~hQp zzI5N>UBCX%^8aDK-1YtIzU6%oZ_sXzUdJlpmX+SFm33*#kKNOj{SQc-T%Gp)+WG@b zEf-Jc?cVOxzO+Tvu-lqJ-P2`q&)!1Eq)9=?A|}a%`LF$Tsdr=euedq#|Crcre`d~h z^8BWHa?|0t4_!}PdfdO)*ll|~TJ&q~_Tgm#MmrM_^8;~keqMTTYEEi$2{_)n`&bzQ zycwB97;tAVjtxbgk$~6rr^dm~gQtSadVc{fRK6 Zff>Ws0p6@^AO$Qy_z6gF1S(-*007Hu-Ae!f literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 1b03f8ef6b..989459632e 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -38,7 +38,9 @@ namespace osu.Game.Tests.Skins // Covers legacy song progress, UR counter, colour hit error metre. "Archives/modified-classic-20220801.osk", // Covers clicks/s counter - "Archives/modified-default-20220818.osk" + "Archives/modified-default-20220818.osk", + // Covers longest combo counter + "Archives/modified-default-20221012.osk" }; /// From 83aedb193079a016f841298d2e4e68227d3fe58b Mon Sep 17 00:00:00 2001 From: "D.Headley" Date: Wed, 12 Oct 2022 12:42:26 +0200 Subject: [PATCH 1643/2686] Make mod use new Combo, remove pointless test --- .../Mods/TestSceneOsuModFreezeFrame.cs | 40 --------- .../Mods/OsuModFreezeFrame.cs | 89 +++++-------------- 2 files changed, 22 insertions(+), 107 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs deleted file mode 100644 index 8af63aa5e2..0000000000 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs +++ /dev/null @@ -1,40 +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.Collections.Generic; -using NUnit.Framework; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; - -namespace osu.Game.Rulesets.Osu.Tests.Mods -{ - public class TestSceneOsuModFreezeFrame : OsuModTestScene - { - [TestCase(OsuModFreezeFrame.BeatDivisor.Quarter_Measure)] - [TestCase(OsuModFreezeFrame.BeatDivisor.Single_Measure)] - [TestCase(OsuModFreezeFrame.BeatDivisor.Quadruple_Measure)] - public void TestFreezeFrequency(OsuModFreezeFrame.BeatDivisor divisor) - { - CreateModTest(new ModTestData - { - Mod = new OsuModFreezeFrame { Divisor = { Value = divisor } }, - PassCondition = checkSomeHit, - Autoplay = true - }); - } - - [Test] - public void TestWithHidden() - { - var mods = new List { new OsuModHidden(), new OsuModFreezeFrame { Divisor = { Value = OsuModFreezeFrame.BeatDivisor.Quadruple_Measure } } }; - CreateModTest(new ModTestData - { - Mods = mods, - PassCondition = checkSomeHit, - Autoplay = true - }); - } - - private bool checkSomeHit() => Player.ScoreProcessor.JudgedHits >= 8; - } -} diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 26adc0f25f..b21e8a4a5f 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -1,22 +1,17 @@ // 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.Linq; -using System.ComponentModel; -using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModFreezeFrame : ModWithVisibilityAdjustment, IApplicableToDrawableRuleset + public class OsuModFreezeFrame : Mod, IApplicableToBeatmap, IApplicableToDrawableRuleset { public override string Name => "Freeze Frame"; @@ -28,80 +23,40 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Fun; - [SettingSource("Beat Divisor", "How often the hitobjects should be grouped according to BPM")] - public Bindable Divisor { get; } = new Bindable(BeatDivisor.Single_Measure); - public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { (drawableRuleset.Playfield as OsuPlayfield)?.FollowPoints.Hide(); } - public override void ApplyToBeatmap(IBeatmap beatmap) + public void ApplyToBeatmap(IBeatmap beatmap) { - base.ApplyToBeatmap(beatmap); + double lastNewComboTime = 0; foreach (var obj in beatmap.HitObjects.OfType()) { - // The +1s below are added due to First HitCircle in each measure not appearing appropriately without them. - var lastTimingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime + 1); - double controlPointDifference = obj.StartTime + 1 - lastTimingPoint.Time; - double remainder = controlPointDifference % (lastTimingPoint.BeatLength * getMeasure(Divisor.Value)) - 1; - double finalPreempt = obj.TimePreempt + remainder; - applyFadeInAdjustment(obj); + if (obj.NewCombo) { lastNewComboTime = obj.StartTime; } - void applyFadeInAdjustment(OsuHitObject osuObject) + applyFadeInAdjustment(obj); + } + + void applyFadeInAdjustment(OsuHitObject osuObject) + { + osuObject.TimePreempt += osuObject.StartTime - lastNewComboTime; + + foreach (var nested in osuObject.NestedHitObjects.OfType()) { - osuObject.TimePreempt = finalPreempt; - foreach (var nested in osuObject.NestedHitObjects.OfType()) - applyFadeInAdjustment(nested); + switch (nested) + { + //SliderRepeat wont layer correctly if preempt is changed. + case SliderRepeat: + return; + + default: + applyFadeInAdjustment(nested); + break; + } } } } - - protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) { } - - protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) { } - - private float getMeasure(BeatDivisor divisor) - { - switch (divisor) - { - case BeatDivisor.Quarter_Measure: - return 0.25f; - - case BeatDivisor.Half_Measure: - return 0.5f; - - case BeatDivisor.Single_Measure: - return 1; - - case BeatDivisor.Double_Measure: - return 2; - - case BeatDivisor.Quadruple_Measure: - return 4; - - default: - throw new ArgumentOutOfRangeException(nameof(divisor), divisor, null); - } - } - - public enum BeatDivisor - { - [Description("1/4")] - Quarter_Measure, - - [Description("1/2")] - Half_Measure, - - [Description("1")] - Single_Measure, - - [Description("2")] - Double_Measure, - - [Description("4")] - Quadruple_Measure - } } } From 8305d886e6460b37818b1eb28a8106d8bd1a6e77 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 12 Oct 2022 17:50:04 +0300 Subject: [PATCH 1644/2686] Refactor internal visibility logic to route back to `PopIn`/`PopOut` --- .../Graphics/Cursor/MenuCursorContainer.cs | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 70fa66b35a..9f876a5e2d 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -28,10 +28,6 @@ namespace osu.Game.Graphics.Cursor private Cursor activeCursor = null!; - private readonly Container fadeContainer; - - protected override Container Content => fadeContainer; - private DragRotationState dragRotationState; private Vector2 positionMouseDown; private Vector2 lastMovePosition; @@ -39,11 +35,6 @@ namespace osu.Game.Graphics.Cursor private Bindable cursorRotate = null!; private Sample tapSample = null!; - public MenuCursorContainer() - { - InternalChild = fadeContainer = new Container { RelativeSizeAxes = Axes.Both }; - } - [BackgroundDependencyLoader] private void load(OsuConfigManager config, ScreenshotManager? screenshotManager, AudioManager audio) { @@ -58,14 +49,37 @@ namespace osu.Game.Graphics.Cursor [Resolved] private OsuUserInputManager inputManager { get; set; } = null!; - private IBindable mouseInputSource = null!; + private readonly IBindable mouseInputSource = new BindableBool(); + + private readonly Bindable internalState = new Bindable(); protected override void LoadComplete() { base.LoadComplete(); - mouseInputSource = inputManager.IsMouseInputSource.GetBoundCopy(); - mouseInputSource.BindValueChanged(m => updateInternalVisibilityState(m.NewValue), true); + internalState.ValueChanged += onInternalStateChanged; + + mouseInputSource.BindTo(inputManager.IsMouseInputSource); + mouseInputSource.BindValueChanged(_ => updateInternalVisibility(), true); + + } + + private void updateInternalVisibility() + { + bool visible = mouseInputSource.Value; + internalState.Value = visible ? Visibility.Visible : Visibility.Hidden; + } + + private void onInternalStateChanged(ValueChangedEvent internalState) + { + if (State.Value == Visibility.Visible) + base.UpdateState(internalState); + } + + protected override void UpdateState(ValueChangedEvent state) + { + if (internalState.Value == Visibility.Visible) + base.UpdateState(state); } protected override void Update() @@ -168,8 +182,6 @@ namespace osu.Game.Graphics.Cursor activeCursor.ScaleTo(0.6f, 250, Easing.In); } - private void updateInternalVisibilityState(bool show) => fadeContainer.FadeTo(show ? 1 : 0, 120, Easing.OutQuint); - private void playTapSample(double baseFrequency = 1f) { const float random_range = 0.02f; From a44cfe29013a6b92eefdc20766257e0422c0ad2a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 12 Oct 2022 17:50:31 +0300 Subject: [PATCH 1645/2686] Hide menu cursor when user is idle --- osu.Game/Graphics/Cursor/MenuCursorContainer.cs | 9 +++++++++ osu.Game/OsuGame.cs | 8 ++++++-- osu.Game/OsuGameBase.cs | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 9f876a5e2d..cc747f00d5 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -49,7 +49,11 @@ namespace osu.Game.Graphics.Cursor [Resolved] private OsuUserInputManager inputManager { get; set; } = null!; + [Resolved] + private OsuGame? game { get; set; } + private readonly IBindable mouseInputSource = new BindableBool(); + private readonly IBindable isIdle = new BindableBool(); private readonly Bindable internalState = new Bindable(); @@ -62,6 +66,11 @@ namespace osu.Game.Graphics.Cursor mouseInputSource.BindTo(inputManager.IsMouseInputSource); mouseInputSource.BindValueChanged(_ => updateInternalVisibility(), true); + if (game != null) + { + isIdle.BindTo(game.IsIdle); + isIdle.BindValueChanged(_ => updateInternalVisibility()); + } } private void updateInternalVisibility() diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1716e48395..b3eaf5cd01 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -70,6 +70,7 @@ namespace osu.Game /// The full osu! experience. Builds on top of to add menus and binding logic /// for initial components that are generally retrieved via DI. /// + [Cached(typeof(OsuGame))] public class OsuGame : OsuGameBase, IKeyBindingHandler, ILocalUserPlayInfo, IPerformFromScreenRunner, IOverlayManager, ILinkHandler { /// @@ -136,6 +137,11 @@ namespace osu.Game private IdleTracker idleTracker; + /// + /// Whether the user is currently in an idle state. + /// + public IBindable IsIdle => idleTracker.IsIdle; + /// /// Whether overlays should be able to be opened game-wide. Value is sourced from the current active screen. /// @@ -266,8 +272,6 @@ namespace osu.Game [BackgroundDependencyLoader] private void load() { - dependencies.CacheAs(this); - SentryLogger.AttachUser(API.LocalUser); dependencies.Cache(osuLogo = new OsuLogo { Alpha = 0 }); diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 478f154d58..7d9ed7bf3e 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -62,6 +62,7 @@ namespace osu.Game /// Unlike , this class will not load any kind of UI, allowing it to be used /// for provide dependencies to test cases without interfering with them. /// + [Cached(typeof(OsuGameBase))] public partial class OsuGameBase : Framework.Game, ICanAcceptFiles, IBeatSyncProvider { public static readonly string[] VIDEO_EXTENSIONS = { ".mp4", ".mov", ".avi", ".flv" }; @@ -253,7 +254,6 @@ namespace osu.Game largeStore.AddTextureSource(Host.CreateTextureLoaderStore(new OnlineStore())); dependencies.Cache(largeStore); - dependencies.CacheAs(this); dependencies.CacheAs(LocalConfig); InitialiseFonts(); From 7a6ecaff0d14569a0beb64d7f0820c68ce954a39 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 12 Oct 2022 17:50:47 +0300 Subject: [PATCH 1646/2686] Remove default invisible cursor container from rulesets --- osu.Game/Rulesets/UI/Playfield.cs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 2ec72d8fe3..354f6c38b6 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -211,7 +211,7 @@ namespace osu.Game.Rulesets.UI /// The default provided cursor is invisible when inside the bounds of the . /// /// The cursor, or null to show the menu cursor. - protected virtual GameplayCursorContainer CreateCursor() => new InvisibleCursorContainer(); + protected virtual GameplayCursorContainer CreateCursor() => null; /// /// Registers a as a nested . @@ -522,14 +522,5 @@ namespace osu.Game.Rulesets.UI } #endregion - - public class InvisibleCursorContainer : GameplayCursorContainer - { - protected override Drawable CreateCursor() => new InvisibleCursor(); - - private class InvisibleCursor : Drawable - { - } - } } } From 6199db11a2e9872bd688e74d608ea24ba5d77f2f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 12 Oct 2022 17:55:32 +0300 Subject: [PATCH 1647/2686] Make `OsuUserInputManager` dependency nullable for tournament client --- osu.Game/Graphics/Cursor/MenuCursorContainer.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index cc747f00d5..380af577ba 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -47,7 +47,7 @@ namespace osu.Game.Graphics.Cursor } [Resolved] - private OsuUserInputManager inputManager { get; set; } = null!; + private OsuUserInputManager? inputManager { get; set; } [Resolved] private OsuGame? game { get; set; } @@ -63,8 +63,11 @@ namespace osu.Game.Graphics.Cursor internalState.ValueChanged += onInternalStateChanged; - mouseInputSource.BindTo(inputManager.IsMouseInputSource); - mouseInputSource.BindValueChanged(_ => updateInternalVisibility(), true); + if (inputManager != null) + { + mouseInputSource.BindTo(inputManager.IsMouseInputSource); + mouseInputSource.BindValueChanged(_ => updateInternalVisibility(), true); + } if (game != null) { From f67f6cc99ca914b152a355122589900437b6b91d Mon Sep 17 00:00:00 2001 From: "D.Headley" Date: Wed, 12 Oct 2022 19:45:08 +0200 Subject: [PATCH 1648/2686] Fix switch case --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index b21e8a4a5f..a91d7831c3 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Mods { //SliderRepeat wont layer correctly if preempt is changed. case SliderRepeat: - return; + break; default: applyFadeInAdjustment(nested); From 565de23222bf84972c6ca89389c91bf1926a8174 Mon Sep 17 00:00:00 2001 From: Feodor0090 <53872073+Feodor0090@users.noreply.github.com> Date: Wed, 12 Oct 2022 21:26:33 +0300 Subject: [PATCH 1649/2686] Fix CQ (non-readonly field) --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index af6f8ba97c..bf01d3b0ac 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Online }); } - private ManualResetEventSlim deletionPerformed = new ManualResetEventSlim(); + private readonly ManualResetEventSlim deletionPerformed = new ManualResetEventSlim(); [Test] public void TestDeletion() From 4fb156ef4eb8055d84d14b1889b8137ec3928abc Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 13 Oct 2022 00:16:42 +0300 Subject: [PATCH 1650/2686] Update xmlodc and add nullability attributes --- osu.Game/Rulesets/UI/DrawableRuleset.cs | 1 + osu.Game/Rulesets/UI/Playfield.cs | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index bd10bc839c..dd3a950264 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -499,6 +499,7 @@ namespace osu.Game.Rulesets.UI /// /// The cursor being displayed by the . May be null if no cursor is provided. /// + [CanBeNull] public abstract GameplayCursorContainer Cursor { get; } /// diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 354f6c38b6..e59e45722a 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -202,14 +202,12 @@ namespace osu.Game.Rulesets.UI /// /// The cursor currently being used by this . May be null if no cursor is provided. /// + [CanBeNull] public GameplayCursorContainer Cursor { get; private set; } /// /// Provide a cursor which is to be used for gameplay. /// - /// - /// The default provided cursor is invisible when inside the bounds of the . - /// /// The cursor, or null to show the menu cursor. protected virtual GameplayCursorContainer CreateCursor() => null; From 09cc89cfa0fa603673fc4cb1170883f7cdc51d00 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 13 Oct 2022 00:17:02 +0300 Subject: [PATCH 1651/2686] Update existing usages of `Cursor` to handle null value --- osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs | 14 +++++++++----- .../Mods/TestSceneOsuModNoScope.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs | 3 ++- osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs | 5 ++++- osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs | 3 ++- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs index 69ae8328e9..3f7560844c 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs @@ -19,17 +19,20 @@ namespace osu.Game.Rulesets.Catch.Mods { public override LocalisableString Description => @"Use the mouse to control the catcher."; - private DrawableRuleset drawableRuleset = null!; + private DrawableCatchRuleset drawableRuleset = null!; public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - this.drawableRuleset = drawableRuleset; + this.drawableRuleset = (DrawableCatchRuleset)drawableRuleset; } public void ApplyToPlayer(Player player) { if (!drawableRuleset.HasReplayLoaded.Value) - drawableRuleset.Cursor.Add(new MouseInputHelper((CatchPlayfield)drawableRuleset.Playfield)); + { + var catchPlayfield = (CatchPlayfield)drawableRuleset.Playfield; + catchPlayfield.CatcherArea.Add(new MouseInputHelper(catchPlayfield.CatcherArea)); + } } private class MouseInputHelper : Drawable, IKeyBindingHandler, IRequireHighFrequencyMousePosition @@ -38,9 +41,10 @@ namespace osu.Game.Rulesets.Catch.Mods public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; - public MouseInputHelper(CatchPlayfield playfield) + public MouseInputHelper(CatcherArea catcherArea) { - catcherArea = playfield.CatcherArea; + this.catcherArea = catcherArea; + RelativeSizeAxes = Axes.Both; } diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs index 44404ca245..045a7e32eb 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Utils; using osu.Framework.Testing; using osu.Game.Beatmaps; @@ -145,6 +146,6 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods private bool isBreak() => Player.IsBreakTime.Value; - private bool cursorAlphaAlmostEquals(float alpha) => Precision.AlmostEquals(Player.DrawableRuleset.Cursor.Alpha, alpha, 0.1f); + private bool cursorAlphaAlmostEquals(float alpha) => Precision.AlmostEquals(Player.DrawableRuleset.Cursor.AsNonNull().Alpha, alpha, 0.1f); } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs index fbde9e0491..38d90eb121 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Framework.Timing; @@ -46,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void Update(Playfield playfield) { - var cursorPos = playfield.Cursor.ActiveCursor.DrawPosition; + var cursorPos = playfield.Cursor.AsNonNull().ActiveCursor.DrawPosition; foreach (var drawable in playfield.HitObjectContainer.AliveObjects) { diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs index 2f84c30581..9a8aa57746 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Beatmaps; @@ -35,7 +36,9 @@ namespace osu.Game.Rulesets.Osu.Mods { bool shouldAlwaysShowCursor = IsBreakTime.Value || spinnerPeriods.IsInAny(playfield.Clock.CurrentTime); float targetAlpha = shouldAlwaysShowCursor ? 1 : ComboBasedAlpha; - playfield.Cursor.Alpha = (float)Interpolation.Lerp(playfield.Cursor.Alpha, targetAlpha, Math.Clamp(playfield.Time.Elapsed / TRANSITION_DURATION, 0, 1)); + + var cursor = playfield.Cursor.AsNonNull(); + cursor.Alpha = (float)Interpolation.Lerp(cursor.Alpha, targetAlpha, Math.Clamp(playfield.Time.Elapsed / TRANSITION_DURATION, 0, 1)); } } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs index 911363a27e..31a6b69d6b 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Localisation; using osu.Framework.Timing; using osu.Framework.Utils; @@ -45,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void Update(Playfield playfield) { - var cursorPos = playfield.Cursor.ActiveCursor.DrawPosition; + var cursorPos = playfield.Cursor.AsNonNull().ActiveCursor.DrawPosition; foreach (var drawable in playfield.HitObjectContainer.AliveObjects) { From 964ed01abb60cf3d21b2691c5bd530abf696d925 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 13 Oct 2022 02:39:37 +0300 Subject: [PATCH 1652/2686] Add confirmation dialog for updating locally modified beatmaps --- osu.Game/Localisation/PopupDialogStrings.cs | 24 +++++++++++ .../Select/Carousel/UpdateBeatmapSetButton.cs | 42 ++++++++++++++----- .../Carousel/UpdateLocalConfirmationDialog.cs | 21 ++++++++++ 3 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Localisation/PopupDialogStrings.cs create mode 100644 osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs diff --git a/osu.Game/Localisation/PopupDialogStrings.cs b/osu.Game/Localisation/PopupDialogStrings.cs new file mode 100644 index 0000000000..b2e9673cbe --- /dev/null +++ b/osu.Game/Localisation/PopupDialogStrings.cs @@ -0,0 +1,24 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class PopupDialogStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.PopupDialog"; + + /// + /// "Are you sure you want to update this beatmap?" + /// + public static LocalisableString UpdateLocallyModifiedText => new TranslatableString(getKey(@"update_locally_modified_text"), @"Are you sure you want to update this beatmap?"); + + /// + /// "This will discard all local changes you have on that beatmap." + /// + public static LocalisableString UpdateLocallyModifiedDescription => new TranslatableString(getKey(@"update_locally_modified_description"), @"This will discard all local changes you have on that beatmap."); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs b/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs index 023d3627b0..1bb607bcf3 100644 --- a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs +++ b/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs @@ -32,9 +32,12 @@ namespace osu.Game.Screens.Select.Carousel [Resolved] private IAPIProvider api { get; set; } = null!; - [Resolved(canBeNull: true)] + [Resolved] private LoginOverlay? loginOverlay { get; set; } + [Resolved] + private IDialogOverlay? dialogOverlay { get; set; } + public UpdateBeatmapSetButton(BeatmapSetInfo beatmapSetInfo) { this.beatmapSetInfo = beatmapSetInfo; @@ -102,17 +105,34 @@ namespace osu.Game.Screens.Select.Carousel }, }); - Action = () => - { - if (!api.IsLoggedIn) - { - loginOverlay?.Show(); - return; - } + Action = updateBeatmap; + } - beatmapDownloader.DownloadAsUpdate(beatmapSetInfo, preferNoVideo.Value); - attachExistingDownload(); - }; + private bool updateConfirmed; + + private void updateBeatmap() + { + if (!api.IsLoggedIn) + { + loginOverlay?.Show(); + return; + } + + if (dialogOverlay != null && beatmapSetInfo.Status == BeatmapOnlineStatus.LocallyModified && !updateConfirmed) + { + dialogOverlay.Push(new UpdateLocalConfirmationDialog(() => + { + updateConfirmed = true; + updateBeatmap(); + })); + + return; + } + + updateConfirmed = false; + + beatmapDownloader.DownloadAsUpdate(beatmapSetInfo, preferNoVideo.Value); + attachExistingDownload(); } protected override void LoadComplete() diff --git a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs b/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs new file mode 100644 index 0000000000..f5267e905e --- /dev/null +++ b/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs @@ -0,0 +1,21 @@ +// 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.Sprites; +using osu.Game.Overlays.Dialog; +using osu.Game.Localisation; + +namespace osu.Game.Screens.Select.Carousel +{ + public class UpdateLocalConfirmationDialog : DeleteConfirmationDialog + { + public UpdateLocalConfirmationDialog(Action onConfirm) + { + HeaderText = PopupDialogStrings.UpdateLocallyModifiedText; + BodyText = PopupDialogStrings.UpdateLocallyModifiedDescription; + Icon = FontAwesome.Solid.ExclamationTriangle; + DeleteAction = onConfirm; + } + } +} From 7db7bcc283ab94c165c795d04554e597af17ddb7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 13 Oct 2022 02:40:20 +0300 Subject: [PATCH 1653/2686] Add test coverage --- .../TestSceneUpdateBeatmapSetButton.cs | 70 ++++++++++++++++--- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs index 70786c93e7..f76f050546 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs @@ -10,10 +10,13 @@ using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Online.API; +using osu.Game.Overlays; +using osu.Game.Overlays.Dialog; using osu.Game.Screens.Select; using osu.Game.Screens.Select.Carousel; using osu.Game.Tests.Online; using osu.Game.Tests.Resources; +using osuTK.Input; namespace osu.Game.Tests.Visual.SongSelect { @@ -41,17 +44,7 @@ namespace osu.Game.Tests.Visual.SongSelect [SetUpSteps] public void SetUpSteps() { - AddStep("create carousel", () => - { - Child = carousel = new BeatmapCarousel - { - RelativeSizeAxes = Axes.Both, - BeatmapSets = new List - { - (testBeatmapSetInfo = TestResources.CreateTestBeatmapSetInfo()), - } - }; - }); + AddStep("create carousel", () => Child = createCarousel()); AddUntilStep("wait for load", () => carousel.BeatmapSetsLoaded); @@ -152,5 +145,60 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("wait for button enabled", () => getUpdateButton()?.Enabled.Value == true); } + + [Test] + public void TestUpdateLocalBeatmap() + { + DialogOverlay dialogOverlay = null!; + + AddStep("create carousel with dialog overlay", () => + { + dialogOverlay = new DialogOverlay(); + + Child = new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] { (typeof(IDialogOverlay), dialogOverlay), }, + Children = new Drawable[] + { + createCarousel(), + dialogOverlay, + }, + }; + }); + + AddStep("setup beatmap state", () => + { + testBeatmapSetInfo.Beatmaps.First().OnlineMD5Hash = "different hash"; + testBeatmapSetInfo.Beatmaps.First().LastOnlineUpdate = DateTimeOffset.Now; + testBeatmapSetInfo.Status = BeatmapOnlineStatus.LocallyModified; + + carousel.UpdateBeatmapSet(testBeatmapSetInfo); + }); + + AddStep("click button", () => getUpdateButton()?.TriggerClick()); + + AddAssert("dialog displayed", () => dialogOverlay.CurrentDialog is UpdateLocalConfirmationDialog); + AddStep("click confirmation", () => + { + InputManager.MoveMouseTo(dialogOverlay.CurrentDialog.ChildrenOfType().First()); + InputManager.PressButton(MouseButton.Left); + }); + + AddUntilStep("update started", () => beatmapDownloader.GetExistingDownload(testBeatmapSetInfo) != null); + AddStep("release mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); + } + + private BeatmapCarousel createCarousel() + { + return carousel = new BeatmapCarousel + { + RelativeSizeAxes = Axes.Both, + BeatmapSets = new List + { + (testBeatmapSetInfo = TestResources.CreateTestBeatmapSetInfo()), + } + }; + } } } From e240f659c21e11a787c9a50b1d638de88b75fd1d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 11:22:40 +0900 Subject: [PATCH 1654/2686] Refactor visibility states to read better --- .../Graphics/Cursor/MenuCursorContainer.cs | 39 +++++++++---------- osu.Game/Input/OsuUserInputManager.cs | 8 ++-- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 380af577ba..94bdef9842 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -35,6 +35,8 @@ namespace osu.Game.Graphics.Cursor private Bindable cursorRotate = null!; private Sample tapSample = null!; + private bool visible; + [BackgroundDependencyLoader] private void load(OsuConfigManager config, ScreenshotManager? screenshotManager, AudioManager audio) { @@ -52,46 +54,41 @@ namespace osu.Game.Graphics.Cursor [Resolved] private OsuGame? game { get; set; } - private readonly IBindable mouseInputSource = new BindableBool(); + private readonly IBindable lastInputWasMouse = new BindableBool(); private readonly IBindable isIdle = new BindableBool(); - private readonly Bindable internalState = new Bindable(); - protected override void LoadComplete() { base.LoadComplete(); - internalState.ValueChanged += onInternalStateChanged; - if (inputManager != null) { - mouseInputSource.BindTo(inputManager.IsMouseInputSource); - mouseInputSource.BindValueChanged(_ => updateInternalVisibility(), true); + lastInputWasMouse.BindTo(inputManager.LastInputWasMouseSource); + lastInputWasMouse.BindValueChanged(_ => updateState(), true); } if (game != null) { isIdle.BindTo(game.IsIdle); - isIdle.BindValueChanged(_ => updateInternalVisibility()); + isIdle.BindValueChanged(_ => updateState()); } } - private void updateInternalVisibility() - { - bool visible = mouseInputSource.Value; - internalState.Value = visible ? Visibility.Visible : Visibility.Hidden; - } + protected override void UpdateState(ValueChangedEvent state) => updateState(); - private void onInternalStateChanged(ValueChangedEvent internalState) + private void updateState() { - if (State.Value == Visibility.Visible) - base.UpdateState(internalState); - } + bool combinedVisibility = State.Value == Visibility.Visible && lastInputWasMouse.Value && !isIdle.Value; - protected override void UpdateState(ValueChangedEvent state) - { - if (internalState.Value == Visibility.Visible) - base.UpdateState(state); + if (visible == combinedVisibility) + return; + + visible = combinedVisibility; + + if (visible) + PopIn(); + else + PopOut(); } protected override void Update() diff --git a/osu.Game/Input/OsuUserInputManager.cs b/osu.Game/Input/OsuUserInputManager.cs index 5e700e32de..82c6ca0edd 100644 --- a/osu.Game/Input/OsuUserInputManager.cs +++ b/osu.Game/Input/OsuUserInputManager.cs @@ -15,9 +15,9 @@ namespace osu.Game.Input /// /// Whether the last input applied to the game is sourced from mouse. /// - public IBindable IsMouseInputSource => isMouseInputSource; + public IBindable LastInputWasMouseSource => lastInputWasMouseSource; - private readonly Bindable isMouseInputSource = new Bindable(); + private readonly Bindable lastInputWasMouseSource = new Bindable(); internal OsuUserInputManager() { @@ -29,11 +29,11 @@ namespace osu.Game.Input { case ButtonStateChangeEvent: case MousePositionChangeEvent: - isMouseInputSource.Value = true; + lastInputWasMouseSource.Value = true; break; default: - isMouseInputSource.Value = false; + lastInputWasMouseSource.Value = false; break; } From dd372c4d19c87e28f53b3a3f92fa17d824fb9ddf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 13:51:02 +0900 Subject: [PATCH 1655/2686] Move "argon" skin judgement text in front of hitobjects --- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs | 2 +- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs index e7dfec256d..6a9b3e3aba 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon ringExplosion?.PlayAnimation(); } - public Drawable? GetAboveHitObjectsProxiedContent() => null; + public Drawable? GetAboveHitObjectsProxiedContent() => JudgementText; private class RingExplosion : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs index b08b7b4e85..bb68c7298f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs @@ -75,6 +75,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { default: JudgementText + .FadeInFromZero(300, Easing.OutQuint) .ScaleTo(Vector2.One) .ScaleTo(new Vector2(1.2f), 1800, Easing.OutQuint); break; @@ -96,7 +97,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon ringExplosion?.PlayAnimation(); } - public Drawable? GetAboveHitObjectsProxiedContent() => null; + public Drawable? GetAboveHitObjectsProxiedContent() => JudgementText.CreateProxy(); private class RingExplosion : CompositeDrawable { From 4149235e63173f374a80a7235411ef72588c455b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 5 Oct 2022 17:50:36 +0900 Subject: [PATCH 1656/2686] Limit minimum brightness of combo colours --- osu.Game/Configuration/OsuConfigManager.cs | 4 +- osu.Game/Graphics/OsuColour.cs | 167 ++++++++++++++++++ .../Sections/Gameplay/BeatmapSettings.cs | 6 + .../Objects/Drawables/DrawableHitObject.cs | 14 +- 4 files changed, 189 insertions(+), 2 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index e3bfb6b1e9..b433d81f31 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -175,6 +175,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f); SetDefault(OsuSetting.LastProcessedMetadataId, -1); + SetDefault(OsuSetting.ComboColourBrightness, 0.7f, 0f, 1f); } protected override bool CheckLookupContainsPrivateInformation(OsuSetting lookup) @@ -370,6 +371,7 @@ namespace osu.Game.Configuration DiscordRichPresence, AutomaticallyDownloadWhenSpectating, ShowOnlineExplicitContent, - LastProcessedMetadataId + LastProcessedMetadataId, + ComboColourBrightness } } diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index 91161d5c71..bd0604bb76 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -229,6 +229,173 @@ namespace osu.Game.Graphics return Gray(brightness > 0.5f ? 0.2f : 0.9f); } + /// + /// Converts RGBA to HSPA. + /// + public static Color4 ToHSPA(Color4 colour) + { + const float p_r = 0.299f; + const float p_g = 0.587f; + const float p_b = 0.114f; + + Color4 result = new Color4 + { + A = colour.A, + B = MathF.Sqrt(colour.R * colour.R * p_r + colour.G * colour.G * p_g + colour.B + colour.B * p_b) + }; + + if (colour.R == colour.G && colour.R == colour.B) + return result; + + if (colour.R >= colour.G && colour.R >= colour.B) + { + if (colour.B >= colour.G) + { + result.R = 6f / 6f - 1f / 6f * (colour.B - colour.G) / (colour.R - colour.G); + result.G = 1f - colour.G / colour.R; + } + else + { + result.R = 0f / 6f + 1f / 6f * (colour.G - colour.B) / (colour.R - colour.B); + result.G = 1f - colour.B / colour.R; + } + } + else if (colour.G >= colour.R && colour.G >= colour.B) + { + if (colour.R >= colour.B) + { + result.R = 2f / 6f - 1f / 6f * (colour.R - colour.B) / (colour.G - colour.B); + result.G = 1f - colour.B / colour.G; + } + else + { + result.R = 2f / 6f + 1f / 6f * (colour.B - colour.R) / (colour.G - colour.R); + result.G = 1f - colour.R / colour.G; + } + } + else + { + if (colour.G >= colour.R) + { + result.R = 4f / 6f - 1f / 6f * (colour.G - colour.R) / (colour.B - colour.R); + result.G = 1f - colour.R / colour.B; + } + else + { + result.R = 4f / 6f + 1f / 6f * (colour.R - colour.G) / (colour.B - colour.G); + result.G = 1f - colour.G / colour.B; + } + } + + return result; + } + + public static Color4 FromHSPA(Color4 colour) + { + const float p_r = 0.299f; + const float p_g = 0.587f; + const float p_b = 0.114f; + + float minOverMax = 1f - colour.G; + + Color4 result = new Color4 { A = colour.A }; + + if (minOverMax > 0f) + { + float part = 1f + colour.R * (1f / minOverMax - 1f); + + if (colour.R < 1f / 6f) + { + colour.R = 6f * (colour.R - 0f / 6f); + result.B = colour.B / MathF.Sqrt(p_r / minOverMax / minOverMax + p_g * part * part + p_b); + result.R = result.B / minOverMax; + result.G = result.B + colour.R * (result.R - result.B); + } + else if (colour.R < 2f / 6f) + { + colour.R = 6f * (-colour.R + 2f / 6f); + result.B = colour.B / MathF.Sqrt(p_g / minOverMax / minOverMax + p_r * part * part + p_b); + result.G = result.B / minOverMax; + result.R = result.B + colour.R * (result.R - result.B); + } + else if (colour.R < 3f / 6f) + { + colour.R = 6f * (colour.R - 2f / 6f); + result.R = colour.B / MathF.Sqrt(p_g / minOverMax / minOverMax + p_b * part * part + p_r); + result.G = result.R / minOverMax; + result.B = result.R + colour.R * (result.G - result.R); + } + else if (colour.R < 4f / 6f) + { + colour.R = 6f * (-colour.R + 4f / 6f); + result.R = colour.B / MathF.Sqrt(p_b / minOverMax / minOverMax + p_g * part * part + p_r); + result.B = result.R / minOverMax; + result.G = result.R + colour.R * (result.B - result.R); + } + else if (colour.R < 5f / 6f) + { + colour.R = 6f * (colour.R - 4f / 6f); + result.G = colour.B / MathF.Sqrt(p_b / minOverMax / minOverMax + p_r * part * part + p_g); + result.B = result.G / minOverMax; + result.R = result.G + colour.R * (result.B - result.G); + } + else + { + colour.R = 6f * (-colour.R + 6f / 6f); + result.G = colour.B / MathF.Sqrt(p_r / minOverMax / minOverMax + p_b * part * part + p_g); + result.R = result.G / minOverMax; + result.B = result.G + colour.R * (result.R - result.G); + } + } + else + { + if (colour.R < 1f / 6f) + { + colour.R = 6f * (colour.R - 0f / 6f); + result.R = MathF.Sqrt(colour.B * colour.B / (p_r + p_g * colour.R * colour.R)); + result.G = result.R * colour.R; + result.B = 0f; + } + else if (colour.R < 2f / 6f) + { + colour.R = 6f * (-colour.R + 2f / 6f); + result.G = MathF.Sqrt(colour.B * colour.B / (p_g + p_r * colour.R * colour.R)); + result.R = result.G * colour.R; + result.B = 0f; + } + else if (colour.R < 3f / 6f) + { + colour.R = 6f * (colour.R - 2f / 6f); + result.G = MathF.Sqrt(colour.B * colour.B / (p_g + p_b * colour.R * colour.R)); + result.B = result.G * colour.R; + result.R = 0f; + } + else if (colour.R < 4f / 6f) + { + colour.R = 6f * (-colour.R + 4f / 6f); + result.B = MathF.Sqrt(colour.B * colour.B / (p_b + p_g * colour.R * colour.R)); + result.G = result.B * colour.R; + result.R = 0f; + } + else if (colour.R < 5f / 6f) + { + colour.R = 6f * (colour.R - 4f / 6f); + result.B = MathF.Sqrt(colour.B * colour.B / (p_b + p_r * colour.R * colour.R)); + result.R = result.B * colour.R; + result.G = 0f; + } + else + { + colour.R = 6f * (-colour.R + 6f / 6f); + result.R = MathF.Sqrt(colour.B * colour.B / (p_r + p_b * colour.R * colour.R)); + result.B = result.R * colour.R; + result.G = 0f; + } + } + + return result; + } + public readonly Color4 TeamColourRed = Color4Extensions.FromHex("#AA1414"); public readonly Color4 TeamColourBlue = Color4Extensions.FromHex("#1462AA"); diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs index becb7aa80f..16b7b74f38 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs @@ -40,6 +40,12 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay LabelText = GraphicsSettingsStrings.StoryboardVideo, Current = config.GetBindable(OsuSetting.ShowStoryboard) }, + new SettingsSlider + { + LabelText = "Combo colour brightness", + Current = config.GetBindable(OsuSetting.ComboColourBrightness), + DisplayAsPercentage = true + } }; } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index dec68a6c22..0ef15ed5c2 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics.Primitives; using osu.Framework.Threading; using osu.Game.Audio; using osu.Game.Configuration; +using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Pooling; using osu.Game.Rulesets.Objects.Types; @@ -128,6 +129,7 @@ namespace osu.Game.Rulesets.Objects.Drawables private readonly Bindable comboIndexBindable = new Bindable(); private readonly Bindable positionalHitsoundsLevel = new Bindable(); + private readonly Bindable comboColourBrightness = new Bindable(); private readonly Bindable comboIndexWithOffsetsBindable = new Bindable(); protected override bool RequiresChildrenUpdate => true; @@ -171,6 +173,7 @@ namespace osu.Game.Rulesets.Objects.Drawables private void load(OsuConfigManager config, ISkinSource skinSource) { config.BindWith(OsuSetting.PositionalHitsoundsLevel, positionalHitsoundsLevel); + config.BindWith(OsuSetting.ComboColourBrightness, comboColourBrightness); // Explicit non-virtual function call in case a DrawableHitObject overrides AddInternal. base.AddInternal(Samples = new PausableSkinnableSound()); @@ -192,6 +195,8 @@ namespace osu.Game.Rulesets.Objects.Drawables comboIndexBindable.BindValueChanged(_ => UpdateComboColour()); comboIndexWithOffsetsBindable.BindValueChanged(_ => UpdateComboColour(), true); + comboColourBrightness.BindValueChanged(_ => UpdateComboColour()); + // Apply transforms updateState(State.Value, true); } @@ -519,7 +524,14 @@ namespace osu.Game.Rulesets.Objects.Drawables { if (!(HitObject is IHasComboInformation combo)) return; - AccentColour.Value = combo.GetComboColour(CurrentSkin); + Color4 colour = combo.GetComboColour(CurrentSkin); + + // Normalise the combo colour to the given brightness level. + colour = OsuColour.ToHSPA(colour); + colour.B = comboColourBrightness.Value; + colour = OsuColour.FromHSPA(colour); + + AccentColour.Value = colour; } /// From 338115ff6a00d4eaf9ce90e061c71f9504307174 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 13 Oct 2022 15:05:15 +0900 Subject: [PATCH 1657/2686] Move check to LegacyDifficultyControlPoint --- .../Beatmaps/TaikoBeatmapConverter.cs | 9 +-------- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 6 +++--- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 20 +++++++------------ 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 613c41a59a..524565a863 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -162,14 +162,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps #pragma warning disable 618 if (difficultyPoint is LegacyBeatmapDecoder.LegacyDifficultyControlPoint legacyDifficultyPoint) #pragma warning restore 618 - { - double bpmMultiplier; - if (beatmap.BeatmapInfo.OnlineID == 1 || beatmap.BeatmapInfo.OnlineID == 3) - bpmMultiplier = legacyDifficultyPoint.BpmMultiplierMania; - else - bpmMultiplier = legacyDifficultyPoint.BpmMultiplier; - beatLength = timingPoint.BeatLength * bpmMultiplier; - } + beatLength = timingPoint.BeatLength * legacyDifficultyPoint.BpmMultiplier; else beatLength = timingPoint.BeatLength / difficultyPoint.SliderVelocity; diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 75500fbc4e..683bc19ce6 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -427,8 +427,10 @@ namespace osu.Game.Beatmaps.Formats addControlPoint(time, controlPoint, true); } + int onlineRulesetID = beatmap.BeatmapInfo.Ruleset.OnlineID; + #pragma warning disable 618 - addControlPoint(time, new LegacyDifficultyControlPoint(beatLength) + addControlPoint(time, new LegacyDifficultyControlPoint(onlineRulesetID, beatLength) #pragma warning restore 618 { SliderVelocity = speedMultiplier, @@ -440,8 +442,6 @@ namespace osu.Game.Beatmaps.Formats OmitFirstBarLine = omitFirstBarSignature, }; - int onlineRulesetID = beatmap.BeatmapInfo.Ruleset.OnlineID; - // osu!taiko and osu!mania use effect points rather than difficulty points for scroll speed adjustments. if (onlineRulesetID == 1 || onlineRulesetID == 3) effectPoint.ScrollSpeed = speedMultiplier; diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 03819af149..ed7ca47cfd 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -168,25 +168,21 @@ namespace osu.Game.Beatmaps.Formats /// public double BpmMultiplier { get; private set; } - /// - /// Legacy BPM multiplier that introduces floating-point errors for rulesets that depend on it. - /// This is to be used for taiko and mania specific beatmaps. - /// DO NOT USE THIS UNLESS 100% SURE. - /// - public double BpmMultiplierMania { get; private set; } - /// /// Whether or not slider ticks should be generated at this control point. /// This exists for backwards compatibility with maps that abuse NaN slider velocity behavior on osu!stable (e.g. /b/2628991). /// public bool GenerateTicks { get; private set; } = true; - public LegacyDifficultyControlPoint(double beatLength) + public LegacyDifficultyControlPoint(int rulesetId, double beatLength) : this() { // Note: In stable, the division occurs on floats, but with compiler optimisations turned on actually seems to occur on doubles via some .NET black magic (possibly inlining?). - BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 1000) / 100.0 : 1; - BpmMultiplierMania = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; + if (rulesetId == 1 || rulesetId == 3) + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 10000) / 100.0 : 1; + else + BpmMultiplier = beatLength < 0 ? Math.Clamp((float)-beatLength, 10, 1000) / 100.0 : 1; + GenerateTicks = !double.IsNaN(beatLength); } @@ -204,7 +200,6 @@ namespace osu.Game.Beatmaps.Formats base.CopyFrom(other); BpmMultiplier = ((LegacyDifficultyControlPoint)other).BpmMultiplier; - BpmMultiplierMania = ((LegacyDifficultyControlPoint)other).BpmMultiplierMania; GenerateTicks = ((LegacyDifficultyControlPoint)other).GenerateTicks; } @@ -215,11 +210,10 @@ namespace osu.Game.Beatmaps.Formats public bool Equals(LegacyDifficultyControlPoint? other) => base.Equals(other) && BpmMultiplier == other.BpmMultiplier - && BpmMultiplierMania == other.BpmMultiplierMania && GenerateTicks == other.GenerateTicks; // ReSharper disable twice NonReadonlyMemberInGetHashCode - public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier, BpmMultiplierMania, GenerateTicks); + public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), BpmMultiplier, GenerateTicks); } internal class LegacySampleControlPoint : SampleControlPoint, IEquatable From f6f5d33f53c0f40ce5382bd95677093157e50eca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 15:44:23 +0900 Subject: [PATCH 1658/2686] Add slight padding to playfield (roughly matches stable) --- osu.Game/Screens/Edit/EditorScreenWithTimeline.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs index b3aafb9730..bcb084fd4e 100644 --- a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs +++ b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs @@ -106,6 +106,7 @@ namespace osu.Game.Screens.Edit Name = "Main content", RelativeSizeAxes = Axes.Both, Depth = float.MaxValue, + Padding = new MarginPadding(10), Child = spinner = new LoadingSpinner(true) { State = { Value = Visibility.Visible }, From a525b3f9f81d64da3c31f9fb29ac1e9bccf603dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 15:44:33 +0900 Subject: [PATCH 1659/2686] Reorder and rename toggle checkboxes to fit better --- .../Edit/Compose/Components/Timeline/TimelineArea.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs index c2415ce978..58d378154a 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs @@ -78,16 +78,16 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline LabelText = "Waveform", Current = { Value = true }, }, - controlPointsCheckbox = new OsuCheckbox - { - LabelText = "Control Points", - Current = { Value = true }, - }, ticksCheckbox = new OsuCheckbox { LabelText = "Ticks", Current = { Value = true }, - } + }, + controlPointsCheckbox = new OsuCheckbox + { + LabelText = "BPM", + Current = { Value = true }, + }, } } } From c3902728f65813f693ed9a5254e01b7eb313b8e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 15:47:54 +0900 Subject: [PATCH 1660/2686] Reorganise beatmap snap control to work better in compact mode --- .../Compose/Components/BeatDivisorControl.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 40403e08ad..19ea2162a3 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -123,16 +123,6 @@ namespace osu.Game.Screens.Edit.Compose.Components } }, new Drawable[] - { - new TextFlowContainer(s => s.Font = s.Font.With(size: 14)) - { - Padding = new MarginPadding { Horizontal = 15 }, - Text = "beat snap", - RelativeSizeAxes = Axes.X, - TextAnchor = Anchor.TopCentre - }, - }, - new Drawable[] { new Container { @@ -173,6 +163,16 @@ namespace osu.Game.Screens.Edit.Compose.Components } } }, + new Drawable[] + { + new TextFlowContainer(s => s.Font = s.Font.With(size: 14)) + { + Padding = new MarginPadding { Horizontal = 15, Vertical = 8 }, + Text = "beat snap", + RelativeSizeAxes = Axes.X, + TextAnchor = Anchor.TopCentre, + }, + }, }, RowDimensions = new[] { From 0f4a2a605941a53772e6318450906b866310ff98 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 16:04:38 +0900 Subject: [PATCH 1661/2686] Improve feel of settings toolbox group --- .../TestSceneSettingsToolboxGroup.cs | 8 +++ osu.Game/Overlays/SettingsToolboxGroup.cs | 69 ++++++++++--------- osu.Game/Screens/Play/PlayerLoader.cs | 3 + 3 files changed, 49 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs index 50e506f82b..9fb0905a4f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs @@ -5,12 +5,14 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; using osu.Game.Overlays.Settings; +using osuTK; using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface @@ -20,11 +22,17 @@ namespace osu.Game.Tests.Visual.UserInterface { private SettingsToolboxGroup group; + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + [SetUp] public void SetUp() => Schedule(() => { Child = group = new SettingsToolboxGroup("example") { + Scale = new Vector2(3), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Children = new Drawable[] { new RoundedButton diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index 548d75c9a9..2f47019272 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -1,8 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Caching; using osu.Framework.Extensions.EnumExtensions; @@ -23,25 +22,40 @@ namespace osu.Game.Overlays { public class SettingsToolboxGroup : Container, IExpandable { + private readonly string title; public const int CONTAINER_WIDTH = 270; private const float transition_duration = 250; - private const int border_thickness = 2; private const int header_height = 30; private const int corner_radius = 5; - private const float fade_duration = 800; - private const float inactive_alpha = 0.5f; - private readonly Cached headerTextVisibilityCache = new Cached(); - private readonly FillFlowContainer content; + protected override Container Content => content; + + private readonly FillFlowContainer content = new FillFlowContainer + { + Name = @"Content", + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeDuration = transition_duration, + AutoSizeEasing = Easing.OutQuint, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = 10, Top = 5, Bottom = 10 }, + Spacing = new Vector2(0, 15), + }; public BindableBool Expanded { get; } = new BindableBool(true); - private readonly OsuSpriteText headerText; + private OsuSpriteText headerText = null!; - private readonly Container headerContent; + private Container headerContent = null!; + + private Box background = null!; + + private IconButton expandButton = null!; /// /// Create a new instance. @@ -49,20 +63,24 @@ namespace osu.Game.Overlays /// The title to be displayed in the header of this group. public SettingsToolboxGroup(string title) { + this.title = title; + AutoSizeAxes = Axes.Y; Width = CONTAINER_WIDTH; Masking = true; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { CornerRadius = corner_radius; - BorderColour = Color4.Black; - BorderThickness = border_thickness; InternalChildren = new Drawable[] { - new Box + background = new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.5f, + Colour = colourProvider.Background5, }, new FillFlowContainer { @@ -88,7 +106,7 @@ namespace osu.Game.Overlays Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 17), Padding = new MarginPadding { Left = 10, Right = 30 }, }, - new IconButton + expandButton = new IconButton { Origin = Anchor.Centre, Anchor = Anchor.CentreRight, @@ -99,19 +117,7 @@ namespace osu.Game.Overlays }, } }, - content = new FillFlowContainer - { - Name = @"Content", - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Direction = FillDirection.Vertical, - RelativeSizeAxes = Axes.X, - AutoSizeDuration = transition_duration, - AutoSizeEasing = Easing.OutQuint, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding(15), - Spacing = new Vector2(0, 15), - } + content } }, }; @@ -175,9 +181,10 @@ namespace osu.Game.Overlays private void updateFadeState() { - this.FadeTo(IsHovered ? 1 : inactive_alpha, fade_duration, Easing.OutQuint); - } + const float fade_duration = 500; - protected override Container Content => content; + background.FadeTo(IsHovered ? 1 : 0, fade_duration, Easing.OutQuint); + expandButton.FadeTo(IsHovered ? 1 : 0, fade_duration, Easing.OutQuint); + } } } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index e32d3d90be..2d096f1c38 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -71,6 +71,9 @@ namespace osu.Game.Screens.Play private AudioFilter lowPassFilter = null!; private AudioFilter highPassFilter = null!; + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + protected bool BackgroundBrightnessReduction { set From 4d99c7002be11fa31e5d22c91227cb7cceb80084 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 16:33:01 +0900 Subject: [PATCH 1662/2686] Add background behind editor toolbox groups --- .../Edit/DistancedHitObjectComposer.cs | 31 ++++++++++---- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 40 +++++++++++++------ 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index 4726211666..5f1f7a1fbf 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -8,6 +8,8 @@ using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Localisation; @@ -52,20 +54,33 @@ namespace osu.Game.Rulesets.Edit } [BackgroundDependencyLoader] - private void load() + private void load(OverlayColourProvider colourProvider) { - AddInternal(RightSideToolboxContainer = new ExpandingToolboxContainer(130, 250) + AddInternal(new Container { - Padding = new MarginPadding(10), - Alpha = DistanceSpacingMultiplier.Disabled ? 0 : 1, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Child = new EditorToolboxGroup("snapping") + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Children = new Drawable[] { - Child = distanceSpacingSlider = new ExpandableSlider> + new Box { - Current = { BindTarget = DistanceSpacingMultiplier }, - KeyboardStep = adjust_step, + Colour = colourProvider.Background5, + RelativeSizeAxes = Axes.Both, + }, + RightSideToolboxContainer = new ExpandingToolboxContainer(130, 250) + { + Padding = new MarginPadding(10), + Alpha = DistanceSpacingMultiplier.Disabled ? 0 : 1, + Child = new EditorToolboxGroup("snapping") + { + Child = distanceSpacingSlider = new ExpandableSlider> + { + Current = { BindTarget = DistanceSpacingMultiplier }, + KeyboardStep = adjust_step, + } + } } } }); diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 37c66037eb..63f0c64c80 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -12,10 +12,12 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Framework.Logging; using osu.Game.Beatmaps; +using osu.Game.Overlays; using osu.Game.Rulesets.Configuration; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Mods; @@ -80,7 +82,7 @@ namespace osu.Game.Rulesets.Edit dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); [BackgroundDependencyLoader] - private void load() + private void load(OverlayColourProvider colourProvider) { Config = Dependencies.Get().GetConfigFor(Ruleset); @@ -116,25 +118,37 @@ namespace osu.Game.Rulesets.Edit .WithChild(BlueprintContainer = CreateBlueprintContainer()) } }, - new ExpandingToolboxContainer(90, 200) + new Container { - Padding = new MarginPadding(10), + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, Children = new Drawable[] { - new EditorToolboxGroup("toolbox (1-9)") + new Box { - Child = toolboxCollection = new EditorRadioButtonCollection { RelativeSizeAxes = Axes.X } + Colour = colourProvider.Background5, + RelativeSizeAxes = Axes.Both, }, - new EditorToolboxGroup("toggles (Q~P)") + new ExpandingToolboxContainer(60, 200) { - Child = togglesCollection = new FillFlowContainer + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 5), - }, - } + new EditorToolboxGroup("toolbox (1-9)") + { + Child = toolboxCollection = new EditorRadioButtonCollection { RelativeSizeAxes = Axes.X } + }, + new EditorToolboxGroup("toggles (Q~P)") + { + Child = togglesCollection = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), + }, + } + } + }, } }, }; From 15f9697c9f0d69ff3a09587761b3b72a9e15f7a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 16:33:09 +0900 Subject: [PATCH 1663/2686] Roughly update design of editor buttons --- .../RadioButtons/EditorRadioButton.cs | 26 ++++++---------- .../TernaryButtons/DrawableTernaryButton.cs | 30 +++++++------------ 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButton.cs b/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButton.cs index 82e94dc862..071bb9fdcb 100644 --- a/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButton.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButton.cs @@ -8,13 +8,12 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; -using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; using osuTK; using osuTK.Graphics; @@ -30,9 +29,9 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons public readonly RadioButton Button; private Color4 defaultBackgroundColour; - private Color4 defaultBubbleColour; + private Color4 defaultIconColour; private Color4 selectedBackgroundColour; - private Color4 selectedBubbleColour; + private Color4 selectedIconColour; private Drawable icon; @@ -50,20 +49,13 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OverlayColourProvider colourProvider) { - defaultBackgroundColour = colours.Gray3; - defaultBubbleColour = defaultBackgroundColour.Darken(0.5f); - selectedBackgroundColour = colours.BlueDark; - selectedBubbleColour = selectedBackgroundColour.Lighten(0.5f); + defaultBackgroundColour = colourProvider.Background3; + selectedBackgroundColour = colourProvider.Background1; - Content.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Radius = 2, - Offset = new Vector2(0, 1), - Colour = Color4.Black.Opacity(0.5f) - }; + defaultIconColour = defaultBackgroundColour.Darken(0.5f); + selectedIconColour = selectedBackgroundColour.Lighten(0.5f); Add(icon = (Button.CreateIcon?.Invoke() ?? new Circle()).With(b => { @@ -98,7 +90,7 @@ namespace osu.Game.Screens.Edit.Components.RadioButtons return; BackgroundColour = Button.Selected.Value ? selectedBackgroundColour : defaultBackgroundColour; - icon.Colour = Button.Selected.Value ? selectedBubbleColour : defaultBubbleColour; + icon.Colour = Button.Selected.Value ? selectedIconColour : defaultIconColour; } protected override SpriteText CreateText() => new OsuSpriteText diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs index 55302833c1..1fb5c0285d 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs @@ -6,12 +6,11 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; using osuTK; using osuTK.Graphics; @@ -20,9 +19,9 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons internal class DrawableTernaryButton : OsuButton { private Color4 defaultBackgroundColour; - private Color4 defaultBubbleColour; + private Color4 defaultIconColour; private Color4 selectedBackgroundColour; - private Color4 selectedBubbleColour; + private Color4 selectedIconColour; private Drawable icon; @@ -38,20 +37,13 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OverlayColourProvider colourProvider) { - defaultBackgroundColour = colours.Gray3; - defaultBubbleColour = defaultBackgroundColour.Darken(0.5f); - selectedBackgroundColour = colours.BlueDark; - selectedBubbleColour = selectedBackgroundColour.Lighten(0.5f); + defaultBackgroundColour = colourProvider.Background3; + selectedBackgroundColour = colourProvider.Background1; - Content.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Radius = 2, - Offset = new Vector2(0, 1), - Colour = Color4.Black.Opacity(0.5f) - }; + defaultIconColour = defaultBackgroundColour.Darken(0.5f); + selectedIconColour = selectedBackgroundColour.Lighten(0.5f); Add(icon = (Button.CreateIcon?.Invoke() ?? new Circle()).With(b => { @@ -85,17 +77,17 @@ namespace osu.Game.Screens.Edit.Components.TernaryButtons switch (Button.Bindable.Value) { case TernaryState.Indeterminate: - icon.Colour = selectedBubbleColour.Darken(0.5f); + icon.Colour = selectedIconColour.Darken(0.5f); BackgroundColour = selectedBackgroundColour.Darken(0.5f); break; case TernaryState.False: - icon.Colour = defaultBubbleColour; + icon.Colour = defaultIconColour; BackgroundColour = defaultBackgroundColour; break; case TernaryState.True: - icon.Colour = selectedBubbleColour; + icon.Colour = selectedIconColour; BackgroundColour = selectedBackgroundColour; break; } From 6608ada925cc9f12987723b419e10132ee1bab37 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 16:57:37 +0900 Subject: [PATCH 1664/2686] Fix test failures due to missing colour provider dependency --- .../Editor/TestSceneOsuDistanceSnapGrid.cs | 4 ++++ .../Visual/Editing/TestSceneEditorComposeRadioButtons.cs | 5 +++++ osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs | 4 ---- osu.Game/Overlays/SettingsToolboxGroup.cs | 6 +++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs index c102678e00..dc74d38cdc 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input; using osu.Framework.Utils; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Overlays; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Edit; @@ -33,6 +34,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor [Cached(typeof(IBeatSnapProvider))] private readonly EditorBeatmap editorBeatmap; + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + [Cached] private readonly EditorClock editorClock; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorComposeRadioButtons.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorComposeRadioButtons.cs index 56435c69a4..6a69347651 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorComposeRadioButtons.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorComposeRadioButtons.cs @@ -4,8 +4,10 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Game.Overlays; using osu.Game.Screens.Edit.Components.RadioButtons; namespace osu.Game.Tests.Visual.Editing @@ -13,6 +15,9 @@ namespace osu.Game.Tests.Visual.Editing [TestFixture] public class TestSceneEditorComposeRadioButtons : OsuTestScene { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); + public TestSceneEditorComposeRadioButtons() { EditorRadioButtonCollection collection; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs index adb495f3d3..58b5b41702 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs @@ -148,10 +148,6 @@ namespace osu.Game.Tests.Visual.Editing }); AddAssert("no circles placed", () => editorBeatmap.HitObjects.Count == 0); - - AddStep("place circle", () => InputManager.Click(MouseButton.Left)); - - AddAssert("circle placed", () => editorBeatmap.HitObjects.Count == 1); } [Test] diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index 2f47019272..008479b8e0 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -70,8 +70,8 @@ namespace osu.Game.Overlays Masking = true; } - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + [BackgroundDependencyLoader(true)] + private void load(OverlayColourProvider? colourProvider) { CornerRadius = corner_radius; @@ -80,7 +80,7 @@ namespace osu.Game.Overlays background = new Box { RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, + Colour = colourProvider?.Background5 ?? Color4.Black, }, new FillFlowContainer { From a93c350ca85944d38b09744801a7ac8f6b361411 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 17:11:56 +0900 Subject: [PATCH 1665/2686] Start settings panels without background visible --- osu.Game/Overlays/SettingsToolboxGroup.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index 008479b8e0..37c8ec749d 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -80,6 +80,7 @@ namespace osu.Game.Overlays background = new Box { RelativeSizeAxes = Axes.Both, + Alpha = 0, Colour = colourProvider?.Background5 ?? Color4.Black, }, new FillFlowContainer From b33935e39225104f740fc4c9611f4d5cd13f44d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 17:12:28 +0900 Subject: [PATCH 1666/2686] Fix player loading screen settings scaling in This always looked weird, and from the looks of the structure was probably unintentional from the start (it is in the logo tracking container for whatever reason). --- osu.Game/Screens/Play/PlayerLoader.cs | 51 +++++++++++++++------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 2d096f1c38..0065520268 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -64,6 +64,8 @@ namespace osu.Game.Screens.Play protected Task? DisposalTask { get; private set; } + private OsuScrollContainer settingsScroll = null!; + private bool backgroundBrightnessReduction; private readonly BindableDouble volumeAdjustment = new BindableDouble(1); @@ -168,30 +170,30 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new OsuScrollContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RelativeSizeAxes = Axes.Y, - Width = SettingsToolboxGroup.CONTAINER_WIDTH + padding * 2, - Padding = new MarginPadding { Vertical = padding }, - Masking = false, - Child = PlayerSettings = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Padding = new MarginPadding { Horizontal = padding }, - Children = new PlayerSettingsGroup[] - { - VisualSettings = new VisualSettings(), - AudioSettings = new AudioSettings(), - new InputSettings() - } - }, - }, - idleTracker = new IdleTracker(750), }), + settingsScroll = new OsuScrollContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.Y, + Width = SettingsToolboxGroup.CONTAINER_WIDTH + padding * 2, + Padding = new MarginPadding { Vertical = padding }, + Masking = false, + Child = PlayerSettings = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Padding = new MarginPadding { Horizontal = padding }, + Children = new PlayerSettingsGroup[] + { + VisualSettings = new VisualSettings(), + AudioSettings = new AudioSettings(), + new InputSettings() + } + }, + }, + idleTracker = new IdleTracker(750), lowPassFilter = new AudioFilter(audio.TrackMixer), highPassFilter = new AudioFilter(audio.TrackMixer, BQFType.HighPass) }; @@ -392,6 +394,8 @@ namespace osu.Game.Screens.Play { MetadataInfo.Loading = true; + settingsScroll.FadeInFromZero(400); + content.FadeInFromZero(400); content.ScaleTo(1, 650, Easing.OutQuint).Then().Schedule(prepareNewPlayer); lowPassFilter.CutoffTo(1000, 650, Easing.OutQuint); @@ -407,6 +411,7 @@ namespace osu.Game.Screens.Play content.ScaleTo(0.7f, CONTENT_OUT_DURATION * 2, Easing.OutQuint); content.FadeOut(CONTENT_OUT_DURATION, Easing.OutQuint); + settingsScroll.FadeOut(CONTENT_OUT_DURATION, Easing.OutQuint); lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF, CONTENT_OUT_DURATION); highPassFilter.CutoffTo(0, CONTENT_OUT_DURATION); } From 3645269108a388196e3cb254b4acae5e54c836c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 17:29:07 +0900 Subject: [PATCH 1667/2686] Improve logo transition and reduce delay of exiting player loader in optimal conditions --- osu.Game/Screens/Play/PlayerLoader.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 0065520268..b553818a2d 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -318,6 +318,16 @@ namespace osu.Game.Screens.Play content.StopTracking(); } + protected override void LogoSuspending(OsuLogo logo) + { + base.LogoSuspending(logo); + content.StopTracking(); + + logo + .FadeOut(CONTENT_OUT_DURATION / 2, Easing.OutQuint) + .ScaleTo(logo.Scale * 0.8f, CONTENT_OUT_DURATION * 2, Easing.OutQuint); + } + #endregion protected override void Update() @@ -440,7 +450,7 @@ namespace osu.Game.Screens.Play ContentOut(); - TransformSequence pushSequence = this.Delay(CONTENT_OUT_DURATION); + TransformSequence pushSequence = this.Delay(0); // only show if the warning was created (i.e. the beatmap needs it) // and this is not a restart of the map (the warning expires after first load). @@ -449,6 +459,7 @@ namespace osu.Game.Screens.Play const double epilepsy_display_length = 3000; pushSequence + .Delay(CONTENT_OUT_DURATION) .Schedule(() => epilepsyWarning.State.Value = Visibility.Visible) .TransformBindableTo(volumeAdjustment, 0.25, EpilepsyWarning.FADE_DURATION, Easing.OutQuint) .Delay(epilepsy_display_length) From aa8040d69675ef646a4bc8f2fea0db70fb00e574 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 13 Oct 2022 15:52:06 +0300 Subject: [PATCH 1668/2686] Add hover box to beatmap card icon button --- .../Cards/Buttons/BeatmapCardIconButton.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs index c5b251cc2b..de75fceec8 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -4,13 +4,16 @@ #nullable disable using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Graphics.Containers; using osu.Game.Overlays; using osuTK; +using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { @@ -59,6 +62,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons protected override Container Content => content; private readonly Container content; + private readonly Box hover; protected BeatmapCardIconButton() { @@ -69,6 +73,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { RelativeSizeAxes = Axes.Both, Masking = true, + CornerRadius = BeatmapCard.CORNER_RADIUS, Origin = Anchor.Centre, Anchor = Anchor.Centre, Children = new Drawable[] @@ -76,8 +81,14 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons Icon = new SpriteIcon { Origin = Anchor.Centre, - Anchor = Anchor.Centre - } + Anchor = Anchor.Centre, + }, + hover = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White.Opacity(0.1f), + Blending = BlendingParameters.Additive, + }, } }); @@ -116,8 +127,9 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { bool isHovered = IsHovered && Enabled.Value; - content.ScaleTo(isHovered ? 1.2f : 1, 500, Easing.OutQuint); - content.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); + hover.FadeTo(isHovered ? 1f : 0f, 500, Easing.OutQuint); + Icon.ScaleTo(isHovered ? 1.2f : 1, 500, Easing.OutQuint); + Icon.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); } } } From 6c316bcc9e8746104b6875da8efecf0e668d8406 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 13 Oct 2022 15:52:20 +0300 Subject: [PATCH 1669/2686] Make beatmap card icon buttons fill up to the area --- .../TestSceneBeatmapCardDownloadButton.cs | 3 ++- .../TestSceneBeatmapCardFavouriteButton.cs | 12 ++++++++++-- .../Drawables/Cards/BeatmapCardExtra.cs | 1 - .../Drawables/Cards/BeatmapCardNormal.cs | 1 - .../Cards/Buttons/BeatmapCardIconButton.cs | 1 - .../Cards/CollapsibleButtonContainer.cs | 19 ++++++++++--------- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs index 10515fd95f..82e18e45bb 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs @@ -59,8 +59,9 @@ namespace osu.Game.Tests.Visual.Beatmaps { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Size = new Vector2(25f, 50f), + Scale = new Vector2(2f), State = { Value = DownloadState.NotDownloaded }, - Scale = new Vector2(2) }; }); } diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs index 2fe2264348..9540d9e4f7 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs @@ -37,7 +37,11 @@ namespace osu.Game.Tests.Visual.Beatmaps beatmapSetInfo = CreateAPIBeatmapSet(Ruleset.Value); beatmapSetInfo.HasFavourited = favourited; }); - AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) { Scale = new Vector2(2) }); + AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) + { + Size = new Vector2(25f, 50f), + Scale = new Vector2(2f), + }); assertCorrectIcon(favourited); AddAssert("correct tooltip text", () => button.TooltipText == (favourited ? BeatmapsetsStrings.ShowDetailsUnfavourite : BeatmapsetsStrings.ShowDetailsFavourite)); @@ -51,7 +55,11 @@ namespace osu.Game.Tests.Visual.Beatmaps BeatmapFavouriteAction? lastRequestAction = null; AddStep("create beatmap set", () => beatmapSetInfo = CreateAPIBeatmapSet(Ruleset.Value)); - AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) { Scale = new Vector2(2) }); + AddStep("create button", () => Child = button = new FavouriteButton(beatmapSetInfo) + { + Size = new Vector2(25f, 50f), + Scale = new Vector2(2f), + }); assertCorrectIcon(false); diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs index 4b9e5d9ae4..646c990564 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs @@ -81,7 +81,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards FavouriteState = { BindTarget = FavouriteState }, ButtonsCollapsedWidth = CORNER_RADIUS, ButtonsExpandedWidth = 30, - ButtonsPadding = new MarginPadding { Vertical = 35 }, Children = new Drawable[] { new FillFlowContainer diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs index d9ce64879f..addc88700c 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs @@ -82,7 +82,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards FavouriteState = { BindTarget = FavouriteState }, ButtonsCollapsedWidth = CORNER_RADIUS, ButtonsExpandedWidth = 30, - ButtonsPadding = new MarginPadding { Vertical = 17.5f }, Children = new Drawable[] { new FillFlowContainer diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs index de75fceec8..a4beab02ed 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -92,7 +92,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons } }); - Size = new Vector2(24); IconSize = 12; } diff --git a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs index 107c126eb5..5ace3233e2 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs @@ -48,12 +48,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards } } - public MarginPadding ButtonsPadding - { - get => buttons.Padding; - set => buttons.Padding = value; - } - protected override Container Content => mainContent; private readonly Container background; @@ -104,25 +98,32 @@ namespace osu.Game.Beatmaps.Drawables.Cards Child = buttons = new Container { RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(3), Children = new BeatmapCardIconButton[] { new FavouriteButton(beatmapSet) { Current = FavouriteState, Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Height = 0.48f, }, new DownloadButton(beatmapSet) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - State = { BindTarget = downloadTracker.State } + State = { BindTarget = downloadTracker.State }, + RelativeSizeAxes = Axes.Both, + Height = 0.48f, }, new GoToBeatmapButton(beatmapSet) { Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, - State = { BindTarget = downloadTracker.State } + State = { BindTarget = downloadTracker.State }, + RelativeSizeAxes = Axes.Both, + Height = 0.48f, } } } From ef72b66dad05a31ed45c979d9e8468d0a12c4e16 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 13 Oct 2022 16:09:50 +0300 Subject: [PATCH 1670/2686] Remove beatmap card background workaround to fix broken corners --- .../Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs index 5ace3233e2..f70694bdda 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs @@ -80,9 +80,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards RelativeSizeAxes = Axes.Both, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - // workaround for masking artifacts at the top & bottom of card, - // which become especially visible on downloaded beatmaps (when the icon area has a lime background). - Padding = new MarginPadding { Vertical = 1 }, Child = new Box { RelativeSizeAxes = Axes.Both, From df66a0c2e9ce41e5b180cf33f9e82c0864838fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 13 Oct 2022 21:03:52 +0200 Subject: [PATCH 1671/2686] Fix flaky update beatmap set test It is generally not possible to click a button that's not yet there, and it turns out that when the test in question is ran headless, it may not necessarily be there immediately. --- .../Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs index f76f050546..96cfbe4dd1 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps; @@ -150,6 +151,7 @@ namespace osu.Game.Tests.Visual.SongSelect public void TestUpdateLocalBeatmap() { DialogOverlay dialogOverlay = null!; + UpdateBeatmapSetButton? updateButton = null; AddStep("create carousel with dialog overlay", () => { @@ -176,7 +178,8 @@ namespace osu.Game.Tests.Visual.SongSelect carousel.UpdateBeatmapSet(testBeatmapSetInfo); }); - AddStep("click button", () => getUpdateButton()?.TriggerClick()); + AddUntilStep("wait for update button", () => (updateButton = getUpdateButton()) != null); + AddStep("click button", () => updateButton.AsNonNull().TriggerClick()); AddAssert("dialog displayed", () => dialogOverlay.CurrentDialog is UpdateLocalConfirmationDialog); AddStep("click confirmation", () => From e97dbf3dbce8538793ab8b477c51b5437ba75eed Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 13 Oct 2022 22:12:32 +0300 Subject: [PATCH 1672/2686] Move copy toast to its own file --- osu.Game/Graphics/UserInterface/CopyUrlToast.cs | 16 ++++++++++++++++ .../Graphics/UserInterface/ExternalLinkButton.cs | 12 +----------- 2 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/CopyUrlToast.cs diff --git a/osu.Game/Graphics/UserInterface/CopyUrlToast.cs b/osu.Game/Graphics/UserInterface/CopyUrlToast.cs new file mode 100644 index 0000000000..66aaf1a212 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/CopyUrlToast.cs @@ -0,0 +1,16 @@ +// 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.Localisation; +using osu.Game.Overlays.OSD; + +namespace osu.Game.Graphics.UserInterface +{ + public class CopyUrlToast : Toast + { + public CopyUrlToast() + : base(UserInterfaceStrings.GeneralHeader, ToastStrings.UrlCopied, "") + { + } + } +} diff --git a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs index 7f86a060ad..288539f421 100644 --- a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs +++ b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs @@ -10,10 +10,8 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Game.Localisation; using osu.Framework.Platform; using osu.Game.Overlays; -using osu.Game.Overlays.OSD; using osuTK; using osuTK.Graphics; @@ -94,15 +92,7 @@ namespace osu.Game.Graphics.UserInterface private void copyUrl() { host.GetClipboard()?.SetText(Link); - onScreenDisplay?.Display(new CopyUrlToast(ToastStrings.UrlCopied)); - } - - private class CopyUrlToast : Toast - { - public CopyUrlToast(LocalisableString value) - : base(UserInterfaceStrings.GeneralHeader, value, "") - { - } + onScreenDisplay?.Display(new CopyUrlToast()); } } } From a0cca391f6365cd892862701a1aa58d316cd2edc Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 13 Oct 2022 22:18:26 +0300 Subject: [PATCH 1673/2686] Add copy link button to comments --- osu.Game/Overlays/Comments/DrawableComment.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 193d15064a..1f18540044 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -20,6 +20,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; using osu.Framework.Localisation; +using osu.Framework.Platform; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -71,6 +72,12 @@ namespace osu.Game.Overlays.Comments [Resolved] private IAPIProvider api { get; set; } = null!; + [Resolved] + private GameHost host { get; set; } = null!; + + [Resolved(canBeNull: true)] + private OnScreenDisplay? onScreenDisplay { get; set; } + public DrawableComment(Comment comment) { Comment = comment; @@ -323,6 +330,8 @@ namespace osu.Game.Overlays.Comments if (WasDeleted) makeDeleted(); + actionsContainer.AddLink("Copy URL", copyUrl); + if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) { actionsContainer.AddLink("Delete", deleteComment); @@ -403,6 +412,12 @@ namespace osu.Game.Overlays.Comments api.Queue(request); } + private void copyUrl() + { + host.GetClipboard()?.SetText($@"https://osu.ppy.sh/comments/{Comment.Id}"); + onScreenDisplay?.Display(new CopyUrlToast()); + } + protected override void LoadComplete() { ShowDeleted.BindValueChanged(show => From 34ff072a9b2eb51837bbadedcddae25fd537707e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 13 Oct 2022 22:47:48 +0300 Subject: [PATCH 1674/2686] Change text --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 1f18540044..9c82c9aa98 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -330,7 +330,7 @@ namespace osu.Game.Overlays.Comments if (WasDeleted) makeDeleted(); - actionsContainer.AddLink("Copy URL", copyUrl); + actionsContainer.AddLink("Copy link", copyUrl); if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) { From 194bb02c28279d32c1673749824a1adfacdb4746 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 13 Oct 2022 22:47:53 +0300 Subject: [PATCH 1675/2686] Add test --- .../Visual/Online/TestSceneCommentActions.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index bf01d3b0ac..59a25880c4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -10,6 +10,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -35,6 +36,9 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + [Resolved] + private GameHost host { get; set; } = null!; + private CommentsContainer commentsContainer = null!; [BackgroundDependencyLoader] @@ -204,6 +208,22 @@ namespace osu.Game.Tests.Visual.Online }); } + [Test] + public void TestCopyLink() + { + addTestComments(); + AddUntilStep("Comments loaded", () => this.ChildrenOfType().Count() == 2); + AddStep("Click copy link", () => + { + var comment = this.ChildrenOfType().First(); + var links = comment.ChildrenOfType().Single(x => x.Name == @"Actions buttons"); + var btn = links.ChildrenOfType().Single(x => x.Text.ToString().StartsWith("Copy")); + InputManager.MoveMouseTo(btn); + InputManager.Click(MouseButton.Left); + }); + AddUntilStep("Link copied", () => host.GetClipboard()?.GetText() == "https://osu.ppy.sh/comments/1"); + } + private void addTestComments() { AddStep("set up response", () => From 310588ad94c8ef58d220d0885762435678dce116 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Thu, 13 Oct 2022 13:01:05 -0700 Subject: [PATCH 1676/2686] Renew smoke rng every draw --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 6c998e244c..8316ece2b3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -216,8 +216,6 @@ namespace osu.Game.Rulesets.Osu.Skinning SmokeEndTime = Source.smokeEndTime; CurrentTime = Source.Clock.CurrentTime; - rotationRNG = new Random(Source.rotationSeed); - initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); firstVisiblePointTime = SmokeEndTime - initialFadeOutDurationTrunc; @@ -233,6 +231,8 @@ namespace osu.Game.Rulesets.Osu.Skinning if (points.Count == 0) return; + rotationRNG = new Random(Source.rotationSeed); + quadBatch ??= renderer.CreateQuadBatch(max_point_count / 10, 10); texture ??= renderer.WhitePixel; RectangleF textureRect = texture.GetTextureRect(); From 295e6f5a680a20418857e94c24eb0c04800fec66 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 13 Oct 2022 23:57:25 +0300 Subject: [PATCH 1677/2686] Move toast to it's namespace --- osu.Game/Graphics/UserInterface/ExternalLinkButton.cs | 1 + osu.Game/Overlays/Comments/DrawableComment.cs | 1 + .../{Graphics/UserInterface => Overlays/OSD}/CopyUrlToast.cs | 3 +-- 3 files changed, 3 insertions(+), 2 deletions(-) rename osu.Game/{Graphics/UserInterface => Overlays/OSD}/CopyUrlToast.cs (83%) diff --git a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs index 288539f421..e51dbeed14 100644 --- a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs +++ b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs @@ -12,6 +12,7 @@ using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Overlays; +using osu.Game.Overlays.OSD; using osuTK; using osuTK.Graphics; diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 9c82c9aa98..7a8625906c 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -26,6 +26,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; using osu.Game.Overlays.Dialog; +using osu.Game.Overlays.OSD; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments diff --git a/osu.Game/Graphics/UserInterface/CopyUrlToast.cs b/osu.Game/Overlays/OSD/CopyUrlToast.cs similarity index 83% rename from osu.Game/Graphics/UserInterface/CopyUrlToast.cs rename to osu.Game/Overlays/OSD/CopyUrlToast.cs index 66aaf1a212..ea835a1c5e 100644 --- a/osu.Game/Graphics/UserInterface/CopyUrlToast.cs +++ b/osu.Game/Overlays/OSD/CopyUrlToast.cs @@ -2,9 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using osu.Game.Localisation; -using osu.Game.Overlays.OSD; -namespace osu.Game.Graphics.UserInterface +namespace osu.Game.Overlays.OSD { public class CopyUrlToast : Toast { From a375c3389b0646c26f418683d2bdc500221623fd Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 13 Oct 2022 23:59:36 +0300 Subject: [PATCH 1678/2686] Delete the test --- .../Visual/Online/TestSceneCommentActions.cs | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 59a25880c4..bf01d3b0ac 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -10,7 +10,6 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -36,9 +35,6 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - [Resolved] - private GameHost host { get; set; } = null!; - private CommentsContainer commentsContainer = null!; [BackgroundDependencyLoader] @@ -208,22 +204,6 @@ namespace osu.Game.Tests.Visual.Online }); } - [Test] - public void TestCopyLink() - { - addTestComments(); - AddUntilStep("Comments loaded", () => this.ChildrenOfType().Count() == 2); - AddStep("Click copy link", () => - { - var comment = this.ChildrenOfType().First(); - var links = comment.ChildrenOfType().Single(x => x.Name == @"Actions buttons"); - var btn = links.ChildrenOfType().Single(x => x.Text.ToString().StartsWith("Copy")); - InputManager.MoveMouseTo(btn); - InputManager.Click(MouseButton.Left); - }); - AddUntilStep("Link copied", () => host.GetClipboard()?.GetText() == "https://osu.ppy.sh/comments/1"); - } - private void addTestComments() { AddStep("set up response", () => From 8a47628fe1c98a46c68b0037e41efa1a34bb9452 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 14 Oct 2022 00:04:13 +0300 Subject: [PATCH 1679/2686] Use spacer drawable instead of spacing on links container --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 7a8625906c..59f6b74722 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -211,7 +211,6 @@ namespace osu.Game.Overlays.Comments { Name = @"Actions buttons", AutoSizeAxes = Axes.Both, - Spacing = new Vector2(10, 0) }, actionsLoading = new LoadingSpinner { @@ -332,6 +331,7 @@ namespace osu.Game.Overlays.Comments makeDeleted(); actionsContainer.AddLink("Copy link", copyUrl); + actionsContainer.AddArbitraryDrawable(new Container { Width = 10 }); if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) { From 3e5e717fce3a47983793f60ef8147aa624178b84 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 14 Oct 2022 01:59:55 +0300 Subject: [PATCH 1680/2686] Add failing test cases --- .../TestSceneModSelectOverlay.cs | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 4c43a2fdcd..0292ce5905 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -17,6 +17,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Mods; using osu.Game.Overlays.Settings; using osu.Game.Rulesets; +using osu.Game.Rulesets.Catch.Mods; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; @@ -338,26 +339,36 @@ namespace osu.Game.Tests.Visual.UserInterface } [Test] - public void TestRulesetChanges() + public void TestCommonModsMaintainedOnRulesetChange() { createScreen(); changeRuleset(0); - var noFailMod = new OsuRuleset().GetModsFor(ModType.DifficultyReduction).FirstOrDefault(m => m is OsuModNoFail); - - AddStep("set mods externally", () => { SelectedMods.Value = new[] { noFailMod }; }); + AddStep("select relax mod", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateMod() }); changeRuleset(0); + AddAssert("ensure mod still selected", () => SelectedMods.Value.SingleOrDefault() is OsuModRelax); - AddAssert("ensure mods still selected", () => SelectedMods.Value.SingleOrDefault(m => m is OsuModNoFail) != null); + changeRuleset(2); + AddAssert("catch variant selected", () => SelectedMods.Value.SingleOrDefault() is CatchModRelax); changeRuleset(3); + AddAssert("no mod selected", () => SelectedMods.Value.Count == 0); + } - AddAssert("ensure mods not selected", () => SelectedMods.Value.Count == 0); - + [Test] + public void TestUncommonModsDiscardedOnRulesetChange() + { + createScreen(); changeRuleset(0); - AddAssert("ensure mods not selected", () => SelectedMods.Value.Count == 0); + AddStep("select single tap mod", () => SelectedMods.Value = new[] { new OsuModSingleTap() }); + + changeRuleset(0); + AddAssert("ensure mod still selected", () => SelectedMods.Value.SingleOrDefault() is OsuModSingleTap); + + changeRuleset(3); + AddAssert("no mod selected", () => SelectedMods.Value.Count == 0); } [Test] From 739b21ab3bb3245910ce1115e6f6003fa589e2c1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 14 Oct 2022 02:02:24 +0300 Subject: [PATCH 1681/2686] Maintain mod selection on ruleset change for common mods --- osu.Game/OsuGameBase.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 478f154d58..662d165580 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -586,11 +586,16 @@ namespace osu.Game return; } + var previouslySelectedMods = SelectedMods.Value.ToArray(); + if (!SelectedMods.Disabled) SelectedMods.Value = Array.Empty(); AvailableMods.Value = dict; + if (!SelectedMods.Disabled) + SelectedMods.Value = previouslySelectedMods.Select(m => instance.CreateModFromAcronym(m.Acronym)).Where(m => m != null).ToArray(); + void revertRulesetChange() => Ruleset.Value = r.OldValue?.Available == true ? r.OldValue : RulesetStore.AvailableRulesets.First(); } From 01c65d3cc1281da68e501506785724ac5e2f9f58 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 14 Oct 2022 02:16:23 +0300 Subject: [PATCH 1682/2686] Remove seemingly unnecessary/leftover code --- osu.Game/Screens/Select/SongSelect.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index ece94b5365..f5a058e945 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -502,8 +502,6 @@ namespace osu.Game.Screens.Select if (transferRulesetValue()) { - Mods.Value = Array.Empty(); - // transferRulesetValue() may trigger a re-filter. If the current selection does not match the new ruleset, we want to switch away from it. // The default logic on WorkingBeatmap change is to switch to a matching ruleset (see workingBeatmapChanged()), but we don't want that here. // We perform an early selection attempt and clear out the beatmap selection to avoid a second ruleset change (revert). From 029f896db86b07371849a1440c295427878ac9fd Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Thu, 13 Oct 2022 16:18:47 -0700 Subject: [PATCH 1683/2686] Use `StatelessRNG` for smoke rotation --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 8316ece2b3..7af1b5d86a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; +using osu.Game.Utils; using osuTK; using osuTK.Graphics; @@ -185,6 +186,8 @@ namespace osu.Game.Rulesets.Osu.Skinning private float radius; private Vector2 drawSize; private Texture? texture; + private int rotationSeed; + private int rotationIndex; // anim calculation vars (color, scale, direction) private double initialFadeOutDurationTrunc; @@ -194,8 +197,6 @@ namespace osu.Game.Rulesets.Osu.Skinning private double reFadeInTime; private double finalFadeOutTime; - private Random rotationRNG = new Random(); - public SmokeDrawNode(ITexturedShaderDrawable source) : base(source) { @@ -216,6 +217,8 @@ namespace osu.Game.Rulesets.Osu.Skinning SmokeEndTime = Source.smokeEndTime; CurrentTime = Source.Clock.CurrentTime; + rotationSeed = Source.rotationSeed; + initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); firstVisiblePointTime = SmokeEndTime - initialFadeOutDurationTrunc; @@ -231,7 +234,7 @@ namespace osu.Game.Rulesets.Osu.Skinning if (points.Count == 0) return; - rotationRNG = new Random(Source.rotationSeed); + rotationIndex = rotationSeed; quadBatch ??= renderer.CreateQuadBatch(max_point_count / 10, 10); texture ??= renderer.WhitePixel; @@ -311,7 +314,11 @@ namespace osu.Game.Rulesets.Osu.Skinning return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); } - private float nextRotation() => max_rotation * ((float)rotationRNG.NextDouble() * 2 - 1); + private float nextRotation() + { + rotationIndex++; + return max_rotation * (StatelessRNG.NextSingle(rotationIndex) * 2 - 1); + } private void drawPointQuad(SmokePoint point, RectangleF textureRect) { From 516e99df7264b59fe4097bfffb358bf3c88e1e44 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 14 Oct 2022 02:38:43 +0300 Subject: [PATCH 1684/2686] Add test coverage for flashlight mod --- .../Mods/TestSceneCatchModFlashlight.cs | 23 +++++++++++++++++ .../Mods/TestSceneManiaModFlashlight.cs | 23 +++++++++++++++++ .../Mods/TestSceneOsuModFlashlight.cs | 25 +++++++++++++++++++ .../TestSceneOsuFlashlight.cs | 21 ---------------- .../Mods/TestSceneTaikoModFlashlight.cs | 20 +++++++++++++++ 5 files changed, 91 insertions(+), 21 deletions(-) create mode 100644 osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModFlashlight.cs create mode 100644 osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFlashlight.cs create mode 100644 osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFlashlight.cs delete mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs create mode 100644 osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModFlashlight.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModFlashlight.cs new file mode 100644 index 0000000000..538fc7fac6 --- /dev/null +++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModFlashlight.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Catch.Mods; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Catch.Tests.Mods +{ + public class TestSceneCatchModFlashlight : ModTestScene + { + protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); + + [TestCase(1f)] + [TestCase(0.5f)] + [TestCase(1.25f)] + [TestCase(1.5f)] + public void TestSizeMultiplier(float sizeMultiplier) => CreateModTest(new ModTestData { Mod = new CatchModFlashlight { SizeMultiplier = { Value = sizeMultiplier } }, PassCondition = () => true }); + + [Test] + public void TestComboBasedSize([Values] bool comboBasedSize) => CreateModTest(new ModTestData { Mod = new CatchModFlashlight { ComboBasedSize = { Value = comboBasedSize } }, PassCondition = () => true }); + } +} diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFlashlight.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFlashlight.cs new file mode 100644 index 0000000000..0e222fea89 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFlashlight.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Mania.Tests.Mods +{ + public class TestSceneManiaModFlashlight : ModTestScene + { + protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); + + [TestCase(1f)] + [TestCase(0.5f)] + [TestCase(1.5f)] + [TestCase(3f)] + public void TestSizeMultiplier(float sizeMultiplier) => CreateModTest(new ModTestData { Mod = new ManiaModFlashlight { SizeMultiplier = { Value = sizeMultiplier } }, PassCondition = () => true }); + + [Test] + public void TestComboBasedSize([Values] bool comboBasedSize) => CreateModTest(new ModTestData { Mod = new ManiaModFlashlight { ComboBasedSize = { Value = comboBasedSize } }, PassCondition = () => true }); + } +} diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFlashlight.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFlashlight.cs new file mode 100644 index 0000000000..704a548c61 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFlashlight.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Osu.Mods; + +namespace osu.Game.Rulesets.Osu.Tests.Mods +{ + public class TestSceneOsuModFlashlight : OsuModTestScene + { + [TestCase(600)] + [TestCase(120)] + [TestCase(1200)] + public void TestFollowDelay(double followDelay) => CreateModTest(new ModTestData { Mod = new OsuModFlashlight { FollowDelay = { Value = followDelay } }, PassCondition = () => true }); + + [TestCase(1f)] + [TestCase(0.5f)] + [TestCase(1.5f)] + [TestCase(2f)] + public void TestSizeMultiplier(float sizeMultiplier) => CreateModTest(new ModTestData { Mod = new OsuModFlashlight { SizeMultiplier = { Value = sizeMultiplier } }, PassCondition = () => true }); + + [Test] + public void TestComboBasedSize([Values] bool comboBasedSize) => CreateModTest(new ModTestData { Mod = new OsuModFlashlight { ComboBasedSize = { Value = comboBasedSize } }, PassCondition = () => true }); + } +} diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs deleted file mode 100644 index e0d1646cb0..0000000000 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Tests.Visual; - -namespace osu.Game.Rulesets.Osu.Tests -{ - public class TestSceneOsuFlashlight : TestSceneOsuPlayer - { - protected override TestPlayer CreatePlayer(Ruleset ruleset) - { - SelectedMods.Value = new Mod[] { new OsuModAutoplay(), new OsuModFlashlight(), }; - - return base.CreatePlayer(ruleset); - } - } -} diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs new file mode 100644 index 0000000000..417b59f5d2 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs @@ -0,0 +1,20 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Rulesets.Taiko.Mods; + +namespace osu.Game.Rulesets.Taiko.Tests.Mods +{ + public class TestSceneTaikoModFlashlight : TaikoModTestScene + { + [TestCase(1f)] + [TestCase(0.5f)] + [TestCase(1.25f)] + [TestCase(1.5f)] + public void TestSizeMultiplier(float sizeMultiplier) => CreateModTest(new ModTestData { Mod = new TaikoModFlashlight { SizeMultiplier = { Value = sizeMultiplier } }, PassCondition = () => true }); + + [Test] + public void TestComboBasedSize([Values] bool comboBasedSize) => CreateModTest(new ModTestData { Mod = new TaikoModFlashlight { ComboBasedSize = { Value = comboBasedSize } }, PassCondition = () => true }); + } +} From b43bae122c1ec719b074b7f2e1ac39cbda338541 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 14 Oct 2022 13:40:48 +0900 Subject: [PATCH 1685/2686] Fix incorrect porting of code --- osu.Game/Graphics/OsuColour.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index bd0604bb76..0f055856d3 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -302,11 +302,10 @@ namespace osu.Game.Graphics if (minOverMax > 0f) { - float part = 1f + colour.R * (1f / minOverMax - 1f); - if (colour.R < 1f / 6f) { colour.R = 6f * (colour.R - 0f / 6f); + float part = 1f + colour.R * (1f / minOverMax - 1f); result.B = colour.B / MathF.Sqrt(p_r / minOverMax / minOverMax + p_g * part * part + p_b); result.R = result.B / minOverMax; result.G = result.B + colour.R * (result.R - result.B); @@ -314,13 +313,15 @@ namespace osu.Game.Graphics else if (colour.R < 2f / 6f) { colour.R = 6f * (-colour.R + 2f / 6f); + float part = 1f + colour.R * (1f / minOverMax - 1f); result.B = colour.B / MathF.Sqrt(p_g / minOverMax / minOverMax + p_r * part * part + p_b); result.G = result.B / minOverMax; - result.R = result.B + colour.R * (result.R - result.B); + result.R = result.B + colour.R * (result.G - result.B); } else if (colour.R < 3f / 6f) { colour.R = 6f * (colour.R - 2f / 6f); + float part = 1f + colour.R * (1f / minOverMax - 1f); result.R = colour.B / MathF.Sqrt(p_g / minOverMax / minOverMax + p_b * part * part + p_r); result.G = result.R / minOverMax; result.B = result.R + colour.R * (result.G - result.R); @@ -328,6 +329,7 @@ namespace osu.Game.Graphics else if (colour.R < 4f / 6f) { colour.R = 6f * (-colour.R + 4f / 6f); + float part = 1f + colour.R * (1f / minOverMax - 1f); result.R = colour.B / MathF.Sqrt(p_b / minOverMax / minOverMax + p_g * part * part + p_r); result.B = result.R / minOverMax; result.G = result.R + colour.R * (result.B - result.R); @@ -335,6 +337,7 @@ namespace osu.Game.Graphics else if (colour.R < 5f / 6f) { colour.R = 6f * (colour.R - 4f / 6f); + float part = 1f + colour.R * (1f / minOverMax - 1f); result.G = colour.B / MathF.Sqrt(p_b / minOverMax / minOverMax + p_r * part * part + p_g); result.B = result.G / minOverMax; result.R = result.G + colour.R * (result.B - result.G); @@ -342,6 +345,7 @@ namespace osu.Game.Graphics else { colour.R = 6f * (-colour.R + 6f / 6f); + float part = 1f + colour.R * (1f / minOverMax - 1f); result.G = colour.B / MathF.Sqrt(p_r / minOverMax / minOverMax + p_b * part * part + p_g); result.R = result.G / minOverMax; result.B = result.G + colour.R * (result.R - result.G); From 15db65c037c22f672272733fb4b8e1d9a25f731b Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 14 Oct 2022 14:12:48 +0900 Subject: [PATCH 1686/2686] Extract to struct, add dictionary term --- osu.Game/Graphics/HSPAColour.cs | 200 ++++++++++++++++++ osu.Game/Graphics/OsuColour.cs | 171 --------------- .../Objects/Drawables/DrawableHitObject.cs | 4 +- osu.sln.DotSettings | 1 + 4 files changed, 202 insertions(+), 174 deletions(-) create mode 100644 osu.Game/Graphics/HSPAColour.cs diff --git a/osu.Game/Graphics/HSPAColour.cs b/osu.Game/Graphics/HSPAColour.cs new file mode 100644 index 0000000000..5e3bc29b7e --- /dev/null +++ b/osu.Game/Graphics/HSPAColour.cs @@ -0,0 +1,200 @@ +// 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 osuTK.Graphics; + +namespace osu.Game.Graphics +{ + public struct HSPAColour + { + private const float p_r = 0.299f; + private const float p_g = 0.587f; + private const float p_b = 0.114f; + + /// + /// The hue. + /// + public float H; + + /// + /// The saturation. + /// + public float S; + + /// + /// The perceived brightness of this colour. + /// + public float P; + + /// + /// The alpha. + /// + public float A; + + public HSPAColour(float h, float s, float p, float a) + { + H = h; + S = s; + P = p; + A = a; + } + + public HSPAColour(Color4 colour) + { + H = 0; + S = 0; + P = MathF.Sqrt(colour.R * colour.R * p_r + colour.G * colour.G * p_g + colour.B + colour.B * p_b); + A = colour.A; + + if (colour.R == colour.G && colour.R == colour.B) + return; + + if (colour.R >= colour.G && colour.R >= colour.B) + { + if (colour.B >= colour.G) + { + H = 6f / 6f - 1f / 6f * (colour.B - colour.G) / (colour.R - colour.G); + S = 1f - colour.G / colour.R; + } + else + { + H = 0f / 6f + 1f / 6f * (colour.G - colour.B) / (colour.R - colour.B); + S = 1f - colour.B / colour.R; + } + } + else if (colour.G >= colour.R && colour.G >= colour.B) + { + if (colour.R >= colour.B) + { + H = 2f / 6f - 1f / 6f * (colour.R - colour.B) / (colour.G - colour.B); + S = 1f - colour.B / colour.G; + } + else + { + H = 2f / 6f + 1f / 6f * (colour.B - colour.R) / (colour.G - colour.R); + S = 1f - colour.R / colour.G; + } + } + else + { + if (colour.G >= colour.R) + { + H = 4f / 6f - 1f / 6f * (colour.G - colour.R) / (colour.B - colour.R); + S = 1f - colour.R / colour.B; + } + else + { + H = 4f / 6f + 1f / 6f * (colour.R - colour.G) / (colour.B - colour.G); + S = 1f - colour.G / colour.B; + } + } + } + + public Color4 ToColor4() + { + float minOverMax = 1f - S; + + Color4 result = new Color4 { A = A }; + + if (minOverMax > 0f) + { + if (H < 1f / 6f) + { + H = 6f * (H - 0f / 6f); + float part = 1f + H * (1f / minOverMax - 1f); + result.B = P / MathF.Sqrt(p_r / minOverMax / minOverMax + p_g * part * part + p_b); + result.R = result.B / minOverMax; + result.G = result.B + H * (result.R - result.B); + } + else if (H < 2f / 6f) + { + H = 6f * (-H + 2f / 6f); + float part = 1f + H * (1f / minOverMax - 1f); + result.B = P / MathF.Sqrt(p_g / minOverMax / minOverMax + p_r * part * part + p_b); + result.G = result.B / minOverMax; + result.R = result.B + H * (result.G - result.B); + } + else if (H < 3f / 6f) + { + H = 6f * (H - 2f / 6f); + float part = 1f + H * (1f / minOverMax - 1f); + result.R = P / MathF.Sqrt(p_g / minOverMax / minOverMax + p_b * part * part + p_r); + result.G = result.R / minOverMax; + result.B = result.R + H * (result.G - result.R); + } + else if (H < 4f / 6f) + { + H = 6f * (-H + 4f / 6f); + float part = 1f + H * (1f / minOverMax - 1f); + result.R = P / MathF.Sqrt(p_b / minOverMax / minOverMax + p_g * part * part + p_r); + result.B = result.R / minOverMax; + result.G = result.R + H * (result.B - result.R); + } + else if (H < 5f / 6f) + { + H = 6f * (H - 4f / 6f); + float part = 1f + H * (1f / minOverMax - 1f); + result.G = P / MathF.Sqrt(p_b / minOverMax / minOverMax + p_r * part * part + p_g); + result.B = result.G / minOverMax; + result.R = result.G + H * (result.B - result.G); + } + else + { + H = 6f * (-H + 6f / 6f); + float part = 1f + H * (1f / minOverMax - 1f); + result.G = P / MathF.Sqrt(p_r / minOverMax / minOverMax + p_b * part * part + p_g); + result.R = result.G / minOverMax; + result.B = result.G + H * (result.R - result.G); + } + } + else + { + if (H < 1f / 6f) + { + H = 6f * (H - 0f / 6f); + result.R = MathF.Sqrt(P * P / (p_r + p_g * H * H)); + result.G = result.R * H; + result.B = 0f; + } + else if (H < 2f / 6f) + { + H = 6f * (-H + 2f / 6f); + result.G = MathF.Sqrt(P * P / (p_g + p_r * H * H)); + result.R = result.G * H; + result.B = 0f; + } + else if (H < 3f / 6f) + { + H = 6f * (H - 2f / 6f); + result.G = MathF.Sqrt(P * P / (p_g + p_b * H * H)); + result.B = result.G * H; + result.R = 0f; + } + else if (H < 4f / 6f) + { + H = 6f * (-H + 4f / 6f); + result.B = MathF.Sqrt(P * P / (p_b + p_g * H * H)); + result.G = result.B * H; + result.R = 0f; + } + else if (H < 5f / 6f) + { + H = 6f * (H - 4f / 6f); + result.B = MathF.Sqrt(P * P / (p_b + p_r * H * H)); + result.R = result.B * H; + result.G = 0f; + } + else + { + H = 6f * (-H + 6f / 6f); + result.R = MathF.Sqrt(P * P / (p_r + p_b * H * H)); + result.B = result.R * H; + result.G = 0f; + } + } + + return result; + } + } +} diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index 0f055856d3..91161d5c71 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -229,177 +229,6 @@ namespace osu.Game.Graphics return Gray(brightness > 0.5f ? 0.2f : 0.9f); } - /// - /// Converts RGBA to HSPA. - /// - public static Color4 ToHSPA(Color4 colour) - { - const float p_r = 0.299f; - const float p_g = 0.587f; - const float p_b = 0.114f; - - Color4 result = new Color4 - { - A = colour.A, - B = MathF.Sqrt(colour.R * colour.R * p_r + colour.G * colour.G * p_g + colour.B + colour.B * p_b) - }; - - if (colour.R == colour.G && colour.R == colour.B) - return result; - - if (colour.R >= colour.G && colour.R >= colour.B) - { - if (colour.B >= colour.G) - { - result.R = 6f / 6f - 1f / 6f * (colour.B - colour.G) / (colour.R - colour.G); - result.G = 1f - colour.G / colour.R; - } - else - { - result.R = 0f / 6f + 1f / 6f * (colour.G - colour.B) / (colour.R - colour.B); - result.G = 1f - colour.B / colour.R; - } - } - else if (colour.G >= colour.R && colour.G >= colour.B) - { - if (colour.R >= colour.B) - { - result.R = 2f / 6f - 1f / 6f * (colour.R - colour.B) / (colour.G - colour.B); - result.G = 1f - colour.B / colour.G; - } - else - { - result.R = 2f / 6f + 1f / 6f * (colour.B - colour.R) / (colour.G - colour.R); - result.G = 1f - colour.R / colour.G; - } - } - else - { - if (colour.G >= colour.R) - { - result.R = 4f / 6f - 1f / 6f * (colour.G - colour.R) / (colour.B - colour.R); - result.G = 1f - colour.R / colour.B; - } - else - { - result.R = 4f / 6f + 1f / 6f * (colour.R - colour.G) / (colour.B - colour.G); - result.G = 1f - colour.G / colour.B; - } - } - - return result; - } - - public static Color4 FromHSPA(Color4 colour) - { - const float p_r = 0.299f; - const float p_g = 0.587f; - const float p_b = 0.114f; - - float minOverMax = 1f - colour.G; - - Color4 result = new Color4 { A = colour.A }; - - if (minOverMax > 0f) - { - if (colour.R < 1f / 6f) - { - colour.R = 6f * (colour.R - 0f / 6f); - float part = 1f + colour.R * (1f / minOverMax - 1f); - result.B = colour.B / MathF.Sqrt(p_r / minOverMax / minOverMax + p_g * part * part + p_b); - result.R = result.B / minOverMax; - result.G = result.B + colour.R * (result.R - result.B); - } - else if (colour.R < 2f / 6f) - { - colour.R = 6f * (-colour.R + 2f / 6f); - float part = 1f + colour.R * (1f / minOverMax - 1f); - result.B = colour.B / MathF.Sqrt(p_g / minOverMax / minOverMax + p_r * part * part + p_b); - result.G = result.B / minOverMax; - result.R = result.B + colour.R * (result.G - result.B); - } - else if (colour.R < 3f / 6f) - { - colour.R = 6f * (colour.R - 2f / 6f); - float part = 1f + colour.R * (1f / minOverMax - 1f); - result.R = colour.B / MathF.Sqrt(p_g / minOverMax / minOverMax + p_b * part * part + p_r); - result.G = result.R / minOverMax; - result.B = result.R + colour.R * (result.G - result.R); - } - else if (colour.R < 4f / 6f) - { - colour.R = 6f * (-colour.R + 4f / 6f); - float part = 1f + colour.R * (1f / minOverMax - 1f); - result.R = colour.B / MathF.Sqrt(p_b / minOverMax / minOverMax + p_g * part * part + p_r); - result.B = result.R / minOverMax; - result.G = result.R + colour.R * (result.B - result.R); - } - else if (colour.R < 5f / 6f) - { - colour.R = 6f * (colour.R - 4f / 6f); - float part = 1f + colour.R * (1f / minOverMax - 1f); - result.G = colour.B / MathF.Sqrt(p_b / minOverMax / minOverMax + p_r * part * part + p_g); - result.B = result.G / minOverMax; - result.R = result.G + colour.R * (result.B - result.G); - } - else - { - colour.R = 6f * (-colour.R + 6f / 6f); - float part = 1f + colour.R * (1f / minOverMax - 1f); - result.G = colour.B / MathF.Sqrt(p_r / minOverMax / minOverMax + p_b * part * part + p_g); - result.R = result.G / minOverMax; - result.B = result.G + colour.R * (result.R - result.G); - } - } - else - { - if (colour.R < 1f / 6f) - { - colour.R = 6f * (colour.R - 0f / 6f); - result.R = MathF.Sqrt(colour.B * colour.B / (p_r + p_g * colour.R * colour.R)); - result.G = result.R * colour.R; - result.B = 0f; - } - else if (colour.R < 2f / 6f) - { - colour.R = 6f * (-colour.R + 2f / 6f); - result.G = MathF.Sqrt(colour.B * colour.B / (p_g + p_r * colour.R * colour.R)); - result.R = result.G * colour.R; - result.B = 0f; - } - else if (colour.R < 3f / 6f) - { - colour.R = 6f * (colour.R - 2f / 6f); - result.G = MathF.Sqrt(colour.B * colour.B / (p_g + p_b * colour.R * colour.R)); - result.B = result.G * colour.R; - result.R = 0f; - } - else if (colour.R < 4f / 6f) - { - colour.R = 6f * (-colour.R + 4f / 6f); - result.B = MathF.Sqrt(colour.B * colour.B / (p_b + p_g * colour.R * colour.R)); - result.G = result.B * colour.R; - result.R = 0f; - } - else if (colour.R < 5f / 6f) - { - colour.R = 6f * (colour.R - 4f / 6f); - result.B = MathF.Sqrt(colour.B * colour.B / (p_b + p_r * colour.R * colour.R)); - result.R = result.B * colour.R; - result.G = 0f; - } - else - { - colour.R = 6f * (-colour.R + 6f / 6f); - result.R = MathF.Sqrt(colour.B * colour.B / (p_r + p_b * colour.R * colour.R)); - result.B = result.R * colour.R; - result.G = 0f; - } - } - - return result; - } - public readonly Color4 TeamColourRed = Color4Extensions.FromHex("#AA1414"); public readonly Color4 TeamColourBlue = Color4Extensions.FromHex("#1462AA"); diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 0ef15ed5c2..4ba64687db 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -527,9 +527,7 @@ namespace osu.Game.Rulesets.Objects.Drawables Color4 colour = combo.GetComboColour(CurrentSkin); // Normalise the combo colour to the given brightness level. - colour = OsuColour.ToHSPA(colour); - colour.B = comboColourBrightness.Value; - colour = OsuColour.FromHSPA(colour); + colour = new HSPAColour(colour) { P = comboColourBrightness.Value }.ToColor4(); AccentColour.Value = colour; } diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 44df495929..154ad0fe8c 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -334,6 +334,7 @@ GL GLSL HID + HSPA HSV HTML HUD From 8a88339e787293a7b585acce105aaff236f2c565 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 14 Oct 2022 14:37:24 +0900 Subject: [PATCH 1687/2686] Allow combo colour normalisation to be disabled --- osu.Game/Configuration/OsuConfigManager.cs | 3 +++ .../Sections/Gameplay/BeatmapSettings.cs | 23 +++++++++++++++++-- .../Objects/Drawables/DrawableHitObject.cs | 6 ++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index b433d81f31..33e61372da 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -175,6 +175,8 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f); SetDefault(OsuSetting.LastProcessedMetadataId, -1); + + SetDefault(OsuSetting.NormaliseComboColourBrightness, false); SetDefault(OsuSetting.ComboColourBrightness, 0.7f, 0f, 1f); } @@ -372,6 +374,7 @@ namespace osu.Game.Configuration AutomaticallyDownloadWhenSpectating, ShowOnlineExplicitContent, LastProcessedMetadataId, + NormaliseComboColourBrightness, ComboColourBrightness } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs index 16b7b74f38..0de8f6509f 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs @@ -4,6 +4,7 @@ #nullable disable using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; @@ -15,9 +16,15 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { protected override LocalisableString Header => GameplaySettingsStrings.BeatmapHeader; + private readonly BindableFloat comboColourBrightness = new BindableFloat(); + private readonly BindableBool normaliseComboColourBrightness = new BindableBool(); + [BackgroundDependencyLoader] private void load(OsuConfigManager config) { + config.BindWith(OsuSetting.ComboColourBrightness, comboColourBrightness); + config.BindWith(OsuSetting.NormaliseComboColourBrightness, normaliseComboColourBrightness); + Children = new Drawable[] { new SettingsCheckbox @@ -40,13 +47,25 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay LabelText = GraphicsSettingsStrings.StoryboardVideo, Current = config.GetBindable(OsuSetting.ShowStoryboard) }, + new SettingsCheckbox + { + LabelText = "Normalise combo colour brightness", + Current = normaliseComboColourBrightness + }, new SettingsSlider { LabelText = "Combo colour brightness", - Current = config.GetBindable(OsuSetting.ComboColourBrightness), - DisplayAsPercentage = true + Current = comboColourBrightness, + DisplayAsPercentage = true, } }; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + normaliseComboColourBrightness.BindValueChanged(normalise => comboColourBrightness.Disabled = !normalise.NewValue, true); + } } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 4ba64687db..7e2f93dced 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -129,6 +129,7 @@ namespace osu.Game.Rulesets.Objects.Drawables private readonly Bindable comboIndexBindable = new Bindable(); private readonly Bindable positionalHitsoundsLevel = new Bindable(); + private readonly Bindable normaliseComboColourBrightness = new Bindable(); private readonly Bindable comboColourBrightness = new Bindable(); private readonly Bindable comboIndexWithOffsetsBindable = new Bindable(); @@ -173,6 +174,7 @@ namespace osu.Game.Rulesets.Objects.Drawables private void load(OsuConfigManager config, ISkinSource skinSource) { config.BindWith(OsuSetting.PositionalHitsoundsLevel, positionalHitsoundsLevel); + config.BindWith(OsuSetting.NormaliseComboColourBrightness, normaliseComboColourBrightness); config.BindWith(OsuSetting.ComboColourBrightness, comboColourBrightness); // Explicit non-virtual function call in case a DrawableHitObject overrides AddInternal. @@ -195,6 +197,7 @@ namespace osu.Game.Rulesets.Objects.Drawables comboIndexBindable.BindValueChanged(_ => UpdateComboColour()); comboIndexWithOffsetsBindable.BindValueChanged(_ => UpdateComboColour(), true); + normaliseComboColourBrightness.BindValueChanged(_ => UpdateComboColour()); comboColourBrightness.BindValueChanged(_ => UpdateComboColour()); // Apply transforms @@ -527,7 +530,8 @@ namespace osu.Game.Rulesets.Objects.Drawables Color4 colour = combo.GetComboColour(CurrentSkin); // Normalise the combo colour to the given brightness level. - colour = new HSPAColour(colour) { P = comboColourBrightness.Value }.ToColor4(); + if (normaliseComboColourBrightness.Value) + colour = new HSPAColour(colour) { P = comboColourBrightness.Value }.ToColor4(); AccentColour.Value = colour; } From 525f98c1581540116a8633b76076ec67362bd396 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 14 Oct 2022 18:01:54 +0900 Subject: [PATCH 1688/2686] Fix max combo missing from playlists results screen --- osu.Game/Online/Rooms/MultiplayerScore.cs | 4 +++- .../Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Rooms/MultiplayerScore.cs b/osu.Game/Online/Rooms/MultiplayerScore.cs index 6f597e5b10..d5e0c7a970 100644 --- a/osu.Game/Online/Rooms/MultiplayerScore.cs +++ b/osu.Game/Online/Rooms/MultiplayerScore.cs @@ -65,7 +65,7 @@ namespace osu.Game.Online.Rooms [CanBeNull] public MultiplayerScoresAround ScoresAround { get; set; } - public ScoreInfo CreateScoreInfo(RulesetStore rulesets, PlaylistItem playlistItem, [NotNull] BeatmapInfo beatmap) + public ScoreInfo CreateScoreInfo(ScoreManager scoreManager, RulesetStore rulesets, PlaylistItem playlistItem, [NotNull] BeatmapInfo beatmap) { var ruleset = rulesets.GetRuleset(playlistItem.RulesetID); if (ruleset == null) @@ -90,6 +90,8 @@ namespace osu.Game.Online.Rooms Position = Position, }; + scoreManager.PopulateMaximumStatistics(scoreInfo); + return scoreInfo; } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs index 41633c34ce..27193d3cb6 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs @@ -182,7 +182,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists /// An optional pivot around which the scores were retrieved. private void performSuccessCallback([NotNull] Action> callback, [NotNull] List scores, [CanBeNull] MultiplayerScores pivot = null) => Schedule(() => { - var scoreInfos = scoreManager.OrderByTotalScore(scores.Select(s => s.CreateScoreInfo(rulesets, playlistItem, Beatmap.Value.BeatmapInfo))).ToArray(); + var scoreInfos = scoreManager.OrderByTotalScore(scores.Select(s => s.CreateScoreInfo(scoreManager, rulesets, playlistItem, Beatmap.Value.BeatmapInfo))).ToArray(); // Select a score if we don't already have one selected. // Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll). From 2404bb42b9d2fc6980d5cffa305b63a4be733944 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Oct 2022 19:33:49 +0900 Subject: [PATCH 1689/2686] Use 10% alpha rather than 0% when toolbox is not hovered --- osu.Game/Overlays/SettingsToolboxGroup.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index 37c8ec749d..27f727c9e3 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -80,7 +80,7 @@ namespace osu.Game.Overlays background = new Box { RelativeSizeAxes = Axes.Both, - Alpha = 0, + Alpha = 0.1f, Colour = colourProvider?.Background5 ?? Color4.Black, }, new FillFlowContainer @@ -184,7 +184,7 @@ namespace osu.Game.Overlays { const float fade_duration = 500; - background.FadeTo(IsHovered ? 1 : 0, fade_duration, Easing.OutQuint); + background.FadeTo(IsHovered ? 1 : 0.1f, fade_duration, Easing.OutQuint); expandButton.FadeTo(IsHovered ? 1 : 0, fade_duration, Easing.OutQuint); } } From 32c3e35762eeb42f8088717f99097594278504b0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Oct 2022 19:38:27 +0900 Subject: [PATCH 1690/2686] Change background colour to a lighter tint to avoid clash with slider bars --- osu.Game/Overlays/SettingsToolboxGroup.cs | 2 +- osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index 27f727c9e3..04c9a626b5 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -81,7 +81,7 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, Alpha = 0.1f, - Colour = colourProvider?.Background5 ?? Color4.Black, + Colour = colourProvider?.Background4 ?? Color4.Black, }, new FillFlowContainer { diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index 5f1f7a1fbf..667a3cb409 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -71,7 +71,6 @@ namespace osu.Game.Rulesets.Edit }, RightSideToolboxContainer = new ExpandingToolboxContainer(130, 250) { - Padding = new MarginPadding(10), Alpha = DistanceSpacingMultiplier.Disabled ? 0 : 1, Child = new EditorToolboxGroup("snapping") { From dcb6357964abbbd3643c83f6cd9a5c9556573d24 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 14 Oct 2022 20:23:55 +0900 Subject: [PATCH 1691/2686] Add ability to remove the current item in multiplayer --- .../Multiplayer/Match/Playlist/MultiplayerQueueList.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs index 39740e650f..ba6b482729 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs @@ -78,9 +78,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist return; bool isItemOwner = Item.OwnerID == api.LocalUser.Value.OnlineID || multiplayerClient.IsHost; + bool isValidItem = isItemOwner && !Item.Expired; - AllowDeletion = isItemOwner && !Item.Expired && Item.ID != multiplayerClient.Room.Settings.PlaylistItemId; - AllowEditing = isItemOwner && !Item.Expired; + AllowDeletion = isValidItem + && (Item.ID != multiplayerClient.Room.Settings.PlaylistItemId // This is an optimisation for the following check. + || multiplayerClient.Room.Playlist.Count(i => !i.Expired) > 1); + + AllowEditing = isValidItem; } protected override void Dispose(bool isDisposing) From c65a8a83f390d8bc49d0946cf4c1588b5afc185f Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 14 Oct 2022 15:52:09 +0300 Subject: [PATCH 1692/2686] Add basic UI for reporting --- .../Visual/Online/TestSceneCommentActions.cs | 9 ++- .../Overlays/Comments/CommentReportReason.cs | 14 ++++ osu.Game/Overlays/Comments/DrawableComment.cs | 13 +++- .../Overlays/Comments/ReportCommentPopover.cs | 78 +++++++++++++++++++ 4 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 osu.Game/Overlays/Comments/CommentReportReason.cs create mode 100644 osu.Game/Overlays/Comments/ReportCommentPopover.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index bf01d3b0ac..1f3e9dd54c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -10,6 +10,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -42,9 +43,13 @@ namespace osu.Game.Tests.Visual.Online { base.Content.AddRange(new Drawable[] { - content = new OsuScrollContainer + new PopoverContainer() { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + Child = content = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both + } }, dialogOverlay }); diff --git a/osu.Game/Overlays/Comments/CommentReportReason.cs b/osu.Game/Overlays/Comments/CommentReportReason.cs new file mode 100644 index 0000000000..e768214438 --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentReportReason.cs @@ -0,0 +1,14 @@ +// 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.Overlays.Comments +{ + public enum CommentReportReason + { + Insults, + Spam, + UnwantedContent, + Nonsense, + Other + } +} diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 193d15064a..e675ceef4e 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -19,6 +19,8 @@ using System; using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; +using osu.Framework.Extensions; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; @@ -29,7 +31,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { - public class DrawableComment : CompositeDrawable + public class DrawableComment : CompositeDrawable, IHasPopover { private const int avatar_size = 40; @@ -324,9 +326,9 @@ namespace osu.Game.Overlays.Comments makeDeleted(); if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) - { actionsContainer.AddLink("Delete", deleteComment); - } + else + actionsContainer.AddLink("Report", this.ShowPopover); if (Comment.IsTopLevel) { @@ -544,5 +546,10 @@ namespace osu.Game.Overlays.Comments return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? "deleted" : string.Empty; } } + + public Popover GetPopover() + { + return new ReportCommentPopover(Comment.Id); + } } } diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs new file mode 100644 index 0000000000..119b51a7d7 --- /dev/null +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -0,0 +1,78 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterfaceV2; +using osuTK; + +namespace osu.Game.Overlays.Comments +{ + public class ReportCommentPopover : OsuPopover + { + public readonly long ID; + private LabelledEnumDropdown reason = null!; + private LabelledTextBox info = null!; + private ShakeContainer shaker = null!; + + public ReportCommentPopover(long id) + { + ID = id; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Child = new FillFlowContainer + { + Direction = FillDirection.Vertical, + Width = 500, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(7), + Children = new Drawable[] + { + reason = new LabelledEnumDropdown + { + Label = "Reason" + }, + info = new LabelledTextBox + { + Label = "Additional info", + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = shaker = new ShakeContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new RoundedButton + { + BackgroundColour = colours.Pink3, + Text = "Send report", + RelativeSizeAxes = Axes.X, + Action = send + } + } + } + } + }; + } + + private void send() + { + string infoValue = info.Current.Value; + var reasonValue = reason.Current.Value; + + if (reasonValue == CommentReportReason.Other && string.IsNullOrWhiteSpace(infoValue)) + { + shaker.Shake(); + return; + } + } + } +} From 7251d41deba1823276c129cb99e9d35823a1c094 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 14 Oct 2022 16:15:28 +0300 Subject: [PATCH 1693/2686] Add request class --- .../API/Requests/CommentReportRequest.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 osu.Game/Online/API/Requests/CommentReportRequest.cs diff --git a/osu.Game/Online/API/Requests/CommentReportRequest.cs b/osu.Game/Online/API/Requests/CommentReportRequest.cs new file mode 100644 index 0000000000..2195d612f3 --- /dev/null +++ b/osu.Game/Online/API/Requests/CommentReportRequest.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Net.Http; +using osu.Framework.IO.Network; +using osu.Game.Overlays.Comments; + +namespace osu.Game.Online.API.Requests +{ + public class CommentReportRequest : APIRequest + { + public readonly long CommentID; + public readonly CommentReportReason Reason; + public readonly string? Info; + + public CommentReportRequest(long commentID, CommentReportReason reason, string? info) + { + CommentID = commentID; + Reason = reason; + Info = info; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Post; + + req.AddParameter(@"reportable_type", @"comment"); + req.AddParameter(@"reportable_id", $"{CommentID}"); + req.AddParameter(@"reason", Reason.ToString()); + if (!string.IsNullOrWhiteSpace(Info)) + req.AddParameter(@"comments", Info); + + return req; + } + + protected override string Target => @"reports"; + } +} From 3e9fd4c08c9dde11b6925ffa43ae3c1a486da50f Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 14 Oct 2022 16:26:25 +0300 Subject: [PATCH 1694/2686] Implement reporting flow --- osu.Game/Overlays/Comments/DrawableComment.cs | 28 ++++++++++++++++++- .../Overlays/Comments/ReportCommentPopover.cs | 11 ++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index e675ceef4e..f7f71788ee 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -27,6 +27,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; using osu.Game.Overlays.Dialog; +using osu.Game.Overlays.Notifications; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments @@ -73,6 +74,9 @@ namespace osu.Game.Overlays.Comments [Resolved] private IAPIProvider api { get; set; } = null!; + [Resolved(canBeNull: true)] + private NotificationOverlay? notificationOverlay { get; set; } + public DrawableComment(Comment comment) { Comment = comment; @@ -405,6 +409,28 @@ namespace osu.Game.Overlays.Comments api.Queue(request); } + public void ReportComment(CommentReportReason reason, string comment) + { + actionsContainer.Hide(); + actionsLoading.Show(); + var request = new CommentReportRequest(Comment.Id, reason, comment); + request.Success += () => + { + actionsLoading.Hide(); + notificationOverlay?.Post(new SimpleNotification + { + Icon = FontAwesome.Solid.CheckCircle, + Text = "The comment reported successfully." + }); + }; + request.Failure += _ => + { + actionsLoading.Hide(); + actionsContainer.Show(); + }; + api.Queue(request); + } + protected override void LoadComplete() { ShowDeleted.BindValueChanged(show => @@ -549,7 +575,7 @@ namespace osu.Game.Overlays.Comments public Popover GetPopover() { - return new ReportCommentPopover(Comment.Id); + return new ReportCommentPopover(ReportComment); } } } diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 119b51a7d7..5f9e7ff45c 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -1,7 +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; using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; @@ -13,14 +15,14 @@ namespace osu.Game.Overlays.Comments { public class ReportCommentPopover : OsuPopover { - public readonly long ID; + private readonly Action action; private LabelledEnumDropdown reason = null!; private LabelledTextBox info = null!; private ShakeContainer shaker = null!; - public ReportCommentPopover(long id) + public ReportCommentPopover(Action action) { - ID = id; + this.action = action; } [BackgroundDependencyLoader] @@ -73,6 +75,9 @@ namespace osu.Game.Overlays.Comments shaker.Shake(); return; } + + this.HidePopover(); + action.Invoke(reasonValue, infoValue); } } } From dc0aa2295a6969172e736686892b3f59fb93e34d Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 14 Oct 2022 16:51:48 +0300 Subject: [PATCH 1695/2686] Add test --- .../Visual/Online/TestSceneCommentActions.cs | 85 +++++++++++++++++-- osu.Game/Overlays/Comments/DrawableComment.cs | 8 +- 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 1f3e9dd54c..00ae59fa30 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -15,6 +15,7 @@ using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -38,12 +39,14 @@ namespace osu.Game.Tests.Visual.Online private CommentsContainer commentsContainer = null!; + private readonly ManualResetEventSlim requestLock = new ManualResetEventSlim(); + [BackgroundDependencyLoader] private void load() { base.Content.AddRange(new Drawable[] { - new PopoverContainer() + new PopoverContainer { RelativeSizeAxes = Axes.Both, Child = content = new OsuScrollContainer @@ -85,8 +88,6 @@ namespace osu.Game.Tests.Visual.Online }); } - private readonly ManualResetEventSlim deletionPerformed = new ManualResetEventSlim(); - [Test] public void TestDeletion() { @@ -110,7 +111,7 @@ namespace osu.Game.Tests.Visual.Online }); AddStep("Setup request handling", () => { - deletionPerformed.Reset(); + requestLock.Reset(); dummyAPI.HandleRequest = request => { @@ -143,7 +144,7 @@ namespace osu.Game.Tests.Visual.Online Task.Run(() => { - deletionPerformed.Wait(10000); + requestLock.Wait(10000); req.TriggerSuccess(cb); }); @@ -154,7 +155,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Loading spinner shown", () => commentsContainer.ChildrenOfType().Any(d => d.IsPresent)); - AddStep("Complete request", () => deletionPerformed.Set()); + AddStep("Complete request", () => requestLock.Set()); AddUntilStep("Comment is deleted locally", () => this.ChildrenOfType().Single(x => x.Comment.Id == 1).WasDeleted); } @@ -209,6 +210,78 @@ namespace osu.Game.Tests.Visual.Online }); } + [Test] + public void TestReport() + { + const string report_text = "I don't like this comment"; + DrawableComment? targetComment = null; + CommentReportRequest? request = null; + + addTestComments(); + AddUntilStep("Comment exists", () => + { + var comments = this.ChildrenOfType(); + targetComment = comments.SingleOrDefault(x => x.Comment.Id == 2); + return targetComment != null; + }); + AddStep("Setup request handling", () => + { + requestLock.Reset(); + + dummyAPI.HandleRequest = r => + { + if (!(r is CommentReportRequest req)) + return false; + + Task.Run(() => + { + request = req; + requestLock.Wait(10000); + req.TriggerSuccess(); + }); + + return true; + }; + }); + AddStep("Click the button", () => + { + var btn = targetComment.ChildrenOfType().Single(x => x.Text == "Report"); + InputManager.MoveMouseTo(btn); + InputManager.Click(MouseButton.Left); + }); + AddStep("Select \"other\"", () => + { + var field = this.ChildrenOfType>().Single(); + field.Current.Value = CommentReportReason.Other; + }); + AddStep("Try to report", () => + { + var btn = this.ChildrenOfType().Single().ChildrenOfType().Single(); + InputManager.MoveMouseTo(btn); + InputManager.Click(MouseButton.Left); + }); + AddWaitStep("Wait", 3); + AddAssert("Nothing happened", () => this.ChildrenOfType().Any()); + AddStep("Enter some text", () => + { + var field = this.ChildrenOfType().Single(); + field.Current.Value = report_text; + }); + AddStep("Try to report", () => + { + var btn = this.ChildrenOfType().Single().ChildrenOfType().Single(); + InputManager.MoveMouseTo(btn); + InputManager.Click(MouseButton.Left); + }); + AddWaitStep("Wait", 3); + AddAssert("Overlay closed", () => !this.ChildrenOfType().Any()); + AddAssert("Loading spinner shown", () => targetComment.ChildrenOfType().Any(d => d.IsPresent)); + AddStep("Complete request", () => requestLock.Set()); + AddUntilStep("Request sent", () => request != null); + AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Info == report_text && request.Reason == CommentReportReason.Other); + AddUntilStep("Buttons hidden", () => !targetComment.ChildrenOfType().Single(x => x.Name == @"Actions buttons").IsPresent); + } + private void addTestComments() { AddStep("set up response", () => diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index f7f71788ee..362e0634c5 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -414,7 +414,7 @@ namespace osu.Game.Overlays.Comments actionsContainer.Hide(); actionsLoading.Show(); var request = new CommentReportRequest(Comment.Id, reason, comment); - request.Success += () => + request.Success += () => Schedule(() => { actionsLoading.Hide(); notificationOverlay?.Post(new SimpleNotification @@ -422,12 +422,12 @@ namespace osu.Game.Overlays.Comments Icon = FontAwesome.Solid.CheckCircle, Text = "The comment reported successfully." }); - }; - request.Failure += _ => + }); + request.Failure += _ => Schedule(() => { actionsLoading.Hide(); actionsContainer.Show(); - }; + }); api.Queue(request); } From b1b97505ac6704400b8817448d9a47b167956af8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 14 Oct 2022 22:14:23 +0300 Subject: [PATCH 1696/2686] Fix smoke displayed in "No scope" mod --- osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs | 7 ++++++- osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs | 7 ++++++- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 3 ++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs index 44404ca245..0fb2a68cfa 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs @@ -12,6 +12,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.UI; using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Mods @@ -145,6 +146,10 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods private bool isBreak() => Player.IsBreakTime.Value; - private bool cursorAlphaAlmostEquals(float alpha) => Precision.AlmostEquals(Player.DrawableRuleset.Cursor.Alpha, alpha, 0.1f); + private OsuPlayfield playfield => (OsuPlayfield)Player.DrawableRuleset.Playfield; + + private bool cursorAlphaAlmostEquals(float alpha) => + Precision.AlmostEquals(playfield.Cursor.Alpha, alpha, 0.1f) && + Precision.AlmostEquals(playfield.Smoke.Alpha, alpha, 0.1f); } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs index 2f84c30581..f5db8951d6 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModNoScope.cs @@ -9,6 +9,7 @@ using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.UI; using osu.Game.Utils; @@ -35,7 +36,11 @@ namespace osu.Game.Rulesets.Osu.Mods { bool shouldAlwaysShowCursor = IsBreakTime.Value || spinnerPeriods.IsInAny(playfield.Clock.CurrentTime); float targetAlpha = shouldAlwaysShowCursor ? 1 : ComboBasedAlpha; - playfield.Cursor.Alpha = (float)Interpolation.Lerp(playfield.Cursor.Alpha, targetAlpha, Math.Clamp(playfield.Time.Elapsed / TRANSITION_DURATION, 0, 1)); + float currentAlpha = (float)Interpolation.Lerp(playfield.Cursor.Alpha, targetAlpha, Math.Clamp(playfield.Time.Elapsed / TRANSITION_DURATION, 0, 1)); + + var osuPlayfield = (OsuPlayfield)playfield; + osuPlayfield.Cursor.Alpha = currentAlpha; + osuPlayfield.Smoke.Alpha = currentAlpha; } } } diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index 2e67e91460..e9a6c84c0b 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -36,6 +36,7 @@ namespace osu.Game.Rulesets.Osu.UI private readonly ProxyContainer spinnerProxies; private readonly JudgementContainer judgementLayer; + public SmokeContainer Smoke { get; } public FollowPointRenderer FollowPoints { get; } public static readonly Vector2 BASE_SIZE = new Vector2(512, 384); @@ -54,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.UI InternalChildren = new Drawable[] { playfieldBorder = new PlayfieldBorder { RelativeSizeAxes = Axes.Both }, - new SmokeContainer { RelativeSizeAxes = Axes.Both }, + Smoke = new SmokeContainer { RelativeSizeAxes = Axes.Both }, spinnerProxies = new ProxyContainer { RelativeSizeAxes = Axes.Both }, FollowPoints = new FollowPointRenderer { RelativeSizeAxes = Axes.Both }, judgementLayer = new JudgementContainer { RelativeSizeAxes = Axes.Both }, From 46bcabea6c5714cb8a8980aa33cbff2ddc746233 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Fri, 14 Oct 2022 12:42:04 -0700 Subject: [PATCH 1697/2686] Separate smoke rotation seed and index --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 7af1b5d86a..aba4d0ff63 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -234,7 +234,7 @@ namespace osu.Game.Rulesets.Osu.Skinning if (points.Count == 0) return; - rotationIndex = rotationSeed; + rotationIndex = 0; quadBatch ??= renderer.CreateQuadBatch(max_point_count / 10, 10); texture ??= renderer.WhitePixel; @@ -314,11 +314,7 @@ namespace osu.Game.Rulesets.Osu.Skinning return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); } - private float nextRotation() - { - rotationIndex++; - return max_rotation * (StatelessRNG.NextSingle(rotationIndex) * 2 - 1); - } + private float nextRotation() => max_rotation * (StatelessRNG.NextSingle(rotationSeed, rotationIndex++) * 2 - 1); private void drawPointQuad(SmokePoint point, RectangleF textureRect) { From 06e6713237ac8284e556411b88a2e2af49621ca5 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 Oct 2022 00:18:24 +0300 Subject: [PATCH 1698/2686] Move mouse input detection inside `MenuCursorContainer` to allow testing --- .../Graphics/Cursor/MenuCursorContainer.cs | 44 +++++++++++++++---- osu.Game/Input/OsuUserInputManager.cs | 26 ----------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 94bdef9842..33b0c308cc 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Input.Events; using osu.Framework.Utils; using osu.Game.Configuration; -using osu.Game.Input; using osuTK; namespace osu.Game.Graphics.Cursor @@ -35,6 +34,8 @@ namespace osu.Game.Graphics.Cursor private Bindable cursorRotate = null!; private Sample tapSample = null!; + private MouseInputDetector mouseInputDetector = null!; + private bool visible; [BackgroundDependencyLoader] @@ -46,10 +47,9 @@ namespace osu.Game.Graphics.Cursor screenshotCursorVisibility.BindTo(screenshotManager.CursorVisibility); tapSample = audio.Samples.Get(@"UI/cursor-tap"); - } - [Resolved] - private OsuUserInputManager? inputManager { get; set; } + Add(mouseInputDetector = new MouseInputDetector()); + } [Resolved] private OsuGame? game { get; set; } @@ -61,11 +61,8 @@ namespace osu.Game.Graphics.Cursor { base.LoadComplete(); - if (inputManager != null) - { - lastInputWasMouse.BindTo(inputManager.LastInputWasMouseSource); - lastInputWasMouse.BindValueChanged(_ => updateState(), true); - } + lastInputWasMouse.BindTo(mouseInputDetector.LastInputWasMouseSource); + lastInputWasMouse.BindValueChanged(_ => updateState(), true); if (game != null) { @@ -247,6 +244,35 @@ namespace osu.Game.Graphics.Cursor } } + private class MouseInputDetector : Component + { + /// + /// Whether the last input applied to the game is sourced from mouse. + /// + public IBindable LastInputWasMouseSource => lastInputWasMouseSource; + + private readonly Bindable lastInputWasMouseSource = new Bindable(); + + public MouseInputDetector() + { + RelativeSizeAxes = Axes.Both; + } + + protected override bool Handle(UIEvent e) + { + switch (e) + { + case MouseEvent: + lastInputWasMouseSource.Value = true; + return false; + + default: + lastInputWasMouseSource.Value = false; + return false; + } + } + } + private enum DragRotationState { NotDragging, diff --git a/osu.Game/Input/OsuUserInputManager.cs b/osu.Game/Input/OsuUserInputManager.cs index 82c6ca0edd..7a9002a004 100644 --- a/osu.Game/Input/OsuUserInputManager.cs +++ b/osu.Game/Input/OsuUserInputManager.cs @@ -3,43 +3,17 @@ #nullable disable -using osu.Framework.Bindables; using osu.Framework.Input; -using osu.Framework.Input.StateChanges.Events; using osuTK.Input; namespace osu.Game.Input { public class OsuUserInputManager : UserInputManager { - /// - /// Whether the last input applied to the game is sourced from mouse. - /// - public IBindable LastInputWasMouseSource => lastInputWasMouseSource; - - private readonly Bindable lastInputWasMouseSource = new Bindable(); - internal OsuUserInputManager() { } - public override void HandleInputStateChange(InputStateChangeEvent inputStateChange) - { - switch (inputStateChange) - { - case ButtonStateChangeEvent: - case MousePositionChangeEvent: - lastInputWasMouseSource.Value = true; - break; - - default: - lastInputWasMouseSource.Value = false; - break; - } - - base.HandleInputStateChange(inputStateChange); - } - protected override MouseButtonEventManager CreateButtonEventManagerFor(MouseButton button) { switch (button) From 97c4282e555f73d33a55b06572b5ffd2302a57ba Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 Oct 2022 00:18:50 +0300 Subject: [PATCH 1699/2686] Add test cases for hiding cursor on keyboard input --- .../Visual/UserInterface/TestSceneCursors.cs | 70 ++++++++++++++++--- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs index 6033fc5871..0f238eb547 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs @@ -15,6 +15,7 @@ using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Sprites; using osuTK; using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { @@ -81,19 +82,18 @@ namespace osu.Game.Tests.Visual.UserInterface }; AddToggleStep("Smooth transitions", b => cursorBoxes.ForEach(box => box.SmoothTransition = b)); - - testUserCursor(); - testLocalCursor(); - testUserCursorOverride(); - testMultipleLocalCursors(); } + [SetUp] + public void SetUp() => Schedule(moveOut); + /// /// -- Green Box -- /// Tests whether hovering in and out of a drawable that provides the user cursor (green) /// results in the correct visibility state for that cursor. /// - private void testUserCursor() + [Test] + public void TestUserCursor() { AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0])); AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].Cursor)); @@ -108,7 +108,8 @@ namespace osu.Game.Tests.Visual.UserInterface /// Tests whether hovering in and out of a drawable that provides a local cursor (purple) /// results in the correct visibility and state for that cursor. /// - private void testLocalCursor() + [Test] + public void TestLocalCursor() { AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3])); AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor)); @@ -125,7 +126,8 @@ namespace osu.Game.Tests.Visual.UserInterface /// Tests whether overriding a user cursor (green) with another user cursor (blue) /// results in the correct visibility and states for the cursors. /// - private void testUserCursorOverride() + [Test] + public void TestUserCursorOverride() { AddStep("Move to blue-green boundary", () => InputManager.MoveMouseTo(cursorBoxes[1].ScreenSpaceDrawQuad.BottomRight - new Vector2(10))); AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor)); @@ -140,7 +142,8 @@ namespace osu.Game.Tests.Visual.UserInterface /// -- Yellow-Purple Box Boundary -- /// Tests whether multiple local cursors (purple + yellow) may be visible and at the mouse position at the same time. /// - private void testMultipleLocalCursors() + [Test] + public void TestMultipleLocalCursors() { AddStep("Move to yellow-purple boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.BottomRight - new Vector2(10))); AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor)); @@ -156,7 +159,8 @@ namespace osu.Game.Tests.Visual.UserInterface /// -- Yellow-Blue Box Boundary -- /// Tests whether a local cursor (yellow) may be displayed along with a user cursor override (blue). /// - private void testUserOverrideWithLocal() + [Test] + public void TestUserOverrideWithLocal() { AddStep("Move to yellow-blue boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.TopRight - new Vector2(10))); AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor)); @@ -168,6 +172,52 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor)); } + /// + /// Ensures non-mouse input hides global cursor on a "local cursor" area (which doesn't hide global cursor). + /// + [Test] + public void TestKeyboardLocalCursor([Values] bool clickToShow) + { + AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3].ScreenSpaceDrawQuad.Centre + new Vector2(10, 0))); + AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor)); + AddAssert("Check global cursor alpha is 1", () => globalCursorDisplay.MenuCursor.Alpha == 1); + + AddStep("Press key", () => InputManager.Key(Key.A)); + AddAssert("Check purple cursor still visible", () => checkVisible(cursorBoxes[3].Cursor)); + AddUntilStep("Check global cursor alpha is 0", () => globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0); + + if (clickToShow) + AddStep("Click mouse", () => InputManager.Click(MouseButton.Left)); + else + AddStep("Move mouse", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + Vector2.One)); + + AddAssert("Check purple cursor still visible", () => checkVisible(cursorBoxes[3].Cursor)); + AddUntilStep("Check global cursor alpha is 1", () => globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 1); + } + + /// + /// Ensures mouse input after non-mouse input doesn't show global cursor on a "user cursor" area (which hides global cursor). + /// + [Test] + public void TestKeyboardUserCursor([Values] bool clickToShow) + { + AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0])); + AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].Cursor)); + AddAssert("Check global cursor alpha is 0", () => !checkVisible(globalCursorDisplay.MenuCursor) && globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0); + + AddStep("Press key", () => InputManager.Key(Key.A)); + AddAssert("Check green cursor still visible", () => checkVisible(cursorBoxes[0].Cursor)); + AddAssert("Check global cursor alpha is still 0", () => !checkVisible(globalCursorDisplay.MenuCursor) && globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0); + + if (clickToShow) + AddStep("Click mouse", () => InputManager.Click(MouseButton.Left)); + else + AddStep("Move mouse", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + Vector2.One)); + + AddAssert("Check green cursor still visible", () => checkVisible(cursorBoxes[0].Cursor)); + AddAssert("Check global cursor alpha is still 0", () => !checkVisible(globalCursorDisplay.MenuCursor) && globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0); + } + /// /// Moves the cursor to a point not covered by any cursor containers. /// From 45f590ca433a4e336b99c4d01e716d6c7ade7f20 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 Oct 2022 00:18:56 +0300 Subject: [PATCH 1700/2686] Add test case for hiding cursor on idle --- osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index cf62c73ad4..6070b1456f 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -25,6 +25,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Menu; using osu.Game.Skinning; +using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation { @@ -79,6 +80,16 @@ namespace osu.Game.Tests.Visual.Navigation [Resolved] private OsuGameBase gameBase { get; set; } + [Test] + public void TestCursorHidesWhenIdle() + { + AddStep("click mouse", () => InputManager.Click(MouseButton.Left)); + AddUntilStep("wait until idle", () => Game.IsIdle.Value); + AddUntilStep("menu cursor hidden", () => Game.GlobalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0); + AddStep("click mouse", () => InputManager.Click(MouseButton.Left)); + AddUntilStep("menu cursor shown", () => Game.GlobalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 1); + } + [Test] public void TestNullRulesetHandled() { From 241ecb63a15cc339eda58d2679d54c184be32493 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 Oct 2022 00:19:40 +0300 Subject: [PATCH 1701/2686] Hide manual input manager cursor in `OsuGameTestScene`s Allows checking that the cursor is actually hidden in `TestSceneOsuGame.TestCursorHidesWhenIdle`. --- osu.Game/Tests/Visual/OsuGameTestScene.cs | 5 ++++ .../Visual/OsuManualInputManagerTestScene.cs | 26 +++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuGameTestScene.cs b/osu.Game/Tests/Visual/OsuGameTestScene.cs index e47d19fba6..3ca83a4781 100644 --- a/osu.Game/Tests/Visual/OsuGameTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGameTestScene.cs @@ -17,6 +17,7 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; +using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays; @@ -42,6 +43,8 @@ namespace osu.Game.Tests.Visual protected override bool CreateNestedActionContainer => false; + protected override bool DisplayCursorForManualInput => false; + [BackgroundDependencyLoader] private void load() { @@ -119,6 +122,8 @@ namespace osu.Game.Tests.Visual public RealmAccess Realm => Dependencies.Get(); + public new GlobalCursorDisplay GlobalCursorDisplay => base.GlobalCursorDisplay; + public new BackButton BackButton => base.BackButton; public new BeatmapManager BeatmapManager => base.BeatmapManager; diff --git a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs index 9082ca9c58..e56c546bac 100644 --- a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs +++ b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs @@ -36,21 +36,31 @@ namespace osu.Game.Tests.Visual /// protected virtual bool CreateNestedActionContainer => true; + /// + /// Whether a menu cursor controlled by the manual input manager should be displayed. + /// True by default, but is disabled for s as they provide their own global cursor. + /// + protected virtual bool DisplayCursorForManualInput => true; + protected OsuManualInputManagerTestScene() { - GlobalCursorDisplay cursorDisplay; + var mainContent = content = new Container { RelativeSizeAxes = Axes.Both }; - CompositeDrawable mainContent = cursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both }; - - cursorDisplay.Child = content = new OsuTooltipContainer(cursorDisplay.MenuCursor) + if (DisplayCursorForManualInput) { - RelativeSizeAxes = Axes.Both - }; + var cursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both }; + + cursorDisplay.Add(new OsuTooltipContainer(cursorDisplay.MenuCursor) + { + RelativeSizeAxes = Axes.Both, + Child = mainContent + }); + + mainContent = cursorDisplay; + } if (CreateNestedActionContainer) - { mainContent = new GlobalActionContainer(null).WithChild(mainContent); - } base.Content.AddRange(new Drawable[] { From 421b81b6caaa94aba437e417df924a14faa7744a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 Oct 2022 00:41:14 +0300 Subject: [PATCH 1702/2686] Fix broken test case --- osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs index 0f238eb547..6c0191ae27 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs @@ -162,7 +162,7 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestUserOverrideWithLocal() { - AddStep("Move to yellow-blue boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.TopRight - new Vector2(10))); + AddStep("Move to yellow-blue boundary", () => InputManager.MoveMouseTo(cursorBoxes[5].ScreenSpaceDrawQuad.TopRight - new Vector2(10, 0))); AddAssert("Check blue cursor visible", () => checkVisible(cursorBoxes[1].Cursor)); AddAssert("Check blue cursor at mouse", () => checkAtMouse(cursorBoxes[1].Cursor)); AddAssert("Check yellow cursor visible", () => checkVisible(cursorBoxes[5].Cursor)); From 91358f4a6aa5a0d7fe41f4473bbd7bb67f261367 Mon Sep 17 00:00:00 2001 From: Aki <75532970+AkiSakurai@users.noreply.github.com> Date: Sat, 15 Oct 2022 15:11:28 +0800 Subject: [PATCH 1703/2686] Implement tablet button bindings --- .../Settings/Sections/Input/KeyBindingRow.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 2fea2e34b2..c91a6a48d4 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -327,6 +327,50 @@ namespace osu.Game.Overlays.Settings.Sections.Input finalise(); } + protected override bool OnTabletAuxiliaryButtonPress(TabletAuxiliaryButtonPressEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + finalise(); + + return true; + } + + protected override void OnTabletAuxiliaryButtonRelease(TabletAuxiliaryButtonReleaseEvent e) + { + if (!HasFocus) + { + base.OnTabletAuxiliaryButtonRelease(e); + return; + } + + finalise(); + } + + protected override bool OnTabletPenButtonPress(TabletPenButtonPressEvent e) + { + if (!HasFocus) + return false; + + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + finalise(); + + return true; + } + + protected override void OnTabletPenButtonRelease(TabletPenButtonReleaseEvent e) + { + if (!HasFocus) + { + base.OnTabletPenButtonRelease(e); + return; + } + + finalise(); + } + private void clear() { if (bindTarget == null) From 7d53d35bf619aa209391edd773d5c594d7bce15d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 Oct 2022 16:23:54 +0300 Subject: [PATCH 1704/2686] Remove duplicate & outdated test case --- .../SongSelect/TestScenePlaySongSelect.cs | 30 ------------------- 1 file changed, 30 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index cc8746959b..248bf9f5ed 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -538,36 +538,6 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("selection shown on wedge", () => songSelect!.CurrentBeatmapDetailsBeatmap.BeatmapInfo.MatchesOnlineID(target)); } - [Test] - public void TestRulesetChangeResetsMods() - { - createSongSelect(); - changeRuleset(0); - - changeMods(new OsuModHardRock()); - - int actionIndex = 0; - int modChangeIndex = 0; - int rulesetChangeIndex = 0; - - AddStep("change ruleset", () => - { - SelectedMods.ValueChanged += onModChange; - songSelect!.Ruleset.ValueChanged += onRulesetChange; - - Ruleset.Value = new TaikoRuleset().RulesetInfo; - - SelectedMods.ValueChanged -= onModChange; - songSelect!.Ruleset.ValueChanged -= onRulesetChange; - }); - - AddAssert("mods changed before ruleset", () => modChangeIndex < rulesetChangeIndex); - AddAssert("empty mods", () => !SelectedMods.Value.Any()); - - void onModChange(ValueChangedEvent> e) => modChangeIndex = actionIndex++; - void onRulesetChange(ValueChangedEvent e) => rulesetChangeIndex = actionIndex++; - } - [Test] public void TestModsRetainedBetweenSongSelect() { From 841e20c3363ebe2dd5e9fd0c408d7342ca78273d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 15 Oct 2022 17:16:08 +0300 Subject: [PATCH 1705/2686] Remove unused usings --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 248bf9f5ed..63532fdba8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -32,7 +31,6 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Rulesets.Taiko; using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Select; From cdea4f879680ccf8f5001716a9e3335c4e59ff04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 16 Oct 2022 00:05:27 +0900 Subject: [PATCH 1706/2686] Remove attempted proxying logic in mania implementation --- osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs index 6a9b3e3aba..e7dfec256d 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon ringExplosion?.PlayAnimation(); } - public Drawable? GetAboveHitObjectsProxiedContent() => JudgementText; + public Drawable? GetAboveHitObjectsProxiedContent() => null; private class RingExplosion : CompositeDrawable { From cd1885a17bbec36fecf2117910f4a8e4c0add095 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sun, 16 Oct 2022 02:55:10 -0700 Subject: [PATCH 1707/2686] Fix hit error bar icon orientation Icons now keep their original orientation when the hit error bar is flipped --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 747f4d4a8a..9687952fff 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -338,8 +338,26 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters base.Update(); // undo any layout rotation to display icons in the correct orientation - if (labelEarly != null) labelEarly.Rotation = -Rotation; - if (labelLate != null) labelLate.Rotation = -Rotation; + bool xFlipped = Scale.X < 0; + bool yFlipped = Scale.Y < 0; + bool horizontal = Rotation == 90 || Rotation == -90; + + bool flipX = (xFlipped && yFlipped) || (xFlipped && !horizontal) || (yFlipped && horizontal); + bool flipY = (xFlipped && yFlipped) || (xFlipped && horizontal) || (yFlipped && !horizontal); + + Vector2 flipScale = new Vector2(flipX ? -1 : 1, flipY ? -1 : 1); + + if (labelEarly != null) + { + labelEarly.Rotation = -Rotation; + labelEarly.Scale = flipScale; + } + + if (labelLate != null) + { + labelLate.Rotation = -Rotation; + labelLate.Scale = flipScale; + } } private void createColourBars((HitResult result, double length)[] windows) From 9822a092c4f11c46f8e185d029772eb5ef71d934 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 16 Oct 2022 19:50:55 +0300 Subject: [PATCH 1708/2686] Add localization for enum --- osu.Game/Overlays/Comments/CommentReportReason.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Overlays/Comments/CommentReportReason.cs b/osu.Game/Overlays/Comments/CommentReportReason.cs index e768214438..4fbec0164d 100644 --- a/osu.Game/Overlays/Comments/CommentReportReason.cs +++ b/osu.Game/Overlays/Comments/CommentReportReason.cs @@ -1,14 +1,26 @@ // 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.Localisation; +using osu.Game.Resources.Localisation.Web; + namespace osu.Game.Overlays.Comments { public enum CommentReportReason { + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsInsults))] Insults, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsSpam))] Spam, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsUnwantedContent))] UnwantedContent, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsNonsense))] Nonsense, + + [LocalisableDescription(typeof(UsersStrings), nameof(UsersStrings.ReportOptionsOther))] Other } } From ba595ab8fa6f9d520e98f3adb46c53d98ed1ab00 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 16 Oct 2022 19:57:21 +0300 Subject: [PATCH 1709/2686] Display toast instead of notification --- osu.Game/Overlays/Comments/DrawableComment.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 362e0634c5..998f3b8e62 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -23,11 +23,12 @@ using osu.Framework.Extensions; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; using osu.Game.Overlays.Dialog; -using osu.Game.Overlays.Notifications; +using osu.Game.Overlays.OSD; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments @@ -75,7 +76,7 @@ namespace osu.Game.Overlays.Comments private IAPIProvider api { get; set; } = null!; [Resolved(canBeNull: true)] - private NotificationOverlay? notificationOverlay { get; set; } + private OnScreenDisplay? onScreenDisplay { get; set; } public DrawableComment(Comment comment) { @@ -417,11 +418,7 @@ namespace osu.Game.Overlays.Comments request.Success += () => Schedule(() => { actionsLoading.Hide(); - notificationOverlay?.Post(new SimpleNotification - { - Icon = FontAwesome.Solid.CheckCircle, - Text = "The comment reported successfully." - }); + onScreenDisplay?.Display(new ReportToast()); }); request.Failure += _ => Schedule(() => { @@ -577,5 +574,13 @@ namespace osu.Game.Overlays.Comments { return new ReportCommentPopover(ReportComment); } + + private class ReportToast : Toast + { + public ReportToast() + : base(UserInterfaceStrings.GeneralHeader, UsersStrings.ReportThanks, "") + { + } + } } } From d6030891a24104dd33e6caf3fc708a1ebc516948 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sun, 16 Oct 2022 10:06:38 -0700 Subject: [PATCH 1710/2686] Reuse existing code in hit error bar fix Use `UprightAspectMaintainingContainer` instead of a local fix for hit error bar orientation --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 93 ++++++++++--------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 9687952fff..60da967085 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -15,6 +15,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; @@ -273,45 +274,74 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters break; case LabelStyles.Icons: - labelEarly = new SpriteIcon + labelEarly = new UprightAspectMaintainingContainer { - Y = -10, - Size = new Vector2(icon_size), - Icon = FontAwesome.Solid.ShippingFast, + AutoSizeAxes = Axes.Both, Anchor = Anchor.TopCentre, Origin = Anchor.Centre, + Y = -10, + Children = new Drawable[] + { + new SpriteIcon + { + Size = new Vector2(icon_size), + Icon = FontAwesome.Solid.ShippingFast, + } + } }; - labelLate = new SpriteIcon + labelLate = new UprightAspectMaintainingContainer { - Y = 10, - Size = new Vector2(icon_size), - Icon = FontAwesome.Solid.Bicycle, + AutoSizeAxes = Axes.Both, Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, + Y = 10, + Children = new Drawable[] + { + new SpriteIcon + { + Y = 10, + Size = new Vector2(icon_size), + Icon = FontAwesome.Solid.Bicycle, + } + } }; break; case LabelStyles.Text: - labelEarly = new OsuSpriteText + labelEarly = new UprightAspectMaintainingContainer { - Y = -10, - Text = "Early", - Font = OsuFont.Default.With(size: 10), - Height = 12, + AutoSizeAxes = Axes.Both, Anchor = Anchor.TopCentre, Origin = Anchor.Centre, + Y = -10, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = "Early", + Font = OsuFont.Default.With(size: 10), + Height = 12, + } + } }; - labelLate = new OsuSpriteText + labelLate = new UprightAspectMaintainingContainer { - Y = 10, - Text = "Late", - Font = OsuFont.Default.With(size: 10), - Height = 12, + AutoSizeAxes = Axes.Both, Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, + Y = 10, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = "Late", + Font = OsuFont.Default.With(size: 10), + Height = 12, + } + } }; break; @@ -333,33 +363,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - protected override void Update() - { - base.Update(); - - // undo any layout rotation to display icons in the correct orientation - bool xFlipped = Scale.X < 0; - bool yFlipped = Scale.Y < 0; - bool horizontal = Rotation == 90 || Rotation == -90; - - bool flipX = (xFlipped && yFlipped) || (xFlipped && !horizontal) || (yFlipped && horizontal); - bool flipY = (xFlipped && yFlipped) || (xFlipped && horizontal) || (yFlipped && !horizontal); - - Vector2 flipScale = new Vector2(flipX ? -1 : 1, flipY ? -1 : 1); - - if (labelEarly != null) - { - labelEarly.Rotation = -Rotation; - labelEarly.Scale = flipScale; - } - - if (labelLate != null) - { - labelLate.Rotation = -Rotation; - labelLate.Scale = flipScale; - } - } - private void createColourBars((HitResult result, double length)[] windows) { // max to avoid div-by-zero. From e1785f73a28c3da1befcc9aa8dd1b41f3f8207d2 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 16 Oct 2022 20:14:05 +0300 Subject: [PATCH 1711/2686] Make report's comment not optional --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 2 +- osu.Game/Online/API/Requests/CommentReportRequest.cs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 00ae59fa30..3515b5fb0a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -278,7 +278,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Loading spinner shown", () => targetComment.ChildrenOfType().Any(d => d.IsPresent)); AddStep("Complete request", () => requestLock.Set()); AddUntilStep("Request sent", () => request != null); - AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Info == report_text && request.Reason == CommentReportReason.Other); + AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Comment == report_text && request.Reason == CommentReportReason.Other); AddUntilStep("Buttons hidden", () => !targetComment.ChildrenOfType().Single(x => x.Name == @"Actions buttons").IsPresent); } diff --git a/osu.Game/Online/API/Requests/CommentReportRequest.cs b/osu.Game/Online/API/Requests/CommentReportRequest.cs index 2195d612f3..3f57756ced 100644 --- a/osu.Game/Online/API/Requests/CommentReportRequest.cs +++ b/osu.Game/Online/API/Requests/CommentReportRequest.cs @@ -11,13 +11,13 @@ namespace osu.Game.Online.API.Requests { public readonly long CommentID; public readonly CommentReportReason Reason; - public readonly string? Info; + public readonly string Comment; - public CommentReportRequest(long commentID, CommentReportReason reason, string? info) + public CommentReportRequest(long commentID, CommentReportReason reason, string comment) { CommentID = commentID; Reason = reason; - Info = info; + Comment = comment; } protected override WebRequest CreateWebRequest() @@ -28,8 +28,7 @@ namespace osu.Game.Online.API.Requests req.AddParameter(@"reportable_type", @"comment"); req.AddParameter(@"reportable_id", $"{CommentID}"); req.AddParameter(@"reason", Reason.ToString()); - if (!string.IsNullOrWhiteSpace(Info)) - req.AddParameter(@"comments", Info); + req.AddParameter(@"comments", Comment); return req; } From 4a8d976cb4e0be0fbd789d192147e4e8b9ec7735 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 16 Oct 2022 20:20:34 +0300 Subject: [PATCH 1712/2686] Use api's endpoint --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 59f6b74722..0675d99a25 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -415,7 +415,7 @@ namespace osu.Game.Overlays.Comments private void copyUrl() { - host.GetClipboard()?.SetText($@"https://osu.ppy.sh/comments/{Comment.Id}"); + host.GetClipboard()?.SetText($@"{api.APIEndpointUrl}/comments/{Comment.Id}"); onScreenDisplay?.Display(new CopyUrlToast()); } From 85de80279382341b5c7392c35b0930eb2dd362a4 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sun, 16 Oct 2022 11:47:21 -0700 Subject: [PATCH 1713/2686] Only create hit error bar icon containers once Move icon container creation to BDL, and only recreate the contained icon when `recreateLabels` is called --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 104 +++++------------- 1 file changed, 30 insertions(+), 74 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 60da967085..0f5270d644 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -45,8 +45,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public Bindable LabelStyle { get; } = new Bindable(LabelStyles.Icons); private SpriteIcon arrow; - private Drawable labelEarly; - private Drawable labelLate; + private UprightAspectMaintainingContainer labelEarly; + private UprightAspectMaintainingContainer labelLate; private Container colourBarsEarly; private Container colourBarsLate; @@ -123,6 +123,18 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativeSizeAxes = Axes.Y, Width = judgement_line_width, }, + labelEarly = new UprightAspectMaintainingContainer { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Y = -10, + }, + labelLate = new UprightAspectMaintainingContainer { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.BottomCentre, + Origin = Anchor.Centre, + Y = 10, + }, } }, arrowContainer = new Container @@ -262,86 +274,39 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { const float icon_size = 14; - labelEarly?.Expire(); - labelEarly = null; - - labelLate?.Expire(); - labelLate = null; - switch (style) { case LabelStyles.None: break; case LabelStyles.Icons: - labelEarly = new UprightAspectMaintainingContainer + labelEarly.Child = new SpriteIcon { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopCentre, - Origin = Anchor.Centre, - Y = -10, - Children = new Drawable[] - { - new SpriteIcon - { - Size = new Vector2(icon_size), - Icon = FontAwesome.Solid.ShippingFast, - } - } + Size = new Vector2(icon_size), + Icon = FontAwesome.Solid.ShippingFast, }; - labelLate = new UprightAspectMaintainingContainer + labelLate.Child = new SpriteIcon { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre, - Y = 10, - Children = new Drawable[] - { - new SpriteIcon - { - Y = 10, - Size = new Vector2(icon_size), - Icon = FontAwesome.Solid.Bicycle, - } - } + Size = new Vector2(icon_size), + Icon = FontAwesome.Solid.Bicycle, }; break; case LabelStyles.Text: - labelEarly = new UprightAspectMaintainingContainer + labelEarly.Child = new OsuSpriteText { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.TopCentre, - Origin = Anchor.Centre, - Y = -10, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = "Early", - Font = OsuFont.Default.With(size: 10), - Height = 12, - } - } + Text = "Early", + Font = OsuFont.Default.With(size: 10), + Height = 12, }; - labelLate = new UprightAspectMaintainingContainer + labelLate.Child = new OsuSpriteText { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.BottomCentre, - Origin = Anchor.Centre, - Y = 10, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = "Late", - Font = OsuFont.Default.With(size: 10), - Height = 12, - } - } + Text = "Late", + Font = OsuFont.Default.With(size: 10), + Height = 12, }; break; @@ -350,17 +315,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters throw new ArgumentOutOfRangeException(nameof(style), style, null); } - if (labelEarly != null) - { - colourBars.Add(labelEarly); - labelEarly.FadeInFromZero(500); - } - - if (labelLate != null) - { - colourBars.Add(labelLate); - labelLate.FadeInFromZero(500); - } + labelEarly.FadeInFromZero(500); + labelLate.FadeInFromZero(500); } private void createColourBars((HitResult result, double length)[] windows) From ae05f374a2e79a57373010324fbaea833611b456 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 17 Oct 2022 03:26:28 +0300 Subject: [PATCH 1714/2686] Fix potential invalid operation exception in `SubmittingPlayer` token retrieval --- osu.Game/Screens/Play/SubmittingPlayer.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index d56b9c23c8..345bd5a134 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -86,16 +86,13 @@ namespace osu.Game.Screens.Play // Generally a timeout would not happen here as APIAccess will timeout first. if (!tcs.Task.Wait(60000)) - handleTokenFailure(new InvalidOperationException("Token retrieval timed out (request never run)")); + req.TriggerFailure(new InvalidOperationException("Token retrieval timed out (request never run)")); return true; void handleTokenFailure(Exception exception) { - // This method may be invoked multiple times due to the Task.Wait call above. - // We only really care about the first error. - if (!tcs.TrySetResult(false)) - return; + tcs.SetResult(false); if (HandleTokenRetrievalFailure(exception)) { From 1e7b8cd227523acd458c2184d3a35f5ea8d163e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Oct 2022 13:22:06 +0900 Subject: [PATCH 1715/2686] Fix formatting issues --- .../Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 0f5270d644..d6b9c62369 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -123,13 +123,15 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativeSizeAxes = Axes.Y, Width = judgement_line_width, }, - labelEarly = new UprightAspectMaintainingContainer { + labelEarly = new UprightAspectMaintainingContainer + { AutoSizeAxes = Axes.Both, Anchor = Anchor.TopCentre, Origin = Anchor.Centre, Y = -10, }, - labelLate = new UprightAspectMaintainingContainer { + labelLate = new UprightAspectMaintainingContainer + { AutoSizeAxes = Axes.Both, Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, From 2adbf4cc1a5d27aad1d5a99d41766c598b7dfa60 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 17 Oct 2022 08:26:51 +0300 Subject: [PATCH 1716/2686] Add arc-shaped progress bars to "argon" spinner --- .../Skinning/Argon/ArgonSpinnerDisc.cs | 105 +++++++++++++----- .../Skinning/Argon/ArgonSpinnerProgressArc.cs | 67 +++++++++++ .../Skinning/Argon/ArgonSpinnerRingArc.cs | 33 ++++++ 3 files changed, 175 insertions(+), 30 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs create mode 100644 osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs index 4669b5b913..3b418fcb2d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -16,7 +16,6 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { @@ -52,6 +51,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private Container centre = null!; private CircularContainer fill = null!; + private Container ticksContainer = null!; + private ArgonSpinnerTicks ticks = null!; + [BackgroundDependencyLoader] private void load(DrawableHitObject drawableHitObject) { @@ -70,41 +72,84 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - fill = new CircularContainer + new Container { - Name = @"Fill", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Masking = true, - EdgeEffect = new EdgeEffectParameters + Padding = new MarginPadding(8f), + Children = new[] { - Type = EdgeEffectType.Shadow, - Colour = Colour4.FromHex("FC618F").Opacity(1f), - Radius = 40, + fill = new CircularContainer + { + Name = @"Fill", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Colour4.FromHex("FC618F").Opacity(1f), + Radius = 40, + }, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0f, + AlwaysPresent = true, + } + }, + new Container + { + Name = @"Ring", + Masking = true, + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new ArgonSpinnerRingArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Top Arc", + }, + new ArgonSpinnerRingArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Bottom Arc", + Scale = new Vector2(1, -1), + }, + } + }, + ticksContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Child = ticks = new ArgonSpinnerTicks(), + } }, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0f, - AlwaysPresent = true, - } }, - new CircularContainer + new Container { - Name = @"Ring", - Masking = true, - BorderColour = Color4.White, - BorderThickness = 5, + Name = @"Sides", RelativeSizeAxes = Axes.Both, - Child = new Box + Children = new[] { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true, + new ArgonSpinnerProgressArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Left Bar" + }, + new ArgonSpinnerProgressArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Right Bar", + Scale = new Vector2(-1, 1), + }, } }, - new ArgonSpinnerTicks(), } }, centre = new Container @@ -167,7 +212,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon float targetScale = initial_fill_scale + (0.98f - initial_fill_scale) * drawableSpinner.Progress; fill.Scale = new Vector2((float)Interpolation.Lerp(fill.Scale.X, targetScale, Math.Clamp(Math.Abs(Time.Elapsed) / 100, 0, 1))); - disc.Rotation = drawableSpinner.RotationTracker.Rotation; + ticks.Rotation = drawableSpinner.RotationTracker.Rotation; } private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) @@ -180,12 +225,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt)) { this.ScaleTo(initial_scale); - this.RotateTo(0); + ticksContainer.RotateTo(0); using (BeginDelayedSequence(spinner.TimePreempt / 2)) { // constant ambient rotation to give the spinner "spinning" character. - this.RotateTo((float)(25 * spinner.Duration / 2000), spinner.TimePreempt + spinner.Duration); + ticksContainer.RotateTo((float)(25 * spinner.Duration / 2000), spinner.TimePreempt + spinner.Duration); } using (BeginDelayedSequence(spinner.TimePreempt + spinner.Duration + drawableHitObject.Result.TimeOffset)) @@ -194,7 +239,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { case ArmedState.Hit: this.ScaleTo(initial_scale * 1.2f, 320, Easing.Out); - this.RotateTo(Rotation + 180, 320); + ticksContainer.RotateTo(ticksContainer.Rotation + 180, 320); break; case ArmedState.Miss: diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs new file mode 100644 index 0000000000..be7921a1f1 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs @@ -0,0 +1,67 @@ +// 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.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonSpinnerProgressArc : CompositeDrawable + { + private const float arc_fill = 0.15f; + private const float arc_radius = 0.12f; + + private CircularProgress fill = null!; + + private DrawableSpinner spinner = null!; + + [BackgroundDependencyLoader] + private void load(DrawableHitObject drawableHitObject, OsuColour colours) + { + RelativeSizeAxes = Axes.Both; + + spinner = (DrawableSpinner)drawableHitObject; + + InternalChildren = new Drawable[] + { + new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = Color4.White.Opacity(0.25f), + RelativeSizeAxes = Axes.Both, + Current = { Value = arc_fill }, + Rotation = 90 - arc_fill * 180, + InnerRadius = arc_radius, + RoundedCaps = true, + }, + fill = new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + InnerRadius = arc_radius, + RoundedCaps = true, + } + }; + } + + protected override void Update() + { + base.Update(); + + fill.Alpha = (float)Interpolation.DampContinuously(fill.Alpha, spinner.Progress > 0 ? 1 : 0, 120f, (float)Math.Abs(Time.Elapsed)); + fill.Current.Value = (float)Interpolation.DampContinuously(fill.Current.Value, arc_fill * spinner.Progress, 120f, (float)Math.Abs(Time.Elapsed)); + fill.Rotation = (float)(90 - fill.Current.Value * 180); + } + } +} diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs new file mode 100644 index 0000000000..ec9d7bbae5 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs @@ -0,0 +1,33 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; + +namespace osu.Game.Rulesets.Osu.Skinning.Argon +{ + public class ArgonSpinnerRingArc : CompositeDrawable + { + private const float arc_fill = 0.31f; + private const float arc_radius = 0.02f; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + + InternalChild = new CircularProgress + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Current = { Value = arc_fill }, + Rotation = -arc_fill * 180, + InnerRadius = arc_radius, + RoundedCaps = true, + }; + } + } +} From 7ed26369a3e7b974466d15131bdc3e4a722ef210 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 12:41:57 +0300 Subject: [PATCH 1717/2686] Make a new report form, closer to web --- .../Overlays/Comments/CommentReportDialog.cs | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 osu.Game/Overlays/Comments/CommentReportDialog.cs diff --git a/osu.Game/Overlays/Comments/CommentReportDialog.cs b/osu.Game/Overlays/Comments/CommentReportDialog.cs new file mode 100644 index 0000000000..26a768b4ec --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentReportDialog.cs @@ -0,0 +1,144 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Resources.Localisation.Web; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Comments +{ + public class CommentReportDialog : VisibilityContainer + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider, OsuColour colours) + { + RelativeSizeAxes = Axes.Both; + + Child = new Container + { + Masking = true, + CornerRadius = 10, + Width = 500, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + Colour = colourProvider.Background6, + RelativeSizeAxes = Axes.Both, + }, + new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(10), + Children = new[] + { + new CircularContainer + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Masking = true, + Size = new Vector2(100f), + BorderColour = Color4.White, + BorderThickness = 5f, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0), + }, + new SpriteIcon + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Icon = FontAwesome.Solid.ExclamationTriangle, + Size = new Vector2(50), + }, + }, + }, + new OsuTextFlowContainer(t => t.Font = t.Font.With(size: 25)) + { + Text = UsersStrings.ReportTitle("the comment"), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + TextAnchor = Anchor.TopCentre, + }, + Empty().With(d => d.Height = 10), + new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = UsersStrings.ReportReason, + Font = OsuFont.Torus.With(size: 20), + }, + new OsuEnumDropdown + { + RelativeSizeAxes = Axes.X + }, + new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = UsersStrings.ReportComments, + Font = OsuFont.Torus.With(size: 20), + }, + new OsuTextBox + { + RelativeSizeAxes = Axes.X, + PlaceholderText = UsersStrings.ReportPlaceholder + }, + new RoundedButton + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 200, + BackgroundColour = colours.Red3, + Text = UsersStrings.ReportActionsSend, + Action = send, + Margin = new MarginPadding { Bottom = 5, Top = 10 }, + }, + new RoundedButton + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 200, + Text = UsersStrings.ReportActionsCancel, + Action = () => + { + Hide(); + Expire(); + } + } + } + } + } + }; + } + + private void send() + { + } + + protected override void PopIn() + { + } + + protected override void PopOut() + { + } + } +} From 28277dd880a20ce80d71efedb5767edda74169ef Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 17 Oct 2022 19:34:05 +0900 Subject: [PATCH 1718/2686] Fix tests --- .../Multiplayer/TestSceneMultiplayerQueueList.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs index f31261dc1f..63677ce378 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs @@ -97,14 +97,23 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - public void TestCurrentItemDoesNotHaveDeleteButton() + public void TestSingleItemDoesNotHaveDeleteButton() + { + AddStep("set all players queue mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }).WaitSafely()); + AddUntilStep("wait for queue mode change", () => MultiplayerClient.ClientAPIRoom?.QueueMode.Value == QueueMode.AllPlayers); + + assertDeleteButtonVisibility(0, false); + } + + [Test] + public void TestCurrentItemHasDeleteButtonIfNotSingle() { AddStep("set all players queue mode", () => MultiplayerClient.ChangeSettings(new MultiplayerRoomSettings { QueueMode = QueueMode.AllPlayers }).WaitSafely()); AddUntilStep("wait for queue mode change", () => MultiplayerClient.ClientAPIRoom?.QueueMode.Value == QueueMode.AllPlayers); addPlaylistItem(() => API.LocalUser.Value.OnlineID); - assertDeleteButtonVisibility(0, false); + assertDeleteButtonVisibility(0, true); assertDeleteButtonVisibility(1, true); AddStep("finish current item", () => MultiplayerClient.FinishCurrentItem().WaitSafely()); From d7e5bcbd3c401a99e5414a25cd5e097c3c6a7836 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 13:41:46 +0300 Subject: [PATCH 1719/2686] Add popover containers to overlays --- osu.Game/Overlays/BeatmapSetOverlay.cs | 24 ++++++---- .../Changelog/ChangelogSingleBuild.cs | 46 +++++++++++-------- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 207dc91ca5..904fd6ead6 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapSet; @@ -44,20 +45,25 @@ namespace osu.Game.Overlays Info info; CommentsSection comments; - Child = new FillFlowContainer + Child = new PopoverContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Children = new Drawable[] + Child = new FillFlowContainer { - info = new Info(), - new ScoresContainer + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Children = new Drawable[] { - Beatmap = { BindTarget = Header.HeaderContent.Picker.Beatmap } - }, - comments = new CommentsSection() + info = new Info(), + new ScoresContainer + { + Beatmap = { BindTarget = Header.HeaderContent.Picker.Beatmap } + }, + comments = new CommentsSection() + } } }; diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index e4f240f0e7..afdfd0ff68 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -10,6 +10,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; @@ -63,28 +64,33 @@ namespace osu.Game.Overlays.Changelog { CommentsContainer comments; - Children = new Drawable[] + Child = new PopoverContainer { - new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, - new Box + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - Height = 2, - Colour = colourProvider.Background6, - Margin = new MarginPadding { Top = 30 }, - }, - new ChangelogSupporterPromo - { - Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, - }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = 2, - Colour = colourProvider.Background6, - Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, - }, - comments = new CommentsContainer() + new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, + new Box + { + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colourProvider.Background6, + Margin = new MarginPadding { Top = 30 }, + }, + new ChangelogSupporterPromo + { + Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, + }, + new Box + { + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colourProvider.Background6, + Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, + }, + comments = new CommentsContainer() + } }; comments.ShowComments(CommentableType.Build, build.Id); From ffa22d8a682983cd8aa7e2ade12d824cb6f18f46 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 13:42:17 +0300 Subject: [PATCH 1720/2686] Update popover not to use labelled drawables --- osu.Game/Overlays/Comments/DrawableComment.cs | 5 +-- .../Overlays/Comments/ReportCommentPopover.cs | 43 ++++++++++++++----- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 998f3b8e62..04e088dc35 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -570,10 +570,7 @@ namespace osu.Game.Overlays.Comments } } - public Popover GetPopover() - { - return new ReportCommentPopover(ReportComment); - } + public Popover GetPopover() => new ReportCommentPopover(ReportComment); private class ReportToast : Toast { diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 5f9e7ff45c..ad135f7eec 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -8,7 +8,10 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Resources.Localisation.Web; using osuTK; namespace osu.Game.Overlays.Comments @@ -16,8 +19,8 @@ namespace osu.Game.Overlays.Comments public class ReportCommentPopover : OsuPopover { private readonly Action action; - private LabelledEnumDropdown reason = null!; - private LabelledTextBox info = null!; + private OsuEnumDropdown reason = null!; + private OsuTextBox info = null!; private ShakeContainer shaker = null!; public ReportCommentPopover(Action action) @@ -36,13 +39,28 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(7), Children = new Drawable[] { - reason = new LabelledEnumDropdown + new OsuSpriteText { - Label = "Reason" + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = UsersStrings.ReportReason, + Font = OsuFont.Torus.With(size: 20), }, - info = new LabelledTextBox + reason = new OsuEnumDropdown { - Label = "Additional info", + RelativeSizeAxes = Axes.X + }, + new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = UsersStrings.ReportComments, + Font = OsuFont.Torus.With(size: 20), + }, + info = new OsuTextBox + { + RelativeSizeAxes = Axes.X, + PlaceholderText = UsersStrings.ReportPlaceholder }, new Container { @@ -54,10 +72,13 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Y, Child = new RoundedButton { - BackgroundColour = colours.Pink3, - Text = "Send report", - RelativeSizeAxes = Axes.X, - Action = send + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 200, + BackgroundColour = colours.Red3, + Text = UsersStrings.ReportActionsSend, + Action = send, + Margin = new MarginPadding { Bottom = 5, Top = 10 }, } } } @@ -70,7 +91,7 @@ namespace osu.Game.Overlays.Comments string infoValue = info.Current.Value; var reasonValue = reason.Current.Value; - if (reasonValue == CommentReportReason.Other && string.IsNullOrWhiteSpace(infoValue)) + if (string.IsNullOrWhiteSpace(infoValue)) { shaker.Shake(); return; From ceb4d624b5b4749dc08ea2591ce93513aeb1afe6 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 13:43:35 +0300 Subject: [PATCH 1721/2686] Delete wip form --- .../Overlays/Comments/CommentReportDialog.cs | 144 ------------------ 1 file changed, 144 deletions(-) delete mode 100644 osu.Game/Overlays/Comments/CommentReportDialog.cs diff --git a/osu.Game/Overlays/Comments/CommentReportDialog.cs b/osu.Game/Overlays/Comments/CommentReportDialog.cs deleted file mode 100644 index 26a768b4ec..0000000000 --- a/osu.Game/Overlays/Comments/CommentReportDialog.cs +++ /dev/null @@ -1,144 +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.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Resources.Localisation.Web; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Overlays.Comments -{ - public class CommentReportDialog : VisibilityContainer - { - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, OsuColour colours) - { - RelativeSizeAxes = Axes.Both; - - Child = new Container - { - Masking = true, - CornerRadius = 10, - Width = 500, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new Box - { - Colour = colourProvider.Background6, - RelativeSizeAxes = Axes.Both, - }, - new FillFlowContainer - { - Direction = FillDirection.Vertical, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding(10), - Children = new[] - { - new CircularContainer - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Masking = true, - Size = new Vector2(100f), - BorderColour = Color4.White, - BorderThickness = 5f, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0), - }, - new SpriteIcon - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Icon = FontAwesome.Solid.ExclamationTriangle, - Size = new Vector2(50), - }, - }, - }, - new OsuTextFlowContainer(t => t.Font = t.Font.With(size: 25)) - { - Text = UsersStrings.ReportTitle("the comment"), - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - TextAnchor = Anchor.TopCentre, - }, - Empty().With(d => d.Height = 10), - new OsuSpriteText - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Text = UsersStrings.ReportReason, - Font = OsuFont.Torus.With(size: 20), - }, - new OsuEnumDropdown - { - RelativeSizeAxes = Axes.X - }, - new OsuSpriteText - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Text = UsersStrings.ReportComments, - Font = OsuFont.Torus.With(size: 20), - }, - new OsuTextBox - { - RelativeSizeAxes = Axes.X, - PlaceholderText = UsersStrings.ReportPlaceholder - }, - new RoundedButton - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Width = 200, - BackgroundColour = colours.Red3, - Text = UsersStrings.ReportActionsSend, - Action = send, - Margin = new MarginPadding { Bottom = 5, Top = 10 }, - }, - new RoundedButton - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Width = 200, - Text = UsersStrings.ReportActionsCancel, - Action = () => - { - Hide(); - Expire(); - } - } - } - } - } - }; - } - - private void send() - { - } - - protected override void PopIn() - { - } - - protected override void PopOut() - { - } - } -} From 3bcc91511fb185d63061d80268c88cec9e57e31e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 13:46:13 +0300 Subject: [PATCH 1722/2686] Update test --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 3515b5fb0a..a6524aad1a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -249,11 +249,6 @@ namespace osu.Game.Tests.Visual.Online InputManager.MoveMouseTo(btn); InputManager.Click(MouseButton.Left); }); - AddStep("Select \"other\"", () => - { - var field = this.ChildrenOfType>().Single(); - field.Current.Value = CommentReportReason.Other; - }); AddStep("Try to report", () => { var btn = this.ChildrenOfType().Single().ChildrenOfType().Single(); @@ -264,7 +259,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Nothing happened", () => this.ChildrenOfType().Any()); AddStep("Enter some text", () => { - var field = this.ChildrenOfType().Single(); + var field = this.ChildrenOfType().Single(); field.Current.Value = report_text; }); AddStep("Try to report", () => From 18cc3b0bd313772d92f58c34c2cf71e9561cb74f Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 20:23:25 +0300 Subject: [PATCH 1723/2686] Fix reason not set in test --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index a6524aad1a..54c135ba15 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -257,10 +257,12 @@ namespace osu.Game.Tests.Visual.Online }); AddWaitStep("Wait", 3); AddAssert("Nothing happened", () => this.ChildrenOfType().Any()); - AddStep("Enter some text", () => + AddStep("Set report data", () => { var field = this.ChildrenOfType().Single(); field.Current.Value = report_text; + var reason = this.ChildrenOfType>().Single(); + reason.Current.Value = CommentReportReason.Other; }); AddStep("Try to report", () => { From 797acf334f431f02795722a8495e81cfe2e181fe Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 20:41:13 +0300 Subject: [PATCH 1724/2686] Show username in popup --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- .../Overlays/Comments/ReportCommentPopover.cs | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 04e088dc35..5fca9b0b4b 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -570,7 +570,7 @@ namespace osu.Game.Overlays.Comments } } - public Popover GetPopover() => new ReportCommentPopover(ReportComment); + public Popover GetPopover() => new ReportCommentPopover(this); private class ReportToast : Toast { diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index ad135f7eec..5214f8a3e3 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -1,7 +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 System; using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Graphics; @@ -18,14 +17,14 @@ namespace osu.Game.Overlays.Comments { public class ReportCommentPopover : OsuPopover { - private readonly Action action; + private readonly DrawableComment comment; private OsuEnumDropdown reason = null!; private OsuTextBox info = null!; private ShakeContainer shaker = null!; - public ReportCommentPopover(Action action) + public ReportCommentPopover(DrawableComment comment) { - this.action = action; + this.comment = comment; } [BackgroundDependencyLoader] @@ -39,6 +38,14 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(7), Children = new Drawable[] { + new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = UsersStrings.ReportTitle(comment.Comment.User?.Username ?? comment.Comment.LegacyName!), + Font = OsuFont.Torus.With(size: 25), + Margin = new MarginPadding { Bottom = 10 } + }, new OsuSpriteText { Origin = Anchor.TopCentre, @@ -98,7 +105,7 @@ namespace osu.Game.Overlays.Comments } this.HidePopover(); - action.Invoke(reasonValue, infoValue); + comment.ReportComment(reasonValue, infoValue); } } } From cd77ae062e43a2202bd2a1e074700d30793ce4bc Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 17 Oct 2022 20:41:23 +0300 Subject: [PATCH 1725/2686] Localize the button --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 5fca9b0b4b..6182f9b188 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -333,7 +333,7 @@ namespace osu.Game.Overlays.Comments if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) actionsContainer.AddLink("Delete", deleteComment); else - actionsContainer.AddLink("Report", this.ShowPopover); + actionsContainer.AddLink(UsersStrings.ReportButtonText, this.ShowPopover); if (Comment.IsTopLevel) { From 1778120f3e2f0bf190aed2860e28f025e8a16cb6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 12:10:30 +0900 Subject: [PATCH 1726/2686] Add inline comment mentioning binding issues --- osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index bc49deedae..54d50b01c4 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -92,6 +92,9 @@ namespace osu.Game.Rulesets.Catch.Edit { switch (e.Action) { + // Note that right now these are hard to use as the default key bindings conflict with existing editor key bindings. + // In the future we will want to expose this via UI and potentially change the key bindings to be editor-specific. + // May be worth considering standardising "zoom" behaviour with what the timeline uses (ie. alt-wheel) but that may cause new conflicts. case GlobalAction.IncreaseScrollSpeed: this.TransformBindableTo(timeRangeMultiplier, timeRangeMultiplier.Value - 1, 200, Easing.OutQuint); break; From 6a7f6c76ffe7758786517cc66a9e582d742130bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 14:31:54 +0900 Subject: [PATCH 1727/2686] Fix osu! editor padding being applied to toolboxes The result of https://github.com/ppy/osu/pull/20739 and https://github.com/ppy/osu/pull/20738 having unintended side effects when applied together. --- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 3 +++ osu.Game/Rulesets/Edit/HitObjectComposer.cs | 11 ++++++++++- osu.Game/Screens/Edit/EditorScreenWithTimeline.cs | 1 - 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 60896b17bf..6b4a6e39d9 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -60,6 +60,9 @@ namespace osu.Game.Rulesets.Osu.Edit [BackgroundDependencyLoader] private void load() { + // Give a bit of breathing room around the playfield content. + PlayfieldContentContainer.Padding = new MarginPadding(10); + LayerBelowRuleset.AddRange(new Drawable[] { distanceSnapGridContainer = new Container diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 63f0c64c80..3bed835854 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Edit InternalChildren = new Drawable[] { - new Container + PlayfieldContentContainer = new Container { Name = "Content", RelativeSizeAxes = Axes.Both, @@ -166,6 +166,15 @@ namespace osu.Game.Rulesets.Edit EditorBeatmap.SelectedHitObjects.CollectionChanged += selectionChanged; } + /// + /// Houses all content relevant to the playfield. + /// + /// + /// Generally implementations should not be adding to this directly. + /// Use or instead. + /// + protected Container PlayfieldContentContainer { get; private set; } + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs index bcb084fd4e..b3aafb9730 100644 --- a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs +++ b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs @@ -106,7 +106,6 @@ namespace osu.Game.Screens.Edit Name = "Main content", RelativeSizeAxes = Axes.Both, Depth = float.MaxValue, - Padding = new MarginPadding(10), Child = spinner = new LoadingSpinner(true) { State = { Value = Visibility.Visible }, From 860214c22a11fb5107161c5bb59bb6a6ba734a02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 14:38:45 +0900 Subject: [PATCH 1728/2686] Adjust paddings to feel better now that backgrounds are visible of toolboxes --- osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs b/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs index d3371d3543..26dd5dfa55 100644 --- a/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs +++ b/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs @@ -19,7 +19,8 @@ namespace osu.Game.Rulesets.Edit { RelativeSizeAxes = Axes.Y; - FillFlow.Spacing = new Vector2(10); + FillFlow.Spacing = new Vector2(5); + Padding = new MarginPadding { Vertical = 5 }; } protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => base.ReceivePositionalInputAtSubTree(screenSpacePos) && anyToolboxHovered(screenSpacePos); From 6b42f1931acf432dcc058298d9520229aeb33a12 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 15:01:25 +0900 Subject: [PATCH 1729/2686] Remove autosize easing in `SettingsToolboxGroup` It just feels like unnecessary motion. --- osu.Game/Overlays/SettingsToolboxGroup.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index 04c9a626b5..6dd9e2a56d 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -40,8 +40,6 @@ namespace osu.Game.Overlays Anchor = Anchor.TopCentre, Direction = FillDirection.Vertical, RelativeSizeAxes = Axes.X, - AutoSizeDuration = transition_duration, - AutoSizeEasing = Easing.OutQuint, AutoSizeAxes = Axes.Y, Padding = new MarginPadding { Horizontal = 10, Top = 5, Bottom = 10 }, Spacing = new Vector2(0, 15), From fbad33bef701c45917e633d4863663be9f3c3274 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 15:01:53 +0900 Subject: [PATCH 1730/2686] Adjust durations and make start off screen --- osu.Game/Screens/Play/PlayerLoader.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index b553818a2d..4ff5083107 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -229,6 +229,9 @@ namespace osu.Game.Screens.Play Beatmap.Value.Track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment); + // Start off-screen. + settingsScroll.MoveToX(settingsScroll.DrawWidth); + content.ScaleTo(0.7f); contentIn(); @@ -404,10 +407,12 @@ namespace osu.Game.Screens.Play { MetadataInfo.Loading = true; - settingsScroll.FadeInFromZero(400); - content.FadeInFromZero(400); content.ScaleTo(1, 650, Easing.OutQuint).Then().Schedule(prepareNewPlayer); + + settingsScroll.FadeInFromZero(500, Easing.Out) + .MoveToX(0, 500, Easing.OutQuint); + lowPassFilter.CutoffTo(1000, 650, Easing.OutQuint); highPassFilter.CutoffTo(300).Then().CutoffTo(0, 1250); // 1250 is to line up with the appearance of MetadataInfo (750 delay + 500 fade-in) @@ -421,7 +426,10 @@ namespace osu.Game.Screens.Play content.ScaleTo(0.7f, CONTENT_OUT_DURATION * 2, Easing.OutQuint); content.FadeOut(CONTENT_OUT_DURATION, Easing.OutQuint); - settingsScroll.FadeOut(CONTENT_OUT_DURATION, Easing.OutQuint); + + settingsScroll.FadeOut(CONTENT_OUT_DURATION, Easing.OutQuint) + .MoveToX(settingsScroll.DrawWidth, CONTENT_OUT_DURATION * 2, Easing.OutQuint); + lowPassFilter.CutoffTo(AudioFilter.MAX_LOWPASS_CUTOFF, CONTENT_OUT_DURATION); highPassFilter.CutoffTo(0, CONTENT_OUT_DURATION); } From ec3761ced9122bdf5d5ab0b79a1de6de4ae8893c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 16:01:04 +0900 Subject: [PATCH 1731/2686] Standardise control point search logic in `OverlappingScrollAlgorithm` Was using a very local algorithm which I cannot guarantee is correct. I'd rather it just use the one used everywhere else. --- .../Gameplay/TestSceneScrollingHitObjects.cs | 4 +-- .../Beatmaps/ControlPoints/ControlPoint.cs | 5 +--- .../ControlPoints/ControlPointInfo.cs | 8 +++--- .../Beatmaps/ControlPoints/IControlPoint.cs | 13 ++++++++++ .../Rulesets/Timing/MultiplierControlPoint.cs | 12 ++++----- .../Algorithms/OverlappingScrollAlgorithm.cs | 26 +++---------------- .../Algorithms/SequentialScrollAlgorithm.cs | 6 ++--- .../UI/Scrolling/DrawableScrollingRuleset.cs | 4 +-- 8 files changed, 35 insertions(+), 43 deletions(-) create mode 100644 osu.Game/Beatmaps/ControlPoints/IControlPoint.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs index 156a1ee34a..6d036f8e9b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs @@ -214,7 +214,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void addControlPoints(IList controlPoints, double sequenceStartTime) { - controlPoints.ForEach(point => point.StartTime += sequenceStartTime); + controlPoints.ForEach(point => point.Time += sequenceStartTime); scrollContainers.ForEach(container => { @@ -224,7 +224,7 @@ namespace osu.Game.Tests.Visual.Gameplay foreach (var playfield in playfields) { foreach (var controlPoint in controlPoints) - playfield.Add(createDrawablePoint(playfield, controlPoint.StartTime)); + playfield.Add(createDrawablePoint(playfield, controlPoint.Time)); } } diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs index 56a432aec4..0a09e6e7e6 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs @@ -9,11 +9,8 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.ControlPoints { - public abstract class ControlPoint : IComparable, IDeepCloneable, IEquatable + public abstract class ControlPoint : IComparable, IDeepCloneable, IEquatable, IControlPoint { - /// - /// The time at which the control point takes effect. - /// [JsonIgnore] public double Time { get; set; } diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 4be6b5eede..cfe3c671ac 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -196,8 +196,8 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the control point at. /// The control point to use when is before any control points. /// The active control point at , or a fallback if none found. - protected T BinarySearchWithFallback(IReadOnlyList list, double time, T fallback) - where T : ControlPoint + internal static T BinarySearchWithFallback(IReadOnlyList list, double time, T fallback) + where T : class, IControlPoint { return BinarySearch(list, time) ?? fallback; } @@ -208,8 +208,8 @@ namespace osu.Game.Beatmaps.ControlPoints /// The list to search. /// The time to find the control point at. /// The active control point at . - protected virtual T BinarySearch(IReadOnlyList list, double time) - where T : ControlPoint + internal static T BinarySearch(IReadOnlyList list, double time) + where T : class, IControlPoint { if (list == null) throw new ArgumentNullException(nameof(list)); diff --git a/osu.Game/Beatmaps/ControlPoints/IControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/IControlPoint.cs new file mode 100644 index 0000000000..6a287285d8 --- /dev/null +++ b/osu.Game/Beatmaps/ControlPoints/IControlPoint.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.Beatmaps.ControlPoints +{ + public interface IControlPoint + { + /// + /// The time at which the control point takes effect. + /// + public double Time { get; } + } +} diff --git a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs index 1e80bd165b..279de2f940 100644 --- a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs +++ b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs @@ -11,12 +11,12 @@ namespace osu.Game.Rulesets.Timing /// /// A control point which adds an aggregated multiplier based on the provided 's BeatLength and 's SpeedMultiplier. /// - public class MultiplierControlPoint : IComparable + public class MultiplierControlPoint : IComparable, IControlPoint { /// /// The time in milliseconds at which this starts. /// - public double StartTime; + public double Time { get; set; } /// /// The aggregate multiplier which this provides. @@ -54,13 +54,13 @@ namespace osu.Game.Rulesets.Timing /// /// Creates a . /// - /// The start time of this . - public MultiplierControlPoint(double startTime) + /// The start time of this . + public MultiplierControlPoint(double time) { - StartTime = startTime; + Time = time; } // ReSharper disable once ImpureMethodCallOnReadonlyValueField - public int CompareTo(MultiplierControlPoint other) => StartTime.CompareTo(other?.StartTime); + public int CompareTo(MultiplierControlPoint other) => Time.CompareTo(other?.Time); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs index d41117bce8..8fd7677a52 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs @@ -5,21 +5,18 @@ using System; using osu.Framework.Lists; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Timing; namespace osu.Game.Rulesets.UI.Scrolling.Algorithms { public class OverlappingScrollAlgorithm : IScrollAlgorithm { - private readonly MultiplierControlPoint searchPoint; - private readonly SortedList controlPoints; public OverlappingScrollAlgorithm(SortedList controlPoints) { this.controlPoints = controlPoints; - - searchPoint = new MultiplierControlPoint(); } public double GetDisplayStartTime(double originTime, float offset, double timeRange, float scrollLength) @@ -52,7 +49,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms for (; i < controlPoints.Count; i++) { float lastPos = pos; - pos = PositionAt(controlPoints[i].StartTime, currentTime, timeRange, scrollLength); + pos = PositionAt(controlPoints[i].Time, currentTime, timeRange, scrollLength); if (pos > position) { @@ -64,7 +61,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms i = Math.Clamp(i, 0, controlPoints.Count - 1); - return controlPoints[i].StartTime + (position - pos) * timeRange / controlPoints[i].Multiplier / scrollLength; + return controlPoints[i].Time + (position - pos) * timeRange / controlPoints[i].Multiplier / scrollLength; } public void Reset() @@ -76,21 +73,6 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms /// /// The time which the should affect. /// The . - private MultiplierControlPoint controlPointAt(double time) - { - if (controlPoints.Count == 0) - return new MultiplierControlPoint(double.NegativeInfinity); - - if (time < controlPoints[0].StartTime) - return controlPoints[0]; - - searchPoint.StartTime = time; - int index = controlPoints.BinarySearch(searchPoint); - - if (index < 0) - index = ~index - 1; - - return controlPoints[index]; - } + private MultiplierControlPoint controlPointAt(double time) => ControlPointInfo.BinarySearch(controlPoints, time) ?? new MultiplierControlPoint(double.NegativeInfinity); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs index bfddc22573..8d43185eac 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs @@ -121,7 +121,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms if (controlPoints.Count == 0) return; - positionMappings.Add(new PositionMapping(controlPoints[0].StartTime, controlPoints[0])); + positionMappings.Add(new PositionMapping(controlPoints[0].Time, controlPoints[0])); for (int i = 0; i < controlPoints.Count - 1; i++) { @@ -129,9 +129,9 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms var next = controlPoints[i + 1]; // Figure out how much of the time range the duration represents, and adjust it by the speed multiplier - float length = (float)((next.StartTime - current.StartTime) / timeRange * current.Multiplier); + float length = (float)((next.Time - current.Time) / timeRange * current.Multiplier); - positionMappings.Add(new PositionMapping(next.StartTime, next, positionMappings[^1].Position + length)); + positionMappings.Add(new PositionMapping(next.Time, next, positionMappings[^1].Position + length)); } } diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 825aba5bc2..68469d083c 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -158,9 +158,9 @@ namespace osu.Game.Rulesets.UI.Scrolling // Trim unwanted sequences of timing changes timingChanges = timingChanges // Collapse sections after the last hit object - .Where(s => s.StartTime <= lastObjectTime) + .Where(s => s.Time <= lastObjectTime) // Collapse sections with the same start time - .GroupBy(s => s.StartTime).Select(g => g.Last()).OrderBy(s => s.StartTime); + .GroupBy(s => s.Time).Select(g => g.Last()).OrderBy(s => s.Time); ControlPoints.AddRange(timingChanges); From d237c818f6d744f4a92697f7b45cbc6ff7747dc4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 16:15:21 +0900 Subject: [PATCH 1732/2686] Fix nested objects in overlapping scrolling hit object container ruleset not using correct reference time --- .../UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs | 2 +- .../UI/Scrolling/Algorithms/IScrollAlgorithm.cs | 5 +++-- .../Scrolling/Algorithms/OverlappingScrollAlgorithm.cs | 4 ++-- .../Scrolling/Algorithms/SequentialScrollAlgorithm.cs | 2 +- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 10 +++++----- osu.Game/Tests/Visual/ScrollingTestContainer.cs | 2 +- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs index 0bd8aa64c9..c957a84eb1 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/ConstantScrollAlgorithm.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms return -PositionAt(startTime, endTime, timeRange, scrollLength); } - public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) + public float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null) => (float)((time - currentTime) / timeRange * scrollLength); public double TimeAt(float position, double currentTime, double timeRange, float scrollLength) diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs index d2fb9e3531..f78509f919 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/IScrollAlgorithm.cs @@ -53,8 +53,9 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms /// The current time. /// The amount of visible time. /// The absolute spatial length through . + /// The time to be used for control point lookups (ie. the parent's start time for nested hit objects). /// The absolute spatial position. - float PositionAt(double time, double currentTime, double timeRange, float scrollLength); + float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null); /// /// Computes the time which brings a point to a provided spatial position given the current time. @@ -63,7 +64,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms /// The current time. /// The amount of visible time. /// The absolute spatial length through . - /// The time at which == . + /// The time at which == . double TimeAt(float position, double currentTime, double timeRange, float scrollLength); /// diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs index 8fd7677a52..00bc7453d8 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs @@ -34,8 +34,8 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms return -PositionAt(startTime, endTime, timeRange, scrollLength); } - public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) - => (float)((time - currentTime) / timeRange * controlPointAt(time).Multiplier * scrollLength); + public float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null) + => (float)((time - currentTime) / timeRange * controlPointAt(originTime ?? time).Multiplier * scrollLength); public double TimeAt(float position, double currentTime, double timeRange, float scrollLength) { diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs index 8d43185eac..774beb20c7 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms return (float)(objectLength * scrollLength); } - public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) + public float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null) { double timelineLength = relativePositionAt(time, timeRange) - relativePositionAt(currentTime, timeRange); return (float)(timelineLength * scrollLength); diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 37da157cc1..443a37ab1c 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -93,9 +93,9 @@ namespace osu.Game.Rulesets.UI.Scrolling /// /// Given a time, return the position along the scrolling axis within this at time . /// - public float PositionAtTime(double time, double currentTime) + public float PositionAtTime(double time, double currentTime, double? originTime = null) { - float scrollPosition = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); + float scrollPosition = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength, originTime); return axisInverted ? -scrollPosition : scrollPosition; } @@ -252,14 +252,14 @@ namespace osu.Game.Rulesets.UI.Scrolling updateLayoutRecursive(obj); // Nested hitobjects don't need to scroll, but they do need accurate positions and start lifetime - updatePosition(obj, hitObject.HitObject.StartTime); + updatePosition(obj, hitObject.HitObject.StartTime, hitObject.HitObject.StartTime); setComputedLifetimeStart(obj.Entry); } } - private void updatePosition(DrawableHitObject hitObject, double currentTime) + private void updatePosition(DrawableHitObject hitObject, double currentTime, double? parentHitObjectStartTime = null) { - float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime); + float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime, parentHitObjectStartTime); if (scrollingAxis == Direction.Horizontal) hitObject.X = position; diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs index cf7fe6e45d..87f4bb3f3b 100644 --- a/osu.Game/Tests/Visual/ScrollingTestContainer.cs +++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs @@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual public float GetLength(double startTime, double endTime, double timeRange, float scrollLength) => implementation.GetLength(startTime, endTime, timeRange, scrollLength); - public float PositionAt(double time, double currentTime, double timeRange, float scrollLength) + public float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null) => implementation.PositionAt(time, currentTime, timeRange, scrollLength); public double TimeAt(float position, double currentTime, double timeRange, float scrollLength) From 49d5931022de62351712c71d7c53789c2bc45ac1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 16 Oct 2022 18:39:25 +0900 Subject: [PATCH 1733/2686] Initial setup with adjustable max combo --- osu.Game.Tests/Gameplay/TestSceneScoring.cs | 138 ++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 osu.Game.Tests/Gameplay/TestSceneScoring.cs diff --git a/osu.Game.Tests/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Gameplay/TestSceneScoring.cs new file mode 100644 index 0000000000..febe6aa123 --- /dev/null +++ b/osu.Game.Tests/Gameplay/TestSceneScoring.cs @@ -0,0 +1,138 @@ +// 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.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Threading; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Settings; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Judgements; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Scoring; +using osu.Game.Tests.Visual; +using osuTK.Graphics; + +namespace osu.Game.Tests.Gameplay +{ + public class TestSceneScoring : OsuTestScene + { + private Container graphs = null!; + private SettingsSlider sliderMaxCombo = null!; + + [Test] + public void TestBasic() + { + AddStep("setup tests", () => + { + Children = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + graphs = new Container + { + RelativeSizeAxes = Axes.X, + Height = 200, + }, + }, + new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Full, + Children = new Drawable[] + { + sliderMaxCombo = new SettingsSlider + { + Width = 0.5f, + Current = new BindableInt(1024) + { + MinValue = 96, + MaxValue = 8192, + }, + LabelText = "max combo", + } + } + }, + }, + } + } + }; + + sliderMaxCombo.Current.BindValueChanged(_ => rerun()); + + rerun(); + }); + } + + private ScheduledDelegate? debouncedRun; + + private void rerun() + { + graphs.Clear(); + + debouncedRun?.Cancel(); + debouncedRun = Scheduler.AddDelayed(() => + { + runForProcessor("lazer-classic", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); + runForProcessor("lazer-standardised", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); + }, 200); + } + + private void runForProcessor(string name, ScoreProcessor processor) + { + int maxCombo = sliderMaxCombo.Current.Value; + + var beatmap = new OsuBeatmap(); + + for (int i = 0; i < maxCombo; i++) + { + beatmap.HitObjects.Add(new HitCircle()); + } + + processor.ApplyBeatmap(beatmap); + + int[] missLocations = { 200, 500, 800 }; + + List results = new List(); + + for (int i = 0; i < maxCombo; i++) + { + if (missLocations.Contains(i)) + { + processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) + { + Type = HitResult.Miss + }); + } + else + { + processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) + { + Type = HitResult.Great + }); + } + + results.Add((float)processor.TotalScore.Value); + } + + graphs.Add(new LineGraph + { + RelativeSizeAxes = Axes.Both, + LineColour = Color4.Red, + Values = results + }); + } + } +} From 94c57a459defc4ee6764dae1aa6b7d0fa3fa3f69 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Oct 2022 23:27:26 +0900 Subject: [PATCH 1734/2686] Add ability to add miss locations by clicking --- osu.Game.Tests/Gameplay/TestSceneScoring.cs | 107 ++++++++++++++++++-- 1 file changed, 98 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Gameplay/TestSceneScoring.cs index febe6aa123..e18bf5f0bf 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoring.cs @@ -2,12 +2,14 @@ // 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.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; using osu.Framework.Threading; +using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Osu; @@ -22,7 +24,7 @@ namespace osu.Game.Tests.Gameplay { public class TestSceneScoring : OsuTestScene { - private Container graphs = null!; + private GraphContainer graphs = null!; private SettingsSlider sliderMaxCombo = null!; [Test] @@ -39,7 +41,7 @@ namespace osu.Game.Tests.Gameplay { new Drawable[] { - graphs = new Container + graphs = new GraphContainer { RelativeSizeAxes = Axes.X, Height = 200, @@ -70,7 +72,10 @@ namespace osu.Game.Tests.Gameplay } }; - sliderMaxCombo.Current.BindValueChanged(_ => rerun()); + sliderMaxCombo.Current.BindValueChanged(_ => rerun(true)); + graphs.MissLocations.BindCollectionChanged((_, __) => rerun()); + + graphs.MaxCombo.BindTo(sliderMaxCombo.Current); rerun(); }); @@ -78,7 +83,7 @@ namespace osu.Game.Tests.Gameplay private ScheduledDelegate? debouncedRun; - private void rerun() + private void rerun(bool debounce = false) { graphs.Clear(); @@ -87,7 +92,7 @@ namespace osu.Game.Tests.Gameplay { runForProcessor("lazer-classic", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); runForProcessor("lazer-standardised", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); - }, 200); + }, debounce ? 200 : 0); } private void runForProcessor(string name, ScoreProcessor processor) @@ -103,13 +108,11 @@ namespace osu.Game.Tests.Gameplay processor.ApplyBeatmap(beatmap); - int[] missLocations = { 200, 500, 800 }; - List results = new List(); for (int i = 0; i < maxCombo; i++) { - if (missLocations.Contains(i)) + if (graphs.MissLocations.Contains(i)) { processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { @@ -135,4 +138,90 @@ namespace osu.Game.Tests.Gameplay }); } } + + public class GraphContainer : Container + { + public readonly BindableList MissLocations = new BindableList(); + + public Bindable MaxCombo = new Bindable(); + + protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; + + private readonly Box hoverLine; + + private readonly Container missLines; + + public GraphContainer() + { + InternalChild = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + Colour = OsuColour.Gray(0.1f), + RelativeSizeAxes = Axes.Both, + }, + Content, + hoverLine = new Box + { + Colour = Color4.Yellow, + RelativeSizeAxes = Axes.Y, + Alpha = 0, + Width = 1, + }, + missLines = new Container + { + RelativeSizeAxes = Axes.Both, + }, + } + }; + + MissLocations.BindCollectionChanged((_, _) => updateMissLocations(), true); + + MaxCombo.BindValueChanged(_ => updateMissLocations()); + } + + private void updateMissLocations() + { + missLines.Clear(); + + foreach (int miss in MissLocations) + { + missLines.Add(new Box + { + Colour = Color4.Red, + Width = 1, + RelativeSizeAxes = Axes.Y, + RelativePositionAxes = Axes.X, + X = (float)miss / MaxCombo.Value, + }); + } + } + + protected override bool OnHover(HoverEvent e) + { + hoverLine.Show(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + hoverLine.Hide(); + base.OnHoverLost(e); + } + + protected override bool OnMouseMove(MouseMoveEvent e) + { + hoverLine.X = e.MousePosition.X; + return base.OnMouseMove(e); + } + + protected override bool OnClick(ClickEvent e) + { + MissLocations.Add((int)(e.MousePosition.X / DrawWidth * MaxCombo.Value)); + return true; + } + } } From 1ea2a1ff04bcac4fab4fdeee27d18ccc417d51bd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Oct 2022 23:41:07 +0900 Subject: [PATCH 1735/2686] Add basic legend and line colouring --- osu.Game.Tests/Gameplay/TestSceneScoring.cs | 54 ++++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Gameplay/TestSceneScoring.cs index e18bf5f0bf..95b7868b91 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoring.cs @@ -1,15 +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; using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Framework.Threading; using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Osu; @@ -27,6 +30,20 @@ namespace osu.Game.Tests.Gameplay private GraphContainer graphs = null!; private SettingsSlider sliderMaxCombo = null!; + private FillFlowContainer legend = null!; + + private static readonly Color4[] line_colours = + { + Color4Extensions.FromHex("588c7e"), + Color4Extensions.FromHex("b2a367"), + Color4Extensions.FromHex("c98f65"), + Color4Extensions.FromHex("bc5151"), + Color4Extensions.FromHex("5c8bd6"), + Color4Extensions.FromHex("7f6ab7"), + Color4Extensions.FromHex("a368ad"), + Color4Extensions.FromHex("aa6880"), + }; + [Test] public void TestBasic() { @@ -48,6 +65,15 @@ namespace osu.Game.Tests.Gameplay }, }, new Drawable[] + { + legend = new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + Height = 200, + }, + }, + new Drawable[] { new FillFlowContainer { @@ -58,6 +84,7 @@ namespace osu.Game.Tests.Gameplay sliderMaxCombo = new SettingsSlider { Width = 0.5f, + TransferValueOnCommit = true, Current = new BindableInt(1024) { MinValue = 96, @@ -72,7 +99,7 @@ namespace osu.Game.Tests.Gameplay } }; - sliderMaxCombo.Current.BindValueChanged(_ => rerun(true)); + sliderMaxCombo.Current.BindValueChanged(_ => rerun()); graphs.MissLocations.BindCollectionChanged((_, __) => rerun()); graphs.MaxCombo.BindTo(sliderMaxCombo.Current); @@ -81,22 +108,19 @@ namespace osu.Game.Tests.Gameplay }); } - private ScheduledDelegate? debouncedRun; - - private void rerun(bool debounce = false) + private void rerun() { graphs.Clear(); + legend.Clear(); - debouncedRun?.Cancel(); - debouncedRun = Scheduler.AddDelayed(() => - { - runForProcessor("lazer-classic", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); - runForProcessor("lazer-standardised", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); - }, debounce ? 200 : 0); + runForProcessor("lazer-classic", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); + runForProcessor("lazer-standardised", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); } private void runForProcessor(string name, ScoreProcessor processor) { + Color4 colour = line_colours[Math.Abs(name.GetHashCode()) % line_colours.Length]; + int maxCombo = sliderMaxCombo.Current.Value; var beatmap = new OsuBeatmap(); @@ -133,9 +157,15 @@ namespace osu.Game.Tests.Gameplay graphs.Add(new LineGraph { RelativeSizeAxes = Axes.Both, - LineColour = Color4.Red, + LineColour = colour, Values = results }); + + legend.Add(new OsuSpriteText + { + Colour = colour, + Text = $"{FontAwesome.Solid.Circle.Icon} {name}" + }); } } From 19b4d2d25ed4ed28a9bb4db2db8130da2298079c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Oct 2022 23:49:15 +0900 Subject: [PATCH 1736/2686] Add vertical grid lines --- osu.Game.Tests/Gameplay/TestSceneScoring.cs | 33 +++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Gameplay/TestSceneScoring.cs index 95b7868b91..363f1ea758 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoring.cs @@ -180,6 +180,7 @@ namespace osu.Game.Tests.Gameplay private readonly Box hoverLine; private readonly Container missLines; + private readonly Container verticalGridLines; public GraphContainer() { @@ -193,6 +194,10 @@ namespace osu.Game.Tests.Gameplay Colour = OsuColour.Gray(0.1f), RelativeSizeAxes = Axes.Both, }, + verticalGridLines = new Container + { + RelativeSizeAxes = Axes.Both, + }, Content, hoverLine = new Box { @@ -208,9 +213,33 @@ namespace osu.Game.Tests.Gameplay } }; - MissLocations.BindCollectionChanged((_, _) => updateMissLocations(), true); + MissLocations.BindCollectionChanged((_, _) => updateMissLocations()); - MaxCombo.BindValueChanged(_ => updateMissLocations()); + MaxCombo.BindValueChanged(_ => + { + updateMissLocations(); + updateVerticalGridLines(); + }, true); + } + + private void updateVerticalGridLines() + { + verticalGridLines.Clear(); + + for (int i = 0; i < MaxCombo.Value; i++) + { + if (i % 100 == 0) + { + verticalGridLines.Add(new Box + { + Colour = OsuColour.Gray(0.2f), + Width = 1, + RelativeSizeAxes = Axes.Y, + RelativePositionAxes = Axes.X, + X = (float)i / MaxCombo.Value, + }); + } + } } private void updateMissLocations() From c77847b2844ae8e7f8793a092884c00545b54927 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 16:50:30 +0900 Subject: [PATCH 1737/2686] Improve layout and add combo text --- osu.Game.Tests/Gameplay/TestSceneScoring.cs | 41 ++++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Gameplay/TestSceneScoring.cs index 363f1ea758..54ead45992 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoring.cs @@ -54,30 +54,38 @@ namespace osu.Game.Tests.Gameplay new GridContainer { RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + }, Content = new[] { new Drawable[] { graphs = new GraphContainer { - RelativeSizeAxes = Axes.X, - Height = 200, + RelativeSizeAxes = Axes.Both, }, }, new Drawable[] { legend = new FillFlowContainer { + Padding = new MarginPadding(20), Direction = FillDirection.Vertical, RelativeSizeAxes = Axes.X, - Height = 200, + AutoSizeAxes = Axes.Y, }, }, new Drawable[] { new FillFlowContainer { - RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(20), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Direction = FillDirection.Full, Children = new Drawable[] { @@ -230,13 +238,26 @@ namespace osu.Game.Tests.Gameplay { if (i % 100 == 0) { - verticalGridLines.Add(new Box + verticalGridLines.AddRange(new Drawable[] { - Colour = OsuColour.Gray(0.2f), - Width = 1, - RelativeSizeAxes = Axes.Y, - RelativePositionAxes = Axes.X, - X = (float)i / MaxCombo.Value, + new Box + { + Colour = OsuColour.Gray(0.2f), + Width = 1, + RelativeSizeAxes = Axes.Y, + RelativePositionAxes = Axes.X, + X = (float)i / MaxCombo.Value, + }, + new OsuSpriteText + { + RelativePositionAxes = Axes.X, + X = (float)i / MaxCombo.Value, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Text = $"{i:#,0}", + Rotation = -30, + Y = -20, + } }); } } From d694c8b7711693b53a9bc3db22c420940688a4c3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 16:55:04 +0900 Subject: [PATCH 1738/2686] Move test scene more correctly into visual folder --- osu.Game.Tests/{ => Visual}/Gameplay/TestSceneScoring.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename osu.Game.Tests/{ => Visual}/Gameplay/TestSceneScoring.cs (99%) diff --git a/osu.Game.Tests/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs similarity index 99% rename from osu.Game.Tests/Gameplay/TestSceneScoring.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index 54ead45992..f2ad97dc03 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -20,10 +20,9 @@ using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; -using osu.Game.Tests.Visual; using osuTK.Graphics; -namespace osu.Game.Tests.Gameplay +namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneScoring : OsuTestScene { From 7360cca047baa8ad309c1fe459433a8792647533 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 17:23:23 +0900 Subject: [PATCH 1739/2686] Add stable v1 algorithm --- .../Visual/Gameplay/TestSceneScoring.cs | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index f2ad97dc03..1cd96a65e9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -122,43 +122,60 @@ namespace osu.Game.Tests.Visual.Gameplay runForProcessor("lazer-classic", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); runForProcessor("lazer-standardised", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); + + int totalScore = 0; + int currentCombo = 0; + + runForAlgorithm("stable-v1", () => + { + const int base_score = 300; + const float score_multiplier = 1; + + totalScore += base_score; + + // combo multiplier + // ReSharper disable once PossibleLossOfFraction + totalScore += (int)(Math.Max(0, currentCombo - 1) * (base_score / 25 * score_multiplier)); + + currentCombo++; + }, () => + { + currentCombo = 0; + }, () => totalScore); } private void runForProcessor(string name, ScoreProcessor processor) { - Color4 colour = line_colours[Math.Abs(name.GetHashCode()) % line_colours.Length]; - int maxCombo = sliderMaxCombo.Current.Value; var beatmap = new OsuBeatmap(); - for (int i = 0; i < maxCombo; i++) - { beatmap.HitObjects.Add(new HitCircle()); - } processor.ApplyBeatmap(beatmap); + runForAlgorithm(name, + () => processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { Type = HitResult.Great }), + () => processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { Type = HitResult.Miss }), + () => (int)processor.TotalScore.Value); + } + + private void runForAlgorithm(string name, Action applyHit, Action applyMiss, Func getTotalScore) + { + int maxCombo = sliderMaxCombo.Current.Value; + + Color4 colour = line_colours[Math.Abs(name.GetHashCode()) % line_colours.Length]; + List results = new List(); for (int i = 0; i < maxCombo; i++) { if (graphs.MissLocations.Contains(i)) - { - processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) - { - Type = HitResult.Miss - }); - } + applyMiss(); else - { - processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) - { - Type = HitResult.Great - }); - } + applyHit(); - results.Add((float)processor.TotalScore.Value); + results.Add(getTotalScore()); } graphs.Add(new LineGraph From 743ae10df5f9e537605d3431ded469a4d8d74420 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 17:28:13 +0900 Subject: [PATCH 1740/2686] Improve colouring --- .../Visual/Gameplay/TestSceneScoring.cs | 26 +++++-------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index 1cd96a65e9..d7d5a8f4ab 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -31,18 +31,6 @@ namespace osu.Game.Tests.Visual.Gameplay private FillFlowContainer legend = null!; - private static readonly Color4[] line_colours = - { - Color4Extensions.FromHex("588c7e"), - Color4Extensions.FromHex("b2a367"), - Color4Extensions.FromHex("c98f65"), - Color4Extensions.FromHex("bc5151"), - Color4Extensions.FromHex("5c8bd6"), - Color4Extensions.FromHex("7f6ab7"), - Color4Extensions.FromHex("a368ad"), - Color4Extensions.FromHex("aa6880"), - }; - [Test] public void TestBasic() { @@ -120,13 +108,13 @@ namespace osu.Game.Tests.Visual.Gameplay graphs.Clear(); legend.Clear(); - runForProcessor("lazer-classic", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); - runForProcessor("lazer-standardised", new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); + runForProcessor("lazer-standardised", Color4.Cyan, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); + runForProcessor("lazer-classic", Color4.Orange, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); int totalScore = 0; int currentCombo = 0; - runForAlgorithm("stable-v1", () => + runForAlgorithm("stable-v1", Color4.Beige, () => { const int base_score = 300; const float score_multiplier = 1; @@ -144,7 +132,7 @@ namespace osu.Game.Tests.Visual.Gameplay }, () => totalScore); } - private void runForProcessor(string name, ScoreProcessor processor) + private void runForProcessor(string name, Color4 colour, ScoreProcessor processor) { int maxCombo = sliderMaxCombo.Current.Value; @@ -154,18 +142,16 @@ namespace osu.Game.Tests.Visual.Gameplay processor.ApplyBeatmap(beatmap); - runForAlgorithm(name, + runForAlgorithm(name, colour, () => processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { Type = HitResult.Great }), () => processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { Type = HitResult.Miss }), () => (int)processor.TotalScore.Value); } - private void runForAlgorithm(string name, Action applyHit, Action applyMiss, Func getTotalScore) + private void runForAlgorithm(string name, Color4 colour, Action applyHit, Action applyMiss, Func getTotalScore) { int maxCombo = sliderMaxCombo.Current.Value; - Color4 colour = line_colours[Math.Abs(name.GetHashCode()) % line_colours.Length]; - List results = new List(); for (int i = 0; i < maxCombo; i++) From 4b2fe72a908d9c20aa2dce1e9d12a7286d767299 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 17:50:51 +0900 Subject: [PATCH 1741/2686] Add stable v2 algorithm --- .../Visual/Gameplay/TestSceneScoring.cs | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index d7d5a8f4ab..937c52a3cf 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -109,14 +108,15 @@ namespace osu.Game.Tests.Visual.Gameplay legend.Clear(); runForProcessor("lazer-standardised", Color4.Cyan, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); - runForProcessor("lazer-classic", Color4.Orange, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); + runForProcessor("lazer-classic", Color4.MediumPurple, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); int totalScore = 0; int currentCombo = 0; - runForAlgorithm("stable-v1", Color4.Beige, () => + const int base_score = 300; + + runForAlgorithm("ScoreV1 (classic)", Color4.Beige, () => { - const int base_score = 300; const float score_multiplier = 1; totalScore += base_score; @@ -130,6 +130,43 @@ namespace osu.Game.Tests.Visual.Gameplay { currentCombo = 0; }, () => totalScore); + + double comboPortion = 0; + + int maxCombo = sliderMaxCombo.Current.Value; + + double currentBaseScore = 0; + double maxBaseScore = 0; + + int currentHits = 0; + + double comboPortionMax = 0; + for (int i = 0; i < maxCombo; i++) + comboPortionMax += base_score * (1 + (i + 1) / 10.0); + + runForAlgorithm("ScoreV2", Color4.OrangeRed, () => + { + maxBaseScore += base_score; + currentBaseScore += base_score; + comboPortion += base_score * (1 + ++currentCombo / 10.0); + + currentHits++; + }, () => + { + currentHits++; + maxBaseScore += base_score; + + currentCombo = 0; + }, () => + { + double accuracy = currentBaseScore / maxBaseScore; + + return (int)Math.Round + ( + 700000 * comboPortion / comboPortionMax + + 300000 * Math.Pow(accuracy, 10) * ((double)currentHits / maxCombo) + ); + }); } private void runForProcessor(string name, Color4 colour, ScoreProcessor processor) From 74986e0c8c38c3ba600dc6e1292fe61e67f96165 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 18:05:54 +0900 Subject: [PATCH 1742/2686] Show final scores and change colouring again --- .../Visual/Gameplay/TestSceneScoring.cs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index 937c52a3cf..5f053e9982 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -60,7 +60,7 @@ namespace osu.Game.Tests.Visual.Gameplay legend = new FillFlowContainer { Padding = new MarginPadding(20), - Direction = FillDirection.Vertical, + Direction = FillDirection.Full, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }, @@ -107,7 +107,7 @@ namespace osu.Game.Tests.Visual.Gameplay graphs.Clear(); legend.Clear(); - runForProcessor("lazer-standardised", Color4.Cyan, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); + runForProcessor("lazer-standardised", Color4.YellowGreen, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); runForProcessor("lazer-classic", Color4.MediumPurple, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); int totalScore = 0; @@ -115,7 +115,7 @@ namespace osu.Game.Tests.Visual.Gameplay const int base_score = 300; - runForAlgorithm("ScoreV1 (classic)", Color4.Beige, () => + runForAlgorithm("ScoreV1 (classic)", Color4.Purple, () => { const float score_multiplier = 1; @@ -129,7 +129,13 @@ namespace osu.Game.Tests.Visual.Gameplay }, () => { currentCombo = 0; - }, () => totalScore); + }, () => + { + // Arbitrary value chosen towards the upper range. + const double score_multiplier = 4; + + return (int)(totalScore * score_multiplier); + }); double comboPortion = 0; @@ -211,8 +217,18 @@ namespace osu.Game.Tests.Visual.Gameplay legend.Add(new OsuSpriteText { Colour = colour, + RelativeSizeAxes = Axes.X, + Width = 0.5f, Text = $"{FontAwesome.Solid.Circle.Icon} {name}" }); + + legend.Add(new OsuSpriteText + { + Colour = colour, + RelativeSizeAxes = Axes.X, + Width = 0.5f, + Text = $"final score {getTotalScore():#,0}" + }); } } From a7b3aa62fb4b560c88e95c2be8e318a6e6f9ccf1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 18:13:13 +0900 Subject: [PATCH 1743/2686] Move lines to background to better visualise graphs at points of change --- osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index 5f053e9982..14678bd617 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Settings; @@ -85,6 +86,13 @@ namespace osu.Game.Tests.Visual.Gameplay MaxValue = 8192, }, LabelText = "max combo", + }, + new OsuTextFlowContainer + { + RelativeSizeAxes = Axes.X, + Width = 0.5f, + AutoSizeAxes = Axes.Y, + Text = "Left click to add miss" } } }, @@ -261,18 +269,20 @@ namespace osu.Game.Tests.Visual.Gameplay { RelativeSizeAxes = Axes.Both, }, - Content, hoverLine = new Box { Colour = Color4.Yellow, RelativeSizeAxes = Axes.Y, + Origin = Anchor.TopCentre, Alpha = 0, Width = 1, }, missLines = new Container { + Alpha = 0.6f, RelativeSizeAxes = Axes.Both, }, + Content, } }; @@ -298,6 +308,7 @@ namespace osu.Game.Tests.Visual.Gameplay new Box { Colour = OsuColour.Gray(0.2f), + Origin = Anchor.TopCentre, Width = 1, RelativeSizeAxes = Axes.Y, RelativePositionAxes = Axes.X, @@ -327,6 +338,7 @@ namespace osu.Game.Tests.Visual.Gameplay missLines.Add(new Box { Colour = Color4.Red, + Origin = Anchor.TopCentre, Width = 1, RelativeSizeAxes = Axes.Y, RelativePositionAxes = Axes.X, From 74e1b5794bcfd1d30f086d8f999b6b73469a16fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 18:27:05 +0900 Subject: [PATCH 1744/2686] Add ability to add "OK" or 100s via right click --- .../Visual/Gameplay/TestSceneScoring.cs | 132 +++++++++++++----- 1 file changed, 94 insertions(+), 38 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index 14678bd617..f0deeb118b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -21,6 +21,7 @@ using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; using osuTK.Graphics; +using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { @@ -92,7 +93,7 @@ namespace osu.Game.Tests.Visual.Gameplay RelativeSizeAxes = Axes.X, Width = 0.5f, AutoSizeAxes = Axes.Y, - Text = "Left click to add miss" + Text = $"Left click to add miss\nRight click to add OK/{base_ok}" } } }, @@ -102,7 +103,9 @@ namespace osu.Game.Tests.Visual.Gameplay }; sliderMaxCombo.Current.BindValueChanged(_ => rerun()); + graphs.MissLocations.BindCollectionChanged((_, __) => rerun()); + graphs.NonPerfectLocations.BindCollectionChanged((_, __) => rerun()); graphs.MaxCombo.BindTo(sliderMaxCombo.Current); @@ -110,6 +113,9 @@ namespace osu.Game.Tests.Visual.Gameplay }); } + private const int base_great = 300; + private const int base_ok = 100; + private void rerun() { graphs.Clear(); @@ -118,33 +124,50 @@ namespace osu.Game.Tests.Visual.Gameplay runForProcessor("lazer-standardised", Color4.YellowGreen, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Standardised } }); runForProcessor("lazer-classic", Color4.MediumPurple, new ScoreProcessor(new OsuRuleset()) { Mode = { Value = ScoringMode.Classic } }); + runScoreV1(); + runScoreV2(); + } + + private void runScoreV1() + { int totalScore = 0; int currentCombo = 0; - const int base_score = 300; - - runForAlgorithm("ScoreV1 (classic)", Color4.Purple, () => + void applyHitV1(int baseScore) { + if (baseScore == 0) + { + currentCombo = 0; + return; + } + const float score_multiplier = 1; - totalScore += base_score; + totalScore += baseScore; // combo multiplier // ReSharper disable once PossibleLossOfFraction - totalScore += (int)(Math.Max(0, currentCombo - 1) * (base_score / 25 * score_multiplier)); + totalScore += (int)(Math.Max(0, currentCombo - 1) * (baseScore / 25 * score_multiplier)); currentCombo++; - }, () => - { - currentCombo = 0; - }, () => - { - // Arbitrary value chosen towards the upper range. - const double score_multiplier = 4; + } - return (int)(totalScore * score_multiplier); - }); + runForAlgorithm("ScoreV1 (classic)", Color4.Purple, + () => applyHitV1(base_great), + () => applyHitV1(base_ok), + () => applyHitV1(0), + () => + { + // Arbitrary value chosen towards the upper range. + const double score_multiplier = 4; + return (int)(totalScore * score_multiplier); + }); + } + + private void runScoreV2() + { + int currentCombo = 0; double comboPortion = 0; int maxCombo = sliderMaxCombo.Current.Value; @@ -154,33 +177,43 @@ namespace osu.Game.Tests.Visual.Gameplay int currentHits = 0; - double comboPortionMax = 0; for (int i = 0; i < maxCombo; i++) - comboPortionMax += base_score * (1 + (i + 1) / 10.0); + applyHitV2(base_great); - runForAlgorithm("ScoreV2", Color4.OrangeRed, () => + double comboPortionMax = comboPortion; + + comboPortion = 0; + maxBaseScore = 0; + currentBaseScore = 0; + currentHits = 0; + + void applyHitV2(int baseScore) { - maxBaseScore += base_score; - currentBaseScore += base_score; - comboPortion += base_score * (1 + ++currentCombo / 10.0); + maxBaseScore += baseScore; + currentBaseScore += baseScore; + comboPortion += baseScore * (1 + ++currentCombo / 10.0); currentHits++; - }, () => - { - currentHits++; - maxBaseScore += base_score; + } - currentCombo = 0; - }, () => - { - double accuracy = currentBaseScore / maxBaseScore; + runForAlgorithm("ScoreV2", Color4.OrangeRed, + () => applyHitV2(base_great), + () => applyHitV2(base_ok), + () => + { + currentHits++; + maxBaseScore += base_great; + currentCombo = 0; + }, () => + { + double accuracy = currentBaseScore / maxBaseScore; - return (int)Math.Round - ( - 700000 * comboPortion / comboPortionMax + - 300000 * Math.Pow(accuracy, 10) * ((double)currentHits / maxCombo) - ); - }); + return (int)Math.Round + ( + 700000 * comboPortion / comboPortionMax + + 300000 * Math.Pow(accuracy, 10) * ((double)currentHits / maxCombo) + ); + }); } private void runForProcessor(string name, Color4 colour, ScoreProcessor processor) @@ -195,11 +228,12 @@ namespace osu.Game.Tests.Visual.Gameplay runForAlgorithm(name, colour, () => processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { Type = HitResult.Great }), + () => processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { Type = HitResult.Ok }), () => processor.ApplyResult(new OsuJudgementResult(new HitCircle(), new OsuJudgement()) { Type = HitResult.Miss }), () => (int)processor.TotalScore.Value); } - private void runForAlgorithm(string name, Color4 colour, Action applyHit, Action applyMiss, Func getTotalScore) + private void runForAlgorithm(string name, Color4 colour, Action applyHit, Action applyNonPerfect, Action applyMiss, Func getTotalScore) { int maxCombo = sliderMaxCombo.Current.Value; @@ -209,6 +243,8 @@ namespace osu.Game.Tests.Visual.Gameplay { if (graphs.MissLocations.Contains(i)) applyMiss(); + else if (graphs.NonPerfectLocations.Contains(i)) + applyNonPerfect(); else applyHit(); @@ -243,6 +279,7 @@ namespace osu.Game.Tests.Visual.Gameplay public class GraphContainer : Container { public readonly BindableList MissLocations = new BindableList(); + public readonly BindableList NonPerfectLocations = new BindableList(); public Bindable MaxCombo = new Bindable(); @@ -287,6 +324,7 @@ namespace osu.Game.Tests.Visual.Gameplay }; MissLocations.BindCollectionChanged((_, _) => updateMissLocations()); + NonPerfectLocations.BindCollectionChanged((_, _) => updateMissLocations()); MaxCombo.BindValueChanged(_ => { @@ -345,6 +383,19 @@ namespace osu.Game.Tests.Visual.Gameplay X = (float)miss / MaxCombo.Value, }); } + + foreach (int miss in NonPerfectLocations) + { + missLines.Add(new Box + { + Colour = Color4.Orange, + Origin = Anchor.TopCentre, + Width = 1, + RelativeSizeAxes = Axes.Y, + RelativePositionAxes = Axes.X, + X = (float)miss / MaxCombo.Value, + }); + } } protected override bool OnHover(HoverEvent e) @@ -365,9 +416,14 @@ namespace osu.Game.Tests.Visual.Gameplay return base.OnMouseMove(e); } - protected override bool OnClick(ClickEvent e) + protected override bool OnMouseDown(MouseDownEvent e) { - MissLocations.Add((int)(e.MousePosition.X / DrawWidth * MaxCombo.Value)); + int combo = (int)(e.MousePosition.X / DrawWidth * MaxCombo.Value); + + if (e.Button == MouseButton.Left) + MissLocations.Add(combo); + else + NonPerfectLocations.Add(combo); return true; } } From d92aca7c22dbd8c6674037ef8078d567f80fad8e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 18:30:18 +0900 Subject: [PATCH 1745/2686] Fix scoreV2 being higher than intended --- osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index f0deeb118b..7743b44bd4 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -167,14 +167,12 @@ namespace osu.Game.Tests.Visual.Gameplay private void runScoreV2() { - int currentCombo = 0; - double comboPortion = 0; - int maxCombo = sliderMaxCombo.Current.Value; + int currentCombo = 0; + double comboPortion = 0; double currentBaseScore = 0; double maxBaseScore = 0; - int currentHits = 0; for (int i = 0; i < maxCombo; i++) @@ -182,9 +180,10 @@ namespace osu.Game.Tests.Visual.Gameplay double comboPortionMax = comboPortion; + currentCombo = 0; comboPortion = 0; - maxBaseScore = 0; currentBaseScore = 0; + maxBaseScore = 0; currentHits = 0; void applyHitV2(int baseScore) From d5666ca7179cef03dda84d989918a48ded3cfc82 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 19:01:43 +0900 Subject: [PATCH 1746/2686] Add tooltip display of current values --- .../Visual/Gameplay/TestSceneScoring.cs | 79 +++++++++++++++++-- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index 7743b44bd4..ec98d00e68 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -3,10 +3,12 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; @@ -20,6 +22,7 @@ using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; +using osuTK; using osuTK.Graphics; using osuTK.Input; @@ -252,6 +255,7 @@ namespace osu.Game.Tests.Visual.Gameplay graphs.Add(new LineGraph { + Name = name, RelativeSizeAxes = Axes.Both, LineColour = colour, Values = results @@ -275,7 +279,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - public class GraphContainer : Container + public class GraphContainer : Container, IHasCustomTooltip> { public readonly BindableList MissLocations = new BindableList(); public readonly BindableList NonPerfectLocations = new BindableList(); @@ -289,6 +293,8 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly Container missLines; private readonly Container verticalGridLines; + public int CurrentHoverCombo { get; private set; } + public GraphContainer() { InternalChild = new Container @@ -411,19 +417,82 @@ namespace osu.Game.Tests.Visual.Gameplay protected override bool OnMouseMove(MouseMoveEvent e) { + CurrentHoverCombo = (int)(e.MousePosition.X / DrawWidth * MaxCombo.Value); + hoverLine.X = e.MousePosition.X; return base.OnMouseMove(e); } protected override bool OnMouseDown(MouseDownEvent e) { - int combo = (int)(e.MousePosition.X / DrawWidth * MaxCombo.Value); - if (e.Button == MouseButton.Left) - MissLocations.Add(combo); + MissLocations.Add(CurrentHoverCombo); else - NonPerfectLocations.Add(combo); + NonPerfectLocations.Add(CurrentHoverCombo); + return true; } + + private GraphTooltip? tooltip; + + public ITooltip> GetCustomTooltip() => tooltip ??= new GraphTooltip(this); + + public IEnumerable TooltipContent => Content.OfType(); + + public class GraphTooltip : CompositeDrawable, ITooltip> + { + private readonly GraphContainer graphContainer; + + private readonly OsuTextFlowContainer textFlow; + + public GraphTooltip(GraphContainer graphContainer) + { + this.graphContainer = graphContainer; + AutoSizeAxes = Axes.Both; + + Masking = true; + CornerRadius = 10; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = OsuColour.Gray(0.15f), + RelativeSizeAxes = Axes.Both, + }, + textFlow = new OsuTextFlowContainer + { + Colour = Color4.White, + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding(10), + } + }; + } + + private int? lastContentCombo; + + public void SetContent(IEnumerable content) + { + int relevantCombo = graphContainer.CurrentHoverCombo; + + if (lastContentCombo == relevantCombo) + return; + + lastContentCombo = relevantCombo; + textFlow.Clear(); + + textFlow.AddParagraph($"At combo {relevantCombo}:"); + + foreach (var graph in content) + { + float valueAtHover = graph.Values.ElementAt(relevantCombo); + float ofTotal = valueAtHover / graph.Values.Last(); + + textFlow.AddParagraph($"{graph.Name}: {valueAtHover:#,0} ({ofTotal * 100:N0}% of final)\n", st => st.Colour = graph.LineColour); + } + } + + public void Move(Vector2 pos) => this.MoveTo(pos); + } } } From f23bc484dc2c925d7405f879be9d4ddd13508e76 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Oct 2022 19:15:11 +0900 Subject: [PATCH 1747/2686] Use better method of positioning mouse over visual settings area --- .../Visual/Background/TestSceneUserDimBackgrounds.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index 5aadd6f56a..917434ae22 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -244,7 +244,10 @@ namespace osu.Game.Tests.Visual.Background public void TestResumeFromPlayer() { performFullSetup(); - AddStep("Move mouse to Visual Settings", () => InputManager.MoveMouseTo(playerLoader.VisualSettingsPos)); + AddStep("Move mouse to Visual Settings location", () => InputManager.MoveMouseTo(playerLoader.ScreenSpaceDrawQuad.TopRight + + new Vector2(-playerLoader.VisualSettingsPos.ScreenSpaceDrawQuad.Width, + playerLoader.VisualSettingsPos.ScreenSpaceDrawQuad.Height / 2 + ))); AddStep("Resume PlayerLoader", () => player.Restart()); AddUntilStep("Screen is dimmed and blur applied", () => songSelect.IsBackgroundDimmed() && songSelect.IsUserBlurApplied()); AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos)); From e1a8bfa135a103540ad232555fd7f7f33e3eee45 Mon Sep 17 00:00:00 2001 From: Dario Headley Date: Tue, 18 Oct 2022 13:39:40 +0200 Subject: [PATCH 1748/2686] Fixed approachCircle preempt --- .../Mods/OsuModApproachDifferent.cs | 2 +- .../Mods/OsuModFreezeFrame.cs | 42 +++++++++++++++---- osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs | 2 +- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs index ec93f19e17..f213d9f193 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModApproachDifferent.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override double ScoreMultiplier => 1; public override IconUsage? Icon { get; } = FontAwesome.Regular.Circle; - public override Type[] IncompatibleMods => new[] { typeof(IHidesApproachCircles) }; + public override Type[] IncompatibleMods => new[] { typeof(IHidesApproachCircles), typeof(OsuModFreezeFrame) }; [SettingSource("Initial size", "Change the initial size of the approach circle, relative to hit circles.", 0)] public BindableFloat Scale { get; } = new BindableFloat(4) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index a91d7831c3..f2ee93a704 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -1,17 +1,20 @@ // 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.Linq; +using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.UI; -using osu.Game.Rulesets.UI; +using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModFreezeFrame : Mod, IApplicableToBeatmap, IApplicableToDrawableRuleset + public class OsuModFreezeFrame : Mod, IApplicableToDrawableHitObject, IApplicableToBeatmap + { public override string Name => "Freeze Frame"; @@ -21,16 +24,18 @@ namespace osu.Game.Rulesets.Osu.Mods public override LocalisableString Description => "Burn the notes into your memory."; + //Alters the transforms of the approach circles, breaking the effects of these mods. + public override Type[] IncompatibleMods => new[] { typeof(OsuModApproachDifferent), /*typeof(OsuModHidden)*/ }; + public override ModType Type => ModType.Fun; - public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) - { - (drawableRuleset.Playfield as OsuPlayfield)?.FollowPoints.Hide(); - } + //mod breaks normal approach circle preempt + private double approachCircleTimePreempt; public void ApplyToBeatmap(IBeatmap beatmap) { double lastNewComboTime = 0; + approachCircleTimePreempt = beatmap.HitObjects.OfType().FirstOrDefault()!.TimePreempt; foreach (var obj in beatmap.HitObjects.OfType()) { @@ -58,5 +63,28 @@ namespace osu.Game.Rulesets.Osu.Mods } } } + + public void ApplyToDrawableHitObject(DrawableHitObject drawableObject) + { + drawableObject.ApplyCustomUpdateState += (drawableHitObject, _) => + { + if (drawableHitObject is not DrawableHitCircle drawableHitCircle) return; + + var hitCircle = drawableHitCircle.HitObject; + var approachCircle = drawableHitCircle.ApproachCircle; + + approachCircle.ClearTransforms(); + approachCircle.ScaleTo(4); + approachCircle.FadeTo(0); + + using (drawableHitCircle.ApproachCircle.BeginAbsoluteSequence(hitCircle.StartTime - approachCircleTimePreempt)) + { + //Redo ApproachCircle animation with correct startTime. + approachCircle.LifetimeStart = hitCircle.StartTime - approachCircleTimePreempt; + approachCircle.FadeTo(1, Math.Min(hitCircle.TimeFadeIn * 2, hitCircle.TimePreempt)); + approachCircle.ScaleTo(1, approachCircleTimePreempt).Then().Expire(); + } + }; + } } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index 996ee1cddb..2d7c0c82de 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override LocalisableString Description => @"Play with no approach circles and fading circles/sliders."; public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1; - public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSpinIn) }; + public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSpinIn), typeof(OsuModFreezeFrame) }; public const double FADE_IN_DURATION_MULTIPLIER = 0.4; public const double FADE_OUT_DURATION_MULTIPLIER = 0.3; From acf3498f83a225ddf10bef957370655944f1e2fd Mon Sep 17 00:00:00 2001 From: "D.Headley" Date: Tue, 18 Oct 2022 13:49:10 +0200 Subject: [PATCH 1749/2686] Code Quality --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index f2ee93a704..7395e09d97 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -14,7 +14,6 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Mods { public class OsuModFreezeFrame : Mod, IApplicableToDrawableHitObject, IApplicableToBeatmap - { public override string Name => "Freeze Frame"; From 764bc1948fffea55f1fd0eb13150949fdbf88c83 Mon Sep 17 00:00:00 2001 From: "D.Headley" Date: Tue, 18 Oct 2022 14:59:43 +0200 Subject: [PATCH 1750/2686] remove commented out Incompatible mod --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 7395e09d97..8bf2c89057 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override LocalisableString Description => "Burn the notes into your memory."; //Alters the transforms of the approach circles, breaking the effects of these mods. - public override Type[] IncompatibleMods => new[] { typeof(OsuModApproachDifferent), /*typeof(OsuModHidden)*/ }; + public override Type[] IncompatibleMods => new[] { typeof(OsuModApproachDifferent), typeof(OsuModHidden) }; public override ModType Type => ModType.Fun; From d6ed5612802cbf5b0a5d83e69e6d7fdfe375bcd8 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Wed, 19 Oct 2022 00:16:24 +0900 Subject: [PATCH 1751/2686] make EndPlacement virtual --- .../Edit/Blueprints/HitPlacementBlueprint.cs | 1 + osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs index 08e7e57688..863a2c9eac 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs @@ -26,6 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Edit.Blueprints Size = new Vector2(TaikoHitObject.DEFAULT_SIZE * TaikoPlayfield.DEFAULT_HEIGHT) }; } + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 3bed835854..0266317817 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -359,7 +359,7 @@ namespace osu.Game.Rulesets.Edit EditorBeatmap.PlacementObject.Value = hitObject; } - public void EndPlacement(HitObject hitObject, bool commit) + public virtual void EndPlacement(HitObject hitObject, bool commit) { EditorBeatmap.PlacementObject.Value = null; From 2245456224ceaeb200f9270f1909a25b8e4107e2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 Oct 2022 22:22:53 +0300 Subject: [PATCH 1752/2686] Remove fade easing from legacy hit circles on hit --- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 1b2ab82044..f9f9751b6c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -134,10 +134,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy switch (state) { case ArmedState.Hit: - CircleSprite.FadeOut(legacy_fade_duration, Easing.Out); + CircleSprite.FadeOut(legacy_fade_duration); CircleSprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); - OverlaySprite.FadeOut(legacy_fade_duration, Easing.Out); + OverlaySprite.FadeOut(legacy_fade_duration); OverlaySprite.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); if (hasNumber) @@ -146,11 +146,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (legacyVersion >= 2.0m) // legacy skins of version 2.0 and newer only apply very short fade out to the number piece. - hitCircleText.FadeOut(legacy_fade_duration / 4, Easing.Out); + hitCircleText.FadeOut(legacy_fade_duration / 4); else { // old skins scale and fade it normally along other pieces. - hitCircleText.FadeOut(legacy_fade_duration, Easing.Out); + hitCircleText.FadeOut(legacy_fade_duration); hitCircleText.ScaleTo(1.4f, legacy_fade_duration, Easing.Out); } } From d46bc7f72af15ec64567ddb7873d814006304198 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 Oct 2022 23:43:31 +0300 Subject: [PATCH 1753/2686] Adjust fade out time to match stable --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index d58a435728..6711c74c9e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -331,7 +331,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { base.UpdateHitStateTransforms(state); - const float fade_out_time = 450; + const float fade_out_time = 240; switch (state) { From 03edfce8223dc57cad38e184e82ce3b992c10478 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 Oct 2022 23:43:42 +0300 Subject: [PATCH 1754/2686] Remove fade easing from sliders --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 6711c74c9e..e37f1133aa 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -341,7 +341,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables break; } - this.FadeOut(fade_out_time, Easing.OutQuint).Expire(); + this.FadeOut(fade_out_time).Expire(); } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => SliderBody?.ReceivePositionalInputAt(screenSpacePos) ?? base.ReceivePositionalInputAt(screenSpacePos); From 3b3f3dc1598f0e1444bb6e89a99065aa269e4ddb Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 Oct 2022 23:48:40 +0300 Subject: [PATCH 1755/2686] Fix new-style spinners fading in later than usual --- .../Skinning/Legacy/LegacyNewStyleSpinner.cs | 4 ++-- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs index 22944becf3..71c3e4c9f0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs @@ -107,8 +107,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt)) this.FadeOut(); - using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimeFadeIn / 2)) - this.FadeInFromZero(spinner.TimeFadeIn / 2); + using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimeFadeIn)) + this.FadeInFromZero(spinner.TimeFadeIn); using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt)) { diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs index 004222ad7a..a817e5f2b7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs @@ -65,6 +65,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { spin = new Sprite { + Alpha = 0, Anchor = Anchor.TopCentre, Origin = Anchor.Centre, Texture = source.GetTexture("spinner-spin"), @@ -82,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy }, bonusCounter = new LegacySpriteText(LegacyFont.Score) { - Alpha = 0f, + Alpha = 0, Anchor = Anchor.TopCentre, Origin = Anchor.Centre, Scale = new Vector2(SPRITE_SCALE), @@ -179,6 +180,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy spmCounter.MoveToOffset(new Vector2(0, -spm_hide_offset), d.HitObject.TimeFadeIn, Easing.Out); } + using (BeginAbsoluteSequence(d.HitObject.StartTime - d.HitObject.TimeFadeIn / 2)) + spin.FadeInFromZero(d.HitObject.TimeFadeIn / 2); + using (BeginAbsoluteSequence(d.HitObject.StartTime)) ApproachCircle?.ScaleTo(SPRITE_SCALE * 0.1f, d.HitObject.Duration); From 13e23237914dc6f2d4d5681ecc7920301aa0691c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 18 Oct 2022 23:48:51 +0300 Subject: [PATCH 1756/2686] Adjust fade out duration to match stable --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 53f4d21975..6ae9d5bc34 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables /// public readonly IBindable SpinsPerMinute = new BindableDouble(); - private const double fade_out_duration = 160; + private const double fade_out_duration = 240; public DrawableSpinner() : this(null) From a76a0397226b844e923b40e3965a4e745bc0c321 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Tue, 18 Oct 2022 23:40:43 +0200 Subject: [PATCH 1757/2686] Rename KiaiFlashingDrawable and move to osu.Game --- .../Skinning/LegacyKiaiFlashingDrawable.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename osu.Game.Rulesets.Osu/Skinning/Legacy/KiaiFlashingDrawable.cs => osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs (88%) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/KiaiFlashingDrawable.cs b/osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs similarity index 88% rename from osu.Game.Rulesets.Osu/Skinning/Legacy/KiaiFlashingDrawable.cs rename to osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs index 152ed5c3d9..c64f322df9 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/KiaiFlashingDrawable.cs +++ b/osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs @@ -7,15 +7,15 @@ using osu.Framework.Graphics; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; -namespace osu.Game.Rulesets.Osu.Skinning.Legacy +namespace osu.Game.Skinning { - internal class KiaiFlashingDrawable : BeatSyncedContainer + public class LegacyKiaiFlashingDrawable : BeatSyncedContainer { private readonly Drawable flashingDrawable; private const float flash_opacity = 0.3f; - public KiaiFlashingDrawable(Func creationFunc) + public LegacyKiaiFlashingDrawable(Func creationFunc) { AutoSizeAxes = Axes.Both; From 2b5f12e4fb67ede5e419596ad3d8bc14642bdb2b Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Tue, 18 Oct 2022 23:47:26 +0200 Subject: [PATCH 1758/2686] Mark existing Drawable test scenes as NUnit for reuse in kiai test scenes --- .../Skinning/TestSceneDrawableDrumRoll.cs | 4 ++-- .../Skinning/TestSceneDrawableHit.cs | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs index 2d27e0e40e..e42dc254ac 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs @@ -25,8 +25,8 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning TimeRange = { Value = 5000 }, }; - [BackgroundDependencyLoader] - private void load() + [Test] + public void DrumrollTest() { AddStep("Drum roll", () => SetContents(_ => { diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs index d5a97f8f88..8e9c487c2f 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs @@ -4,7 +4,6 @@ #nullable disable using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; @@ -16,8 +15,8 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [TestFixture] public class TestSceneDrawableHit : TaikoSkinnableTestScene { - [BackgroundDependencyLoader] - private void load() + [Test] + public void TestHits() { AddStep("Centre hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime()) { From bc57ef061ee32f9a507277ba2128cfab3b4eb25c Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Tue, 18 Oct 2022 23:48:50 +0200 Subject: [PATCH 1759/2686] Add tests for DrawableHit and DrawableDrumRoll kiai flashing --- .../Skinning/TestSceneDrawableDrumRollKiai.cs | 30 +++++++++++++++++++ .../Skinning/TestSceneDrawableHitKiai.cs | 30 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRollKiai.cs create mode 100644 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHitKiai.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRollKiai.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRollKiai.cs new file mode 100644 index 0000000000..53977150e7 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRollKiai.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps; + +namespace osu.Game.Rulesets.Taiko.Tests.Skinning +{ + [TestFixture] + public class TestSceneDrawableDrumRollKiai : TestSceneDrawableDrumRoll + { + [SetUp] + public void SetUp() => Schedule(() => + { + var controlPointInfo = new ControlPointInfo(); + + controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); + controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); + + Beatmap.Value = CreateWorkingBeatmap(new Beatmap + { + ControlPointInfo = controlPointInfo + }); + + // track needs to be playing for BeatSyncedContainer to work. + Beatmap.Value.Track.Start(); + }); + } +} diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHitKiai.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHitKiai.cs new file mode 100644 index 0000000000..fac0530749 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHitKiai.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; + +namespace osu.Game.Rulesets.Taiko.Tests.Skinning +{ + [TestFixture] + public class TestSceneDrawableHitKiai : TestSceneDrawableHit + { + [SetUp] + public void SetUp() => Schedule(() => + { + var controlPointInfo = new ControlPointInfo(); + + controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); + controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); + + Beatmap.Value = CreateWorkingBeatmap(new Beatmap + { + ControlPointInfo = controlPointInfo + }); + + // track needs to be playing for BeatSyncedContainer to work. + Beatmap.Value.Track.Start(); + }); + } +} From 59213fc00bd2cf10710e26d674c038c1c99def50 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Tue, 18 Oct 2022 23:53:12 +0200 Subject: [PATCH 1760/2686] Update LegacyMainCirclePiece to use renamed version of KiaiFlashingDrawable --- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 1b2ab82044..211411591c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy InternalChildren = new[] { - CircleSprite = new KiaiFlashingDrawable(() => new Sprite { Texture = skin.GetTexture(circleName) }) + CircleSprite = new LegacyKiaiFlashingDrawable(() => new Sprite { Texture = skin.GetTexture(circleName) }) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Child = OverlaySprite = new KiaiFlashingDrawable(() => skin.GetAnimation(@$"{circleName}overlay", true, true, frameLength: 1000 / 2d)) + Child = OverlaySprite = new LegacyKiaiFlashingDrawable(() => skin.GetAnimation(@$"{circleName}overlay", true, true, frameLength: 1000 / 2d)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, From a21acdb5bc70cbf185f2e2e2447da669c0b2e703 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Tue, 18 Oct 2022 23:55:02 +0200 Subject: [PATCH 1761/2686] Implement kiai flashing for legacy taiko skins --- osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs index 399bd9260d..6bbeb0ed4c 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } // backgroundLayer is guaranteed to exist due to the pre-check in TaikoLegacySkinTransformer. - AddInternal(backgroundLayer = getDrawableFor("circle")); + AddInternal(backgroundLayer = new LegacyKiaiFlashingDrawable(() => getDrawableFor("circle"))); var foregroundLayer = getDrawableFor("circleoverlay"); if (foregroundLayer != null) From 003e4247f9064e86f2c6bc1aa2eb7baeda7f49ee Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Tue, 18 Oct 2022 23:55:40 +0200 Subject: [PATCH 1762/2686] Implement kiai flashing for "triangles" taiko skin --- .../Skinning/Default/CirclePiece.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index a7ab1bcd4a..d0eaf9a602 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Framework.Audio.Track; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -32,6 +33,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default private const double pre_beat_transition_time = 80; + private const float flash_opacity = 0.3f; + private Color4 accentColour; /// @@ -157,6 +160,13 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default if (!effectPoint.KiaiMode) return; + FlashBox + // Make sure the hit indicator usage of FlashBox doesn't get faded out prematurely by a kiai flash + .DelayUntilTransformsFinished() + .FadeTo(flash_opacity, 0, Easing.OutQuint) + .Then() + .FadeOut(Math.Max(80, timingPoint.BeatLength - 80), Easing.OutSine); + if (beatIndex % timingPoint.TimeSignature.Numerator != 0) return; From 9b123e7365a777b11e3de8990b21ad5cfb80820b Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Wed, 19 Oct 2022 00:51:44 +0200 Subject: [PATCH 1763/2686] Adjust flash intensity and fade values to feel better --- osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs | 2 +- osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index d0eaf9a602..70eacbe61d 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs @@ -163,7 +163,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default FlashBox // Make sure the hit indicator usage of FlashBox doesn't get faded out prematurely by a kiai flash .DelayUntilTransformsFinished() - .FadeTo(flash_opacity, 0, Easing.OutQuint) + .FadeTo(flash_opacity) .Then() .FadeOut(Math.Max(80, timingPoint.BeatLength - 80), Easing.OutSine); diff --git a/osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs b/osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs index c64f322df9..2bcdd5b5a1 100644 --- a/osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs +++ b/osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs @@ -13,7 +13,7 @@ namespace osu.Game.Skinning { private readonly Drawable flashingDrawable; - private const float flash_opacity = 0.3f; + private const float flash_opacity = 0.55f; public LegacyKiaiFlashingDrawable(Func creationFunc) { @@ -44,7 +44,7 @@ namespace osu.Game.Skinning flashingDrawable .FadeTo(flash_opacity) .Then() - .FadeOut(timingPoint.BeatLength * 0.75f); + .FadeOut(Math.Max(80, timingPoint.BeatLength - 80), Easing.OutSine); } } } From 343c560b1b92e7e8fb603915816f0f8aad2116de Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 18 Oct 2022 03:33:03 -0700 Subject: [PATCH 1764/2686] Remove smoke point maximum/cap --- .../Skinning/SmokeSegment.cs | 144 +++++++++--------- 1 file changed, 75 insertions(+), 69 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index aba4d0ff63..6aee9ca2df 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -22,8 +23,6 @@ namespace osu.Game.Rulesets.Osu.Skinning { public abstract class SmokeSegment : Drawable, ITexturedShaderDrawable { - private const int max_point_count = 18_000; - // fade anim values private const double initial_fade_out_duration = 4000; @@ -85,12 +84,6 @@ namespace osu.Game.Rulesets.Osu.Skinning totalDistance = pointInterval; } - private Vector2 nextPointDirection() - { - float angle = RNG.NextSingle(0, 2 * MathF.PI); - return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); - } - public void AddPosition(Vector2 position, double time) { lastPosition ??= position; @@ -107,33 +100,27 @@ namespace osu.Game.Rulesets.Osu.Skinning Vector2 pointPos = (pointInterval - (totalDistance - delta)) * increment + (Vector2)lastPosition; increment *= pointInterval; - if (SmokePoints.Count > 0 && SmokePoints[^1].Time > time) - { - int index = ~SmokePoints.BinarySearch(new SmokePoint { Time = time }, new SmokePoint.UpperBoundComparer()); - SmokePoints.RemoveRange(index, SmokePoints.Count - index); - } - totalDistance %= pointInterval; - for (int i = 0; i < count; i++) + if (SmokePoints.Count == 0 || SmokePoints[^1].Time <= time) { - SmokePoints.Add(new SmokePoint + for (int i = 0; i < count; i++) { - Position = pointPos, - Time = time, - Direction = nextPointDirection(), - }); + SmokePoints.Add(new SmokePoint + { + Position = pointPos, + Time = time, + Angle = RNG.NextSingle(0, 2 * MathF.PI), + }); - pointPos += increment; + pointPos += increment; + } } Invalidate(Invalidation.DrawNode); } lastPosition = position; - - if (SmokePoints.Count >= max_point_count) - FinishDrawing(time); } public void FinishDrawing(double time) @@ -157,7 +144,7 @@ namespace osu.Game.Rulesets.Osu.Skinning { public Vector2 Position; public double Time; - public Vector2 Direction; + public float Angle; public struct UpperBoundComparer : IComparer { @@ -171,6 +158,17 @@ namespace osu.Game.Rulesets.Osu.Skinning return x.Time > target.Time ? 1 : -1; } } + + public struct LowerBoundComparer : IComparer + { + public int Compare(SmokePoint x, SmokePoint target) + { + // Similar logic as UpperBoundComparer, except returned index will always be + // the first element larger or equal + + return x.Time < target.Time ? -1 : 1; + } + } } protected class SmokeDrawNode : TexturedShaderDrawNode @@ -187,11 +185,11 @@ namespace osu.Game.Rulesets.Osu.Skinning private Vector2 drawSize; private Texture? texture; private int rotationSeed; - private int rotationIndex; + private int firstVisibleIndex; // anim calculation vars (color, scale, direction) private double initialFadeOutDurationTrunc; - private double firstVisiblePointTime; + private double firstVisiblePointTimeAfterSmokeEnded; private double initialFadeOutTime; private double reFadeInTime; @@ -206,9 +204,6 @@ namespace osu.Game.Rulesets.Osu.Skinning { base.ApplyState(); - points.Clear(); - points.AddRange(Source.SmokePoints); - radius = Source.radius; drawSize = Source.DrawSize; texture = Source.Texture; @@ -220,11 +215,18 @@ namespace osu.Game.Rulesets.Osu.Skinning rotationSeed = Source.rotationSeed; initialFadeOutDurationTrunc = Math.Min(initial_fade_out_duration, SmokeEndTime - SmokeStartTime); - firstVisiblePointTime = SmokeEndTime - initialFadeOutDurationTrunc; + firstVisiblePointTimeAfterSmokeEnded = SmokeEndTime - initialFadeOutDurationTrunc; - initialFadeOutTime = CurrentTime; - reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / re_fade_in_speed); - finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTime * (1 - 1 / final_fade_out_speed); + initialFadeOutTime = Math.Min(CurrentTime, SmokeEndTime); + reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTimeAfterSmokeEnded * (1 - 1 / re_fade_in_speed); + finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTimeAfterSmokeEnded * (1 - 1 / final_fade_out_speed); + + double firstVisibleTime = Math.Min(SmokeEndTime, CurrentTime) - initialFadeOutDurationTrunc; + firstVisibleIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = firstVisibleTime }, new SmokePoint.LowerBoundComparer()); + int futureIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = CurrentTime }, new SmokePoint.UpperBoundComparer()); + + points.Clear(); + points.AddRange(Source.SmokePoints.Skip(firstVisibleIndex).Take(futureIndex - firstVisibleIndex)); } public sealed override void Draw(IRenderer renderer) @@ -234,9 +236,12 @@ namespace osu.Game.Rulesets.Osu.Skinning if (points.Count == 0) return; - rotationIndex = 0; - - quadBatch ??= renderer.CreateQuadBatch(max_point_count / 10, 10); + quadBatch ??= renderer.CreateQuadBatch(200, 4); + if (points.Count > quadBatch.Size * 4 && quadBatch.Size != 10922) + { + int batchSize = Math.Min((int)(quadBatch.Size * 1.5f), 10922); + quadBatch = renderer.CreateQuadBatch(batchSize, 4); + } texture ??= renderer.WhitePixel; RectangleF textureRect = texture.GetTextureRect(); @@ -248,8 +253,8 @@ namespace osu.Game.Rulesets.Osu.Skinning shader.Bind(); texture.Bind(); - foreach (var point in points) - drawPointQuad(point, textureRect); + for (int i = 0; i < points.Count; i++) + drawPointQuad(points[i], textureRect, i + firstVisibleIndex); shader.Unbind(); renderer.PopLocalMatrix(); @@ -263,30 +268,31 @@ namespace osu.Game.Rulesets.Osu.Skinning { var color = Color4.White; - double timeDoingInitialFadeOut = Math.Min(initialFadeOutTime, SmokeEndTime) - point.Time; - - if (timeDoingInitialFadeOut > 0) + double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; + if (timeDoingFinalFadeOut > 0 && point.Time > firstVisiblePointTimeAfterSmokeEnded) { - float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); - color.A = (1 - fraction) * initial_alpha; + float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); + fraction = MathF.Pow(fraction, 5); + color.A = (1 - fraction) * re_fade_in_alpha; } - - if (color.A > 0) + else { - double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed; - double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; - - if (timeDoingFinalFadeOut > 0) + double timeDoingInitialFadeOut = initialFadeOutTime - point.Time; + if (timeDoingInitialFadeOut > 0) { - float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); - fraction = MathF.Pow(fraction, 5); - color.A = (1 - fraction) * re_fade_in_alpha; + float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); + color.A = (1 - fraction) * initial_alpha; } - else if (timeDoingReFadeIn > 0) + + if (point.Time > firstVisiblePointTimeAfterSmokeEnded) { - float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1); - fraction = 1 - MathF.Pow(1 - fraction, 5); - color.A = fraction * (re_fade_in_alpha - color.A) + color.A; + double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed; + if (timeDoingReFadeIn > 0) + { + float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1); + fraction = 1 - MathF.Pow(1 - fraction, 5); + color.A = fraction * (re_fade_in_alpha - color.A) + color.A; + } } } @@ -301,33 +307,33 @@ namespace osu.Game.Rulesets.Osu.Skinning return fraction * (final_scale - initial_scale) + initial_scale; } - protected virtual Vector2 PointDirection(SmokePoint point) + protected virtual Vector2 PointDirection(SmokePoint point, int index) { - float initialAngle = MathF.Atan2(point.Direction.Y, point.Direction.X); - float finalAngle = initialAngle + nextRotation(); - double timeDoingRotation = CurrentTime - point.Time; float fraction = Math.Clamp((float)(timeDoingRotation / rotation_duration), 0, 1); fraction = 1 - MathF.Pow(1 - fraction, 5); - float angle = fraction * (finalAngle - initialAngle) + initialAngle; + float angle = fraction * getRotation(index) + point.Angle; return new Vector2(MathF.Sin(angle), -MathF.Cos(angle)); } - private float nextRotation() => max_rotation * (StatelessRNG.NextSingle(rotationSeed, rotationIndex++) * 2 - 1); + private float getRotation(int index) => max_rotation * (StatelessRNG.NextSingle(rotationSeed, index) * 2 - 1); - private void drawPointQuad(SmokePoint point, RectangleF textureRect) + private void drawPointQuad(SmokePoint point, RectangleF textureRect, int index) { Debug.Assert(quadBatch != null); var colour = PointColour(point); - float scale = PointScale(point); - var dir = PointDirection(point); - var ortho = dir.PerpendicularLeft; - - if (colour.A == 0 || scale == 0) + if (colour.A == 0) return; + float scale = PointScale(point); + if (scale == 0) + return; + + var dir = PointDirection(point, index); + var ortho = dir.PerpendicularLeft; + var localTopLeft = point.Position + (radius * scale * (-ortho - dir)); var localTopRight = point.Position + (radius * scale * (-ortho + dir)); var localBotLeft = point.Position + (radius * scale * (ortho - dir)); From a9b8ba94fa923eb54ca4304504f1e2e6cf416f04 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 18 Oct 2022 22:59:58 -0700 Subject: [PATCH 1765/2686] Add necessary newlines --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 6aee9ca2df..5e72f165df 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -237,11 +237,13 @@ namespace osu.Game.Rulesets.Osu.Skinning return; quadBatch ??= renderer.CreateQuadBatch(200, 4); + if (points.Count > quadBatch.Size * 4 && quadBatch.Size != 10922) { int batchSize = Math.Min((int)(quadBatch.Size * 1.5f), 10922); quadBatch = renderer.CreateQuadBatch(batchSize, 4); } + texture ??= renderer.WhitePixel; RectangleF textureRect = texture.GetTextureRect(); @@ -269,6 +271,7 @@ namespace osu.Game.Rulesets.Osu.Skinning var color = Color4.White; double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; + if (timeDoingFinalFadeOut > 0 && point.Time > firstVisiblePointTimeAfterSmokeEnded) { float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); @@ -278,6 +281,7 @@ namespace osu.Game.Rulesets.Osu.Skinning else { double timeDoingInitialFadeOut = initialFadeOutTime - point.Time; + if (timeDoingInitialFadeOut > 0) { float fraction = Math.Clamp((float)(timeDoingInitialFadeOut / initial_fade_out_duration), 0, 1); @@ -287,6 +291,7 @@ namespace osu.Game.Rulesets.Osu.Skinning if (point.Time > firstVisiblePointTimeAfterSmokeEnded) { double timeDoingReFadeIn = reFadeInTime - point.Time / re_fade_in_speed; + if (timeDoingReFadeIn > 0) { float fraction = Math.Clamp((float)(timeDoingReFadeIn / re_fade_in_duration), 0, 1); From 50ab9bff8b8609b1b3438c314d2b957c23578e9d Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 18 Oct 2022 23:05:09 -0700 Subject: [PATCH 1766/2686] Rename for consistency --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 5e72f165df..23bfea5240 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -185,7 +185,7 @@ namespace osu.Game.Rulesets.Osu.Skinning private Vector2 drawSize; private Texture? texture; private int rotationSeed; - private int firstVisibleIndex; + private int firstVisiblePointIndex; // anim calculation vars (color, scale, direction) private double initialFadeOutDurationTrunc; @@ -221,12 +221,12 @@ namespace osu.Game.Rulesets.Osu.Skinning reFadeInTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTimeAfterSmokeEnded * (1 - 1 / re_fade_in_speed); finalFadeOutTime = CurrentTime - initialFadeOutDurationTrunc - firstVisiblePointTimeAfterSmokeEnded * (1 - 1 / final_fade_out_speed); - double firstVisibleTime = Math.Min(SmokeEndTime, CurrentTime) - initialFadeOutDurationTrunc; - firstVisibleIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = firstVisibleTime }, new SmokePoint.LowerBoundComparer()); - int futureIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = CurrentTime }, new SmokePoint.UpperBoundComparer()); + double firstVisiblePointTime = Math.Min(SmokeEndTime, CurrentTime) - initialFadeOutDurationTrunc; + firstVisiblePointIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = firstVisiblePointTime }, new SmokePoint.LowerBoundComparer()); + int futurePointIndex = ~Source.SmokePoints.BinarySearch(new SmokePoint { Time = CurrentTime }, new SmokePoint.UpperBoundComparer()); points.Clear(); - points.AddRange(Source.SmokePoints.Skip(firstVisibleIndex).Take(futureIndex - firstVisibleIndex)); + points.AddRange(Source.SmokePoints.Skip(firstVisiblePointIndex).Take(futurePointIndex - firstVisiblePointIndex)); } public sealed override void Draw(IRenderer renderer) @@ -256,7 +256,7 @@ namespace osu.Game.Rulesets.Osu.Skinning texture.Bind(); for (int i = 0; i < points.Count; i++) - drawPointQuad(points[i], textureRect, i + firstVisibleIndex); + drawPointQuad(points[i], textureRect, i + firstVisiblePointIndex); shader.Unbind(); renderer.PopLocalMatrix(); @@ -272,7 +272,7 @@ namespace osu.Game.Rulesets.Osu.Skinning double timeDoingFinalFadeOut = finalFadeOutTime - point.Time / final_fade_out_speed; - if (timeDoingFinalFadeOut > 0 && point.Time > firstVisiblePointTimeAfterSmokeEnded) + if (timeDoingFinalFadeOut > 0 && point.Time >= firstVisiblePointTimeAfterSmokeEnded) { float fraction = Math.Clamp((float)(timeDoingFinalFadeOut / final_fade_out_duration), 0, 1); fraction = MathF.Pow(fraction, 5); From 9356a40a394f7afcfa95a1325c3b537c7d8a0f0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Oct 2022 15:13:20 +0900 Subject: [PATCH 1767/2686] Remove redundant flash layer colour logic In a previous iteration, the flash layer was white on the initial hit, but this seems to have been removed for the final implementation. --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index ffdcba3cdb..ca0d99f2f6 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -173,11 +173,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon .FadeOut(flash_in_duration); } - // The flash layer starts white to give the wanted brightness, but is almost immediately - // recoloured to the accent colour. This would more correctly be done with two layers (one for the initial flash) - // but works well enough with the colour fade. flash.FadeTo(1, flash_in_duration, Easing.OutQuint); - flash.FlashColour(accentColour.Value, fade_out_time, Easing.OutQuint); this.FadeOut(fade_out_time, Easing.OutQuad); break; From aca0d04834b667bb2893ccb9fbf2f2827fc93254 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Oct 2022 15:52:25 +0900 Subject: [PATCH 1768/2686] Forcefully remove transforms before reapplying to avoid old accent colour getting rewound --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index ca0d99f2f6..f5df06f023 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -108,18 +108,23 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { base.LoadComplete(); - accentColour.BindValueChanged(colour => - { - outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); - outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); - innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); - flash.Colour = colour.NewValue; - }, true); - indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); + accentColour.BindValueChanged(colour => + { + // A colour transform is applied. + // Without removing transforms first, when it is rewound it may apply an old colour. + outerGradient.ClearTransforms(); + outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); + + outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); + innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); + flash.Colour = colour.NewValue; + + updateStateTransforms(drawableObject, drawableObject.State.Value); + }, true); + drawableObject.ApplyCustomUpdateState += updateStateTransforms; - updateStateTransforms(drawableObject, drawableObject.State.Value); } private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) From 59e2478b0ec8e3a4a0ebaf615489224c88b38fd3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Oct 2022 16:01:07 +0900 Subject: [PATCH 1769/2686] Fix some older beatmaps having missing backgrounds Closes https://github.com/ppy/osu/issues/20824. Note that this will require a reimport of beatmaps as it is baked into the database. Probably not worth making a migration for at this point in time. --- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 75500fbc4e..5f5749dc73 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -355,6 +355,14 @@ namespace osu.Game.Beatmaps.Formats switch (type) { + case LegacyEventType.Sprite: + // Generally, the background is the first thing defined in a beatmap file. + // In some older beatmaps, it is not present and replaced by a storyboard-level background instead. + // Allow the first sprite (by file order) to act as the background in such cases. + if (string.IsNullOrEmpty(beatmap.BeatmapInfo.Metadata.BackgroundFile)) + beatmap.BeatmapInfo.Metadata.BackgroundFile = CleanFilename(split[3]); + break; + case LegacyEventType.Background: beatmap.BeatmapInfo.Metadata.BackgroundFile = CleanFilename(split[2]); break; From 830b92d3aebb8a89298504d649baedd27f5e28e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Oct 2022 20:06:39 +0900 Subject: [PATCH 1770/2686] Add momentary shortcuts to toggle grid/distance snap Matching osu!stable. I use these quite a lot while mapping and I'm sure others do as well. Hold `Shift` = invert grid snap Hold `Alt` = invert distance snap --- .../Edit/CatchHitObjectComposer.cs | 31 ++++++++++++++++ .../Edit/OsuHitObjectComposer.cs | 37 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 54d50b01c4..d40200f2dd 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -26,6 +26,7 @@ using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Components.TernaryButtons; using osu.Game.Screens.Edit.Compose.Components; using osuTK; +using osuTK.Input; namespace osu.Game.Rulesets.Catch.Edit { @@ -88,6 +89,36 @@ namespace osu.Game.Rulesets.Catch.Edit updateDistanceSnapGrid(); } + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.Repeat) + return false; + + if (handleToggleViaKey(e.Key)) + return true; + + return base.OnKeyDown(e); + } + + protected override void OnKeyUp(KeyUpEvent e) + { + handleToggleViaKey(e.Key); + base.OnKeyUp(e); + } + + private bool handleToggleViaKey(Key key) + { + switch (key) + { + case Key.AltLeft: + case Key.AltRight: + distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; + return true; + } + + return false; + } + public override bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 6b4a6e39d9..b9177e9cdd 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -13,6 +13,7 @@ using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; @@ -24,6 +25,7 @@ using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Components.TernaryButtons; using osu.Game.Screens.Edit.Compose.Components; using osuTK; +using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit { @@ -229,6 +231,41 @@ namespace osu.Game.Rulesets.Osu.Edit } } + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.Repeat) + return false; + + if (handleToggleViaKey(e.Key)) + return true; + + return base.OnKeyDown(e); + } + + protected override void OnKeyUp(KeyUpEvent e) + { + handleToggleViaKey(e.Key); + base.OnKeyUp(e); + } + + private bool handleToggleViaKey(Key key) + { + switch (key) + { + case Key.ShiftLeft: + case Key.ShiftRight: + rectangularGridSnapToggle.Value = rectangularGridSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; + return true; + + case Key.AltLeft: + case Key.AltRight: + distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; + return true; + } + + return false; + } + private DistanceSnapGrid createDistanceSnapGrid(IEnumerable selectedHitObjects) { if (BlueprintContainer.CurrentTool is SpinnerCompositionTool) From bea136ce50fb586619794a3b33f0ccf8337e8942 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Oct 2022 23:56:42 +0900 Subject: [PATCH 1771/2686] Adjust test assert ordering to read better --- osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs index 58b5b41702..1c87eb49c9 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs @@ -161,10 +161,11 @@ namespace osu.Game.Tests.Visual.Editing AddStep("hold alt", () => InputManager.PressKey(Key.LAlt)); AddStep("scroll mouse 5 steps", () => InputManager.ScrollVerticalBy(5)); - AddAssert("distance spacing increased by 0.5", () => editorBeatmap.BeatmapInfo.DistanceSpacing == originalSpacing + 0.5); AddStep("release alt", () => InputManager.ReleaseKey(Key.LAlt)); AddStep("release ctrl", () => InputManager.ReleaseKey(Key.LControl)); + + AddAssert("distance spacing increased by 0.5", () => editorBeatmap.BeatmapInfo.DistanceSpacing == originalSpacing + 0.5); } public class EditorBeatmapContainer : Container From 966dd786ae4460b39ada7d9bf95512114539f261 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 19 Oct 2022 23:59:34 +0900 Subject: [PATCH 1772/2686] Don't consume keys when handling momentary snap toggles --- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index b9177e9cdd..e46131dd6e 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -236,8 +236,7 @@ namespace osu.Game.Rulesets.Osu.Edit if (e.Repeat) return false; - if (handleToggleViaKey(e.Key)) - return true; + handleToggleViaKey(e.Key); return base.OnKeyDown(e); } @@ -248,22 +247,20 @@ namespace osu.Game.Rulesets.Osu.Edit base.OnKeyUp(e); } - private bool handleToggleViaKey(Key key) + private void handleToggleViaKey(Key key) { switch (key) { case Key.ShiftLeft: case Key.ShiftRight: rectangularGridSnapToggle.Value = rectangularGridSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; - return true; + break; case Key.AltLeft: case Key.AltRight: distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; - return true; + break; } - - return false; } private DistanceSnapGrid createDistanceSnapGrid(IEnumerable selectedHitObjects) From d83c398b58bdb2d11859dadb96f1c66f6820a890 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Wed, 19 Oct 2022 23:31:23 +0200 Subject: [PATCH 1773/2686] Apply review: changed DelayUntilTransformsFinished to ArmedState check --- .../Skinning/Default/CirclePiece.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index 70eacbe61d..36daefbd36 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -14,6 +15,7 @@ using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Containers; +using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects; using osuTK.Graphics; @@ -155,17 +157,21 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default }; } + [Resolved] + private DrawableHitObject drawableHitObject { get; set; } + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { if (!effectPoint.KiaiMode) return; - FlashBox - // Make sure the hit indicator usage of FlashBox doesn't get faded out prematurely by a kiai flash - .DelayUntilTransformsFinished() - .FadeTo(flash_opacity) - .Then() - .FadeOut(Math.Max(80, timingPoint.BeatLength - 80), Easing.OutSine); + if (drawableHitObject.State.Value == ArmedState.Idle) + { + FlashBox + .FadeTo(flash_opacity) + .Then() + .FadeOut(Math.Max(80, timingPoint.BeatLength - 80), Easing.OutSine); + } if (beatIndex % timingPoint.TimeSignature.Numerator != 0) return; From 1852714d2d32a329313b6525eec35381f4dbe6ec Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 Oct 2022 01:16:27 +0300 Subject: [PATCH 1774/2686] Fix existing alpha transform cleared on accent colour change Clearing it causes its start value to be lost. --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index f5df06f023..4b5adaa033 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -114,9 +114,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { // A colour transform is applied. // Without removing transforms first, when it is rewound it may apply an old colour. - outerGradient.ClearTransforms(); + outerGradient.ClearTransforms(targetMember: nameof(Colour)); outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); - outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); flash.Colour = colour.NewValue; From ba37daa456b5239af39abbf428e638058669c706 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 Oct 2022 01:18:07 +0300 Subject: [PATCH 1775/2686] Bring back removed newline --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 4b5adaa033..36dc8c801d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -116,6 +116,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon // Without removing transforms first, when it is rewound it may apply an old colour. outerGradient.ClearTransforms(targetMember: nameof(Colour)); outerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue, colour.NewValue.Darken(0.1f)); + outerFill.Colour = innerFill.Colour = colour.NewValue.Darken(4); innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); flash.Colour = colour.NewValue; From 57320074a0f6140bdd17423e416af3db200361c8 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 01:24:36 +0300 Subject: [PATCH 1776/2686] Fix accidental breakage of changelog layout --- .../Overlays/Changelog/ChangelogContent.cs | 13 +++++- .../Changelog/ChangelogSingleBuild.cs | 46 ++++++++----------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogContent.cs b/osu.Game/Overlays/Changelog/ChangelogContent.cs index 1e49efb10e..dca2f3b1b0 100644 --- a/osu.Game/Overlays/Changelog/ChangelogContent.cs +++ b/osu.Game/Overlays/Changelog/ChangelogContent.cs @@ -7,20 +7,29 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using System; +using osu.Framework.Graphics.Cursor; namespace osu.Game.Overlays.Changelog { - public class ChangelogContent : FillFlowContainer + public class ChangelogContent : PopoverContainer { public Action BuildSelected; public void SelectBuild(APIChangelogBuild build) => BuildSelected?.Invoke(build); + protected override Container Content { get; } + public ChangelogContent() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Direction = FillDirection.Vertical; + Content = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical + }; + base.Content.Add(Content); } } } diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index afdfd0ff68..e4f240f0e7 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -10,7 +10,6 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; @@ -64,33 +63,28 @@ namespace osu.Game.Overlays.Changelog { CommentsContainer comments; - Child = new PopoverContainer + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] + new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, + new Box { - new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = 2, - Colour = colourProvider.Background6, - Margin = new MarginPadding { Top = 30 }, - }, - new ChangelogSupporterPromo - { - Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, - }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = 2, - Colour = colourProvider.Background6, - Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, - }, - comments = new CommentsContainer() - } + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colourProvider.Background6, + Margin = new MarginPadding { Top = 30 }, + }, + new ChangelogSupporterPromo + { + Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, + }, + new Box + { + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colourProvider.Background6, + Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, + }, + comments = new CommentsContainer() }; comments.ShowComments(CommentableType.Build, build.Id); From 78943a21d81fc6658a5be485f354b7f925b4636e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Oct 2022 08:06:05 +0900 Subject: [PATCH 1777/2686] Update osu.Game/Beatmaps/ControlPoints/IControlPoint.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Beatmaps/ControlPoints/IControlPoint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/ControlPoints/IControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/IControlPoint.cs index 6a287285d8..091e99e029 100644 --- a/osu.Game/Beatmaps/ControlPoints/IControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/IControlPoint.cs @@ -8,6 +8,6 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The time at which the control point takes effect. /// - public double Time { get; } + double Time { get; } } } From a7d4a74ed660366bce2dd1ddef5065363761f595 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Oct 2022 08:07:56 +0900 Subject: [PATCH 1778/2686] Update osu.Game/Tests/Visual/ScrollingTestContainer.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Tests/Visual/ScrollingTestContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs index 87f4bb3f3b..1817a704b9 100644 --- a/osu.Game/Tests/Visual/ScrollingTestContainer.cs +++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs @@ -100,7 +100,7 @@ namespace osu.Game.Tests.Visual => implementation.GetLength(startTime, endTime, timeRange, scrollLength); public float PositionAt(double time, double currentTime, double timeRange, float scrollLength, double? originTime = null) - => implementation.PositionAt(time, currentTime, timeRange, scrollLength); + => implementation.PositionAt(time, currentTime, timeRange, scrollLength, originTime); public double TimeAt(float position, double currentTime, double timeRange, float scrollLength) => implementation.TimeAt(position, currentTime, timeRange, scrollLength); From eb386d4bd54cc07957d33a3bd96052d4d68b104a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 Oct 2022 03:29:18 +0300 Subject: [PATCH 1779/2686] Enable slider ball tint in default legacy skin --- osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs | 1 - osu.Game/Skinning/DefaultLegacySkin.cs | 2 ++ osu.Game/Skinning/SkinConfiguration.cs | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs b/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs index 306a1e38b9..1c0a62454b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs @@ -9,7 +9,6 @@ namespace osu.Game.Rulesets.Osu.Skinning { SliderBorderSize, SliderPathRadius, - AllowSliderBallTint, CursorCentre, CursorExpand, CursorRotate, diff --git a/osu.Game/Skinning/DefaultLegacySkin.cs b/osu.Game/Skinning/DefaultLegacySkin.cs index 04f1286dc7..b80275a1e8 100644 --- a/osu.Game/Skinning/DefaultLegacySkin.cs +++ b/osu.Game/Skinning/DefaultLegacySkin.cs @@ -46,6 +46,8 @@ namespace osu.Game.Skinning new Color4(242, 24, 57, 255) }; + Configuration.ConfigDictionary[nameof(SkinConfiguration.LegacySetting.AllowSliderBallTint)] = @"true"; + Configuration.LegacyVersion = 2.7m; } } diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index 0b1159f8fd..4e5d96ccb8 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -38,7 +38,8 @@ namespace osu.Game.Skinning HitCirclePrefix, HitCircleOverlap, AnimationFramerate, - LayeredHitSounds + LayeredHitSounds, + AllowSliderBallTint, } public static List DefaultComboColours { get; } = new List From 4bf4938b726c584177b28361e6f198afc8878a3e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 Oct 2022 03:44:58 +0300 Subject: [PATCH 1780/2686] Keep cursor hiding feature to gameplay screens for now --- osu.Game/Graphics/Cursor/MenuCursorContainer.cs | 17 ++++++++++++++++- osu.Game/OsuGame.cs | 2 ++ osu.Game/Screens/IOsuScreen.cs | 5 +++++ osu.Game/Screens/OsuScreen.cs | 5 ++--- osu.Game/Screens/Play/Player.cs | 2 ++ 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index 33b0c308cc..a210cd3063 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -23,6 +23,21 @@ namespace osu.Game.Graphics.Cursor private readonly IBindable screenshotCursorVisibility = new Bindable(true); public override bool IsPresent => screenshotCursorVisibility.Value && base.IsPresent; + private bool hideCursorOnNonMouseInput; + + public bool HideCursorOnNonMouseInput + { + get => hideCursorOnNonMouseInput; + set + { + if (hideCursorOnNonMouseInput == value) + return; + + hideCursorOnNonMouseInput = value; + updateState(); + } + } + protected override Drawable CreateCursor() => activeCursor = new Cursor(); private Cursor activeCursor = null!; @@ -75,7 +90,7 @@ namespace osu.Game.Graphics.Cursor private void updateState() { - bool combinedVisibility = State.Value == Visibility.Visible && lastInputWasMouse.Value && !isIdle.Value; + bool combinedVisibility = State.Value == Visibility.Visible && (lastInputWasMouse.Value || !hideCursorOnNonMouseInput) && !isIdle.Value; if (visible == combinedVisibility) return; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b3eaf5cd01..2bdcb57f2a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1333,6 +1333,8 @@ namespace osu.Game OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode); API.Activity.BindTo(newOsuScreen.Activity); + GlobalCursorDisplay.MenuCursor.HideCursorOnNonMouseInput = newOsuScreen.HideMenuCursorOnNonMouseInput; + if (newOsuScreen.HideOverlaysOnEnter) CloseAllOverlays(); else diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs index 7d8657a3df..a5739a41b1 100644 --- a/osu.Game/Screens/IOsuScreen.cs +++ b/osu.Game/Screens/IOsuScreen.cs @@ -41,6 +41,11 @@ namespace osu.Game.Screens /// bool HideOverlaysOnEnter { get; } + /// + /// Whether the menu cursor should be hidden when non-mouse input is received. + /// + bool HideMenuCursorOnNonMouseInput { get; } + /// /// Whether overlays should be able to be opened when this screen is current. /// diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 0678a90f71..6be13bbda3 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -40,11 +40,10 @@ namespace osu.Game.Screens public virtual bool AllowExternalScreenChange => false; - /// - /// Whether all overlays should be hidden when this screen is entered or resumed. - /// public virtual bool HideOverlaysOnEnter => false; + public virtual bool HideMenuCursorOnNonMouseInput => false; + /// /// The initial overlay activation mode to use when this screen is entered for the first time. /// diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 68b623b781..7048f83c09 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -66,6 +66,8 @@ namespace osu.Game.Screens.Play public override bool HideOverlaysOnEnter => true; + public override bool HideMenuCursorOnNonMouseInput => true; + protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered; // We are managing our own adjustments (see OnEntering/OnExiting). From 39650717eaa89e838e60b4776bbfa4c08aae3163 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 Oct 2022 03:45:17 +0300 Subject: [PATCH 1781/2686] Improve input detection to not make cursor flicker on combined input --- osu.Game/Graphics/Cursor/MenuCursorContainer.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index a210cd3063..af542989ff 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -277,14 +277,19 @@ namespace osu.Game.Graphics.Cursor { switch (e) { - case MouseEvent: + case MouseDownEvent: + case MouseMoveEvent: lastInputWasMouseSource.Value = true; return false; - default: + case KeyDownEvent keyDown when !keyDown.Repeat: + case JoystickPressEvent: + case MidiDownEvent: lastInputWasMouseSource.Value = false; return false; } + + return false; } } From 7d31eaea549922d3bd8f993f4c3382a19498bee7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 Oct 2022 03:32:04 +0300 Subject: [PATCH 1782/2686] Move ball tinting logic to overwrite `SliderBall` colour --- .../Objects/Drawables/DrawableSlider.cs | 19 ------------------- .../Objects/Drawables/DrawableSliderBall.cs | 10 +--------- .../Skinning/Legacy/LegacySliderBall.cs | 11 +++++++++++ 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index e37f1133aa..785d15c15b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -14,12 +14,10 @@ using osu.Game.Audio; using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Rulesets.Osu.Skinning; using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables { @@ -106,7 +104,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { foreach (var drawableHitObject in NestedHitObjects) drawableHitObject.AccentColour.Value = colour.NewValue; - updateBallTint(); }, true); Tracking.BindValueChanged(updateSlidingSample); @@ -257,22 +254,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables SliderBody?.RecyclePath(); } - protected override void ApplySkin(ISkinSource skin, bool allowFallback) - { - base.ApplySkin(skin, allowFallback); - - updateBallTint(); - } - - private void updateBallTint() - { - if (CurrentSkin == null) - return; - - bool allowBallTint = CurrentSkin.GetConfig(OsuSkinConfiguration.AllowSliderBallTint)?.Value ?? false; - Ball.AccentColour = allowBallTint ? AccentColour.Value : Color4.White; - } - protected override void CheckForResult(bool userTriggered, double timeOffset) { if (userTriggered || Time.Current < HitObject.EndTime) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs index a2fe623897..de6ca7dd38 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs @@ -11,28 +11,20 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; using osu.Framework.Input.Events; -using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderBall : CircularContainer, ISliderProgress, IRequireHighFrequencyMousePosition, IHasAccentColour + public class DrawableSliderBall : CircularContainer, ISliderProgress, IRequireHighFrequencyMousePosition { public const float FOLLOW_AREA = 2.4f; public Func GetInitialHitAction; - public Color4 AccentColour - { - get => ball.Colour; - set => ball.Colour = value; - } - private Drawable followCircleReceptor; private DrawableSlider drawableSlider; private Drawable ball; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs index 414879f42d..60d71ae843 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -21,6 +22,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy [Resolved(canBeNull: true)] private DrawableHitObject? parentObject { get; set; } + public Color4 BallColour => animationContent.Colour; + private Sprite layerNd = null!; private Sprite layerSpec = null!; @@ -61,6 +64,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy }; } + private readonly IBindable accentColour = new Bindable(); + protected override void LoadComplete() { base.LoadComplete(); @@ -69,6 +74,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { parentObject.ApplyCustomUpdateState += updateStateTransforms; updateStateTransforms(parentObject, parentObject.State.Value); + + if (skin.GetConfig(SkinConfiguration.LegacySetting.AllowSliderBallTint)?.Value == true) + { + accentColour.BindTo(parentObject.AccentColour); + accentColour.BindValueChanged(a => animationContent.Colour = a.NewValue, true); + } } } From f444bb9ba6a74a0eeb956104ab22d00e2d29e769 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 Oct 2022 03:32:33 +0300 Subject: [PATCH 1783/2686] Update existing test case --- .../TestSceneSliderApplication.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs index 0169627867..728aa27da2 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs @@ -14,6 +14,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Skinning; using osu.Game.Tests.Visual; using osuTK; @@ -68,10 +69,8 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("create slider", () => { - var tintingSkin = skinManager.GetSkin(DefaultLegacySkin.CreateInfo()); - tintingSkin.Configuration.ConfigDictionary["AllowSliderBallTint"] = "1"; - - var provider = Ruleset.Value.CreateInstance().CreateSkinTransformer(tintingSkin, Beatmap.Value.Beatmap); + var skin = skinManager.GetSkin(DefaultLegacySkin.CreateInfo()); + var provider = Ruleset.Value.CreateInstance().CreateSkinTransformer(skin, Beatmap.Value.Beatmap); Child = new SkinProvidingContainer(provider) { @@ -92,10 +91,10 @@ namespace osu.Game.Rulesets.Osu.Tests }); AddStep("set accent white", () => dho.AccentColour.Value = Color4.White); - AddAssert("ball is white", () => dho.ChildrenOfType().Single().AccentColour == Color4.White); + AddAssert("ball is white", () => dho.ChildrenOfType().Single().BallColour == Color4.White); AddStep("set accent red", () => dho.AccentColour.Value = Color4.Red); - AddAssert("ball is red", () => dho.ChildrenOfType().Single().AccentColour == Color4.Red); + AddAssert("ball is red", () => dho.ChildrenOfType().Single().BallColour == Color4.Red); } private Slider prepareObject(Slider slider) From 212f15e2d29bfc7435803b5b662fd7a2598dea56 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 20 Oct 2022 04:06:33 +0300 Subject: [PATCH 1784/2686] Update existing test cases --- osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs index 6c0191ae27..75c47f0b1b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs @@ -178,6 +178,7 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestKeyboardLocalCursor([Values] bool clickToShow) { + AddStep("Enable cursor hiding", () => globalCursorDisplay.MenuCursor.HideCursorOnNonMouseInput = true); AddStep("Move to purple area", () => InputManager.MoveMouseTo(cursorBoxes[3].ScreenSpaceDrawQuad.Centre + new Vector2(10, 0))); AddAssert("Check purple cursor visible", () => checkVisible(cursorBoxes[3].Cursor)); AddAssert("Check global cursor alpha is 1", () => globalCursorDisplay.MenuCursor.Alpha == 1); @@ -201,6 +202,7 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestKeyboardUserCursor([Values] bool clickToShow) { + AddStep("Enable cursor hiding", () => globalCursorDisplay.MenuCursor.HideCursorOnNonMouseInput = true); AddStep("Move to green area", () => InputManager.MoveMouseTo(cursorBoxes[0])); AddAssert("Check green cursor visible", () => checkVisible(cursorBoxes[0].Cursor)); AddAssert("Check global cursor alpha is 0", () => !checkVisible(globalCursorDisplay.MenuCursor) && globalCursorDisplay.MenuCursor.ActiveCursor.Alpha == 0); From a754dc6d3b4d4fc2d02b58f7e68284f92710025a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Oct 2022 14:34:07 +0900 Subject: [PATCH 1785/2686] Expose binary search methods publicly Co-authored-by: Dan Balasescu --- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index cfe3c671ac..9186685f0c 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -196,7 +196,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the control point at. /// The control point to use when is before any control points. /// The active control point at , or a fallback if none found. - internal static T BinarySearchWithFallback(IReadOnlyList list, double time, T fallback) + public static T BinarySearchWithFallback(IReadOnlyList list, double time, T fallback) where T : class, IControlPoint { return BinarySearch(list, time) ?? fallback; @@ -208,7 +208,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The list to search. /// The time to find the control point at. /// The active control point at . - internal static T BinarySearch(IReadOnlyList list, double time) + public static T BinarySearch(IReadOnlyList list, double time) where T : class, IControlPoint { if (list == null) From 42bb9dc3e3db17b9cb39da3103ce10820a683db9 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Thu, 20 Oct 2022 22:17:26 +0900 Subject: [PATCH 1786/2686] revert EndPlacement change --- .../Edit/TaikoHitObjectComposer.cs | 12 ------------ osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs index 06c982397c..57c45fc074 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; @@ -19,16 +17,6 @@ namespace osu.Game.Rulesets.Taiko.Edit { } - public override void EndPlacement(HitObject hitObject, bool commit) - { - EditorBeatmap.PlacementObject.Value = null; - - if (commit) - { - EditorBeatmap.Add(hitObject); - } - } - protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] { new HitCompositionTool(), diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 0266317817..3bed835854 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -359,7 +359,7 @@ namespace osu.Game.Rulesets.Edit EditorBeatmap.PlacementObject.Value = hitObject; } - public virtual void EndPlacement(HitObject hitObject, bool commit) + public void EndPlacement(HitObject hitObject, bool commit) { EditorBeatmap.PlacementObject.Value = null; From 26860a903e684db7d3c06241d6889dbcd9186a5a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Oct 2022 22:30:30 +0900 Subject: [PATCH 1787/2686] Refactor implementation to support hitobjects nested multiple levels deep --- .../Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 443a37ab1c..424fc7c44c 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -236,8 +236,10 @@ namespace osu.Game.Rulesets.UI.Scrolling entry.LifetimeStart = Math.Min(entry.HitObject.StartTime - judgementOffset, computedStartTime); } - private void updateLayoutRecursive(DrawableHitObject hitObject) + private void updateLayoutRecursive(DrawableHitObject hitObject, double? parentHitObjectStartTime = null) { + parentHitObjectStartTime ??= hitObject.HitObject.StartTime; + if (hitObject.HitObject is IHasDuration e) { float length = LengthAtTime(hitObject.HitObject.StartTime, e.EndTime); @@ -249,10 +251,10 @@ namespace osu.Game.Rulesets.UI.Scrolling foreach (var obj in hitObject.NestedHitObjects) { - updateLayoutRecursive(obj); + updateLayoutRecursive(obj, parentHitObjectStartTime); // Nested hitobjects don't need to scroll, but they do need accurate positions and start lifetime - updatePosition(obj, hitObject.HitObject.StartTime, hitObject.HitObject.StartTime); + updatePosition(obj, hitObject.HitObject.StartTime, parentHitObjectStartTime); setComputedLifetimeStart(obj.Entry); } } From 5c13c443ff79af12849311737f99ab705b6211ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 20 Oct 2022 23:08:18 +0900 Subject: [PATCH 1788/2686] Fix incorrect fallback logic Regressed when attempting to share implementation of binary search. --- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 2 +- .../Scrolling/Algorithms/OverlappingScrollAlgorithm.cs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 9186685f0c..422e306450 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -207,7 +207,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The list to search. /// The time to find the control point at. - /// The active control point at . + /// The active control point at . Will return null if there are no control points, or if the time is before the first control point. public static T BinarySearch(IReadOnlyList list, double time) where T : class, IControlPoint { diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs index 00bc7453d8..54079c7895 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/OverlappingScrollAlgorithm.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Linq; using osu.Framework.Lists; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Timing; @@ -73,6 +74,13 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms ///
/// The time which the should affect. /// The . - private MultiplierControlPoint controlPointAt(double time) => ControlPointInfo.BinarySearch(controlPoints, time) ?? new MultiplierControlPoint(double.NegativeInfinity); + private MultiplierControlPoint controlPointAt(double time) + { + return ControlPointInfo.BinarySearch(controlPoints, time) + // The standard binary search will fail if there's no control points, or if the time is before the first. + // For this method, we want to use the first control point in the latter case. + ?? controlPoints.FirstOrDefault() + ?? new MultiplierControlPoint(double.NegativeInfinity); + } } } From ed39481932a148297c546013987e8fbbccaeaf47 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 18:11:35 +0300 Subject: [PATCH 1789/2686] Use another string for title --- osu.Game/Overlays/Comments/ReportCommentPopover.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 5214f8a3e3..83b13c8f56 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Comments { Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, - Text = UsersStrings.ReportTitle(comment.Comment.User?.Username ?? comment.Comment.LegacyName!), + Text = ReportStrings.CommentTitle(comment.Comment.User?.Username ?? comment.Comment.LegacyName!), Font = OsuFont.Torus.With(size: 25), Margin = new MarginPadding { Bottom = 10 } }, From 635900085c62854e4b8ec842a2a003cfbaff90e0 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 18:12:20 +0300 Subject: [PATCH 1790/2686] Disable button when there is no text --- .../Overlays/Comments/ReportCommentPopover.cs | 51 ++++++++----------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 83b13c8f56..14da02f838 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -2,11 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; @@ -19,8 +19,8 @@ namespace osu.Game.Overlays.Comments { private readonly DrawableComment comment; private OsuEnumDropdown reason = null!; - private OsuTextBox info = null!; - private ShakeContainer shaker = null!; + private readonly Bindable commentText = new Bindable(); + private RoundedButton submitButton = null!; public ReportCommentPopover(DrawableComment comment) { @@ -64,48 +64,37 @@ namespace osu.Game.Overlays.Comments Text = UsersStrings.ReportComments, Font = OsuFont.Torus.With(size: 20), }, - info = new OsuTextBox + new OsuTextBox { RelativeSizeAxes = Axes.X, - PlaceholderText = UsersStrings.ReportPlaceholder + PlaceholderText = UsersStrings.ReportPlaceholder, + Current = commentText }, - new Container + submitButton = new RoundedButton { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = shaker = new ShakeContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = new RoundedButton - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Width = 200, - BackgroundColour = colours.Red3, - Text = UsersStrings.ReportActionsSend, - Action = send, - Margin = new MarginPadding { Bottom = 5, Top = 10 }, - } - } + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 200, + BackgroundColour = colours.Red3, + Text = UsersStrings.ReportActionsSend, + Action = send, + Margin = new MarginPadding { Bottom = 5, Top = 10 }, } } }; + commentText.BindValueChanged(e => + { + submitButton.Enabled.Value = !string.IsNullOrWhiteSpace(e.NewValue); + }, true); } private void send() { - string infoValue = info.Current.Value; - var reasonValue = reason.Current.Value; - - if (string.IsNullOrWhiteSpace(infoValue)) - { - shaker.Shake(); + if (string.IsNullOrWhiteSpace(commentText.Value)) return; - } this.HidePopover(); - comment.ReportComment(reasonValue, infoValue); + comment.ReportComment(reason.Current.Value, commentText.Value); } } } From da4f04ace77929cb1927f4c5aa34ccde189d551f Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 18:22:55 +0300 Subject: [PATCH 1791/2686] Make dropdown not resize --- osu.Game/Overlays/Comments/ReportCommentPopover.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 14da02f838..202f27777d 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -7,6 +7,7 @@ using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; @@ -30,7 +31,7 @@ namespace osu.Game.Overlays.Comments [BackgroundDependencyLoader] private void load(OsuColour colours) { - Child = new FillFlowContainer + Child = new ReverseChildIDFillFlowContainer { Direction = FillDirection.Vertical, Width = 500, @@ -53,9 +54,14 @@ namespace osu.Game.Overlays.Comments Text = UsersStrings.ReportReason, Font = OsuFont.Torus.With(size: 20), }, - reason = new OsuEnumDropdown + new Container { - RelativeSizeAxes = Axes.X + RelativeSizeAxes = Axes.X, + Height = 40, + Child = reason = new OsuEnumDropdown + { + RelativeSizeAxes = Axes.X + } }, new OsuSpriteText { From 0ef903230c04e118d8ab94f6f628eba6ccab1ab1 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 18:47:42 +0300 Subject: [PATCH 1792/2686] Make report button a separate component --- osu.Game/Overlays/Comments/DrawableComment.cs | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 75f68782b8..a2b11bfc69 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -34,7 +34,8 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { - public class DrawableComment : CompositeDrawable, IHasPopover + [Cached] + public class DrawableComment : CompositeDrawable { private const int avatar_size = 40; @@ -64,6 +65,7 @@ namespace osu.Game.Overlays.Comments private ShowRepliesButton showRepliesButton = null!; private ChevronButton chevronButton = null!; private LinkFlowContainer actionsContainer = null!; + private ReportButton? reportButton; private LoadingSpinner actionsLoading = null!; private DeletedCommentsCounter deletedCommentsCounter = null!; private OsuSpriteText deletedLabel = null!; @@ -334,12 +336,12 @@ namespace osu.Game.Overlays.Comments makeDeleted(); actionsContainer.AddLink("Copy link", copyUrl); - actionsContainer.AddArbitraryDrawable(new Container { Width = 10 }); + actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) actionsContainer.AddLink("Delete", deleteComment); else - actionsContainer.AddLink(UsersStrings.ReportButtonText, this.ShowPopover); + actionsContainer.AddArbitraryDrawable(reportButton = new ReportButton()); if (Comment.IsTopLevel) { @@ -424,6 +426,8 @@ namespace osu.Game.Overlays.Comments request.Success += () => Schedule(() => { actionsLoading.Hide(); + reportButton?.Expire(); + actionsContainer.Show(); onScreenDisplay?.Display(new ReportToast()); }); request.Failure += _ => Schedule(() => @@ -582,8 +586,6 @@ namespace osu.Game.Overlays.Comments } } - public Popover GetPopover() => new ReportCommentPopover(this); - private class ReportToast : Toast { public ReportToast() @@ -591,5 +593,25 @@ namespace osu.Game.Overlays.Comments { } } + + private class ReportButton : LinkFlowContainer, IHasPopover + { + public ReportButton() + : base(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) + { + } + + [Resolved] + private DrawableComment comment { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + AddLink(UsersStrings.ReportButtonText, this.ShowPopover); + } + + public Popover GetPopover() => new ReportCommentPopover(comment); + } } } From 81bdf716ef41a8b9968cbe6e05b00dace996075b Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 20 Oct 2022 19:56:00 +0300 Subject: [PATCH 1793/2686] Change test --- osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs | 2 +- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 54c135ba15..a2e0c90c4c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -276,7 +276,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Complete request", () => requestLock.Set()); AddUntilStep("Request sent", () => request != null); AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Comment == report_text && request.Reason == CommentReportReason.Other); - AddUntilStep("Buttons hidden", () => !targetComment.ChildrenOfType().Single(x => x.Name == @"Actions buttons").IsPresent); + AddUntilStep("Button expired", () => !targetComment.ChildrenOfType().Any()); } private void addTestComments() diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index a2b11bfc69..199f678be1 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -594,7 +594,7 @@ namespace osu.Game.Overlays.Comments } } - private class ReportButton : LinkFlowContainer, IHasPopover + internal class ReportButton : LinkFlowContainer, IHasPopover { public ReportButton() : base(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) From bf4a91f1f00b6fab2208416558e142dba6b10caa Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 20 Oct 2022 12:48:44 -0700 Subject: [PATCH 1794/2686] Fix skin toolbox component button not playing hover/click sounds --- osu.Game/Skinning/Editor/SkinComponentToolbox.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs index 980dee8601..469657c03c 100644 --- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs @@ -85,10 +85,6 @@ namespace osu.Game.Skinning.Editor { public Action? RequestPlacement; - protected override bool ShouldBeConsideredForInput(Drawable child) => false; - - public override bool PropagateNonPositionalInputSubTree => false; - private readonly Drawable component; private readonly CompositeDrawable? dependencySource; @@ -177,6 +173,10 @@ namespace osu.Game.Skinning.Editor public class DependencyBorrowingContainer : Container { + protected override bool ShouldBeConsideredForInput(Drawable child) => false; + + public override bool PropagateNonPositionalInputSubTree => false; + private readonly CompositeDrawable? donor; public DependencyBorrowingContainer(CompositeDrawable? donor) From 27ce3d8342e0a239042f1402ca486e44461770c6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 21 Oct 2022 01:52:19 +0300 Subject: [PATCH 1795/2686] Fix input settings not displaying in visual test browser --- osu.Desktop/OsuGameDesktop.cs | 29 ----------------------------- osu.Game/OsuGameBase.cs | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 3ee1b3da30..09f7292845 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -18,17 +18,9 @@ using osu.Framework; using osu.Framework.Logging; using osu.Game.Updater; using osu.Desktop.Windows; -using osu.Framework.Input.Handlers; -using osu.Framework.Input.Handlers.Joystick; -using osu.Framework.Input.Handlers.Mouse; -using osu.Framework.Input.Handlers.Tablet; -using osu.Framework.Input.Handlers.Touch; using osu.Framework.Threading; using osu.Game.IO; using osu.Game.IPC; -using osu.Game.Overlays.Settings; -using osu.Game.Overlays.Settings.Sections; -using osu.Game.Overlays.Settings.Sections.Input; using osu.Game.Utils; using SDL2; @@ -148,27 +140,6 @@ namespace osu.Desktop desktopWindow.DragDrop += f => fileDrop(new[] { f }); } - public override SettingsSubsection CreateSettingsSubsectionFor(InputHandler handler) - { - switch (handler) - { - case ITabletHandler th: - return new TabletSettings(th); - - case MouseHandler mh: - return new MouseSettings(mh); - - case JoystickHandler jh: - return new JoystickSettings(jh); - - case TouchHandler th: - return new InputSection.HandlerSection(th); - - default: - return base.CreateSettingsSubsectionFor(handler); - } - } - protected override BatteryInfo CreateBatteryInfo() => new SDL2BatteryInfo(); private readonly List importableFiles = new List(); diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 7d9ed7bf3e..1177f01609 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -21,7 +21,11 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Framework.Input; using osu.Framework.Input.Handlers; +using osu.Framework.Input.Handlers.Joystick; using osu.Framework.Input.Handlers.Midi; +using osu.Framework.Input.Handlers.Mouse; +using osu.Framework.Input.Handlers.Tablet; +using osu.Framework.Input.Handlers.Touch; using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Framework.Platform; @@ -46,6 +50,7 @@ using osu.Game.Online.Spectator; using osu.Game.Overlays; using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings.Sections; +using osu.Game.Overlays.Settings.Sections.Input; using osu.Game.Resources; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -521,6 +526,24 @@ namespace osu.Game /// Should be overriden per-platform to provide settings for platform-specific handlers. public virtual SettingsSubsection CreateSettingsSubsectionFor(InputHandler handler) { + if (RuntimeInfo.IsDesktop) + { + switch (handler) + { + case ITabletHandler th: + return new TabletSettings(th); + + case MouseHandler mh: + return new MouseSettings(mh); + + case JoystickHandler jh: + return new JoystickSettings(jh); + + case TouchHandler: + return new InputSection.HandlerSection(handler); + } + } + switch (handler) { case MidiHandler: From d441e98af785942277e6172c732f512cee626f07 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 15:34:25 +0900 Subject: [PATCH 1796/2686] Adjust kiai flash period in line with stable --- osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index 36daefbd36..6b5a9ae6d2 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Extensions.Color4Extensions; @@ -170,7 +169,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default FlashBox .FadeTo(flash_opacity) .Then() - .FadeOut(Math.Max(80, timingPoint.BeatLength - 80), Easing.OutSine); + .FadeOut(timingPoint.BeatLength * 0.75, Easing.OutSine); } if (beatIndex % timingPoint.TimeSignature.Numerator != 0) From 23b7b9013e65f0b9c7828ac5d1cbac4b18d98dc0 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Thu, 20 Oct 2022 23:37:05 -0700 Subject: [PATCH 1797/2686] Change smoke quadbatch growth factor to 2 from 1.5 --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 23bfea5240..46c8e7c02a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -238,9 +238,9 @@ namespace osu.Game.Rulesets.Osu.Skinning quadBatch ??= renderer.CreateQuadBatch(200, 4); - if (points.Count > quadBatch.Size * 4 && quadBatch.Size != 10922) + if (points.Count > quadBatch.Size && quadBatch.Size != IRenderer.MAX_QUADS) { - int batchSize = Math.Min((int)(quadBatch.Size * 1.5f), 10922); + int batchSize = Math.Min(quadBatch.Size * 2, IRenderer.MAX_QUADS); quadBatch = renderer.CreateQuadBatch(batchSize, 4); } From 6cdfddea6261a293bf54f285ead6c012eddb1cb2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 16:10:55 +0900 Subject: [PATCH 1798/2686] Always enable distance spacing when adusting distance space multiplier --- osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index 46a827e03a..feedad7f25 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Edit { case GlobalAction.EditorIncreaseDistanceSpacing: case GlobalAction.EditorDecreaseDistanceSpacing: - return adjustDistanceSpacing(e.Action, adjust_step); + return AdjustDistanceSpacing(e.Action, adjust_step); } return false; @@ -127,13 +127,13 @@ namespace osu.Game.Rulesets.Edit { case GlobalAction.EditorIncreaseDistanceSpacing: case GlobalAction.EditorDecreaseDistanceSpacing: - return adjustDistanceSpacing(e.Action, e.ScrollAmount * adjust_step); + return AdjustDistanceSpacing(e.Action, e.ScrollAmount * adjust_step); } return false; } - private bool adjustDistanceSpacing(GlobalAction action, float amount) + protected virtual bool AdjustDistanceSpacing(GlobalAction action, float amount) { if (DistanceSpacingMultiplier.Disabled) return false; From ef990c55ca43efec56f378a205a456749f71ba06 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 16:11:19 +0900 Subject: [PATCH 1799/2686] Handle distance/grid toggles based on key type, rathern than individual left/right --- .../Edit/OsuHitObjectComposer.cs | 59 ++++++++++++++----- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index e46131dd6e..4eb1cc3513 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -16,6 +16,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; +using osu.Game.Input.Bindings; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Mods; @@ -25,7 +26,6 @@ using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Components.TernaryButtons; using osu.Game.Screens.Edit.Compose.Components; using osuTK; -using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit { @@ -236,30 +236,61 @@ namespace osu.Game.Rulesets.Osu.Edit if (e.Repeat) return false; - handleToggleViaKey(e.Key); - + handleToggleViaKey(e); return base.OnKeyDown(e); } protected override void OnKeyUp(KeyUpEvent e) { - handleToggleViaKey(e.Key); + handleToggleViaKey(e); base.OnKeyUp(e); } - private void handleToggleViaKey(Key key) + protected override bool AdjustDistanceSpacing(GlobalAction action, float amount) { - switch (key) - { - case Key.ShiftLeft: - case Key.ShiftRight: - rectangularGridSnapToggle.Value = rectangularGridSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; - break; + // To allow better visualisation, ensure that the spacing grid is visible before adjusting. + distanceSnapToggle.Value = TernaryState.True; - case Key.AltLeft: - case Key.AltRight: + return base.AdjustDistanceSpacing(action, amount); + } + + private TernaryState? gridSnapBeforeMomentary; + private TernaryState? distanceSnapBeforeMomentary; + + private void handleToggleViaKey(KeyboardEvent key) + { + if (key.ShiftPressed) + { + if (gridSnapBeforeMomentary == null) + { + gridSnapBeforeMomentary = rectangularGridSnapToggle.Value; + rectangularGridSnapToggle.Value = rectangularGridSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; + } + } + else + { + if (gridSnapBeforeMomentary != null) + { + rectangularGridSnapToggle.Value = gridSnapBeforeMomentary.Value; + gridSnapBeforeMomentary = null; + } + } + + if (key.AltPressed) + { + if (distanceSnapBeforeMomentary == null) + { + distanceSnapBeforeMomentary = distanceSnapToggle.Value; distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; - break; + } + } + else + { + if (distanceSnapBeforeMomentary != null) + { + distanceSnapToggle.Value = distanceSnapBeforeMomentary.Value; + distanceSnapBeforeMomentary = null; + } } } From 16f5c2a7c6b90dc54baab5407e3b2a06cbf89653 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 17:15:36 +0900 Subject: [PATCH 1800/2686] Apply same fix to osu!catch composer --- .../Edit/CatchHitObjectComposer.cs | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index d40200f2dd..72750fb798 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -94,29 +94,36 @@ namespace osu.Game.Rulesets.Catch.Edit if (e.Repeat) return false; - if (handleToggleViaKey(e.Key)) - return true; - + handleToggleViaKey(e); return base.OnKeyDown(e); } protected override void OnKeyUp(KeyUpEvent e) { - handleToggleViaKey(e.Key); + handleToggleViaKey(e); base.OnKeyUp(e); } - private bool handleToggleViaKey(Key key) - { - switch (key) - { - case Key.AltLeft: - case Key.AltRight: - distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; - return true; - } + private TernaryState? distanceSnapBeforeMomentary; - return false; + private void handleToggleViaKey(KeyboardEvent key) + { + if (key.AltPressed) + { + if (distanceSnapBeforeMomentary == null) + { + distanceSnapBeforeMomentary = distanceSnapToggle.Value; + distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; + } + } + else + { + if (distanceSnapBeforeMomentary != null) + { + distanceSnapToggle.Value = distanceSnapBeforeMomentary.Value; + distanceSnapBeforeMomentary = null; + } + } } public override bool OnPressed(KeyBindingPressEvent e) From ca91f9f7160517afebbd17eebb9b7c704fa054a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 17:16:55 +0900 Subject: [PATCH 1801/2686] Don't allow two momentary toggles at the same time to avoid edge cases --- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 4eb1cc3513..282631bb1a 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -261,7 +261,7 @@ namespace osu.Game.Rulesets.Osu.Edit { if (key.ShiftPressed) { - if (gridSnapBeforeMomentary == null) + if (distanceSnapBeforeMomentary == null && gridSnapBeforeMomentary == null) { gridSnapBeforeMomentary = rectangularGridSnapToggle.Value; rectangularGridSnapToggle.Value = rectangularGridSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; @@ -278,7 +278,7 @@ namespace osu.Game.Rulesets.Osu.Edit if (key.AltPressed) { - if (distanceSnapBeforeMomentary == null) + if (gridSnapBeforeMomentary == null && distanceSnapBeforeMomentary == null) { distanceSnapBeforeMomentary = distanceSnapToggle.Value; distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; From 7b1edff2b36a728e4ef964ea4bf849d86c37d368 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 21 Oct 2022 18:06:38 +0900 Subject: [PATCH 1802/2686] Add unique hover/select samples to settings sidebar buttons --- osu.Game/Graphics/UserInterface/HoverSampleSet.cs | 3 +++ osu.Game/Overlays/Settings/SidebarButton.cs | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/HoverSampleSet.cs b/osu.Game/Graphics/UserInterface/HoverSampleSet.cs index 6358317e9d..f0ff76b35d 100644 --- a/osu.Game/Graphics/UserInterface/HoverSampleSet.cs +++ b/osu.Game/Graphics/UserInterface/HoverSampleSet.cs @@ -15,6 +15,9 @@ namespace osu.Game.Graphics.UserInterface [Description("button")] Button, + [Description("button-sidebar")] + ButtonSidebar, + [Description("toolbar")] Toolbar, diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs index c6a4cbbcaa..2c4832c68a 100644 --- a/osu.Game/Overlays/Settings/SidebarButton.cs +++ b/osu.Game/Overlays/Settings/SidebarButton.cs @@ -16,6 +16,11 @@ namespace osu.Game.Overlays.Settings [Resolved] protected OverlayColourProvider ColourProvider { get; private set; } + protected SidebarButton() + : base(HoverSampleSet.ButtonSidebar) + { + } + [BackgroundDependencyLoader] private void load() { From af84f708b7b83d87738fecc45982ec13083c9755 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 19:01:28 +0900 Subject: [PATCH 1803/2686] Avoid serialising some more properties of `SoloScoreInfo` unless present --- .../Online/API/Requests/Responses/SoloScoreInfo.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 2c9f250028..4469d50acb 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -114,6 +114,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty("has_replay")] public bool HasReplay { get; set; } + // These properties are calculated or not relevant to any external usage. public bool ShouldSerializeID() => false; public bool ShouldSerializeUser() => false; public bool ShouldSerializeBeatmap() => false; @@ -122,6 +123,18 @@ namespace osu.Game.Online.API.Requests.Responses public bool ShouldSerializeOnlineID() => false; public bool ShouldSerializeHasReplay() => false; + // These fields only need to be serialised if they hold values. + // Generally this is required because this model may be used by server-side components, but + // we don't want to bother sending these fields in score submission requests, for instance. + public bool ShouldSerializeEndedAt() => EndedAt != default; + public bool ShouldSerializeStartedAt() => StartedAt != default; + public bool ShouldSerializeLegacyScoreId() => LegacyScoreId != null; + public bool ShouldSerializeLegacyTotalScore() => LegacyTotalScore != null; + public bool ShouldSerializeMods() => Mods.Length > 0; + public bool ShouldSerializeUserID() => UserID > 0; + public bool ShouldSerializeBeatmapID() => BeatmapID > 0; + public bool ShouldSerializeBuildID() => BuildID != null; + #endregion public override string ToString() => $"score_id: {ID} user_id: {UserID}"; From 1e09a212791de25c93c7f48183aacff6f369aa46 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 19:55:58 +0900 Subject: [PATCH 1804/2686] Remove unused using statement --- osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 72750fb798..27235bd62e 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -26,7 +26,6 @@ using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Components.TernaryButtons; using osu.Game.Screens.Edit.Compose.Components; using osuTK; -using osuTK.Input; namespace osu.Game.Rulesets.Catch.Edit { From 8b74b5807f3f43b7107ed19dd39636afddada643 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 20:53:37 +0900 Subject: [PATCH 1805/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 3f4c8e2d24..50fb1c4eda 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f1fed6913b..42da129195 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index c79d0e4864..d883ce0045 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + From 447d420c997622ec256d7dc8678ee052feb3510c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 21:03:39 +0900 Subject: [PATCH 1806/2686] Fix adjusting volume via settings playing tick samples twice --- .../Graphics/UserInterface/OsuSliderBar.cs | 5 +++++ .../Settings/Sections/Audio/VolumeSettings.cs | 18 +++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 2a8b41fd20..9acb0c7f94 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -44,6 +44,8 @@ namespace osu.Game.Graphics.UserInterface public virtual LocalisableString TooltipText { get; private set; } + public bool PlaySamplesOnAdjust { get; set; } = true; + /// /// Whether to format the tooltip as a percentage or the actual value. /// @@ -187,6 +189,9 @@ namespace osu.Game.Graphics.UserInterface private void playSample(T value) { + if (!PlaySamplesOnAdjust) + return; + if (Clock == null || Clock.CurrentTime - lastSampleTime <= 30) return; diff --git a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs index cea8fdd733..8f188f04d9 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs @@ -8,6 +8,7 @@ using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Audio @@ -21,7 +22,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio { Children = new Drawable[] { - new SettingsSlider + new VolumeAdjustSlider { LabelText = AudioSettingsStrings.MasterVolume, Current = audio.Volume, @@ -35,14 +36,15 @@ namespace osu.Game.Overlays.Settings.Sections.Audio KeyboardStep = 0.01f, DisplayAsPercentage = true }, - new SettingsSlider + new VolumeAdjustSlider { LabelText = AudioSettingsStrings.EffectVolume, Current = audio.VolumeSample, KeyboardStep = 0.01f, DisplayAsPercentage = true }, - new SettingsSlider + + new VolumeAdjustSlider { LabelText = AudioSettingsStrings.MusicVolume, Current = audio.VolumeTrack, @@ -51,5 +53,15 @@ namespace osu.Game.Overlays.Settings.Sections.Audio }, }; } + + private class VolumeAdjustSlider : SettingsSlider + { + protected override Drawable CreateControl() + { + var sliderBar = (OsuSliderBar)base.CreateControl(); + sliderBar.PlaySamplesOnAdjust = false; + return sliderBar; + } + } } } From 7dc03097ffa73297def50e96b8c7609db4ee1246 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 21:51:17 +0900 Subject: [PATCH 1807/2686] Change distance snap to never account for slider velocity This is a nuanced detail that was implemented incorrectly from the outset. When mapping, generally a mapper chooses the distance spacing with no regard to the SV. It has always been common to have a lower or higher distance spacing than SV, but with the way the lazer editor has worked, the SV was multiplied into the distance snap grid display, incorectly changing its spacing depending on the "reference object" (which is usually the previous hitobject chronologically). --- osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index 46a827e03a..d23d8ad438 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -148,7 +148,7 @@ namespace osu.Game.Rulesets.Edit public virtual float GetBeatSnapDistanceAt(HitObject referenceObject) { - return (float)(100 * EditorBeatmap.Difficulty.SliderMultiplier * referenceObject.DifficultyControlPoint.SliderVelocity / BeatSnapProvider.BeatDivisor); + return (float)(100 * EditorBeatmap.Difficulty.SliderMultiplier * 1 / BeatSnapProvider.BeatDivisor); } public virtual float DurationToDistance(HitObject referenceObject, double duration) From bace3df4cae732e0b34d518cc0cb3a7cbea1c488 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 22:58:10 +0900 Subject: [PATCH 1808/2686] Update test assertions in line with change --- .../Editing/TestSceneHitObjectComposerDistanceSnapping.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs index 1e87ed27df..a98f931e7a 100644 --- a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs +++ b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs @@ -71,9 +71,9 @@ namespace osu.Game.Tests.Editing [TestCase(1)] [TestCase(2)] - public void TestSpeedMultiplier(float multiplier) + public void TestSpeedMultiplierDoesNotChangeDistanceSnap(float multiplier) { - assertSnapDistance(100 * multiplier, new HitObject + assertSnapDistance(100, new HitObject { DifficultyControlPoint = new DifficultyControlPoint { From 645a84b1d633973d5e360aec52d4f1693a91baf8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 22:58:36 +0900 Subject: [PATCH 1809/2686] Display current distance snap and add button to update to use it --- .../Edit/CatchHitObjectComposer.cs | 6 ++ .../Edit/OsuHitObjectComposer.cs | 8 ++ .../Edit/DistancedHitObjectComposer.cs | 74 ++++++++++++++++++- osu.Game/Rulesets/Edit/ExpandableButton.cs | 36 +++++++++ 4 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Rulesets/Edit/ExpandableButton.cs diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 54d50b01c4..f2eaebbfe5 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -81,6 +81,12 @@ namespace osu.Game.Rulesets.Catch.Edit inputManager = GetContainingInputManager(); } + protected override double ReadCurrentDistanceSnap(HitObject before, HitObject after) + { + // TODO: catch lol + return 1; + } + protected override void Update() { base.Update(); diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 6b4a6e39d9..58d0005ab7 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -112,6 +112,14 @@ namespace osu.Game.Rulesets.Osu.Edit private RectangularPositionSnapGrid rectangularPositionSnapGrid; + protected override double ReadCurrentDistanceSnap(HitObject before, HitObject after) + { + float expectedDistance = DurationToDistance(before, after.StartTime - before.GetEndTime()); + float actualDistance = Vector2.Distance(((OsuHitObject)before).EndPosition, ((OsuHitObject)after).Position); + + return actualDistance / expectedDistance; + } + protected override void Update() { base.Update(); diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index d23d8ad438..10be00ac55 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -3,6 +3,8 @@ #nullable disable +using System.Diagnostics; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -13,7 +15,9 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Framework.Utils; using osu.Game.Configuration; +using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Overlays; @@ -32,7 +36,7 @@ namespace osu.Game.Rulesets.Edit { private const float adjust_step = 0.1f; - public Bindable DistanceSpacingMultiplier { get; } = new BindableDouble(1.0) + public BindableDouble DistanceSpacingMultiplier { get; } = new BindableDouble(1.0) { MinValue = 0.1, MaxValue = 6.0, @@ -44,6 +48,9 @@ namespace osu.Game.Rulesets.Edit protected ExpandingToolboxContainer RightSideToolboxContainer { get; private set; } private ExpandableSlider> distanceSpacingSlider; + private ExpandableButton readCurrentButton; + + private OsuSpriteText currentDistanceSpacingDisplay; [Resolved(canBeNull: true)] private OnScreenDisplay onScreenDisplay { get; set; } @@ -74,10 +81,29 @@ namespace osu.Game.Rulesets.Edit Alpha = DistanceSpacingMultiplier.Disabled ? 0 : 1, Child = new EditorToolboxGroup("snapping") { - Child = distanceSpacingSlider = new ExpandableSlider> + Children = new Drawable[] { - Current = { BindTarget = DistanceSpacingMultiplier }, - KeyboardStep = adjust_step, + distanceSpacingSlider = new ExpandableSlider> + { + Current = { BindTarget = DistanceSpacingMultiplier }, + KeyboardStep = adjust_step, + }, + currentDistanceSpacingDisplay = new OsuSpriteText + { + }, + readCurrentButton = new ExpandableButton + { + Text = "Use current", + Action = () => + { + (HitObject before, HitObject after)? objects = getObjectsOnEitherSideOfCurrentTime(); + + Debug.Assert(objects != null); + + DistanceSpacingMultiplier.Value = ReadCurrentDistanceSnap(objects.Value.before, objects.Value.after); + }, + RelativeSizeAxes = Axes.X, + } } } } @@ -85,6 +111,46 @@ namespace osu.Game.Rulesets.Edit }); } + private (HitObject before, HitObject after)? getObjectsOnEitherSideOfCurrentTime() + { + HitObject lastBefore = Playfield.HitObjectContainer.AliveObjects.LastOrDefault(h => h.HitObject.GetEndTime() <= EditorClock.CurrentTime)?.HitObject; + + if (lastBefore == null) + return null; + + HitObject firstAfter = Playfield.HitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime >= EditorClock.CurrentTime)?.HitObject; + + if (firstAfter == null) + return null; + + if (lastBefore == firstAfter) + return null; + + return (lastBefore, firstAfter); + } + + protected abstract double ReadCurrentDistanceSnap(HitObject before, HitObject after); + + protected override void Update() + { + base.Update(); + + (HitObject before, HitObject after)? objects = getObjectsOnEitherSideOfCurrentTime(); + + if (objects != null) + { + double currentSnap = ReadCurrentDistanceSnap(objects.Value.before, objects.Value.after); + readCurrentButton.Enabled.Value = Precision.AlmostEquals(currentSnap, DistanceSpacingMultiplier.Value, DistanceSpacingMultiplier.Precision); + + currentDistanceSpacingDisplay.Text = $"Current {currentSnap:N1}x"; + } + else + { + readCurrentButton.Enabled.Value = false; + currentDistanceSpacingDisplay.Text = "Current: -"; + } + } + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Game/Rulesets/Edit/ExpandableButton.cs b/osu.Game/Rulesets/Edit/ExpandableButton.cs new file mode 100644 index 0000000000..32885c1a1c --- /dev/null +++ b/osu.Game/Rulesets/Edit/ExpandableButton.cs @@ -0,0 +1,36 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterfaceV2; + +namespace osu.Game.Rulesets.Edit +{ + internal class ExpandableButton : RoundedButton, IExpandable + { + public BindableBool Expanded { get; } = new BindableBool(); + + [Resolved(canBeNull: true)] + private IExpandingContainer? expandingContainer { get; set; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + expandingContainer?.Expanded.BindValueChanged(containerExpanded => + { + Expanded.Value = containerExpanded.NewValue; + }, true); + + Expanded.BindValueChanged(expanded => + { + if (expanded.NewValue) + Show(); + else + Hide(); + }, true); + } + } +} From f6de366766b1d22fbc10650ec0feb24aebac71d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 23:21:07 +0900 Subject: [PATCH 1810/2686] Combine display and button into one control --- .../Edit/DistancedHitObjectComposer.cs | 22 +++--- osu.Game/Rulesets/Edit/ExpandableButton.cs | 69 ++++++++++++++++++- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index 10be00ac55..9ef8480b25 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -17,7 +17,6 @@ using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Framework.Utils; using osu.Game.Configuration; -using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Overlays; @@ -48,9 +47,7 @@ namespace osu.Game.Rulesets.Edit protected ExpandingToolboxContainer RightSideToolboxContainer { get; private set; } private ExpandableSlider> distanceSpacingSlider; - private ExpandableButton readCurrentButton; - - private OsuSpriteText currentDistanceSpacingDisplay; + private ExpandableButton currentDistanceSpacingButton; [Resolved(canBeNull: true)] private OnScreenDisplay onScreenDisplay { get; set; } @@ -88,12 +85,8 @@ namespace osu.Game.Rulesets.Edit Current = { BindTarget = DistanceSpacingMultiplier }, KeyboardStep = adjust_step, }, - currentDistanceSpacingDisplay = new OsuSpriteText + currentDistanceSpacingButton = new ExpandableButton { - }, - readCurrentButton = new ExpandableButton - { - Text = "Use current", Action = () => { (HitObject before, HitObject after)? objects = getObjectsOnEitherSideOfCurrentTime(); @@ -140,14 +133,17 @@ namespace osu.Game.Rulesets.Edit if (objects != null) { double currentSnap = ReadCurrentDistanceSnap(objects.Value.before, objects.Value.after); - readCurrentButton.Enabled.Value = Precision.AlmostEquals(currentSnap, DistanceSpacingMultiplier.Value, DistanceSpacingMultiplier.Precision); - currentDistanceSpacingDisplay.Text = $"Current {currentSnap:N1}x"; + currentDistanceSpacingButton.Enabled.Value = currentDistanceSpacingButton.Expanded.Value + && !Precision.AlmostEquals(currentSnap, DistanceSpacingMultiplier.Value, DistanceSpacingMultiplier.Precision / 2); + currentDistanceSpacingButton.ContractedLabelText = $"(current {currentSnap:N2}x)"; + currentDistanceSpacingButton.ExpandedLabelText = $"Use current ({currentSnap:N2}x)"; } else { - readCurrentButton.Enabled.Value = false; - currentDistanceSpacingDisplay.Text = "Current: -"; + currentDistanceSpacingButton.Enabled.Value = false; + currentDistanceSpacingButton.ContractedLabelText = "Current N/A"; + currentDistanceSpacingButton.ExpandedLabelText = "Use current (N/A)"; } } diff --git a/osu.Game/Rulesets/Edit/ExpandableButton.cs b/osu.Game/Rulesets/Edit/ExpandableButton.cs index 32885c1a1c..572ae19a03 100644 --- a/osu.Game/Rulesets/Edit/ExpandableButton.cs +++ b/osu.Game/Rulesets/Edit/ExpandableButton.cs @@ -3,6 +3,9 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Localisation; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterfaceV2; @@ -10,6 +13,54 @@ namespace osu.Game.Rulesets.Edit { internal class ExpandableButton : RoundedButton, IExpandable { + private float actualHeight; + + public override float Height + { + get => base.Height; + set => base.Height = actualHeight = value; + } + + private LocalisableString contractedLabelText; + + /// + /// The label text to display when this slider is in a contracted state. + /// + public LocalisableString ContractedLabelText + { + get => contractedLabelText; + set + { + if (value == contractedLabelText) + return; + + contractedLabelText = value; + + if (!Expanded.Value) + Text = value; + } + } + + private LocalisableString expandedLabelText; + + /// + /// The label text to display when this slider is in an expanded state. + /// + public LocalisableString ExpandedLabelText + { + get => expandedLabelText; + set + { + if (value == expandedLabelText) + return; + + expandedLabelText = value; + + if (Expanded.Value) + Text = value; + } + } + public BindableBool Expanded { get; } = new BindableBool(); [Resolved(canBeNull: true)] @@ -26,10 +77,24 @@ namespace osu.Game.Rulesets.Edit Expanded.BindValueChanged(expanded => { + Text = expanded.NewValue ? expandedLabelText : contractedLabelText; + if (expanded.NewValue) - Show(); + { + SpriteText.Anchor = Anchor.Centre; + SpriteText.Origin = Anchor.Centre; + SpriteText.Font = OsuFont.GetFont(weight: FontWeight.Bold); + base.Height = actualHeight; + Background.Show(); + } else - Hide(); + { + SpriteText.Anchor = Anchor.CentreLeft; + SpriteText.Origin = Anchor.CentreLeft; + SpriteText.Font = OsuFont.GetFont(weight: FontWeight.Regular); + base.Height = SpriteText.DrawHeight; + Background.Hide(); + } }, true); } } From 15aeb4a137c91274b9e7d964917db3d0df576938 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 21 Oct 2022 17:25:41 +0300 Subject: [PATCH 1811/2686] Display text in buttons flow instead of toast --- .../Visual/Online/TestSceneCommentActions.cs | 1 - osu.Game/Overlays/Comments/DrawableComment.cs | 19 ++++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index a2e0c90c4c..b4ffcd42b5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -276,7 +276,6 @@ namespace osu.Game.Tests.Visual.Online AddStep("Complete request", () => requestLock.Set()); AddUntilStep("Request sent", () => request != null); AddAssert("Request is correct", () => request != null && request.CommentID == 2 && request.Comment == report_text && request.Reason == CommentReportReason.Other); - AddUntilStep("Button expired", () => !targetComment.ChildrenOfType().Any()); } private void addTestComments() diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 199f678be1..4d4ed06200 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -24,7 +24,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Comments.Buttons; @@ -426,9 +425,8 @@ namespace osu.Game.Overlays.Comments request.Success += () => Schedule(() => { actionsLoading.Hide(); - reportButton?.Expire(); + reportButton?.MarkReported(); actionsContainer.Show(); - onScreenDisplay?.Display(new ReportToast()); }); request.Failure += _ => Schedule(() => { @@ -586,14 +584,6 @@ namespace osu.Game.Overlays.Comments } } - private class ReportToast : Toast - { - public ReportToast() - : base(UserInterfaceStrings.GeneralHeader, UsersStrings.ReportThanks, "") - { - } - } - internal class ReportButton : LinkFlowContainer, IHasPopover { public ReportButton() @@ -611,6 +601,13 @@ namespace osu.Game.Overlays.Comments AddLink(UsersStrings.ReportButtonText, this.ShowPopover); } + public void MarkReported() + { + Clear(true); + AddText(UsersStrings.ReportThanks); + this.Delay(3000).Then().FadeOut(2000); + } + public Popover GetPopover() => new ReportCommentPopover(comment); } } From bb921ff9a76e2e608e97b1d6c571454337c00ab6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 23:35:47 +0900 Subject: [PATCH 1812/2686] Fix incorrect current DS value when inside a slider --- osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index 9ef8480b25..4a7e0828cd 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Edit private (HitObject before, HitObject after)? getObjectsOnEitherSideOfCurrentTime() { - HitObject lastBefore = Playfield.HitObjectContainer.AliveObjects.LastOrDefault(h => h.HitObject.GetEndTime() <= EditorClock.CurrentTime)?.HitObject; + HitObject lastBefore = Playfield.HitObjectContainer.AliveObjects.LastOrDefault(h => h.HitObject.StartTime <= EditorClock.CurrentTime)?.HitObject; if (lastBefore == null) return null; From f516e32949d2b4c24bad95b2c57c2f95f5ef20dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 23:35:53 +0900 Subject: [PATCH 1813/2686] Improve UI a bit --- .../Rulesets/Edit/DistancedHitObjectComposer.cs | 15 +++++++++------ osu.Game/Rulesets/Edit/ExpandableButton.cs | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index 4a7e0828cd..9a65570e72 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -94,6 +94,7 @@ namespace osu.Game.Rulesets.Edit Debug.Assert(objects != null); DistanceSpacingMultiplier.Value = ReadCurrentDistanceSnap(objects.Value.before, objects.Value.after); + // TODO: This should probably also force distance spacing grid on. }, RelativeSizeAxes = Axes.X, } @@ -130,20 +131,22 @@ namespace osu.Game.Rulesets.Edit (HitObject before, HitObject after)? objects = getObjectsOnEitherSideOfCurrentTime(); - if (objects != null) - { - double currentSnap = ReadCurrentDistanceSnap(objects.Value.before, objects.Value.after); + double currentSnap = objects == null + ? 0 + : ReadCurrentDistanceSnap(objects.Value.before, objects.Value.after); + if (currentSnap > DistanceSpacingMultiplier.MinValue) + { currentDistanceSpacingButton.Enabled.Value = currentDistanceSpacingButton.Expanded.Value && !Precision.AlmostEquals(currentSnap, DistanceSpacingMultiplier.Value, DistanceSpacingMultiplier.Precision / 2); - currentDistanceSpacingButton.ContractedLabelText = $"(current {currentSnap:N2}x)"; + currentDistanceSpacingButton.ContractedLabelText = $"current {currentSnap:N2}x"; currentDistanceSpacingButton.ExpandedLabelText = $"Use current ({currentSnap:N2}x)"; } else { currentDistanceSpacingButton.Enabled.Value = false; - currentDistanceSpacingButton.ContractedLabelText = "Current N/A"; - currentDistanceSpacingButton.ExpandedLabelText = "Use current (N/A)"; + currentDistanceSpacingButton.ContractedLabelText = string.Empty; + currentDistanceSpacingButton.ExpandedLabelText = "Use current (unavailable)"; } } diff --git a/osu.Game/Rulesets/Edit/ExpandableButton.cs b/osu.Game/Rulesets/Edit/ExpandableButton.cs index 572ae19a03..5b60a2536d 100644 --- a/osu.Game/Rulesets/Edit/ExpandableButton.cs +++ b/osu.Game/Rulesets/Edit/ExpandableButton.cs @@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Edit SpriteText.Anchor = Anchor.CentreLeft; SpriteText.Origin = Anchor.CentreLeft; SpriteText.Font = OsuFont.GetFont(weight: FontWeight.Regular); - base.Height = SpriteText.DrawHeight; + base.Height = actualHeight / 2; Background.Hide(); } }, true); From c1ed775deb3a14a4344bc0b177b65baaa99f2d4e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Oct 2022 23:36:16 +0900 Subject: [PATCH 1814/2686] 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 50fb1c4eda..b036d3d177 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 42da129195..b64d135ab8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index d883ce0045..06fac451ad 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 678bfb2caa67d779d052ae70d61401d66bb912bf Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 21 Oct 2022 20:56:18 +0300 Subject: [PATCH 1815/2686] Ban `char.ToLower()`/`char.ToUpper()` as well for better safety --- CodeAnalysis/BannedSymbols.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CodeAnalysis/BannedSymbols.txt b/CodeAnalysis/BannedSymbols.txt index 022da0a2ea..03fd21829d 100644 --- a/CodeAnalysis/BannedSymbols.txt +++ b/CodeAnalysis/BannedSymbols.txt @@ -15,6 +15,8 @@ M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Collections.Gen M:System.Threading.Tasks.Task.Wait();Don't use Task.Wait. Use Task.WaitSafely() to ensure we avoid deadlocks. P:System.Threading.Tasks.Task`1.Result;Don't use Task.Result. Use Task.GetResultSafely() to ensure we avoid deadlocks. M:System.Threading.ManualResetEventSlim.Wait();Specify a timeout to avoid waiting forever. +M:System.Char.ToLower(System.Char);char.ToLower() changes behaviour depending on CultureInfo.CurrentCulture. Use char.ToLowerInvariant() instead. If wanting culture-sensitive behaviour, explicitly provide CultureInfo.CurrentCulture. +M:System.Char.ToUpper(System.Char);char.ToUpper() changes behaviour depending on CultureInfo.CurrentCulture. Use char.ToUpperInvariant() instead. If wanting culture-sensitive behaviour, explicitly provide CultureInfo.CurrentCulture. M:System.String.ToLower();string.ToLower() changes behaviour depending on CultureInfo.CurrentCulture. Use string.ToLowerInvariant() instead. If wanting culture-sensitive behaviour, explicitly provide CultureInfo.CurrentCulture or use LocalisableString. M:System.String.ToUpper();string.ToUpper() changes behaviour depending on CultureInfo.CurrentCulture. Use string.ToUpperInvariant() instead. If wanting culture-sensitive behaviour, explicitly provide CultureInfo.CurrentCulture or use LocalisableString. M:Humanizer.InflectorExtensions.Pascalize(System.String);Humanizer's .Pascalize() extension method changes behaviour depending on CultureInfo.CurrentCulture. Use StringDehumanizeExtensions.ToPascalCase() instead. From 081cf1cc47c5ad775840ab1227bbb85808477ad1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 22 Oct 2022 02:45:28 +0300 Subject: [PATCH 1816/2686] Adjust comment report popover design --- osu.Game/Overlays/Comments/ReportCommentPopover.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 202f27777d..f3d6e319bf 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -39,6 +39,13 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(7), Children = new Drawable[] { + new SpriteIcon + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Icon = FontAwesome.Solid.ExclamationTriangle, + Size = new Vector2(36), + }, new OsuSpriteText { Origin = Anchor.TopCentre, @@ -52,7 +59,6 @@ namespace osu.Game.Overlays.Comments Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Text = UsersStrings.ReportReason, - Font = OsuFont.Torus.With(size: 20), }, new Container { @@ -68,7 +74,6 @@ namespace osu.Game.Overlays.Comments Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, Text = UsersStrings.ReportComments, - Font = OsuFont.Torus.With(size: 20), }, new OsuTextBox { From 9b5e35d5992985722ddf8576500c6d69040c3998 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 22 Oct 2022 02:45:06 +0300 Subject: [PATCH 1817/2686] Remove dependency on `DrawableComment` from report popover and simplify logic Allows for testing the button and popover in isolation. --- .../Overlays/Comments/ReportCommentPopover.cs | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index f3d6e319bf..39fd52aa2a 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -1,16 +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; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; using osuTK; @@ -18,12 +20,15 @@ namespace osu.Game.Overlays.Comments { public class ReportCommentPopover : OsuPopover { - private readonly DrawableComment comment; - private OsuEnumDropdown reason = null!; - private readonly Bindable commentText = new Bindable(); + public Action? Action; + + private readonly Comment? comment; + + private OsuEnumDropdown reasonDropdown = null!; + private OsuTextBox commentsTextBox = null!; private RoundedButton submitButton = null!; - public ReportCommentPopover(DrawableComment comment) + public ReportCommentPopover(Comment? comment) { this.comment = comment; } @@ -50,7 +55,7 @@ namespace osu.Game.Overlays.Comments { Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, - Text = ReportStrings.CommentTitle(comment.Comment.User?.Username ?? comment.Comment.LegacyName!), + Text = ReportStrings.CommentTitle(comment?.User?.Username ?? comment?.LegacyName ?? @"Someone"), Font = OsuFont.Torus.With(size: 25), Margin = new MarginPadding { Bottom = 10 } }, @@ -64,7 +69,7 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, Height = 40, - Child = reason = new OsuEnumDropdown + Child = reasonDropdown = new OsuEnumDropdown { RelativeSizeAxes = Axes.X } @@ -75,11 +80,10 @@ namespace osu.Game.Overlays.Comments Anchor = Anchor.TopCentre, Text = UsersStrings.ReportComments, }, - new OsuTextBox + commentsTextBox = new OsuTextBox { RelativeSizeAxes = Axes.X, PlaceholderText = UsersStrings.ReportPlaceholder, - Current = commentText }, submitButton = new RoundedButton { @@ -88,24 +92,20 @@ namespace osu.Game.Overlays.Comments Width = 200, BackgroundColour = colours.Red3, Text = UsersStrings.ReportActionsSend, - Action = send, + Action = () => + { + Action?.Invoke(reasonDropdown.Current.Value, commentsTextBox.Text); + this.HidePopover(); + }, Margin = new MarginPadding { Bottom = 5, Top = 10 }, } } }; - commentText.BindValueChanged(e => + + commentsTextBox.Current.BindValueChanged(e => { submitButton.Enabled.Value = !string.IsNullOrWhiteSpace(e.NewValue); }, true); } - - private void send() - { - if (string.IsNullOrWhiteSpace(commentText.Value)) - return; - - this.HidePopover(); - comment.ReportComment(reason.Current.Value, commentText.Value); - } } } From 6c82bc36ed703bbfb6a4567baeea669375bfed0c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 22 Oct 2022 02:47:11 +0300 Subject: [PATCH 1818/2686] Encapsulate report logic inside button implementation Avoids complicating the `DrawableComment` class, and allows for isolated testability. --- .../Overlays/Comments/CommentReportButton.cs | 91 +++++++++++++++++++ osu.Game/Overlays/Comments/DrawableComment.cs | 51 +---------- 2 files changed, 92 insertions(+), 50 deletions(-) create mode 100644 osu.Game/Overlays/Comments/CommentReportButton.cs diff --git a/osu.Game/Overlays/Comments/CommentReportButton.cs b/osu.Game/Overlays/Comments/CommentReportButton.cs new file mode 100644 index 0000000000..4f5c5c6dcf --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentReportButton.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Resources.Localisation.Web; +using osuTK; + +namespace osu.Game.Overlays.Comments +{ + public class CommentReportButton : CompositeDrawable, IHasPopover + { + private readonly Comment comment; + + private LinkFlowContainer link = null!; + private LoadingSpinner loading = null!; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + [Resolved] + private OverlayColourProvider? colourProvider { get; set; } + + public CommentReportButton(Comment comment) + { + this.comment = comment; + } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + link = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) + { + AutoSizeAxes = Axes.Both, + }, + loading = new LoadingSpinner + { + Size = new Vector2(12f), + } + }; + + link.AddLink(UsersStrings.ReportButtonText, this.ShowPopover); + } + + private void report(CommentReportReason reason, string comments) + { + var request = new CommentReportRequest(comment.Id, reason, comments); + + link.Hide(); + loading.Show(); + + request.Success += () => Schedule(() => + { + loading.Hide(); + + link.Clear(true); + link.AddText(UsersStrings.ReportThanks, s => s.Colour = colourProvider?.Content2 ?? Colour4.White); + link.Show(); + + this.FadeOut(2000, Easing.InQuint).Expire(); + }); + + request.Failure += _ => Schedule(() => + { + loading.Hide(); + link.Show(); + }); + + api.Queue(request); + } + + public Popover GetPopover() => new ReportCommentPopover(comment) + { + Action = report + }; + } +} diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 4d4ed06200..aa08de798c 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -19,8 +19,6 @@ using System; using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; -using osu.Framework.Extensions; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Graphics.UserInterface; @@ -64,7 +62,6 @@ namespace osu.Game.Overlays.Comments private ShowRepliesButton showRepliesButton = null!; private ChevronButton chevronButton = null!; private LinkFlowContainer actionsContainer = null!; - private ReportButton? reportButton; private LoadingSpinner actionsLoading = null!; private DeletedCommentsCounter deletedCommentsCounter = null!; private OsuSpriteText deletedLabel = null!; @@ -340,7 +337,7 @@ namespace osu.Game.Overlays.Comments if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) actionsContainer.AddLink("Delete", deleteComment); else - actionsContainer.AddArbitraryDrawable(reportButton = new ReportButton()); + actionsContainer.AddArbitraryDrawable(new CommentReportButton(Comment)); if (Comment.IsTopLevel) { @@ -417,25 +414,6 @@ namespace osu.Game.Overlays.Comments api.Queue(request); } - public void ReportComment(CommentReportReason reason, string comment) - { - actionsContainer.Hide(); - actionsLoading.Show(); - var request = new CommentReportRequest(Comment.Id, reason, comment); - request.Success += () => Schedule(() => - { - actionsLoading.Hide(); - reportButton?.MarkReported(); - actionsContainer.Show(); - }); - request.Failure += _ => Schedule(() => - { - actionsLoading.Hide(); - actionsContainer.Show(); - }); - api.Queue(request); - } - private void copyUrl() { host.GetClipboard()?.SetText($@"{api.APIEndpointUrl}/comments/{Comment.Id}"); @@ -583,32 +561,5 @@ namespace osu.Game.Overlays.Comments return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? "deleted" : string.Empty; } } - - internal class ReportButton : LinkFlowContainer, IHasPopover - { - public ReportButton() - : base(s => s.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold)) - { - } - - [Resolved] - private DrawableComment comment { get; set; } = null!; - - [BackgroundDependencyLoader] - private void load() - { - AutoSizeAxes = Axes.Both; - AddLink(UsersStrings.ReportButtonText, this.ShowPopover); - } - - public void MarkReported() - { - Clear(true); - AddText(UsersStrings.ReportThanks); - this.Delay(3000).Then().FadeOut(2000); - } - - public Popover GetPopover() => new ReportCommentPopover(comment); - } } } From 90a9961a69655de48b05ecef8de33146c09c564d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 22 Oct 2022 02:47:23 +0300 Subject: [PATCH 1819/2686] Add visual test case for report button Makes it much easier to test button/popover design changes --- .../Online/TestSceneCommentReportButton.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs new file mode 100644 index 0000000000..fb56a41507 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs @@ -0,0 +1,46 @@ +// 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.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Testing; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.Comments; +using osu.Game.Tests.Visual.UserInterface; +using osuTK; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneCommentReportButton : ThemeComparisonTestScene + { + [SetUpSteps] + public void SetUpSteps() + { + AddStep("setup API", () => ((DummyAPIAccess)API).HandleRequest += req => + { + switch (req) + { + case CommentReportRequest report: + Scheduler.AddDelayed(report.TriggerSuccess, 1000); + return true; + } + + return false; + }); + } + + protected override Drawable CreateContent() => new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + Child = new CommentReportButton(new Comment { User = new APIUser { Username = "Someone" } }) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(2f), + }.With(b => Schedule(b.ShowPopover)), + }; + } +} From b0a4cd4f30e65ce7e04884f986c9d2c8f2501912 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 22 Oct 2022 03:43:14 +0300 Subject: [PATCH 1820/2686] Inline content creation in base add method --- osu.Game/Overlays/Changelog/ChangelogContent.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogContent.cs b/osu.Game/Overlays/Changelog/ChangelogContent.cs index dca2f3b1b0..2b54df7226 100644 --- a/osu.Game/Overlays/Changelog/ChangelogContent.cs +++ b/osu.Game/Overlays/Changelog/ChangelogContent.cs @@ -23,13 +23,13 @@ namespace osu.Game.Overlays.Changelog { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Content = new FillFlowContainer + + base.Content.Add(Content = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical - }; - base.Content.Add(Content); + }); } } } From 3d37a67590f866bc43a26c69a2be15ca1938279e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Oct 2022 14:15:17 +0900 Subject: [PATCH 1821/2686] 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 b036d3d177..152e050805 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b64d135ab8..bd8c915f5f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 06fac451ad..1a3f9dbe67 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 9155fcf3cb8cb71eaae196b8962f136c54fc8bd7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 22 Oct 2022 23:25:08 +0900 Subject: [PATCH 1822/2686] 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 152e050805..f251e8ee71 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index bd8c915f5f..e0561d9b21 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 1a3f9dbe67..cf70b65578 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From a74e873b983678993ca7d3c4c6d20468d052e9b7 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Sun, 23 Oct 2022 01:13:29 +0900 Subject: [PATCH 1823/2686] remove useless using --- osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs index 57c45fc074..161799c980 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Screens.Edit.Compose.Components; From f14d871f97375bdff5f1eada82facd6b5e8ea6f3 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Sun, 23 Oct 2022 01:32:22 +0900 Subject: [PATCH 1824/2686] let TaikoSpan show in timeline before placed --- .../Edit/Blueprints/TaikoSpanPlacementBlueprint.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs index 23a005190a..70364cabf1 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs @@ -52,6 +52,12 @@ namespace osu.Game.Rulesets.Taiko.Edit.Blueprints private double originalStartTime; private Vector2 originalPosition; + protected override void LoadComplete() + { + base.LoadComplete(); + BeginPlacement(); + } + protected override bool OnMouseDown(MouseDownEvent e) { if (e.Button != MouseButton.Left) From f4db2c1ff421588f3896f8e26bcb43da082179a7 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Sat, 22 Oct 2022 22:38:04 +0200 Subject: [PATCH 1825/2686] Add test --- .../TestSceneControlPointConversion.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs new file mode 100644 index 0000000000..e2ec41ce21 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.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 NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Objects; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Taiko.Tests +{ + public class TestSceneControlPointConversion : OsuTestScene + { + [Test] + public void TestSceneScrollSpeedConversion() + { + const double start_time = 1000; + const double slider_velocity = 10; + + var beatmap = new Beatmap + { + HitObjects = + { + new HitObject + { + StartTime = start_time, + DifficultyControlPoint = new DifficultyControlPoint { SliderVelocity = slider_velocity } + } + }, + BeatmapInfo = { Ruleset = { OnlineID = 0 } }, + }; + + var convertedBeatmap = new TaikoRuleset().CreateBeatmapConverter(beatmap).Convert(); + + AddAssert("effect point generated", () => convertedBeatmap.ControlPointInfo.EffectPointAt(start_time).ScrollSpeed == slider_velocity); + } + } +} From e8960ba53b25c33dae8822598180c3fb189397e8 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Sat, 22 Oct 2022 22:46:19 +0200 Subject: [PATCH 1826/2686] whitespace removal --- .../TestSceneControlPointConversion.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs index e2ec41ce21..72763421cc 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Taiko.Tests }; var convertedBeatmap = new TaikoRuleset().CreateBeatmapConverter(beatmap).Convert(); - + AddAssert("effect point generated", () => convertedBeatmap.ControlPointInfo.EffectPointAt(start_time).ScrollSpeed == slider_velocity); } } From a35026d537faf39e902a541f5b6ed284e507aba1 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Sat, 22 Oct 2022 23:29:44 +0200 Subject: [PATCH 1827/2686] Downgrade AutoMapper to fix Android startup crash --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index e0561d9b21..22474c0592 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -18,7 +18,7 @@ - + From 889c2978d7a95ea864c584db8bd61d81dc615f04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 Oct 2022 13:13:40 +0900 Subject: [PATCH 1828/2686] Fix point conversion not using invariant culture This was only the case in a fallback path (ie. when the user provides a `json` file with an old or computed format from an external source). Closes #20844. --- osu.Game.Tournament/JsonPointConverter.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/JsonPointConverter.cs b/osu.Game.Tournament/JsonPointConverter.cs index db48c36c99..d3b40a3526 100644 --- a/osu.Game.Tournament/JsonPointConverter.cs +++ b/osu.Game.Tournament/JsonPointConverter.cs @@ -6,6 +6,7 @@ using System; using System.Diagnostics; using System.Drawing; +using System.Globalization; using Newtonsoft.Json; namespace osu.Game.Tournament @@ -31,7 +32,9 @@ namespace osu.Game.Tournament Debug.Assert(str != null); - return new PointConverter().ConvertFromString(str) as Point? ?? new Point(); + // Null check suppression is required due to .NET standard expecting a non-null context. + // Seems to work fine at a runtime level (and the parameter is nullable in .NET 6+). + return new PointConverter().ConvertFromString(null!, CultureInfo.InvariantCulture, str) as Point? ?? new Point(); } var point = new Point(); From e9b3048a8bca903f35bf483a02a4972c64934fc1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 Oct 2022 13:58:00 +0900 Subject: [PATCH 1829/2686] Change the order of global bindings to give overlays lowest priority --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index ad53f6d90f..4a233e5bf3 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -31,14 +31,17 @@ namespace osu.Game.Input.Bindings parentInputManager = GetContainingInputManager(); } - // IMPORTANT: Do not change the order of key bindings in this list. - // It is used to decide the order of precedence (see note in DatabasedKeyBindingContainer). + // IMPORTANT: Take care when changing order of the items in the enumerable. + // It is used to decide the order of precedence, with the earlier items having higher precedence. public override IEnumerable DefaultKeyBindings => GlobalKeyBindings - .Concat(OverlayKeyBindings) .Concat(EditorKeyBindings) .Concat(InGameKeyBindings) .Concat(SongSelectKeyBindings) - .Concat(AudioControlKeyBindings); + .Concat(AudioControlKeyBindings) + // Overlay bindings may conflict with more local cases like the editor so they are checked last. + // It has generally been agreed on that local screens like the editor should have priority, + // based on such usages potentially requiring a lot more key bindings that may be "shared" with global ones. + .Concat(OverlayKeyBindings); public IEnumerable GlobalKeyBindings => new[] { From e72a71a28e9d25f0133592a8a24af3fe29fe3318 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 Oct 2022 13:58:11 +0900 Subject: [PATCH 1830/2686] Add simple editor "duplicate objects" key binding --- .../Input/Bindings/GlobalActionContainer.cs | 4 ++++ .../GlobalActionKeyBindingStrings.cs | 5 ++++ osu.Game/Screens/Edit/Editor.cs | 23 ++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 4a233e5bf3..476fda81b7 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -90,6 +90,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.F3 }, GlobalAction.EditorTimingMode), new KeyBinding(new[] { InputKey.F4 }, GlobalAction.EditorSetupMode), new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.A }, GlobalAction.EditorVerifyMode), + new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.EditorDuplicateSelection), new KeyBinding(new[] { InputKey.J }, GlobalAction.EditorNudgeLeft), new KeyBinding(new[] { InputKey.K }, GlobalAction.EditorNudgeRight), new KeyBinding(new[] { InputKey.G }, GlobalAction.EditorCycleGridDisplayMode), @@ -346,5 +347,8 @@ namespace osu.Game.Input.Bindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleProfile))] ToggleProfile, + + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorDuplicateSelection))] + EditorDuplicateSelection } } diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 172818c1c0..403fa8017a 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -184,6 +184,11 @@ namespace osu.Game.Localisation ///
public static LocalisableString EditorTapForBPM => new TranslatableString(getKey(@"editor_tap_for_bpm"), @"Tap for BPM"); + /// + /// "Duplicate selection" + /// + public static LocalisableString EditorDuplicateSelection => new TranslatableString(getKey(@"editor_duplicate_selection"), @"Duplicate selection"); + /// /// "Cycle grid display mode" /// diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 3dfc7010f3..51f2ca16c2 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -304,6 +304,7 @@ namespace osu.Game.Screens.Edit cutMenuItem = new EditorMenuItem("Cut", MenuItemType.Standard, Cut), copyMenuItem = new EditorMenuItem("Copy", MenuItemType.Standard, Copy), pasteMenuItem = new EditorMenuItem("Paste", MenuItemType.Standard, Paste), + duplicateMenuItem = new EditorMenuItem("Duplicate", MenuItemType.Standard, Duplicate), } }, new MenuItem("View") @@ -575,6 +576,10 @@ namespace osu.Game.Screens.Edit this.Exit(); return true; + case GlobalAction.EditorDuplicateSelection: + Duplicate(); + return true; + case GlobalAction.EditorComposeMode: Mode.Value = EditorScreenMode.Compose; return true; @@ -741,6 +746,7 @@ namespace osu.Game.Screens.Edit private EditorMenuItem cutMenuItem; private EditorMenuItem copyMenuItem; + private EditorMenuItem duplicateMenuItem; private EditorMenuItem pasteMenuItem; private readonly BindableWithCurrent canCut = new BindableWithCurrent(); @@ -750,7 +756,11 @@ namespace osu.Game.Screens.Edit private void setUpClipboardActionAvailability() { canCut.Current.BindValueChanged(cut => cutMenuItem.Action.Disabled = !cut.NewValue, true); - canCopy.Current.BindValueChanged(copy => copyMenuItem.Action.Disabled = !copy.NewValue, true); + canCopy.Current.BindValueChanged(copy => + { + copyMenuItem.Action.Disabled = !copy.NewValue; + duplicateMenuItem.Action.Disabled = !copy.NewValue; + }, true); canPaste.Current.BindValueChanged(paste => pasteMenuItem.Action.Disabled = !paste.NewValue, true); } @@ -765,6 +775,17 @@ namespace osu.Game.Screens.Edit protected void Copy() => currentScreen?.Copy(); + protected void Duplicate() + { + // This is an initial implementation just to get an idea of how people used this function. + // There are a couple of differences from osu!stable's implementation which will require more work to match: + // - The "clipboard" is not populated during the duplication process. + // - The duplicated hitobjects are inserted after the original pattern (add one beat_length and then quantize using beat snap). + // - The duplicated hitobjects are selected (but this is also applied for all paste operations so should be changed there). + Copy(); + Paste(); + } + protected void Paste() => currentScreen?.Paste(); #endregion From d0e6bda9ef52dbf0a53d4c9685cc8c7c35535ad5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 Oct 2022 15:19:36 +0900 Subject: [PATCH 1831/2686] Stop `HitObjectComposer` from handling `Shift`+`Number` keys --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 3bed835854..520fcb0290 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -238,7 +238,7 @@ namespace osu.Game.Rulesets.Edit protected override bool OnKeyDown(KeyDownEvent e) { - if (e.ControlPressed || e.AltPressed || e.SuperPressed) + if (e.ControlPressed || e.AltPressed || e.SuperPressed || e.ShiftPressed) return false; if (checkLeftToggleFromKey(e.Key, out int leftIndex)) From 1d5df150272056da2780dd6ab06ad8923da5e5ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 Oct 2022 15:20:15 +0900 Subject: [PATCH 1832/2686] Add ability to use `Shift`+`Number` to set current beat divisor in editor --- osu.Game/Screens/Edit/BindableBeatDivisor.cs | 20 ++++++++++++++++ .../Compose/Components/BeatDivisorControl.cs | 23 ++++++++++--------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Edit/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs index a7faf961cf..aa8e202e22 100644 --- a/osu.Game/Screens/Edit/BindableBeatDivisor.cs +++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs @@ -25,6 +25,26 @@ namespace osu.Game.Screens.Edit BindValueChanged(_ => ensureValidDivisor()); } + /// + /// Set a divisor, updating the valid divisor range appropriately. + /// + /// The intended divisor. + public void SetArbitraryDivisor(int divisor) + { + // If the current valid divisor range doesn't contain the proposed value, attempt to find one which does. + if (!ValidDivisors.Value.Presets.Contains(divisor)) + { + if (BeatDivisorPresetCollection.COMMON.Presets.Contains(divisor)) + ValidDivisors.Value = BeatDivisorPresetCollection.COMMON; + else if (BeatDivisorPresetCollection.TRIPLETS.Presets.Contains(divisor)) + ValidDivisors.Value = BeatDivisorPresetCollection.TRIPLETS; + else + ValidDivisors.Value = BeatDivisorPresetCollection.Custom(divisor); + } + + Value = divisor; + } + private void updateBindableProperties() { ensureValidDivisor(); diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 19ea2162a3..6dca799549 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -209,6 +209,17 @@ namespace osu.Game.Screens.Edit.Compose.Components } } + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.ShiftPressed && e.Key >= Key.Number1 && e.Key <= Key.Number9) + { + beatDivisor.SetArbitraryDivisor(e.Key - Key.Number0); + return true; + } + + return base.OnKeyDown(e); + } + internal class DivisorDisplay : OsuAnimatedButton, IHasPopover { public BindableBeatDivisor BeatDivisor { get; } = new BindableBeatDivisor(); @@ -306,17 +317,7 @@ namespace osu.Game.Screens.Edit.Compose.Components return; } - if (!BeatDivisor.ValidDivisors.Value.Presets.Contains(divisor)) - { - if (BeatDivisorPresetCollection.COMMON.Presets.Contains(divisor)) - BeatDivisor.ValidDivisors.Value = BeatDivisorPresetCollection.COMMON; - else if (BeatDivisorPresetCollection.TRIPLETS.Presets.Contains(divisor)) - BeatDivisor.ValidDivisors.Value = BeatDivisorPresetCollection.TRIPLETS; - else - BeatDivisor.ValidDivisors.Value = BeatDivisorPresetCollection.Custom(divisor); - } - - BeatDivisor.Value = divisor; + BeatDivisor.SetArbitraryDivisor(divisor); this.HidePopover(); } From f08270f6b06945f6f86655d36861ed7bf54aaef5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 Oct 2022 15:54:09 +0900 Subject: [PATCH 1833/2686] Fix incorrect `maxBaseScore` accounting due to silly oversight --- osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index ec98d00e68..f8b5085a70 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -191,7 +191,7 @@ namespace osu.Game.Tests.Visual.Gameplay void applyHitV2(int baseScore) { - maxBaseScore += baseScore; + maxBaseScore += base_great; currentBaseScore += baseScore; comboPortion += baseScore * (1 + ++currentCombo / 10.0); From 14704fd07cdaa6fe51482ceb56a29f7ae33c5a2d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 Oct 2022 16:08:49 +0900 Subject: [PATCH 1834/2686] Fix crash when exiting seeding editor too soon Closes https://github.com/ppy/osu/issues/20783. --- .../Screens/Editors/SeedingEditorScreen.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs index 1bc929604d..348661e2a3 100644 --- a/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs @@ -239,17 +239,17 @@ namespace osu.Game.Tournament.Screens.Editors var req = new GetBeatmapRequest(new APIBeatmap { OnlineID = Model.ID }); - req.Success += res => + req.Success += res => Schedule(() => { Model.Beatmap = new TournamentBeatmap(res); updatePanel(); - }; + }); - req.Failure += _ => + req.Failure += _ => Schedule(() => { Model.Beatmap = null; updatePanel(); - }; + }); API.Queue(req); }, true); From de881cc5cb44829ce9fdc1f468f28000869081bd Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Mon, 24 Oct 2022 23:17:28 +0900 Subject: [PATCH 1835/2686] useless #nullable disable --- osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs | 2 -- osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs | 2 -- osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs | 2 -- osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs | 2 -- 4 files changed, 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs index e14354222b..6af3ba908d 100644 --- a/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs +++ b/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.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. -#nullable disable - using System; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs index 8321fde171..20b8bba6da 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs index 1085f2c277..0a2c073dcd 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.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. -#nullable disable - using System; using osu.Game.Graphics.UserInterface; diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs index 6af3b99017..4e75a92e19 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItemSpacer.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. -#nullable disable - namespace osu.Game.Screens.Edit.Components.Menus { public class EditorMenuItemSpacer : EditorMenuItem From a2682b3ce39ddf9fc3e6c311206520c4e4d8472b Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Mon, 24 Oct 2022 23:18:34 +0900 Subject: [PATCH 1836/2686] background dim settings for editor View -> Background Dim follow `DimLevel` and `BlurLevel` Co-Authored-By: Dead_Bush_Sanpai --- osu.Game/Configuration/OsuConfigManager.cs | 2 ++ osu.Game/Screens/Edit/Editor.cs | 23 +++++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 1378e1691a..f8c851757e 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -122,6 +122,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1); SetDefault(OsuSetting.DimLevel, 0.7, 0, 1, 0.01); SetDefault(OsuSetting.BlurLevel, 0, 0, 1, 0.01); + SetDefault(OsuSetting.EditorUseDim, false); SetDefault(OsuSetting.LightenDuringBreaks, true); SetDefault(OsuSetting.HitLighting, true); @@ -292,6 +293,7 @@ namespace osu.Game.Configuration GameplayCursorDuringTouch, DimLevel, BlurLevel, + EditorUseDim, LightenDuringBreaks, ShowStoryboard, KeyOverlay, diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 3dfc7010f3..9cfd1badd1 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -176,6 +176,8 @@ namespace osu.Game.Screens.Edit [Resolved(canBeNull: true)] private OnScreenDisplay onScreenDisplay { get; set; } + private Bindable useUserDim; + public Editor(EditorLoader loader = null) { this.loader = loader; @@ -260,6 +262,9 @@ namespace osu.Game.Screens.Edit OsuMenuItem undoMenuItem; OsuMenuItem redoMenuItem; + TernaryStateRadioMenuItem backgroundDim; + useUserDim = config.GetBindable(OsuSetting.EditorUseDim); + AddInternal(new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, @@ -311,6 +316,7 @@ namespace osu.Game.Screens.Edit Items = new MenuItem[] { new WaveformOpacityMenuItem(config.GetBindable(OsuSetting.EditorWaveformOpacity)), + backgroundDim = new TernaryStateRadioMenuItem("Background Dim", MenuItemType.Standard, _ => useUserDim.Value = !useUserDim.Value), } } } @@ -330,6 +336,13 @@ namespace osu.Game.Screens.Edit changeHandler?.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true); changeHandler?.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true); + + useUserDim.BindValueChanged(s => + { + dimBackground(); + backgroundDim.State.Value = s.NewValue ? TernaryState.True : TernaryState.False; + }); + backgroundDim.State.Value = useUserDim.Value ? TernaryState.True : TernaryState.False; } [Resolved] @@ -626,9 +639,9 @@ namespace osu.Game.Screens.Edit ApplyToBackground(b => { // todo: temporary. we want to be applying dim using the UserDimContainer eventually. - b.FadeColour(Color4.DarkGray, 500); + if (!useUserDim.Value) b.FadeColour(Color4.DarkGray, 500); - b.IgnoreUserSettings.Value = true; + b.IgnoreUserSettings.Value = !useUserDim.Value; b.BlurAmount.Value = 0; }); } @@ -656,7 +669,11 @@ namespace osu.Game.Screens.Edit } } - ApplyToBackground(b => b.FadeColour(Color4.White, 500)); + ApplyToBackground(b => + { + b.FadeColour(Color4.White, 500); + b.IgnoreUserSettings.Value = true; + }); resetTrack(); refetchBeatmap(); From 9def12c60bceb6c75a92f74be14aafd1d10b8fe6 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Mon, 24 Oct 2022 22:50:56 +0300 Subject: [PATCH 1837/2686] Write new tests --- .../SongSelect/TestSceneBeatmapCarousel.cs | 103 ++++++++++-------- 1 file changed, 57 insertions(+), 46 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 0e72463d1e..303af61d20 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -827,6 +827,63 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle)); } + [Test] + public void TestCarouselSelectsNextWhenPreviousIsFiltered() + { + List sets = new List(); + + // 10 sets that go osu! -> taiko -> catch -> osu! -> ... + for (int i = 0; i < 10; i++) + { + var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 3); + sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { rulesetInfo })); + } + + // Sort mode is important to keep the ruleset order + loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title }); + setSelected(1, 1); + + for (int i = 1; i < 10; i++) + { + var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 3); + AddStep($"Set ruleset to {rulesetInfo.ShortName}", () => + { + carousel.Filter(new FilterCriteria { Ruleset = rulesetInfo, Sort = SortMode.Title }, false); + }); + waitForSelection(i + 1, 1); + } + } + + [Test] + public void TestCarouselSelectsBackwardsWhenDistanceIsShorter() + { + List sets = new List(); + + // 10 sets that go taiko, osu!, osu!, osu!, taiko, osu!, osu!, osu!, ... + for (int i = 0; i < 10; i++) + { + var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 4 == 0 ? 1 : 0); + sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { rulesetInfo })); + } + + // Sort mode is important to keep the ruleset order + loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title }); + + for (int i = 2; i < 10; i += 4) + { + setSelected(i, 1); + AddStep("Set ruleset to taiko", () => + { + carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(1), Sort = SortMode.Title }, false); + }); + waitForSelection(i - 1, 1); + AddStep("Remove ruleset filter", () => + { + carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false); + }); + } + } + [Test] public void TestCarouselRemembersSelection() { @@ -862,52 +919,6 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Selection was remembered", () => eagerSelectedIDs.Count == 1); } - [Test] - public void TestRandomFallbackOnNonMatchingPrevious() - { - List manySets = new List(); - - AddStep("populate maps", () => - { - manySets.Clear(); - - for (int i = 0; i < 10; i++) - { - manySets.Add(TestResources.CreateTestBeatmapSetInfo(3, new[] - { - // all taiko except for first - rulesets.GetRuleset(i > 0 ? 1 : 0) - })); - } - }); - - loadBeatmaps(manySets); - - for (int i = 0; i < 10; i++) - { - AddStep("Reset filter", () => carousel.Filter(new FilterCriteria(), false)); - - AddStep("select first beatmap", () => carousel.SelectBeatmap(manySets.First().Beatmaps.First())); - - AddStep("Toggle non-matching filter", () => - { - carousel.Filter(new FilterCriteria { SearchText = Guid.NewGuid().ToString() }, false); - }); - - AddAssert("selection lost", () => carousel.SelectedBeatmapInfo == null); - - AddStep("Restore different ruleset filter", () => - { - carousel.Filter(new FilterCriteria { Ruleset = rulesets.GetRuleset(1) }, false); - eagerSelectedIDs.Add(carousel.SelectedBeatmapSet!.ID); - }); - - AddAssert("selection changed", () => !carousel.SelectedBeatmapInfo!.Equals(manySets.First().Beatmaps.First())); - } - - AddAssert("Selection was random", () => eagerSelectedIDs.Count > 2); - } - [Test] public void TestFilteringByUserStarDifficulty() { From b95091fbb0a79bbb4d42a173c30354aabfb864a0 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Mon, 24 Oct 2022 22:55:09 +0300 Subject: [PATCH 1838/2686] Move test to improve diff readability --- .../SongSelect/TestSceneBeatmapCarousel.cs | 114 +++++++++--------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index 303af61d20..eacaf7f92e 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -827,63 +827,6 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("remove single ruleset set", () => carousel.RemoveBeatmapSet(testSingle)); } - [Test] - public void TestCarouselSelectsNextWhenPreviousIsFiltered() - { - List sets = new List(); - - // 10 sets that go osu! -> taiko -> catch -> osu! -> ... - for (int i = 0; i < 10; i++) - { - var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 3); - sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { rulesetInfo })); - } - - // Sort mode is important to keep the ruleset order - loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title }); - setSelected(1, 1); - - for (int i = 1; i < 10; i++) - { - var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 3); - AddStep($"Set ruleset to {rulesetInfo.ShortName}", () => - { - carousel.Filter(new FilterCriteria { Ruleset = rulesetInfo, Sort = SortMode.Title }, false); - }); - waitForSelection(i + 1, 1); - } - } - - [Test] - public void TestCarouselSelectsBackwardsWhenDistanceIsShorter() - { - List sets = new List(); - - // 10 sets that go taiko, osu!, osu!, osu!, taiko, osu!, osu!, osu!, ... - for (int i = 0; i < 10; i++) - { - var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 4 == 0 ? 1 : 0); - sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { rulesetInfo })); - } - - // Sort mode is important to keep the ruleset order - loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title }); - - for (int i = 2; i < 10; i += 4) - { - setSelected(i, 1); - AddStep("Set ruleset to taiko", () => - { - carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(1), Sort = SortMode.Title }, false); - }); - waitForSelection(i - 1, 1); - AddStep("Remove ruleset filter", () => - { - carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false); - }); - } - } - [Test] public void TestCarouselRemembersSelection() { @@ -966,6 +909,63 @@ namespace osu.Game.Tests.Visual.SongSelect checkVisibleItemCount(true, 15); } + [Test] + public void TestCarouselSelectsNextWhenPreviousIsFiltered() + { + List sets = new List(); + + // 10 sets that go osu! -> taiko -> catch -> osu! -> ... + for (int i = 0; i < 10; i++) + { + var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 3); + sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { rulesetInfo })); + } + + // Sort mode is important to keep the ruleset order + loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title }); + setSelected(1, 1); + + for (int i = 1; i < 10; i++) + { + var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 3); + AddStep($"Set ruleset to {rulesetInfo.ShortName}", () => + { + carousel.Filter(new FilterCriteria { Ruleset = rulesetInfo, Sort = SortMode.Title }, false); + }); + waitForSelection(i + 1, 1); + } + } + + [Test] + public void TestCarouselSelectsBackwardsWhenDistanceIsShorter() + { + List sets = new List(); + + // 10 sets that go taiko, osu!, osu!, osu!, taiko, osu!, osu!, osu!, ... + for (int i = 0; i < 10; i++) + { + var rulesetInfo = rulesets.AvailableRulesets.ElementAt(i % 4 == 0 ? 1 : 0); + sets.Add(TestResources.CreateTestBeatmapSetInfo(5, new[] { rulesetInfo })); + } + + // Sort mode is important to keep the ruleset order + loadBeatmaps(sets, () => new FilterCriteria { Sort = SortMode.Title }); + + for (int i = 2; i < 10; i += 4) + { + setSelected(i, 1); + AddStep("Set ruleset to taiko", () => + { + carousel.Filter(new FilterCriteria { Ruleset = rulesets.AvailableRulesets.ElementAt(1), Sort = SortMode.Title }, false); + }); + waitForSelection(i - 1, 1); + AddStep("Remove ruleset filter", () => + { + carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false); + }); + } + } + private void loadBeatmaps(List beatmapSets = null, Func initialCriteria = null, Action carouselAdjust = null, int? count = null, bool randomDifficulties = false) { From da74690ec9363c3be62d5a9a5e5c76b8f0f63033 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 11:38:58 +0900 Subject: [PATCH 1839/2686] Add test coverage of clone operations --- .../Editing/TestSceneEditorClipboard.cs | 31 +++++++++++++++++++ osu.Game/Tests/Visual/EditorTestScene.cs | 2 ++ 2 files changed, 33 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs index 23e137865c..9fa3b2db1a 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs @@ -155,6 +155,20 @@ namespace osu.Game.Tests.Visual.Editing AddUntilStep("composer selection box is visible", () => Editor.ChildrenOfType().First().ChildrenOfType().First().Alpha > 0); } + [Test] + public void TestClone() + { + var addedObject = new HitCircle { StartTime = 1000 }; + AddStep("add hitobject", () => EditorBeatmap.Add(addedObject)); + AddStep("select added object", () => EditorBeatmap.SelectedHitObjects.Add(addedObject)); + + AddAssert("is one object", () => EditorBeatmap.HitObjects.Count == 1); + AddStep("clone", () => Editor.Duplicate()); + AddAssert("is two objects", () => EditorBeatmap.HitObjects.Count == 2); + AddStep("clone", () => Editor.Duplicate()); + AddAssert("is three objects", () => EditorBeatmap.HitObjects.Count == 3); + } + [Test] public void TestCutNothing() { @@ -175,5 +189,22 @@ namespace osu.Game.Tests.Visual.Editing AddStep("paste hitobject", () => Editor.Paste()); AddAssert("are no objects", () => EditorBeatmap.HitObjects.Count == 0); } + + [Test] + public void TestCloneNothing() + { + // Add arbitrary object and copy to clipboard. + // This is tested to ensure that clone doesn't incorrectly read from the clipboard when no selection is made. + var addedObject = new HitCircle { StartTime = 1000 }; + AddStep("add hitobject", () => EditorBeatmap.Add(addedObject)); + AddStep("select added object", () => EditorBeatmap.SelectedHitObjects.Add(addedObject)); + AddStep("copy hitobject", () => Editor.Copy()); + + AddStep("deselect all objects", () => EditorBeatmap.SelectedHitObjects.Clear()); + + AddAssert("is one object", () => EditorBeatmap.HitObjects.Count == 1); + AddStep("clone", () => Editor.Duplicate()); + AddAssert("still one object", () => EditorBeatmap.HitObjects.Count == 1); + } } } diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index ced72aa593..0e24c5c47a 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -110,6 +110,8 @@ namespace osu.Game.Tests.Visual public new void Paste() => base.Paste(); + public new void Duplicate() => base.Duplicate(); + public new void SwitchToDifficulty(BeatmapInfo beatmapInfo) => base.SwitchToDifficulty(beatmapInfo); public new void CreateNewDifficulty(RulesetInfo rulesetInfo) => base.CreateNewDifficulty(rulesetInfo); From 1e579e06f8079e82f0694db8af6faa8ade586a08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 11:42:12 +0900 Subject: [PATCH 1840/2686] Fix duplicate working incorrectly if there is no selection currently made --- osu.Game/Screens/Edit/Editor.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 51f2ca16c2..cc551c3262 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -777,6 +777,10 @@ namespace osu.Game.Screens.Edit protected void Duplicate() { + // Avoid attempting to clone if copying is not available (as it may result in pasting something unexpected). + if (!canCopy.Value) + return; + // This is an initial implementation just to get an idea of how people used this function. // There are a couple of differences from osu!stable's implementation which will require more work to match: // - The "clipboard" is not populated during the duplication process. From 4d4f6e25bab755fe8de9d90909a3beec2a22590c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 11:43:23 +0900 Subject: [PATCH 1841/2686] Rename to "clone" instead of "duplicate" --- osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs | 6 +++--- osu.Game/Input/Bindings/GlobalActionContainer.cs | 6 +++--- osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 4 ++-- osu.Game/Screens/Edit/Editor.cs | 8 ++++---- osu.Game/Tests/Visual/EditorTestScene.cs | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs index 9fa3b2db1a..0a5a1febe4 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs @@ -163,9 +163,9 @@ namespace osu.Game.Tests.Visual.Editing AddStep("select added object", () => EditorBeatmap.SelectedHitObjects.Add(addedObject)); AddAssert("is one object", () => EditorBeatmap.HitObjects.Count == 1); - AddStep("clone", () => Editor.Duplicate()); + AddStep("clone", () => Editor.Clone()); AddAssert("is two objects", () => EditorBeatmap.HitObjects.Count == 2); - AddStep("clone", () => Editor.Duplicate()); + AddStep("clone", () => Editor.Clone()); AddAssert("is three objects", () => EditorBeatmap.HitObjects.Count == 3); } @@ -203,7 +203,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("deselect all objects", () => EditorBeatmap.SelectedHitObjects.Clear()); AddAssert("is one object", () => EditorBeatmap.HitObjects.Count == 1); - AddStep("clone", () => Editor.Duplicate()); + AddStep("clone", () => Editor.Clone()); AddAssert("still one object", () => EditorBeatmap.HitObjects.Count == 1); } } diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 476fda81b7..a58c6723ef 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -90,7 +90,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(new[] { InputKey.F3 }, GlobalAction.EditorTimingMode), new KeyBinding(new[] { InputKey.F4 }, GlobalAction.EditorSetupMode), new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.A }, GlobalAction.EditorVerifyMode), - new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.EditorDuplicateSelection), + new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.EditorCloneSelection), new KeyBinding(new[] { InputKey.J }, GlobalAction.EditorNudgeLeft), new KeyBinding(new[] { InputKey.K }, GlobalAction.EditorNudgeRight), new KeyBinding(new[] { InputKey.G }, GlobalAction.EditorCycleGridDisplayMode), @@ -348,7 +348,7 @@ namespace osu.Game.Input.Bindings [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.ToggleProfile))] ToggleProfile, - [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorDuplicateSelection))] - EditorDuplicateSelection + [LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorCloneSelection))] + EditorCloneSelection } } diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 403fa8017a..14e0bbbced 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -185,9 +185,9 @@ namespace osu.Game.Localisation public static LocalisableString EditorTapForBPM => new TranslatableString(getKey(@"editor_tap_for_bpm"), @"Tap for BPM"); /// - /// "Duplicate selection" + /// "Clone selection" /// - public static LocalisableString EditorDuplicateSelection => new TranslatableString(getKey(@"editor_duplicate_selection"), @"Duplicate selection"); + public static LocalisableString EditorCloneSelection => new TranslatableString(getKey(@"editor_clone_selection"), @"Clone selection"); /// /// "Cycle grid display mode" diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index cc551c3262..c2899bc1ec 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -304,7 +304,7 @@ namespace osu.Game.Screens.Edit cutMenuItem = new EditorMenuItem("Cut", MenuItemType.Standard, Cut), copyMenuItem = new EditorMenuItem("Copy", MenuItemType.Standard, Copy), pasteMenuItem = new EditorMenuItem("Paste", MenuItemType.Standard, Paste), - duplicateMenuItem = new EditorMenuItem("Duplicate", MenuItemType.Standard, Duplicate), + duplicateMenuItem = new EditorMenuItem("Clone", MenuItemType.Standard, Clone), } }, new MenuItem("View") @@ -576,8 +576,8 @@ namespace osu.Game.Screens.Edit this.Exit(); return true; - case GlobalAction.EditorDuplicateSelection: - Duplicate(); + case GlobalAction.EditorCloneSelection: + Clone(); return true; case GlobalAction.EditorComposeMode: @@ -775,7 +775,7 @@ namespace osu.Game.Screens.Edit protected void Copy() => currentScreen?.Copy(); - protected void Duplicate() + protected void Clone() { // Avoid attempting to clone if copying is not available (as it may result in pasting something unexpected). if (!canCopy.Value) diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 0e24c5c47a..0e7bb72162 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -110,7 +110,7 @@ namespace osu.Game.Tests.Visual public new void Paste() => base.Paste(); - public new void Duplicate() => base.Duplicate(); + public new void Clone() => base.Clone(); public new void SwitchToDifficulty(BeatmapInfo beatmapInfo) => base.SwitchToDifficulty(beatmapInfo); From 1b42f5ec6ec79ce7d73dcbd917fd33f5a518a21a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 11:51:31 +0900 Subject: [PATCH 1842/2686] Add test coverage of `BeatDivisorControl` key bindings --- .../Editing/TestSceneBeatDivisorControl.cs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs index ecd7732862..f2d27b9117 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs @@ -106,6 +106,49 @@ namespace osu.Game.Tests.Visual.Editing assertBeatSnap(16); } + [Test] + public void TestKeyboardNavigation() + { + pressKey(1); + assertBeatSnap(1); + assertPreset(BeatDivisorType.Common); + + pressKey(2); + assertBeatSnap(2); + assertPreset(BeatDivisorType.Common); + + pressKey(3); + assertBeatSnap(3); + assertPreset(BeatDivisorType.Triplets); + + pressKey(4); + assertBeatSnap(4); + assertPreset(BeatDivisorType.Common); + + pressKey(5); + assertBeatSnap(5); + assertPreset(BeatDivisorType.Custom, 5); + + pressKey(6); + assertBeatSnap(6); + assertPreset(BeatDivisorType.Triplets); + + pressKey(7); + assertBeatSnap(7); + assertPreset(BeatDivisorType.Custom, 7); + + pressKey(8); + assertBeatSnap(8); + assertPreset(BeatDivisorType.Common); + + void pressKey(int key) => AddStep($"press shift+{key}", () => + { + InputManager.PressKey(Key.ShiftLeft); + InputManager.Key(Key.Number0 + key); + InputManager.ReleaseKey(Key.ShiftLeft); + }); + } + [Test] public void TestBeatPresetNavigation() { From 8e4f5381e3cba926282ea72d52621cca6be6a52e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 12:03:46 +0900 Subject: [PATCH 1843/2686] Add top level test coverage of editor shortcuts --- .../Visual/Editing/TestSceneEditorBindings.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneEditorBindings.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBindings.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBindings.cs new file mode 100644 index 0000000000..5771d64775 --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBindings.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 NUnit.Framework; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Editing +{ + /// + /// Test editor hotkeys at a high level to ensure they all work well together. + /// + public class TestSceneEditorBindings : EditorTestScene + { + protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); + + [Test] + public void TestBeatDivisorChangeHotkeys() + { + AddStep("hold shift", () => InputManager.PressKey(Key.LShift)); + + AddStep("press 4", () => InputManager.Key(Key.Number4)); + AddAssert("snap updated to 4", () => EditorBeatmap.BeatmapInfo.BeatDivisor, () => Is.EqualTo(4)); + + AddStep("press 6", () => InputManager.Key(Key.Number6)); + AddAssert("snap updated to 6", () => EditorBeatmap.BeatmapInfo.BeatDivisor, () => Is.EqualTo(6)); + + AddStep("release shift", () => InputManager.ReleaseKey(Key.LShift)); + } + } +} From 2456a18bc1be49d23b3beb0e1ca2fed087f148d2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 12:48:17 +0900 Subject: [PATCH 1844/2686] Rewrite implementation to avoid duplicated LINQ returns --- .../Carousel/CarouselGroupEagerSelect.cs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs index 2c1ccebfab..a96d768ff9 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs @@ -115,26 +115,24 @@ namespace osu.Game.Screens.Select.Carousel protected virtual CarouselItem GetNextToSelect() { int forwardsIndex = lastSelectedIndex; + bool hasForwards; + int backwardsIndex = lastSelectedIndex; + bool hasBackwards; - while (true) + while ((hasBackwards = backwardsIndex >= 0) | (hasForwards = forwardsIndex < Items.Count)) { - // check if a direction has been exhausted and an item (or null) from the other direction should be returned - if (forwardsIndex >= Items.Count) - return Items.Reverse().Skip(Items.Count - backwardsIndex - 1).FirstOrDefault(item => !item.Filtered.Value); - if (backwardsIndex < 0) - return Items.Skip(forwardsIndex).FirstOrDefault(item => !item.Filtered.Value); - - // check if an unfiltered item has been reached - if (!Items[forwardsIndex].Filtered.Value) + if (hasForwards && !Items[forwardsIndex].Filtered.Value) return Items[forwardsIndex]; - if (!Items[backwardsIndex].Filtered.Value) + + if (hasBackwards && !Items[backwardsIndex].Filtered.Value) return Items[backwardsIndex]; - // increment the indices forwardsIndex++; backwardsIndex--; } + + return null; } protected virtual void PerformSelection() From f9c61904262f30b9f6297bcee9737cc13c691021 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Tue, 25 Oct 2022 13:00:53 +0900 Subject: [PATCH 1845/2686] Add DimAmount for UserDimContainer --- osu.Game/Graphics/Containers/UserDimContainer.cs | 5 ++++- osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs index d52fb7c60a..296855522b 100644 --- a/osu.Game/Graphics/Containers/UserDimContainer.cs +++ b/osu.Game/Graphics/Containers/UserDimContainer.cs @@ -48,13 +48,15 @@ namespace osu.Game.Graphics.Containers protected Bindable UserDimLevel { get; private set; } + public Bindable DimAmount { get; set; } = new Bindable(); + protected Bindable LightenDuringBreaks { get; private set; } protected Bindable ShowStoryboard { get; private set; } private float breakLightening => LightenDuringBreaks.Value && IsBreakTime.Value ? BREAK_LIGHTEN_AMOUNT : 0; - protected float DimLevel => Math.Max(!IgnoreUserSettings.Value ? (float)UserDimLevel.Value - breakLightening : 0, 0); + protected float DimLevel => Math.Max(!IgnoreUserSettings.Value ? (float)UserDimLevel.Value - breakLightening : DimAmount.Value, 0); protected override Container Content => dimContent; @@ -76,6 +78,7 @@ namespace osu.Game.Graphics.Containers ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); UserDimLevel.ValueChanged += _ => UpdateVisuals(); + DimAmount.ValueChanged += _ => UpdateVisuals(); LightenDuringBreaks.ValueChanged += _ => UpdateVisuals(); IsBreakTime.ValueChanged += _ => UpdateVisuals(); ShowStoryboard.ValueChanged += _ => UpdateVisuals(); diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs index ca05c8af46..053bcf2387 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs @@ -43,6 +43,8 @@ namespace osu.Game.Screens.Backgrounds /// public readonly Bindable BlurAmount = new BindableFloat(); + public readonly Bindable DimAmount = new Bindable(); + internal readonly IBindable IsBreakTime = new Bindable(); private readonly DimmableBackground dimmable; @@ -58,6 +60,7 @@ namespace osu.Game.Screens.Backgrounds dimmable.IgnoreUserSettings.BindTo(IgnoreUserSettings); dimmable.IsBreakTime.BindTo(IsBreakTime); dimmable.BlurAmount.BindTo(BlurAmount); + dimmable.DimAmount.BindTo(DimAmount); StoryboardReplacesBackground.BindTo(dimmable.StoryboardReplacesBackground); } From 3d72ff28c3e09b1e1be93917ceaf2957e34d1adc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 13:25:38 +0900 Subject: [PATCH 1846/2686] Add test scene for "Freeze Frame" mod --- .../Mods/TestSceneOsuModFreezeFrame.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs new file mode 100644 index 0000000000..7d7b2d9071 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.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 NUnit.Framework; +using osu.Game.Rulesets.Osu.Mods; + +namespace osu.Game.Rulesets.Osu.Tests.Mods +{ + public class TestSceneOsuModFreezeFrame : OsuModTestScene + { + [Test] + public void TestFreezeFrame() + { + CreateModTest(new ModTestData + { + Mod = new OsuModFreezeFrame(), + PassCondition = () => true, + Autoplay = false, + }); + } + } +} From 588fc750cdeac7b2b915506f62eb168adb960687 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 13:26:32 +0900 Subject: [PATCH 1847/2686] Change approach circles to all appear at the same time, but don't adjust AR --- .../Mods/OsuModFreezeFrame.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 8bf2c89057..2187d33a49 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -29,12 +29,17 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Fun; //mod breaks normal approach circle preempt - private double approachCircleTimePreempt; + private double originalPreempt; public void ApplyToBeatmap(IBeatmap beatmap) { + var firstHitObject = beatmap.HitObjects.OfType().FirstOrDefault(); + if (firstHitObject == null) + return; + double lastNewComboTime = 0; - approachCircleTimePreempt = beatmap.HitObjects.OfType().FirstOrDefault()!.TimePreempt; + + originalPreempt = firstHitObject.TimePreempt; foreach (var obj in beatmap.HitObjects.OfType()) { @@ -72,17 +77,12 @@ namespace osu.Game.Rulesets.Osu.Mods var hitCircle = drawableHitCircle.HitObject; var approachCircle = drawableHitCircle.ApproachCircle; - approachCircle.ClearTransforms(); - approachCircle.ScaleTo(4); - approachCircle.FadeTo(0); + // Reapply scale, ensuring the AR isn't changes due to the new preempt. + approachCircle.ClearTransforms(targetMember: nameof(approachCircle.Scale)); + approachCircle.ScaleTo(4 * (float)(hitCircle.TimePreempt / originalPreempt)); - using (drawableHitCircle.ApproachCircle.BeginAbsoluteSequence(hitCircle.StartTime - approachCircleTimePreempt)) - { - //Redo ApproachCircle animation with correct startTime. - approachCircle.LifetimeStart = hitCircle.StartTime - approachCircleTimePreempt; - approachCircle.FadeTo(1, Math.Min(hitCircle.TimeFadeIn * 2, hitCircle.TimePreempt)); - approachCircle.ScaleTo(1, approachCircleTimePreempt).Then().Expire(); - } + using (drawableHitCircle.ApproachCircle.BeginAbsoluteSequence(hitCircle.StartTime - hitCircle.TimePreempt)) + approachCircle.ScaleTo(1, hitCircle.TimePreempt).Then().Expire(); }; } } From 279ef556e3c4eb818d40d837809739cf7a8eb8ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 13:27:26 +0900 Subject: [PATCH 1848/2686] Fix typon in comment --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 2187d33a49..20d75ab019 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Mods var hitCircle = drawableHitCircle.HitObject; var approachCircle = drawableHitCircle.ApproachCircle; - // Reapply scale, ensuring the AR isn't changes due to the new preempt. + // Reapply scale, ensuring the AR isn't changed due to the new preempt. approachCircle.ClearTransforms(targetMember: nameof(approachCircle.Scale)); approachCircle.ScaleTo(4 * (float)(hitCircle.TimePreempt / originalPreempt)); From 22ea9a8ab4f2d4c07820935f3c3dc823c8c1b65b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 13:34:21 +0900 Subject: [PATCH 1849/2686] Add early return of carousel group has no items --- osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs index a96d768ff9..6a53f8f527 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs @@ -114,6 +114,9 @@ namespace osu.Game.Screens.Select.Carousel /// An unfiltered item nearest to the last selected one or null if all items are filtered protected virtual CarouselItem GetNextToSelect() { + if (Items.Count == 0) + return null; + int forwardsIndex = lastSelectedIndex; bool hasForwards; From 02a3f8c17fb14bdd2c699c20a1416d0563aec045 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 14:09:22 +0900 Subject: [PATCH 1850/2686] Allow both distance snap and grid snap to be applied at the same time --- .../Edit/OsuHitObjectComposer.cs | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 6b4a6e39d9..67061bdaf2 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -80,19 +80,7 @@ namespace osu.Game.Rulesets.Osu.Edit placementObject = EditorBeatmap.PlacementObject.GetBoundCopy(); placementObject.ValueChanged += _ => updateDistanceSnapGrid(); - distanceSnapToggle.ValueChanged += _ => - { - updateDistanceSnapGrid(); - - if (distanceSnapToggle.Value == TernaryState.True) - rectangularGridSnapToggle.Value = TernaryState.False; - }; - - rectangularGridSnapToggle.ValueChanged += _ => - { - if (rectangularGridSnapToggle.Value == TernaryState.True) - distanceSnapToggle.Value = TernaryState.False; - }; + distanceSnapToggle.ValueChanged += _ => updateDistanceSnapGrid(); // we may be entering the screen with a selection already active updateDistanceSnapGrid(); @@ -134,22 +122,27 @@ namespace osu.Game.Rulesets.Osu.Edit if (snapType.HasFlagFast(SnapType.NearbyObjects) && snapToVisibleBlueprints(screenSpacePosition, out var snapResult)) return snapResult; + SnapResult result = base.FindSnappedPositionAndTime(screenSpacePosition, snapType); + if (snapType.HasFlagFast(SnapType.Grids)) { if (distanceSnapToggle.Value == TernaryState.True && distanceSnapGrid != null) { (Vector2 pos, double time) = distanceSnapGrid.GetSnappedPosition(distanceSnapGrid.ToLocalSpace(screenSpacePosition)); - return new SnapResult(distanceSnapGrid.ToScreenSpace(pos), time, PlayfieldAtScreenSpacePosition(screenSpacePosition)); + + result.ScreenSpacePosition = distanceSnapGrid.ToScreenSpace(pos); + result.Time = time; } if (rectangularGridSnapToggle.Value == TernaryState.True) { - Vector2 pos = rectangularPositionSnapGrid.GetSnappedPosition(rectangularPositionSnapGrid.ToLocalSpace(screenSpacePosition)); - return new SnapResult(rectangularPositionSnapGrid.ToScreenSpace(pos), null, PlayfieldAtScreenSpacePosition(screenSpacePosition)); + Vector2 pos = rectangularPositionSnapGrid.GetSnappedPosition(rectangularPositionSnapGrid.ToLocalSpace(result.ScreenSpacePosition)); + + result.ScreenSpacePosition = rectangularPositionSnapGrid.ToScreenSpace(pos); } } - return base.FindSnappedPositionAndTime(screenSpacePosition, snapType); + return result; } private bool snapToVisibleBlueprints(Vector2 screenSpacePosition, out SnapResult snapResult) From 2f0283e4d4b6d547a2c7a04387a514a115142988 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 14:22:28 +0900 Subject: [PATCH 1851/2686] Simplify logic with new multi-grid snap support --- .../Edit/CatchHitObjectComposer.cs | 21 +++------- .../Edit/OsuHitObjectComposer.cs | 42 ++++++------------- 2 files changed, 18 insertions(+), 45 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 27235bd62e..9ba17c89ff 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -103,25 +103,16 @@ namespace osu.Game.Rulesets.Catch.Edit base.OnKeyUp(e); } - private TernaryState? distanceSnapBeforeMomentary; + private bool distanceSnapMomentary; private void handleToggleViaKey(KeyboardEvent key) { - if (key.AltPressed) + bool altPressed = key.AltPressed; + + if (altPressed != distanceSnapMomentary) { - if (distanceSnapBeforeMomentary == null) - { - distanceSnapBeforeMomentary = distanceSnapToggle.Value; - distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; - } - } - else - { - if (distanceSnapBeforeMomentary != null) - { - distanceSnapToggle.Value = distanceSnapBeforeMomentary.Value; - distanceSnapBeforeMomentary = null; - } + distanceSnapMomentary = altPressed; + distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; } } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 838f18bad5..bf7cddd099 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -247,43 +247,25 @@ namespace osu.Game.Rulesets.Osu.Edit return base.AdjustDistanceSpacing(action, amount); } - private TernaryState? gridSnapBeforeMomentary; - private TernaryState? distanceSnapBeforeMomentary; + private bool distanceSnapMomentary; + private bool gridSnapMomentary; private void handleToggleViaKey(KeyboardEvent key) { - if (key.ShiftPressed) + bool altPressed = key.AltPressed; + + if (altPressed != distanceSnapMomentary) { - if (distanceSnapBeforeMomentary == null && gridSnapBeforeMomentary == null) - { - gridSnapBeforeMomentary = rectangularGridSnapToggle.Value; - rectangularGridSnapToggle.Value = rectangularGridSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; - } - } - else - { - if (gridSnapBeforeMomentary != null) - { - rectangularGridSnapToggle.Value = gridSnapBeforeMomentary.Value; - gridSnapBeforeMomentary = null; - } + distanceSnapMomentary = altPressed; + distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; } - if (key.AltPressed) + bool shiftPressed = key.ShiftPressed; + + if (shiftPressed != gridSnapMomentary) { - if (gridSnapBeforeMomentary == null && distanceSnapBeforeMomentary == null) - { - distanceSnapBeforeMomentary = distanceSnapToggle.Value; - distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; - } - } - else - { - if (distanceSnapBeforeMomentary != null) - { - distanceSnapToggle.Value = distanceSnapBeforeMomentary.Value; - distanceSnapBeforeMomentary = null; - } + gridSnapMomentary = shiftPressed; + rectangularGridSnapToggle.Value = rectangularGridSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; } } From a9755295e44445e25c5aeebec212f5baa83b89df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 14:32:08 +0900 Subject: [PATCH 1852/2686] Update tests in line with new behaviour --- .../Editor/TestSceneOsuEditorGrids.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs index 1e73885540..479687c496 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs @@ -20,20 +20,27 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); [Test] - public void TestGridExclusivity() + public void TestGridToggles() { AddStep("enable distance snap grid", () => InputManager.Key(Key.T)); AddStep("select second object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.ElementAt(1))); + AddUntilStep("distance snap grid visible", () => this.ChildrenOfType().Any()); rectangularGridActive(false); AddStep("enable rectangular grid", () => InputManager.Key(Key.Y)); - AddUntilStep("distance snap grid hidden", () => !this.ChildrenOfType().Any()); + + AddStep("select second object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.ElementAt(1))); + AddUntilStep("distance snap grid still visible", () => this.ChildrenOfType().Any()); rectangularGridActive(true); - AddStep("enable distance snap grid", () => InputManager.Key(Key.T)); + AddStep("disable distance snap grid", () => InputManager.Key(Key.T)); + AddUntilStep("distance snap grid hidden", () => !this.ChildrenOfType().Any()); AddStep("select second object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.ElementAt(1))); - AddUntilStep("distance snap grid visible", () => this.ChildrenOfType().Any()); + rectangularGridActive(true); + + AddStep("disable rectangular grid", () => InputManager.Key(Key.Y)); + AddUntilStep("distance snap grid still hidden", () => !this.ChildrenOfType().Any()); rectangularGridActive(false); } From 16ef0b09e8a86eb33b0bce3ca2a230ab24c840bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 14:36:35 +0900 Subject: [PATCH 1853/2686] Add test coverage of momentary toggles --- .../Editor/TestSceneOsuEditorGrids.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs index 479687c496..f6d3512fe6 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs @@ -44,6 +44,28 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor rectangularGridActive(false); } + [Test] + public void TestDistanceSnapMomentaryToggle() + { + AddStep("select second object", () => EditorBeatmap.SelectedHitObjects.Add(EditorBeatmap.HitObjects.ElementAt(1))); + + AddUntilStep("distance snap grid hidden", () => !this.ChildrenOfType().Any()); + AddStep("hold alt", () => InputManager.PressKey(Key.AltLeft)); + AddUntilStep("distance snap grid visible", () => this.ChildrenOfType().Any()); + AddStep("release alt", () => InputManager.ReleaseKey(Key.AltLeft)); + AddUntilStep("distance snap grid hidden", () => !this.ChildrenOfType().Any()); + } + + [Test] + public void TestGridSnapMomentaryToggle() + { + rectangularGridActive(false); + AddStep("hold shift", () => InputManager.PressKey(Key.ShiftLeft)); + rectangularGridActive(true); + AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft)); + rectangularGridActive(false); + } + private void rectangularGridActive(bool active) { AddStep("choose placement tool", () => InputManager.Key(Key.Number2)); From da93849b8084b7bc0fb057704ee1a7a1606bf82f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 14:55:33 +0900 Subject: [PATCH 1854/2686] Rename some pieces and better document `SampleBankInfo` --- .../Objects/Legacy/ConvertHitObjectParser.cs | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index b289299a63..930ee0448f 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -199,8 +199,8 @@ namespace osu.Game.Rulesets.Objects.Legacy if (stringAddBank == @"none") stringAddBank = null; - bankInfo.Normal = stringBank; - bankInfo.Add = string.IsNullOrEmpty(stringAddBank) ? stringBank : stringAddBank; + bankInfo.BankForNormal = stringBank; + bankInfo.BankForAdditions = string.IsNullOrEmpty(stringAddBank) ? stringBank : stringAddBank; if (split.Length > 2) bankInfo.CustomSampleBank = Parsing.ParseInt(split[2]); @@ -447,32 +447,54 @@ namespace osu.Game.Rulesets.Objects.Legacy var soundTypes = new List { - new LegacyHitSampleInfo(HitSampleInfo.HIT_NORMAL, bankInfo.Normal, bankInfo.Volume, bankInfo.CustomSampleBank, + new LegacyHitSampleInfo(HitSampleInfo.HIT_NORMAL, bankInfo.BankForNormal, bankInfo.Volume, bankInfo.CustomSampleBank, // if the sound type doesn't have the Normal flag set, attach it anyway as a layered sample. // None also counts as a normal non-layered sample: https://osu.ppy.sh/help/wiki/osu!_File_Formats/Osu_(file_format)#hitsounds type != LegacyHitSoundType.None && !type.HasFlagFast(LegacyHitSoundType.Normal)) }; if (type.HasFlagFast(LegacyHitSoundType.Finish)) - soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_FINISH, bankInfo.Add, bankInfo.Volume, bankInfo.CustomSampleBank)); + soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_FINISH, bankInfo.BankForAdditions, bankInfo.Volume, bankInfo.CustomSampleBank)); if (type.HasFlagFast(LegacyHitSoundType.Whistle)) - soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_WHISTLE, bankInfo.Add, bankInfo.Volume, bankInfo.CustomSampleBank)); + soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_WHISTLE, bankInfo.BankForAdditions, bankInfo.Volume, bankInfo.CustomSampleBank)); if (type.HasFlagFast(LegacyHitSoundType.Clap)) - soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_CLAP, bankInfo.Add, bankInfo.Volume, bankInfo.CustomSampleBank)); + soundTypes.Add(new LegacyHitSampleInfo(HitSampleInfo.HIT_CLAP, bankInfo.BankForAdditions, bankInfo.Volume, bankInfo.CustomSampleBank)); return soundTypes; } private class SampleBankInfo { + /// + /// An optional overriding filename which causes all bank/sample specifications to be ignored. + /// public string Filename; - public string Normal; - public string Add; + /// + /// The bank identifier to use for the base ("hitnormal") sample. + /// Transferred to when appropriate. + /// + public string BankForNormal; + + /// + /// The bank identifier to use for additions ("hitwhistle", "hitfinish", "hitclap"). + /// Transferred to when appropriate. + /// + public string BankForAdditions; + + /// + /// Hit sample volume (0-100). + /// See . + /// public int Volume; + /// + /// The index of the custom sample bank. Is only used if 2 or above for "reasons". + /// This will add a suffix to lookups, allowing extended bank lookups (ie. "normal-hitnormal-2"). + /// See . + /// public int CustomSampleBank; public SampleBankInfo Clone() => (SampleBankInfo)MemberwiseClone(); @@ -503,7 +525,8 @@ namespace osu.Game.Rulesets.Objects.Legacy public sealed override HitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newSuffix = default, Optional newVolume = default) => With(newName, newBank, newVolume); - public virtual LegacyHitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newVolume = default, Optional newCustomSampleBank = default, + public virtual LegacyHitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newVolume = default, + Optional newCustomSampleBank = default, Optional newIsLayered = default) => new LegacyHitSampleInfo(newName.GetOr(Name), newBank.GetOr(Bank), newVolume.GetOr(Volume), newCustomSampleBank.GetOr(CustomSampleBank), newIsLayered.GetOr(IsLayered)); @@ -537,7 +560,8 @@ namespace osu.Game.Rulesets.Objects.Legacy Path.ChangeExtension(Filename, null) }; - public sealed override LegacyHitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newVolume = default, Optional newCustomSampleBank = default, + public sealed override LegacyHitSampleInfo With(Optional newName = default, Optional newBank = default, Optional newVolume = default, + Optional newCustomSampleBank = default, Optional newIsLayered = default) => new FileHitSampleInfo(Filename, newVolume.GetOr(Volume)); From f4aae9138bf98ec4475ce14d709dae20be4ca001 Mon Sep 17 00:00:00 2001 From: "D.Headley" Date: Tue, 25 Oct 2022 08:48:45 +0200 Subject: [PATCH 1855/2686] Remove Incompatibility with HD --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index 20d75ab019..bea5d4f5d9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override LocalisableString Description => "Burn the notes into your memory."; //Alters the transforms of the approach circles, breaking the effects of these mods. - public override Type[] IncompatibleMods => new[] { typeof(OsuModApproachDifferent), typeof(OsuModHidden) }; + public override Type[] IncompatibleMods => new[] { typeof(OsuModApproachDifferent) }; public override ModType Type => ModType.Fun; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs index 2d7c0c82de..996ee1cddb 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHidden.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override LocalisableString Description => @"Play with no approach circles and fading circles/sliders."; public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.06 : 1; - public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSpinIn), typeof(OsuModFreezeFrame) }; + public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSpinIn) }; public const double FADE_IN_DURATION_MULTIPLIER = 0.4; public const double FADE_OUT_DURATION_MULTIPLIER = 0.3; From cf3bf41b4902f754d64344bda326928190dd3ff7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 25 Oct 2022 18:57:15 +0900 Subject: [PATCH 1856/2686] Harden and simplify logic to avoid weird issues --- .../Select/Carousel/CarouselGroupEagerSelect.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs index 6a53f8f527..34865c7f51 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs @@ -118,13 +118,16 @@ namespace osu.Game.Screens.Select.Carousel return null; int forwardsIndex = lastSelectedIndex; - bool hasForwards; - int backwardsIndex = lastSelectedIndex; - bool hasBackwards; - while ((hasBackwards = backwardsIndex >= 0) | (hasForwards = forwardsIndex < Items.Count)) + while (true) { + bool hasBackwards = backwardsIndex >= 0 && backwardsIndex < Items.Count; + bool hasForwards = forwardsIndex < Items.Count; + + if (!hasBackwards && !hasForwards) + return null; + if (hasForwards && !Items[forwardsIndex].Filtered.Value) return Items[forwardsIndex]; @@ -134,8 +137,6 @@ namespace osu.Game.Screens.Select.Carousel forwardsIndex++; backwardsIndex--; } - - return null; } protected virtual void PerformSelection() From 92ab39f5c2d94c34964b7c22894f3914c7aa8311 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 25 Oct 2022 19:16:23 +0900 Subject: [PATCH 1857/2686] Fix hold note disappear instantly --- osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 48647f9f5f..14dbc432ff 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -69,6 +69,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables ///
private double? releaseTime; + public override double MaximumJudgementOffset => Tail.MaximumJudgementOffset; + public DrawableHoldNote() : this(null) { @@ -260,7 +262,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables tick.MissForcefully(); } - ApplyResult(r => r.Type = r.Judgement.MaxResult); + ApplyResult(r => r.Type = Tail.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult); endHold(); } From 0b8b3223222d4cfe3311e65707bd5fe3d59ad7d5 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 25 Oct 2022 19:48:33 +0900 Subject: [PATCH 1858/2686] Fix tests --- osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs | 2 +- osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs index 8f776ff507..0296303867 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mania.Tests assertHeadJudgement(HitResult.Miss); assertTickJudgement(HitResult.LargeTickMiss); assertTailJudgement(HitResult.Miss); - assertNoteJudgement(HitResult.IgnoreHit); + assertNoteJudgement(HitResult.IgnoreMiss); } /// diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs index 1f139b5b78..464dbecee5 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs @@ -76,8 +76,8 @@ namespace osu.Game.Rulesets.Mania.Tests performTest(objects, new List()); - addJudgementAssert(objects[0], HitResult.IgnoreHit); - addJudgementAssert(objects[1], HitResult.IgnoreHit); + addJudgementAssert(objects[0], HitResult.IgnoreMiss); + addJudgementAssert(objects[1], HitResult.IgnoreMiss); } [Test] From 242f80b8b31a670032048d305469302aa7afd123 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Tue, 25 Oct 2022 15:49:14 +0200 Subject: [PATCH 1859/2686] Set scrollspeed directly at beatmap decode --- .../TestSceneControlPointConversion.cs | 38 ------------------- .../Beatmaps/TaikoBeatmapConverter.cs | 23 ----------- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 7 +--- 3 files changed, 1 insertion(+), 67 deletions(-) delete mode 100644 osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs deleted file mode 100644 index 72763421cc..0000000000 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneControlPointConversion.cs +++ /dev/null @@ -1,38 +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 NUnit.Framework; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Objects; -using osu.Game.Tests.Visual; - -namespace osu.Game.Rulesets.Taiko.Tests -{ - public class TestSceneControlPointConversion : OsuTestScene - { - [Test] - public void TestSceneScrollSpeedConversion() - { - const double start_time = 1000; - const double slider_velocity = 10; - - var beatmap = new Beatmap - { - HitObjects = - { - new HitObject - { - StartTime = start_time, - DifficultyControlPoint = new DifficultyControlPoint { SliderVelocity = slider_velocity } - } - }, - BeatmapInfo = { Ruleset = { OnlineID = 0 } }, - }; - - var convertedBeatmap = new TaikoRuleset().CreateBeatmapConverter(beatmap).Convert(); - - AddAssert("effect point generated", () => convertedBeatmap.ControlPointInfo.EffectPointAt(start_time).ScrollSpeed == slider_velocity); - } - } -} diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index c1e1052569..524565a863 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -57,29 +57,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps Beatmap converted = base.ConvertBeatmap(original, cancellationToken); - if (original.BeatmapInfo.Ruleset.OnlineID == 0) - { - // Post processing step to transform standard slider velocity changes into scroll speed changes - double lastScrollSpeed = 1; - - foreach (HitObject hitObject in original.HitObjects) - { - double nextScrollSpeed = hitObject.DifficultyControlPoint.SliderVelocity; - - if (!Precision.AlmostEquals(lastScrollSpeed, nextScrollSpeed)) - { - EffectControlPoint currentControlPoint = converted.ControlPointInfo.EffectPointAt(hitObject.StartTime); - - if (Precision.AlmostEquals(currentControlPoint.Time, hitObject.StartTime)) - currentControlPoint.ScrollSpeed = nextScrollSpeed; - else - converted.ControlPointInfo.Add(hitObject.StartTime, new EffectControlPoint { ScrollSpeed = nextScrollSpeed }); - - lastScrollSpeed = nextScrollSpeed; - } - } - } - if (original.BeatmapInfo.Ruleset.OnlineID == 3) { // Post processing step to transform mania hit objects with the same start time into strong hits diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 75500fbc4e..2d9320d9c4 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -438,14 +438,9 @@ namespace osu.Game.Beatmaps.Formats { KiaiMode = kiaiMode, OmitFirstBarLine = omitFirstBarSignature, + ScrollSpeed = speedMultiplier, }; - int onlineRulesetID = beatmap.BeatmapInfo.Ruleset.OnlineID; - - // osu!taiko and osu!mania use effect points rather than difficulty points for scroll speed adjustments. - if (onlineRulesetID == 1 || onlineRulesetID == 3) - effectPoint.ScrollSpeed = speedMultiplier; - addControlPoint(time, effectPoint, timingChange); addControlPoint(time, new LegacySampleControlPoint From aae5359b2e5e33cb37404dda1e580a3ee77691b1 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Tue, 25 Oct 2022 17:47:51 +0200 Subject: [PATCH 1860/2686] Update Tests --- .../Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 2 +- osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index fdd0167ed3..d9bbe7a51e 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -175,7 +175,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(4, controlPoints.TimingPoints.Count); Assert.AreEqual(5, controlPoints.DifficultyPoints.Count); Assert.AreEqual(34, controlPoints.SamplePoints.Count); - Assert.AreEqual(8, controlPoints.EffectPoints.Count); + Assert.AreEqual(13, controlPoints.EffectPoints.Count); var timingPoint = controlPoints.TimingPointAt(0); Assert.AreEqual(956, timingPoint.Time); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs index 03c184c27d..e93382cc9b 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs @@ -67,8 +67,8 @@ namespace osu.Game.Tests.Visual.Editing InputManager.Click(MouseButton.Left); }); - AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 54670); - AddUntilStep("Ensure seeked to correct time", () => EditorClock.CurrentTimeAccurate == 54670); + AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 37560); + AddUntilStep("Ensure seeked to correct time", () => EditorClock.CurrentTimeAccurate == 37560); AddStep("Seek to just before next point", () => EditorClock.Seek(69000)); AddStep("Start clock", () => EditorClock.Start()); @@ -85,8 +85,8 @@ namespace osu.Game.Tests.Visual.Editing InputManager.Click(MouseButton.Left); }); - AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 54670); - AddUntilStep("Ensure seeked to correct time", () => EditorClock.CurrentTimeAccurate == 54670); + AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 37560); + AddUntilStep("Ensure seeked to correct time", () => EditorClock.CurrentTimeAccurate == 37560); AddStep("Seek to later", () => EditorClock.Seek(80000)); AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 69670); From d2b0a413da43e15ea6964fa6650a15ec89d068a7 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Tue, 25 Oct 2022 18:18:25 +0200 Subject: [PATCH 1861/2686] Always encode scroll speed as slider velocity in the legacy encoder --- osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 03c63ff4f2..c9ee63424c 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -185,19 +185,12 @@ namespace osu.Game.Beatmaps.Formats SampleControlPoint lastRelevantSamplePoint = null; DifficultyControlPoint lastRelevantDifficultyPoint = null; - // In osu!taiko and osu!mania, a scroll speed is stored as "slider velocity" in legacy formats. - // In that case, a scrolling speed change is a global effect and per-hit object difficulty control points are ignored. - bool scrollSpeedEncodedAsSliderVelocity = onlineRulesetID == 1 || onlineRulesetID == 3; - // iterate over hitobjects and pull out all required sample and difficulty changes extractDifficultyControlPoints(beatmap.HitObjects); extractSampleControlPoints(beatmap.HitObjects); - if (scrollSpeedEncodedAsSliderVelocity) - { - foreach (var point in legacyControlPoints.EffectPoints) - legacyControlPoints.Add(point.Time, new DifficultyControlPoint { SliderVelocity = point.ScrollSpeed }); - } + foreach (var point in legacyControlPoints.EffectPoints) + legacyControlPoints.Add(point.Time, new DifficultyControlPoint { SliderVelocity = point.ScrollSpeed }); foreach (var group in legacyControlPoints.Groups) { @@ -244,9 +237,6 @@ namespace osu.Game.Beatmaps.Formats IEnumerable collectDifficultyControlPoints(IEnumerable hitObjects) { - if (scrollSpeedEncodedAsSliderVelocity) - yield break; - foreach (var hitObject in hitObjects) yield return hitObject.DifficultyControlPoint; } From 93e9b4a2c5329a46668b6f4261680abfb763a7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 25 Oct 2022 19:53:05 +0200 Subject: [PATCH 1862/2686] Add failing test case --- .../Mods/TestSceneTaikoModFlashlight.cs | 36 +++++++++++++++++++ .../Mods/TaikoModFlashlight.cs | 8 ++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs index 417b59f5d2..d55ce17e6c 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs @@ -1,8 +1,12 @@ // 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 NUnit.Framework; +using osu.Framework.Testing; using osu.Game.Rulesets.Taiko.Mods; +using osu.Game.Rulesets.Taiko.UI; +using osuTK; namespace osu.Game.Rulesets.Taiko.Tests.Mods { @@ -16,5 +20,37 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods [Test] public void TestComboBasedSize([Values] bool comboBasedSize) => CreateModTest(new ModTestData { Mod = new TaikoModFlashlight { ComboBasedSize = { Value = comboBasedSize } }, PassCondition = () => true }); + + [Test] + public void TestFlashlightAlwaysHasNonZeroSize() + { + bool failed = false; + + CreateModTest(new ModTestData + { + Mod = new TestTaikoModFlashlight { ComboBasedSize = { Value = true } }, + Autoplay = false, + PassCondition = () => + { + failed |= this.ChildrenOfType().SingleOrDefault()?.FlashlightSize.Y == 0; + return !failed; + } + }); + } + + private class TestTaikoModFlashlight : TaikoModFlashlight + { + protected override Flashlight CreateFlashlight() => new TestTaikoFlashlight(this, Playfield); + + public class TestTaikoFlashlight : TaikoFlashlight + { + public TestTaikoFlashlight(TaikoModFlashlight modFlashlight, TaikoPlayfield taikoPlayfield) + : base(modFlashlight, taikoPlayfield) + { + } + + public new Vector2 FlashlightSize => base.FlashlightSize; + } + } } } diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 98f954ad29..d5b0b64036 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -27,17 +27,17 @@ namespace osu.Game.Rulesets.Taiko.Mods public override float DefaultFlashlightSize => 200; - protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, playfield); + protected override Flashlight CreateFlashlight() => new TaikoFlashlight(this, Playfield); - private TaikoPlayfield playfield = null!; + protected TaikoPlayfield Playfield { get; private set; } = null!; public override void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - playfield = (TaikoPlayfield)drawableRuleset.Playfield; + Playfield = (TaikoPlayfield)drawableRuleset.Playfield; base.ApplyToDrawableRuleset(drawableRuleset); } - private class TaikoFlashlight : Flashlight + public class TaikoFlashlight : Flashlight { private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.RequiredParentSizeToFit | Invalidation.DrawInfo); private readonly TaikoPlayfield taikoPlayfield; From e3bc1126d75e204b08a85059b6f818c4c292d60d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 25 Oct 2022 20:03:22 +0200 Subject: [PATCH 1863/2686] Fix invalid flashlight size calculation This regressed in #20714. One usage of `getSizeFor(0)` was replaced by `adjustSize(GetSize())`, but another usage of `getSizeFor(Combo.Value)` was replaced by `adjustSize(Combo.Value)`, which is not correct, since `adjustSize()` is expecting to receive a combo-based size, rather than a combo value directly. --- osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index d5b0b64036..2b3dc799ab 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Taiko.Mods FlashlightPosition = ToLocalSpace(taikoPlayfield.HitTarget.ScreenSpaceDrawQuad.Centre); ClearTransforms(targetMember: nameof(FlashlightSize)); - FlashlightSize = adjustSize(Combo.Value); + FlashlightSize = adjustSize(GetSize()); flashlightProperties.Validate(); } From 974f22dd97a4f79fc9709a5431c2f1ecae73549f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 25 Oct 2022 20:11:29 +0200 Subject: [PATCH 1864/2686] Attempt to make flashlight code slightly more legible --- .../Mods/TaikoModFlashlight.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 2b3dc799ab..46569c2495 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -47,21 +47,28 @@ namespace osu.Game.Rulesets.Taiko.Mods { this.taikoPlayfield = taikoPlayfield; - FlashlightSize = adjustSize(GetSize()); + FlashlightSize = adjustSizeForPlayfieldAspectRatio(GetSize()); FlashlightSmoothness = 1.4f; AddLayout(flashlightProperties); } - private Vector2 adjustSize(float size) + /// + /// Returns the aspect ratio-adjusted size of the flashlight. + /// This ensures that the size of the flashlight remains independent of taiko-specific aspect ratio adjustments. + /// + /// + /// The size of the flashlight. + /// The value provided here should always come from . + /// + private Vector2 adjustSizeForPlayfieldAspectRatio(float size) { - // Preserve flashlight size through the playfield's aspect adjustment. return new Vector2(0, size * taikoPlayfield.DrawHeight / TaikoPlayfield.DEFAULT_HEIGHT); } protected override void UpdateFlashlightSize(float size) { - this.TransformTo(nameof(FlashlightSize), adjustSize(size), FLASHLIGHT_FADE_DURATION); + this.TransformTo(nameof(FlashlightSize), adjustSizeForPlayfieldAspectRatio(size), FLASHLIGHT_FADE_DURATION); } protected override string FragmentShader => "CircularFlashlight"; @@ -75,7 +82,7 @@ namespace osu.Game.Rulesets.Taiko.Mods FlashlightPosition = ToLocalSpace(taikoPlayfield.HitTarget.ScreenSpaceDrawQuad.Centre); ClearTransforms(targetMember: nameof(FlashlightSize)); - FlashlightSize = adjustSize(GetSize()); + FlashlightSize = adjustSizeForPlayfieldAspectRatio(GetSize()); flashlightProperties.Validate(); } From f5ca447b8e289712a9ffe8c6ff164f2d36aa87e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 25 Oct 2022 21:34:41 +0200 Subject: [PATCH 1865/2686] Rename one more "{duplicate -> clone}" reference --- osu.Game/Screens/Edit/Editor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index c2899bc1ec..912681e114 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -304,7 +304,7 @@ namespace osu.Game.Screens.Edit cutMenuItem = new EditorMenuItem("Cut", MenuItemType.Standard, Cut), copyMenuItem = new EditorMenuItem("Copy", MenuItemType.Standard, Copy), pasteMenuItem = new EditorMenuItem("Paste", MenuItemType.Standard, Paste), - duplicateMenuItem = new EditorMenuItem("Clone", MenuItemType.Standard, Clone), + cloneMenuItem = new EditorMenuItem("Clone", MenuItemType.Standard, Clone), } }, new MenuItem("View") @@ -746,7 +746,7 @@ namespace osu.Game.Screens.Edit private EditorMenuItem cutMenuItem; private EditorMenuItem copyMenuItem; - private EditorMenuItem duplicateMenuItem; + private EditorMenuItem cloneMenuItem; private EditorMenuItem pasteMenuItem; private readonly BindableWithCurrent canCut = new BindableWithCurrent(); @@ -759,7 +759,7 @@ namespace osu.Game.Screens.Edit canCopy.Current.BindValueChanged(copy => { copyMenuItem.Action.Disabled = !copy.NewValue; - duplicateMenuItem.Action.Disabled = !copy.NewValue; + cloneMenuItem.Action.Disabled = !copy.NewValue; }, true); canPaste.Current.BindValueChanged(paste => pasteMenuItem.Action.Disabled = !paste.NewValue, true); } From 8505848b1a0efaf3682a7b703b94f95f95d902c2 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 25 Oct 2022 18:06:49 -0700 Subject: [PATCH 1866/2686] Scroll beatmap listing to top when searching via tags/source --- osu.Game/Overlays/BeatmapListingOverlay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 2be328427b..c73936da8a 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -115,6 +115,7 @@ namespace osu.Game.Overlays { filterControl.Search(query); Show(); + ScrollFlow.ScrollToStart(); } protected override BeatmapListingHeader CreateHeader() => new BeatmapListingHeader(); From d9d083752aeac9d1342084f63d6495d5a0e78a8b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 11:03:11 +0900 Subject: [PATCH 1867/2686] Clamp backwards index to total current items to fix edge case of item removal --- osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs index 34865c7f51..6366fc8050 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselGroupEagerSelect.cs @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Select.Carousel return null; int forwardsIndex = lastSelectedIndex; - int backwardsIndex = lastSelectedIndex; + int backwardsIndex = Math.Min(lastSelectedIndex, Items.Count - 1); while (true) { From cbcebfa130f342f3900b86542e72ed8c2098a287 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 12:18:54 +0900 Subject: [PATCH 1868/2686] Remove switch back to selection tool to simplify test flow --- osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs index f6d3512fe6..f9cea5761b 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs @@ -79,8 +79,6 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddAssert("placement blueprint at (0, 0)", () => Precision.AlmostEquals(Editor.ChildrenOfType().Single().HitObject.Position, new Vector2(0, 0))); else AddAssert("placement blueprint at (1, 1)", () => Precision.AlmostEquals(Editor.ChildrenOfType().Single().HitObject.Position, new Vector2(1, 1))); - - AddStep("choose selection tool", () => InputManager.Key(Key.Number1)); } [Test] From 5f10b81af1dfaf0f717858961780538a1fc2498d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 12:55:59 +0900 Subject: [PATCH 1869/2686] Move distance snap grid test cursor behind grid to better visualise centre-points --- .../Editor/TestSceneOsuDistanceSnapGrid.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs index dc74d38cdc..f880739950 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs @@ -88,8 +88,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor RelativeSizeAxes = Axes.Both, Colour = Color4.SlateGray }, + new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }, grid = new OsuDistanceSnapGrid(new HitCircle { Position = grid_position }), - new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position } }; }); @@ -166,8 +166,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor RelativeSizeAxes = Axes.Both, Colour = Color4.SlateGray }, + new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }, grid = new OsuDistanceSnapGrid(new HitCircle { Position = grid_position }, new HitCircle { StartTime = 200 }), - new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position } }; }); From cab9a1c01203236748b6a72077dec351286d5d34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 13:08:19 +0900 Subject: [PATCH 1870/2686] Add test coverage of distance snap grid failing visually --- .../Editor/TestSceneOsuDistanceSnapGrid.cs | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs index f880739950..1b67fc2ca9 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs @@ -4,12 +4,15 @@ #nullable disable using System; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Overlays; @@ -52,6 +55,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor }; private OsuDistanceSnapGrid grid; + private SnappingCursorContainer cursor; public TestSceneOsuDistanceSnapGrid() { @@ -88,7 +92,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor RelativeSizeAxes = Axes.Both, Colour = Color4.SlateGray }, - new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }, + cursor = new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }, grid = new OsuDistanceSnapGrid(new HitCircle { Position = grid_position }), }; }); @@ -154,6 +158,37 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor assertSnappedDistance(expectedDistance); } + [Test] + public void TestReferenceObjectNotOnSnapGrid() + { + AddStep("create grid", () => + { + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.SlateGray + }, + cursor = new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }, + grid = new OsuDistanceSnapGrid(new HitCircle + { + Position = grid_position, + // This is important. It sets the reference object to a point in time that isn't on the current snap divisor's grid. + // We are testing that the grid's display is offset correctly. + StartTime = 40, + }), + }; + }); + + AddStep("move mouse to point", () => InputManager.MoveMouseTo(grid.ToScreenSpace(grid_position + new Vector2(beat_length, 0) * 2))); + + AddAssert("Ensure cursor is on a grid line", () => + { + return grid.ChildrenOfType().Any(p => Precision.AlmostEquals(p.ScreenSpaceDrawQuad.TopRight.X, grid.ToScreenSpace(cursor.LastSnappedPosition).X)); + }); + } + [Test] public void TestLimitedDistance() { @@ -166,7 +201,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor RelativeSizeAxes = Axes.Both, Colour = Color4.SlateGray }, - new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }, + cursor = new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnappedPosition(grid.ToLocalSpace(v)).position }, grid = new OsuDistanceSnapGrid(new HitCircle { Position = grid_position }, new HitCircle { StartTime = 200 }), }; }); @@ -186,6 +221,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor { public Func GetSnapPosition; + public Vector2 LastSnappedPosition { get; private set; } + private readonly Drawable cursor; private InputManager inputManager; @@ -214,7 +251,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor protected override void Update() { base.Update(); - cursor.Position = GetSnapPosition.Invoke(inputManager.CurrentState.Mouse.Position); + cursor.Position = LastSnappedPosition = GetSnapPosition.Invoke(inputManager.CurrentState.Mouse.Position); } } } From 2016d330553bc1dc4ebbe3135011e71454590b8e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 13:10:39 +0900 Subject: [PATCH 1871/2686] Offset start of distance snap grid drawing if reference object's start time doesn't align Closes #20938. --- .../Edit/Compose/Components/CircularDistanceSnapGrid.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs index 98079116cd..6e54e98740 100644 --- a/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs @@ -53,9 +53,16 @@ namespace osu.Game.Screens.Edit.Compose.Components float maxDistance = new Vector2(dx, dy).Length; int requiredCircles = Math.Min(MaxIntervals, (int)(maxDistance / DistanceBetweenTicks)); + // We need to offset the drawn lines to the next valid snap for the currently selected divisor. + // + // Picture the scenario where the user has just placed an object on a 1/2 snap, then changes to + // 1/3 snap and expects to be able to place the next object on a valid 1/3 snap, regardless of the + // fact that the 1/2 snap reference object is not valid for 1/3 snapping. + float offset = SnapProvider.FindSnappedDistance(ReferenceObject, 0); + for (int i = 0; i < requiredCircles; i++) { - float diameter = (i + 1) * DistanceBetweenTicks * 2; + float diameter = (offset + (i + 1) * DistanceBetweenTicks) * 2; AddInternal(new Ring(ReferenceObject, GetColourForIndexFromPlacement(i)) { From 8d9a85e9e588b1cc964ecc6514ed1d105b713c10 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 13:14:12 +0900 Subject: [PATCH 1872/2686] Fix typos in xmldoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Rulesets/Edit/ExpandableButton.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Edit/ExpandableButton.cs b/osu.Game/Rulesets/Edit/ExpandableButton.cs index 5b60a2536d..a66600bd58 100644 --- a/osu.Game/Rulesets/Edit/ExpandableButton.cs +++ b/osu.Game/Rulesets/Edit/ExpandableButton.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Edit private LocalisableString contractedLabelText; /// - /// The label text to display when this slider is in a contracted state. + /// The label text to display when this button is in a contracted state. /// public LocalisableString ContractedLabelText { @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Edit private LocalisableString expandedLabelText; /// - /// The label text to display when this slider is in an expanded state. + /// The label text to display when this button is in an expanded state. /// public LocalisableString ExpandedLabelText { From 54ae16badc5eeeb5c5f63cc59a3b3a48832da203 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 13:27:23 +0900 Subject: [PATCH 1873/2686] Move distance snap toggle button implementation to `DistancedHitObjectComposer` --- .../Edit/CatchHitObjectComposer.cs | 39 +------------------ .../Edit/OsuHitObjectComposer.cs | 19 ++------- .../Edit/DistancedHitObjectComposer.cs | 39 +++++++++++++++++++ 3 files changed, 44 insertions(+), 53 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 9ba17c89ff..721ef64dc0 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -10,7 +10,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; using osu.Framework.Input; using osu.Framework.Input.Events; using osu.Game.Beatmaps; @@ -23,7 +22,6 @@ using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; -using osu.Game.Screens.Edit.Components.TernaryButtons; using osu.Game.Screens.Edit.Compose.Components; using osuTK; @@ -35,8 +33,6 @@ namespace osu.Game.Rulesets.Catch.Edit private CatchDistanceSnapGrid distanceSnapGrid; - private readonly Bindable distanceSnapToggle = new Bindable(); - private InputManager inputManager; private readonly BindableDouble timeRangeMultiplier = new BindableDouble(1) @@ -88,34 +84,6 @@ namespace osu.Game.Rulesets.Catch.Edit updateDistanceSnapGrid(); } - protected override bool OnKeyDown(KeyDownEvent e) - { - if (e.Repeat) - return false; - - handleToggleViaKey(e); - return base.OnKeyDown(e); - } - - protected override void OnKeyUp(KeyUpEvent e) - { - handleToggleViaKey(e); - base.OnKeyUp(e); - } - - private bool distanceSnapMomentary; - - private void handleToggleViaKey(KeyboardEvent key) - { - bool altPressed = key.AltPressed; - - if (altPressed != distanceSnapMomentary) - { - distanceSnapMomentary = altPressed; - distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; - } - } - public override bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) @@ -148,11 +116,6 @@ namespace osu.Game.Rulesets.Catch.Edit new BananaShowerCompositionTool() }; - protected override IEnumerable CreateTernaryButtons() => base.CreateTernaryButtons().Concat(new[] - { - new TernaryButton(distanceSnapToggle, "Distance Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Ruler }) - }); - public override SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition, SnapType snapType = SnapType.All) { var result = base.FindSnappedPositionAndTime(screenSpacePosition, snapType); @@ -224,7 +187,7 @@ namespace osu.Game.Rulesets.Catch.Edit private void updateDistanceSnapGrid() { - if (distanceSnapToggle.Value != TernaryState.True) + if (DistanceSnapToggle.Value != TernaryState.True) { distanceSnapGrid.Hide(); return; diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index bf7cddd099..a543cb62fa 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -46,12 +46,10 @@ namespace osu.Game.Rulesets.Osu.Edit new SpinnerCompositionTool() }; - private readonly Bindable distanceSnapToggle = new Bindable(); private readonly Bindable rectangularGridSnapToggle = new Bindable(); protected override IEnumerable CreateTernaryButtons() => base.CreateTernaryButtons().Concat(new[] { - new TernaryButton(distanceSnapToggle, "Distance Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Ruler }), new TernaryButton(rectangularGridSnapToggle, "Grid Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Th }) }); @@ -82,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.Edit placementObject = EditorBeatmap.PlacementObject.GetBoundCopy(); placementObject.ValueChanged += _ => updateDistanceSnapGrid(); - distanceSnapToggle.ValueChanged += _ => updateDistanceSnapGrid(); + DistanceSnapToggle.ValueChanged += _ => updateDistanceSnapGrid(); // we may be entering the screen with a selection already active updateDistanceSnapGrid(); @@ -128,7 +126,7 @@ namespace osu.Game.Rulesets.Osu.Edit if (snapType.HasFlagFast(SnapType.Grids)) { - if (distanceSnapToggle.Value == TernaryState.True && distanceSnapGrid != null) + if (DistanceSnapToggle.Value == TernaryState.True && distanceSnapGrid != null) { (Vector2 pos, double time) = distanceSnapGrid.GetSnappedPosition(distanceSnapGrid.ToLocalSpace(screenSpacePosition)); @@ -197,7 +195,7 @@ namespace osu.Game.Rulesets.Osu.Edit distanceSnapGridCache.Invalidate(); distanceSnapGrid = null; - if (distanceSnapToggle.Value != TernaryState.True) + if (DistanceSnapToggle.Value != TernaryState.True) return; switch (BlueprintContainer.CurrentTool) @@ -242,24 +240,15 @@ namespace osu.Game.Rulesets.Osu.Edit protected override bool AdjustDistanceSpacing(GlobalAction action, float amount) { // To allow better visualisation, ensure that the spacing grid is visible before adjusting. - distanceSnapToggle.Value = TernaryState.True; + DistanceSnapToggle.Value = TernaryState.True; return base.AdjustDistanceSpacing(action, amount); } - private bool distanceSnapMomentary; private bool gridSnapMomentary; private void handleToggleViaKey(KeyboardEvent key) { - bool altPressed = key.AltPressed; - - if (altPressed != distanceSnapMomentary) - { - distanceSnapMomentary = altPressed; - distanceSnapToggle.Value = distanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; - } - bool shiftPressed = key.ShiftPressed; if (shiftPressed != gridSnapMomentary) diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index 449996131d..cd7c25509c 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -3,6 +3,8 @@ #nullable disable +using System.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -10,6 +12,7 @@ using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Localisation; @@ -20,6 +23,7 @@ using osu.Game.Overlays; using osu.Game.Overlays.OSD; using osu.Game.Overlays.Settings.Sections; using osu.Game.Rulesets.Objects; +using osu.Game.Screens.Edit.Components.TernaryButtons; namespace osu.Game.Rulesets.Edit { @@ -48,6 +52,10 @@ namespace osu.Game.Rulesets.Edit [Resolved(canBeNull: true)] private OnScreenDisplay onScreenDisplay { get; set; } + protected readonly Bindable DistanceSnapToggle = new Bindable(); + + private bool distanceSnapMomentary; + protected DistancedHitObjectComposer(Ruleset ruleset) : base(ruleset) { @@ -105,6 +113,37 @@ namespace osu.Game.Rulesets.Edit } } + protected override IEnumerable CreateTernaryButtons() => base.CreateTernaryButtons().Concat(new[] + { + new TernaryButton(DistanceSnapToggle, "Distance Snap", () => new SpriteIcon { Icon = FontAwesome.Solid.Ruler }) + }); + + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.Repeat) + return false; + + handleToggleViaKey(e); + return base.OnKeyDown(e); + } + + protected override void OnKeyUp(KeyUpEvent e) + { + handleToggleViaKey(e); + base.OnKeyUp(e); + } + + private void handleToggleViaKey(KeyboardEvent key) + { + bool altPressed = key.AltPressed; + + if (altPressed != distanceSnapMomentary) + { + distanceSnapMomentary = altPressed; + DistanceSnapToggle.Value = DistanceSnapToggle.Value == TernaryState.False ? TernaryState.True : TernaryState.False; + } + } + public virtual bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) From 6b53ea3400511e74b8c108189f0014a73eaa4f63 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 13:37:01 +0900 Subject: [PATCH 1874/2686] Enable distance snapping when DS value is changed via user interaction --- .../Rulesets/Edit/DistancedHitObjectComposer.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index ab320af902..ca7ca79813 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -89,8 +89,9 @@ namespace osu.Game.Rulesets.Edit { distanceSpacingSlider = new ExpandableSlider> { - Current = { BindTarget = DistanceSpacingMultiplier }, KeyboardStep = adjust_step, + // Manual binding in LoadComplete to handle one-way event flow. + Current = DistanceSpacingMultiplier.GetUnboundCopy(), }, currentDistanceSpacingButton = new ExpandableButton { @@ -101,6 +102,7 @@ namespace osu.Game.Rulesets.Edit Debug.Assert(objects != null); DistanceSpacingMultiplier.Value = ReadCurrentDistanceSnap(objects.Value.before, objects.Value.after); + DistanceSnapToggle.Value = TernaryState.True; }, RelativeSizeAxes = Axes.X, } @@ -173,6 +175,14 @@ namespace osu.Game.Rulesets.Edit EditorBeatmap.BeatmapInfo.DistanceSpacing = multiplier.NewValue; }, true); + + // Manual binding to handle enabling distance spacing when the slider is interacted with. + distanceSpacingSlider.Current.BindValueChanged(spacing => + { + DistanceSpacingMultiplier.Value = spacing.NewValue; + DistanceSnapToggle.Value = TernaryState.True; + }); + DistanceSpacingMultiplier.BindValueChanged(spacing => distanceSpacingSlider.Current.Value = spacing.NewValue); } } @@ -245,6 +255,7 @@ namespace osu.Game.Rulesets.Edit else if (action == GlobalAction.EditorDecreaseDistanceSpacing) DistanceSpacingMultiplier.Value -= amount; + DistanceSnapToggle.Value = TernaryState.True; return true; } From f8a4af5e0e400067471fb0a301cf945fcdaba023 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 13:45:06 +0900 Subject: [PATCH 1875/2686] Add osu!catch read-distance-spacing implementation --- .../Edit/CatchHitObjectComposer.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 004919e807..220bc49203 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -79,8 +80,15 @@ namespace osu.Game.Rulesets.Catch.Edit protected override double ReadCurrentDistanceSnap(HitObject before, HitObject after) { - // TODO: catch lol - return 1; + // osu!catch's distance snap implementation is limited, in that a custom spacing cannot be specified. + // Therefore this functionality is not currently used. + // + // The implementation below is probably correct but should be checked if/when exposed via controls. + + float expectedDistance = DurationToDistance(before, after.StartTime - before.GetEndTime()); + float actualDistance = Math.Abs(((CatchHitObject)before).EffectiveX - ((CatchHitObject)after).EffectiveX); + + return actualDistance / expectedDistance; } protected override void Update() From d03161ec013ad0a1b670aad474158c3349e85352 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 14:39:39 +0900 Subject: [PATCH 1876/2686] Apply distance snap time component even when nearby object snap kicks in --- .../Edit/OsuHitObjectComposer.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 67061bdaf2..f9a952c2fb 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -13,6 +13,7 @@ using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; @@ -120,7 +121,24 @@ namespace osu.Game.Rulesets.Osu.Edit public override SnapResult FindSnappedPositionAndTime(Vector2 screenSpacePosition, SnapType snapType = SnapType.All) { if (snapType.HasFlagFast(SnapType.NearbyObjects) && snapToVisibleBlueprints(screenSpacePosition, out var snapResult)) + { + // In the case of snapping to nearby objects, a time value is not provided. + // This matches the stable editor (which also uses current time), but with the introduction of time-snapping distance snap + // this could result in unexpected behaviour when distance snapping is turned on an a user attempts to place an object that is + // BOTH on a valid distance snap ring, and also at the same position as a previous object. + // + // We want to ensure that in this particular case, the time-snapping component of distance snap is still applied. + // The easiest way to ensure this is to attempt application of distance snap after a nearby object is found, and copy over + // the time value if the proposed positions are roughly the same. + if (snapType.HasFlagFast(SnapType.Grids) && distanceSnapToggle.Value == TernaryState.True && distanceSnapGrid != null) + { + (Vector2 distanceSnappedPosition, double distanceSnappedTime) = distanceSnapGrid.GetSnappedPosition(distanceSnapGrid.ToLocalSpace(snapResult.ScreenSpacePosition)); + if (Precision.AlmostEquals(distanceSnapGrid.ToScreenSpace(distanceSnappedPosition), snapResult.ScreenSpacePosition, 1)) + snapResult.Time = distanceSnappedTime; + } + return snapResult; + } SnapResult result = base.FindSnappedPositionAndTime(screenSpacePosition, snapType); From 6991195d69b6a444ec4aad8b5e915fc105ce6d99 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Tue, 25 Oct 2022 13:01:24 +0900 Subject: [PATCH 1877/2686] let editor dim different from gameplay dim --- .../Editing/TestSceneEditorTestGameplay.cs | 15 ++++-- osu.Game/Configuration/OsuConfigManager.cs | 4 +- .../Screens/Edit/BackgroundDimMenuItem.cs | 46 +++++++++++++++++++ osu.Game/Screens/Edit/Editor.cs | 25 ++++------ 4 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 osu.Game/Screens/Edit/BackgroundDimMenuItem.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs index a5d115331d..9722c60cba 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs @@ -7,10 +7,12 @@ using System; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -21,7 +23,6 @@ using osu.Game.Screens.Edit.GameplayTest; using osu.Game.Screens.Play; using osu.Game.Storyboards; using osu.Game.Tests.Beatmaps.IO; -using osuTK.Graphics; using osuTK.Input; namespace osu.Game.Tests.Visual.Editing @@ -40,6 +41,14 @@ namespace osu.Game.Tests.Visual.Editing private BeatmapSetInfo importedBeatmapSet; + private Bindable editorDim; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + editorDim = config.GetBindable(OsuSetting.EditorDim); + } + public override void SetUpSteps() { AddStep("import test beatmap", () => importedBeatmapSet = BeatmapImportHelper.LoadOszIntoOsu(game).GetResultSafely()); @@ -77,7 +86,7 @@ namespace osu.Game.Tests.Visual.Editing // this test cares about checking the background belonging to the editor specifically, so check that using reference equality // (as `.Equals()` cannot discern between the two, as they technically share the same database GUID). var background = this.ChildrenOfType().Single(b => ReferenceEquals(b.Beatmap.BeatmapInfo, EditorBeatmap.BeatmapInfo)); - return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0; + return background.DimAmount.Value == editorDim.Value && background.BlurAmount.Value == 0; }); AddAssert("no mods selected", () => SelectedMods.Value.Count == 0); } @@ -110,7 +119,7 @@ namespace osu.Game.Tests.Visual.Editing // this test cares about checking the background belonging to the editor specifically, so check that using reference equality // (as `.Equals()` cannot discern between the two, as they technically share the same database GUID). var background = this.ChildrenOfType().Single(b => ReferenceEquals(b.Beatmap.BeatmapInfo, EditorBeatmap.BeatmapInfo)); - return background.Colour == Color4.DarkGray && background.BlurAmount.Value == 0; + return background.DimAmount.Value == editorDim.Value && background.BlurAmount.Value == 0; }); AddStep("start track", () => EditorClock.Start()); diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index f8c851757e..30299eb062 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -122,7 +122,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1); SetDefault(OsuSetting.DimLevel, 0.7, 0, 1, 0.01); SetDefault(OsuSetting.BlurLevel, 0, 0, 1, 0.01); - SetDefault(OsuSetting.EditorUseDim, false); + SetDefault(OsuSetting.EditorDim, 0.25f); SetDefault(OsuSetting.LightenDuringBreaks, true); SetDefault(OsuSetting.HitLighting, true); @@ -293,7 +293,7 @@ namespace osu.Game.Configuration GameplayCursorDuringTouch, DimLevel, BlurLevel, - EditorUseDim, + EditorDim, LightenDuringBreaks, ShowStoryboard, KeyOverlay, diff --git a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs new file mode 100644 index 0000000000..b8644ed690 --- /dev/null +++ b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs @@ -0,0 +1,46 @@ +// 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 osu.Framework.Bindables; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Edit +{ + internal class BackgroundDimMenuItem : MenuItem + { + private readonly Bindable backgroudDim; + + private readonly Dictionary menuItemLookup = new Dictionary(); + + public BackgroundDimMenuItem(Bindable backgroudDim) + : base("Background dim") + { + Items = new[] + { + createMenuItem(0f), + createMenuItem(0.25f), + createMenuItem(0.5f), + createMenuItem(0.75f), + createMenuItem(1f), + }; + + this.backgroudDim = backgroudDim; + backgroudDim.BindValueChanged(dim => + { + foreach (var kvp in menuItemLookup) + kvp.Value.State.Value = kvp.Key == dim.NewValue ? TernaryState.True : TernaryState.False; + }, true); + } + + private TernaryStateRadioMenuItem createMenuItem(float dim) + { + var item = new TernaryStateRadioMenuItem($"{dim * 100}%", MenuItemType.Standard, _ => updateOpacity(dim)); + menuItemLookup[dim] = item; + return item; + } + + private void updateOpacity(float dim) => backgroudDim.Value = dim; + } +} diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 9cfd1badd1..3c91d302ae 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -51,7 +51,6 @@ using osu.Game.Screens.Edit.Timing; using osu.Game.Screens.Edit.Verify; using osu.Game.Screens.Play; using osu.Game.Users; -using osuTK.Graphics; using osuTK.Input; using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; @@ -176,7 +175,7 @@ namespace osu.Game.Screens.Edit [Resolved(canBeNull: true)] private OnScreenDisplay onScreenDisplay { get; set; } - private Bindable useUserDim; + private Bindable editorDim; public Editor(EditorLoader loader = null) { @@ -262,8 +261,7 @@ namespace osu.Game.Screens.Edit OsuMenuItem undoMenuItem; OsuMenuItem redoMenuItem; - TernaryStateRadioMenuItem backgroundDim; - useUserDim = config.GetBindable(OsuSetting.EditorUseDim); + editorDim = config.GetBindable(OsuSetting.EditorDim); AddInternal(new OsuContextMenuContainer { @@ -316,7 +314,7 @@ namespace osu.Game.Screens.Edit Items = new MenuItem[] { new WaveformOpacityMenuItem(config.GetBindable(OsuSetting.EditorWaveformOpacity)), - backgroundDim = new TernaryStateRadioMenuItem("Background Dim", MenuItemType.Standard, _ => useUserDim.Value = !useUserDim.Value), + new BackgroundDimMenuItem(editorDim), } } } @@ -337,12 +335,7 @@ namespace osu.Game.Screens.Edit changeHandler?.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true); changeHandler?.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true); - useUserDim.BindValueChanged(s => - { - dimBackground(); - backgroundDim.State.Value = s.NewValue ? TernaryState.True : TernaryState.False; - }); - backgroundDim.State.Value = useUserDim.Value ? TernaryState.True : TernaryState.False; + editorDim.BindValueChanged(_ => dimBackground()); } [Resolved] @@ -638,10 +631,8 @@ namespace osu.Game.Screens.Edit { ApplyToBackground(b => { - // todo: temporary. we want to be applying dim using the UserDimContainer eventually. - if (!useUserDim.Value) b.FadeColour(Color4.DarkGray, 500); - - b.IgnoreUserSettings.Value = !useUserDim.Value; + b.IgnoreUserSettings.Value = true; + b.DimAmount.Value = editorDim.Value; b.BlurAmount.Value = 0; }); } @@ -671,8 +662,8 @@ namespace osu.Game.Screens.Edit ApplyToBackground(b => { - b.FadeColour(Color4.White, 500); - b.IgnoreUserSettings.Value = true; + //b.DimAmount.UnbindAll(); + b.DimAmount.Value = 0; }); resetTrack(); From 614011d612b760d94b97f6d23df360a75b6649d8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 15:25:50 +0900 Subject: [PATCH 1878/2686] Update `TestSceneObjectOrderedHitPolicy` to provide better output --- osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs index 1665c40b40..ed1891b7d9 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs @@ -377,7 +377,7 @@ namespace osu.Game.Rulesets.Osu.Tests private void addJudgementAssert(OsuHitObject hitObject, HitResult result) { AddAssert($"({hitObject.GetType().ReadableName()} @ {hitObject.StartTime}) judgement is {result}", - () => judgementResults.Single(r => r.HitObject == hitObject).Type == result); + () => judgementResults.Single(r => r.HitObject == hitObject).Type, () => Is.EqualTo(result)); } private void addJudgementAssert(string name, Func hitObject, HitResult result) From 674ae9e7427e06dfbffb9287a0c5f7a39fa11f3a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 15:26:20 +0900 Subject: [PATCH 1879/2686] Refactor `DrawableSliderHead` to never update the drawable position Slider heads are guaranteed to always be drawn at (0,0). This fixes weird behaviour in the editor, but also simplifies things in the process. Win-win. Closes #20644. --- .../Objects/Drawables/DrawableHitCircle.cs | 9 +++++++-- .../Objects/Drawables/DrawableSliderHead.cs | 19 +++++-------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 23db29b9a6..841a52da7b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -102,8 +102,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Size = HitArea.DrawSize; - PositionBindable.BindValueChanged(_ => Position = HitObject.StackedPosition); - StackHeightBindable.BindValueChanged(_ => Position = HitObject.StackedPosition); + PositionBindable.BindValueChanged(_ => UpdatePosition()); + StackHeightBindable.BindValueChanged(_ => UpdatePosition()); ScaleBindable.BindValueChanged(scale => scaleContainer.Scale = new Vector2(scale.NewValue)); } @@ -134,6 +134,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } + protected virtual void UpdatePosition() + { + Position = HitObject.StackedPosition; + } + public override void Shake() => shakeContainer.Shake(); protected override void CheckForResult(bool userTriggered, double timeOffset) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index 80b9544e5b..d1d749d7e2 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -6,7 +6,6 @@ using System; using System.Diagnostics; using JetBrains.Annotations; -using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Scoring; @@ -43,13 +42,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { } - [BackgroundDependencyLoader] - private void load() - { - PositionBindable.BindValueChanged(_ => updatePosition()); - pathVersion.BindValueChanged(_ => updatePosition()); - } - protected override void OnFree() { base.OnFree(); @@ -57,6 +49,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables pathVersion.UnbindFrom(DrawableSlider.PathVersion); } + protected override void UpdatePosition() + { + // Slider head is always drawn at (0,0). + } + protected override void OnApply() { base.OnApply(); @@ -100,11 +97,5 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables base.Shake(); DrawableSlider.Shake(); } - - private void updatePosition() - { - if (Slider != null) - Position = HitObject.Position - Slider.Position; - } } } From 81bb00c25829fca1d394775961bb8e10e28cec2e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 24 Oct 2022 16:57:45 +0900 Subject: [PATCH 1880/2686] Add argon transformer for osu!catch (and basic new catcher design) --- osu.Game.Rulesets.Catch/CatchRuleset.cs | 4 + .../Skinning/Argon/ArgonCatcher.cs | 86 ++++++++ .../Skinning/Argon/ArgonJudgementPiece.cs | 193 ++++++++++++++++++ .../Argon/CatchArgonSkinTransformer.cs | 34 +++ 4 files changed, 317 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs create mode 100644 osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs create mode 100644 osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 5c9c95827a..e0f7820262 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -17,6 +17,7 @@ using osu.Game.Rulesets.Catch.Edit; using osu.Game.Rulesets.Catch.Mods; using osu.Game.Rulesets.Catch.Replays; using osu.Game.Rulesets.Catch.Scoring; +using osu.Game.Rulesets.Catch.Skinning.Argon; using osu.Game.Rulesets.Catch.Skinning.Legacy; using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Difficulty; @@ -188,6 +189,9 @@ namespace osu.Game.Rulesets.Catch { case LegacySkin: return new CatchLegacySkinTransformer(skin); + + case ArgonSkin: + return new CatchArgonSkinTransformer(skin); } return null; diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs new file mode 100644 index 0000000000..4e3439cb2b --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs @@ -0,0 +1,86 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Catch.UI; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Skinning.Argon +{ + public class ArgonCatcher : CompositeDrawable + { + [Resolved] + private Bindable currentState { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + Height = 10, + Children = new Drawable[] + { + new Circle + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + }, + new Box + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + Colour = Color4.White, + Alpha = 0.25f, + RelativeSizeAxes = Axes.X, + X = -2, + Width = 20, + Height = 1.8f, + }, + new Circle + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + Colour = Color4.White, + RelativeSizeAxes = Axes.X, + X = -2, + Width = 15 / 170f, + Height = 4, + }, + new Box + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreLeft, + Colour = Color4.White, + Alpha = 0.25f, + RelativeSizeAxes = Axes.X, + X = 2, + Width = 20, + Height = 1.8f, + }, + new Circle + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreLeft, + Colour = Color4.White, + X = 2, + RelativeSizeAxes = Axes.X, + Width = 15 / 170f, + Height = 4, + }, + } + }, + }; + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs new file mode 100644 index 0000000000..59e8b5a0b3 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs @@ -0,0 +1,193 @@ +// 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.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Skinning.Argon +{ + public class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + { + protected readonly HitResult Result; + + protected SpriteText JudgementText { get; private set; } = null!; + + private RingExplosion? ringExplosion; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + public ArgonJudgementPiece(HitResult result) + { + Result = result; + Origin = Anchor.Centre; + Y = 160; + } + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + JudgementText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = Result.GetDescription().ToUpperInvariant(), + Colour = colours.ForHitResult(Result), + Blending = BlendingParameters.Additive, + Spacing = new Vector2(10, 0), + Font = OsuFont.Default.With(size: 28, weight: FontWeight.Regular), + }, + }; + + if (Result.IsHit()) + { + AddInternal(ringExplosion = new RingExplosion(Result) + { + Colour = colours.ForHitResult(Result), + }); + } + } + + /// + /// Plays the default animation for this judgement piece. + /// + /// + /// The base implementation only handles fade (for all result types) and misses. + /// Individual rulesets are recommended to implement their appropriate hit animations. + /// + public virtual void PlayAnimation() + { + switch (Result) + { + default: + JudgementText + .ScaleTo(Vector2.One) + .ScaleTo(new Vector2(1.4f), 1800, Easing.OutQuint); + break; + + case HitResult.Miss: + this.ScaleTo(1.6f); + this.ScaleTo(1, 100, Easing.In); + + this.MoveTo(Vector2.Zero); + this.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint); + + this.RotateTo(0); + this.RotateTo(40, 800, Easing.InQuint); + break; + } + + this.FadeOutFromOne(800); + + ringExplosion?.PlayAnimation(); + } + + public Drawable? GetAboveHitObjectsProxiedContent() => null; + + private class RingExplosion : CompositeDrawable + { + private readonly float travel = 52; + + public RingExplosion(HitResult result) + { + const float thickness = 4; + + const float small_size = 9; + const float large_size = 14; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Blending = BlendingParameters.Additive; + + int countSmall = 0; + int countLarge = 0; + + switch (result) + { + case HitResult.Meh: + countSmall = 3; + travel *= 0.3f; + break; + + case HitResult.Ok: + case HitResult.Good: + countSmall = 4; + travel *= 0.6f; + break; + + case HitResult.Great: + case HitResult.Perfect: + countSmall = 4; + countLarge = 4; + break; + } + + for (int i = 0; i < countSmall; i++) + AddInternal(new RingPiece(thickness) { Size = new Vector2(small_size) }); + + for (int i = 0; i < countLarge; i++) + AddInternal(new RingPiece(thickness) { Size = new Vector2(large_size) }); + } + + public void PlayAnimation() + { + foreach (var c in InternalChildren) + { + const float start_position_ratio = 0.3f; + + float direction = RNG.NextSingle(0, 360); + float distance = RNG.NextSingle(travel / 2, travel); + + c.MoveTo(new Vector2( + MathF.Cos(direction) * distance * start_position_ratio, + MathF.Sin(direction) * distance * start_position_ratio + )); + + c.MoveTo(new Vector2( + MathF.Cos(direction) * distance, + MathF.Sin(direction) * distance + ), 600, Easing.OutQuint); + } + + this.FadeOutFromOne(1000, Easing.OutQuint); + } + + public class RingPiece : CircularContainer + { + public RingPiece(float thickness = 9) + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Masking = true; + BorderThickness = thickness; + BorderColour = Color4.White; + + Child = new Box + { + AlwaysPresent = true, + Alpha = 0, + RelativeSizeAxes = Axes.Both + }; + } + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs new file mode 100644 index 0000000000..764f3c6cbd --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs @@ -0,0 +1,34 @@ +// 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.Graphics; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Catch.Skinning.Argon +{ + public class CatchArgonSkinTransformer : SkinTransformer + { + public CatchArgonSkinTransformer(ISkin skin) + : base(skin) + { + } + + public override Drawable? GetDrawableComponent(ISkinComponent component) + { + switch (component) + { + case CatchSkinComponent osuComponent: + // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. + switch (osuComponent.Component) + { + case CatchSkinComponents.Catcher: + return new ArgonCatcher(); + } + + break; + } + + return base.GetDrawableComponent(component); + } + } +} From 4ff4de00b3f7eff901ff318ee26f0a1ed160af88 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 16:08:01 +0900 Subject: [PATCH 1881/2686] Add argon fruit design --- .../Skinning/Argon/ArgonFruitPiece.cs | 104 ++++++++++++++++++ .../Argon/CatchArgonSkinTransformer.cs | 3 + .../Skinning/Default/CatchHitObjectPiece.cs | 3 +- .../Skinning/Default/DropletPiece.cs | 2 +- .../Skinning/Default/FruitPiece.cs | 4 +- 5 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs new file mode 100644 index 0000000000..7a59254028 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs @@ -0,0 +1,104 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Utils; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.Skinning.Default; +using osu.Game.Rulesets.Catch.UI; +using osuTK; + +namespace osu.Game.Rulesets.Catch.Skinning.Argon +{ + internal class ArgonFruitPiece : CatchHitObjectPiece + { + public readonly Bindable VisualRepresentation = new Bindable(); + + protected override Drawable HyperBorderPiece => hyperBorderPiece; + + private Drawable hyperBorderPiece = null!; + + private Container layers = null!; + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + RelativeSizeAxes = Axes.Both; + + Texture largeTexture = getTexture("A"); + + InternalChildren = new[] + { + new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(20), + }, + layers = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Alpha = 0.15f, + Texture = largeTexture + }, + new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Alpha = 0.5f, + Texture = getTexture("B") + }, + new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Texture = getTexture("C") + }, + } + }, + hyperBorderPiece = new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR, + Blending = BlendingParameters.Additive, + Alpha = 0.15f, + Texture = largeTexture, + }, + }; + + Texture getTexture(string type) => textures.Get($"Gameplay/catch/blob-{type}{RNG.Next(1, 7)}"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + IndexInBeatmap.BindValueChanged(index => + { + VisualRepresentation.Value = Fruit.GetVisualRepresentation(index.NewValue); + }, true); + + AccentColour.BindValueChanged(colour => + { + foreach (var sprite in layers) + sprite.Colour = colour.NewValue; + }, true); + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs index 764f3c6cbd..621a71b1d1 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs @@ -23,6 +23,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { case CatchSkinComponents.Catcher: return new ArgonCatcher(); + + case CatchSkinComponents.Fruit: + return new ArgonFruitPiece(); } break; diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs index 6cc5220699..fd1047f27e 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs @@ -7,6 +7,7 @@ using System; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Catch.Objects.Drawables; using osuTK.Graphics; @@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default /// A part of this piece that will be only visible when is true. /// [CanBeNull] - protected virtual HyperBorderPiece HyperBorderPiece => null; + protected virtual Drawable HyperBorderPiece => null; protected override void LoadComplete() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs index 6b7f25eed1..e4c2f04476 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default { public class DropletPiece : CatchHitObjectPiece { - protected override HyperBorderPiece HyperBorderPiece { get; } + protected override Drawable HyperBorderPiece { get; } public DropletPiece() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs index 8fb5c8f84a..9dce0e9129 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs @@ -19,13 +19,13 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default public readonly Bindable VisualRepresentation = new Bindable(); protected override BorderPiece BorderPiece { get; } - protected override HyperBorderPiece HyperBorderPiece { get; } + protected override Drawable HyperBorderPiece { get; } public FruitPiece() { RelativeSizeAxes = Axes.Both; - InternalChildren = new Drawable[] + InternalChildren = new[] { new FruitPulpFormation { From a475ca848d188d9ac490d4b3a6f6edc3c5250f5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 16:31:40 +0900 Subject: [PATCH 1882/2686] Add rotation to fruit pieces --- .../Skinning/Argon/ArgonFruitPiece.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs index 7a59254028..9561659792 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs @@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon private Container layers = null!; + private float rotationRandomness; + [BackgroundDependencyLoader] private void load(TextureStore textures) { @@ -99,6 +101,24 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon foreach (var sprite in layers) sprite.Colour = colour.NewValue; }, true); + + rotationRandomness = RNG.NextSingle(0.2f, 1) * (RNG.NextBool() ? -1 : 1); + } + + protected override void Update() + { + base.Update(); + + for (int i = 0; i < layers.Count; i++) + { + layers[i].Rotation += + // Layers are ordered from largest to smallest. Smaller layers should rotate more. + (i * 2) + * (float)Clock.ElapsedFrameTime + * 0.02f * rotationRandomness + // Each layer should alternate rotation direction. + * (i % 2 == 1 ? 1 : -1); + } } } } From 0a8a13f52915e90f30b60a62aecc048378cad645 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 17:01:58 +0900 Subject: [PATCH 1883/2686] Add argon banana piece --- .../Skinning/Argon/ArgonBananaPiece.cs | 82 +++++++++++++++++++ .../Argon/CatchArgonSkinTransformer.cs | 3 + 2 files changed, 85 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs new file mode 100644 index 0000000000..49edc80770 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs @@ -0,0 +1,82 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.Containers; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Skinning.Argon +{ + internal class ArgonBananaPiece : ArgonFruitPiece + { + [BackgroundDependencyLoader] + private void load() + { + AddInternal(new UprightAspectMaintainingContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new Drawable[] + { + new Circle + { + Colour = Color4.White.Opacity(0.4f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Size = new Vector2(8), + Scale = new Vector2(30, 1), + }, + new Box + { + Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0), Color4.White), + RelativeSizeAxes = Axes.X, + Blending = BlendingParameters.Additive, + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + Width = 1.6f, + Height = 2, + }, + new Box + { + Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.White.Opacity(0)), + RelativeSizeAxes = Axes.X, + Blending = BlendingParameters.Additive, + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + Width = 1.6f, + Height = 2, + }, + new Circle + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(1.2f), + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Hollow = false, + Colour = Color4.White.Opacity(0.1f), + Radius = 50, + }, + Child = + { + Alpha = 0, + AlwaysPresent = true, + }, + BorderColour = Color4.White.Opacity(0.1f), + BorderThickness = 3, + }, + } + }); + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs index 621a71b1d1..b55706b6d0 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs @@ -26,6 +26,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon case CatchSkinComponents.Fruit: return new ArgonFruitPiece(); + + case CatchSkinComponents.Banana: + return new ArgonBananaPiece(); } break; From 2deaae270c19d991e7b12fc1280146efa3c11b2c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 17:12:20 +0900 Subject: [PATCH 1884/2686] Fix catcher not consdiering allowable catch range --- .../Skinning/Argon/ArgonCatcher.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs index 4e3439cb2b..ffd99aff4a 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs @@ -34,48 +34,51 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon new Circle { RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Colour = Color4.White, + Width = Catcher.ALLOWED_CATCH_RANGE, }, new Box { + Name = "long line left", Anchor = Anchor.CentreLeft, Origin = Anchor.CentreRight, Colour = Color4.White, Alpha = 0.25f, RelativeSizeAxes = Axes.X, - X = -2, Width = 20, Height = 1.8f, }, new Circle { + Name = "bumper left", Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreRight, + Origin = Anchor.CentreLeft, Colour = Color4.White, RelativeSizeAxes = Axes.X, - X = -2, - Width = 15 / 170f, + Width = (1 - Catcher.ALLOWED_CATCH_RANGE) / 2, Height = 4, }, new Box { + Name = "long line right", Anchor = Anchor.CentreRight, Origin = Anchor.CentreLeft, Colour = Color4.White, Alpha = 0.25f, RelativeSizeAxes = Axes.X, - X = 2, Width = 20, Height = 1.8f, }, new Circle { + Name = "bumper right", Anchor = Anchor.CentreRight, - Origin = Anchor.CentreLeft, + Origin = Anchor.CentreRight, Colour = Color4.White, - X = 2, RelativeSizeAxes = Axes.X, - Width = 15 / 170f, + Width = (1 - Catcher.ALLOWED_CATCH_RANGE) / 2, Height = 4, }, } From 14a4fad6f1c21e14c7d72ec52461524ebb3b5bbc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 17:16:38 +0900 Subject: [PATCH 1885/2686] Remove unused `VisualRepresentation` --- .../Skinning/Argon/ArgonFruitPiece.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs index 9561659792..2412de7dbe 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs @@ -2,14 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Utils; -using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Skinning.Default; using osu.Game.Rulesets.Catch.UI; using osuTK; @@ -18,8 +16,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { internal class ArgonFruitPiece : CatchHitObjectPiece { - public readonly Bindable VisualRepresentation = new Bindable(); - protected override Drawable HyperBorderPiece => hyperBorderPiece; private Drawable hyperBorderPiece = null!; @@ -91,11 +87,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { base.LoadComplete(); - IndexInBeatmap.BindValueChanged(index => - { - VisualRepresentation.Value = Fruit.GetVisualRepresentation(index.NewValue); - }, true); - AccentColour.BindValueChanged(colour => { foreach (var sprite in layers) From 8a513003ce38f4212e9f40f90c21ec1555ca1c0d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 17:32:26 +0900 Subject: [PATCH 1886/2686] Add argon droplet --- .../Skinning/Argon/ArgonDropletPiece.cs | 118 ++++++++++++++++++ .../Argon/CatchArgonSkinTransformer.cs | 3 + .../Skinning/Default/DropletPiece.cs | 2 +- 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs new file mode 100644 index 0000000000..c607b96729 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs @@ -0,0 +1,118 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Utils; +using osu.Game.Rulesets.Catch.Skinning.Default; +using osu.Game.Rulesets.Catch.UI; +using osuTK; + +namespace osu.Game.Rulesets.Catch.Skinning.Argon +{ + internal class ArgonDropletPiece : CatchHitObjectPiece + { + protected override Drawable HyperBorderPiece => hyperBorderPiece; + + private Drawable hyperBorderPiece = null!; + + private Container layers = null!; + + private float rotationRandomness; + + [BackgroundDependencyLoader] + private void load(TextureStore textures) + { + RelativeSizeAxes = Axes.Both; + + const float droplet_scale_down = 0.5f; + + InternalChildren = new[] + { + new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(20), + }, + layers = new Container + { + Scale = new Vector2(droplet_scale_down), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Alpha = 0.15f, + Texture = getTexture("A") + }, + new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Alpha = 0.5f, + Scale = new Vector2(0.8f), + Texture = getTexture("A") + }, + } + }, + hyperBorderPiece = new Sprite + { + Scale = new Vector2(droplet_scale_down), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR, + Blending = BlendingParameters.Additive, + Alpha = 0.15f, + Texture = getTexture("A"), + }, + }; + + Texture getTexture(string type) => textures.Get($"Gameplay/catch/blob-{type}{RNG.Next(1, 7)}"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + AccentColour.BindValueChanged(colour => + { + foreach (var sprite in layers) + sprite.Colour = colour.NewValue; + }, true); + + rotationRandomness = RNG.NextSingle(0.2f, 1); + } + + protected override void Update() + { + base.Update(); + + // Note that droplets are rotated at a higher level, so this is mostly just to create more + // random arrangements of the multiple layers than actually rotate. + // + // Because underlying rotation is always clockwise, we apply anti-clockwise resistance to avoid + // making things spin too fast. + for (int i = 0; i < layers.Count; i++) + { + layers[i].Rotation -= + // Layers are ordered from largest to smallest. Smaller layers should rotate more. + (i * 4) + * (float)Clock.ElapsedFrameTime + * 0.2f * rotationRandomness + // Each layer should alternate rotation direction. + * (i % 2 == 1 ? 0.5f : 1); + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs index b55706b6d0..76a5b221fd 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs @@ -29,6 +29,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon case CatchSkinComponents.Banana: return new ArgonBananaPiece(); + + case CatchSkinComponents.Droplet: + return new ArgonDropletPiece(); } break; diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs index e4c2f04476..b8ae062382 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default { Size = new Vector2(CatchHitObject.OBJECT_RADIUS / 2); - InternalChildren = new Drawable[] + InternalChildren = new[] { new Pulp { From 44f55ed152d21be35ddbf36393d0a919172060de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 18:20:45 +0900 Subject: [PATCH 1887/2686] Add argon osu!catch hit explosion --- .../Skinning/Argon/ArgonHitExplosion.cs | 112 ++++++++++++++++++ .../Argon/CatchArgonSkinTransformer.cs | 3 + 2 files changed, 115 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Skinning/Argon/ArgonHitExplosion.cs diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonHitExplosion.cs new file mode 100644 index 0000000000..90dca49dfd --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonHitExplosion.cs @@ -0,0 +1,112 @@ +// 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.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Skinning.Argon +{ + public class ArgonHitExplosion : CompositeDrawable, IHitExplosion + { + public override bool RemoveWhenNotAlive => true; + + private Container tallExplosion = null!; + private Container largeFaint = null!; + + private readonly Bindable accentColour = new Bindable(); + + public ArgonHitExplosion() + { + Size = new Vector2(20); + Anchor = Anchor.BottomCentre; + Origin = Anchor.BottomCentre; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + tallExplosion = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Width = 0.1f, + Child = new Box + { + AlwaysPresent = true, + Alpha = 0, + RelativeSizeAxes = Axes.Both, + }, + }, + largeFaint = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Child = new Box + { + AlwaysPresent = true, + Alpha = 0, + RelativeSizeAxes = Axes.Both, + }, + }, + }; + + accentColour.BindValueChanged(colour => + { + tallExplosion.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = colour.NewValue, + Hollow = false, + Roundness = 15, + Radius = 15, + }; + + largeFaint.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Interpolation.ValueAt(0.2f, colour.NewValue, Color4.White, 0, 1), + Hollow = false, + Radius = 50, + }; + }, true); + } + + public void Animate(HitExplosionEntry entry) + { + X = entry.Position; + Scale = new Vector2(entry.HitObject.Scale); + accentColour.Value = entry.ObjectColour; + + using (BeginAbsoluteSequence(entry.LifetimeStart)) + { + this.FadeOutFromOne(400); + + if (!(entry.HitObject is Droplet)) + { + float scale = Math.Clamp(entry.JudgementResult.ComboAtJudgement / 200f, 0.35f, 1.125f); + + tallExplosion + .ScaleTo(new Vector2(1.1f, 20 * scale), 200, Easing.OutQuint) + .Then() + .ScaleTo(new Vector2(1.1f, 1), 600, Easing.In); + } + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs index 76a5b221fd..30542187f2 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs @@ -21,6 +21,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (osuComponent.Component) { + case CatchSkinComponents.HitExplosion: + return new ArgonHitExplosion(); + case CatchSkinComponents.Catcher: return new ArgonCatcher(); From 8a80cb55bd4741f34d891c6aa0ece5bfa57e583c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 Oct 2022 18:55:00 +0900 Subject: [PATCH 1888/2686] Remove unused catcher animation state for now --- osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs index ffd99aff4a..4db0df4a34 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -13,9 +12,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { public class ArgonCatcher : CompositeDrawable { - [Resolved] - private Bindable currentState { get; set; } = null!; - [BackgroundDependencyLoader] private void load() { From dffebdf7eda6e68045c6e3c99d868507ea06a3dc Mon Sep 17 00:00:00 2001 From: nullium21 Date: Wed, 26 Oct 2022 13:31:32 +0300 Subject: [PATCH 1889/2686] Only use 0-9A-Za-z-_()[] characters in filenames --- osu.Game/Extensions/ModelExtensions.cs | 31 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/osu.Game/Extensions/ModelExtensions.cs b/osu.Game/Extensions/ModelExtensions.cs index b10071bb45..51bea02726 100644 --- a/osu.Game/Extensions/ModelExtensions.cs +++ b/osu.Game/Extensions/ModelExtensions.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.IO; -using System.Linq; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.IO; @@ -137,20 +136,34 @@ namespace osu.Game.Extensions return instance.OnlineID.Equals(other.OnlineID); } - private static readonly char[] invalid_filename_characters = Path.GetInvalidFileNameChars() - // Backslash is added to avoid issues when exporting to zip. - // See SharpCompress filename normalisation https://github.com/adamhathcock/sharpcompress/blob/a1e7c0068db814c9aa78d86a94ccd1c761af74bd/src/SharpCompress/Writers/Zip/ZipWriter.cs#L143. - .Append('\\') - .ToArray(); + private static bool isValidFilenameChar(this char ch) + { + if (ch >= '0' && ch <= '9') + return true; + + if (ch >= 'A' && ch <= 'Z') + return true; + + if (ch >= 'a' && ch <= 'z') + return true; + + return "-_()[]".Contains(ch); + } /// /// Get a valid filename for use inside a zip file. Avoids backslashes being incorrectly converted to directories. /// public static string GetValidArchiveContentFilename(this string filename) { - foreach (char c in invalid_filename_characters) - filename = filename.Replace(c, '_'); - return filename; + char[] resultData = filename.ToCharArray(); + + for (int i = 0; i < resultData.Length; i++) + { + if (!isValidFilenameChar(resultData[i])) + resultData[i] = '_'; + } + + return new string(resultData); } } } From e4f25fc4d49bfd0d91f764c4b54a68c4671404d6 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Wed, 26 Oct 2022 16:42:00 +0200 Subject: [PATCH 1890/2686] Don't overwrite special precision legacy difficulty points --- osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index c9ee63424c..b1383c9e85 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -10,6 +10,7 @@ using System.IO; using System.Linq; using System.Text; using JetBrains.Annotations; +using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Legacy; @@ -190,7 +191,14 @@ namespace osu.Game.Beatmaps.Formats extractSampleControlPoints(beatmap.HitObjects); foreach (var point in legacyControlPoints.EffectPoints) + { + DifficultyControlPoint difficultyPoint = legacyControlPoints.DifficultyPointAt(point.Time); + + if (Precision.AlmostEquals(difficultyPoint.SliderVelocity, point.ScrollSpeed, acceptableDifference: point.ScrollSpeedBindable.Precision)) + continue; + legacyControlPoints.Add(point.Time, new DifficultyControlPoint { SliderVelocity = point.ScrollSpeed }); + } foreach (var group in legacyControlPoints.Groups) { From 77dcd0fae284eff1a556ae28fc18498db961426d Mon Sep 17 00:00:00 2001 From: OliBomby Date: Wed, 26 Oct 2022 17:21:20 +0200 Subject: [PATCH 1891/2686] Create BezierConverter.cs --- osu.Game/Rulesets/Objects/BezierConverter.cs | 352 +++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 osu.Game/Rulesets/Objects/BezierConverter.cs diff --git a/osu.Game/Rulesets/Objects/BezierConverter.cs b/osu.Game/Rulesets/Objects/BezierConverter.cs new file mode 100644 index 0000000000..414341641f --- /dev/null +++ b/osu.Game/Rulesets/Objects/BezierConverter.cs @@ -0,0 +1,352 @@ +// 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 osu.Framework.Utils; +using osu.Game.Rulesets.Objects.Types; +using osuTK; + +namespace osu.Game.Rulesets.Objects +{ + public static class BezierConverter + { + private struct CircleBezierPreset + { + public readonly double ArcLength; + public readonly Vector2d[] ControlPoints; + + public CircleBezierPreset(double arcLength, Vector2d[] controlPoints) + { + ArcLength = arcLength; + ControlPoints = controlPoints; + } + } + + // Extremely accurate a bezier anchor positions for approximating circles of several arc lengths + private static readonly CircleBezierPreset[] circle_presets = + { + new CircleBezierPreset(0.4993379862754501, + new[] { new Vector2d(1, 0), new Vector2d(1, 0.2549893626632736f), new Vector2d(0.8778997558480327f, 0.47884446188920726f) }), + new CircleBezierPreset(1.7579419829169447, + new[] { new Vector2d(1, 0), new Vector2d(1, 0.6263026f), new Vector2d(0.42931178f, 1.0990661f), new Vector2d(-0.18605515f, 0.9825393f) }), + new CircleBezierPreset(3.1385246920140215, + new[] { new Vector2d(1, 0), new Vector2d(1, 0.87084764f), new Vector2d(0.002304826f, 1.5033062f), new Vector2d(-0.9973236f, 0.8739115f), new Vector2d(-0.9999953f, 0.0030679568f) }), + new CircleBezierPreset(5.69720464620727, + new[] { new Vector2d(1, 0), new Vector2d(1, 1.4137783f), new Vector2d(-1.4305235f, 2.0779421f), new Vector2d(-2.3410065f, -0.94017583f), new Vector2d(0.05132711f, -1.7309346f), new Vector2d(0.8331702f, -0.5530167f) }), + new CircleBezierPreset(2 * Math.PI, + new[] { new Vector2d(1, 0), new Vector2d(1, 1.2447058f), new Vector2d(-0.8526471f, 2.118367f), new Vector2d(-2.6211002f, 7.854936e-06f), new Vector2d(-0.8526448f, -2.118357f), new Vector2d(1, -1.2447058f), new Vector2d(1, 0) }) + }; + + #region CircularArcProperties + + //TODO: Get this from osu!framework instead + public readonly struct CircularArcProperties + { + public readonly bool IsValid; + public readonly double ThetaStart; + public readonly double ThetaRange; + public readonly double Direction; + public readonly float Radius; + public readonly Vector2 Centre; + + public double ThetaEnd => ThetaStart + ThetaRange * Direction; + + public CircularArcProperties(double thetaStart, double thetaRange, double direction, float radius, Vector2 centre) + { + IsValid = true; + ThetaStart = thetaStart; + ThetaRange = thetaRange; + Direction = direction; + Radius = radius; + Centre = centre; + } + } + + /// + /// Computes various properties that can be used to approximate the circular arc. + /// + /// Three distinct points on the arc. + private static CircularArcProperties circularArcProperties(ReadOnlySpan controlPoints) + { + Vector2 a = controlPoints[0]; + Vector2 b = controlPoints[1]; + Vector2 c = controlPoints[2]; + + // If we have a degenerate triangle where a side-length is almost zero, then give up and fallback to a more numerically stable method. + if (Precision.AlmostEquals(0, (b.Y - a.Y) * (c.X - a.X) - (b.X - a.X) * (c.Y - a.Y))) + return default; // Implicitly sets `IsValid` to false + + // See: https://en.wikipedia.org/wiki/Circumscribed_circle#Cartesian_coordinates_2 + float d = 2 * (a.X * (b - c).Y + b.X * (c - a).Y + c.X * (a - b).Y); + float aSq = a.LengthSquared; + float bSq = b.LengthSquared; + float cSq = c.LengthSquared; + + Vector2 centre = new Vector2( + aSq * (b - c).Y + bSq * (c - a).Y + cSq * (a - b).Y, + aSq * (c - b).X + bSq * (a - c).X + cSq * (b - a).X) / d; + + Vector2 dA = a - centre; + Vector2 dC = c - centre; + + float r = dA.Length; + + double thetaStart = Math.Atan2(dA.Y, dA.X); + double thetaEnd = Math.Atan2(dC.Y, dC.X); + + while (thetaEnd < thetaStart) + thetaEnd += 2 * Math.PI; + + double dir = 1; + double thetaRange = thetaEnd - thetaStart; + + // Decide in which direction to draw the circle, depending on which side of + // AC B lies. + Vector2 orthoAtoC = c - a; + orthoAtoC = new Vector2(orthoAtoC.Y, -orthoAtoC.X); + + if (Vector2.Dot(orthoAtoC, b - a) < 0) + { + dir = -dir; + thetaRange = 2 * Math.PI - thetaRange; + } + + return new CircularArcProperties(thetaStart, thetaRange, dir, r, centre); + } + + #endregion + + public static IEnumerable ConvertToLegacyBezier(IList controlPoints, Vector2 position) + { + Vector2[] vertices = new Vector2[controlPoints.Count]; + for (int i = 0; i < controlPoints.Count; i++) + vertices[i] = controlPoints[i].Position; + + var result = new List(); + int start = 0; + + for (int i = 0; i < controlPoints.Count; i++) + { + if (controlPoints[i].Type == null && i < controlPoints.Count - 1) + continue; + + // The current vertex ends the segment + var segmentVertices = vertices.AsSpan().Slice(start, i - start + 1); + var segmentType = controlPoints[start].Type ?? PathType.Linear; + + switch (segmentType) + { + case PathType.Catmull: + result.AddRange(from segment in ConvertCatmullToBezierAnchors(segmentVertices) from v in segment select v + position); + + break; + + case PathType.Linear: + result.AddRange(from segment in ConvertLinearToBezierAnchors(segmentVertices) from v in segment select v + position); + + break; + + case PathType.PerfectCurve: + result.AddRange(ConvertCircleToBezierAnchors(segmentVertices).Select(v => v + position)); + + break; + + default: + foreach (Vector2 v in segmentVertices) + { + result.Add(v + position); + } + + break; + } + + // Start the new segment at the current vertex + start = i; + } + + return result; + } + + public static List ConvertToModernBezier(IList controlPoints) + { + Vector2[] vertices = new Vector2[controlPoints.Count]; + for (int i = 0; i < controlPoints.Count; i++) + vertices[i] = controlPoints[i].Position; + + var result = new List(); + int start = 0; + + for (int i = 0; i < controlPoints.Count; i++) + { + if (controlPoints[i].Type == null && i < controlPoints.Count - 1) + continue; + + // The current vertex ends the segment + var segmentVertices = vertices.AsSpan().Slice(start, i - start + 1); + var segmentType = controlPoints[start].Type ?? PathType.Linear; + + switch (segmentType) + { + case PathType.Catmull: + foreach (var segment in ConvertCatmullToBezierAnchors(segmentVertices)) + { + for (int j = 0; j < segment.Length - 1; j++) + { + result.Add(new PathControlPoint(segment[j], j == 0 ? PathType.Bezier : null)); + } + } + + break; + + case PathType.Linear: + foreach (var segment in ConvertLinearToBezierAnchors(segmentVertices)) + { + for (int j = 0; j < segment.Length - 1; j++) + { + result.Add(new PathControlPoint(segment[j], j == 0 ? PathType.Bezier : null)); + } + } + + break; + + case PathType.PerfectCurve: + var circleResult = ConvertCircleToBezierAnchors(segmentVertices); + + for (int j = 0; j < circleResult.Length - 1; j++) + { + result.Add(new PathControlPoint(circleResult[j], j == 0 ? PathType.Bezier : null)); + } + + break; + + default: + for (int j = 0; j < segmentVertices.Length - 1; j++) + { + result.Add(new PathControlPoint(segmentVertices[j], j == 0 ? PathType.Bezier : null)); + } + + break; + } + + // Start the new segment at the current vertex + start = i; + } + + result.Add(new PathControlPoint(controlPoints[^1].Position)); + + return result; + } + + /// + /// Converts perfect curve anchors to bezier anchors. + /// + /// The control point positions to convert. + public static Vector2[] ConvertCircleToBezierAnchors(ReadOnlySpan controlPoints) + { + var pr = circularArcProperties(controlPoints); + if (!pr.IsValid) + return controlPoints.ToArray(); + + CircleBezierPreset preset = circle_presets.Last(); + + foreach (CircleBezierPreset cbp in circle_presets) + { + if (cbp.ArcLength < pr.ThetaRange) continue; + + preset = cbp; + break; + } + + double arcLength = preset.ArcLength; + var arc = new Vector2d[preset.ControlPoints.Length]; + preset.ControlPoints.CopyTo(arc, 0); + + // Converge on arcLength of thetaRange + int n = arc.Length - 1; + double tf = pr.ThetaRange / arcLength; + + while (Math.Abs(tf - 1) > 1E-7) + { + for (int j = 0; j < n; j++) + { + for (int i = n; i > j; i--) + { + arc[i] = arc[i] * tf + arc[i - 1] * (1 - tf); + } + } + + arcLength = Math.Atan2(arc.Last()[1], arc.Last()[0]); + + if (arcLength < 0) + { + arcLength += 2 * Math.PI; + } + + tf = pr.ThetaRange / arcLength; + } + + // Adjust rotation, radius, and position + var result = new Vector2[arc.Length]; + + for (int i = 0; i < arc.Length; i++) + { + result[i] = new Vector2( + (float)((Math.Cos(pr.ThetaStart) * arc[i].X + -Math.Sin(pr.ThetaStart) * pr.Direction * arc[i].Y) * pr.Radius + pr.Centre.X), + (float)((Math.Sin(pr.ThetaStart) * arc[i].X + Math.Cos(pr.ThetaStart) * pr.Direction * arc[i].Y) * pr.Radius + pr.Centre.Y)); + } + + return result; + } + + /// + /// Converts catmull anchors to bezier anchors. + /// + /// The control point positions to convert. + public static Vector2[][] ConvertCatmullToBezierAnchors(ReadOnlySpan controlPoints) + { + int iLen = controlPoints.Length; + var bezier = new Vector2[iLen - 1][]; + + for (int i = 0; i < iLen - 1; i++) + { + var v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i]; + var v2 = controlPoints[i]; + var v3 = i < iLen - 1 ? controlPoints[i + 1] : v2 + v2 - v1; + var v4 = i < iLen - 2 ? controlPoints[i + 2] : v3 + v3 - v2; + + bezier[i] = new[] + { + v2, + (-v1 + 6 * v2 + v3) / 6, + (-v4 + 6 * v3 + v2) / 6, + v3 + }; + } + + return bezier; + } + + /// + /// Converts linear anchors to bezier anchors. + /// + /// The control point positions to convert. + public static Vector2[][] ConvertLinearToBezierAnchors(ReadOnlySpan controlPoints) + { + int iLen = controlPoints.Length; + var bezier = new Vector2[iLen - 1][]; + + for (int i = 0; i < iLen - 1; i++) + { + bezier[i] = new[] + { + controlPoints[i], + controlPoints[i + 1] + }; + } + + return bezier; + } + } +} From 86d5fcc26d6a86f7a57bf87285cb53d04da54959 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Wed, 26 Oct 2022 19:30:42 +0200 Subject: [PATCH 1892/2686] Added tests --- .../Gameplay/TestSceneBezierConverter.cs | 172 ++++++++++++++++++ osu.Game/Rulesets/Objects/BezierConverter.cs | 3 + 2 files changed, 175 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs new file mode 100644 index 0000000000..c915ae0054 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs @@ -0,0 +1,172 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Lines; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneBezierConverter : OsuTestScene + { + private readonly SmoothPath drawablePath; + private readonly SmoothPath controlPointDrawablePath; + private readonly SmoothPath convertedDrawablePath; + private readonly SmoothPath convertedControlPointDrawablePath; + private SliderPath path; + private SliderPath convertedPath; + + public TestSceneBezierConverter() + { + Children = new Drawable[] + { + new Container + { + Children = + new Drawable[] + { + drawablePath = new SmoothPath(), + controlPointDrawablePath = new SmoothPath + { + Colour = Colour4.Magenta, + PathRadius = 1f + } + }, + Position = new Vector2(100) + }, + new Container + { + Children = + new Drawable[] + { + convertedDrawablePath = new SmoothPath(), + convertedControlPointDrawablePath = new SmoothPath + { + Colour = Colour4.Magenta, + PathRadius = 1f + } + }, + Position = new Vector2(100, 300) + } + }; + } + + [SetUp] + public void Setup() => Schedule(() => + { + path = new SliderPath(); + convertedPath = new SliderPath(); + + path.Version.ValueChanged += getConvertedControlPoints; + }); + + private void getConvertedControlPoints(ValueChangedEvent obj) + { + convertedPath.ControlPoints.Clear(); + convertedPath.ControlPoints.AddRange(BezierConverter.ConvertToModernBezier(path.ControlPoints)); + } + + protected override void Update() + { + base.Update(); + + if (path != null) + { + List vertices = new List(); + path.GetPathToProgress(vertices, 0, 1); + + drawablePath.Vertices = vertices; + controlPointDrawablePath.Vertices = path.ControlPoints.Select(o => o.Position).ToList(); + if (controlPointDrawablePath.Vertices.Count > 0) + controlPointDrawablePath.Position = drawablePath.PositionInBoundingBox(drawablePath.Vertices[0]) - controlPointDrawablePath.PositionInBoundingBox(controlPointDrawablePath.Vertices[0]); + } + + if (convertedPath != null) + { + List vertices = new List(); + convertedPath.GetPathToProgress(vertices, 0, 1); + + convertedDrawablePath.Vertices = vertices; + convertedControlPointDrawablePath.Vertices = convertedPath.ControlPoints.Select(o => o.Position).ToList(); + if (convertedControlPointDrawablePath.Vertices.Count > 0) + convertedControlPointDrawablePath.Position = convertedDrawablePath.PositionInBoundingBox(convertedDrawablePath.Vertices[0]) - convertedControlPointDrawablePath.PositionInBoundingBox(convertedControlPointDrawablePath.Vertices[0]); + } + } + + [Test] + public void TestEmptyPath() + { + } + + [TestCase(PathType.Linear)] + [TestCase(PathType.Bezier)] + [TestCase(PathType.Catmull)] + [TestCase(PathType.PerfectCurve)] + public void TestSingleSegment(PathType type) + => AddStep("create path", () => path.ControlPoints.AddRange(createSegment(type, Vector2.Zero, new Vector2(0, 100), new Vector2(100)))); + + [TestCase(PathType.Linear)] + [TestCase(PathType.Bezier)] + [TestCase(PathType.Catmull)] + [TestCase(PathType.PerfectCurve)] + public void TestMultipleSegment(PathType type) + { + AddStep("create path", () => + { + path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero)); + path.ControlPoints.AddRange(createSegment(type, new Vector2(0, 100), new Vector2(100), Vector2.Zero)); + }); + } + + [TestCase(0, 100)] + [TestCase(1, 100)] + [TestCase(5, 100)] + [TestCase(10, 100)] + [TestCase(30, 100)] + [TestCase(50, 100)] + [TestCase(100, 100)] + [TestCase(100, 1)] + public void TestPerfectCurveAngles(float height, float width) + { + AddStep("create path", () => + { + path.ControlPoints.AddRange(createSegment(PathType.PerfectCurve, Vector2.Zero, new Vector2(width / 2, height), new Vector2(width, 0))); + }); + } + + [TestCase(2)] + [TestCase(4)] + public void TestPerfectCurveFallbackScenarios(int points) + { + AddStep("create path", () => + { + switch (points) + { + case 2: + path.ControlPoints.AddRange(createSegment(PathType.PerfectCurve, Vector2.Zero, new Vector2(0, 100))); + break; + + case 4: + path.ControlPoints.AddRange(createSegment(PathType.PerfectCurve, Vector2.Zero, new Vector2(0, 100), new Vector2(100), new Vector2(100, 0))); + break; + } + }); + } + + private List createSegment(PathType type, params Vector2[] controlPoints) + { + var points = controlPoints.Select(p => new PathControlPoint { Position = p }).ToList(); + points[0].Type = type; + return points; + } + } +} diff --git a/osu.Game/Rulesets/Objects/BezierConverter.cs b/osu.Game/Rulesets/Objects/BezierConverter.cs index 414341641f..9220993559 100644 --- a/osu.Game/Rulesets/Objects/BezierConverter.cs +++ b/osu.Game/Rulesets/Objects/BezierConverter.cs @@ -245,6 +245,9 @@ namespace osu.Game.Rulesets.Objects /// The control point positions to convert. public static Vector2[] ConvertCircleToBezierAnchors(ReadOnlySpan controlPoints) { + if (controlPoints.Length != 3) + return controlPoints.ToArray(); + var pr = circularArcProperties(controlPoints); if (!pr.IsValid) return controlPoints.ToArray(); From 8b8d0c2293056405941d5b444cb43b7ec5f88ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 26 Oct 2022 23:30:14 +0200 Subject: [PATCH 1893/2686] Fix typo in comment --- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index f9a952c2fb..1675d11896 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -124,7 +124,7 @@ namespace osu.Game.Rulesets.Osu.Edit { // In the case of snapping to nearby objects, a time value is not provided. // This matches the stable editor (which also uses current time), but with the introduction of time-snapping distance snap - // this could result in unexpected behaviour when distance snapping is turned on an a user attempts to place an object that is + // this could result in unexpected behaviour when distance snapping is turned on and a user attempts to place an object that is // BOTH on a valid distance snap ring, and also at the same position as a previous object. // // We want to ensure that in this particular case, the time-snapping component of distance snap is still applied. From 0efbae6e70d0190ba42c54c140a4aaecc66be84e Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 26 Oct 2022 18:33:07 -0700 Subject: [PATCH 1894/2686] Fix osu! logo drag area being a square --- osu.Game/Screens/Menu/OsuLogo.cs | 33 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index e9b50f94f7..3efd74d2c8 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -113,7 +113,7 @@ namespace osu.Game.Screens.Menu AutoSizeAxes = Axes.Both, Children = new Drawable[] { - logoBounceContainer = new DragContainer + logoBounceContainer = new Container { AutoSizeAxes = Axes.Both, Children = new Drawable[] @@ -407,27 +407,24 @@ namespace osu.Game.Screens.Menu impactContainer.ScaleTo(1.12f, 250); } - private class DragContainer : Container + public override bool DragBlocksClick => false; + + protected override bool OnDragStart(DragStartEvent e) => true; + + protected override void OnDrag(DragEvent e) { - public override bool DragBlocksClick => false; + Vector2 change = e.MousePosition - e.MouseDownPosition; - protected override bool OnDragStart(DragStartEvent e) => true; + // Diminish the drag distance as we go further to simulate "rubber band" feeling. + change *= change.Length <= 0 ? 0 : MathF.Pow(change.Length, 0.6f) / change.Length; - protected override void OnDrag(DragEvent e) - { - Vector2 change = e.MousePosition - e.MouseDownPosition; + logoBounceContainer.MoveTo(change); + } - // Diminish the drag distance as we go further to simulate "rubber band" feeling. - change *= change.Length <= 0 ? 0 : MathF.Pow(change.Length, 0.6f) / change.Length; - - this.MoveTo(change); - } - - protected override void OnDragEnd(DragEndEvent e) - { - this.MoveTo(Vector2.Zero, 800, Easing.OutElastic); - base.OnDragEnd(e); - } + protected override void OnDragEnd(DragEndEvent e) + { + logoBounceContainer.MoveTo(Vector2.Zero, 800, Easing.OutElastic); + base.OnDragEnd(e); } } } From 14c7cbde38ce4bada24f6a99076833873026b6a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 Oct 2022 11:40:59 +0900 Subject: [PATCH 1895/2686] Fix toggle mute (and volume meter traversal) handling repeat key presses Closes #20953. --- osu.Game/Overlays/Volume/VolumeControlReceptor.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs index f2b637c104..624be0b25c 100644 --- a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs +++ b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs @@ -23,10 +23,14 @@ namespace osu.Game.Overlays.Volume { case GlobalAction.DecreaseVolume: case GlobalAction.IncreaseVolume: + ActionRequested?.Invoke(e.Action); + return true; + case GlobalAction.ToggleMute: case GlobalAction.NextVolumeMeter: case GlobalAction.PreviousVolumeMeter: - ActionRequested?.Invoke(e.Action); + if (!e.Repeat) + ActionRequested?.Invoke(e.Action); return true; } From 93ffe3d7adcac60168368a458e8920c667ca26d1 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Thu, 27 Oct 2022 07:25:50 +0200 Subject: [PATCH 1896/2686] Revert to first approach --- .../Beatmaps/TaikoBeatmapConverter.cs | 23 +++++++++++++++++++ .../Formats/LegacyBeatmapDecoderTest.cs | 2 +- .../Visual/Editing/TestSceneTimingScreen.cs | 8 +++---- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 7 +++++- .../Beatmaps/Formats/LegacyBeatmapEncoder.cs | 18 ++++++++------- 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 524565a863..c1e1052569 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -57,6 +57,29 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps Beatmap converted = base.ConvertBeatmap(original, cancellationToken); + if (original.BeatmapInfo.Ruleset.OnlineID == 0) + { + // Post processing step to transform standard slider velocity changes into scroll speed changes + double lastScrollSpeed = 1; + + foreach (HitObject hitObject in original.HitObjects) + { + double nextScrollSpeed = hitObject.DifficultyControlPoint.SliderVelocity; + + if (!Precision.AlmostEquals(lastScrollSpeed, nextScrollSpeed)) + { + EffectControlPoint currentControlPoint = converted.ControlPointInfo.EffectPointAt(hitObject.StartTime); + + if (Precision.AlmostEquals(currentControlPoint.Time, hitObject.StartTime)) + currentControlPoint.ScrollSpeed = nextScrollSpeed; + else + converted.ControlPointInfo.Add(hitObject.StartTime, new EffectControlPoint { ScrollSpeed = nextScrollSpeed }); + + lastScrollSpeed = nextScrollSpeed; + } + } + } + if (original.BeatmapInfo.Ruleset.OnlineID == 3) { // Post processing step to transform mania hit objects with the same start time into strong hits diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index d9bbe7a51e..fdd0167ed3 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -175,7 +175,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual(4, controlPoints.TimingPoints.Count); Assert.AreEqual(5, controlPoints.DifficultyPoints.Count); Assert.AreEqual(34, controlPoints.SamplePoints.Count); - Assert.AreEqual(13, controlPoints.EffectPoints.Count); + Assert.AreEqual(8, controlPoints.EffectPoints.Count); var timingPoint = controlPoints.TimingPointAt(0); Assert.AreEqual(956, timingPoint.Time); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs index e93382cc9b..03c184c27d 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs @@ -67,8 +67,8 @@ namespace osu.Game.Tests.Visual.Editing InputManager.Click(MouseButton.Left); }); - AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 37560); - AddUntilStep("Ensure seeked to correct time", () => EditorClock.CurrentTimeAccurate == 37560); + AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 54670); + AddUntilStep("Ensure seeked to correct time", () => EditorClock.CurrentTimeAccurate == 54670); AddStep("Seek to just before next point", () => EditorClock.Seek(69000)); AddStep("Start clock", () => EditorClock.Start()); @@ -85,8 +85,8 @@ namespace osu.Game.Tests.Visual.Editing InputManager.Click(MouseButton.Left); }); - AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 37560); - AddUntilStep("Ensure seeked to correct time", () => EditorClock.CurrentTimeAccurate == 37560); + AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 54670); + AddUntilStep("Ensure seeked to correct time", () => EditorClock.CurrentTimeAccurate == 54670); AddStep("Seek to later", () => EditorClock.Seek(80000)); AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 69670); diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index c38510aeef..9c50c06cb7 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -448,9 +448,14 @@ namespace osu.Game.Beatmaps.Formats { KiaiMode = kiaiMode, OmitFirstBarLine = omitFirstBarSignature, - ScrollSpeed = speedMultiplier, }; + int onlineRulesetID = beatmap.BeatmapInfo.Ruleset.OnlineID; + + // osu!taiko and osu!mania use effect points rather than difficulty points for scroll speed adjustments. + if (onlineRulesetID == 1 || onlineRulesetID == 3) + effectPoint.ScrollSpeed = speedMultiplier; + addControlPoint(time, effectPoint, timingChange); addControlPoint(time, new LegacySampleControlPoint diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index b1383c9e85..03c63ff4f2 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -10,7 +10,6 @@ using System.IO; using System.Linq; using System.Text; using JetBrains.Annotations; -using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Legacy; @@ -186,18 +185,18 @@ namespace osu.Game.Beatmaps.Formats SampleControlPoint lastRelevantSamplePoint = null; DifficultyControlPoint lastRelevantDifficultyPoint = null; + // In osu!taiko and osu!mania, a scroll speed is stored as "slider velocity" in legacy formats. + // In that case, a scrolling speed change is a global effect and per-hit object difficulty control points are ignored. + bool scrollSpeedEncodedAsSliderVelocity = onlineRulesetID == 1 || onlineRulesetID == 3; + // iterate over hitobjects and pull out all required sample and difficulty changes extractDifficultyControlPoints(beatmap.HitObjects); extractSampleControlPoints(beatmap.HitObjects); - foreach (var point in legacyControlPoints.EffectPoints) + if (scrollSpeedEncodedAsSliderVelocity) { - DifficultyControlPoint difficultyPoint = legacyControlPoints.DifficultyPointAt(point.Time); - - if (Precision.AlmostEquals(difficultyPoint.SliderVelocity, point.ScrollSpeed, acceptableDifference: point.ScrollSpeedBindable.Precision)) - continue; - - legacyControlPoints.Add(point.Time, new DifficultyControlPoint { SliderVelocity = point.ScrollSpeed }); + foreach (var point in legacyControlPoints.EffectPoints) + legacyControlPoints.Add(point.Time, new DifficultyControlPoint { SliderVelocity = point.ScrollSpeed }); } foreach (var group in legacyControlPoints.Groups) @@ -245,6 +244,9 @@ namespace osu.Game.Beatmaps.Formats IEnumerable collectDifficultyControlPoints(IEnumerable hitObjects) { + if (scrollSpeedEncodedAsSliderVelocity) + yield break; + foreach (var hitObject in hitObjects) yield return hitObject.DifficultyControlPoint; } From d5c88cca8c5ba9bde038cf5c5a47fab70293000f Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Thu, 27 Oct 2022 07:29:36 +0200 Subject: [PATCH 1897/2686] Fix result of merge conflict --- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 9c50c06cb7..5f0a2a0824 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -450,8 +450,6 @@ namespace osu.Game.Beatmaps.Formats OmitFirstBarLine = omitFirstBarSignature, }; - int onlineRulesetID = beatmap.BeatmapInfo.Ruleset.OnlineID; - // osu!taiko and osu!mania use effect points rather than difficulty points for scroll speed adjustments. if (onlineRulesetID == 1 || onlineRulesetID == 3) effectPoint.ScrollSpeed = speedMultiplier; From 4127aaa9882c3b2007849e982b9fcc1d0b551ec4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 27 Oct 2022 14:34:24 +0900 Subject: [PATCH 1898/2686] Extract general elements from HubClientConnector into SocketClientConnector --- osu.Game/Online/HubClient.cs | 28 ++++ osu.Game/Online/HubClientConnector.cs | 161 +------------------- osu.Game/Online/SocketClient.cs | 24 +++ osu.Game/Online/SocketClientConnector.cs | 183 +++++++++++++++++++++++ 4 files changed, 242 insertions(+), 154 deletions(-) create mode 100644 osu.Game/Online/HubClient.cs create mode 100644 osu.Game/Online/SocketClient.cs create mode 100644 osu.Game/Online/SocketClientConnector.cs diff --git a/osu.Game/Online/HubClient.cs b/osu.Game/Online/HubClient.cs new file mode 100644 index 0000000000..262e298f34 --- /dev/null +++ b/osu.Game/Online/HubClient.cs @@ -0,0 +1,28 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR.Client; + +namespace osu.Game.Online +{ + public class HubClient : SocketClient + { + public readonly HubConnection Connection; + + public HubClient(HubConnection connection) + { + Connection = connection; + Connection.Closed += InvokeClosed; + } + + public override Task StartAsync(CancellationToken cancellationToken) => Connection.StartAsync(cancellationToken); + + public override async ValueTask DisposeAsync() + { + await base.DisposeAsync().ConfigureAwait(false); + await Connection.DisposeAsync().ConfigureAwait(false); + } + } +} diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 6bfe09e911..33e9f92817 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -10,13 +10,11 @@ using Microsoft.AspNetCore.SignalR.Client; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using osu.Framework; -using osu.Framework.Bindables; -using osu.Framework.Logging; using osu.Game.Online.API; namespace osu.Game.Online { - public class HubClientConnector : IHubClientConnector + public class HubClientConnector : SocketClientConnector, IHubClientConnector { public const string SERVER_SHUTDOWN_MESSAGE = "Server is shutting down."; @@ -25,7 +23,6 @@ namespace osu.Game.Online ///
public Action? ConfigureConnection { get; set; } - private readonly string clientName; private readonly string endpoint; private readonly string versionHash; private readonly bool preferMessagePack; @@ -34,18 +31,7 @@ namespace osu.Game.Online /// /// The current connection opened by this connector. /// - public HubConnection? CurrentConnection { get; private set; } - - /// - /// Whether this is connected to the hub, use to access the connection, if this is true. - /// - public IBindable IsConnected => isConnected; - - private readonly Bindable isConnected = new Bindable(); - private readonly SemaphoreSlim connectionLock = new SemaphoreSlim(1); - private CancellationTokenSource connectCancelSource = new CancellationTokenSource(); - - private readonly IBindable apiState = new Bindable(); + public new HubConnection? CurrentConnection => ((HubClient?)base.CurrentConnection)?.Connection; /// /// Constructs a new . @@ -56,99 +42,16 @@ namespace osu.Game.Online /// The hash representing the current game version, used for verification purposes. /// Whether to use MessagePack for serialisation if available on this platform. public HubClientConnector(string clientName, string endpoint, IAPIProvider api, string versionHash, bool preferMessagePack = true) + : base(api) { - this.clientName = clientName; + ClientName = clientName; this.endpoint = endpoint; this.api = api; this.versionHash = versionHash; this.preferMessagePack = preferMessagePack; - - apiState.BindTo(api.State); - apiState.BindValueChanged(_ => Task.Run(connectIfPossible), true); } - public Task Reconnect() - { - Logger.Log($"{clientName} reconnecting...", LoggingTarget.Network); - return Task.Run(connectIfPossible); - } - - private async Task connectIfPossible() - { - switch (apiState.Value) - { - case APIState.Failing: - case APIState.Offline: - await disconnect(true); - break; - - case APIState.Online: - await connect(); - break; - } - } - - private async Task connect() - { - cancelExistingConnect(); - - if (!await connectionLock.WaitAsync(10000).ConfigureAwait(false)) - throw new TimeoutException("Could not obtain a lock to connect. A previous attempt is likely stuck."); - - try - { - while (apiState.Value == APIState.Online) - { - // ensure any previous connection was disposed. - // this will also create a new cancellation token source. - await disconnect(false).ConfigureAwait(false); - - // this token will be valid for the scope of this connection. - // if cancelled, we can be sure that a disconnect or reconnect is handled elsewhere. - var cancellationToken = connectCancelSource.Token; - - cancellationToken.ThrowIfCancellationRequested(); - - Logger.Log($"{clientName} connecting...", LoggingTarget.Network); - - try - { - // importantly, rebuild the connection each attempt to get an updated access token. - CurrentConnection = buildConnection(cancellationToken); - - await CurrentConnection.StartAsync(cancellationToken).ConfigureAwait(false); - - Logger.Log($"{clientName} connected!", LoggingTarget.Network); - isConnected.Value = true; - return; - } - catch (OperationCanceledException) - { - //connection process was cancelled. - throw; - } - catch (Exception e) - { - await handleErrorAndDelay(e, cancellationToken).ConfigureAwait(false); - } - } - } - finally - { - connectionLock.Release(); - } - } - - /// - /// Handles an exception and delays an async flow. - /// - private async Task handleErrorAndDelay(Exception exception, CancellationToken cancellationToken) - { - Logger.Log($"{clientName} connect attempt failed: {exception.Message}", LoggingTarget.Network); - await Task.Delay(5000, cancellationToken).ConfigureAwait(false); - } - - private HubConnection buildConnection(CancellationToken cancellationToken) + protected override Task BuildConnectionAsync(CancellationToken cancellationToken) { var builder = new HubConnectionBuilder() .WithUrl(endpoint, options => @@ -188,59 +91,9 @@ namespace osu.Game.Online ConfigureConnection?.Invoke(newConnection); - newConnection.Closed += ex => onConnectionClosed(ex, cancellationToken); - return newConnection; + return Task.FromResult((SocketClient)new HubClient(newConnection)); } - private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) - { - isConnected.Value = false; - - if (ex != null) - await handleErrorAndDelay(ex, cancellationToken).ConfigureAwait(false); - else - Logger.Log($"{clientName} disconnected", LoggingTarget.Network); - - // make sure a disconnect wasn't triggered (and this is still the active connection). - if (!cancellationToken.IsCancellationRequested) - await Task.Run(connect, default).ConfigureAwait(false); - } - - private async Task disconnect(bool takeLock) - { - cancelExistingConnect(); - - if (takeLock) - { - if (!await connectionLock.WaitAsync(10000).ConfigureAwait(false)) - throw new TimeoutException("Could not obtain a lock to disconnect. A previous attempt is likely stuck."); - } - - try - { - if (CurrentConnection != null) - await CurrentConnection.DisposeAsync().ConfigureAwait(false); - } - finally - { - CurrentConnection = null; - if (takeLock) - connectionLock.Release(); - } - } - - private void cancelExistingConnect() - { - connectCancelSource.Cancel(); - connectCancelSource = new CancellationTokenSource(); - } - - public override string ToString() => $"Connector for {clientName} ({(IsConnected.Value ? "connected" : "not connected")}"; - - public void Dispose() - { - apiState.UnbindAll(); - cancelExistingConnect(); - } + protected override string ClientName { get; } } } diff --git a/osu.Game/Online/SocketClient.cs b/osu.Game/Online/SocketClient.cs new file mode 100644 index 0000000000..3b4aa1b49b --- /dev/null +++ b/osu.Game/Online/SocketClient.cs @@ -0,0 +1,24 @@ +// 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.Threading; +using System.Threading.Tasks; + +namespace osu.Game.Online +{ + public abstract class SocketClient : IAsyncDisposable + { + public event Func? Closed; + + protected Task InvokeClosed(Exception? exception) => Closed?.Invoke(exception) ?? Task.CompletedTask; + + public abstract Task StartAsync(CancellationToken cancellationToken); + + public virtual ValueTask DisposeAsync() + { + Closed = null; + return new ValueTask(Task.CompletedTask); + } + } +} diff --git a/osu.Game/Online/SocketClientConnector.cs b/osu.Game/Online/SocketClientConnector.cs new file mode 100644 index 0000000000..823e724ef9 --- /dev/null +++ b/osu.Game/Online/SocketClientConnector.cs @@ -0,0 +1,183 @@ +// 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.Threading; +using System.Threading.Tasks; +using osu.Framework.Bindables; +using osu.Framework.Extensions.TypeExtensions; +using osu.Framework.Graphics; +using osu.Framework.Logging; +using osu.Game.Online.API; + +namespace osu.Game.Online +{ + public abstract class SocketClientConnector : Component + { + /// + /// Whether this is connected to the hub, use to access the connection, if this is true. + /// + public IBindable IsConnected => isConnected; + + /// + /// The current connection opened by this connector. + /// + public SocketClient? CurrentConnection { get; private set; } + + private readonly Bindable isConnected = new Bindable(); + private readonly SemaphoreSlim connectionLock = new SemaphoreSlim(1); + private CancellationTokenSource connectCancelSource = new CancellationTokenSource(); + + private readonly IBindable apiState = new Bindable(); + + /// + /// Constructs a new . + /// + /// An API provider used to react to connection state changes. + protected SocketClientConnector(IAPIProvider api) + { + apiState.BindTo(api.State); + apiState.BindValueChanged(_ => Task.Run(connectIfPossible), true); + } + + public Task Reconnect() + { + Logger.Log($"{ClientName} reconnecting...", LoggingTarget.Network); + return Task.Run(connectIfPossible); + } + + private async Task connectIfPossible() + { + switch (apiState.Value) + { + case APIState.Failing: + case APIState.Offline: + await disconnect(true); + break; + + case APIState.Online: + await connect(); + break; + } + } + + private async Task connect() + { + cancelExistingConnect(); + + if (!await connectionLock.WaitAsync(10000).ConfigureAwait(false)) + throw new TimeoutException("Could not obtain a lock to connect. A previous attempt is likely stuck."); + + try + { + while (apiState.Value == APIState.Online) + { + // ensure any previous connection was disposed. + // this will also create a new cancellation token source. + await disconnect(false).ConfigureAwait(false); + + // this token will be valid for the scope of this connection. + // if cancelled, we can be sure that a disconnect or reconnect is handled elsewhere. + var cancellationToken = connectCancelSource.Token; + + cancellationToken.ThrowIfCancellationRequested(); + + Logger.Log($"{ClientName} connecting...", LoggingTarget.Network); + + try + { + // importantly, rebuild the connection each attempt to get an updated access token. + CurrentConnection = await BuildConnectionAsync(cancellationToken).ConfigureAwait(false); + CurrentConnection.Closed += ex => onConnectionClosed(ex, cancellationToken); + + cancellationToken.ThrowIfCancellationRequested(); + + await CurrentConnection.StartAsync(cancellationToken).ConfigureAwait(false); + + Logger.Log($"{ClientName} connected!", LoggingTarget.Network); + isConnected.Value = true; + return; + } + catch (OperationCanceledException) + { + //connection process was cancelled. + throw; + } + catch (Exception e) + { + await handleErrorAndDelay(e, cancellationToken).ConfigureAwait(false); + } + } + } + finally + { + connectionLock.Release(); + } + } + + /// + /// Handles an exception and delays an async flow. + /// + private async Task handleErrorAndDelay(Exception exception, CancellationToken cancellationToken) + { + Logger.Log($"{ClientName} connect attempt failed: {exception.Message}", LoggingTarget.Network); + await Task.Delay(5000, cancellationToken).ConfigureAwait(false); + } + + protected abstract Task BuildConnectionAsync(CancellationToken cancellationToken); + + private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) + { + isConnected.Value = false; + + if (ex != null) + await handleErrorAndDelay(ex, cancellationToken).ConfigureAwait(false); + else + Logger.Log($"{ClientName} disconnected", LoggingTarget.Network); + + // make sure a disconnect wasn't triggered (and this is still the active connection). + if (!cancellationToken.IsCancellationRequested) + await Task.Run(connect, default).ConfigureAwait(false); + } + + private async Task disconnect(bool takeLock) + { + cancelExistingConnect(); + + if (takeLock) + { + if (!await connectionLock.WaitAsync(10000).ConfigureAwait(false)) + throw new TimeoutException("Could not obtain a lock to disconnect. A previous attempt is likely stuck."); + } + + try + { + if (CurrentConnection != null) + await CurrentConnection.DisposeAsync().ConfigureAwait(false); + } + finally + { + CurrentConnection = null; + if (takeLock) + connectionLock.Release(); + } + } + + private void cancelExistingConnect() + { + connectCancelSource.Cancel(); + connectCancelSource = new CancellationTokenSource(); + } + + protected virtual string ClientName => GetType().ReadableName(); + + public override string ToString() => $"{ClientName} ({(IsConnected.Value ? "connected" : "not connected")})"; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + apiState.UnbindAll(); + cancelExistingConnect(); + } + } +} From 097d310d7464056893d2baba9c1a23a3dac0ccfa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 Oct 2022 14:40:14 +0900 Subject: [PATCH 1899/2686] Only draw path visualiser when hovered or single slider is selected --- .../Sliders/SliderSelectionBlueprint.cs | 51 +++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 265a1d21b1..9716f2820f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -59,6 +59,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private readonly BindableList controlPoints = new BindableList(); private readonly IBindable pathVersion = new Bindable(); + private BindableList selectedObjects; public SliderSelectionBlueprint(Slider slider) : base(slider) @@ -86,6 +87,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders pathVersion.BindValueChanged(_ => editorBeatmap?.Update(HitObject)); BodyPiece.UpdateFrom(HitObject); + + selectedObjects = editorBeatmap.SelectedHitObjects.GetBoundCopy(); + selectedObjects.BindCollectionChanged((_, _) => updateVisualDefinition()); } public override bool HandleQuickDeletion() @@ -108,14 +112,21 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders BodyPiece.UpdateFrom(HitObject); } + protected override bool OnHover(HoverEvent e) + { + updateVisualDefinition(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + updateVisualDefinition(); + base.OnHoverLost(e); + } + protected override void OnSelected() { - AddInternal(ControlPointVisualiser = new PathControlPointVisualiser(HitObject, true) - { - RemoveControlPointsRequested = removeControlPoints, - SplitControlPointsRequested = splitControlPoints - }); - + updateVisualDefinition(); base.OnSelected(); } @@ -123,13 +134,33 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { base.OnDeselected(); - // throw away frame buffers on deselection. - ControlPointVisualiser?.Expire(); - ControlPointVisualiser = null; - + updateVisualDefinition(); BodyPiece.RecyclePath(); } + private void updateVisualDefinition() + { + bool hasSingleObjectSelected = editorBeatmap.SelectedHitObjects.Count == 1; + + // To reduce overhead of drawing these blueprints, only add extra detail when hovered or when only this slider is selected. + if (IsSelected && (hasSingleObjectSelected || IsHovered)) + { + if (ControlPointVisualiser == null) + { + AddInternal(ControlPointVisualiser = new PathControlPointVisualiser(HitObject, true) + { + RemoveControlPointsRequested = removeControlPoints, + SplitControlPointsRequested = splitControlPoints + }); + } + } + else + { + ControlPointVisualiser?.Expire(); + ControlPointVisualiser = null; + } + } + private Vector2 rightClickPosition; protected override bool OnMouseDown(MouseDownEvent e) From 2f172b66cf80290ee3b9bfd3d4c8d971f342d05c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 Oct 2022 14:52:46 +0900 Subject: [PATCH 1900/2686] Block hover if a multi-selection is made to avoid overlapping path visualisers --- .../Blueprints/Sliders/SliderSelectionBlueprint.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 9716f2820f..ab164028b1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -104,6 +104,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders return true; } + private bool hasSingleObjectSelected => editorBeatmap.SelectedHitObjects.Count == 1; + protected override void Update() { base.Update(); @@ -115,7 +117,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders protected override bool OnHover(HoverEvent e) { updateVisualDefinition(); - return base.OnHover(e); + + // In the case more than a single object is selected, block hover from arriving at sliders behind this one. + // Without doing this, the path visualisers of potentially hundreds of sliders will render, which is not only + // visually noisy but also functionally useless. + return !hasSingleObjectSelected; } protected override void OnHoverLost(HoverLostEvent e) @@ -140,8 +146,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void updateVisualDefinition() { - bool hasSingleObjectSelected = editorBeatmap.SelectedHitObjects.Count == 1; - // To reduce overhead of drawing these blueprints, only add extra detail when hovered or when only this slider is selected. if (IsSelected && (hasSingleObjectSelected || IsHovered)) { From 6cca3a3dc82cb2b7972c8232d00aa6dcf119be96 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 27 Oct 2022 14:55:24 +0900 Subject: [PATCH 1901/2686] Add new API requests --- .../Online/API/Requests/ChatAckRequest.cs | 21 +++++++++++ .../API/Requests/GetNotificationsRequest.cs | 12 ++++++ .../API/Requests/Responses/APINotification.cs | 37 +++++++++++++++++++ .../Responses/APINotificationsBundle.cs | 20 ++++++++++ .../API/Requests/Responses/ChatAckResponse.cs | 15 ++++++++ .../API/Requests/Responses/ChatSilence.cs | 17 +++++++++ 6 files changed, 122 insertions(+) create mode 100644 osu.Game/Online/API/Requests/ChatAckRequest.cs create mode 100644 osu.Game/Online/API/Requests/GetNotificationsRequest.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APINotification.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APINotificationsBundle.cs create mode 100644 osu.Game/Online/API/Requests/Responses/ChatAckResponse.cs create mode 100644 osu.Game/Online/API/Requests/Responses/ChatSilence.cs diff --git a/osu.Game/Online/API/Requests/ChatAckRequest.cs b/osu.Game/Online/API/Requests/ChatAckRequest.cs new file mode 100644 index 0000000000..f09df4908e --- /dev/null +++ b/osu.Game/Online/API/Requests/ChatAckRequest.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Net.Http; +using osu.Framework.IO.Network; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class ChatAckRequest : APIRequest + { + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Post; + return req; + } + + protected override string Target => "chat/ack"; + } +} diff --git a/osu.Game/Online/API/Requests/GetNotificationsRequest.cs b/osu.Game/Online/API/Requests/GetNotificationsRequest.cs new file mode 100644 index 0000000000..e419807a85 --- /dev/null +++ b/osu.Game/Online/API/Requests/GetNotificationsRequest.cs @@ -0,0 +1,12 @@ +// 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.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetNotificationsRequest : APIRequest + { + protected override string Target => "notifications"; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APINotification.cs b/osu.Game/Online/API/Requests/Responses/APINotification.cs new file mode 100644 index 0000000000..e1f0fa7221 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APINotification.cs @@ -0,0 +1,37 @@ +// 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 Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + [JsonObject(MemberSerialization.OptIn)] + public class APINotification + { + [JsonProperty("id")] + public long Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } = null!; + + [JsonProperty("created_at")] + public DateTimeOffset? CreatedAt { get; set; } + + [JsonProperty("object_type")] + public string ObjectType { get; set; } = null!; + + [JsonProperty("object_id")] + public string ObjectId { get; set; } = null!; + + [JsonProperty("source_user_id")] + public long? SourceUserId { get; set; } + + [JsonProperty("is_read")] + public bool IsRead { get; set; } + + [JsonProperty("details")] + public Dictionary? Details { get; set; } + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APINotificationsBundle.cs b/osu.Game/Online/API/Requests/Responses/APINotificationsBundle.cs new file mode 100644 index 0000000000..067f1066b3 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APINotificationsBundle.cs @@ -0,0 +1,20 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + [JsonObject(MemberSerialization.OptIn)] + public class APINotificationsBundle + { + [JsonProperty("has_more")] + public bool HasMore { get; set; } + + [JsonProperty("notifications")] + public APINotification[] Notifications { get; set; } = null!; + + [JsonProperty("notification_endpoint")] + public string Endpoint { get; set; } = null!; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/ChatAckResponse.cs b/osu.Game/Online/API/Requests/Responses/ChatAckResponse.cs new file mode 100644 index 0000000000..6ed22a19b2 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/ChatAckResponse.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 System.Collections.Generic; +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + [JsonObject(MemberSerialization.OptIn)] + public class ChatAckResponse + { + [JsonProperty("silences")] + public List Silences { get; set; } = null!; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/ChatSilence.cs b/osu.Game/Online/API/Requests/Responses/ChatSilence.cs new file mode 100644 index 0000000000..45fd6e1ba3 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/ChatSilence.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; + +namespace osu.Game.Online.API.Requests.Responses +{ + [JsonObject(MemberSerialization.OptIn)] + public class ChatSilence + { + [JsonProperty("id")] + public uint Id { get; set; } + + [JsonProperty("user_id")] + public uint UserId { get; set; } + } +} From 0c7672e1248b190686a2d69b58e9f3612f1884e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 Oct 2022 16:02:04 +0900 Subject: [PATCH 1902/2686] Avoid unnecessarily refreshing `SliderBodyPiece`'s path --- .../Sliders/Components/SliderBodyPiece.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index bb967a0a76..da2a6ced67 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -40,16 +40,23 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components body.BorderColour = colours.Yellow; } + private int? lastVersion; + public override void UpdateFrom(Slider hitObject) { base.UpdateFrom(hitObject); body.PathRadius = hitObject.Scale * OsuHitObject.OBJECT_RADIUS; - var vertices = new List(); - hitObject.Path.GetPathToProgress(vertices, 0, 1); + if (lastVersion != hitObject.Path.Version.Value) + { + lastVersion = hitObject.Path.Version.Value; - body.SetVertices(vertices); + var vertices = new List(); + hitObject.Path.GetPathToProgress(vertices, 0, 1); + + body.SetVertices(vertices); + } Size = body.Size; OriginPosition = body.PathOffset; From 39e0362db13a96bed21f265bcb5ae94c87e28097 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 Oct 2022 16:15:22 +0900 Subject: [PATCH 1903/2686] Reduce size of spinner blueprint to better represent gameplay size --- .../Spinners/Components/SpinnerPiece.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index 28690ee0b7..2b1bb5185c 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -16,8 +16,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components { public class SpinnerPiece : BlueprintPiece { - private readonly CircularContainer circle; - private readonly RingPiece ring; + private readonly Circle circle; + private readonly Circle ring; public SpinnerPiece() { @@ -25,18 +25,21 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components RelativeSizeAxes = Axes.Both; FillMode = FillMode.Fit; - Size = new Vector2(1.3f); + Size = new Vector2(1); InternalChildren = new Drawable[] { - circle = new CircularContainer + circle = new Circle { RelativeSizeAxes = Axes.Both, - Masking = true, Alpha = 0.5f, - Child = new Box { RelativeSizeAxes = Axes.Both } }, - ring = new RingPiece() + ring = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(OsuHitObject.OBJECT_RADIUS), + }, }; } From 68d1febe6e9b5939f1f32a112b4c81f1567b1771 Mon Sep 17 00:00:00 2001 From: nullium21 Date: Thu, 27 Oct 2022 10:33:50 +0300 Subject: [PATCH 1904/2686] Use a regex for matching invalid characters instead What the regex does is it matches everything except alphanumeric and [_()[] -], excluding EOL since regex101 seems to also match it, and we probably don't want that to happen. --- osu.Game/Extensions/ModelExtensions.cs | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/osu.Game/Extensions/ModelExtensions.cs b/osu.Game/Extensions/ModelExtensions.cs index 51bea02726..8acc079805 100644 --- a/osu.Game/Extensions/ModelExtensions.cs +++ b/osu.Game/Extensions/ModelExtensions.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.IO; +using System.Text.RegularExpressions; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.IO; @@ -136,34 +137,14 @@ namespace osu.Game.Extensions return instance.OnlineID.Equals(other.OnlineID); } - private static bool isValidFilenameChar(this char ch) - { - if (ch >= '0' && ch <= '9') - return true; - - if (ch >= 'A' && ch <= 'Z') - return true; - - if (ch >= 'a' && ch <= 'z') - return true; - - return "-_()[]".Contains(ch); - } + private static Regex invalid_filename_chars = new(@"(?!$)[^A-Za-z0-9_()[\] -]", RegexOptions.Compiled); /// /// Get a valid filename for use inside a zip file. Avoids backslashes being incorrectly converted to directories. /// public static string GetValidArchiveContentFilename(this string filename) { - char[] resultData = filename.ToCharArray(); - - for (int i = 0; i < resultData.Length; i++) - { - if (!isValidFilenameChar(resultData[i])) - resultData[i] = '_'; - } - - return new string(resultData); + return invalid_filename_chars.Replace(filename, "_"); } } } From d48f95cf7c0f317c6b532e9d455b592e9a521fb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 Oct 2022 13:16:15 +0900 Subject: [PATCH 1905/2686] Use shader based implementation instead of sprites --- .../Skinning/Argon/ArgonDropletPiece.cs | 37 ++++++++++--------- .../Skinning/Argon/ArgonFruitPiece.cs | 36 ++++++++++-------- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs index c607b96729..63a41edaf7 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs @@ -5,8 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Utils; using osu.Game.Rulesets.Catch.Skinning.Default; using osu.Game.Rulesets.Catch.UI; @@ -25,11 +24,13 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon private float rotationRandomness; [BackgroundDependencyLoader] - private void load(TextureStore textures) + private void load() { RelativeSizeAxes = Axes.Both; - const float droplet_scale_down = 0.5f; + const float droplet_scale_down = 0.7f; + + int largeBlobSeed = RNG.Next(); InternalChildren = new[] { @@ -47,38 +48,42 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new Sprite + new CircularBlob { Anchor = Anchor.Centre, Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, + InnerRadius = 0.5f, Alpha = 0.15f, - Texture = getTexture("A") + Seed = largeBlobSeed }, - new Sprite + new CircularBlob { Anchor = Anchor.Centre, Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, + InnerRadius = 0.4f, Alpha = 0.5f, - Scale = new Vector2(0.8f), - Texture = getTexture("A") + Scale = new Vector2(0.7f), + Seed = RNG.Next() }, } }, - hyperBorderPiece = new Sprite + hyperBorderPiece = new CircularBlob { Scale = new Vector2(droplet_scale_down), Anchor = Anchor.Centre, Origin = Anchor.Centre, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR, + RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, + InnerRadius = 0.5f, Alpha = 0.15f, - Texture = getTexture("A"), + Seed = largeBlobSeed }, }; - - Texture getTexture(string type) => textures.Get($"Gameplay/catch/blob-{type}{RNG.Next(1, 7)}"); } protected override void LoadComplete() @@ -106,10 +111,8 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon for (int i = 0; i < layers.Count; i++) { layers[i].Rotation -= - // Layers are ordered from largest to smallest. Smaller layers should rotate more. - (i * 4) - * (float)Clock.ElapsedFrameTime - * 0.2f * rotationRandomness + (float)Clock.ElapsedFrameTime + * 0.4f * rotationRandomness // Each layer should alternate rotation direction. * (i % 2 == 1 ? 0.5f : 1); } diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs index 2412de7dbe..28538d48b3 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs @@ -5,8 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Utils; using osu.Game.Rulesets.Catch.Skinning.Default; using osu.Game.Rulesets.Catch.UI; @@ -25,11 +24,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon private float rotationRandomness; [BackgroundDependencyLoader] - private void load(TextureStore textures) + private void load() { RelativeSizeAxes = Axes.Both; - Texture largeTexture = getTexture("A"); + int largeBlobSeed = RNG.Next(); InternalChildren = new[] { @@ -44,43 +43,50 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new Sprite + new CircularBlob { Anchor = Anchor.Centre, Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, Alpha = 0.15f, - Texture = largeTexture + InnerRadius = 0.5f, + Size = new Vector2(1.1f), + Seed = largeBlobSeed, }, - new Sprite + new CircularBlob { Anchor = Anchor.Centre, Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, + InnerRadius = 0.2f, Alpha = 0.5f, - Texture = getTexture("B") + Seed = RNG.Next(), }, - new Sprite + new CircularBlob { Anchor = Anchor.Centre, Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, - Texture = getTexture("C") + InnerRadius = 0.05f, + Seed = RNG.Next(), }, } }, - hyperBorderPiece = new Sprite + hyperBorderPiece = new CircularBlob { Anchor = Anchor.Centre, Origin = Anchor.Centre, Colour = Catcher.DEFAULT_HYPER_DASH_COLOUR, + RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, - Alpha = 0.15f, - Texture = largeTexture, + InnerRadius = 0.08f, + Size = new Vector2(1.15f), + Seed = largeBlobSeed }, }; - - Texture getTexture(string type) => textures.Get($"Gameplay/catch/blob-{type}{RNG.Next(1, 7)}"); } protected override void LoadComplete() From 6fe8298152db01184197632997a2c0247fd90ac0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 Oct 2022 19:02:01 +0900 Subject: [PATCH 1906/2686] 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 f251e8ee71..5d6c32cea8 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 22474c0592..5d1a834b0e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index cf70b65578..bf218f856a 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 3c4ba6e9fcd596a6fa0d894c47d8ee5d92f073bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 Oct 2022 19:02:32 +0900 Subject: [PATCH 1907/2686] Fix `SoloScoreInfo.Rank` not being serialised if rank is `D` --- osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 4469d50acb..2095b2c700 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -45,6 +46,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonConverter(typeof(StringEnumConverter))] [JsonProperty("rank")] + // ScoreRank is aligned to make 0 equal D. We still want to serialise this (even when DefaultValueHandling.Ignore is used), + // so set the default to an impossible value. + [DefaultValue(null)] public ScoreRank Rank { get; set; } [JsonProperty("started_at")] From 361153f598c34072b009cd91860dc2470917925a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 27 Oct 2022 19:05:50 +0900 Subject: [PATCH 1908/2686] Fix nullref in tests due to missing `EditorBeatmap` dependency --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index ab164028b1..0b0a76cce0 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -104,7 +104,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders return true; } - private bool hasSingleObjectSelected => editorBeatmap.SelectedHitObjects.Count == 1; + private bool hasSingleObjectSelected => editorBeatmap == null || editorBeatmap.SelectedHitObjects.Count == 1; protected override void Update() { From e582d9d5a8720928e03a792a9b92dc91fbd54baf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 01:17:09 +0900 Subject: [PATCH 1909/2686] Remove unused using statements --- .../Edit/Blueprints/Spinners/Components/SpinnerPiece.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index 2b1bb5185c..b5a13a22ce 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -5,11 +5,9 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components From 7faf5cd1f6f7962002162dafc463037e0e2011e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 01:20:17 +0900 Subject: [PATCH 1910/2686] Fix one more null edge case --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 0b0a76cce0..b5b04823a7 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private readonly BindableList controlPoints = new BindableList(); private readonly IBindable pathVersion = new Bindable(); - private BindableList selectedObjects; + private readonly BindableList selectedObjects = new BindableList(); public SliderSelectionBlueprint(Slider slider) : base(slider) @@ -88,7 +88,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders BodyPiece.UpdateFrom(HitObject); - selectedObjects = editorBeatmap.SelectedHitObjects.GetBoundCopy(); + if (editorBeatmap != null) + selectedObjects.BindTo(editorBeatmap.SelectedHitObjects); selectedObjects.BindCollectionChanged((_, _) => updateVisualDefinition()); } @@ -104,7 +105,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders return true; } - private bool hasSingleObjectSelected => editorBeatmap == null || editorBeatmap.SelectedHitObjects.Count == 1; + private bool hasSingleObjectSelected => editorBeatmap == null || selectedObjects.Count == 1; protected override void Update() { From dcff8a193cf1f206d614cb59e8092801b0d050c9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 01:26:10 +0900 Subject: [PATCH 1911/2686] Use better method of forcing serialisation --- osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 2095b2c700..57586e3d77 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -45,10 +44,8 @@ namespace osu.Game.Online.API.Requests.Responses public int MaxCombo { get; set; } [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("rank")] - // ScoreRank is aligned to make 0 equal D. We still want to serialise this (even when DefaultValueHandling.Ignore is used), - // so set the default to an impossible value. - [DefaultValue(null)] + // ScoreRank is aligned to make 0 equal D. We still want to serialise this (even when DefaultValueHandling.Ignore is used). + [JsonProperty("rank", DefaultValueHandling = DefaultValueHandling.Include)] public ScoreRank Rank { get; set; } [JsonProperty("started_at")] From 446a9c1b05d5c98e89d85c699afa82338f9f7810 Mon Sep 17 00:00:00 2001 From: sw1tchbl4d3 Date: Thu, 27 Oct 2022 23:41:17 +0200 Subject: [PATCH 1912/2686] Make added effect points inherit previous effect point settings --- .../Beatmaps/TaikoBeatmapConverter.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index c1e1052569..3cc47deed0 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -65,17 +65,16 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps foreach (HitObject hitObject in original.HitObjects) { double nextScrollSpeed = hitObject.DifficultyControlPoint.SliderVelocity; + EffectControlPoint currentEffectPoint = converted.ControlPointInfo.EffectPointAt(hitObject.StartTime); - if (!Precision.AlmostEquals(lastScrollSpeed, nextScrollSpeed)) + if (!Precision.AlmostEquals(lastScrollSpeed, nextScrollSpeed, acceptableDifference: currentEffectPoint.ScrollSpeedBindable.Precision)) { - EffectControlPoint currentControlPoint = converted.ControlPointInfo.EffectPointAt(hitObject.StartTime); - - if (Precision.AlmostEquals(currentControlPoint.Time, hitObject.StartTime)) - currentControlPoint.ScrollSpeed = nextScrollSpeed; - else - converted.ControlPointInfo.Add(hitObject.StartTime, new EffectControlPoint { ScrollSpeed = nextScrollSpeed }); - - lastScrollSpeed = nextScrollSpeed; + converted.ControlPointInfo.Add(hitObject.StartTime, new EffectControlPoint + { + KiaiMode = currentEffectPoint.KiaiMode, + OmitFirstBarLine = currentEffectPoint.OmitFirstBarLine, + ScrollSpeed = lastScrollSpeed = nextScrollSpeed, + }); } } } From 9969c00ead98ccd88a3eb5f88d7c2357628a495c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 10:19:53 +0900 Subject: [PATCH 1913/2686] Apply two minor fixes from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs | 2 +- .../Skinning/Argon/CatchArgonSkinTransformer.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs index 63a41edaf7..267f8a06a3 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs @@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon layers[i].Rotation -= (float)Clock.ElapsedFrameTime * 0.4f * rotationRandomness - // Each layer should alternate rotation direction. + // Each layer should alternate rotation speed. * (i % 2 == 1 ? 0.5f : 1); } } diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs index 30542187f2..8dae0a2b78 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs @@ -17,9 +17,9 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { switch (component) { - case CatchSkinComponent osuComponent: + case CatchSkinComponent catchComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. - switch (osuComponent.Component) + switch (catchComponent.Component) { case CatchSkinComponents.HitExplosion: return new ArgonHitExplosion(); From 71970d83cf658add8dbe68cf15390da4f305d489 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 12:47:44 +0900 Subject: [PATCH 1914/2686] Remove obsoleted `ShowProgressGraph` global setting This was moved to the component itself. --- osu.Game/Configuration/OsuConfigManager.cs | 3 -- .../Screens/Play/HUD/DefaultSongProgress.cs | 48 ------------------- 2 files changed, 51 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 1378e1691a..825c345c0a 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -127,7 +127,6 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.HitLighting, true); SetDefault(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always); - SetDefault(OsuSetting.ShowProgressGraph, true); SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true); SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true); SetDefault(OsuSetting.KeyOverlay, false); @@ -302,8 +301,6 @@ namespace osu.Game.Configuration FloatingComments, HUDVisibilityMode, - // This has been migrated to the component itself. can be removed 20221027. - ShowProgressGraph, ShowHealthDisplayWhenCantFail, FadePlayfieldWhenHealthLow, MouseDisableButtons, diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index 30b420441c..45d0cf8462 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -9,7 +9,6 @@ using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; -using osu.Game.Skinning; using osuTK; namespace osu.Game.Screens.Play.HUD @@ -45,12 +44,6 @@ namespace osu.Game.Screens.Play.HUD [Resolved] private DrawableRuleset? drawableRuleset { get; set; } - [Resolved] - private OsuConfigManager config { get; set; } = null!; - - [Resolved] - private SkinManager skinManager { get; set; } = null!; - public DefaultSongProgress() { RelativeSizeAxes = Axes.X; @@ -100,47 +93,6 @@ namespace osu.Game.Screens.Play.HUD { AllowSeeking.BindValueChanged(_ => updateBarVisibility(), true); ShowGraph.BindValueChanged(_ => updateGraphVisibility(), true); - - migrateSettingFromConfig(); - } - - /// - /// This setting has been migrated to a per-component level. - /// Only take the value from the config if it is in a non-default state (then reset it to default so it only applies once). - /// - /// Can be removed 20221027. - /// - private void migrateSettingFromConfig() - { - Bindable configShowGraph = config.GetBindable(OsuSetting.ShowProgressGraph); - - if (!configShowGraph.IsDefault) - { - ShowGraph.Value = configShowGraph.Value; - - // This is pretty ugly, but the only way to make this stick... - var skinnableTarget = this.FindClosestParent(); - - if (skinnableTarget != null) - { - // If the skin is not mutable, a mutable instance will be created, causing this migration logic to run again on the correct skin. - // Therefore we want to avoid resetting the config value on this invocation. - if (skinManager.EnsureMutableSkin()) - return; - - // If `EnsureMutableSkin` actually changed the skin, default layout may take a frame to apply. - // See `SkinnableTargetComponentsContainer`'s use of ScheduleAfterChildren. - ScheduleAfterChildren(() => - { - var skin = skinManager.CurrentSkin.Value; - skin.UpdateDrawableTarget(skinnableTarget); - - skinManager.Save(skin); - }); - - configShowGraph.SetDefault(); - } - } } protected override void PopIn() From 29f504ecc031e8f930e639da5c8d4d7197fdc986 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 13:00:39 +0900 Subject: [PATCH 1915/2686] Remove obsoleted tournament migration flow --- .../NonVisual/CustomTourneyDirectoryTest.cs | 79 +----------------- ...eManager.cs => TournamentConfigManager.cs} | 13 ++- osu.Game.Tournament/IO/TournamentStorage.cs | 80 ++----------------- 3 files changed, 19 insertions(+), 153 deletions(-) rename osu.Game.Tournament/Configuration/{TournamentStorageManager.cs => TournamentConfigManager.cs} (55%) diff --git a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs index d314f40c30..f778e67f58 100644 --- a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs +++ b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tournament.Tests.NonVisual // manual cleaning so we can prepare a config file. storage.DeleteDirectory(string.Empty); - using (var storageConfig = new TournamentStorageManager(storage)) + using (var storageConfig = new TournamentConfigManager(storage)) storageConfig.SetValue(StorageConfig.CurrentTournament, custom_tournament); try @@ -66,82 +66,5 @@ namespace osu.Game.Tournament.Tests.NonVisual } } } - - [Test] - public void TestMigration() - { - using (HeadlessGameHost host = new TestRunHeadlessGameHost(nameof(TestMigration), null)) // don't use clean run as we are writing test files for migration. - { - string osuRoot = Path.Combine(host.UserStoragePaths.First(), nameof(TestMigration)); - string configFile = Path.Combine(osuRoot, "tournament.ini"); - - if (File.Exists(configFile)) - File.Delete(configFile); - - // Recreate the old setup that uses "tournament" as the base path. - string oldPath = Path.Combine(osuRoot, "tournament"); - - string videosPath = Path.Combine(oldPath, "Videos"); - string modsPath = Path.Combine(oldPath, "Mods"); - string flagsPath = Path.Combine(oldPath, "Flags"); - - Directory.CreateDirectory(videosPath); - Directory.CreateDirectory(modsPath); - Directory.CreateDirectory(flagsPath); - - // Define testing files corresponding to the specific file migrations that are needed - string bracketFile = Path.Combine(osuRoot, TournamentGameBase.BRACKET_FILENAME); - - string drawingsConfig = Path.Combine(osuRoot, "drawings.ini"); - string drawingsFile = Path.Combine(osuRoot, "drawings.txt"); - string drawingsResult = Path.Combine(osuRoot, "drawings_results.txt"); - - // Define sample files to test recursive copying - string videoFile = Path.Combine(videosPath, "video.mp4"); - string modFile = Path.Combine(modsPath, "mod.png"); - string flagFile = Path.Combine(flagsPath, "flag.png"); - - File.WriteAllText(bracketFile, "{}"); - File.WriteAllText(drawingsConfig, "test"); - File.WriteAllText(drawingsFile, "test"); - File.WriteAllText(drawingsResult, "test"); - File.WriteAllText(videoFile, "test"); - File.WriteAllText(modFile, "test"); - File.WriteAllText(flagFile, "test"); - - try - { - var osu = LoadTournament(host); - - var storage = osu.Dependencies.Get(); - - string migratedPath = Path.Combine(host.Storage.GetFullPath("."), "tournaments", "default"); - - videosPath = Path.Combine(migratedPath, "Videos"); - modsPath = Path.Combine(migratedPath, "Mods"); - flagsPath = Path.Combine(migratedPath, "Flags"); - - videoFile = Path.Combine(videosPath, "video.mp4"); - modFile = Path.Combine(modsPath, "mod.png"); - flagFile = Path.Combine(flagsPath, "flag.png"); - - Assert.That(storage.GetFullPath("."), Is.EqualTo(migratedPath)); - - Assert.True(storage.Exists(TournamentGameBase.BRACKET_FILENAME)); - Assert.True(storage.Exists("drawings.txt")); - Assert.True(storage.Exists("drawings_results.txt")); - - Assert.True(storage.Exists("drawings.ini")); - - Assert.True(storage.Exists(videoFile)); - Assert.True(storage.Exists(modFile)); - Assert.True(storage.Exists(flagFile)); - } - finally - { - host.Exit(); - } - } - } } } diff --git a/osu.Game.Tournament/Configuration/TournamentStorageManager.cs b/osu.Game.Tournament/Configuration/TournamentConfigManager.cs similarity index 55% rename from osu.Game.Tournament/Configuration/TournamentStorageManager.cs rename to osu.Game.Tournament/Configuration/TournamentConfigManager.cs index 0b9a556296..8f256ba9c3 100644 --- a/osu.Game.Tournament/Configuration/TournamentStorageManager.cs +++ b/osu.Game.Tournament/Configuration/TournamentConfigManager.cs @@ -8,14 +8,23 @@ using osu.Framework.Platform; namespace osu.Game.Tournament.Configuration { - public class TournamentStorageManager : IniConfigManager + public class TournamentConfigManager : IniConfigManager { protected override string Filename => "tournament.ini"; - public TournamentStorageManager(Storage storage) + private const string default_tournament = "default"; + + public TournamentConfigManager(Storage storage) : base(storage) { } + + protected override void InitialiseDefaults() + { + base.InitialiseDefaults(); + + SetDefault(StorageConfig.CurrentTournament, default_tournament); + } } public enum StorageConfig diff --git a/osu.Game.Tournament/IO/TournamentStorage.cs b/osu.Game.Tournament/IO/TournamentStorage.cs index bd52b6dfed..e59f90a45e 100644 --- a/osu.Game.Tournament/IO/TournamentStorage.cs +++ b/osu.Game.Tournament/IO/TournamentStorage.cs @@ -1,10 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; -using System.IO; using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Framework.Platform; @@ -13,35 +10,28 @@ using osu.Game.Tournament.Configuration; namespace osu.Game.Tournament.IO { - public class TournamentStorage : MigratableStorage + public class TournamentStorage : WrappedStorage { - private const string default_tournament = "default"; - private readonly Storage storage; - /// /// The storage where all tournaments are located. /// public readonly Storage AllTournaments; - private readonly TournamentStorageManager storageConfig; public readonly Bindable CurrentTournament; + protected TournamentConfigManager TournamentConfigManager { get; } + public TournamentStorage(Storage storage) : base(storage.GetStorageForDirectory("tournaments"), string.Empty) { - this.storage = storage; AllTournaments = UnderlyingStorage; - storageConfig = new TournamentStorageManager(storage); + TournamentConfigManager = new TournamentConfigManager(storage); - if (storage.Exists("tournament.ini")) - { - ChangeTargetStorage(AllTournaments.GetStorageForDirectory(storageConfig.Get(StorageConfig.CurrentTournament))); - } - else - Migrate(AllTournaments.GetStorageForDirectory(default_tournament)); + CurrentTournament = TournamentConfigManager.GetBindable(StorageConfig.CurrentTournament); + + ChangeTargetStorage(AllTournaments.GetStorageForDirectory(CurrentTournament.Value)); - CurrentTournament = storageConfig.GetBindable(StorageConfig.CurrentTournament); Logger.Log("Using tournament storage: " + GetFullPath(string.Empty)); CurrentTournament.BindValueChanged(updateTournament); @@ -53,62 +43,6 @@ namespace osu.Game.Tournament.IO Logger.Log("Changing tournament storage: " + GetFullPath(string.Empty)); } - protected override void ChangeTargetStorage(Storage newStorage) - { - // due to an unfortunate oversight, on OSes that are sensitive to pathname casing - // the custom flags directory needed to be named `Flags` (uppercase), - // while custom mods and videos directories needed to be named `mods` and `videos` respectively (lowercase). - // to unify handling to uppercase, move any non-compliant directories automatically for the user to migrate. - // can be removed 20220528 - if (newStorage.ExistsDirectory("flags")) - AttemptOperation(() => Directory.Move(newStorage.GetFullPath("flags"), newStorage.GetFullPath("Flags"))); - if (newStorage.ExistsDirectory("mods")) - AttemptOperation(() => Directory.Move(newStorage.GetFullPath("mods"), newStorage.GetFullPath("Mods"))); - if (newStorage.ExistsDirectory("videos")) - AttemptOperation(() => Directory.Move(newStorage.GetFullPath("videos"), newStorage.GetFullPath("Videos"))); - - base.ChangeTargetStorage(newStorage); - } - public IEnumerable ListTournaments() => AllTournaments.GetDirectories(string.Empty); - - public override bool Migrate(Storage newStorage) - { - // this migration only happens once on moving to the per-tournament storage system. - // listed files are those known at that point in time. - // this can be removed at some point in the future (6 months obsoletion would mean 2021-04-19) - - var source = new DirectoryInfo(storage.GetFullPath("tournament")); - var destination = new DirectoryInfo(newStorage.GetFullPath(".")); - - if (source.Exists) - { - Logger.Log("Migrating tournament assets to default tournament storage."); - CopyRecursive(source, destination); - DeleteRecursive(source); - } - - moveFileIfExists(TournamentGameBase.BRACKET_FILENAME, destination); - moveFileIfExists("drawings.txt", destination); - moveFileIfExists("drawings_results.txt", destination); - moveFileIfExists("drawings.ini", destination); - - ChangeTargetStorage(newStorage); - storageConfig.SetValue(StorageConfig.CurrentTournament, default_tournament); - storageConfig.Save(); - - return true; - } - - private void moveFileIfExists(string file, DirectoryInfo destination) - { - if (!storage.Exists(file)) - return; - - Logger.Log($"Migrating {file} to default tournament storage."); - var fileInfo = new System.IO.FileInfo(storage.GetFullPath(file)); - AttemptOperation(() => fileInfo.CopyTo(Path.Combine(destination.FullName, fileInfo.Name), true)); - fileInfo.Delete(); - } } } From 707b9eaa502368e085702387f90943780879db4e Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 28 Oct 2022 13:07:44 +0900 Subject: [PATCH 1916/2686] Remove unnecessary null-forgiving --- .../Difficulty/Evaluators/ColourEvaluator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index 36f8babc6b..9f63e84867 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -55,11 +55,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators double difficulty = 0.0d; if (colour.MonoStreak?.FirstHitObject == hitObject) // Difficulty for MonoStreak - difficulty += EvaluateDifficultyOf(colour.MonoStreak!); + difficulty += EvaluateDifficultyOf(colour.MonoStreak); if (colour.AlternatingMonoPattern?.FirstHitObject == hitObject) // Difficulty for AlternatingMonoPattern - difficulty += EvaluateDifficultyOf(colour.AlternatingMonoPattern!); + difficulty += EvaluateDifficultyOf(colour.AlternatingMonoPattern); if (colour.RepeatingHitPattern?.FirstHitObject == hitObject) // Difficulty for RepeatingHitPattern - difficulty += EvaluateDifficultyOf(colour.RepeatingHitPattern!); + difficulty += EvaluateDifficultyOf(colour.RepeatingHitPattern); return difficulty; } From 08832ae593b558c764af7bbfc5de636a965b1e34 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 13:09:28 +0900 Subject: [PATCH 1917/2686] Remove obsoleted `PositionalHitsounds` global setting --- osu.Game/Configuration/OsuConfigManager.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 825c345c0a..80034744de 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -118,7 +118,6 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.Prefer24HourTime, CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern.Contains(@"tt")); // Gameplay - SetDefault(OsuSetting.PositionalHitsounds, true); // replaced by level setting below, can be removed 20220703. SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1); SetDefault(OsuSetting.DimLevel, 0.7, 0, 1, 0.01); SetDefault(OsuSetting.BlurLevel, 0, 0, 1, 0.01); @@ -202,14 +201,11 @@ namespace osu.Game.Configuration if (!int.TryParse(pieces[0], out int year)) return; if (!int.TryParse(pieces[1], out int monthDay)) return; + // ReSharper disable once UnusedVariable int combined = (year * 10000) + monthDay; - if (combined < 20220103) - { - var positionalHitsoundsEnabled = GetBindable(OsuSetting.PositionalHitsounds); - if (!positionalHitsoundsEnabled.Value) - SetValue(OsuSetting.PositionalHitsoundsLevel, 0); - } + // migrations can be added here using a condition like: + // if (combined < 20220103) { performMigration() } } public override TrackedSettings CreateTrackedSettings() @@ -295,7 +291,6 @@ namespace osu.Game.Configuration ShowStoryboard, KeyOverlay, GameplayLeaderboard, - PositionalHitsounds, PositionalHitsoundsLevel, AlwaysPlayFirstComboBreak, FloatingComments, From 21f8a91efbd0bcd065e430314f065ab5e21ea16c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 13:12:18 +0900 Subject: [PATCH 1918/2686] Remove obsoleted `int` parsing logic of configuration ruleset --- osu.Game/OsuGame.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 2bdcb57f2a..0a5dd02cbd 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -280,10 +280,7 @@ namespace osu.Game configRuleset = LocalConfig.GetBindable(OsuSetting.Ruleset); uiScale = LocalConfig.GetBindable(OsuSetting.UIScale); - var preferredRuleset = int.TryParse(configRuleset.Value, out int rulesetId) - // int parsing can be removed 20220522 - ? RulesetStore.GetRuleset(rulesetId) - : RulesetStore.GetRuleset(configRuleset.Value); + var preferredRuleset = RulesetStore.GetRuleset(configRuleset.Value); try { From 42eafe318c132813b1abfbeac8126704fdd2d4fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 13:07:47 +0900 Subject: [PATCH 1919/2686] Remove various simple obsoletions --- osu.Game/Beatmaps/BeatmapInfo.cs | 8 --- osu.Game/Beatmaps/Formats/IHasComboColours.cs | 7 --- osu.Game/Beatmaps/Timing/TimeSignatures.cs | 20 -------- osu.Game/Configuration/DatabasedSetting.cs | 51 ------------------- osu.Game/Database/RealmAccess.cs | 12 +---- .../Mods/IApplicableToDrawableHitObjects.cs | 18 ------- osu.Game/Rulesets/Mods/ICreateReplay.cs | 22 -------- osu.Game/Rulesets/Mods/Mod.cs | 3 -- osu.Game/Rulesets/Mods/ModAutoplay.cs | 13 +---- .../Objects/Drawables/DrawableHitObject.cs | 12 ----- .../Ranking/Statistics/StatisticItem.cs | 6 --- osu.Game/Skinning/SkinConfiguration.cs | 2 - osu.Game/Skinning/SkinImporter.cs | 49 ------------------ 13 files changed, 2 insertions(+), 221 deletions(-) delete mode 100644 osu.Game/Beatmaps/Timing/TimeSignatures.cs delete mode 100644 osu.Game/Configuration/DatabasedSetting.cs delete mode 100644 osu.Game/Rulesets/Mods/IApplicableToDrawableHitObjects.cs delete mode 100644 osu.Game/Rulesets/Mods/ICreateReplay.cs diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 6f9df1ba7f..3208598f56 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -238,14 +238,6 @@ namespace osu.Game.Beatmaps #region Compatibility properties - [Ignored] - [Obsolete("Use BeatmapInfo.Difficulty instead.")] // can be removed 20220719 - public BeatmapDifficulty BaseDifficulty - { - get => Difficulty; - set => Difficulty = value; - } - [Ignored] public string? Path => File?.Filename; diff --git a/osu.Game/Beatmaps/Formats/IHasComboColours.cs b/osu.Game/Beatmaps/Formats/IHasComboColours.cs index d5e96da246..1d9cc0be65 100644 --- a/osu.Game/Beatmaps/Formats/IHasComboColours.cs +++ b/osu.Game/Beatmaps/Formats/IHasComboColours.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using System.Collections.Generic; using osuTK.Graphics; @@ -22,11 +21,5 @@ namespace osu.Game.Beatmaps.Formats /// if empty, will fall back to default combo colours. /// List CustomComboColours { get; } - - /// - /// Adds combo colours to the list. - /// - [Obsolete("Use CustomComboColours directly.")] // can be removed 20220215 - void AddComboColours(params Color4[] colours); } } diff --git a/osu.Game/Beatmaps/Timing/TimeSignatures.cs b/osu.Game/Beatmaps/Timing/TimeSignatures.cs deleted file mode 100644 index 95c971eebf..0000000000 --- a/osu.Game/Beatmaps/Timing/TimeSignatures.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using System; -using System.ComponentModel; - -namespace osu.Game.Beatmaps.Timing -{ - [Obsolete("Use osu.Game.Beatmaps.Timing.TimeSignature instead.")] - public enum TimeSignatures // can be removed 20220722 - { - [Description("4/4")] - SimpleQuadruple = 4, - - [Description("3/4")] - SimpleTriple = 3 - } -} diff --git a/osu.Game/Configuration/DatabasedSetting.cs b/osu.Game/Configuration/DatabasedSetting.cs deleted file mode 100644 index 0c1b4021a1..0000000000 --- a/osu.Game/Configuration/DatabasedSetting.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. - -#nullable disable - -using System.ComponentModel.DataAnnotations.Schema; -using osu.Game.Database; - -namespace osu.Game.Configuration -{ - [Table("Settings")] - public class DatabasedSetting : IHasPrimaryKey // can be removed 20220315. - { - public int ID { get; set; } - - public bool IsManaged => ID > 0; - - public int? RulesetID { get; set; } - - public int? Variant { get; set; } - - public int? SkinInfoID { get; set; } - - [Column("Key")] - public string Key { get; set; } - - [Column("Value")] - public string StringValue - { - get => Value.ToString(); - set => Value = value; - } - - public object Value; - - public DatabasedSetting(string key, object value) - { - Key = key; - Value = value; - } - - /// - /// Constructor for derived classes that may require serialisation. - /// - public DatabasedSetting() - { - } - - public override string ToString() => $"{Key}=>{Value}"; - } -} diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index edcd020226..1a938c12e5 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -857,17 +857,7 @@ namespace osu.Game.Database if (legacyCollectionImporter.GetAvailableCount(storage).GetResultSafely() > 0) { - legacyCollectionImporter.ImportFromStorage(storage).ContinueWith(task => - { - if (task.Exception != null) - { - // can be removed 20221027 (just for initial safety). - Logger.Error(task.Exception.InnerException, "Collections could not be migrated to realm. Please provide your \"collection.db\" to the dev team."); - return; - } - - storage.Move("collection.db", "collection.db.migrated"); - }); + legacyCollectionImporter.ImportFromStorage(storage).ContinueWith(_ => storage.Move("collection.db", "collection.db.migrated")); } break; diff --git a/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObjects.cs b/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObjects.cs deleted file mode 100644 index 7f926dd8b8..0000000000 --- a/osu.Game/Rulesets/Mods/IApplicableToDrawableHitObjects.cs +++ /dev/null @@ -1,18 +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 osu.Framework.Extensions.IEnumerableExtensions; -using osu.Game.Rulesets.Objects.Drawables; - -namespace osu.Game.Rulesets.Mods -{ - [Obsolete(@"Use the singular version IApplicableToDrawableHitObject instead.")] // Can be removed 20211216 - public interface IApplicableToDrawableHitObjects : IApplicableToDrawableHitObject - { - void ApplyToDrawableHitObjects(IEnumerable drawables); - - void IApplicableToDrawableHitObject.ApplyToDrawableHitObject(DrawableHitObject drawable) => ApplyToDrawableHitObjects(drawable.Yield()); - } -} diff --git a/osu.Game/Rulesets/Mods/ICreateReplay.cs b/osu.Game/Rulesets/Mods/ICreateReplay.cs deleted file mode 100644 index 1e5eeca92c..0000000000 --- a/osu.Game/Rulesets/Mods/ICreateReplay.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 System; -using System.Collections.Generic; -using osu.Game.Beatmaps; -using osu.Game.Scoring; - -namespace osu.Game.Rulesets.Mods -{ - [Obsolete("Use ICreateReplayData instead")] // Can be removed 20220929 - public interface ICreateReplay : ICreateReplayData - { - public Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods); - - ModReplayData ICreateReplayData.CreateReplayData(IBeatmap beatmap, IReadOnlyList mods) - { - var replayScore = CreateReplayScore(beatmap, mods); - return new ModReplayData(replayScore.Replay, new ModCreatedUser { Username = replayScore.ScoreInfo.User.Username }); - } - } -} diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index e4c91d3037..98df540de4 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -101,9 +101,6 @@ namespace osu.Game.Rulesets.Mods [JsonIgnore] public virtual bool ValidForMultiplayerAsFreeMod => true; - [Obsolete("Going forward, the concept of \"ranked\" doesn't exist. The only exceptions are automation mods, which should now override and set UserPlayable to false.")] // Can be removed 20211009 - public virtual bool Ranked => false; - /// /// Whether this mod requires configuration to apply changes to the game. /// diff --git a/osu.Game/Rulesets/Mods/ModAutoplay.cs b/osu.Game/Rulesets/Mods/ModAutoplay.cs index 6cafe0716d..83afda3a28 100644 --- a/osu.Game/Rulesets/Mods/ModAutoplay.cs +++ b/osu.Game/Rulesets/Mods/ModAutoplay.cs @@ -8,7 +8,6 @@ using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Replays; -using osu.Game.Scoring; namespace osu.Game.Rulesets.Mods { @@ -33,16 +32,6 @@ namespace osu.Game.Rulesets.Mods public override bool HasImplementation => GetType().GenericTypeArguments.Length == 0; - [Obsolete("Override CreateReplayData(IBeatmap, IReadOnlyList) instead")] // Can be removed 20220929 - public virtual Score CreateReplayScore(IBeatmap beatmap, IReadOnlyList mods) => new Score { Replay = new Replay() }; - - public virtual ModReplayData CreateReplayData(IBeatmap beatmap, IReadOnlyList mods) - { -#pragma warning disable CS0618 - var replayScore = CreateReplayScore(beatmap, mods); -#pragma warning restore CS0618 - - return new ModReplayData(replayScore.Replay, new ModCreatedUser { Username = replayScore.ScoreInfo.User.Username }); - } + public virtual ModReplayData CreateReplayData(IBeatmap beatmap, IReadOnlyList mods) => new ModReplayData(new Replay(), new ModCreatedUser { Username = @"autoplay" }); } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index dec68a6c22..d624164013 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -196,18 +196,6 @@ namespace osu.Game.Rulesets.Objects.Drawables updateState(State.Value, true); } - /// - /// Applies a hit object to be represented by this . - /// - [Obsolete("Use either overload of Apply that takes a single argument of type HitObject or HitObjectLifetimeEntry")] // Can be removed 20211021. - public void Apply([NotNull] HitObject hitObject, [CanBeNull] HitObjectLifetimeEntry lifetimeEntry) - { - if (lifetimeEntry != null) - Apply(lifetimeEntry); - else - Apply(hitObject); - } - /// /// Applies a new to be represented by this . /// A new is automatically created and applied to this . diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs index e3ac054d1b..5bbd260d3f 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticItem.cs @@ -36,12 +36,6 @@ namespace osu.Game.Screens.Ranking.Statistics /// public readonly bool RequiresHitEvents; - [Obsolete("Use constructor which takes creation function instead.")] // Can be removed 20220803. - public StatisticItem([NotNull] string name, [NotNull] Drawable content, [CanBeNull] Dimension dimension = null) - : this(name, () => content, true, dimension) - { - } - /// /// Creates a new , to be displayed inside a in the results screen. /// diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index 4e5d96ccb8..a9f660312e 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -66,8 +66,6 @@ namespace osu.Game.Skinning } } - void IHasComboColours.AddComboColours(params Color4[] colours) => CustomComboColours.AddRange(colours); - public Dictionary CustomColours { get; } = new Dictionary(); public readonly Dictionary ConfigDictionary = new Dictionary(); diff --git a/osu.Game/Skinning/SkinImporter.cs b/osu.Game/Skinning/SkinImporter.cs index 701dcdfc2d..f594a7b2d2 100644 --- a/osu.Game/Skinning/SkinImporter.cs +++ b/osu.Game/Skinning/SkinImporter.cs @@ -4,11 +4,9 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Threading; using Newtonsoft.Json; -using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.Database; @@ -33,9 +31,6 @@ namespace osu.Game.Skinning this.skinResources = skinResources; modelManager = new ModelManager(storage, realm); - - // can be removed 20220420. - populateMissingHashes(); } public override IEnumerable HandledExtensions => new[] { ".osk" }; @@ -158,18 +153,6 @@ namespace osu.Game.Skinning } modelManager.ReplaceFile(existingFile, stream, realm); - - // can be removed 20220502. - if (!ensureIniWasUpdated(item)) - { - Logger.Log($"Skin {item}'s skin.ini had issues and has been removed. Please report this and provide the problematic skin.", LoggingTarget.Database, LogLevel.Important); - - var existingIni = item.GetFile(@"skin.ini"); - if (existingIni != null) - item.Files.Remove(existingIni); - - writeNewSkinIni(); - } } } @@ -194,38 +177,6 @@ namespace osu.Game.Skinning } } - private bool ensureIniWasUpdated(SkinInfo item) - { - // This is a final consistency check to ensure that hash computation doesn't enter an infinite loop. - // With other changes to the surrounding code this should never be hit, but until we are 101% sure that there - // are no other cases let's avoid a hard startup crash by bailing and alerting. - - var instance = createInstance(item); - - return instance.Configuration.SkinInfo.Name == item.Name; - } - - private void populateMissingHashes() - { - Realm.Run(realm => - { - var skinsWithoutHashes = realm.All().Where(i => !i.Protected && string.IsNullOrEmpty(i.Hash)).ToArray(); - - foreach (SkinInfo skin in skinsWithoutHashes) - { - try - { - realm.Write(_ => skin.Hash = ComputeHash(skin)); - } - catch (Exception e) - { - modelManager.Delete(skin); - Logger.Error(e, $"Existing skin {skin} has been deleted during hash recomputation due to being invalid"); - } - } - }); - } - private Skin createInstance(SkinInfo item) => item.CreateInstance(skinResources); public void Save(Skin skin) From f9d2c30c3eb65fdf4074ac862f837ea94e639898 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 13:52:45 +0900 Subject: [PATCH 1920/2686] Add user toggle for application of safe areas --- .../TestSceneSafeAreaHandling.cs | 11 ++++++++++ osu.Game/Configuration/OsuConfigManager.cs | 4 +++- .../Graphics/Containers/ScalingContainer.cs | 11 ++++++++-- osu.Game/OsuGame.cs | 5 +++++ osu.Game/OsuGameBase.cs | 4 +++- .../Sections/Graphics/LayoutSettings.cs | 20 +++++++++++++++---- 6 files changed, 47 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSafeAreaHandling.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSafeAreaHandling.cs index 2ba0fa36c3..90365ec939 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSafeAreaHandling.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSafeAreaHandling.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Configuration; using osu.Game.Overlays.Settings; using osuTK.Graphics; @@ -24,6 +25,8 @@ namespace osu.Game.Tests.Visual.UserInterface private readonly Bindable safeAreaPaddingLeft = new BindableFloat { MinValue = 0, MaxValue = 200 }; private readonly Bindable safeAreaPaddingRight = new BindableFloat { MinValue = 0, MaxValue = 200 }; + private readonly Bindable applySafeAreaConsiderations = new Bindable(true); + protected override void LoadComplete() { base.LoadComplete(); @@ -84,6 +87,11 @@ namespace osu.Game.Tests.Visual.UserInterface Current = safeAreaPaddingRight, LabelText = "Right" }, + new SettingsCheckbox + { + LabelText = "Apply", + Current = applySafeAreaConsiderations, + }, } } } @@ -93,6 +101,7 @@ namespace osu.Game.Tests.Visual.UserInterface safeAreaPaddingBottom.BindValueChanged(_ => updateSafeArea()); safeAreaPaddingLeft.BindValueChanged(_ => updateSafeArea()); safeAreaPaddingRight.BindValueChanged(_ => updateSafeArea()); + applySafeAreaConsiderations.BindValueChanged(_ => updateSafeArea()); }); base.SetUpSteps(); @@ -107,6 +116,8 @@ namespace osu.Game.Tests.Visual.UserInterface Left = safeAreaPaddingLeft.Value, Right = safeAreaPaddingRight.Value, }; + + Game.LocalConfig.SetValue(OsuSetting.SafeAreaConsiderations, applySafeAreaConsiderations.Value); } [Test] diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 1378e1691a..e449837c92 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -154,6 +154,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.SongSelectRightMouseScroll, false); SetDefault(OsuSetting.Scaling, ScalingMode.Off); + SetDefault(OsuSetting.SafeAreaConsiderations, true); SetDefault(OsuSetting.ScalingSizeX, 0.8f, 0.2f, 1f); SetDefault(OsuSetting.ScalingSizeY, 0.8f, 0.2f, 1f); @@ -370,6 +371,7 @@ namespace osu.Game.Configuration DiscordRichPresence, AutomaticallyDownloadWhenSpectating, ShowOnlineExplicitContent, - LastProcessedMetadataId + LastProcessedMetadataId, + SafeAreaConsiderations, } } diff --git a/osu.Game/Graphics/Containers/ScalingContainer.cs b/osu.Game/Graphics/Containers/ScalingContainer.cs index 17c51129a7..11e57d4be3 100644 --- a/osu.Game/Graphics/Containers/ScalingContainer.cs +++ b/osu.Game/Graphics/Containers/ScalingContainer.cs @@ -29,6 +29,7 @@ namespace osu.Game.Graphics.Containers private Bindable sizeY; private Bindable posX; private Bindable posY; + private Bindable applySafeAreaPadding; private Bindable safeAreaPadding; @@ -132,6 +133,9 @@ namespace osu.Game.Graphics.Containers posY = config.GetBindable(OsuSetting.ScalingPositionY); posY.ValueChanged += _ => Scheduler.AddOnce(updateSize); + applySafeAreaPadding = config.GetBindable(OsuSetting.SafeAreaConsiderations); + applySafeAreaPadding.BindValueChanged(_ => Scheduler.AddOnce(updateSize)); + safeAreaPadding = safeArea.SafeAreaPadding.GetBoundCopy(); safeAreaPadding.BindValueChanged(_ => Scheduler.AddOnce(updateSize)); } @@ -192,7 +196,7 @@ namespace osu.Game.Graphics.Containers bool requiresMasking = targetRect.Size != Vector2.One // For the top level scaling container, for now we apply masking if safe areas are in use. // In the future this can likely be removed as more of the actual UI supports overflowing into the safe areas. - || (targetMode == ScalingMode.Everything && safeAreaPadding.Value.Total != Vector2.Zero); + || (targetMode == ScalingMode.Everything && (applySafeAreaPadding.Value && safeAreaPadding.Value.Total != Vector2.Zero)); if (requiresMasking) sizableContainer.Masking = true; @@ -225,6 +229,9 @@ namespace osu.Game.Graphics.Containers [Resolved] private ISafeArea safeArea { get; set; } + [Resolved] + private OsuConfigManager config { get; set; } + private readonly bool confineHostCursor; private readonly LayoutValue cursorRectCache = new LayoutValue(Invalidation.RequiredParentSizeToFit); @@ -259,7 +266,7 @@ namespace osu.Game.Graphics.Containers { if (host.Window == null) return; - bool coversWholeScreen = Size == Vector2.One && safeArea.SafeAreaPadding.Value.Total == Vector2.Zero; + bool coversWholeScreen = Size == Vector2.One && (!config.Get(OsuSetting.SafeAreaConsiderations) || safeArea.SafeAreaPadding.Value.Total == Vector2.Zero); host.Window.CursorConfineRect = coversWholeScreen ? null : ToScreenSpace(DrawRectangle).AABBFloat; } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 2bdcb57f2a..b3009fb85f 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -179,6 +179,8 @@ namespace osu.Game private Bindable configRuleset; + private Bindable applySafeAreaConsiderations; + private Bindable uiScale; private Bindable configSkin; @@ -312,6 +314,9 @@ namespace osu.Game SelectedMods.BindValueChanged(modsChanged); Beatmap.BindValueChanged(beatmapChanged, true); + + applySafeAreaConsiderations = LocalConfig.GetBindable(OsuSetting.SafeAreaConsiderations); + applySafeAreaConsiderations.BindValueChanged(apply => SafeAreaContainer.SafeAreaOverrideEdges = apply.NewValue ? SafeAreaOverrideEdges : Edges.All); } private ExternalLinkOpener externalLinkOpener; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 7d9ed7bf3e..4c31158597 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -189,6 +189,8 @@ namespace osu.Game private RealmAccess realm; + protected SafeAreaContainer SafeAreaContainer { get; private set; } + /// /// For now, this is used as a source specifically for beat synced components. /// Going forward, it could potentially be used as the single source-of-truth for beatmap timing. @@ -341,7 +343,7 @@ namespace osu.Game GlobalActionContainer globalBindings; - base.Content.Add(new SafeAreaContainer + base.Content.Add(SafeAreaContainer = new SafeAreaContainer { SafeAreaOverrideEdges = SafeAreaOverrideEdges, RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 59b56522a4..f77e1bfc6a 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -20,6 +20,7 @@ using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; +using osuTK; using osuTK.Graphics; namespace osu.Game.Overlays.Settings.Sections.Graphics @@ -50,6 +51,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics private SettingsDropdown resolutionDropdown = null!; private SettingsDropdown displayDropdown = null!; private SettingsDropdown windowModeDropdown = null!; + private SettingsCheckbox safeAreaConsiderationsCheckbox = null!; private Bindable scalingPositionX = null!; private Bindable scalingPositionY = null!; @@ -101,6 +103,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics ItemSource = resolutions, Current = sizeFullscreen }, + safeAreaConsiderationsCheckbox = new SettingsCheckbox + { + LabelText = "Shrink game to avoid cameras and notches", + Current = osuConfig.GetBindable(OsuSetting.SafeAreaConsiderations), + }, new SettingsSlider { LabelText = GraphicsSettingsStrings.UIScaling, @@ -166,7 +173,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics windowModeDropdown.Current.BindValueChanged(_ => { - updateDisplayModeDropdowns(); + updateDisplaySettingsVisibility(); updateScreenModeWarning(); }, true); @@ -191,7 +198,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics .Distinct()); } - updateDisplayModeDropdowns(); + updateDisplaySettingsVisibility(); }), true); scalingMode.BindValueChanged(_ => @@ -221,11 +228,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics Scheduler.AddOnce(d => { displayDropdown.Items = d; - updateDisplayModeDropdowns(); + updateDisplaySettingsVisibility(); }, displays); } - private void updateDisplayModeDropdowns() + private void updateDisplaySettingsVisibility() { if (resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen) resolutionDropdown.Show(); @@ -236,6 +243,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics displayDropdown.Show(); else displayDropdown.Hide(); + + if (host.Window.SafeAreaPadding.Value.Total != Vector2.Zero) + safeAreaConsiderationsCheckbox.Show(); + else + safeAreaConsiderationsCheckbox.Hide(); } private void updateScreenModeWarning() From 10c658e4408d565fca826f8ad7afe29bc6435f3f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 14:34:24 +0900 Subject: [PATCH 1921/2686] Ensure `updateVisualDefinition` is called once on load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index b5b04823a7..6fd1546d30 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders if (editorBeatmap != null) selectedObjects.BindTo(editorBeatmap.SelectedHitObjects); - selectedObjects.BindCollectionChanged((_, _) => updateVisualDefinition()); + selectedObjects.BindCollectionChanged((_, _) => updateVisualDefinition(), true); } public override bool HandleQuickDeletion() From 300ffbb500e0b51ef3eebd363ea25904da109f74 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 14:35:55 +0900 Subject: [PATCH 1922/2686] Don't bother checking for null `editorBeatmap` --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 6fd1546d30..36ee7c2460 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders return true; } - private bool hasSingleObjectSelected => editorBeatmap == null || selectedObjects.Count == 1; + private bool hasSingleObjectSelected => selectedObjects.Count == 1; protected override void Update() { From b3219526a57e415e870082ff176a03e65610cf27 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 28 Oct 2022 14:42:42 +0900 Subject: [PATCH 1923/2686] Populate beatmap ruleset in SoloScoreInfo.ToScoreInfo() --- .../API/Requests/Responses/SoloScoreInfo.cs | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 57586e3d77..77dcfd39e3 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -154,10 +154,8 @@ namespace osu.Game.Online.API.Requests.Responses var mods = Mods.Select(apiMod => apiMod.ToMod(rulesetInstance)).ToArray(); - var scoreInfo = ToScoreInfo(mods); - + var scoreInfo = ToScoreInfo(mods, beatmap); scoreInfo.Ruleset = ruleset; - if (beatmap != null) scoreInfo.BeatmapInfo = beatmap; return scoreInfo; } @@ -166,25 +164,47 @@ namespace osu.Game.Online.API.Requests.Responses /// Create a from an API score instance. /// /// The mod instances, resolved from a ruleset. - /// - public ScoreInfo ToScoreInfo(Mod[] mods) => new ScoreInfo + /// The object to populate the scores' beatmap with. + /// + /// If this is a type, then the score will be fully populated with the given object. + /// Otherwise, if this is an type (e.g. ), then only the beatmap ruleset will be populated. + /// Otherwise, if this is null, then the beatmap ruleset will not be populated. + /// The online beatmap ID is populated in all cases. + /// + /// + /// The populated . + public ScoreInfo ToScoreInfo(Mod[] mods, IBeatmapInfo? beatmap = null) { - OnlineID = OnlineID, - User = User ?? new APIUser { Id = UserID }, - BeatmapInfo = new BeatmapInfo { OnlineID = BeatmapID }, - Ruleset = new RulesetInfo { OnlineID = RulesetID }, - Passed = Passed, - TotalScore = TotalScore, - Accuracy = Accuracy, - MaxCombo = MaxCombo, - Rank = Rank, - Statistics = Statistics, - MaximumStatistics = MaximumStatistics, - Date = EndedAt, - Hash = HasReplay ? "online" : string.Empty, // TODO: temporary? - Mods = mods, - PP = PP, - }; + var score = new ScoreInfo + { + OnlineID = OnlineID, + User = User ?? new APIUser { Id = UserID }, + BeatmapInfo = new BeatmapInfo { OnlineID = BeatmapID }, + Ruleset = new RulesetInfo { OnlineID = RulesetID }, + Passed = Passed, + TotalScore = TotalScore, + Accuracy = Accuracy, + MaxCombo = MaxCombo, + Rank = Rank, + Statistics = Statistics, + MaximumStatistics = MaximumStatistics, + Date = EndedAt, + Hash = HasReplay ? "online" : string.Empty, // TODO: temporary? + Mods = mods, + PP = PP, + }; + + if (beatmap is BeatmapInfo realmBeatmap) + score.BeatmapInfo = realmBeatmap; + else if (beatmap != null) + { + score.BeatmapInfo.Ruleset.OnlineID = beatmap.Ruleset.OnlineID; + score.BeatmapInfo.Ruleset.Name = beatmap.Ruleset.Name; + score.BeatmapInfo.Ruleset.ShortName = beatmap.Ruleset.ShortName; + } + + return score; + } /// /// Creates a from a local score for score submission. From c1e9398c19d3e74850c9f7fe546d8fefdabefa2f Mon Sep 17 00:00:00 2001 From: nullium21 Date: Fri, 28 Oct 2022 09:19:34 +0300 Subject: [PATCH 1924/2686] Fix regex by allowing file extensions + typed new Apparently, the _whole_ filename was checked with GetValidArchiveContentFilename, not just the stem. --- osu.Game/Extensions/ModelExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Extensions/ModelExtensions.cs b/osu.Game/Extensions/ModelExtensions.cs index 8acc079805..73a87c7003 100644 --- a/osu.Game/Extensions/ModelExtensions.cs +++ b/osu.Game/Extensions/ModelExtensions.cs @@ -137,7 +137,7 @@ namespace osu.Game.Extensions return instance.OnlineID.Equals(other.OnlineID); } - private static Regex invalid_filename_chars = new(@"(?!$)[^A-Za-z0-9_()[\] -]", RegexOptions.Compiled); + private static Regex invalid_filename_chars = new Regex(@"(?!$)[^A-Za-z0-9_()[\]. -]", RegexOptions.Compiled); /// /// Get a valid filename for use inside a zip file. Avoids backslashes being incorrectly converted to directories. From 6901ed997d353628005b524ad553d7eed9c83cde Mon Sep 17 00:00:00 2001 From: nullium21 Date: Fri, 28 Oct 2022 09:21:47 +0300 Subject: [PATCH 1925/2686] One more little change Damn, i forgor. Sorry, CI runners. --- osu.Game/Extensions/ModelExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Extensions/ModelExtensions.cs b/osu.Game/Extensions/ModelExtensions.cs index 73a87c7003..f8db5f4e88 100644 --- a/osu.Game/Extensions/ModelExtensions.cs +++ b/osu.Game/Extensions/ModelExtensions.cs @@ -137,7 +137,7 @@ namespace osu.Game.Extensions return instance.OnlineID.Equals(other.OnlineID); } - private static Regex invalid_filename_chars = new Regex(@"(?!$)[^A-Za-z0-9_()[\]. -]", RegexOptions.Compiled); + private static readonly Regex invalid_filename_chars = new Regex(@"(?!$)[^A-Za-z0-9_()[\]. \-]", RegexOptions.Compiled); /// /// Get a valid filename for use inside a zip file. Avoids backslashes being incorrectly converted to directories. From 87328dd1f535ec4f5c799b73ac8207ed439b1596 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 27 Oct 2022 23:36:30 -0700 Subject: [PATCH 1926/2686] Fix bar hit error meter labels not clearing when setting to none --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index d6b9c62369..e7b2ce1672 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -279,6 +279,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters switch (style) { case LabelStyles.None: + labelEarly.Clear(); + labelLate.Clear(); break; case LabelStyles.Icons: From 33bb1212d1e84c3d887380d27f6159ca95361ad5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 28 Oct 2022 16:19:15 +0900 Subject: [PATCH 1927/2686] Add notifications websocket + chat implementation --- osu.Game/Online/Chat/Message.cs | 7 ++ .../Online/Notifications/EndChatRequest.cs | 16 +++ .../Notifications/NewChatMessageData.cs | 29 +++++ .../Notifications/NotificationsClient.cs | 113 ++++++++++++++++++ .../NotificationsClientConnector.cs | 65 ++++++++++ .../NotificationsClient_Processing.cs | 102 ++++++++++++++++ .../Online/Notifications/SocketMessage.cs | 21 ++++ .../Online/Notifications/StartChatRequest.cs | 16 +++ 8 files changed, 369 insertions(+) create mode 100644 osu.Game/Online/Notifications/EndChatRequest.cs create mode 100644 osu.Game/Online/Notifications/NewChatMessageData.cs create mode 100644 osu.Game/Online/Notifications/NotificationsClient.cs create mode 100644 osu.Game/Online/Notifications/NotificationsClientConnector.cs create mode 100644 osu.Game/Online/Notifications/NotificationsClient_Processing.cs create mode 100644 osu.Game/Online/Notifications/SocketMessage.cs create mode 100644 osu.Game/Online/Notifications/StartChatRequest.cs diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 86562341eb..25c5b0853f 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -30,6 +30,13 @@ namespace osu.Game.Online.Chat [JsonProperty(@"sender")] public APIUser Sender; + [JsonProperty(@"sender_id")] + public int SenderId + { + get => Sender?.Id ?? 0; + set => Sender = new APIUser { Id = value }; + } + [JsonConstructor] public Message() { diff --git a/osu.Game/Online/Notifications/EndChatRequest.cs b/osu.Game/Online/Notifications/EndChatRequest.cs new file mode 100644 index 0000000000..1173b1e8d0 --- /dev/null +++ b/osu.Game/Online/Notifications/EndChatRequest.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; + +namespace osu.Game.Online.Notifications +{ + [JsonObject(MemberSerialization.OptIn)] + public class EndChatRequest : SocketMessage + { + public EndChatRequest() + { + Event = "chat.end"; + } + } +} diff --git a/osu.Game/Online/Notifications/NewChatMessageData.cs b/osu.Game/Online/Notifications/NewChatMessageData.cs new file mode 100644 index 0000000000..b388afa743 --- /dev/null +++ b/osu.Game/Online/Notifications/NewChatMessageData.cs @@ -0,0 +1,29 @@ +// 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 System.Runtime.Serialization; +using Newtonsoft.Json; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.Notifications +{ + [JsonObject(MemberSerialization.OptIn)] + public class NewChatMessageData + { + [JsonProperty("messages")] + public List Messages { get; set; } = null!; + + [JsonProperty("users")] + private List users { get; set; } = null!; + + [OnDeserialized] + private void onDeserialised(StreamingContext context) + { + foreach (var m in Messages) + m.Sender = users.Single(u => u.OnlineID == m.SenderId); + } + } +} diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs new file mode 100644 index 0000000000..63260e5df9 --- /dev/null +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -0,0 +1,113 @@ +// 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.Diagnostics; +using System.Net.WebSockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using osu.Framework.Extensions.TypeExtensions; +using osu.Framework.Logging; +using osu.Game.Online.API; + +namespace osu.Game.Online.Notifications +{ + public partial class NotificationsClient : SocketClient + { + private readonly ClientWebSocket socket; + private readonly string endpoint; + private readonly IAPIProvider api; + + public NotificationsClient(ClientWebSocket socket, string endpoint, IAPIProvider api) + { + this.socket = socket; + this.endpoint = endpoint; + this.api = api; + } + + public override async Task StartAsync(CancellationToken cancellationToken) + { + await socket.ConnectAsync(new Uri(endpoint), cancellationToken).ConfigureAwait(false); + await onConnectedAsync(); + runReadLoop(cancellationToken); + } + + private void runReadLoop(CancellationToken cancellationToken) => Task.Run((Func)(async () => + { + byte[] buffer = new byte[1024]; + StringBuilder messageResult = new StringBuilder(); + + while (!cancellationToken.IsCancellationRequested) + { + try + { + WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, cancellationToken); + + switch (result.MessageType) + { + case WebSocketMessageType.Text: + messageResult.Append(Encoding.UTF8.GetString(buffer[..result.Count])); + + if (result.EndOfMessage) + { + SocketMessage? message = JsonConvert.DeserializeObject(messageResult.ToString()); + messageResult.Clear(); + + Debug.Assert(message != null); + + if (message.Error != null) + { + Logger.Log($"{GetType().ReadableName()} error: {message.Error}", LoggingTarget.Network); + break; + } + + await onMessageReceivedAsync(message); + } + + break; + + case WebSocketMessageType.Binary: + throw new NotImplementedException(); + + case WebSocketMessageType.Close: + throw new Exception("Connection closed by remote host."); + } + } + catch (Exception ex) + { + await InvokeClosed(ex); + return; + } + } + }), cancellationToken); + + private async Task closeAsync() + { + try + { + await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Disconnecting", CancellationToken.None).ConfigureAwait(false); + } + catch + { + // Closure can fail if the connection is aborted. Don't really care since it's disposed anyway. + } + } + + private async Task sendMessage(SocketMessage message, CancellationToken cancellationToken) + { + if (socket.State != WebSocketState.Open) + return; + + await socket.SendAsync(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message)), WebSocketMessageType.Text, true, cancellationToken); + } + + public override async ValueTask DisposeAsync() + { + await base.DisposeAsync(); + await closeAsync(); + socket.Dispose(); + } + } +} diff --git a/osu.Game/Online/Notifications/NotificationsClientConnector.cs b/osu.Game/Online/Notifications/NotificationsClientConnector.cs new file mode 100644 index 0000000000..18b2a1b19d --- /dev/null +++ b/osu.Game/Online/Notifications/NotificationsClientConnector.cs @@ -0,0 +1,65 @@ +// 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.Net; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.Notifications +{ + public class NotificationsClientConnector : SocketClientConnector + { + public event Action? ChannelJoined; + public event Action>? NewMessages; + public event Action? PresenceReceived; + + private readonly IAPIProvider api; + private bool chatStarted; + + public NotificationsClientConnector(IAPIProvider api) + : base(api) + { + this.api = api; + } + + public void StartChat() + { + chatStarted = true; + + if (CurrentConnection is NotificationsClient client) + client.EnableChat = true; + } + + protected override async Task BuildConnectionAsync(CancellationToken cancellationToken) + { + var tcs = new TaskCompletionSource(); + + var req = new GetNotificationsRequest(); + req.Success += bundle => tcs.SetResult(bundle.Endpoint); + req.Failure += ex => tcs.SetException(ex); + api.Queue(req); + + string endpoint = await tcs.Task; + + ClientWebSocket socket = new ClientWebSocket(); + socket.Options.SetRequestHeader("Authorization", $"Bearer {api.AccessToken}"); + socket.Options.Proxy = WebRequest.DefaultWebProxy; + if (socket.Options.Proxy != null) + socket.Options.Proxy.Credentials = CredentialCache.DefaultCredentials; + + return new NotificationsClient(socket, endpoint, api) + { + ChannelJoined = c => ChannelJoined?.Invoke(c), + NewMessages = m => NewMessages?.Invoke(m), + PresenceReceived = () => PresenceReceived?.Invoke(), + EnableChat = chatStarted + }; + } + } +} diff --git a/osu.Game/Online/Notifications/NotificationsClient_Processing.cs b/osu.Game/Online/Notifications/NotificationsClient_Processing.cs new file mode 100644 index 0000000000..4950a53f6f --- /dev/null +++ b/osu.Game/Online/Notifications/NotificationsClient_Processing.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 System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using osu.Game.Online.API.Requests; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.Notifications +{ + public partial class NotificationsClient + { + public Action? ChannelJoined; + public Action>? NewMessages; + public Action? PresenceReceived; + + private bool enableChat; + private long lastMessageId; + + public bool EnableChat + { + get => enableChat; + set + { + enableChat = value; + Task.Run(startChatIfEnabledAsync); + } + } + + private async Task onConnectedAsync() + { + await startChatIfEnabledAsync(); + } + + private async Task startChatIfEnabledAsync() + { + if (!EnableChat) + return; + + await sendMessage(new StartChatRequest(), CancellationToken.None); + + var fetchReq = new GetUpdatesRequest(lastMessageId); + + fetchReq.Success += updates => + { + if (updates?.Presence != null) + { + foreach (var channel in updates.Presence) + handleJoinedChannel(channel); + + //todo: handle left channels + + handleMessages(updates.Messages); + } + + PresenceReceived?.Invoke(); + }; + + api.Queue(fetchReq); + } + + private Task onMessageReceivedAsync(SocketMessage message) + { + switch (message.Event) + { + case "chat.message.new": + Debug.Assert(message.Data != null); + + NewChatMessageData? messageData = JsonConvert.DeserializeObject(message.Data.ToString()); + Debug.Assert(messageData != null); + + List messages = messageData.Messages.Where(m => m.Sender.OnlineID != api.LocalUser.Value.OnlineID).ToList(); + + foreach (var msg in messages) + handleJoinedChannel(new Channel(msg.Sender) { Id = msg.ChannelId }); + + handleMessages(messages); + break; + } + + return Task.CompletedTask; + } + + private void handleJoinedChannel(Channel channel) + { + // we received this from the server so should mark the channel already joined. + channel.Joined.Value = true; + ChannelJoined?.Invoke(channel); + } + + private void handleMessages(List messages) + { + NewMessages?.Invoke(messages); + lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId; + } + } +} diff --git a/osu.Game/Online/Notifications/SocketMessage.cs b/osu.Game/Online/Notifications/SocketMessage.cs new file mode 100644 index 0000000000..6b5f3435fc --- /dev/null +++ b/osu.Game/Online/Notifications/SocketMessage.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace osu.Game.Online.Notifications +{ + [JsonObject(MemberSerialization.OptIn)] + public class SocketMessage + { + [JsonProperty("event")] + public string Event { get; set; } = null!; + + [JsonProperty("data")] + public JObject? Data { get; set; } + + [JsonProperty("error")] + public string? Error { get; set; } + } +} diff --git a/osu.Game/Online/Notifications/StartChatRequest.cs b/osu.Game/Online/Notifications/StartChatRequest.cs new file mode 100644 index 0000000000..274738886d --- /dev/null +++ b/osu.Game/Online/Notifications/StartChatRequest.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; + +namespace osu.Game.Online.Notifications +{ + [JsonObject(MemberSerialization.OptIn)] + public class StartChatRequest : SocketMessage + { + public StartChatRequest() + { + Event = "chat.start"; + } + } +} From 2f731f86bad8d71790fe0d63e400a6601b5e6408 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 28 Oct 2022 16:22:35 +0900 Subject: [PATCH 1928/2686] Adjust ChannelManager to use notifications client --- .../Components/TournamentMatchChatDisplay.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 119 ++++++------------ osu.Game/OsuGame.cs | 17 +-- 3 files changed, 43 insertions(+), 95 deletions(-) diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs index 6a8e4aa951..ca2b400e8b 100644 --- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tournament.Components if (manager == null) { - AddInternal(manager = new ChannelManager(api) { HighPollRate = { Value = true } }); + AddInternal(manager = new ChannelManager(api)); Channel.BindTo(manager.CurrentChannel); } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index ec84b0643d..b63f841f59 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -6,16 +6,17 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; +using osu.Framework.Graphics.Containers; using osu.Framework.Logging; +using osu.Framework.Threading; using osu.Game.Database; -using osu.Game.Input; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Notifications; using osu.Game.Overlays.Chat.Listing; namespace osu.Game.Online.Chat @@ -23,7 +24,7 @@ namespace osu.Game.Online.Chat /// /// Manages everything channel related /// - public class ChannelManager : PollingComponent, IChannelPostTarget + public class ChannelManager : CompositeComponent, IChannelPostTarget { /// /// The channels the player joins on startup @@ -68,9 +69,12 @@ namespace osu.Game.Online.Chat [Resolved] private UserLookupCache users { get; set; } - public readonly BindableBool HighPollRate = new BindableBool(); + [Resolved] + private NotificationsClientConnector connector { get; set; } - private readonly IBindable isIdle = new BindableBool(); + private readonly IBindable apiState = new Bindable(); + private bool channelsInitialised; + private ScheduledDelegate ackDelegate; public ChannelManager(IAPIProvider api) { @@ -78,30 +82,34 @@ namespace osu.Game.Online.Chat CurrentChannel.ValueChanged += currentChannelChanged; } - [BackgroundDependencyLoader(permitNulls: true)] - private void load(IdleTracker idleTracker) + [BackgroundDependencyLoader] + private void load() { - HighPollRate.BindValueChanged(updatePollRate); - isIdle.BindValueChanged(updatePollRate, true); - - if (idleTracker != null) - isIdle.BindTo(idleTracker.IsIdle); - } - - private void updatePollRate(ValueChangedEvent valueChangedEvent) - { - // Polling will eventually be replaced with websocket, but let's avoid doing these background operations as much as possible for now. - // The only loss will be delayed PM/message highlight notifications. - int millisecondsBetweenPolls = HighPollRate.Value ? 1000 : 60000; - - if (isIdle.Value) - millisecondsBetweenPolls *= 10; - - if (TimeBetweenPolls.Value != millisecondsBetweenPolls) + connector.ChannelJoined += ch => joinChannel(ch); + connector.NewMessages += addMessages; + connector.PresenceReceived += () => { - TimeBetweenPolls.Value = millisecondsBetweenPolls; - Logger.Log($"Chat is now polling every {TimeBetweenPolls.Value} ms"); - } + if (!channelsInitialised) + { + channelsInitialised = true; + // we want this to run after the first presence so we can see if the user is in any channels already. + initializeChannels(); + } + }; + + connector.StartChat(); + + apiState.BindTo(api.State); + apiState.BindValueChanged(status => + { + ackDelegate?.Cancel(); + + if (status.NewValue == APIState.Online) + { + Scheduler.Add(ackDelegate = new ScheduledDelegate(() => api.Queue(new ChatAckRequest()), 0, 60000)); + // Todo: Handle silences. + } + }, true); } /// @@ -328,7 +336,7 @@ namespace osu.Game.Online.Chat } } - private void handleChannelMessages(IEnumerable messages) + private void addMessages(List messages) { var channels = JoinedChannels.ToList(); @@ -376,7 +384,7 @@ namespace osu.Game.Online.Chat var fetchInitialMsgReq = new GetMessagesRequest(channel); fetchInitialMsgReq.Success += messages => { - handleChannelMessages(messages); + addMessages(messages); channel.MessagesLoaded = true; // this will mark the channel as having received messages even if there were none. }; @@ -464,7 +472,7 @@ namespace osu.Game.Online.Chat { channel.Id = resChannel.ChannelID.Value; - handleChannelMessages(resChannel.RecentMessages); + addMessages(resChannel.RecentMessages); channel.MessagesLoaded = true; // this will mark the channel as having received messages even if there were none. } }; @@ -574,57 +582,6 @@ namespace osu.Game.Online.Chat } } - private long lastMessageId; - - private bool channelsInitialised; - - protected override Task Poll() - { - if (!api.IsLoggedIn) - return base.Poll(); - - var fetchReq = new GetUpdatesRequest(lastMessageId); - - var tcs = new TaskCompletionSource(); - - fetchReq.Success += updates => - { - if (updates?.Presence != null) - { - foreach (var channel in updates.Presence) - { - // we received this from the server so should mark the channel already joined. - channel.Joined.Value = true; - joinChannel(channel); - } - - //todo: handle left channels - - handleChannelMessages(updates.Messages); - - foreach (var group in updates.Messages.GroupBy(m => m.ChannelId)) - JoinedChannels.FirstOrDefault(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); - - lastMessageId = updates.Messages.LastOrDefault()?.Id ?? lastMessageId; - } - - if (!channelsInitialised) - { - channelsInitialised = true; - // we want this to run after the first presence so we can see if the user is in any channels already. - initializeChannels(); - } - - tcs.SetResult(true); - }; - - fetchReq.Failure += _ => tcs.SetResult(false); - - api.Queue(fetchReq); - - return tcs.Task; - } - /// /// Marks the as read /// diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 2bdcb57f2a..7a42007fb8 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -44,6 +44,7 @@ using osu.Game.Localisation; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; +using osu.Game.Online.Notifications; using osu.Game.Overlays; using osu.Game.Overlays.Music; using osu.Game.Overlays.Notifications; @@ -83,6 +84,7 @@ namespace osu.Game private ChatOverlay chatOverlay; private ChannelManager channelManager; + private NotificationsClientConnector notificationsClient; [NotNull] protected readonly NotificationOverlay Notifications = new NotificationOverlay(); @@ -676,6 +678,7 @@ namespace osu.Game { base.Dispose(isDisposing); SentryLogger.Dispose(); + notificationsClient.Dispose(); } protected override IDictionary GetFrameworkConfigDefaults() @@ -879,6 +882,7 @@ namespace osu.Game loadComponentSingleFile(dashboard = new DashboardOverlay(), overlayContent.Add, true); loadComponentSingleFile(news = new NewsOverlay(), overlayContent.Add, true); var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true); + loadComponentSingleFile(notificationsClient = new NotificationsClientConnector(API), AddInternal, true); loadComponentSingleFile(channelManager = new ChannelManager(API), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(new MessageNotifier(), AddInternal, true); @@ -908,19 +912,6 @@ namespace osu.Game loadComponentSingleFile(new BackgroundBeatmapProcessor(), Add); - chatOverlay.State.BindValueChanged(_ => updateChatPollRate()); - // Multiplayer modes need to increase poll rate temporarily. - API.Activity.BindValueChanged(_ => updateChatPollRate(), true); - - void updateChatPollRate() - { - channelManager.HighPollRate.Value = - chatOverlay.State.Value == Visibility.Visible - || API.Activity.Value is UserActivity.InLobby - || API.Activity.Value is UserActivity.InMultiplayerGame - || API.Activity.Value is UserActivity.SpectatingMultiplayerGame; - } - Add(difficultyRecommender); Add(externalLinkOpener = new ExternalLinkOpener()); Add(new MusicKeyBindingHandler()); From efa82569117573894533e22beaadcc20a69579f3 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 28 Oct 2022 16:32:17 +0900 Subject: [PATCH 1929/2686] Use more verbatim strings --- .../API/Requests/GetNotificationsRequest.cs | 2 +- .../API/Requests/Responses/APINotification.cs | 16 ++++++++-------- .../Requests/Responses/APINotificationsBundle.cs | 6 +++--- osu.Game/Online/Notifications/EndChatRequest.cs | 2 +- .../Online/Notifications/NewChatMessageData.cs | 4 ++-- .../Online/Notifications/NotificationsClient.cs | 2 +- .../NotificationsClientConnector.cs | 2 +- .../NotificationsClient_Processing.cs | 5 ++++- osu.Game/Online/Notifications/SocketMessage.cs | 6 +++--- .../Online/Notifications/StartChatRequest.cs | 2 +- 10 files changed, 25 insertions(+), 22 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetNotificationsRequest.cs b/osu.Game/Online/API/Requests/GetNotificationsRequest.cs index e419807a85..afd4da296e 100644 --- a/osu.Game/Online/API/Requests/GetNotificationsRequest.cs +++ b/osu.Game/Online/API/Requests/GetNotificationsRequest.cs @@ -7,6 +7,6 @@ namespace osu.Game.Online.API.Requests { public class GetNotificationsRequest : APIRequest { - protected override string Target => "notifications"; + protected override string Target => @"notifications"; } } diff --git a/osu.Game/Online/API/Requests/Responses/APINotification.cs b/osu.Game/Online/API/Requests/Responses/APINotification.cs index e1f0fa7221..2d9122c04b 100644 --- a/osu.Game/Online/API/Requests/Responses/APINotification.cs +++ b/osu.Game/Online/API/Requests/Responses/APINotification.cs @@ -10,28 +10,28 @@ namespace osu.Game.Online.API.Requests.Responses [JsonObject(MemberSerialization.OptIn)] public class APINotification { - [JsonProperty("id")] + [JsonProperty(@"id")] public long Id { get; set; } - [JsonProperty("name")] + [JsonProperty(@"name")] public string Name { get; set; } = null!; - [JsonProperty("created_at")] + [JsonProperty(@"created_at")] public DateTimeOffset? CreatedAt { get; set; } - [JsonProperty("object_type")] + [JsonProperty(@"object_type")] public string ObjectType { get; set; } = null!; - [JsonProperty("object_id")] + [JsonProperty(@"object_id")] public string ObjectId { get; set; } = null!; - [JsonProperty("source_user_id")] + [JsonProperty(@"source_user_id")] public long? SourceUserId { get; set; } - [JsonProperty("is_read")] + [JsonProperty(@"is_read")] public bool IsRead { get; set; } - [JsonProperty("details")] + [JsonProperty(@"details")] public Dictionary? Details { get; set; } } } diff --git a/osu.Game/Online/API/Requests/Responses/APINotificationsBundle.cs b/osu.Game/Online/API/Requests/Responses/APINotificationsBundle.cs index 067f1066b3..ae299e2614 100644 --- a/osu.Game/Online/API/Requests/Responses/APINotificationsBundle.cs +++ b/osu.Game/Online/API/Requests/Responses/APINotificationsBundle.cs @@ -8,13 +8,13 @@ namespace osu.Game.Online.API.Requests.Responses [JsonObject(MemberSerialization.OptIn)] public class APINotificationsBundle { - [JsonProperty("has_more")] + [JsonProperty(@"has_more")] public bool HasMore { get; set; } - [JsonProperty("notifications")] + [JsonProperty(@"notifications")] public APINotification[] Notifications { get; set; } = null!; - [JsonProperty("notification_endpoint")] + [JsonProperty(@"notification_endpoint")] public string Endpoint { get; set; } = null!; } } diff --git a/osu.Game/Online/Notifications/EndChatRequest.cs b/osu.Game/Online/Notifications/EndChatRequest.cs index 1173b1e8d0..f863511804 100644 --- a/osu.Game/Online/Notifications/EndChatRequest.cs +++ b/osu.Game/Online/Notifications/EndChatRequest.cs @@ -10,7 +10,7 @@ namespace osu.Game.Online.Notifications { public EndChatRequest() { - Event = "chat.end"; + Event = @"chat.end"; } } } diff --git a/osu.Game/Online/Notifications/NewChatMessageData.cs b/osu.Game/Online/Notifications/NewChatMessageData.cs index b388afa743..eda9a3a11b 100644 --- a/osu.Game/Online/Notifications/NewChatMessageData.cs +++ b/osu.Game/Online/Notifications/NewChatMessageData.cs @@ -13,10 +13,10 @@ namespace osu.Game.Online.Notifications [JsonObject(MemberSerialization.OptIn)] public class NewChatMessageData { - [JsonProperty("messages")] + [JsonProperty(@"messages")] public List Messages { get; set; } = null!; - [JsonProperty("users")] + [JsonProperty(@"users")] private List users { get; set; } = null!; [OnDeserialized] diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs index 63260e5df9..af9e3ba1e7 100644 --- a/osu.Game/Online/Notifications/NotificationsClient.cs +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -87,7 +87,7 @@ namespace osu.Game.Online.Notifications { try { - await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Disconnecting", CancellationToken.None).ConfigureAwait(false); + await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, @"Disconnecting", CancellationToken.None).ConfigureAwait(false); } catch { diff --git a/osu.Game/Online/Notifications/NotificationsClientConnector.cs b/osu.Game/Online/Notifications/NotificationsClientConnector.cs index 18b2a1b19d..e938ed59f0 100644 --- a/osu.Game/Online/Notifications/NotificationsClientConnector.cs +++ b/osu.Game/Online/Notifications/NotificationsClientConnector.cs @@ -48,7 +48,7 @@ namespace osu.Game.Online.Notifications string endpoint = await tcs.Task; ClientWebSocket socket = new ClientWebSocket(); - socket.Options.SetRequestHeader("Authorization", $"Bearer {api.AccessToken}"); + socket.Options.SetRequestHeader(@"Authorization", @$"Bearer {api.AccessToken}"); socket.Options.Proxy = WebRequest.DefaultWebProxy; if (socket.Options.Proxy != null) socket.Options.Proxy.Credentials = CredentialCache.DefaultCredentials; diff --git a/osu.Game/Online/Notifications/NotificationsClient_Processing.cs b/osu.Game/Online/Notifications/NotificationsClient_Processing.cs index 4950a53f6f..35cf737135 100644 --- a/osu.Game/Online/Notifications/NotificationsClient_Processing.cs +++ b/osu.Game/Online/Notifications/NotificationsClient_Processing.cs @@ -27,6 +27,9 @@ namespace osu.Game.Online.Notifications get => enableChat; set { + if (enableChat == value) + return; + enableChat = value; Task.Run(startChatIfEnabledAsync); } @@ -68,7 +71,7 @@ namespace osu.Game.Online.Notifications { switch (message.Event) { - case "chat.message.new": + case @"chat.message.new": Debug.Assert(message.Data != null); NewChatMessageData? messageData = JsonConvert.DeserializeObject(message.Data.ToString()); diff --git a/osu.Game/Online/Notifications/SocketMessage.cs b/osu.Game/Online/Notifications/SocketMessage.cs index 6b5f3435fc..c52072ccd5 100644 --- a/osu.Game/Online/Notifications/SocketMessage.cs +++ b/osu.Game/Online/Notifications/SocketMessage.cs @@ -9,13 +9,13 @@ namespace osu.Game.Online.Notifications [JsonObject(MemberSerialization.OptIn)] public class SocketMessage { - [JsonProperty("event")] + [JsonProperty(@"event")] public string Event { get; set; } = null!; - [JsonProperty("data")] + [JsonProperty(@"data")] public JObject? Data { get; set; } - [JsonProperty("error")] + [JsonProperty(@"error")] public string? Error { get; set; } } } diff --git a/osu.Game/Online/Notifications/StartChatRequest.cs b/osu.Game/Online/Notifications/StartChatRequest.cs index 274738886d..d17644ee3b 100644 --- a/osu.Game/Online/Notifications/StartChatRequest.cs +++ b/osu.Game/Online/Notifications/StartChatRequest.cs @@ -10,7 +10,7 @@ namespace osu.Game.Online.Notifications { public StartChatRequest() { - Event = "chat.start"; + Event = @"chat.start"; } } } From 8c057b3af7a3d97727007b792017feb1a65660d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 17:26:53 +0900 Subject: [PATCH 1930/2686] Add comment explaining why handlers are added in `OsuGameBase` --- osu.Game/OsuGameBase.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 1177f01609..c94ad34f11 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -526,6 +526,11 @@ namespace osu.Game /// Should be overriden per-platform to provide settings for platform-specific handlers. public virtual SettingsSubsection CreateSettingsSubsectionFor(InputHandler handler) { + // One would think that this could be moved to the `OsuGameDesktop` class, but doing so means that + // OsuGameTestScenes will not show any input options (as they are based on OsuGame not OsuGameDesktop). + // + // This in turn makes it hard for ruleset creators to adjust input settings while testing their ruleset + // within the test browser interface. if (RuntimeInfo.IsDesktop) { switch (handler) From 527b1d9db10e0bdcf4d5c75ac64f4794662bc979 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 28 Oct 2022 17:53:28 +0900 Subject: [PATCH 1931/2686] Generalise + add polling-style for usage in tests --- osu.Game/Online/HubClient.cs | 2 +- .../Notifications/NotificationsClient.cs | 147 ++++++++--------- .../NotificationsClientConnector.cs | 42 ++--- .../NotificationsClient_Processing.cs | 105 ------------- .../Polling/PollingNotificationsClient.cs | 37 +++++ .../PollingNotificationsClientConnector.cs | 26 +++ .../{ => WebSocket}/EndChatRequest.cs | 5 +- .../{ => WebSocket}/NewChatMessageData.cs | 5 +- .../{ => WebSocket}/SocketMessage.cs | 5 +- .../{ => WebSocket}/StartChatRequest.cs | 5 +- .../WebSocket/WebSocketNotificationsClient.cs | 148 ++++++++++++++++++ .../WebSocketNotificationsClientConnector.cs | 46 ++++++ osu.Game/Online/SocketClient.cs | 2 +- osu.Game/Online/SocketClientConnector.cs | 2 +- osu.Game/OsuGame.cs | 3 +- 15 files changed, 357 insertions(+), 223 deletions(-) delete mode 100644 osu.Game/Online/Notifications/NotificationsClient_Processing.cs create mode 100644 osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs create mode 100644 osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs rename osu.Game/Online/Notifications/{ => WebSocket}/EndChatRequest.cs (65%) rename osu.Game/Online/Notifications/{ => WebSocket}/NewChatMessageData.cs (83%) rename osu.Game/Online/Notifications/{ => WebSocket}/SocketMessage.cs (77%) rename osu.Game/Online/Notifications/{ => WebSocket}/StartChatRequest.cs (66%) create mode 100644 osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs create mode 100644 osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs diff --git a/osu.Game/Online/HubClient.cs b/osu.Game/Online/HubClient.cs index 262e298f34..e80931eeae 100644 --- a/osu.Game/Online/HubClient.cs +++ b/osu.Game/Online/HubClient.cs @@ -17,7 +17,7 @@ namespace osu.Game.Online Connection.Closed += InvokeClosed; } - public override Task StartAsync(CancellationToken cancellationToken) => Connection.StartAsync(cancellationToken); + public override Task ConnectAsync(CancellationToken cancellationToken) => Connection.StartAsync(cancellationToken); public override async ValueTask DisposeAsync() { diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs index af9e3ba1e7..6d9226ca17 100644 --- a/osu.Game/Online/Notifications/NotificationsClient.cs +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -2,112 +2,95 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; -using System.Net.WebSockets; -using System.Text; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; -using osu.Framework.Extensions.TypeExtensions; -using osu.Framework.Logging; using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.Chat; namespace osu.Game.Online.Notifications { - public partial class NotificationsClient : SocketClient + /// + /// An abstract client which receives notification-related events (chat/notifications). + /// + public abstract class NotificationsClient : SocketClient { - private readonly ClientWebSocket socket; - private readonly string endpoint; + public Action? ChannelJoined; + public Action>? NewMessages; + public Action? PresenceReceived; + private readonly IAPIProvider api; - public NotificationsClient(ClientWebSocket socket, string endpoint, IAPIProvider api) + private bool enableChat; + private long lastMessageId; + + protected NotificationsClient(IAPIProvider api) { - this.socket = socket; - this.endpoint = endpoint; this.api = api; } - public override async Task StartAsync(CancellationToken cancellationToken) + public bool EnableChat { - await socket.ConnectAsync(new Uri(endpoint), cancellationToken).ConfigureAwait(false); - await onConnectedAsync(); - runReadLoop(cancellationToken); - } - - private void runReadLoop(CancellationToken cancellationToken) => Task.Run((Func)(async () => - { - byte[] buffer = new byte[1024]; - StringBuilder messageResult = new StringBuilder(); - - while (!cancellationToken.IsCancellationRequested) + get => enableChat; + set { - try - { - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, cancellationToken); - - switch (result.MessageType) - { - case WebSocketMessageType.Text: - messageResult.Append(Encoding.UTF8.GetString(buffer[..result.Count])); - - if (result.EndOfMessage) - { - SocketMessage? message = JsonConvert.DeserializeObject(messageResult.ToString()); - messageResult.Clear(); - - Debug.Assert(message != null); - - if (message.Error != null) - { - Logger.Log($"{GetType().ReadableName()} error: {message.Error}", LoggingTarget.Network); - break; - } - - await onMessageReceivedAsync(message); - } - - break; - - case WebSocketMessageType.Binary: - throw new NotImplementedException(); - - case WebSocketMessageType.Close: - throw new Exception("Connection closed by remote host."); - } - } - catch (Exception ex) - { - await InvokeClosed(ex); + if (enableChat == value) return; + + enableChat = value; + + if (EnableChat) + Task.Run(StartChatAsync); + } + } + + public override async Task ConnectAsync(CancellationToken cancellationToken) + { + if (EnableChat) + await StartChatAsync(); + } + + protected virtual Task StartChatAsync() + { + api.Queue(CreateFetchMessagesRequest(0)); + return Task.CompletedTask; + } + + protected APIRequest CreateFetchMessagesRequest(long? lastMessageId = null) + { + var fetchReq = new GetUpdatesRequest(lastMessageId ?? this.lastMessageId); + + fetchReq.Success += updates => + { + if (updates?.Presence != null) + { + foreach (var channel in updates.Presence) + HandleJoinedChannel(channel); + + //todo: handle left channels + + HandleMessages(updates.Messages); } - } - }), cancellationToken); - private async Task closeAsync() - { - try - { - await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, @"Disconnecting", CancellationToken.None).ConfigureAwait(false); - } - catch - { - // Closure can fail if the connection is aborted. Don't really care since it's disposed anyway. - } + PresenceReceived?.Invoke(); + }; + + return fetchReq; } - private async Task sendMessage(SocketMessage message, CancellationToken cancellationToken) + protected void HandleJoinedChannel(Channel channel) { - if (socket.State != WebSocketState.Open) - return; - - await socket.SendAsync(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message)), WebSocketMessageType.Text, true, cancellationToken); + // we received this from the server so should mark the channel already joined. + channel.Joined.Value = true; + ChannelJoined?.Invoke(channel); } - public override async ValueTask DisposeAsync() + protected void HandleMessages(List messages) { - await base.DisposeAsync(); - await closeAsync(); - socket.Dispose(); + NewMessages?.Invoke(messages); + lastMessageId = Math.Max(lastMessageId, messages.LastOrDefault()?.Id ?? 0); } } } diff --git a/osu.Game/Online/Notifications/NotificationsClientConnector.cs b/osu.Game/Online/Notifications/NotificationsClientConnector.cs index e938ed59f0..5b2d6a4e13 100644 --- a/osu.Game/Online/Notifications/NotificationsClientConnector.cs +++ b/osu.Game/Online/Notifications/NotificationsClientConnector.cs @@ -3,29 +3,27 @@ using System; using System.Collections.Generic; -using System.Net; -using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; namespace osu.Game.Online.Notifications { - public class NotificationsClientConnector : SocketClientConnector + /// + /// An abstract connector or s. + /// + public abstract class NotificationsClientConnector : SocketClientConnector { public event Action? ChannelJoined; public event Action>? NewMessages; public event Action? PresenceReceived; - private readonly IAPIProvider api; private bool chatStarted; - public NotificationsClientConnector(IAPIProvider api) + protected NotificationsClientConnector(IAPIProvider api) : base(api) { - this.api = api; } public void StartChat() @@ -36,30 +34,18 @@ namespace osu.Game.Online.Notifications client.EnableChat = true; } - protected override async Task BuildConnectionAsync(CancellationToken cancellationToken) + protected sealed override async Task BuildConnectionAsync(CancellationToken cancellationToken) { - var tcs = new TaskCompletionSource(); + var client = await BuildNotificationClientAsync(cancellationToken); - var req = new GetNotificationsRequest(); - req.Success += bundle => tcs.SetResult(bundle.Endpoint); - req.Failure += ex => tcs.SetException(ex); - api.Queue(req); + client.ChannelJoined = c => ChannelJoined?.Invoke(c); + client.NewMessages = m => NewMessages?.Invoke(m); + client.PresenceReceived = () => PresenceReceived?.Invoke(); + client.EnableChat = chatStarted; - string endpoint = await tcs.Task; - - ClientWebSocket socket = new ClientWebSocket(); - socket.Options.SetRequestHeader(@"Authorization", @$"Bearer {api.AccessToken}"); - socket.Options.Proxy = WebRequest.DefaultWebProxy; - if (socket.Options.Proxy != null) - socket.Options.Proxy.Credentials = CredentialCache.DefaultCredentials; - - return new NotificationsClient(socket, endpoint, api) - { - ChannelJoined = c => ChannelJoined?.Invoke(c), - NewMessages = m => NewMessages?.Invoke(m), - PresenceReceived = () => PresenceReceived?.Invoke(), - EnableChat = chatStarted - }; + return client; } + + protected abstract Task BuildNotificationClientAsync(CancellationToken cancellationToken); } } diff --git a/osu.Game/Online/Notifications/NotificationsClient_Processing.cs b/osu.Game/Online/Notifications/NotificationsClient_Processing.cs deleted file mode 100644 index 35cf737135..0000000000 --- a/osu.Game/Online/Notifications/NotificationsClient_Processing.cs +++ /dev/null @@ -1,105 +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.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Newtonsoft.Json; -using osu.Game.Online.API.Requests; -using osu.Game.Online.Chat; - -namespace osu.Game.Online.Notifications -{ - public partial class NotificationsClient - { - public Action? ChannelJoined; - public Action>? NewMessages; - public Action? PresenceReceived; - - private bool enableChat; - private long lastMessageId; - - public bool EnableChat - { - get => enableChat; - set - { - if (enableChat == value) - return; - - enableChat = value; - Task.Run(startChatIfEnabledAsync); - } - } - - private async Task onConnectedAsync() - { - await startChatIfEnabledAsync(); - } - - private async Task startChatIfEnabledAsync() - { - if (!EnableChat) - return; - - await sendMessage(new StartChatRequest(), CancellationToken.None); - - var fetchReq = new GetUpdatesRequest(lastMessageId); - - fetchReq.Success += updates => - { - if (updates?.Presence != null) - { - foreach (var channel in updates.Presence) - handleJoinedChannel(channel); - - //todo: handle left channels - - handleMessages(updates.Messages); - } - - PresenceReceived?.Invoke(); - }; - - api.Queue(fetchReq); - } - - private Task onMessageReceivedAsync(SocketMessage message) - { - switch (message.Event) - { - case @"chat.message.new": - Debug.Assert(message.Data != null); - - NewChatMessageData? messageData = JsonConvert.DeserializeObject(message.Data.ToString()); - Debug.Assert(messageData != null); - - List messages = messageData.Messages.Where(m => m.Sender.OnlineID != api.LocalUser.Value.OnlineID).ToList(); - - foreach (var msg in messages) - handleJoinedChannel(new Channel(msg.Sender) { Id = msg.ChannelId }); - - handleMessages(messages); - break; - } - - return Task.CompletedTask; - } - - private void handleJoinedChannel(Channel channel) - { - // we received this from the server so should mark the channel already joined. - channel.Joined.Value = true; - ChannelJoined?.Invoke(channel); - } - - private void handleMessages(List messages) - { - NewMessages?.Invoke(messages); - lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId; - } - } -} diff --git a/osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs b/osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs new file mode 100644 index 0000000000..1c5559fcb4 --- /dev/null +++ b/osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs @@ -0,0 +1,37 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading; +using System.Threading.Tasks; +using osu.Game.Online.API; + +namespace osu.Game.Online.Notifications.Polling +{ + /// + /// A notifications client which polls for new messages every second. + /// + public class PollingNotificationsClient : NotificationsClient + { + private readonly IAPIProvider api; + + public PollingNotificationsClient(IAPIProvider api) + : base(api) + { + this.api = api; + } + + public override Task ConnectAsync(CancellationToken cancellationToken) + { + Task.Run(async () => + { + while (!cancellationToken.IsCancellationRequested) + { + await api.PerformAsync(CreateFetchMessagesRequest()); + await Task.Delay(1000, cancellationToken); + } + }, cancellationToken); + + return Task.CompletedTask; + } + } +} diff --git a/osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs b/osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs new file mode 100644 index 0000000000..18a31ff061 --- /dev/null +++ b/osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Threading; +using System.Threading.Tasks; +using osu.Game.Online.API; + +namespace osu.Game.Online.Notifications.Polling +{ + /// + /// A connector for s that poll for new messages. + /// + public class PollingNotificationsClientConnector : NotificationsClientConnector + { + private readonly IAPIProvider api; + + public PollingNotificationsClientConnector(IAPIProvider api) + : base(api) + { + this.api = api; + } + + protected override Task BuildNotificationClientAsync(CancellationToken cancellationToken) + => Task.FromResult((NotificationsClient)new PollingNotificationsClient(api)); + } +} diff --git a/osu.Game/Online/Notifications/EndChatRequest.cs b/osu.Game/Online/Notifications/WebSocket/EndChatRequest.cs similarity index 65% rename from osu.Game/Online/Notifications/EndChatRequest.cs rename to osu.Game/Online/Notifications/WebSocket/EndChatRequest.cs index f863511804..7f67587f5d 100644 --- a/osu.Game/Online/Notifications/EndChatRequest.cs +++ b/osu.Game/Online/Notifications/WebSocket/EndChatRequest.cs @@ -3,8 +3,11 @@ using Newtonsoft.Json; -namespace osu.Game.Online.Notifications +namespace osu.Game.Online.Notifications.WebSocket { + /// + /// A websocket message notifying the server that the client no longer wants to receive chat messages. + /// [JsonObject(MemberSerialization.OptIn)] public class EndChatRequest : SocketMessage { diff --git a/osu.Game/Online/Notifications/NewChatMessageData.cs b/osu.Game/Online/Notifications/WebSocket/NewChatMessageData.cs similarity index 83% rename from osu.Game/Online/Notifications/NewChatMessageData.cs rename to osu.Game/Online/Notifications/WebSocket/NewChatMessageData.cs index eda9a3a11b..850fbd226b 100644 --- a/osu.Game/Online/Notifications/NewChatMessageData.cs +++ b/osu.Game/Online/Notifications/WebSocket/NewChatMessageData.cs @@ -8,8 +8,11 @@ using Newtonsoft.Json; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -namespace osu.Game.Online.Notifications +namespace osu.Game.Online.Notifications.WebSocket { + /// + /// A websocket message sent from the server when new messages arrive. + /// [JsonObject(MemberSerialization.OptIn)] public class NewChatMessageData { diff --git a/osu.Game/Online/Notifications/SocketMessage.cs b/osu.Game/Online/Notifications/WebSocket/SocketMessage.cs similarity index 77% rename from osu.Game/Online/Notifications/SocketMessage.cs rename to osu.Game/Online/Notifications/WebSocket/SocketMessage.cs index c52072ccd5..666a9dd8a3 100644 --- a/osu.Game/Online/Notifications/SocketMessage.cs +++ b/osu.Game/Online/Notifications/WebSocket/SocketMessage.cs @@ -4,8 +4,11 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace osu.Game.Online.Notifications +namespace osu.Game.Online.Notifications.WebSocket { + /// + /// A websocket message, sent either from the client or server. + /// [JsonObject(MemberSerialization.OptIn)] public class SocketMessage { diff --git a/osu.Game/Online/Notifications/StartChatRequest.cs b/osu.Game/Online/Notifications/WebSocket/StartChatRequest.cs similarity index 66% rename from osu.Game/Online/Notifications/StartChatRequest.cs rename to osu.Game/Online/Notifications/WebSocket/StartChatRequest.cs index d17644ee3b..9dd69a7377 100644 --- a/osu.Game/Online/Notifications/StartChatRequest.cs +++ b/osu.Game/Online/Notifications/WebSocket/StartChatRequest.cs @@ -3,8 +3,11 @@ using Newtonsoft.Json; -namespace osu.Game.Online.Notifications +namespace osu.Game.Online.Notifications.WebSocket { + /// + /// A websocket message notifying the server that the client wants to receive chat messages. + /// [JsonObject(MemberSerialization.OptIn)] public class StartChatRequest : SocketMessage { diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs new file mode 100644 index 0000000000..cadeb8b9fa --- /dev/null +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -0,0 +1,148 @@ +// 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.Diagnostics; +using System.Linq; +using System.Net.WebSockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Newtonsoft.Json; +using osu.Framework.Extensions.TypeExtensions; +using osu.Framework.Logging; +using osu.Game.Online.API; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.Notifications.WebSocket +{ + /// + /// A notifications client which receives events via a websocket. + /// + public class WebSocketNotificationsClient : NotificationsClient + { + private readonly ClientWebSocket socket; + private readonly string endpoint; + private readonly IAPIProvider api; + + public WebSocketNotificationsClient(ClientWebSocket socket, string endpoint, IAPIProvider api) + : base(api) + { + this.socket = socket; + this.endpoint = endpoint; + this.api = api; + } + + public override async Task ConnectAsync(CancellationToken cancellationToken) + { + await socket.ConnectAsync(new Uri(endpoint), cancellationToken).ConfigureAwait(false); + runReadLoop(cancellationToken); + await base.ConnectAsync(cancellationToken); + } + + protected override async Task StartChatAsync() + { + await sendMessage(new StartChatRequest(), CancellationToken.None); + await base.StartChatAsync(); + } + + private void runReadLoop(CancellationToken cancellationToken) => Task.Run((Func)(async () => + { + byte[] buffer = new byte[1024]; + StringBuilder messageResult = new StringBuilder(); + + while (!cancellationToken.IsCancellationRequested) + { + try + { + WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, cancellationToken); + + switch (result.MessageType) + { + case WebSocketMessageType.Text: + messageResult.Append(Encoding.UTF8.GetString(buffer[..result.Count])); + + if (result.EndOfMessage) + { + SocketMessage? message = JsonConvert.DeserializeObject(messageResult.ToString()); + messageResult.Clear(); + + Debug.Assert(message != null); + + if (message.Error != null) + { + Logger.Log($"{GetType().ReadableName()} error: {message.Error}", LoggingTarget.Network); + break; + } + + await onMessageReceivedAsync(message); + } + + break; + + case WebSocketMessageType.Binary: + throw new NotImplementedException(); + + case WebSocketMessageType.Close: + throw new Exception("Connection closed by remote host."); + } + } + catch (Exception ex) + { + await InvokeClosed(ex); + return; + } + } + }), cancellationToken); + + private async Task closeAsync() + { + try + { + await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, @"Disconnecting", CancellationToken.None).ConfigureAwait(false); + } + catch + { + // Closure can fail if the connection is aborted. Don't really care since it's disposed anyway. + } + } + + private async Task sendMessage(SocketMessage message, CancellationToken cancellationToken) + { + if (socket.State != WebSocketState.Open) + return; + + await socket.SendAsync(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message)), WebSocketMessageType.Text, true, cancellationToken); + } + + private Task onMessageReceivedAsync(SocketMessage message) + { + switch (message.Event) + { + case @"chat.message.new": + Debug.Assert(message.Data != null); + + NewChatMessageData? messageData = JsonConvert.DeserializeObject(message.Data.ToString()); + Debug.Assert(messageData != null); + + List messages = messageData.Messages.Where(m => m.Sender.OnlineID != api.LocalUser.Value.OnlineID).ToList(); + + foreach (var msg in messages) + HandleJoinedChannel(new Channel(msg.Sender) { Id = msg.ChannelId }); + + HandleMessages(messages); + break; + } + + return Task.CompletedTask; + } + + public override async ValueTask DisposeAsync() + { + await base.DisposeAsync(); + await closeAsync(); + socket.Dispose(); + } + } +} diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs new file mode 100644 index 0000000000..21335a3b59 --- /dev/null +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs @@ -0,0 +1,46 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Net; +using System.Net.WebSockets; +using System.Threading; +using System.Threading.Tasks; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; + +namespace osu.Game.Online.Notifications.WebSocket +{ + /// + /// A connector for s that receive events via a websocket. + /// + public class WebSocketNotificationsClientConnector : NotificationsClientConnector + { + private readonly IAPIProvider api; + + public WebSocketNotificationsClientConnector(IAPIProvider api) + : base(api) + { + this.api = api; + } + + protected override async Task BuildNotificationClientAsync(CancellationToken cancellationToken) + { + var tcs = new TaskCompletionSource(); + + var req = new GetNotificationsRequest(); + req.Success += bundle => tcs.SetResult(bundle.Endpoint); + req.Failure += ex => tcs.SetException(ex); + api.Queue(req); + + string endpoint = await tcs.Task; + + ClientWebSocket socket = new ClientWebSocket(); + socket.Options.SetRequestHeader(@"Authorization", @$"Bearer {api.AccessToken}"); + socket.Options.Proxy = WebRequest.DefaultWebProxy; + if (socket.Options.Proxy != null) + socket.Options.Proxy.Credentials = CredentialCache.DefaultCredentials; + + return new WebSocketNotificationsClient(socket, endpoint, api); + } + } +} diff --git a/osu.Game/Online/SocketClient.cs b/osu.Game/Online/SocketClient.cs index 3b4aa1b49b..748e77fc0b 100644 --- a/osu.Game/Online/SocketClient.cs +++ b/osu.Game/Online/SocketClient.cs @@ -13,7 +13,7 @@ namespace osu.Game.Online protected Task InvokeClosed(Exception? exception) => Closed?.Invoke(exception) ?? Task.CompletedTask; - public abstract Task StartAsync(CancellationToken cancellationToken); + public abstract Task ConnectAsync(CancellationToken cancellationToken); public virtual ValueTask DisposeAsync() { diff --git a/osu.Game/Online/SocketClientConnector.cs b/osu.Game/Online/SocketClientConnector.cs index 823e724ef9..4ce5c75ba8 100644 --- a/osu.Game/Online/SocketClientConnector.cs +++ b/osu.Game/Online/SocketClientConnector.cs @@ -92,7 +92,7 @@ namespace osu.Game.Online cancellationToken.ThrowIfCancellationRequested(); - await CurrentConnection.StartAsync(cancellationToken).ConfigureAwait(false); + await CurrentConnection.ConnectAsync(cancellationToken).ConfigureAwait(false); Logger.Log($"{ClientName} connected!", LoggingTarget.Network); isConnected.Value = true; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 7a42007fb8..df3000a547 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -45,6 +45,7 @@ using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Online.Notifications; +using osu.Game.Online.Notifications.Polling; using osu.Game.Overlays; using osu.Game.Overlays.Music; using osu.Game.Overlays.Notifications; @@ -882,7 +883,7 @@ namespace osu.Game loadComponentSingleFile(dashboard = new DashboardOverlay(), overlayContent.Add, true); loadComponentSingleFile(news = new NewsOverlay(), overlayContent.Add, true); var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true); - loadComponentSingleFile(notificationsClient = new NotificationsClientConnector(API), AddInternal, true); + loadComponentSingleFile(notificationsClient = new PollingNotificationsClientConnector(API), AddInternal, true); loadComponentSingleFile(channelManager = new ChannelManager(API), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(new MessageNotifier(), AddInternal, true); From 66ed77ac91f7a9ab4cd6297833fba3f52a044bf5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 18:04:28 +0900 Subject: [PATCH 1932/2686] Rename and add documentation to function --- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- osu.Game/Database/LegacyExporter.cs | 2 +- osu.Game/Extensions/ModelExtensions.cs | 16 +++++++++------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index befc56d244..965cc43815 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -340,7 +340,7 @@ namespace osu.Game.Beatmaps static string createBeatmapFilenameFromMetadata(BeatmapInfo beatmapInfo) { var metadata = beatmapInfo.Metadata; - return $"{metadata.Artist} - {metadata.Title} ({metadata.Author.Username}) [{beatmapInfo.DifficultyName}].osu".GetValidArchiveContentFilename(); + return $"{metadata.Artist} - {metadata.Title} ({metadata.Author.Username}) [{beatmapInfo.DifficultyName}].osu".GetValidFilename(); } } diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index d9fdc40abc..16d7441dde 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -37,7 +37,7 @@ namespace osu.Game.Database /// The item to export. public void Export(TModel item) { - string filename = $"{item.GetDisplayString().GetValidArchiveContentFilename()}{FileExtension}"; + string filename = $"{item.GetDisplayString().GetValidFilename()}{FileExtension}"; using (var stream = exportStorage.CreateFileSafely(filename)) ExportModelTo(item, stream); diff --git a/osu.Game/Extensions/ModelExtensions.cs b/osu.Game/Extensions/ModelExtensions.cs index f8db5f4e88..efb3c4d633 100644 --- a/osu.Game/Extensions/ModelExtensions.cs +++ b/osu.Game/Extensions/ModelExtensions.cs @@ -15,6 +15,8 @@ namespace osu.Game.Extensions { public static class ModelExtensions { + private static readonly Regex invalid_filename_chars = new Regex(@"(?!$)[^A-Za-z0-9_()[\]. \-]", RegexOptions.Compiled); + /// /// Get the relative path in osu! storage for this file. /// @@ -137,14 +139,14 @@ namespace osu.Game.Extensions return instance.OnlineID.Equals(other.OnlineID); } - private static readonly Regex invalid_filename_chars = new Regex(@"(?!$)[^A-Za-z0-9_()[\]. \-]", RegexOptions.Compiled); - /// - /// Get a valid filename for use inside a zip file. Avoids backslashes being incorrectly converted to directories. + /// Create a valid filename which should work across all platforms. /// - public static string GetValidArchiveContentFilename(this string filename) - { - return invalid_filename_chars.Replace(filename, "_"); - } + /// + /// This function replaces all characters not included in a very pessimistic list which should be compatible + /// across all operating systems. We are using this in place of as + /// that function does not have per-platform considerations (and is only made to work on windows). + /// + public static string GetValidFilename(this string filename) => invalid_filename_chars.Replace(filename, "_"); } } From f46a9d683aebe2f3bef438792bee1921466e727f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 18:07:25 +0900 Subject: [PATCH 1933/2686] Fix null reference in headless tests --- osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index f77e1bfc6a..7f0bded806 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -244,7 +244,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics else displayDropdown.Hide(); - if (host.Window.SafeAreaPadding.Value.Total != Vector2.Zero) + if (host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero) safeAreaConsiderationsCheckbox.Show(); else safeAreaConsiderationsCheckbox.Hide(); From 169bcc265416b52324ab12d177f32b771fa09a0d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 28 Oct 2022 18:08:08 +0900 Subject: [PATCH 1934/2686] Use polling connector in tests --- .../Chat/TestSceneChannelManager.cs | 3 ++- .../Visual/Online/TestSceneChatLink.cs | 5 ++++- .../Visual/Online/TestSceneChatOverlay.cs | 3 ++- .../Visual/Online/TestSceneMessageNotifier.cs | 3 ++- .../Online/TestSceneStandAloneChatDisplay.cs | 5 ++++- .../Components/TournamentMatchChatDisplay.cs | 3 ++- osu.Game/Online/Chat/ChannelManager.cs | 14 ++++++++++---- osu.Game/Online/SocketClientConnector.cs | 19 +++++++++++++++---- osu.Game/OsuGame.cs | 6 +++--- 9 files changed, 44 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index e7eb06c795..84609a2733 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -13,6 +13,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; +using osu.Game.Online.Notifications.Polling; using osu.Game.Tests.Visual; namespace osu.Game.Tests.Chat @@ -151,7 +152,7 @@ namespace osu.Game.Tests.Chat public ChannelManagerContainer(IAPIProvider apiProvider) { - InternalChild = ChannelManager = new ChannelManager(apiProvider); + InternalChild = ChannelManager = new ChannelManager(apiProvider, new PollingNotificationsClientConnector(apiProvider)); } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs index a537f0660c..63526d4278 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; +using osu.Game.Online.Notifications.Polling; using osu.Game.Overlays.Chat; using osuTK.Graphics; @@ -41,11 +42,13 @@ namespace osu.Game.Tests.Visual.Online { linkColour = colours.Blue; - var chatManager = new ChannelManager(API); + var chatManager = new ChannelManager(API, new PollingNotificationsClientConnector(API)); BindableList availableChannels = (BindableList)chatManager.AvailableChannels; availableChannels.Add(new Channel { Name = "#english" }); availableChannels.Add(new Channel { Name = "#japanese" }); Dependencies.Cache(chatManager); + + Add(chatManager); } [SetUp] diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 0b982a5745..dee258f747 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -24,6 +24,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; +using osu.Game.Online.Notifications.Polling; using osu.Game.Overlays; using osu.Game.Overlays.Chat; using osu.Game.Overlays.Chat.Listing; @@ -59,7 +60,7 @@ namespace osu.Game.Tests.Visual.Online RelativeSizeAxes = Axes.Both, CachedDependencies = new (Type, object)[] { - (typeof(ChannelManager), channelManager = new ChannelManager(API)), + (typeof(ChannelManager), channelManager = new ChannelManager(API, new PollingNotificationsClientConnector(API))), }, Children = new Drawable[] { diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 57514cdf37..6d83fb3123 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -16,6 +16,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; +using osu.Game.Online.Notifications.Polling; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osuTK.Input; @@ -250,7 +251,7 @@ namespace osu.Game.Tests.Visual.Online public TestContainer(IAPIProvider api, Channel[] channels) { this.channels = channels; - ChannelManager = new ChannelManager(api); + ChannelManager = new ChannelManager(api, new PollingNotificationsClientConnector(api)); } [BackgroundDependencyLoader] diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index 292facab11..f1daa05e08 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -15,6 +15,7 @@ using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Notifications.Polling; using osu.Game.Overlays.Chat; using osuTK.Input; @@ -56,7 +57,9 @@ namespace osu.Game.Tests.Visual.Online protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { - Add(channelManager = new ChannelManager(parent.Get())); + var api = parent.Get(); + + Add(channelManager = new ChannelManager(api, new PollingNotificationsClientConnector(api))); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs index ca2b400e8b..99cd9beecf 100644 --- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs @@ -9,6 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Online.API; using osu.Game.Online.Chat; +using osu.Game.Online.Notifications.WebSocket; using osu.Game.Overlays.Chat; using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; @@ -48,7 +49,7 @@ namespace osu.Game.Tournament.Components if (manager == null) { - AddInternal(manager = new ChannelManager(api)); + AddInternal(manager = new ChannelManager(api, new WebSocketNotificationsClientConnector(api))); Channel.BindTo(manager.CurrentChannel); } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index b63f841f59..ab3ac6f692 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -65,20 +65,20 @@ namespace osu.Game.Online.Chat public IBindableList AvailableChannels => availableChannels; private readonly IAPIProvider api; + private readonly NotificationsClientConnector connector; [Resolved] private UserLookupCache users { get; set; } - [Resolved] - private NotificationsClientConnector connector { get; set; } - private readonly IBindable apiState = new Bindable(); private bool channelsInitialised; private ScheduledDelegate ackDelegate; - public ChannelManager(IAPIProvider api) + public ChannelManager(IAPIProvider api, NotificationsClientConnector connector) { this.api = api; + this.connector = connector; + CurrentChannel.ValueChanged += currentChannelChanged; } @@ -603,6 +603,12 @@ namespace osu.Game.Online.Chat api.Queue(req); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + connector?.Dispose(); + } } /// diff --git a/osu.Game/Online/SocketClientConnector.cs b/osu.Game/Online/SocketClientConnector.cs index 4ce5c75ba8..c6d5601c1f 100644 --- a/osu.Game/Online/SocketClientConnector.cs +++ b/osu.Game/Online/SocketClientConnector.cs @@ -6,13 +6,12 @@ using System.Threading; using System.Threading.Tasks; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; -using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Game.Online.API; namespace osu.Game.Online { - public abstract class SocketClientConnector : Component + public abstract class SocketClientConnector : IDisposable { /// /// Whether this is connected to the hub, use to access the connection, if this is true. @@ -173,11 +172,23 @@ namespace osu.Game.Online public override string ToString() => $"{ClientName} ({(IsConnected.Value ? "connected" : "not connected")})"; - protected override void Dispose(bool isDisposing) + private bool isDisposed; + + protected virtual void Dispose(bool isDisposing) { - base.Dispose(isDisposing); + if (isDisposed) + return; + apiState.UnbindAll(); cancelExistingConnect(); + + isDisposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); } } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index df3000a547..4ceefbf1fd 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -45,7 +45,7 @@ using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Online.Notifications; -using osu.Game.Online.Notifications.Polling; +using osu.Game.Online.Notifications.WebSocket; using osu.Game.Overlays; using osu.Game.Overlays.Music; using osu.Game.Overlays.Notifications; @@ -757,6 +757,7 @@ namespace osu.Game BackButton.Receptor receptor; dependencies.CacheAs(idleTracker = new GameIdleTracker(6000)); + dependencies.CacheAs(notificationsClient = new WebSocketNotificationsClientConnector(API)); var sessionIdleTracker = new GameIdleTracker(300000); sessionIdleTracker.IsIdle.BindValueChanged(idle => @@ -883,8 +884,7 @@ namespace osu.Game loadComponentSingleFile(dashboard = new DashboardOverlay(), overlayContent.Add, true); loadComponentSingleFile(news = new NewsOverlay(), overlayContent.Add, true); var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true); - loadComponentSingleFile(notificationsClient = new PollingNotificationsClientConnector(API), AddInternal, true); - loadComponentSingleFile(channelManager = new ChannelManager(API), AddInternal, true); + loadComponentSingleFile(channelManager = new ChannelManager(API, notificationsClient), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(new MessageNotifier(), AddInternal, true); loadComponentSingleFile(Settings = new SettingsOverlay(), leftFloatingOverlayContent.Add, true); From e87b541c5893d2c642abac4f288e83cd53e2d8f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 18:29:55 +0900 Subject: [PATCH 1935/2686] Add fade to banana's lighting as it approaches the catcher This also avoids using the `UprightScalingContainer` (and allows for scale adjust in the process). --- .../Skinning/Argon/ArgonBananaPiece.cs | 21 ++++++++++++++++--- .../Skinning/Default/BananaPiece.cs | 6 ++---- .../Skinning/Default/CatchHitObjectPiece.cs | 2 +- .../Skinning/Default/FruitPiece.cs | 2 +- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs index 49edc80770..1a37136f53 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs @@ -5,9 +5,10 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics.Containers; +using osu.Game.Rulesets.Catch.Objects; using osuTK; using osuTK.Graphics; @@ -15,10 +16,14 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { internal class ArgonBananaPiece : ArgonFruitPiece { + private Container stabilisedPieceContainer = null!; + + protected override Drawable BorderPiece => stabilisedPieceContainer; + [BackgroundDependencyLoader] private void load() { - AddInternal(new UprightAspectMaintainingContainer + AddInternal(stabilisedPieceContainer = new Container { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, @@ -44,7 +49,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon Width = 1.6f, Height = 2, }, - new Box + new Circle { Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.White.Opacity(0)), RelativeSizeAxes = Axes.X, @@ -78,5 +83,15 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon } }); } + + protected override void Update() + { + base.Update(); + + float scale = 0.5f + 0.5f * (1 / (ObjectState.DisplaySize.X / (CatchHitObject.OBJECT_RADIUS * 2))); + + stabilisedPieceContainer.Rotation = -ObjectState.DisplayRotation; + stabilisedPieceContainer.Scale = new Vector2(scale); + } } } diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs index 27252594af..359756f159 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs @@ -1,21 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Default { public class BananaPiece : CatchHitObjectPiece { - protected override BorderPiece BorderPiece { get; } + protected override Drawable BorderPiece { get; } public BananaPiece() { RelativeSizeAxes = Axes.Both; - InternalChildren = new Drawable[] + InternalChildren = new[] { new BananaPulpFormation { diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs index fd1047f27e..3b8df6ee6f 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default /// A part of this piece that will be faded out while falling in the playfield. /// [CanBeNull] - protected virtual BorderPiece BorderPiece => null; + protected virtual Drawable BorderPiece => null; /// /// A part of this piece that will be only visible when is true. diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs index 9dce0e9129..adee960c3c 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default public readonly Bindable VisualRepresentation = new Bindable(); - protected override BorderPiece BorderPiece { get; } + protected override Drawable BorderPiece { get; } protected override Drawable HyperBorderPiece { get; } public FruitPiece() From ab78cde2d471fe3478f0a5ac4efc074b102c4f2c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 28 Oct 2022 18:37:43 +0900 Subject: [PATCH 1936/2686] Fix crossthread mutations --- osu.Game/Online/Chat/ChannelManager.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index ab3ac6f692..a901c15bf4 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -85,9 +85,9 @@ namespace osu.Game.Online.Chat [BackgroundDependencyLoader] private void load() { - connector.ChannelJoined += ch => joinChannel(ch); - connector.NewMessages += addMessages; - connector.PresenceReceived += () => + connector.ChannelJoined += ch => Schedule(() => joinChannel(ch)); + connector.NewMessages += msgs => Schedule(() => addMessages(msgs)); + connector.PresenceReceived += () => Schedule(() => { if (!channelsInitialised) { @@ -95,7 +95,7 @@ namespace osu.Game.Online.Chat // we want this to run after the first presence so we can see if the user is in any channels already. initializeChannels(); } - }; + }); connector.StartChat(); From d3173ab1bd836d4061325beb67b8a40eb98cd658 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 28 Oct 2022 18:54:34 +0900 Subject: [PATCH 1937/2686] Remove weird cast --- .../Notifications/WebSocket/WebSocketNotificationsClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index cadeb8b9fa..ff0941ecba 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -47,7 +47,7 @@ namespace osu.Game.Online.Notifications.WebSocket await base.StartChatAsync(); } - private void runReadLoop(CancellationToken cancellationToken) => Task.Run((Func)(async () => + private void runReadLoop(CancellationToken cancellationToken) => Task.Run(async () => { byte[] buffer = new byte[1024]; StringBuilder messageResult = new StringBuilder(); @@ -94,7 +94,7 @@ namespace osu.Game.Online.Notifications.WebSocket return; } } - }), cancellationToken); + }, cancellationToken); private async Task closeAsync() { From 40efa1603bf1d8c0ea8688753a9f1cfab110df15 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 19:35:50 +0900 Subject: [PATCH 1938/2686] Adjust metrics to make banana lens flares look better --- .../Objects/Drawables/CaughtObject.cs | 2 + .../DrawablePalpableCatchHitObject.cs | 2 + .../Objects/Drawables/IHasCatchObjectState.cs | 2 + .../Skinning/Argon/ArgonBananaPiece.cs | 87 ++++++++++++------- 4 files changed, 62 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs index fd0ffbd032..ddfbb34435 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs @@ -28,6 +28,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables public float DisplayRotation => Rotation; + public double DisplayStartTime => HitObject.StartTime; + /// /// Whether this hit object should stay on the catcher plate when the object is caught by the catcher. /// diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs index 5de372852b..dd09b6c06d 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs @@ -18,6 +18,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables { public new PalpableCatchHitObject HitObject => (PalpableCatchHitObject)base.HitObject; + public double DisplayStartTime => LifetimeStart; + Bindable IHasCatchObjectState.AccentColour => AccentColour; public Bindable HyperDash { get; } = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs index 93c80b09db..f30ef0831a 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs @@ -16,6 +16,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables { PalpableCatchHitObject HitObject { get; } + double DisplayStartTime { get; } + Bindable AccentColour { get; } Bindable HyperDash { get; } diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs index 1a37136f53..f8a71cbec9 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; using osu.Game.Rulesets.Catch.Objects; using osuTK; using osuTK.Graphics; @@ -18,46 +19,53 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { private Container stabilisedPieceContainer = null!; - protected override Drawable BorderPiece => stabilisedPieceContainer; + private Drawable fadeContent = null!; [BackgroundDependencyLoader] private void load() { - AddInternal(stabilisedPieceContainer = new Container + AddInternal(fadeContent = new Container { RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, Children = new Drawable[] { - new Circle + stabilisedPieceContainer = new Container { - Colour = Color4.White.Opacity(0.4f), + RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Blending = BlendingParameters.Additive, - Size = new Vector2(8), - Scale = new Vector2(30, 1), - }, - new Box - { - Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0), Color4.White), - RelativeSizeAxes = Axes.X, - Blending = BlendingParameters.Additive, - Anchor = Anchor.Centre, - Origin = Anchor.CentreRight, - Width = 1.6f, - Height = 2, - }, - new Circle - { - Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.White.Opacity(0)), - RelativeSizeAxes = Axes.X, - Blending = BlendingParameters.Additive, - Anchor = Anchor.Centre, - Origin = Anchor.CentreLeft, - Width = 1.6f, - Height = 2, + Children = new Drawable[] + { + new Circle + { + Colour = Color4.White.Opacity(0.4f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Size = new Vector2(8), + Scale = new Vector2(25, 1), + }, + new Box + { + Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0), Color4.White.Opacity(0.8f)), + RelativeSizeAxes = Axes.X, + Blending = BlendingParameters.Additive, + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + Width = 1.6f, + Height = 2, + }, + new Circle + { + Colour = ColourInfo.GradientHorizontal(Color4.White.Opacity(0.8f), Color4.White.Opacity(0)), + RelativeSizeAxes = Axes.X, + Blending = BlendingParameters.Additive, + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + Width = 1.6f, + Height = 2, + }, + } }, new Circle { @@ -88,10 +96,27 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { base.Update(); - float scale = 0.5f + 0.5f * (1 / (ObjectState.DisplaySize.X / (CatchHitObject.OBJECT_RADIUS * 2))); + const float parent_scale_application = 0.4f; + + // relative to time on screen + const float lens_flare_start = 0.3f; + const float lens_flare_end = 0.3f; + + // Undo some of the parent scale being applied to make the lens flare feel a bit better.. + float scale = parent_scale_application + (1 - parent_scale_application) * (1 / (ObjectState.DisplaySize.X / (CatchHitObject.OBJECT_RADIUS * 2))); stabilisedPieceContainer.Rotation = -ObjectState.DisplayRotation; - stabilisedPieceContainer.Scale = new Vector2(scale); + stabilisedPieceContainer.Scale = new Vector2(scale, 1); + + double duration = ObjectState.HitObject.StartTime - ObjectState.DisplayStartTime; + + fadeContent.Alpha = MathHelper.Clamp( + Interpolation.ValueAt( + Time.Current, 1f, 0f, + ObjectState.DisplayStartTime + duration * lens_flare_start, + ObjectState.DisplayStartTime + duration * lens_flare_end, + Easing.OutQuint + ), 0, 1); } } } From 0c25658805458f016f2a2ca64729134a2b00b400 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2022 21:58:38 +0900 Subject: [PATCH 1939/2686] 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 5d6c32cea8..b691751f13 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5d1a834b0e..9dd0d18817 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index bf218f856a..6dce938ebf 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 21d68bfb84dfeaf6605623b2700cec2faa5ed147 Mon Sep 17 00:00:00 2001 From: "D.Headley" Date: Fri, 28 Oct 2022 16:40:21 +0200 Subject: [PATCH 1940/2686] Delete unused button --- .../Screens/Edit/Components/CircularButton.cs | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 osu.Game/Screens/Edit/Components/CircularButton.cs diff --git a/osu.Game/Screens/Edit/Components/CircularButton.cs b/osu.Game/Screens/Edit/Components/CircularButton.cs deleted file mode 100644 index 74e4162102..0000000000 --- a/osu.Game/Screens/Edit/Components/CircularButton.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using osu.Game.Graphics.UserInterface; -using osuTK; - -namespace osu.Game.Screens.Edit.Components -{ - public class CircularButton : OsuButton - { - private const float width = 125; - private const float height = 30; - - public CircularButton() - { - Size = new Vector2(width, height); - } - - protected override void Update() - { - base.Update(); - Content.CornerRadius = DrawHeight / 2f; - Content.CornerExponent = 2; - } - } -} From 19e0b9085c473a2470e86b167d1e2ae05c28ac91 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 29 Oct 2022 00:24:33 +0900 Subject: [PATCH 1941/2686] Remove redundant parameters --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs | 2 +- osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs | 2 +- .../NonVisual/CustomTourneyDirectoryTest.cs | 2 +- osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs index de6ca7dd38..a41ed17d78 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs @@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { // For the same reasons as above w.r.t rewinding, we shouldn't propagate to children here either. // ReSharper disable once RedundantArgumentDefaultValue - removing the "redundant" default value triggers BaseMethodCallWithDefaultParameter - base.ApplyTransformsAt(time, false); + base.ApplyTransformsAt(time); } private bool tracking; diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs index 604b87dc4c..9079ecdc48 100644 --- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs +++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs @@ -188,7 +188,7 @@ namespace osu.Game.Tests.Collections.IO } // Name matches the automatically chosen name from `CleanRunHeadlessGameHost` above, so we end up using the same storage location. - using (HeadlessGameHost host = new TestRunHeadlessGameHost(firstRunName, null)) + using (HeadlessGameHost host = new TestRunHeadlessGameHost(firstRunName)) { try { diff --git a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs index f778e67f58..45dffdc94a 100644 --- a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs +++ b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tournament.Tests.NonVisual [Test] public void TestCustomDirectory() { - using (HeadlessGameHost host = new TestRunHeadlessGameHost(nameof(TestCustomDirectory), null)) // don't use clean run as we are writing a config file. + using (HeadlessGameHost host = new TestRunHeadlessGameHost(nameof(TestCustomDirectory))) // don't use clean run as we are writing a config file. { string osuDesktopStorage = Path.Combine(host.UserStoragePaths.First(), nameof(TestCustomDirectory)); const string custom_tournament = "custom"; diff --git a/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs b/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs index 1bbbcc3661..ca6354cb48 100644 --- a/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs +++ b/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs @@ -21,7 +21,7 @@ namespace osu.Game.Tournament.Tests.NonVisual public void CheckIPCLocation() { // don't use clean run because files are being written before osu! launches. - using (var host = new TestRunHeadlessGameHost(nameof(CheckIPCLocation), null)) + using (var host = new TestRunHeadlessGameHost(nameof(CheckIPCLocation))) { string basePath = Path.Combine(host.UserStoragePaths.First(), nameof(CheckIPCLocation)); From 295c40581b766b14d2fe9d453a396608aeb142d7 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 28 Oct 2022 20:18:11 +0300 Subject: [PATCH 1942/2686] Add a global popover container --- osu.Game/OsuGameBase.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 7d9ed7bf3e..2e2f6f0832 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -18,6 +18,7 @@ using osu.Framework.Development; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Textures; using osu.Framework.Input; using osu.Framework.Input.Handlers; @@ -350,9 +351,13 @@ namespace osu.Game (GlobalCursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both - }).WithChild(content = new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor) + }).WithChild(new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor) { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + Child = content = new PopoverContainer + { + RelativeSizeAxes = Axes.Both, + } }), // to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything. globalBindings = new GlobalActionContainer(this) From 9df96aab38fa7e83ef2055af3c96189e24d7fb50 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 28 Oct 2022 22:17:45 +0300 Subject: [PATCH 1943/2686] Remove local popover containers --- osu.Game/Overlays/BeatmapSetOverlay.cs | 24 +++++++------------ .../Overlays/Changelog/ChangelogContent.cs | 17 +++---------- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 904fd6ead6..207dc91ca5 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -10,7 +10,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.BeatmapSet; @@ -45,25 +44,20 @@ namespace osu.Game.Overlays Info info; CommentsSection comments; - Child = new PopoverContainer + Child = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Child = new FillFlowContainer + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 20), + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 20), - Children = new Drawable[] + info = new Info(), + new ScoresContainer { - info = new Info(), - new ScoresContainer - { - Beatmap = { BindTarget = Header.HeaderContent.Picker.Beatmap } - }, - comments = new CommentsSection() - } + Beatmap = { BindTarget = Header.HeaderContent.Picker.Beatmap } + }, + comments = new CommentsSection() } }; diff --git a/osu.Game/Overlays/Changelog/ChangelogContent.cs b/osu.Game/Overlays/Changelog/ChangelogContent.cs index 2b54df7226..e04133f2e4 100644 --- a/osu.Game/Overlays/Changelog/ChangelogContent.cs +++ b/osu.Game/Overlays/Changelog/ChangelogContent.cs @@ -1,35 +1,24 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.API.Requests.Responses; using System; -using osu.Framework.Graphics.Cursor; namespace osu.Game.Overlays.Changelog { - public class ChangelogContent : PopoverContainer + public class ChangelogContent : FillFlowContainer { - public Action BuildSelected; + public Action? BuildSelected; public void SelectBuild(APIChangelogBuild build) => BuildSelected?.Invoke(build); - protected override Container Content { get; } - public ChangelogContent() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - - base.Content.Add(Content = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical - }); + Direction = FillDirection.Vertical; } } } From a985151e3173f5605d49288bccf4b5346fb32d3b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 29 Oct 2022 18:06:25 +0900 Subject: [PATCH 1944/2686] Fix incorrect constant --- osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs index f8a71cbec9..9a657c9216 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon // relative to time on screen const float lens_flare_start = 0.3f; - const float lens_flare_end = 0.3f; + const float lens_flare_end = 0.8f; // Undo some of the parent scale being applied to make the lens flare feel a bit better.. float scale = parent_scale_application + (1 - parent_scale_application) * (1 / (ObjectState.DisplaySize.X / (CatchHitObject.OBJECT_RADIUS * 2))); From 8c9250285f0fe2188a56451b67c7643b81b49dbf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 29 Oct 2022 18:09:27 +0900 Subject: [PATCH 1945/2686] Revert incorrect removal default value (causing a new warning) --- .../Objects/Drawables/DrawableSliderBall.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs index a41ed17d78..9966ad3a90 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs @@ -79,8 +79,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public override void ApplyTransformsAt(double time, bool propagateChildren = false) { // For the same reasons as above w.r.t rewinding, we shouldn't propagate to children here either. - // ReSharper disable once RedundantArgumentDefaultValue - removing the "redundant" default value triggers BaseMethodCallWithDefaultParameter - base.ApplyTransformsAt(time); + + // ReSharper disable once RedundantArgumentDefaultValue + base.ApplyTransformsAt(time, false); } private bool tracking; From d56786b5ff051ab358b5e0b4c180fdc7743b247d Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 29 Oct 2022 15:25:16 -0700 Subject: [PATCH 1946/2686] Fix toolbar visual bug when toggling clock displays --- osu.Game/Overlays/Toolbar/Toolbar.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 82fa20aa9c..9d0f43c45a 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -141,6 +141,8 @@ namespace osu.Game.Overlays.Toolbar Name = "Right buttons", RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, Children = new Drawable[] { new Box From 24c27e62f6e9a45774b78cf44cbe0b9df21b10d0 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 30 Oct 2022 16:25:15 +0800 Subject: [PATCH 1947/2686] Remove nullable disable annotation in the issue and issue template-related class. --- osu.Game/Rulesets/Edit/Checks/Components/CheckCategory.cs | 2 -- osu.Game/Rulesets/Edit/Checks/Components/CheckMetadata.cs | 2 -- osu.Game/Rulesets/Edit/Checks/Components/ICheck.cs | 2 -- osu.Game/Rulesets/Edit/Checks/Components/Issue.cs | 2 -- osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.cs | 2 -- osu.Game/Rulesets/Edit/Checks/Components/IssueType.cs | 2 -- 6 files changed, 12 deletions(-) diff --git a/osu.Game/Rulesets/Edit/Checks/Components/CheckCategory.cs b/osu.Game/Rulesets/Edit/Checks/Components/CheckCategory.cs index 3e2150fe0b..ae943cfda9 100644 --- a/osu.Game/Rulesets/Edit/Checks/Components/CheckCategory.cs +++ b/osu.Game/Rulesets/Edit/Checks/Components/CheckCategory.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. -#nullable disable - namespace osu.Game.Rulesets.Edit.Checks.Components { /// diff --git a/osu.Game/Rulesets/Edit/Checks/Components/CheckMetadata.cs b/osu.Game/Rulesets/Edit/Checks/Components/CheckMetadata.cs index 5c9021ba61..cebb2f5455 100644 --- a/osu.Game/Rulesets/Edit/Checks/Components/CheckMetadata.cs +++ b/osu.Game/Rulesets/Edit/Checks/Components/CheckMetadata.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. -#nullable disable - namespace osu.Game.Rulesets.Edit.Checks.Components { public class CheckMetadata diff --git a/osu.Game/Rulesets/Edit/Checks/Components/ICheck.cs b/osu.Game/Rulesets/Edit/Checks/Components/ICheck.cs index 333ec0a810..141de55f1d 100644 --- a/osu.Game/Rulesets/Edit/Checks/Components/ICheck.cs +++ b/osu.Game/Rulesets/Edit/Checks/Components/ICheck.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. -#nullable disable - using System.Collections.Generic; namespace osu.Game.Rulesets.Edit.Checks.Components diff --git a/osu.Game/Rulesets/Edit/Checks/Components/Issue.cs b/osu.Game/Rulesets/Edit/Checks/Components/Issue.cs index b3f227f364..2bc9930e8f 100644 --- a/osu.Game/Rulesets/Edit/Checks/Components/Issue.cs +++ b/osu.Game/Rulesets/Edit/Checks/Components/Issue.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; diff --git a/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.cs b/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.cs index 9101d83fa7..97df79ecd8 100644 --- a/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.cs +++ b/osu.Game/Rulesets/Edit/Checks/Components/IssueTemplate.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. -#nullable disable - using Humanizer; using osu.Framework.Graphics; using osuTK.Graphics; diff --git a/osu.Game/Rulesets/Edit/Checks/Components/IssueType.cs b/osu.Game/Rulesets/Edit/Checks/Components/IssueType.cs index a957cbc296..1f708209fe 100644 --- a/osu.Game/Rulesets/Edit/Checks/Components/IssueType.cs +++ b/osu.Game/Rulesets/Edit/Checks/Components/IssueType.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. -#nullable disable - namespace osu.Game.Rulesets.Edit.Checks.Components { /// From db48a57fa7f52be8acee66942e92c118b6a23eb8 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 30 Oct 2022 16:28:49 +0800 Subject: [PATCH 1948/2686] Remove nullable disable annotation in some checks class. --- osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs | 4 +--- osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs | 2 -- osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs | 4 +--- osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs | 2 -- osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs | 6 ++---- osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs | 2 -- osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs | 2 -- osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs | 4 +--- osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs | 4 +--- osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs | 2 -- osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs | 2 -- osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs | 2 -- osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs | 2 -- 13 files changed, 6 insertions(+), 32 deletions(-) diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs index a66c00d78b..f712a7867d 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioInVideo.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. -#nullable disable - using System.Collections.Generic; using System.IO; using osu.Game.Beatmaps; @@ -45,7 +43,7 @@ namespace osu.Game.Rulesets.Edit.Checks foreach (string filename in videoPaths) { - string storagePath = beatmapSet?.GetPathForFile(filename); + string? storagePath = beatmapSet?.GetPathForFile(filename); if (storagePath == null) { diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs index fa3e114c55..94c48c300a 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.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. -#nullable disable - using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit.Checks.Components; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs index 96254ba6fd..daa33fb0da 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioQuality.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Rulesets.Edit.Checks.Components; @@ -29,7 +27,7 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - string audioFile = context.Beatmap.Metadata?.AudioFile; + string? audioFile = context.Beatmap.Metadata?.AudioFile; if (string.IsNullOrEmpty(audioFile)) yield break; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs index 96840fd344..067800b409 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.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. -#nullable disable - using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit.Checks.Components; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs index be0c4501e7..23fa28e7bc 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundQuality.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. -#nullable disable - using System.Collections.Generic; using System.IO; using osu.Game.Beatmaps; @@ -35,7 +33,7 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - string backgroundFile = context.Beatmap.Metadata?.BackgroundFile; + string? backgroundFile = context.Beatmap.Metadata?.BackgroundFile; if (backgroundFile == null) yield break; @@ -51,7 +49,7 @@ namespace osu.Game.Rulesets.Edit.Checks else if (texture.Width < low_width || texture.Height < low_height) yield return new IssueTemplateLowResolution(this).Create(texture.Width, texture.Height); - string storagePath = context.Beatmap.BeatmapInfo.BeatmapSet?.GetPathForFile(backgroundFile); + string? storagePath = context.Beatmap.BeatmapInfo.BeatmapSet?.GetPathForFile(backgroundFile); using (Stream stream = context.WorkingBeatmap.GetStream(storagePath)) { diff --git a/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs index 02579b675d..ba5fbcf58d 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckConcurrentObjects.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Rulesets.Edit.Checks.Components; using osu.Game.Rulesets.Objects; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs b/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs index b25abb0cfc..3358e81d5f 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckFewHitsounds.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using osu.Game.Audio; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs index 67d480c28c..6b256d025a 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit.Checks.Components; @@ -35,7 +33,7 @@ namespace osu.Game.Rulesets.Edit.Checks } // If the file is set, also make sure it still exists. - string storagePath = context.Beatmap.BeatmapInfo.BeatmapSet?.GetPathForFile(filename); + string? storagePath = context.Beatmap.BeatmapInfo.BeatmapSet?.GetPathForFile(filename); if (storagePath != null) yield break; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs index 00b1ca9dc9..d755b5bba5 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -59,7 +57,7 @@ namespace osu.Game.Rulesets.Edit.Checks } } - private IEnumerable getVolumeIssues(HitObject hitObject, HitObject sampledHitObject = null) + private IEnumerable getVolumeIssues(HitObject hitObject, HitObject? sampledHitObject = null) { sampledHitObject ??= hitObject; if (!sampledHitObject.Samples.Any()) diff --git a/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs b/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs index 2a222aece0..1c2ea36948 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckTooShortAudioFiles.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. -#nullable disable - using System.Collections.Generic; using System.IO; using System.Linq; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs index a3c52cf547..ded1bb54ca 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckUnsnappedObjects.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. -#nullable disable - using System; using System.Collections.Generic; using osu.Game.Rulesets.Edit.Checks.Components; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs b/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs index 987711188e..75cb08002f 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckZeroByteFiles.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. -#nullable disable - using System.Collections.Generic; using System.IO; using osu.Game.Extensions; diff --git a/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs index 3b30fab934..b9be94736b 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckZeroLengthObjects.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Rulesets.Edit.Checks.Components; using osu.Game.Rulesets.Objects; From 505ec800da7b55876099ceb63548d1428da51c7e Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 30 Oct 2022 16:29:54 +0800 Subject: [PATCH 1949/2686] File name should be nullable. --- osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs | 2 +- osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs | 2 +- osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs index 94c48c300a..e922ddf023 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckAudioPresence.cs @@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Edit.Checks { protected override CheckCategory Category => CheckCategory.Audio; protected override string TypeOfFile => "audio"; - protected override string GetFilename(IBeatmap beatmap) => beatmap.Metadata?.AudioFile; + protected override string? GetFilename(IBeatmap beatmap) => beatmap.Metadata?.AudioFile; } } diff --git a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs index 067800b409..4ca93a9807 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckBackgroundPresence.cs @@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Edit.Checks { protected override CheckCategory Category => CheckCategory.Resources; protected override string TypeOfFile => "background"; - protected override string GetFilename(IBeatmap beatmap) => beatmap.Metadata?.BackgroundFile; + protected override string? GetFilename(IBeatmap beatmap) => beatmap.Metadata?.BackgroundFile; } } diff --git a/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs b/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs index 6b256d025a..9a921ba808 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckFilePresence.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Edit.Checks { protected abstract CheckCategory Category { get; } protected abstract string TypeOfFile { get; } - protected abstract string GetFilename(IBeatmap beatmap); + protected abstract string? GetFilename(IBeatmap beatmap); public CheckMetadata Metadata => new CheckMetadata(Category, $"Missing {TypeOfFile}"); @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Edit.Checks public IEnumerable Run(BeatmapVerifierContext context) { - string filename = GetFilename(context.Beatmap); + string? filename = GetFilename(context.Beatmap); if (string.IsNullOrEmpty(filename)) { From a1a9238bd161d553ece76851b62204c653f3c0d8 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 30 Oct 2022 16:31:07 +0800 Subject: [PATCH 1950/2686] Use empty string instead of null because issue template not accept null. --- osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs b/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs index d755b5bba5..5b59a81f91 100644 --- a/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs +++ b/osu.Game/Rulesets/Edit/Checks/CheckMutedObjects.cs @@ -72,7 +72,7 @@ namespace osu.Game.Rulesets.Edit.Checks if (edgeType == EdgeType.None) yield break; - string postfix = hitObject is IHasDuration ? edgeType.ToString().ToLowerInvariant() : null; + string postfix = hitObject is IHasDuration ? edgeType.ToString().ToLowerInvariant() : string.Empty; if (maxVolume <= muted_threshold) { From 4c9c65856ca117dd34122e4987c3c0570902d077 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 30 Oct 2022 16:51:56 +0800 Subject: [PATCH 1951/2686] Remove the nullable disable annotation in the testing beatmap and mark some of the properties as nullable. This class will be used in some check test cases. --- osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs index 3d7ebad831..7d2aa99dbe 100644 --- a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.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. -#nullable disable - using System.IO; using osu.Framework.Audio; using osu.Framework.Audio.Track; @@ -16,7 +14,7 @@ namespace osu.Game.Tests.Beatmaps public class TestWorkingBeatmap : WorkingBeatmap { private readonly IBeatmap beatmap; - private readonly Storyboard storyboard; + private readonly Storyboard? storyboard; /// /// Create an instance which provides the when requested. @@ -24,7 +22,7 @@ namespace osu.Game.Tests.Beatmaps /// The beatmap. /// An optional storyboard. /// The . - public TestWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null, AudioManager audioManager = null) + public TestWorkingBeatmap(IBeatmap beatmap, Storyboard? storyboard = null, AudioManager? audioManager = null) : base(beatmap.BeatmapInfo, audioManager) { this.beatmap = beatmap; @@ -37,12 +35,12 @@ namespace osu.Game.Tests.Beatmaps protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard(); - protected internal override ISkin GetSkin() => null; + protected internal override ISkin? GetSkin() => null; - public override Stream GetStream(string storagePath) => null; + public override Stream? GetStream(string storagePath) => null; - protected override Texture GetBackground() => null; + protected override Texture? GetBackground() => null; - protected override Track GetBeatmapTrack() => null; + protected override Track? GetBeatmapTrack() => null; } } From 6ce3841686bbbd6d2630e13d37ae1f1419c1e88b Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 30 Oct 2022 16:36:22 +0800 Subject: [PATCH 1952/2686] Remove nullable disable annotation in the test case. --- .../Editing/Checks/CheckAudioInVideoTest.cs | 6 ++---- .../Editing/Checks/CheckAudioQualityTest.cs | 6 ++---- .../Editing/Checks/CheckBackgroundQualityTest.cs | 11 ++++------- .../Editing/Checks/CheckConcurrentObjectsTest.cs | 4 +--- .../Editing/Checks/CheckFewHitsoundsTest.cs | 8 +++----- .../Editing/Checks/CheckFilePresenceTest.cs | 6 ++---- .../Editing/Checks/CheckMutedObjectsTest.cs | 6 ++---- osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs | 2 -- .../Editing/Checks/CheckTooShortAudioFilesTest.cs | 6 ++---- .../Editing/Checks/CheckUnsnappedObjectsTest.cs | 6 ++---- .../Editing/Checks/CheckZeroByteFilesTest.cs | 6 ++---- .../Editing/Checks/CheckZeroLengthObjectsTest.cs | 4 +--- .../Editing/Checks/MockNestableHitObject.cs | 2 -- 13 files changed, 23 insertions(+), 50 deletions(-) diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs index 947e884494..9f253527fc 100644 --- a/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.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. -#nullable disable - using System.IO; using System.Linq; using Moq; @@ -20,8 +18,8 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckAudioInVideoTest { - private CheckAudioInVideo check; - private IBeatmap beatmap; + private CheckAudioInVideo check = null!; + private IBeatmap beatmap = null!; [SetUp] public void Setup() diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs index 50e6087526..3a2cdaf233 100644 --- a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.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. -#nullable disable - using System.Linq; using Moq; using NUnit.Framework; @@ -19,8 +17,8 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckAudioQualityTest { - private CheckAudioQuality check; - private IBeatmap beatmap; + private CheckAudioQuality check = null!; + private IBeatmap beatmap = null!; [SetUp] public void Setup() diff --git a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs index f91e83a556..d0dffb8fad 100644 --- a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs @@ -1,12 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.IO; using System.Linq; -using JetBrains.Annotations; using Moq; using NUnit.Framework; using osu.Framework.Graphics.Rendering.Dummy; @@ -21,8 +18,8 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckBackgroundQualityTest { - private CheckBackgroundQuality check; - private IBeatmap beatmap; + private CheckBackgroundQuality check = null!; + private IBeatmap beatmap = null!; [SetUp] public void Setup() @@ -118,7 +115,7 @@ namespace osu.Game.Tests.Editing.Checks stream.Verify(x => x.Close(), Times.Once()); } - private BeatmapVerifierContext getContext(Texture background, [CanBeNull] Stream stream = null) + private BeatmapVerifierContext getContext(Texture background, Stream? stream = null) { return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, stream).Object); } @@ -128,7 +125,7 @@ namespace osu.Game.Tests.Editing.Checks /// /// The texture of the background. /// The stream representing the background file. - private Mock getMockWorkingBeatmap(Texture background, [CanBeNull] Stream stream = null) + private Mock getMockWorkingBeatmap(Texture background, Stream? stream = null) { stream ??= new MemoryStream(new byte[1024 * 1024]); diff --git a/osu.Game.Tests/Editing/Checks/CheckConcurrentObjectsTest.cs b/osu.Game.Tests/Editing/Checks/CheckConcurrentObjectsTest.cs index 9c1dd2c1e8..b5c6568583 100644 --- a/osu.Game.Tests/Editing/Checks/CheckConcurrentObjectsTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckConcurrentObjectsTest.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using Moq; @@ -21,7 +19,7 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckConcurrentObjectsTest { - private CheckConcurrentObjects check; + private CheckConcurrentObjects check = null!; [SetUp] public void Setup() diff --git a/osu.Game.Tests/Editing/Checks/CheckFewHitsoundsTest.cs b/osu.Game.Tests/Editing/Checks/CheckFewHitsoundsTest.cs index 82bb2e59c9..01781b98ad 100644 --- a/osu.Game.Tests/Editing/Checks/CheckFewHitsoundsTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckFewHitsoundsTest.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -20,10 +18,10 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckFewHitsoundsTest { - private CheckFewHitsounds check; + private CheckFewHitsounds check = null!; - private List notHitsounded; - private List hitsounded; + private List notHitsounded = null!; + private List hitsounded = null!; [SetUp] public void Setup() diff --git a/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs b/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs index 2f18720a5b..89bb2f9396 100644 --- a/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckFilePresenceTest.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. -#nullable disable - using System.Linq; using NUnit.Framework; using osu.Game.Beatmaps; @@ -16,8 +14,8 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckFilePresenceTest { - private CheckBackgroundPresence check; - private IBeatmap beatmap; + private CheckBackgroundPresence check = null!; + private IBeatmap beatmap = null!; [SetUp] public void Setup() diff --git a/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs b/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs index 622386405a..1e1c214c30 100644 --- a/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -21,8 +19,8 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckMutedObjectsTest { - private CheckMutedObjects check; - private ControlPointInfo cpi; + private CheckMutedObjects check = null!; + private ControlPointInfo cpi = null!; private const int volume_regular = 50; private const int volume_low = 15; diff --git a/osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs b/osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs index 405738cd55..9067714ff9 100644 --- a/osu.Game.Tests/Editing/Checks/CheckTestHelpers.cs +++ b/osu.Game.Tests/Editing/Checks/CheckTestHelpers.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. -#nullable disable - using osu.Game.Models; namespace osu.Game.Tests.Editing.Checks diff --git a/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs b/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs index 7d33b92dbe..05856de556 100644 --- a/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.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. -#nullable disable - using System.Diagnostics; using System.IO; using System.Linq; @@ -22,8 +20,8 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckTooShortAudioFilesTest { - private CheckTooShortAudioFiles check; - private IBeatmap beatmap; + private CheckTooShortAudioFiles check = null!; + private IBeatmap beatmap = null!; [SetUp] public void Setup() diff --git a/osu.Game.Tests/Editing/Checks/CheckUnsnappedObjectsTest.cs b/osu.Game.Tests/Editing/Checks/CheckUnsnappedObjectsTest.cs index f647bf8d8e..c9335dcda5 100644 --- a/osu.Game.Tests/Editing/Checks/CheckUnsnappedObjectsTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckUnsnappedObjectsTest.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using Moq; @@ -21,8 +19,8 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckUnsnappedObjectsTest { - private CheckUnsnappedObjects check; - private ControlPointInfo cpi; + private CheckUnsnappedObjects check = null!; + private ControlPointInfo cpi = null!; [SetUp] public void Setup() diff --git a/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs b/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs index 793cc70a3f..5c66e1beaa 100644 --- a/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.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. -#nullable disable - using System.IO; using System.Linq; using Moq; @@ -17,8 +15,8 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckZeroByteFilesTest { - private CheckZeroByteFiles check; - private IBeatmap beatmap; + private CheckZeroByteFiles check = null!; + private IBeatmap beatmap = null!; [SetUp] public void Setup() diff --git a/osu.Game.Tests/Editing/Checks/CheckZeroLengthObjectsTest.cs b/osu.Game.Tests/Editing/Checks/CheckZeroLengthObjectsTest.cs index 1c1965ab56..648f02839f 100644 --- a/osu.Game.Tests/Editing/Checks/CheckZeroLengthObjectsTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckZeroLengthObjectsTest.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using Moq; @@ -21,7 +19,7 @@ namespace osu.Game.Tests.Editing.Checks [TestFixture] public class CheckZeroLengthObjectsTest { - private CheckZeroLengthObjects check; + private CheckZeroLengthObjects check = null!; [SetUp] public void Setup() diff --git a/osu.Game.Tests/Editing/Checks/MockNestableHitObject.cs b/osu.Game.Tests/Editing/Checks/MockNestableHitObject.cs index 6c0306d63d..29938839d3 100644 --- a/osu.Game.Tests/Editing/Checks/MockNestableHitObject.cs +++ b/osu.Game.Tests/Editing/Checks/MockNestableHitObject.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. -#nullable disable - using System.Collections.Generic; using System.Threading; using osu.Game.Rulesets.Objects; From 500bf90a34b1c02fa17255351b0f9582dbf3484e Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 30 Oct 2022 16:58:16 +0800 Subject: [PATCH 1953/2686] Mark as accept the nullable stream. --- osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs | 2 +- osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs | 4 ++-- osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs index 9f253527fc..9774a8ebb6 100644 --- a/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckAudioInVideoTest.cs @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Editing.Checks Assert.That(issues.Single().Template is CheckAudioInVideo.IssueTemplateMissingFile); } - private BeatmapVerifierContext getContext(Stream resourceStream) + private BeatmapVerifierContext getContext(Stream? resourceStream) { var storyboard = new Storyboard(); var layer = storyboard.GetLayer("Video"); diff --git a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs index d0dffb8fad..5d3fd9cd65 100644 --- a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs @@ -115,7 +115,7 @@ namespace osu.Game.Tests.Editing.Checks stream.Verify(x => x.Close(), Times.Once()); } - private BeatmapVerifierContext getContext(Texture background, Stream? stream = null) + private BeatmapVerifierContext getContext(Texture? background, Stream? stream = null) { return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, stream).Object); } @@ -125,7 +125,7 @@ namespace osu.Game.Tests.Editing.Checks /// /// The texture of the background. /// The stream representing the background file. - private Mock getMockWorkingBeatmap(Texture background, Stream? stream = null) + private Mock getMockWorkingBeatmap(Texture? background, Stream? stream = null) { stream ??= new MemoryStream(new byte[1024 * 1024]); diff --git a/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs b/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs index 05856de556..4918369460 100644 --- a/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckTooShortAudioFilesTest.cs @@ -107,7 +107,7 @@ namespace osu.Game.Tests.Editing.Checks } } - private BeatmapVerifierContext getContext(Stream resourceStream) + private BeatmapVerifierContext getContext(Stream? resourceStream) { var mockWorkingBeatmap = new Mock(beatmap, null, null); mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns(resourceStream); From c8c76f23513f91f7d8d2ace60487eca351f77444 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 30 Oct 2022 16:55:53 +0800 Subject: [PATCH 1954/2686] Use AsNonNull() because the type does not accept the null case. --- osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs | 3 ++- osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs | 3 ++- osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs index 3a2cdaf233..8e269cbab2 100644 --- a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs @@ -5,6 +5,7 @@ using System.Linq; using Moq; using NUnit.Framework; using osu.Framework.Audio.Track; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; @@ -41,7 +42,7 @@ namespace osu.Game.Tests.Editing.Checks var mock = new Mock(); mock.SetupGet(w => w.Beatmap).Returns(beatmap); - mock.SetupGet(w => w.Track).Returns((Track)null); + mock.SetupGet(w => w.Track).Returns(default(Track?).AsNonNull()); Assert.That(check.Run(new BeatmapVerifierContext(beatmap, mock.Object)), Is.Empty); } diff --git a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs index 5d3fd9cd65..1aead6d78c 100644 --- a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using Moq; using NUnit.Framework; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Rendering.Dummy; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; @@ -131,7 +132,7 @@ namespace osu.Game.Tests.Editing.Checks var mock = new Mock(); mock.SetupGet(w => w.Beatmap).Returns(beatmap); - mock.SetupGet(w => w.Background).Returns(background); + mock.SetupGet(w => w.Background).Returns(background.AsNonNull()); mock.Setup(w => w.GetStream(It.IsAny())).Returns(stream); return mock; diff --git a/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs b/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs index 5c66e1beaa..7c2b1690af 100644 --- a/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using Moq; using NUnit.Framework; +using osu.Framework.Extensions.ObjectExtensions; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Checks; @@ -72,7 +73,7 @@ namespace osu.Game.Tests.Editing.Checks private BeatmapVerifierContext getContextMissing() { var mockWorkingBeatmap = new Mock(); - mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns((Stream)null); + mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns(default(Stream?).AsNonNull()); return new BeatmapVerifierContext(beatmap, mockWorkingBeatmap.Object); } From a753369d3e3096ef75087abdf34ff965abcb7a59 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sun, 30 Oct 2022 17:21:50 +0800 Subject: [PATCH 1955/2686] Reuse function `TimeAtPosition()` and `PositionAtTime()`. --- .../Screens/Edit/Compose/Components/Timeline/Timeline.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index a73ada76f5..3a93499527 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -250,7 +250,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private void seekTrackToCurrent() { - double target = Current / Content.DrawWidth * editorClock.TrackLength; + double target = TimeAtPosition(Current); editorClock.Seek(Math.Min(editorClock.TrackLength, target)); } @@ -264,7 +264,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline if (handlingDragInput) editorClock.Stop(); - ScrollTo((float)(editorClock.CurrentTime / editorClock.TrackLength) * Content.DrawWidth, false); + float position = PositionAtTime(editorClock.CurrentTime); + ScrollTo(position, false); } protected override bool OnMouseDown(MouseDownEvent e) From f5e11343c28eebb15a0d6d0916b214a0df7dabbb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 Oct 2022 21:24:58 +0900 Subject: [PATCH 1956/2686] Apply nullability to HUD test scene --- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index a984f508ea..325839a6c9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -1,12 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; @@ -26,9 +25,9 @@ namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneHUDOverlay : OsuManualInputManagerTestScene { - private OsuConfigManager localConfig; + private OsuConfigManager localConfig = null!; - private HUDOverlay hudOverlay; + private HUDOverlay hudOverlay = null!; [Cached] private ScoreProcessor scoreProcessor = new ScoreProcessor(new OsuRuleset()); @@ -220,7 +219,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType().Single().ComponentsLoaded); } - private void createNew(Action action = null) + private void createNew(Action? action = null) { AddStep("create overlay", () => { @@ -239,7 +238,9 @@ namespace osu.Game.Tests.Visual.Gameplay protected override void Dispose(bool isDisposing) { - localConfig?.Dispose(); + if (localConfig.IsNotNull()) + localConfig.Dispose(); + base.Dispose(isDisposing); } } From 8399261c77a53ffb66672d61af7de85440a1a344 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 Oct 2022 21:38:31 +0900 Subject: [PATCH 1957/2686] Add failing test showing hold for menu not working when HUD is hidden --- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 325839a6c9..75510fa822 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Timing; using osu.Game.Configuration; +using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; @@ -148,6 +149,41 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent); } + [Test] + public void TestHoldForMenuDoesWorkWhenHidden() + { + bool activated = false; + + HoldForMenuButton getHoldForMenu() => hudOverlay.ChildrenOfType().Single(); + + createNew(); + + AddStep("bind action", () => + { + activated = false; + + var holdForMenu = getHoldForMenu(); + + holdForMenu.Action += () => activated = true; + }); + + AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false); + AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent); + + AddStep("attempt activate", () => + { + InputManager.MoveMouseTo(getHoldForMenu().OfType().Single()); + InputManager.PressButton(MouseButton.Left); + }); + + AddUntilStep("activated", () => activated); + + AddStep("release mouse button", () => + { + InputManager.ReleaseButton(MouseButton.Left); + }); + } + [Test] public void TestInputDoesntWorkWhenHUDHidden() { From 1035b5fb1905b0a07f910f888e8c253582b13e5b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 30 Oct 2022 21:38:45 +0900 Subject: [PATCH 1958/2686] Fix hold to pause button not working when HUD is hidden --- osu.Game/Screens/Play/HUDOverlay.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 7833c2d7fa..2791f5ff8f 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -39,9 +39,16 @@ namespace osu.Game.Screens.Play /// public float BottomScoringElementsHeight { get; private set; } - // HUD uses AlwaysVisible on child components so they can be in an updated state for next display. - // Without blocking input, this would also allow them to be interacted with in such a state. - public override bool PropagatePositionalInputSubTree => ShowHud.Value; + protected override bool ShouldBeConsideredForInput(Drawable child) + { + // HUD uses AlwaysVisible on child components so they can be in an updated state for next display. + // Without blocking input, this would also allow them to be interacted with in such a state. + if (ShowHud.Value) + return base.ShouldBeConsideredForInput(child); + + // hold to quit button should always be interactive. + return child == bottomRightElements; + } public readonly KeyCounterDisplay KeyCounter; public readonly ModDisplay ModDisplay; From 3f17c206d2cea58bbc1f143d74fee22bdddd1f2b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 Oct 2022 12:49:50 +0900 Subject: [PATCH 1959/2686] Update `fastlane` and dependencies --- Gemfile.lock | 66 ++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index cae682ec2b..07ca3542f9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,25 +3,25 @@ GEM specs: CFPropertyList (3.0.5) rexml - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.601.0) - aws-sdk-core (3.131.2) + aws-partitions (1.653.0) + aws-sdk-core (3.166.0) aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.525.0) - aws-sigv4 (~> 1.1) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.5) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.57.0) - aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-kms (1.59.0) + aws-sdk-core (~> 3, >= 3.165.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.114.0) - aws-sdk-core (~> 3, >= 3.127.0) + aws-sdk-s3 (1.117.1) + aws-sdk-core (~> 3, >= 3.165.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.0) + aws-sigv4 (1.5.2) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) @@ -34,10 +34,10 @@ GEM rake (>= 12.0.0, < 14.0.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.6) + dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.92.3) - faraday (1.10.0) + excon (0.93.1) + faraday (1.10.2) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -66,7 +66,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.6) - fastlane (2.206.2) + fastlane (2.210.1) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -110,9 +110,9 @@ GEM souyuz (= 0.11.1) fastlane-plugin-xamarin (0.6.3) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.23.0) - google-apis-core (>= 0.6, < 2.a) - google-apis-core (0.6.0) + google-apis-androidpublisher_v3 (0.29.0) + google-apis-core (>= 0.9.0, < 2.a) + google-apis-core (0.9.1) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -121,27 +121,27 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-iamcredentials_v1 (0.12.0) - google-apis-core (>= 0.6, < 2.a) - google-apis-playcustomapp_v1 (0.9.0) - google-apis-core (>= 0.6, < 2.a) - google-apis-storage_v1 (0.16.0) - google-apis-core (>= 0.6, < 2.a) + google-apis-iamcredentials_v1 (0.15.0) + google-apis-core (>= 0.9.0, < 2.a) + google-apis-playcustomapp_v1 (0.12.0) + google-apis-core (>= 0.9.1, < 2.a) + google-apis-storage_v1 (0.19.0) + google-apis-core (>= 0.9.0, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.2.0) - google-cloud-storage (1.36.2) + google-cloud-errors (1.3.0) + google-cloud-storage (1.43.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.19.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.2.0) + googleauth (1.3.0) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) memoist (~> 0.16) @@ -154,22 +154,22 @@ GEM httpclient (2.8.3) jmespath (1.6.1) json (2.6.2) - jwt (2.4.1) + jwt (2.5.0) memoist (0.16.2) mini_magick (4.11.0) mini_mime (1.1.2) - mini_portile2 (2.7.1) + mini_portile2 (2.8.0) multi_json (1.15.0) multipart-post (2.0.0) nanaimo (0.3.0) naturally (2.2.1) - nokogiri (1.13.1) - mini_portile2 (~> 2.7.0) + nokogiri (1.13.9) + mini_portile2 (~> 2.8.0) racc (~> 1.4) optparse (0.1.1) os (1.1.4) plist (3.6.0) - public_suffix (4.0.7) + public_suffix (5.0.0) racc (1.6.0) rake (13.0.6) representable (3.2.0) From 4213abfc46b499db14dd65dedf514f906f73f5c9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 Oct 2022 12:55:23 +0900 Subject: [PATCH 1960/2686] Adjust testflight cleanup interval to 30 days Been using this for a while but haven't committed it. --- fastlane/Fastfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane/Fastfile b/fastlane/Fastfile index cc5abf5b03..716115e5c6 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -138,10 +138,10 @@ platform :ios do end lane :testflight_prune_dry do - clean_testflight_testers(days_of_inactivity:45, dry_run: true) + clean_testflight_testers(days_of_inactivity:30, dry_run: true) end lane :testflight_prune do - clean_testflight_testers(days_of_inactivity: 45) + clean_testflight_testers(days_of_inactivity: 30) end end From 94dd4045f1ff6d9ac1324720725047df6538a9f7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 Oct 2022 15:42:17 +0900 Subject: [PATCH 1961/2686] Remove borrowed framework code --- osu.Game/Rulesets/Objects/BezierConverter.cs | 81 +------------------- 1 file changed, 1 insertion(+), 80 deletions(-) diff --git a/osu.Game/Rulesets/Objects/BezierConverter.cs b/osu.Game/Rulesets/Objects/BezierConverter.cs index 9220993559..9c3ea5cf6e 100644 --- a/osu.Game/Rulesets/Objects/BezierConverter.cs +++ b/osu.Game/Rulesets/Objects/BezierConverter.cs @@ -39,85 +39,6 @@ namespace osu.Game.Rulesets.Objects new[] { new Vector2d(1, 0), new Vector2d(1, 1.2447058f), new Vector2d(-0.8526471f, 2.118367f), new Vector2d(-2.6211002f, 7.854936e-06f), new Vector2d(-0.8526448f, -2.118357f), new Vector2d(1, -1.2447058f), new Vector2d(1, 0) }) }; - #region CircularArcProperties - - //TODO: Get this from osu!framework instead - public readonly struct CircularArcProperties - { - public readonly bool IsValid; - public readonly double ThetaStart; - public readonly double ThetaRange; - public readonly double Direction; - public readonly float Radius; - public readonly Vector2 Centre; - - public double ThetaEnd => ThetaStart + ThetaRange * Direction; - - public CircularArcProperties(double thetaStart, double thetaRange, double direction, float radius, Vector2 centre) - { - IsValid = true; - ThetaStart = thetaStart; - ThetaRange = thetaRange; - Direction = direction; - Radius = radius; - Centre = centre; - } - } - - /// - /// Computes various properties that can be used to approximate the circular arc. - /// - /// Three distinct points on the arc. - private static CircularArcProperties circularArcProperties(ReadOnlySpan controlPoints) - { - Vector2 a = controlPoints[0]; - Vector2 b = controlPoints[1]; - Vector2 c = controlPoints[2]; - - // If we have a degenerate triangle where a side-length is almost zero, then give up and fallback to a more numerically stable method. - if (Precision.AlmostEquals(0, (b.Y - a.Y) * (c.X - a.X) - (b.X - a.X) * (c.Y - a.Y))) - return default; // Implicitly sets `IsValid` to false - - // See: https://en.wikipedia.org/wiki/Circumscribed_circle#Cartesian_coordinates_2 - float d = 2 * (a.X * (b - c).Y + b.X * (c - a).Y + c.X * (a - b).Y); - float aSq = a.LengthSquared; - float bSq = b.LengthSquared; - float cSq = c.LengthSquared; - - Vector2 centre = new Vector2( - aSq * (b - c).Y + bSq * (c - a).Y + cSq * (a - b).Y, - aSq * (c - b).X + bSq * (a - c).X + cSq * (b - a).X) / d; - - Vector2 dA = a - centre; - Vector2 dC = c - centre; - - float r = dA.Length; - - double thetaStart = Math.Atan2(dA.Y, dA.X); - double thetaEnd = Math.Atan2(dC.Y, dC.X); - - while (thetaEnd < thetaStart) - thetaEnd += 2 * Math.PI; - - double dir = 1; - double thetaRange = thetaEnd - thetaStart; - - // Decide in which direction to draw the circle, depending on which side of - // AC B lies. - Vector2 orthoAtoC = c - a; - orthoAtoC = new Vector2(orthoAtoC.Y, -orthoAtoC.X); - - if (Vector2.Dot(orthoAtoC, b - a) < 0) - { - dir = -dir; - thetaRange = 2 * Math.PI - thetaRange; - } - - return new CircularArcProperties(thetaStart, thetaRange, dir, r, centre); - } - - #endregion - public static IEnumerable ConvertToLegacyBezier(IList controlPoints, Vector2 position) { Vector2[] vertices = new Vector2[controlPoints.Count]; @@ -248,7 +169,7 @@ namespace osu.Game.Rulesets.Objects if (controlPoints.Length != 3) return controlPoints.ToArray(); - var pr = circularArcProperties(controlPoints); + var pr = new CircularArcProperties(controlPoints); if (!pr.IsValid) return controlPoints.ToArray(); From e38ba5e4c620d986dbae99c83137f183efd6cc9f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 31 Oct 2022 15:46:57 +0900 Subject: [PATCH 1962/2686] Apply nullability to new test scene --- .../Gameplay/TestSceneBezierConverter.cs | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs index c915ae0054..701f30bfd4 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -22,8 +20,9 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly SmoothPath controlPointDrawablePath; private readonly SmoothPath convertedDrawablePath; private readonly SmoothPath convertedControlPointDrawablePath; - private SliderPath path; - private SliderPath convertedPath; + + private SliderPath path = null!; + private SliderPath convertedPath = null!; public TestSceneBezierConverter() { @@ -58,16 +57,20 @@ namespace osu.Game.Tests.Visual.Gameplay Position = new Vector2(100, 300) } }; + + resetPath(); } [SetUp] - public void Setup() => Schedule(() => + public void Setup() => Schedule(resetPath); + + private void resetPath() { path = new SliderPath(); convertedPath = new SliderPath(); path.Version.ValueChanged += getConvertedControlPoints; - }); + } private void getConvertedControlPoints(ValueChangedEvent obj) { @@ -79,26 +82,30 @@ namespace osu.Game.Tests.Visual.Gameplay { base.Update(); - if (path != null) - { - List vertices = new List(); - path.GetPathToProgress(vertices, 0, 1); + List vertices = new List(); - drawablePath.Vertices = vertices; - controlPointDrawablePath.Vertices = path.ControlPoints.Select(o => o.Position).ToList(); - if (controlPointDrawablePath.Vertices.Count > 0) - controlPointDrawablePath.Position = drawablePath.PositionInBoundingBox(drawablePath.Vertices[0]) - controlPointDrawablePath.PositionInBoundingBox(controlPointDrawablePath.Vertices[0]); + path.GetPathToProgress(vertices, 0, 1); + + drawablePath.Vertices = vertices; + controlPointDrawablePath.Vertices = path.ControlPoints.Select(o => o.Position).ToList(); + + if (controlPointDrawablePath.Vertices.Count > 0) + { + controlPointDrawablePath.Position = + drawablePath.PositionInBoundingBox(drawablePath.Vertices[0]) - controlPointDrawablePath.PositionInBoundingBox(controlPointDrawablePath.Vertices[0]); } - if (convertedPath != null) - { - List vertices = new List(); - convertedPath.GetPathToProgress(vertices, 0, 1); + vertices.Clear(); - convertedDrawablePath.Vertices = vertices; - convertedControlPointDrawablePath.Vertices = convertedPath.ControlPoints.Select(o => o.Position).ToList(); - if (convertedControlPointDrawablePath.Vertices.Count > 0) - convertedControlPointDrawablePath.Position = convertedDrawablePath.PositionInBoundingBox(convertedDrawablePath.Vertices[0]) - convertedControlPointDrawablePath.PositionInBoundingBox(convertedControlPointDrawablePath.Vertices[0]); + convertedPath.GetPathToProgress(vertices, 0, 1); + + convertedDrawablePath.Vertices = vertices; + convertedControlPointDrawablePath.Vertices = convertedPath.ControlPoints.Select(o => o.Position).ToList(); + + if (convertedControlPointDrawablePath.Vertices.Count > 0) + { + convertedControlPointDrawablePath.Position = convertedDrawablePath.PositionInBoundingBox(convertedDrawablePath.Vertices[0]) + - convertedControlPointDrawablePath.PositionInBoundingBox(convertedControlPointDrawablePath.Vertices[0]); } } From 414e21c65758beaf70beb0a75aec0edfb2f49407 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 31 Oct 2022 11:39:14 +0100 Subject: [PATCH 1963/2686] Added xmldoc to public methods --- osu.Game/Rulesets/Objects/BezierConverter.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Rulesets/Objects/BezierConverter.cs b/osu.Game/Rulesets/Objects/BezierConverter.cs index 9c3ea5cf6e..1ea79f8fd4 100644 --- a/osu.Game/Rulesets/Objects/BezierConverter.cs +++ b/osu.Game/Rulesets/Objects/BezierConverter.cs @@ -40,6 +40,12 @@ namespace osu.Game.Rulesets.Objects }; public static IEnumerable ConvertToLegacyBezier(IList controlPoints, Vector2 position) + /// + /// Converts a slider path to bezier control point positions compatible with the legacy osu! client. + /// + /// The control points of the path. + /// The offset for the whole path. + /// The list of legacy bezier control point positions. { Vector2[] vertices = new Vector2[controlPoints.Count]; for (int i = 0; i < controlPoints.Count; i++) @@ -90,6 +96,11 @@ namespace osu.Game.Rulesets.Objects return result; } + /// + /// Converts a path of control points to an identical path using only Bezier type control points. + /// + /// The control points of the path. + /// The list of bezier control points. public static List ConvertToModernBezier(IList controlPoints) { Vector2[] vertices = new Vector2[controlPoints.Count]; From 04613038954cf4a977f4e7d91b7e0f3fad2edbce Mon Sep 17 00:00:00 2001 From: OliBomby Date: Mon, 31 Oct 2022 11:39:41 +0100 Subject: [PATCH 1964/2686] Change return type to List --- osu.Game/Rulesets/Objects/BezierConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/BezierConverter.cs b/osu.Game/Rulesets/Objects/BezierConverter.cs index 1ea79f8fd4..ebee36a7db 100644 --- a/osu.Game/Rulesets/Objects/BezierConverter.cs +++ b/osu.Game/Rulesets/Objects/BezierConverter.cs @@ -39,13 +39,13 @@ namespace osu.Game.Rulesets.Objects new[] { new Vector2d(1, 0), new Vector2d(1, 1.2447058f), new Vector2d(-0.8526471f, 2.118367f), new Vector2d(-2.6211002f, 7.854936e-06f), new Vector2d(-0.8526448f, -2.118357f), new Vector2d(1, -1.2447058f), new Vector2d(1, 0) }) }; - public static IEnumerable ConvertToLegacyBezier(IList controlPoints, Vector2 position) /// /// Converts a slider path to bezier control point positions compatible with the legacy osu! client. /// /// The control points of the path. /// The offset for the whole path. /// The list of legacy bezier control point positions. + public static List ConvertToLegacyBezier(IList controlPoints, Vector2 position) { Vector2[] vertices = new Vector2[controlPoints.Count]; for (int i = 0; i < controlPoints.Count; i++) From 706adfb28c290eda95bda8e982e062ad79760c18 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 13:57:34 +0900 Subject: [PATCH 1965/2686] Improve messaging when ruleset load fails --- osu.Game/Rulesets/RulesetStore.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index fdbcd0ed1e..e2b8cd2c4e 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -158,7 +158,7 @@ namespace osu.Game.Rulesets } catch (Exception e) { - LogFailedLoad(assembly.FullName, e); + LogFailedLoad(assembly.GetName().Name.Split('.').Last(), e); } } @@ -168,14 +168,14 @@ namespace osu.Game.Rulesets GC.SuppressFinalize(this); } - protected virtual void Dispose(bool disposing) + protected void Dispose(bool disposing) { AppDomain.CurrentDomain.AssemblyResolve -= resolveRulesetDependencyAssembly; } protected void LogFailedLoad(string name, Exception exception) { - Logger.Log($"Could not load ruleset {name}. Please check for an update from the developer.", level: LogLevel.Error); + Logger.Log($"Could not load ruleset \"{name}\". Please check for an update from the developer.", level: LogLevel.Error); Logger.Log($"Ruleset load failed: {exception}"); } From 2a88409dfe65fd5e48c52bbfdb0397e8d8b4f575 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 15:00:23 +0900 Subject: [PATCH 1966/2686] Fix time snap of sliders not matching when SV is not 1.0x This regressed with https://github.com/ppy/osu/pull/20850 because the function was used in other places which expect it to factor slider velocity into the equation. Rather than reverting, I've added a new argument, as based on the method naming alone it was hard to discern whether SV should actually be considered. The reason for the change in #20850 was to avoid the SV coming in from a reference object which may not have a correct SV in the first place. In such cases, passing `false` to the function will give the expected behaviour. --- osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs | 2 +- osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs | 6 +++--- osu.Game/Rulesets/Edit/IDistanceSnapProvider.cs | 3 ++- .../Screens/Edit/Compose/Components/DistanceSnapGrid.cs | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs b/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs index 53b6db2277..01a49c7dea 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs @@ -193,7 +193,7 @@ namespace osu.Game.Tests.Visual.Editing IBindable IDistanceSnapProvider.DistanceSpacingMultiplier => DistanceSpacingMultiplier; - public float GetBeatSnapDistanceAt(HitObject referenceObject) => beat_snap_distance; + public float GetBeatSnapDistanceAt(HitObject referenceObject, bool useReferenceSliderVelocity = true) => beat_snap_distance; public float DurationToDistance(HitObject referenceObject, double duration) => (float)duration; diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index ca7ca79813..840ed7682a 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -259,9 +259,9 @@ namespace osu.Game.Rulesets.Edit return true; } - public virtual float GetBeatSnapDistanceAt(HitObject referenceObject) + public virtual float GetBeatSnapDistanceAt(HitObject referenceObject, bool useReferenceSliderVelocity = true) { - return (float)(100 * EditorBeatmap.Difficulty.SliderMultiplier * 1 / BeatSnapProvider.BeatDivisor); + return (float)(100 * (useReferenceSliderVelocity ? referenceObject.DifficultyControlPoint.SliderVelocity : 1) * EditorBeatmap.Difficulty.SliderMultiplier * 1 / BeatSnapProvider.BeatDivisor); } public virtual float DurationToDistance(HitObject referenceObject, double duration) @@ -273,7 +273,7 @@ namespace osu.Game.Rulesets.Edit public virtual double DistanceToDuration(HitObject referenceObject, float distance) { double beatLength = BeatSnapProvider.GetBeatLengthAtTime(referenceObject.StartTime); - return distance / GetBeatSnapDistanceAt(referenceObject) * beatLength; + return distance / GetBeatSnapDistanceAt(referenceObject) * beatLength * referenceObject.DifficultyControlPoint.SliderVelocity; } public virtual double FindSnappedDuration(HitObject referenceObject, float distance) diff --git a/osu.Game/Rulesets/Edit/IDistanceSnapProvider.cs b/osu.Game/Rulesets/Edit/IDistanceSnapProvider.cs index 5ad1cc78ff..6fbd994e23 100644 --- a/osu.Game/Rulesets/Edit/IDistanceSnapProvider.cs +++ b/osu.Game/Rulesets/Edit/IDistanceSnapProvider.cs @@ -27,8 +27,9 @@ namespace osu.Game.Rulesets.Edit /// Retrieves the distance between two points within a timing point that are one beat length apart. /// /// An object to be used as a reference point for this operation. + /// Whether the 's slider velocity should be factored into the returned distance. /// The distance between two points residing in the timing point that are one beat length apart. - float GetBeatSnapDistanceAt(HitObject referenceObject); + float GetBeatSnapDistanceAt(HitObject referenceObject, bool useReferenceSliderVelocity = true); /// /// Converts a duration to a distance without applying any snapping. diff --git a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs index 69c7fc2775..c179e7f0c2 100644 --- a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs @@ -97,7 +97,7 @@ namespace osu.Game.Screens.Edit.Compose.Components private void updateSpacing() { float distanceSpacingMultiplier = (float)DistanceSpacingMultiplier.Value; - float beatSnapDistance = SnapProvider.GetBeatSnapDistanceAt(ReferenceObject); + float beatSnapDistance = SnapProvider.GetBeatSnapDistanceAt(ReferenceObject, false); DistanceBetweenTicks = beatSnapDistance * distanceSpacingMultiplier; From e8b791429569d3f9513265ae7ae4f23c2754aba7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 15:13:05 +0900 Subject: [PATCH 1967/2686] Add test coverage of new parameter --- ...tSceneHitObjectComposerDistanceSnapping.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs index a98f931e7a..6fb21e38b0 100644 --- a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs +++ b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Editing { AddStep($"set slider multiplier = {multiplier}", () => composer.EditorBeatmap.Difficulty.SliderMultiplier = multiplier); - assertSnapDistance(100 * multiplier); + assertSnapDistance(100 * multiplier, null, true); } [TestCase(1)] @@ -79,7 +79,20 @@ namespace osu.Game.Tests.Editing { SliderVelocity = multiplier } - }); + }, false); + } + + [TestCase(1)] + [TestCase(2)] + public void TestSpeedMultiplierDoesChangeDistanceSnap(float multiplier) + { + assertSnapDistance(100 * multiplier, new HitObject + { + DifficultyControlPoint = new DifficultyControlPoint + { + SliderVelocity = multiplier + } + }, true); } [TestCase(1)] @@ -88,7 +101,7 @@ namespace osu.Game.Tests.Editing { AddStep($"set divisor = {divisor}", () => BeatDivisor.Value = divisor); - assertSnapDistance(100f / divisor); + assertSnapDistance(100f / divisor, null, true); } [Test] @@ -197,8 +210,8 @@ namespace osu.Game.Tests.Editing assertSnappedDistance(400, 400); } - private void assertSnapDistance(float expectedDistance, HitObject? hitObject = null) - => AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(hitObject ?? new HitObject()), () => Is.EqualTo(expectedDistance)); + private void assertSnapDistance(float expectedDistance, HitObject? refereneObject, bool includeSliderVelocity) + => AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(refereneObject ?? new HitObject(), includeSliderVelocity), () => Is.EqualTo(expectedDistance)); private void assertDurationToDistance(double duration, float expectedDistance) => AddAssert($"duration = {duration} -> distance = {expectedDistance}", () => composer.DurationToDistance(new HitObject(), duration) == expectedDistance); From d807d9d82299c85e13405472394061668e1f1698 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 15:21:17 +0900 Subject: [PATCH 1968/2686] Add failing test covering snap calculations with SV applied --- ...tSceneHitObjectComposerDistanceSnapping.cs | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs index 6fb21e38b0..f759ed5dcf 100644 --- a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs +++ b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs @@ -7,6 +7,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; @@ -104,6 +105,28 @@ namespace osu.Game.Tests.Editing assertSnapDistance(100f / divisor, null, true); } + /// + /// The basic distance-duration functions should always include slider velocity of the reference object. + /// + [Test] + public void TestConversionsWithSliderVelocity() + { + const float base_distance = 100; + const float slider_velocity = 1.2f; + + var referenceObject = new HitObject + { + DifficultyControlPoint = new DifficultyControlPoint + { + SliderVelocity = slider_velocity + } + }; + + assertSnapDistance(base_distance * slider_velocity, referenceObject, true); + assertSnappedDistance(base_distance * slider_velocity + 10, base_distance * slider_velocity, referenceObject); + assertSnappedDuration(base_distance * slider_velocity + 10, 1000, referenceObject); + } + [Test] public void TestConvertDurationToDistance() { @@ -210,20 +233,20 @@ namespace osu.Game.Tests.Editing assertSnappedDistance(400, 400); } - private void assertSnapDistance(float expectedDistance, HitObject? refereneObject, bool includeSliderVelocity) - => AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(refereneObject ?? new HitObject(), includeSliderVelocity), () => Is.EqualTo(expectedDistance)); + private void assertSnapDistance(float expectedDistance, HitObject? referenceObject, bool includeSliderVelocity) + => AddAssert($"distance is {expectedDistance}", () => composer.GetBeatSnapDistanceAt(referenceObject ?? new HitObject(), includeSliderVelocity), () => Is.EqualTo(expectedDistance).Within(Precision.FLOAT_EPSILON)); - private void assertDurationToDistance(double duration, float expectedDistance) - => AddAssert($"duration = {duration} -> distance = {expectedDistance}", () => composer.DurationToDistance(new HitObject(), duration) == expectedDistance); + private void assertDurationToDistance(double duration, float expectedDistance, HitObject? referenceObject = null) + => AddAssert($"duration = {duration} -> distance = {expectedDistance}", () => composer.DurationToDistance(referenceObject ?? new HitObject(), duration), () => Is.EqualTo(expectedDistance).Within(Precision.FLOAT_EPSILON)); - private void assertDistanceToDuration(float distance, double expectedDuration) - => AddAssert($"distance = {distance} -> duration = {expectedDuration}", () => composer.DistanceToDuration(new HitObject(), distance) == expectedDuration); + private void assertDistanceToDuration(float distance, double expectedDuration, HitObject? referenceObject = null) + => AddAssert($"distance = {distance} -> duration = {expectedDuration}", () => composer.DistanceToDuration(referenceObject ?? new HitObject(), distance), () => Is.EqualTo(expectedDuration).Within(Precision.FLOAT_EPSILON)); - private void assertSnappedDuration(float distance, double expectedDuration) - => AddAssert($"distance = {distance} -> duration = {expectedDuration} (snapped)", () => composer.FindSnappedDuration(new HitObject(), distance) == expectedDuration); + private void assertSnappedDuration(float distance, double expectedDuration, HitObject? referenceObject = null) + => AddAssert($"distance = {distance} -> duration = {expectedDuration} (snapped)", () => composer.FindSnappedDuration(referenceObject ?? new HitObject(), distance), () => Is.EqualTo(expectedDuration).Within(Precision.FLOAT_EPSILON)); - private void assertSnappedDistance(float distance, float expectedDistance) - => AddAssert($"distance = {distance} -> distance = {expectedDistance} (snapped)", () => composer.FindSnappedDistance(new HitObject(), distance) == expectedDistance); + private void assertSnappedDistance(float distance, float expectedDistance, HitObject? referenceObject = null) + => AddAssert($"distance = {distance} -> distance = {expectedDistance} (snapped)", () => composer.FindSnappedDistance(referenceObject ?? new HitObject(), distance), () => Is.EqualTo(expectedDistance).Within(Precision.FLOAT_EPSILON)); private class TestHitObjectComposer : OsuHitObjectComposer { From 8280605e92f6ab0d8220531a22b50895bf52ef27 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 16:31:09 +0900 Subject: [PATCH 1969/2686] Fix notch toggle not applying correctly after restart --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 2ac2edd3fc..4f8098136f 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -313,7 +313,7 @@ namespace osu.Game Beatmap.BindValueChanged(beatmapChanged, true); applySafeAreaConsiderations = LocalConfig.GetBindable(OsuSetting.SafeAreaConsiderations); - applySafeAreaConsiderations.BindValueChanged(apply => SafeAreaContainer.SafeAreaOverrideEdges = apply.NewValue ? SafeAreaOverrideEdges : Edges.All); + applySafeAreaConsiderations.BindValueChanged(apply => SafeAreaContainer.SafeAreaOverrideEdges = apply.NewValue ? SafeAreaOverrideEdges : Edges.All, true); } private ExternalLinkOpener externalLinkOpener; From d15585153daf759289013bce8f06e32ada67a501 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 17:07:58 +0900 Subject: [PATCH 1970/2686] Fix breadcrumb display in directory selector overlapping new "show hidden" button Closes #21034. --- .../UserInterfaceV2/OsuDirectorySelectorBreadcrumbDisplay.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorBreadcrumbDisplay.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorBreadcrumbDisplay.cs index 0833c7eb8b..08a569269e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorBreadcrumbDisplay.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorBreadcrumbDisplay.cs @@ -25,10 +25,9 @@ namespace osu.Game.Graphics.UserInterfaceV2 protected override DirectorySelectorDirectory CreateDirectoryItem(DirectoryInfo directory, string displayName = null) => new OsuBreadcrumbDisplayDirectory(directory, displayName); - [BackgroundDependencyLoader] - private void load() + public OsuDirectorySelectorBreadcrumbDisplay() { - Height = 50; + Padding = new MarginPadding(15); } private class OsuBreadcrumbDisplayComputer : OsuBreadcrumbDisplayDirectory From 29bc653d24caaf65038ee39c75b7dab1bfc5307b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 17:14:30 +0900 Subject: [PATCH 1971/2686] Remove incorrect double multiplication and add missing test coverage --- .../Editing/TestSceneHitObjectComposerDistanceSnapping.cs | 3 +++ osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs index f759ed5dcf..495a221159 100644 --- a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs +++ b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs @@ -125,6 +125,9 @@ namespace osu.Game.Tests.Editing assertSnapDistance(base_distance * slider_velocity, referenceObject, true); assertSnappedDistance(base_distance * slider_velocity + 10, base_distance * slider_velocity, referenceObject); assertSnappedDuration(base_distance * slider_velocity + 10, 1000, referenceObject); + + assertDistanceToDuration(base_distance * slider_velocity, 1000, referenceObject); + assertDurationToDistance(1000, base_distance * slider_velocity, referenceObject); } [Test] diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index 840ed7682a..b0a2694a0a 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -273,7 +273,7 @@ namespace osu.Game.Rulesets.Edit public virtual double DistanceToDuration(HitObject referenceObject, float distance) { double beatLength = BeatSnapProvider.GetBeatLengthAtTime(referenceObject.StartTime); - return distance / GetBeatSnapDistanceAt(referenceObject) * beatLength * referenceObject.DifficultyControlPoint.SliderVelocity; + return distance / GetBeatSnapDistanceAt(referenceObject) * beatLength; } public virtual double FindSnappedDuration(HitObject referenceObject, float distance) From 978d15955c911bf4eeef844a3eefabb71a6cb974 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 17:37:32 +0900 Subject: [PATCH 1972/2686] Fix control points not being cloned when running beatmap conversion Closes #20994. I haven't considered how this affects performance of difficulty calculation or otherwise. Seems like a sane initial fix which we can iterate on going forward. I've tested using the scenario in the linked issue. I'm not going to add test coverage because [BeatmapConversionTest](https://github.com/ppy/osu/blob/master/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs) should correctly cover this scenario once we are serialising control points as well. --- osu.Game/Beatmaps/BeatmapConverter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/BeatmapConverter.cs b/osu.Game/Beatmaps/BeatmapConverter.cs index 4419791e43..c7c244bf0e 100644 --- a/osu.Game/Beatmaps/BeatmapConverter.cs +++ b/osu.Game/Beatmaps/BeatmapConverter.cs @@ -47,6 +47,7 @@ namespace osu.Game.Beatmaps // Shallow clone isn't enough to ensure we don't mutate beatmap info unexpectedly. // Can potentially be removed after `Beatmap.Difficulty` doesn't save back to `Beatmap.BeatmapInfo`. original.BeatmapInfo = original.BeatmapInfo.Clone(); + original.ControlPointInfo = original.ControlPointInfo.DeepClone(); return ConvertBeatmap(original, cancellationToken); } From 37407293aa516363a2f4290311db371bebdbd96f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 1 Nov 2022 17:57:20 +0900 Subject: [PATCH 1973/2686] Adjust target and hold off mod multipliers --- osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs index ca9bc89473..2b0098744f 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModHoldOff.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Mods public override string Acronym => "HO"; - public override double ScoreMultiplier => 1; + public override double ScoreMultiplier => 0.9; public override LocalisableString Description => @"Replaces all hold notes with normal notes."; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs index 406968ba08..dc64918e03 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Conversion; public override IconUsage? Icon => OsuIcon.ModTarget; public override LocalisableString Description => @"Practice keeping up with the beat of the song."; - public override double ScoreMultiplier => 1; + public override double ScoreMultiplier => 0.1; public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { From c179f0bb521bdc6c757a39fe8cff8955b5d09864 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 18:31:30 +0900 Subject: [PATCH 1974/2686] Fix argon hit circle outer gradient getting smaller each state application --- osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 36dc8c801d..4b4860e789 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -171,7 +171,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon // This is to give it a bomb-like effect, with the border "triggering" its animation when getting close. using (BeginDelayedSequence(flash_in_duration / 12)) { - outerGradient.ResizeTo(outerGradient.Size * shrink_size, resize_duration, Easing.OutElasticHalf); + outerGradient.ResizeTo(OUTER_GRADIENT_SIZE * shrink_size, resize_duration, Easing.OutElasticHalf); outerGradient .FadeColour(Color4.White, 80) .Then() From ff60eebe216618e9f2e7ac1ca4fd114f0632c847 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 19:12:59 +0900 Subject: [PATCH 1975/2686] Fix large transform retention when adjusting accent colour of hitobject during pause --- .../Skinning/Argon/ArgonMainCirclePiece.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 36dc8c801d..7269c7b151 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -121,12 +121,16 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon innerGradient.Colour = ColourInfo.GradientVertical(colour.NewValue.Darken(0.5f), colour.NewValue.Darken(0.6f)); flash.Colour = colour.NewValue; - updateStateTransforms(drawableObject, drawableObject.State.Value); + // Accent colour may be changed many times during a paused gameplay state. + // Schedule the change to avoid transforms piling up. + Scheduler.AddOnce(updateStateTransforms); }, true); drawableObject.ApplyCustomUpdateState += updateStateTransforms; } + private void updateStateTransforms() => updateStateTransforms(drawableObject, drawableObject.State.Value); + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) From f014acfc8d54c453a50b0f9b22862f6c29204761 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 19:34:53 +0900 Subject: [PATCH 1976/2686] Fix `DrawableHitObject.AccentColour` not being updated if object entry is not attached --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index d624164013..e5150576f2 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -266,6 +266,10 @@ namespace osu.Game.Rulesets.Objects.Drawables updateState(ArmedState.Miss, true); else updateState(ArmedState.Idle, true); + + // Combo colour may have been applied via a bindable flow while no object entry was attached. + // Update here to ensure we're in a good state. + UpdateComboColour(); } } From cd8dc9b17bbfb43e30a28ce4e765885380b494b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 19:47:20 +0900 Subject: [PATCH 1977/2686] Rename "Target" to "Target Practice" --- osu.Game.Rulesets.Osu.Tests/OsuLegacyModConversionTest.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs | 2 +- .../Mods/{OsuModTarget.cs => OsuModTargetPractice.cs} | 7 +++---- osu.Game.Rulesets.Osu/OsuRuleset.cs | 6 +++--- 7 files changed, 11 insertions(+), 12 deletions(-) rename osu.Game.Rulesets.Osu/Mods/{OsuModTarget.cs => OsuModTargetPractice.cs} (98%) diff --git a/osu.Game.Rulesets.Osu.Tests/OsuLegacyModConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuLegacyModConversionTest.cs index 01d83b55e6..b4727b3c02 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuLegacyModConversionTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuLegacyModConversionTest.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Tests new object[] { LegacyMods.Autoplay, new[] { typeof(OsuModAutoplay) } }, new object[] { LegacyMods.SpunOut, new[] { typeof(OsuModSpunOut) } }, new object[] { LegacyMods.Autopilot, new[] { typeof(OsuModAutopilot) } }, - new object[] { LegacyMods.Target, new[] { typeof(OsuModTarget) } }, + new object[] { LegacyMods.Target, new[] { typeof(OsuModTargetPractice) } }, new object[] { LegacyMods.HardRock | LegacyMods.DoubleTime, new[] { typeof(OsuModHardRock), typeof(OsuModDoubleTime) } } }; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 618fcfe05d..1621bb50b1 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods { public override LocalisableString Description => "It never gets boring!"; - public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTarget)).ToArray(); + public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModTargetPractice)).ToArray(); [SettingSource("Angle sharpness", "How sharp angles should be", SettingControlType = typeof(SettingsSlider))] public BindableFloat AngleSharpness { get; } = new BindableFloat(7) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs index 9708800daa..f691731afe 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.Automation; public override LocalisableString Description => @"Spinners will be automatically completed."; public override double ScoreMultiplier => 0.9; - public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot), typeof(OsuModTarget) }; + public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot), typeof(OsuModTargetPractice) }; public void ApplyToDrawableHitObject(DrawableHitObject hitObject) { diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index 67b19124e1..af37f1e2e5 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override ModType Type => ModType.DifficultyIncrease; public override LocalisableString Description => @"Once you start a slider, follow precisely or get a miss."; public override double ScoreMultiplier => 1.0; - public override Type[] IncompatibleMods => new[] { typeof(ModClassic), typeof(OsuModTarget) }; + public override Type[] IncompatibleMods => new[] { typeof(ModClassic), typeof(OsuModTargetPractice) }; public void ApplyToDrawableHitObject(DrawableHitObject drawable) { diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs index 429fe30fc5..b4edb1581e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModSuddenDeath.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot), - typeof(OsuModTarget), + typeof(OsuModTargetPractice), }).ToArray(); } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs similarity index 98% rename from osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs rename to osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs index dc64918e03..55c20eebe9 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs @@ -32,11 +32,10 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModTarget : ModWithVisibilityAdjustment, IApplicableToDrawableRuleset, - IApplicableToHealthProcessor, IApplicableToDifficulty, IApplicableFailOverride, - IHasSeed, IHidesApproachCircles + public class OsuModTargetPractice : ModWithVisibilityAdjustment, IApplicableToDrawableRuleset, + IApplicableToHealthProcessor, IApplicableToDifficulty, IApplicableFailOverride, IHasSeed, IHidesApproachCircles { - public override string Name => "Target"; + public override string Name => "Target Practice"; public override string Acronym => "TP"; public override ModType Type => ModType.Conversion; public override IconUsage? Icon => OsuIcon.ModTarget; diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 69df12ff6d..79a566e33c 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -109,7 +109,7 @@ namespace osu.Game.Rulesets.Osu yield return new OsuModSpunOut(); if (mods.HasFlagFast(LegacyMods.Target)) - yield return new OsuModTarget(); + yield return new OsuModTargetPractice(); if (mods.HasFlagFast(LegacyMods.TouchDevice)) yield return new OsuModTouchDevice(); @@ -131,7 +131,7 @@ namespace osu.Game.Rulesets.Osu value |= LegacyMods.SpunOut; break; - case OsuModTarget: + case OsuModTargetPractice: value |= LegacyMods.Target; break; @@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Osu case ModType.Conversion: return new Mod[] { - new OsuModTarget(), + new OsuModTargetPractice(), new OsuModDifficultyAdjust(), new OsuModClassic(), new OsuModRandom(), From 5b25ef5f2fcc7d4c1db03cd529733fb8375237c4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 1 Nov 2022 21:34:34 +0900 Subject: [PATCH 1978/2686] Construct notifications client via IAPIProvider --- osu.Game.Tests/Chat/TestSceneChannelManager.cs | 3 +-- osu.Game.Tests/Visual/Online/TestSceneChatLink.cs | 3 +-- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 3 +-- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 3 +-- .../Visual/Online/TestSceneStandAloneChatDisplay.cs | 3 +-- osu.Game/Online/API/APIAccess.cs | 5 +++++ osu.Game/Online/API/DummyAPIAccess.cs | 4 ++++ osu.Game/Online/API/IAPIProvider.cs | 6 ++++++ osu.Game/OsuGame.cs | 3 +-- 9 files changed, 21 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index 84609a2733..86be638781 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -13,7 +13,6 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -using osu.Game.Online.Notifications.Polling; using osu.Game.Tests.Visual; namespace osu.Game.Tests.Chat @@ -152,7 +151,7 @@ namespace osu.Game.Tests.Chat public ChannelManagerContainer(IAPIProvider apiProvider) { - InternalChild = ChannelManager = new ChannelManager(apiProvider, new PollingNotificationsClientConnector(apiProvider)); + InternalChild = ChannelManager = new ChannelManager(apiProvider, apiProvider.GetNotificationsConnector()); } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs index 63526d4278..5c46cd96be 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -using osu.Game.Online.Notifications.Polling; using osu.Game.Overlays.Chat; using osuTK.Graphics; @@ -42,7 +41,7 @@ namespace osu.Game.Tests.Visual.Online { linkColour = colours.Blue; - var chatManager = new ChannelManager(API, new PollingNotificationsClientConnector(API)); + var chatManager = new ChannelManager(API, API.GetNotificationsConnector()); BindableList availableChannels = (BindableList)chatManager.AvailableChannels; availableChannels.Add(new Channel { Name = "#english" }); availableChannels.Add(new Channel { Name = "#japanese" }); diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index dee258f747..6b2124f1f8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -24,7 +24,6 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -using osu.Game.Online.Notifications.Polling; using osu.Game.Overlays; using osu.Game.Overlays.Chat; using osu.Game.Overlays.Chat.Listing; @@ -60,7 +59,7 @@ namespace osu.Game.Tests.Visual.Online RelativeSizeAxes = Axes.Both, CachedDependencies = new (Type, object)[] { - (typeof(ChannelManager), channelManager = new ChannelManager(API, new PollingNotificationsClientConnector(API))), + (typeof(ChannelManager), channelManager = new ChannelManager(API, API.GetNotificationsConnector())), }, Children = new Drawable[] { diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 6d83fb3123..cb93812bc2 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -16,7 +16,6 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -using osu.Game.Online.Notifications.Polling; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; using osuTK.Input; @@ -251,7 +250,7 @@ namespace osu.Game.Tests.Visual.Online public TestContainer(IAPIProvider api, Channel[] channels) { this.channels = channels; - ChannelManager = new ChannelManager(api, new PollingNotificationsClientConnector(api)); + ChannelManager = new ChannelManager(api, api.GetNotificationsConnector()); } [BackgroundDependencyLoader] diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index f1daa05e08..07196cc92a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -15,7 +15,6 @@ using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; -using osu.Game.Online.Notifications.Polling; using osu.Game.Overlays.Chat; using osuTK.Input; @@ -59,7 +58,7 @@ namespace osu.Game.Tests.Visual.Online { var api = parent.Get(); - Add(channelManager = new ChannelManager(api, new PollingNotificationsClientConnector(api))); + Add(channelManager = new ChannelManager(api, api.GetNotificationsConnector())); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index a0c8e0d555..8ac2e2d453 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -20,6 +20,8 @@ using osu.Framework.Logging; using osu.Game.Configuration; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Notifications; +using osu.Game.Online.Notifications.WebSocket; using osu.Game.Users; namespace osu.Game.Online.API @@ -299,6 +301,9 @@ namespace osu.Game.Online.API public IHubClientConnector GetHubConnector(string clientName, string endpoint, bool preferMessagePack) => new HubClientConnector(clientName, endpoint, this, versionHash, preferMessagePack); + public NotificationsClientConnector GetNotificationsConnector() => + new WebSocketNotificationsClientConnector(this); + public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password) { Debug.Assert(State.Value == APIState.Offline); diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 7dc34d1293..865e1e0a70 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -9,6 +9,8 @@ using System.Threading.Tasks; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Notifications; +using osu.Game.Online.Notifications.Polling; using osu.Game.Users; namespace osu.Game.Online.API @@ -115,6 +117,8 @@ namespace osu.Game.Online.API public IHubClientConnector GetHubConnector(string clientName, string endpoint, bool preferMessagePack) => null; + public NotificationsClientConnector GetNotificationsConnector() => new PollingNotificationsClientConnector(this); + public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password) { Thread.Sleep(200); diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index a90b11e354..6054effaa1 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -5,6 +5,7 @@ using System; using System.Threading.Tasks; using osu.Framework.Bindables; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Notifications; using osu.Game.Users; namespace osu.Game.Online.API @@ -112,6 +113,11 @@ namespace osu.Game.Online.API /// Whether to use MessagePack for serialisation if available on this platform. IHubClientConnector? GetHubConnector(string clientName, string endpoint, bool preferMessagePack = true); + /// + /// Constructs a new . + /// + NotificationsClientConnector GetNotificationsConnector(); + /// /// Create a new user account. This is a blocking operation. /// diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index c1db9630a0..7384c2a297 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -45,7 +45,6 @@ using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Online.Notifications; -using osu.Game.Online.Notifications.WebSocket; using osu.Game.Overlays; using osu.Game.Overlays.Music; using osu.Game.Overlays.Notifications; @@ -759,7 +758,7 @@ namespace osu.Game BackButton.Receptor receptor; dependencies.CacheAs(idleTracker = new GameIdleTracker(6000)); - dependencies.CacheAs(notificationsClient = new WebSocketNotificationsClientConnector(API)); + dependencies.CacheAs(notificationsClient = API.GetNotificationsConnector()); var sessionIdleTracker = new GameIdleTracker(300000); sessionIdleTracker.IsIdle.BindValueChanged(idle => From e10424286448cc962a346234d0eea9ac2bad4c1e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 1 Nov 2022 22:28:06 +0900 Subject: [PATCH 1979/2686] 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 b691751f13..8711ceec64 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9dd0d18817..8d45ebec57 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 6dce938ebf..76d2e727c8 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 905ebc3c1f7cfdfa798c6cffa2bdff3479b4d1d3 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 1 Nov 2022 20:46:32 +0100 Subject: [PATCH 1980/2686] Initial implementation of a Beatmap Information Skinning Element Signed-off-by: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> --- osu.Game/OsuGameBase.cs | 2 +- .../Components/BeatmapInfoDrawable.cs | 189 ++++++++++++++++++ 2 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Skinning/Components/BeatmapInfoDrawable.cs diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 39ddffd2d0..622e802b72 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -155,7 +155,7 @@ namespace osu.Game protected Storage Storage { get; set; } - protected Bindable Beatmap { get; private set; } // cached via load() method + public Bindable Beatmap { get; private set; } // cached via load() method [Cached] [Cached(typeof(IBindable))] diff --git a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs new file mode 100644 index 0000000000..770082daf9 --- /dev/null +++ b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs @@ -0,0 +1,189 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System; +using System.Text; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Skinning.Components +{ + /// + /// Intended to be a test bed for skinning. May be removed at some point in the future. + /// + [UsedImplicitly] + public class BeatmapInfoDrawable : Container, ISkinnableDrawable + { + public bool UsesFixedAnchor { get; set; } + + [SettingSource("Tracked Beatmap Info", "Which part of the BeatmapInformation should be tracked")] + public Bindable Type { get; } = new Bindable(BeatmapInfo.StarRating); + + [Resolved] + private OsuGameBase mGameBase { get; set; } + + private readonly OsuSpriteText text; + + public BeatmapInfoDrawable() + { + AutoSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + text = new OsuSpriteText + { + Text = "BeatInfoDrawable", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Default.With(size: 40) + } + }; + } + + // [BackgroundDependencyLoader] + // private void load(WorkingBeatmap beatmap) + // { + // this.beatmap = beatmap; + // } + + protected override void LoadComplete() + { + base.LoadComplete(); + Type.BindValueChanged(update, true); + } + + private void update(ValueChangedEvent type) + { + switch (type.NewValue) + { + case BeatmapInfo.CircleSize: + mGameBase.Beatmap.BindValueChanged(bm => + { + text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.CircleSize.ToString("F2"); + }, true); + break; + + case BeatmapInfo.HPDrain: + mGameBase.Beatmap.BindValueChanged(bm => + { + text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.DrainRate.ToString("F2"); + }, true); + break; + + case BeatmapInfo.Accuracy: + mGameBase.Beatmap.BindValueChanged(bm => + { + text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.OverallDifficulty.ToString("F2"); + }, true); + break; + + case BeatmapInfo.ApproachRate: + mGameBase.Beatmap.BindValueChanged(bm => + { + text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.ApproachRate.ToString("F2"); + }, true); + break; + + case BeatmapInfo.StarRating: + mGameBase.Beatmap.BindValueChanged(bm => + { + text.Current.Value = bm.NewValue.BeatmapInfo.StarRating.ToString("F2"); + }, true); + break; + + case BeatmapInfo.Song: + mGameBase.Beatmap.BindValueChanged(bm => + { + text.Current.Value = bm.NewValue.BeatmapInfo.Metadata.Title; + }, true); + break; + + case BeatmapInfo.Artist: + mGameBase.Beatmap.BindValueChanged(bm => + { + text.Current.Value = bm.NewValue.BeatmapInfo.Metadata.Artist; + }, true); + break; + + case BeatmapInfo.Difficulty: + mGameBase.Beatmap.BindValueChanged(bm => + { + text.Current.Value = bm.NewValue.BeatmapInfo.DifficultyName; + }, true); + break; + + case BeatmapInfo.Mapper: + mGameBase.Beatmap.BindValueChanged(bm => + { + text.Current.Value = bm.NewValue.BeatmapInfo.Metadata.Author.Username; + }, true); + break; + + case BeatmapInfo.Length: + mGameBase.Beatmap.BindValueChanged(bm => + { + const long ms_to_s = 1000; + double length = bm.NewValue.BeatmapInfo.Length; + double rawS = length / ms_to_s; + double rawM = rawS / 60; + double rawH = rawM / 60; + double rawD = rawH / 24; + + long s = (long)rawS % 60; + long m = (long)rawM % 60; + long h = (long)rawH % 24; + long d = (long)rawD; + StringBuilder builder = new StringBuilder(); + + if (d != 0) + { + builder.Append(d.ToString("D2")); + builder.Append(":"); + } + + if (h != 0 || d != 0) + { + builder.Append(h.ToString("D2")); + builder.Append(":"); + } + + builder.Append(m.ToString("D2")); + builder.Append(":"); + builder.Append(s.ToString("D2")); + text.Current.Value = builder.ToString(); + }, true); + break; + + case BeatmapInfo.BPM: + mGameBase.Beatmap.BindValueChanged(bm => + { + text.Current.Value = bm.NewValue.BeatmapInfo.BPM.ToString("F2"); + }, true); + break; + } + } + } + + public enum BeatmapInfo + { + CircleSize, + HPDrain, + Accuracy, //OD? + ApproachRate, + StarRating, + Song, + Artist, + Difficulty, + Mapper, + Length, + BPM, + } +} From c231a20cbb9b0607e3e56ec20ef118ff889bbedf Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 1 Nov 2022 20:54:52 +0100 Subject: [PATCH 1981/2686] Add a generic text Element Signed-off-by: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> --- .../Components/BeatmapInfoDrawable.cs | 12 +----- osu.Game/Skinning/Components/TextElement.cs | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Skinning/Components/TextElement.cs diff --git a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs index 770082daf9..cb207d7329 100644 --- a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs +++ b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using System.Text; using JetBrains.Annotations; using osu.Framework.Allocation; @@ -16,9 +15,6 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Skinning.Components { - /// - /// Intended to be a test bed for skinning. May be removed at some point in the future. - /// [UsedImplicitly] public class BeatmapInfoDrawable : Container, ISkinnableDrawable { @@ -48,12 +44,6 @@ namespace osu.Game.Skinning.Components }; } - // [BackgroundDependencyLoader] - // private void load(WorkingBeatmap beatmap) - // { - // this.beatmap = beatmap; - // } - protected override void LoadComplete() { base.LoadComplete(); @@ -176,7 +166,7 @@ namespace osu.Game.Skinning.Components { CircleSize, HPDrain, - Accuracy, //OD? + Accuracy, ApproachRate, StarRating, Song, diff --git a/osu.Game/Skinning/Components/TextElement.cs b/osu.Game/Skinning/Components/TextElement.cs new file mode 100644 index 0000000000..e29ab6de58 --- /dev/null +++ b/osu.Game/Skinning/Components/TextElement.cs @@ -0,0 +1,40 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using JetBrains.Annotations; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Skinning.Components +{ + [UsedImplicitly] + public class TextElement : Container, ISkinnableDrawable + { + public bool UsesFixedAnchor { get; set; } + + [SettingSource("Displayed Text", "What text should be displayed")] + public Bindable Text { get; } = new Bindable("Circles!"); + + public TextElement() + { + AutoSizeAxes = Axes.Both; + OsuSpriteText text; + InternalChildren = new Drawable[] + { + text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Default.With(size: 40) + } + }; + text.Current.BindTo(Text); + } + } +} From 975eed964e5c773de4b882cb7c620e9633130755 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Tue, 1 Nov 2022 21:19:01 +0100 Subject: [PATCH 1982/2686] Don't make Beatmap in OsuGameBase public Signed-off-by: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> --- osu.Game/OsuGameBase.cs | 2 +- .../Components/BeatmapInfoDrawable.cs | 25 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 622e802b72..39ddffd2d0 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -155,7 +155,7 @@ namespace osu.Game protected Storage Storage { get; set; } - public Bindable Beatmap { get; private set; } // cached via load() method + protected Bindable Beatmap { get; private set; } // cached via load() method [Cached] [Cached(typeof(IBindable))] diff --git a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs index cb207d7329..ae91d14830 100644 --- a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs +++ b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs @@ -9,6 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -24,7 +25,7 @@ namespace osu.Game.Skinning.Components public Bindable Type { get; } = new Bindable(BeatmapInfo.StarRating); [Resolved] - private OsuGameBase mGameBase { get; set; } + private IBindable beatmap { get; set; } private readonly OsuSpriteText text; @@ -55,70 +56,70 @@ namespace osu.Game.Skinning.Components switch (type.NewValue) { case BeatmapInfo.CircleSize: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.CircleSize.ToString("F2"); }, true); break; case BeatmapInfo.HPDrain: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.DrainRate.ToString("F2"); }, true); break; case BeatmapInfo.Accuracy: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.OverallDifficulty.ToString("F2"); }, true); break; case BeatmapInfo.ApproachRate: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.ApproachRate.ToString("F2"); }, true); break; case BeatmapInfo.StarRating: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { text.Current.Value = bm.NewValue.BeatmapInfo.StarRating.ToString("F2"); }, true); break; case BeatmapInfo.Song: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { text.Current.Value = bm.NewValue.BeatmapInfo.Metadata.Title; }, true); break; case BeatmapInfo.Artist: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { text.Current.Value = bm.NewValue.BeatmapInfo.Metadata.Artist; }, true); break; case BeatmapInfo.Difficulty: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { text.Current.Value = bm.NewValue.BeatmapInfo.DifficultyName; }, true); break; case BeatmapInfo.Mapper: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { text.Current.Value = bm.NewValue.BeatmapInfo.Metadata.Author.Username; }, true); break; case BeatmapInfo.Length: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { const long ms_to_s = 1000; double length = bm.NewValue.BeatmapInfo.Length; @@ -153,7 +154,7 @@ namespace osu.Game.Skinning.Components break; case BeatmapInfo.BPM: - mGameBase.Beatmap.BindValueChanged(bm => + beatmap.BindValueChanged(bm => { text.Current.Value = bm.NewValue.BeatmapInfo.BPM.ToString("F2"); }, true); From 8ac2075c61727961b1fe43554bc077abdc7ee7b5 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 10:04:24 +0900 Subject: [PATCH 1983/2686] Fix possible threading issues Not really sure of the best way to handle this in general. It could be argued that this should be a `Component` type and the bindable bound in `LoadComplete()`... --- osu.Game/Online/Notifications/NotificationsClient.cs | 6 +++--- .../Notifications/Polling/PollingNotificationsClient.cs | 5 +---- .../Polling/PollingNotificationsClientConnector.cs | 5 +---- osu.Game/Online/SocketClientConnector.cs | 7 +++++-- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs index 6d9226ca17..8c41ae10d7 100644 --- a/osu.Game/Online/Notifications/NotificationsClient.cs +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -21,14 +21,14 @@ namespace osu.Game.Online.Notifications public Action>? NewMessages; public Action? PresenceReceived; - private readonly IAPIProvider api; + protected readonly IAPIProvider API; private bool enableChat; private long lastMessageId; protected NotificationsClient(IAPIProvider api) { - this.api = api; + API = api; } public bool EnableChat @@ -54,7 +54,7 @@ namespace osu.Game.Online.Notifications protected virtual Task StartChatAsync() { - api.Queue(CreateFetchMessagesRequest(0)); + API.Queue(CreateFetchMessagesRequest(0)); return Task.CompletedTask; } diff --git a/osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs b/osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs index 1c5559fcb4..2f343abf86 100644 --- a/osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs +++ b/osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs @@ -12,12 +12,9 @@ namespace osu.Game.Online.Notifications.Polling /// public class PollingNotificationsClient : NotificationsClient { - private readonly IAPIProvider api; - public PollingNotificationsClient(IAPIProvider api) : base(api) { - this.api = api; } public override Task ConnectAsync(CancellationToken cancellationToken) @@ -26,7 +23,7 @@ namespace osu.Game.Online.Notifications.Polling { while (!cancellationToken.IsCancellationRequested) { - await api.PerformAsync(CreateFetchMessagesRequest()); + await API.PerformAsync(CreateFetchMessagesRequest()); await Task.Delay(1000, cancellationToken); } }, cancellationToken); diff --git a/osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs b/osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs index 18a31ff061..ff3f30edcd 100644 --- a/osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs +++ b/osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs @@ -12,15 +12,12 @@ namespace osu.Game.Online.Notifications.Polling /// public class PollingNotificationsClientConnector : NotificationsClientConnector { - private readonly IAPIProvider api; - public PollingNotificationsClientConnector(IAPIProvider api) : base(api) { - this.api = api; } protected override Task BuildNotificationClientAsync(CancellationToken cancellationToken) - => Task.FromResult((NotificationsClient)new PollingNotificationsClient(api)); + => Task.FromResult((NotificationsClient)new PollingNotificationsClient(API)); } } diff --git a/osu.Game/Online/SocketClientConnector.cs b/osu.Game/Online/SocketClientConnector.cs index c6d5601c1f..abf19fbba3 100644 --- a/osu.Game/Online/SocketClientConnector.cs +++ b/osu.Game/Online/SocketClientConnector.cs @@ -23,18 +23,21 @@ namespace osu.Game.Online /// public SocketClient? CurrentConnection { get; private set; } + protected readonly IAPIProvider API; + + private readonly IBindable apiState = new Bindable(); private readonly Bindable isConnected = new Bindable(); private readonly SemaphoreSlim connectionLock = new SemaphoreSlim(1); private CancellationTokenSource connectCancelSource = new CancellationTokenSource(); - private readonly IBindable apiState = new Bindable(); - /// /// Constructs a new . /// /// An API provider used to react to connection state changes. protected SocketClientConnector(IAPIProvider api) { + API = api; + apiState.BindTo(api.State); apiState.BindValueChanged(_ => Task.Run(connectIfPossible), true); } From 5448c0209e0a824a0d6a75d1ae5577c79f03c549 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 10:14:40 +0900 Subject: [PATCH 1984/2686] Rename var --- .../Difficulty/TaikoPerformanceCalculator.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 4839a89646..317e4a2f72 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; // TODO: The detection of rulesets is temporary until the leftover old skills have been reworked. - bool rulesetTaiko = score.BeatmapInfo.Ruleset.OnlineID == 1; + bool taikoSpecificBeatmap = score.BeatmapInfo.Ruleset.OnlineID == 1; double multiplier = 1.13; @@ -54,8 +54,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModEasy)) multiplier *= 0.975; - double difficultyValue = computeDifficultyValue(score, taikoAttributes, rulesetTaiko); - double accuracyValue = computeAccuracyValue(score, taikoAttributes, rulesetTaiko); + double difficultyValue = computeDifficultyValue(score, taikoAttributes, taikoSpecificBeatmap); + double accuracyValue = computeAccuracyValue(score, taikoAttributes, taikoSpecificBeatmap); double totalValue = Math.Pow( Math.Pow(difficultyValue, 1.1) + @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty }; } - private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool rulesetTaiko) + private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool taikoSpecificBeatmap) { double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.115) - 4.0, 2.25) / 1150.0; @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModEasy)) difficultyValue *= 0.985; - if (score.Mods.Any(m => m is ModHidden) && rulesetTaiko) + if (score.Mods.Any(m => m is ModHidden) && taikoSpecificBeatmap) difficultyValue *= 1.025; if (score.Mods.Any(m => m is ModHardRock)) @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty return difficultyValue * Math.Pow(accuracy, 2.0); } - private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool rulesetTaiko) + private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool taikoSpecificBeatmap) { if (attributes.GreatHitWindow <= 0) return 0; @@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty accuracyValue *= lengthBonus; // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values. - if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden) && rulesetTaiko) + if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden) && taikoSpecificBeatmap) accuracyValue *= Math.Max(1.0, 1.1 * lengthBonus); return accuracyValue; From 46d1713e28c1726c28d998bd89a9c481cb7a53ce Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 11:43:22 +0900 Subject: [PATCH 1985/2686] Rename Socket* -> PersistentEndpoint* --- osu.Game/Online/HubClient.cs | 2 +- osu.Game/Online/HubClientConnector.cs | 6 +++--- .../{SocketClient.cs => PersistentEndpointClient.cs} | 2 +- ...tConnector.cs => PersistentEndpointClientConnector.cs} | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) rename osu.Game/Online/{SocketClient.cs => PersistentEndpointClient.cs} (90%) rename osu.Game/Online/{SocketClientConnector.cs => PersistentEndpointClientConnector.cs} (95%) diff --git a/osu.Game/Online/HubClient.cs b/osu.Game/Online/HubClient.cs index 262e298f34..07428f58b4 100644 --- a/osu.Game/Online/HubClient.cs +++ b/osu.Game/Online/HubClient.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.SignalR.Client; namespace osu.Game.Online { - public class HubClient : SocketClient + public class HubClient : PersistentEndpointClient { public readonly HubConnection Connection; diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 33e9f92817..6f246f6dd3 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -14,7 +14,7 @@ using osu.Game.Online.API; namespace osu.Game.Online { - public class HubClientConnector : SocketClientConnector, IHubClientConnector + public class HubClientConnector : PersistentEndpointClientConnector, IHubClientConnector { public const string SERVER_SHUTDOWN_MESSAGE = "Server is shutting down."; @@ -51,7 +51,7 @@ namespace osu.Game.Online this.preferMessagePack = preferMessagePack; } - protected override Task BuildConnectionAsync(CancellationToken cancellationToken) + protected override Task BuildConnectionAsync(CancellationToken cancellationToken) { var builder = new HubConnectionBuilder() .WithUrl(endpoint, options => @@ -91,7 +91,7 @@ namespace osu.Game.Online ConfigureConnection?.Invoke(newConnection); - return Task.FromResult((SocketClient)new HubClient(newConnection)); + return Task.FromResult((PersistentEndpointClient)new HubClient(newConnection)); } protected override string ClientName { get; } diff --git a/osu.Game/Online/SocketClient.cs b/osu.Game/Online/PersistentEndpointClient.cs similarity index 90% rename from osu.Game/Online/SocketClient.cs rename to osu.Game/Online/PersistentEndpointClient.cs index 3b4aa1b49b..d6ed2d8aec 100644 --- a/osu.Game/Online/SocketClient.cs +++ b/osu.Game/Online/PersistentEndpointClient.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace osu.Game.Online { - public abstract class SocketClient : IAsyncDisposable + public abstract class PersistentEndpointClient : IAsyncDisposable { public event Func? Closed; diff --git a/osu.Game/Online/SocketClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs similarity index 95% rename from osu.Game/Online/SocketClientConnector.cs rename to osu.Game/Online/PersistentEndpointClientConnector.cs index 823e724ef9..fca7f2ed48 100644 --- a/osu.Game/Online/SocketClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -12,7 +12,7 @@ using osu.Game.Online.API; namespace osu.Game.Online { - public abstract class SocketClientConnector : Component + public abstract class PersistentEndpointClientConnector : Component { /// /// Whether this is connected to the hub, use to access the connection, if this is true. @@ -22,7 +22,7 @@ namespace osu.Game.Online /// /// The current connection opened by this connector. /// - public SocketClient? CurrentConnection { get; private set; } + public PersistentEndpointClient? CurrentConnection { get; private set; } private readonly Bindable isConnected = new Bindable(); private readonly SemaphoreSlim connectionLock = new SemaphoreSlim(1); @@ -34,7 +34,7 @@ namespace osu.Game.Online /// Constructs a new . /// /// An API provider used to react to connection state changes. - protected SocketClientConnector(IAPIProvider api) + protected PersistentEndpointClientConnector(IAPIProvider api) { apiState.BindTo(api.State); apiState.BindValueChanged(_ => Task.Run(connectIfPossible), true); @@ -124,7 +124,7 @@ namespace osu.Game.Online await Task.Delay(5000, cancellationToken).ConfigureAwait(false); } - protected abstract Task BuildConnectionAsync(CancellationToken cancellationToken); + protected abstract Task BuildConnectionAsync(CancellationToken cancellationToken); private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) { From c9108ce41bd3afc65a931bbd7f79a770030b75df Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 11:44:16 +0900 Subject: [PATCH 1986/2686] Rename StartAsync -> ConnectAsync --- osu.Game/Online/HubClient.cs | 2 +- osu.Game/Online/PersistentEndpointClient.cs | 2 +- osu.Game/Online/PersistentEndpointClientConnector.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/HubClient.cs b/osu.Game/Online/HubClient.cs index 07428f58b4..583f15a4a4 100644 --- a/osu.Game/Online/HubClient.cs +++ b/osu.Game/Online/HubClient.cs @@ -17,7 +17,7 @@ namespace osu.Game.Online Connection.Closed += InvokeClosed; } - public override Task StartAsync(CancellationToken cancellationToken) => Connection.StartAsync(cancellationToken); + public override Task ConnectAsync(CancellationToken cancellationToken) => Connection.StartAsync(cancellationToken); public override async ValueTask DisposeAsync() { diff --git a/osu.Game/Online/PersistentEndpointClient.cs b/osu.Game/Online/PersistentEndpointClient.cs index d6ed2d8aec..e0307f7c6a 100644 --- a/osu.Game/Online/PersistentEndpointClient.cs +++ b/osu.Game/Online/PersistentEndpointClient.cs @@ -13,7 +13,7 @@ namespace osu.Game.Online protected Task InvokeClosed(Exception? exception) => Closed?.Invoke(exception) ?? Task.CompletedTask; - public abstract Task StartAsync(CancellationToken cancellationToken); + public abstract Task ConnectAsync(CancellationToken cancellationToken); public virtual ValueTask DisposeAsync() { diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index fca7f2ed48..7082757b15 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -92,7 +92,7 @@ namespace osu.Game.Online cancellationToken.ThrowIfCancellationRequested(); - await CurrentConnection.StartAsync(cancellationToken).ConfigureAwait(false); + await CurrentConnection.ConnectAsync(cancellationToken).ConfigureAwait(false); Logger.Log($"{ClientName} connected!", LoggingTarget.Network); isConnected.Value = true; From e59c8b7d24fff0072a1392442808ad55634cb6ba Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 11:49:04 +0900 Subject: [PATCH 1987/2686] Use IDisposable instead --- .../PersistentEndpointClientConnector.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index 7082757b15..2ea0c95ec1 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -6,13 +6,12 @@ using System.Threading; using System.Threading.Tasks; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; -using osu.Framework.Graphics; using osu.Framework.Logging; using osu.Game.Online.API; namespace osu.Game.Online { - public abstract class PersistentEndpointClientConnector : Component + public abstract class PersistentEndpointClientConnector : IDisposable { /// /// Whether this is connected to the hub, use to access the connection, if this is true. @@ -173,11 +172,23 @@ namespace osu.Game.Online public override string ToString() => $"{ClientName} ({(IsConnected.Value ? "connected" : "not connected")})"; - protected override void Dispose(bool isDisposing) + private bool isDisposed; + + protected virtual void Dispose(bool isDisposing) { - base.Dispose(isDisposing); + if (isDisposed) + return; + apiState.UnbindAll(); cancelExistingConnect(); + + isDisposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); } } } From 2f3c80f884abd31f0b801a8b2c3193d619adfa60 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 13:08:29 +0900 Subject: [PATCH 1988/2686] Remove toggle and change method of application to blend with original colour --- osu.Game/Configuration/OsuConfigManager.cs | 4 +--- .../Settings/Sections/Gameplay/BeatmapSettings.cs | 14 -------------- .../Objects/Drawables/DrawableHitObject.cs | 10 +++++++--- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 08724aab4b..0d56ab8962 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -175,8 +175,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.LastProcessedMetadataId, -1); - SetDefault(OsuSetting.NormaliseComboColourBrightness, false); - SetDefault(OsuSetting.ComboColourBrightness, 0.7f, 0f, 1f); + SetDefault(OsuSetting.ComboColourBrightness, 0f, -1f, 1f, 1f); } protected override bool CheckLookupContainsPrivateInformation(OsuSetting lookup) @@ -367,7 +366,6 @@ namespace osu.Game.Configuration AutomaticallyDownloadWhenSpectating, ShowOnlineExplicitContent, LastProcessedMetadataId, - NormaliseComboColourBrightness, SafeAreaConsiderations, ComboColourBrightness, } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs index 0de8f6509f..8bfa3e502c 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs @@ -17,13 +17,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay protected override LocalisableString Header => GameplaySettingsStrings.BeatmapHeader; private readonly BindableFloat comboColourBrightness = new BindableFloat(); - private readonly BindableBool normaliseComboColourBrightness = new BindableBool(); [BackgroundDependencyLoader] private void load(OsuConfigManager config) { config.BindWith(OsuSetting.ComboColourBrightness, comboColourBrightness); - config.BindWith(OsuSetting.NormaliseComboColourBrightness, normaliseComboColourBrightness); Children = new Drawable[] { @@ -47,11 +45,6 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay LabelText = GraphicsSettingsStrings.StoryboardVideo, Current = config.GetBindable(OsuSetting.ShowStoryboard) }, - new SettingsCheckbox - { - LabelText = "Normalise combo colour brightness", - Current = normaliseComboColourBrightness - }, new SettingsSlider { LabelText = "Combo colour brightness", @@ -60,12 +53,5 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay } }; } - - protected override void LoadComplete() - { - base.LoadComplete(); - - normaliseComboColourBrightness.BindValueChanged(normalise => comboColourBrightness.Disabled = !normalise.NewValue, true); - } } } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 8a32c015a3..077606cb3a 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -15,6 +15,7 @@ using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Framework.Threading; +using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Configuration; using osu.Game.Graphics; @@ -174,7 +175,6 @@ namespace osu.Game.Rulesets.Objects.Drawables private void load(OsuConfigManager config, ISkinSource skinSource) { config.BindWith(OsuSetting.PositionalHitsoundsLevel, positionalHitsoundsLevel); - config.BindWith(OsuSetting.NormaliseComboColourBrightness, normaliseComboColourBrightness); config.BindWith(OsuSetting.ComboColourBrightness, comboColourBrightness); // Explicit non-virtual function call in case a DrawableHitObject overrides AddInternal. @@ -522,8 +522,12 @@ namespace osu.Game.Rulesets.Objects.Drawables Color4 colour = combo.GetComboColour(CurrentSkin); // Normalise the combo colour to the given brightness level. - if (normaliseComboColourBrightness.Value) - colour = new HSPAColour(colour) { P = comboColourBrightness.Value }.ToColor4(); + if (comboColourBrightness.Value != 0) + { + float pAdjust = 0.6f + 0.4f * comboColourBrightness.Value; + + colour = Interpolation.ValueAt(Math.Abs(comboColourBrightness.Value), colour, new HSPAColour(colour) { P = pAdjust }.ToColor4(), 0, 1, Easing.Out); + } AccentColour.Value = colour; } From 30800c925299a7701e3f83853f47ee22afeb8386 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 13:15:34 +0900 Subject: [PATCH 1989/2686] Add/adjust xmldocs --- osu.Game/Online/PersistentEndpointClient.cs | 11 +++++++++++ osu.Game/Online/PersistentEndpointClientConnector.cs | 8 ++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/PersistentEndpointClient.cs b/osu.Game/Online/PersistentEndpointClient.cs index e0307f7c6a..32c243fbbb 100644 --- a/osu.Game/Online/PersistentEndpointClient.cs +++ b/osu.Game/Online/PersistentEndpointClient.cs @@ -9,10 +9,21 @@ namespace osu.Game.Online { public abstract class PersistentEndpointClient : IAsyncDisposable { + /// + /// An event notifying the that the connection has been closed + /// public event Func? Closed; + /// + /// Notifies the that the connection has been closed. + /// + /// The exception that the connection closed with. protected Task InvokeClosed(Exception? exception) => Closed?.Invoke(exception) ?? Task.CompletedTask; + /// + /// Connects the client to the remote service to begin processing messages. + /// + /// A cancellation token to stop processing messages. public abstract Task ConnectAsync(CancellationToken cancellationToken); public virtual ValueTask DisposeAsync() diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index 2ea0c95ec1..70e10c6c7d 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -14,7 +14,7 @@ namespace osu.Game.Online public abstract class PersistentEndpointClientConnector : IDisposable { /// - /// Whether this is connected to the hub, use to access the connection, if this is true. + /// Whether the managed connection is currently connected. When true use to access the connection. /// public IBindable IsConnected => isConnected; @@ -30,7 +30,7 @@ namespace osu.Game.Online private readonly IBindable apiState = new Bindable(); /// - /// Constructs a new . + /// Constructs a new . /// /// An API provider used to react to connection state changes. protected PersistentEndpointClientConnector(IAPIProvider api) @@ -123,6 +123,10 @@ namespace osu.Game.Online await Task.Delay(5000, cancellationToken).ConfigureAwait(false); } + /// + /// Creates a new . + /// + /// A cancellation token to stop the process. protected abstract Task BuildConnectionAsync(CancellationToken cancellationToken); private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) From 99ba7c29dd99c92bd29396e276558206bc62076b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 13:46:50 +0900 Subject: [PATCH 1990/2686] Change range to 0-100% and rename to "normalisation" --- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- .../Settings/Sections/Gameplay/BeatmapSettings.cs | 8 ++++---- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 6 ++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 0d56ab8962..98776c7487 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -175,7 +175,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.LastProcessedMetadataId, -1); - SetDefault(OsuSetting.ComboColourBrightness, 0f, -1f, 1f, 1f); + SetDefault(OsuSetting.ComboColourNormalisation, 0.2f, 0f, 1f, 0.01f); } protected override bool CheckLookupContainsPrivateInformation(OsuSetting lookup) @@ -367,6 +367,6 @@ namespace osu.Game.Configuration ShowOnlineExplicitContent, LastProcessedMetadataId, SafeAreaConsiderations, - ComboColourBrightness, + ComboColourNormalisation, } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs index 8bfa3e502c..ab9be70a5b 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs @@ -16,12 +16,12 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { protected override LocalisableString Header => GameplaySettingsStrings.BeatmapHeader; - private readonly BindableFloat comboColourBrightness = new BindableFloat(); + private readonly BindableFloat comboColourNormalisation = new BindableFloat(); [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - config.BindWith(OsuSetting.ComboColourBrightness, comboColourBrightness); + config.BindWith(OsuSetting.ComboColourNormalisation, comboColourNormalisation); Children = new Drawable[] { @@ -47,8 +47,8 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay }, new SettingsSlider { - LabelText = "Combo colour brightness", - Current = comboColourBrightness, + LabelText = "Combo colour normalisation", + Current = comboColourNormalisation, DisplayAsPercentage = true, } }; diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 077606cb3a..98fd73c8e9 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -175,7 +175,7 @@ namespace osu.Game.Rulesets.Objects.Drawables private void load(OsuConfigManager config, ISkinSource skinSource) { config.BindWith(OsuSetting.PositionalHitsoundsLevel, positionalHitsoundsLevel); - config.BindWith(OsuSetting.ComboColourBrightness, comboColourBrightness); + config.BindWith(OsuSetting.ComboColourNormalisation, comboColourBrightness); // Explicit non-virtual function call in case a DrawableHitObject overrides AddInternal. base.AddInternal(Samples = new PausableSkinnableSound()); @@ -524,9 +524,7 @@ namespace osu.Game.Rulesets.Objects.Drawables // Normalise the combo colour to the given brightness level. if (comboColourBrightness.Value != 0) { - float pAdjust = 0.6f + 0.4f * comboColourBrightness.Value; - - colour = Interpolation.ValueAt(Math.Abs(comboColourBrightness.Value), colour, new HSPAColour(colour) { P = pAdjust }.ToColor4(), 0, 1, Easing.Out); + colour = Interpolation.ValueAt(Math.Abs(comboColourBrightness.Value), colour, new HSPAColour(colour) { P = 0.6f }.ToColor4(), 0, 1); } AccentColour.Value = colour; From d8aa06ea92fa5a73c23b9305838efbd486aaaa55 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 13:55:01 +0900 Subject: [PATCH 1991/2686] Standardise "Visual Settings" components to fix mismatched paddings and labels --- .../Play/PlayerSettings/PlayerCheckbox.cs | 21 ++++++++++++------- .../Play/PlayerSettings/VisualSettings.cs | 16 ++------------ 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs index dc09676254..cea03d2155 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs @@ -1,22 +1,27 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Settings; namespace osu.Game.Screens.Play.PlayerSettings { - public class PlayerCheckbox : OsuCheckbox + public class PlayerCheckbox : SettingsCheckbox { - [BackgroundDependencyLoader] - private void load(OsuColour colours) + protected override Drawable CreateControl() => new PlayerCheckboxControl(); + + public class PlayerCheckboxControl : OsuCheckbox { - Nub.AccentColour = colours.Yellow; - Nub.GlowingAccentColour = colours.YellowLighter; - Nub.GlowColour = colours.YellowDark; + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Nub.AccentColour = colours.Yellow; + Nub.GlowingAccentColour = colours.YellowLighter; + Nub.GlowColour = colours.YellowDark; + } } } } diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index e55af0bba7..72a57f658c 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Configuration; @@ -24,26 +22,16 @@ namespace osu.Game.Screens.Play.PlayerSettings { Children = new Drawable[] { - new OsuSpriteText - { - Text = GameplaySettingsStrings.BackgroundDim - }, dimSliderBar = new PlayerSliderBar { + LabelText = GameplaySettingsStrings.BackgroundDim, DisplayAsPercentage = true }, - new OsuSpriteText - { - Text = GameplaySettingsStrings.BackgroundBlur - }, blurSliderBar = new PlayerSliderBar { + LabelText = GameplaySettingsStrings.BackgroundBlur, DisplayAsPercentage = true }, - new OsuSpriteText - { - Text = "Toggles:" - }, showStoryboardToggle = new PlayerCheckbox { LabelText = GraphicsSettingsStrings.StoryboardVideo }, beatmapSkinsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapSkins }, beatmapColorsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapColours }, From 61fc3c8cc0878dab7cea7a4dbc7d0bb26e6e6fab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 13:48:03 +0900 Subject: [PATCH 1992/2686] Add setting to visual settings toolbox --- osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index 72a57f658c..10d132fc4d 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Configuration; -using osu.Game.Graphics.Sprites; using osu.Game.Localisation; namespace osu.Game.Screens.Play.PlayerSettings @@ -13,6 +12,7 @@ namespace osu.Game.Screens.Play.PlayerSettings { private readonly PlayerSliderBar dimSliderBar; private readonly PlayerSliderBar blurSliderBar; + private readonly PlayerSliderBar comboColourNormalisationSliderBar; private readonly PlayerCheckbox showStoryboardToggle; private readonly PlayerCheckbox beatmapSkinsToggle; private readonly PlayerCheckbox beatmapColorsToggle; @@ -35,6 +35,11 @@ namespace osu.Game.Screens.Play.PlayerSettings showStoryboardToggle = new PlayerCheckbox { LabelText = GraphicsSettingsStrings.StoryboardVideo }, beatmapSkinsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapSkins }, beatmapColorsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapColours }, + comboColourNormalisationSliderBar = new PlayerSliderBar + { + LabelText = "Combo colour normalisation", + DisplayAsPercentage = true, + }, }; } @@ -46,6 +51,7 @@ namespace osu.Game.Screens.Play.PlayerSettings showStoryboardToggle.Current = config.GetBindable(OsuSetting.ShowStoryboard); beatmapSkinsToggle.Current = config.GetBindable(OsuSetting.BeatmapSkins); beatmapColorsToggle.Current = config.GetBindable(OsuSetting.BeatmapColours); + comboColourNormalisationSliderBar.Current = config.GetBindable(OsuSetting.ComboColourNormalisation); } } } From 50b6fe4acb24e5fa9794d9653489c84d78989d12 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 14:01:03 +0900 Subject: [PATCH 1993/2686] Localise new label --- osu.Game/Localisation/GraphicsSettingsStrings.cs | 5 +++++ .../Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs | 2 +- osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/GraphicsSettingsStrings.cs b/osu.Game/Localisation/GraphicsSettingsStrings.cs index 2ab9d9de87..6e05929d81 100644 --- a/osu.Game/Localisation/GraphicsSettingsStrings.cs +++ b/osu.Game/Localisation/GraphicsSettingsStrings.cs @@ -99,6 +99,11 @@ namespace osu.Game.Localisation /// public static LocalisableString StoryboardVideo => new TranslatableString(getKey(@"storyboard_video"), @"Storyboard / video"); + /// + /// "Combo colour normalisation" + /// + public static LocalisableString ComboColourNormalisation => new TranslatableString(getKey(@"combo_colour_normalisation"), @"Combo colour normalisation"); + /// /// "Hit lighting" /// diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs index ab9be70a5b..8d64337eab 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs @@ -47,7 +47,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay }, new SettingsSlider { - LabelText = "Combo colour normalisation", + LabelText = GraphicsSettingsStrings.ComboColourNormalisation, Current = comboColourNormalisation, DisplayAsPercentage = true, } diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index 10d132fc4d..c837f61a09 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs @@ -37,7 +37,7 @@ namespace osu.Game.Screens.Play.PlayerSettings beatmapColorsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapColours }, comboColourNormalisationSliderBar = new PlayerSliderBar { - LabelText = "Combo colour normalisation", + LabelText = GraphicsSettingsStrings.ComboColourNormalisation, DisplayAsPercentage = true, }, }; From 37300ba9e25ae1d2e3f6e9dd747d27b5fa4d18c9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 13:55:01 +0900 Subject: [PATCH 1994/2686] Standardise "Visual Settings" components to fix mismatched paddings and labels --- .../Play/PlayerSettings/PlayerCheckbox.cs | 21 ++++++++++++------- .../Play/PlayerSettings/VisualSettings.cs | 17 ++------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs index dc09676254..cea03d2155 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs @@ -1,22 +1,27 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Settings; namespace osu.Game.Screens.Play.PlayerSettings { - public class PlayerCheckbox : OsuCheckbox + public class PlayerCheckbox : SettingsCheckbox { - [BackgroundDependencyLoader] - private void load(OsuColour colours) + protected override Drawable CreateControl() => new PlayerCheckboxControl(); + + public class PlayerCheckboxControl : OsuCheckbox { - Nub.AccentColour = colours.Yellow; - Nub.GlowingAccentColour = colours.YellowLighter; - Nub.GlowColour = colours.YellowDark; + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Nub.AccentColour = colours.Yellow; + Nub.GlowingAccentColour = colours.YellowLighter; + Nub.GlowColour = colours.YellowDark; + } } } } diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index e55af0bba7..bb3360acec 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs @@ -1,12 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Configuration; -using osu.Game.Graphics.Sprites; using osu.Game.Localisation; namespace osu.Game.Screens.Play.PlayerSettings @@ -24,26 +21,16 @@ namespace osu.Game.Screens.Play.PlayerSettings { Children = new Drawable[] { - new OsuSpriteText - { - Text = GameplaySettingsStrings.BackgroundDim - }, dimSliderBar = new PlayerSliderBar { + LabelText = GameplaySettingsStrings.BackgroundDim, DisplayAsPercentage = true }, - new OsuSpriteText - { - Text = GameplaySettingsStrings.BackgroundBlur - }, blurSliderBar = new PlayerSliderBar { + LabelText = GameplaySettingsStrings.BackgroundBlur, DisplayAsPercentage = true }, - new OsuSpriteText - { - Text = "Toggles:" - }, showStoryboardToggle = new PlayerCheckbox { LabelText = GraphicsSettingsStrings.StoryboardVideo }, beatmapSkinsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapSkins }, beatmapColorsToggle = new PlayerCheckbox { LabelText = SkinSettingsStrings.BeatmapColours }, From e761c0395d411aadc40e565f8deeff43c641c4a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 14:47:56 +0900 Subject: [PATCH 1995/2686] Fix multiple notifications arriving for imports in edge cases --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 4cf47013bd..7b62c95179 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -148,7 +148,7 @@ namespace osu.Game.Overlays.Notifications } } - private bool completionSent; + private int completionSent; /// /// Attempt to post a completion notification. @@ -162,11 +162,11 @@ namespace osu.Game.Overlays.Notifications if (CompletionTarget == null) return; - if (completionSent) + // Thread-safe barrier, as this may be called by a web request and also scheduled to the update thread at the same time. + if (Interlocked.Increment(ref completionSent) == 0) return; CompletionTarget.Invoke(CreateCompletionNotification()); - completionSent = true; Close(false); } From df1f7e2b13192efc811594d8bbfbf6b2eaab607f Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Wed, 2 Nov 2022 15:09:40 +0900 Subject: [PATCH 1996/2686] remove `#nullable disable` --- osu.Game/Graphics/Containers/UserDimContainer.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs index 296855522b..a6a8f341b6 100644 --- a/osu.Game/Graphics/Containers/UserDimContainer.cs +++ b/osu.Game/Graphics/Containers/UserDimContainer.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -46,13 +44,13 @@ namespace osu.Game.Graphics.Containers /// public bool ContentDisplayed { get; private set; } - protected Bindable UserDimLevel { get; private set; } + protected Bindable UserDimLevel { get; private set; } = null!; public Bindable DimAmount { get; set; } = new Bindable(); - protected Bindable LightenDuringBreaks { get; private set; } + protected Bindable LightenDuringBreaks { get; private set; } = null!; - protected Bindable ShowStoryboard { get; private set; } + protected Bindable ShowStoryboard { get; private set; } = null!; private float breakLightening => LightenDuringBreaks.Value && IsBreakTime.Value ? BREAK_LIGHTEN_AMOUNT : 0; From d6b8439121ce20ec11c8ad2bfae9892394ba9523 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Wed, 2 Nov 2022 15:11:49 +0900 Subject: [PATCH 1997/2686] add xmldoc for DimAmount --- osu.Game/Graphics/Containers/UserDimContainer.cs | 3 +++ osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs index a6a8f341b6..62dd4e19b0 100644 --- a/osu.Game/Graphics/Containers/UserDimContainer.cs +++ b/osu.Game/Graphics/Containers/UserDimContainer.cs @@ -46,6 +46,9 @@ namespace osu.Game.Graphics.Containers protected Bindable UserDimLevel { get; private set; } = null!; + /// + /// The amount of dim to be override if is true. + /// public Bindable DimAmount { get; set; } = new Bindable(); protected Bindable LightenDuringBreaks { get; private set; } = null!; diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs index 053bcf2387..9f3e99d793 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs @@ -43,6 +43,9 @@ namespace osu.Game.Screens.Backgrounds /// public readonly Bindable BlurAmount = new BindableFloat(); + /// + /// The amount of dim to be override if is true. + /// public readonly Bindable DimAmount = new Bindable(); internal readonly IBindable IsBreakTime = new Bindable(); From 98846182909f5be197ce44c413ccdc05cfa79e48 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Wed, 2 Nov 2022 15:12:15 +0900 Subject: [PATCH 1998/2686] rename `editorDim` to `editorBackgroundDim` --- osu.Game/Screens/Edit/Editor.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 3c91d302ae..04fa96171d 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -175,7 +175,7 @@ namespace osu.Game.Screens.Edit [Resolved(canBeNull: true)] private OnScreenDisplay onScreenDisplay { get; set; } - private Bindable editorDim; + private Bindable editorBackgroundDim; public Editor(EditorLoader loader = null) { @@ -261,7 +261,7 @@ namespace osu.Game.Screens.Edit OsuMenuItem undoMenuItem; OsuMenuItem redoMenuItem; - editorDim = config.GetBindable(OsuSetting.EditorDim); + editorBackgroundDim = config.GetBindable(OsuSetting.EditorDim); AddInternal(new OsuContextMenuContainer { @@ -314,7 +314,7 @@ namespace osu.Game.Screens.Edit Items = new MenuItem[] { new WaveformOpacityMenuItem(config.GetBindable(OsuSetting.EditorWaveformOpacity)), - new BackgroundDimMenuItem(editorDim), + new BackgroundDimMenuItem(editorBackgroundDim), } } } @@ -335,7 +335,7 @@ namespace osu.Game.Screens.Edit changeHandler?.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true); changeHandler?.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true); - editorDim.BindValueChanged(_ => dimBackground()); + editorBackgroundDim.BindValueChanged(_ => dimBackground()); } [Resolved] @@ -632,7 +632,7 @@ namespace osu.Game.Screens.Edit ApplyToBackground(b => { b.IgnoreUserSettings.Value = true; - b.DimAmount.Value = editorDim.Value; + b.DimAmount.Value = editorBackgroundDim.Value; b.BlurAmount.Value = 0; }); } From e5f53b1ad8346c3d0e9241bfd79138df2aae3121 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 15:18:47 +0900 Subject: [PATCH 1999/2686] Use Interlocked.Exhange() instead Increment isn't correct since it returns the post-incremented value. It also always increments. --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 7b62c95179..54a1d69a9e 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -163,7 +163,7 @@ namespace osu.Game.Overlays.Notifications return; // Thread-safe barrier, as this may be called by a web request and also scheduled to the update thread at the same time. - if (Interlocked.Increment(ref completionSent) == 0) + if (Interlocked.Exchange(ref completionSent, 1) == 0) return; CompletionTarget.Invoke(CreateCompletionNotification()); From fe66b207020fb816b1395fc50d507717ef8bcf16 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 15:22:46 +0900 Subject: [PATCH 2000/2686] Fix one more case of constructing connector directly --- osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs index 99cd9beecf..04dfe5f7c2 100644 --- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tournament.Components if (manager == null) { - AddInternal(manager = new ChannelManager(api, new WebSocketNotificationsClientConnector(api))); + AddInternal(manager = new ChannelManager(api, api.GetNotificationsConnector())); Channel.BindTo(manager.CurrentChannel); } From 58c6b026ae503097b86f8c8f139912042fa3360a Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 15:23:11 +0900 Subject: [PATCH 2001/2686] Remove unused using --- osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs index 04dfe5f7c2..48ff45974d 100644 --- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs @@ -9,7 +9,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Online.API; using osu.Game.Online.Chat; -using osu.Game.Online.Notifications.WebSocket; using osu.Game.Overlays.Chat; using osu.Game.Tournament.IPC; using osu.Game.Tournament.Models; From db34f238c09597748ff5c9e6c22211d8b8346641 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 15:47:30 +0900 Subject: [PATCH 2002/2686] Fix inverted condition --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 54a1d69a9e..9812feb4a1 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -163,7 +163,7 @@ namespace osu.Game.Overlays.Notifications return; // Thread-safe barrier, as this may be called by a web request and also scheduled to the update thread at the same time. - if (Interlocked.Exchange(ref completionSent, 1) == 0) + if (Interlocked.Exchange(ref completionSent, 1) == 1) return; CompletionTarget.Invoke(CreateCompletionNotification()); From 695104a66666a46f5a1b9429694aa6071320dc62 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 16:59:03 +0900 Subject: [PATCH 2003/2686] Fix TestSceneChatOverlay messages not being unique --- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 6b2124f1f8..fd1bd4f0df 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -42,6 +42,7 @@ namespace osu.Game.Tests.Visual.Online private readonly APIUser testUser = new APIUser { Username = "test user", Id = 5071479 }; private Channel[] testChannels; + private Message[] initialMessages; private Channel testChannel1 => testChannels[0]; private Channel testChannel2 => testChannels[1]; @@ -49,10 +50,14 @@ namespace osu.Game.Tests.Visual.Online [Resolved] private OsuConfigManager config { get; set; } = null!; + private int currentMessageId; + [SetUp] public void SetUp() => Schedule(() => { + currentMessageId = 0; testChannels = Enumerable.Range(1, 10).Select(createPublicChannel).ToArray(); + initialMessages = testChannels.SelectMany(createChannelMessages).ToArray(); Child = new DependencyProvidingContainer { @@ -99,7 +104,7 @@ namespace osu.Game.Tests.Visual.Online return true; case GetMessagesRequest getMessages: - getMessages.TriggerSuccess(createChannelMessages(getMessages.Channel)); + getMessages.TriggerSuccess(initialMessages.ToList()); return true; case GetUserRequest getUser: @@ -546,7 +551,7 @@ namespace osu.Game.Tests.Visual.Online private List createChannelMessages(Channel channel) { - var message = new Message + var message = new Message(currentMessageId++) { ChannelId = channel.Id, Content = $"Hello, this is a message in {channel.Name}", From f688ed12d0b611a5955b817e127a3acd32fc6f98 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 17:00:47 +0900 Subject: [PATCH 2004/2686] Add test for removing chat messages --- .../Visual/Online/TestSceneChatOverlay.cs | 30 +++++++++++++++++++ osu.Game/Online/Chat/Channel.cs | 14 +++++++++ 2 files changed, 44 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index fd1bd4f0df..260b47e836 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -40,6 +40,7 @@ namespace osu.Game.Tests.Visual.Online private ChannelManager channelManager; private readonly APIUser testUser = new APIUser { Username = "test user", Id = 5071479 }; + private readonly APIUser testUser1 = new APIUser { Username = "test user", Id = 5071480 }; private Channel[] testChannels; private Message[] initialMessages; @@ -500,6 +501,35 @@ namespace osu.Game.Tests.Visual.Online waitForChannel1Visible(); } + [Test] + public void TestRemoveMessages() + { + AddStep("Show overlay with channel", () => + { + chatOverlay.Show(); + channelManager.CurrentChannel.Value = channelManager.JoinChannel(testChannel1); + }); + + AddAssert("Overlay is visible", () => chatOverlay.State.Value == Visibility.Visible); + waitForChannel1Visible(); + + AddStep("Send message from another user", () => + { + testChannel1.AddNewMessages(new Message + { + ChannelId = testChannel1.Id, + Content = "Message from another user", + Timestamp = DateTimeOffset.Now, + Sender = testUser1, + }); + }); + + AddStep("Remove messages from other user", () => + { + testChannel1.RemoveMessagesFromUser(testUser.Id); + }); + } + private void joinTestChannel(int i) { AddStep($"Join test channel {i}", () => channelManager.JoinChannel(testChannels[i])); diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index f51ea3e8d6..17a6a430b6 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -149,6 +149,20 @@ namespace osu.Game.Online.Chat NewMessagesArrived?.Invoke(messages); } + public void RemoveMessagesFromUser(int userId) + { + for (int i = 0; i < Messages.Count; i++) + { + var message = Messages[i]; + + if (message.SenderId == userId) + { + Messages.RemoveAt(i--); + MessageRemoved?.Invoke(message); + } + } + } + /// /// Replace or remove a message from the channel. /// From 063a8bdf9e3f12461a6201b33ae182be35a4a102 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 17:13:14 +0900 Subject: [PATCH 2005/2686] Remove messages from silenced users --- .../Chat/TestSceneChannelManager.cs | 29 ++++++++++++++++ .../Online/API/Requests/ChatAckRequest.cs | 6 ++++ .../API/Requests/Responses/ChatSilence.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 34 +++++++++++++++++-- 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index 86be638781..f559b0db73 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -23,6 +23,7 @@ namespace osu.Game.Tests.Chat private ChannelManager channelManager; private int currentMessageId; private List sentMessages; + private List silencedUserIds; [SetUp] public void Setup() => Schedule(() => @@ -39,6 +40,7 @@ namespace osu.Game.Tests.Chat { currentMessageId = 0; sentMessages = new List(); + silencedUserIds = new List(); ((DummyAPIAccess)API).HandleRequest = req => { @@ -55,6 +57,11 @@ namespace osu.Game.Tests.Chat case MarkChannelAsReadRequest markRead: handleMarkChannelAsReadRequest(markRead); return true; + + case ChatAckRequest ack: + ack.TriggerSuccess(new ChatAckResponse { Silences = silencedUserIds.Select(u => new ChatSilence { UserId = u }).ToList() }); + silencedUserIds.Clear(); + return true; } return false; @@ -106,6 +113,28 @@ namespace osu.Game.Tests.Chat AddAssert("channel's last read ID is set to the latest message", () => channel.LastReadId == sentMessages.Last().Id); } + [Test] + public void TestSilencedUsersAreRemoved() + { + Channel channel = null; + + AddStep("join channel and select it", () => + { + channelManager.JoinChannel(channel = createChannel(1, ChannelType.Public)); + channelManager.CurrentChannel.Value = channel; + }); + + AddStep("post message", () => channelManager.PostMessage("Definitely something bad")); + + AddStep("mark user as silenced and send ack request", () => + { + silencedUserIds.Add(API.LocalUser.Value.OnlineID); + channelManager.SendAck(); + }); + + AddAssert("channel has no more messages", () => channel.Messages, () => Is.Empty); + } + private void handlePostMessageRequest(PostMessageRequest request) { var message = new Message(++currentMessageId) diff --git a/osu.Game/Online/API/Requests/ChatAckRequest.cs b/osu.Game/Online/API/Requests/ChatAckRequest.cs index f09df4908e..78f51e21c0 100644 --- a/osu.Game/Online/API/Requests/ChatAckRequest.cs +++ b/osu.Game/Online/API/Requests/ChatAckRequest.cs @@ -9,10 +9,16 @@ namespace osu.Game.Online.API.Requests { public class ChatAckRequest : APIRequest { + public long SinceMessageId; + public uint? SinceSilenceId; + protected override WebRequest CreateWebRequest() { var req = base.CreateWebRequest(); req.Method = HttpMethod.Post; + req.AddParameter(@"since", SinceMessageId.ToString()); + if (SinceSilenceId != null) + req.AddParameter(@"history_since", SinceSilenceId.Value.ToString()); return req; } diff --git a/osu.Game/Online/API/Requests/Responses/ChatSilence.cs b/osu.Game/Online/API/Requests/Responses/ChatSilence.cs index 45fd6e1ba3..afb44e385e 100644 --- a/osu.Game/Online/API/Requests/Responses/ChatSilence.cs +++ b/osu.Game/Online/API/Requests/Responses/ChatSilence.cs @@ -12,6 +12,6 @@ namespace osu.Game.Online.API.Requests.Responses public uint Id { get; set; } [JsonProperty("user_id")] - public uint UserId { get; set; } + public int UserId { get; set; } } } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index a901c15bf4..b9a0aacf5a 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -74,6 +74,9 @@ namespace osu.Game.Online.Chat private bool channelsInitialised; private ScheduledDelegate ackDelegate; + private long lastMessageId; + private uint? lastSilenceId; + public ChannelManager(IAPIProvider api, NotificationsClientConnector connector) { this.api = api; @@ -106,8 +109,7 @@ namespace osu.Game.Online.Chat if (status.NewValue == APIState.Online) { - Scheduler.Add(ackDelegate = new ScheduledDelegate(() => api.Queue(new ChatAckRequest()), 0, 60000)); - // Todo: Handle silences. + Scheduler.Add(ackDelegate = new ScheduledDelegate(SendAck, 0, 60000)); } }, true); } @@ -342,6 +344,8 @@ namespace osu.Game.Online.Chat foreach (var group in messages.GroupBy(m => m.ChannelId)) channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); + + lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId; } private void initializeChannels() @@ -391,6 +395,32 @@ namespace osu.Game.Online.Chat api.Queue(fetchInitialMsgReq); } + /// + /// Sends an acknowledgement request to the API. + /// This marks the user as online to receive messages from public channels, while also returning a list of silenced users. + /// It needs to be called at least once every 10 minutes. + /// + public void SendAck() + { + var req = new ChatAckRequest + { + SinceMessageId = lastMessageId, + SinceSilenceId = lastSilenceId + }; + + req.Success += ack => + { + foreach (var silence in ack.Silences) + { + foreach (var channel in JoinedChannels) + channel.RemoveMessagesFromUser(silence.UserId); + lastSilenceId = Math.Max(lastSilenceId ?? 0, silence.Id); + } + }; + + api.Queue(req); + } + /// /// Find an existing channel instance for the provided channel. Lookup is performed basd on ID. /// The provided channel may be used if an existing instance is not found. From c66064872a18d1bd75cdcdde80fa4242f5054978 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 15:45:23 +0900 Subject: [PATCH 2006/2686] Fix `DrawableHit` test scene not showing rim hits correctly --- .../Skinning/TestSceneDrawableHit.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs index 8e9c487c2f..eb2b6c1d74 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs @@ -30,23 +30,24 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning Origin = Anchor.Centre, })); - AddStep("Rim hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime()) + AddStep("Rim hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(rim: true)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, })); - AddStep("Rim hit (strong)", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(true)) + AddStep("Rim hit (strong)", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime(true, true)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, })); } - private Hit createHitAtCurrentTime(bool strong = false) + private Hit createHitAtCurrentTime(bool strong = false, bool rim = false) { var hit = new Hit { + Type = rim ? HitType.Rim : HitType.Centre, IsStrong = strong, StartTime = Time.Current + 3000, }; From 0689d3845ff82fcae11f5e35e65f72b0e1e6be7a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 16:55:17 +0900 Subject: [PATCH 2007/2686] Fix `TestSceneHitExplosion` not maintaining aspect ratio --- .../Skinning/TestSceneHitExplosion.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs index f87e0355ad..0ddc607336 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.UI; +using osu.Game.Screens.Ranking; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { @@ -49,11 +50,19 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning // the hit needs to be added to hierarchy in order for nested objects to be created correctly. // setting zero alpha is supposed to prevent the test from looking broken. hit.With(h => h.Alpha = 0), - new HitExplosion(hit.Type) + + new AspectContainer { + RelativeSizeAxes = Axes.X, Anchor = Anchor.Centre, Origin = Anchor.Centre, - }.With(explosion => explosion.Apply(hit)) + Child = + new HitExplosion(hit.Type) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }.With(explosion => explosion.Apply(hit)) + } } }; } From 9c758e542505adc7e64049993d843e359c0c0410 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 17:00:39 +0900 Subject: [PATCH 2008/2686] Move `DefaultInputDrum` to correct location --- .../Skinning/Default/DefaultInputDrum.cs | 181 ++++++++++++++++++ osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 172 +---------------- 2 files changed, 182 insertions(+), 171 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs new file mode 100644 index 0000000000..fa60d209e7 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs @@ -0,0 +1,181 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Screens.Ranking; +using osuTK; + +namespace osu.Game.Rulesets.Taiko.Skinning.Default +{ + public class DefaultInputDrum : AspectContainer + { + public DefaultInputDrum() + { + RelativeSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load() + { + const float middle_split = 0.025f; + + InternalChild = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.9f), + Children = new[] + { + new TaikoHalfDrum(false) + { + Name = "Left Half", + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.X, + X = -middle_split / 2, + RimAction = TaikoAction.LeftRim, + CentreAction = TaikoAction.LeftCentre + }, + new TaikoHalfDrum(true) + { + Name = "Right Half", + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.X, + X = middle_split / 2, + RimAction = TaikoAction.RightRim, + CentreAction = TaikoAction.RightCentre + } + } + }; + } + + /// + /// A half-drum. Contains one centre and one rim hit. + /// + private class TaikoHalfDrum : Container, IKeyBindingHandler + { + /// + /// The key to be used for the rim of the half-drum. + /// + public TaikoAction RimAction; + + /// + /// The key to be used for the centre of the half-drum. + /// + public TaikoAction CentreAction; + + private readonly Sprite rim; + private readonly Sprite rimHit; + private readonly Sprite centre; + private readonly Sprite centreHit; + + public TaikoHalfDrum(bool flipped) + { + Masking = true; + + Children = new Drawable[] + { + rim = new Sprite + { + Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both + }, + rimHit = new Sprite + { + Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Blending = BlendingParameters.Additive, + }, + centre = new Sprite + { + Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.7f) + }, + centreHit = new Sprite + { + Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.7f), + Alpha = 0, + Blending = BlendingParameters.Additive + } + }; + } + + [BackgroundDependencyLoader] + private void load(TextureStore textures, OsuColour colours) + { + rim.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer"); + rimHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer-hit"); + centre.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner"); + centreHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner-hit"); + + rimHit.Colour = colours.Blue; + centreHit.Colour = colours.Pink; + } + + public bool OnPressed(KeyBindingPressEvent e) + { + Drawable target = null; + Drawable back = null; + + if (e.Action == CentreAction) + { + target = centreHit; + back = centre; + } + else if (e.Action == RimAction) + { + target = rimHit; + back = rim; + } + + if (target != null) + { + const float scale_amount = 0.05f; + const float alpha_amount = 0.5f; + + const float down_time = 40; + const float up_time = 1000; + + back.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint) + .Then() + .ScaleTo(1, up_time, Easing.OutQuint); + + target.Animate( + t => t.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint), + t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint) + ).Then( + t => t.ScaleTo(1, up_time, Easing.OutQuint), + t => t.FadeOut(up_time, Easing.OutQuint) + ); + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + } + } +} diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 054f98e18f..94e7138142 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -3,18 +3,11 @@ #nullable disable -using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Textures; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; -using osu.Game.Graphics; -using osu.Game.Screens.Ranking; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; -using osuTK; namespace osu.Game.Rulesets.Taiko.UI { @@ -23,8 +16,6 @@ namespace osu.Game.Rulesets.Taiko.UI /// internal class InputDrum : Container { - private const float middle_split = 0.025f; - public InputDrum() { AutoSizeAxes = Axes.X; @@ -43,166 +34,5 @@ namespace osu.Game.Rulesets.Taiko.UI }, }; } - - private class DefaultInputDrum : AspectContainer - { - public DefaultInputDrum() - { - RelativeSizeAxes = Axes.Y; - } - - [BackgroundDependencyLoader] - private void load() - { - InternalChild = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Scale = new Vector2(0.9f), - Children = new[] - { - new TaikoHalfDrum(false) - { - Name = "Left Half", - Anchor = Anchor.Centre, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.X, - X = -middle_split / 2, - RimAction = TaikoAction.LeftRim, - CentreAction = TaikoAction.LeftCentre - }, - new TaikoHalfDrum(true) - { - Name = "Right Half", - Anchor = Anchor.Centre, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.X, - X = middle_split / 2, - RimAction = TaikoAction.RightRim, - CentreAction = TaikoAction.RightCentre - } - } - }; - } - - /// - /// A half-drum. Contains one centre and one rim hit. - /// - private class TaikoHalfDrum : Container, IKeyBindingHandler - { - /// - /// The key to be used for the rim of the half-drum. - /// - public TaikoAction RimAction; - - /// - /// The key to be used for the centre of the half-drum. - /// - public TaikoAction CentreAction; - - private readonly Sprite rim; - private readonly Sprite rimHit; - private readonly Sprite centre; - private readonly Sprite centreHit; - - public TaikoHalfDrum(bool flipped) - { - Masking = true; - - Children = new Drawable[] - { - rim = new Sprite - { - Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both - }, - rimHit = new Sprite - { - Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Blending = BlendingParameters.Additive, - }, - centre = new Sprite - { - Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.7f) - }, - centreHit = new Sprite - { - Anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.7f), - Alpha = 0, - Blending = BlendingParameters.Additive - } - }; - } - - [BackgroundDependencyLoader] - private void load(TextureStore textures, OsuColour colours) - { - rim.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer"); - rimHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-outer-hit"); - centre.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner"); - centreHit.Texture = textures.Get(@"Gameplay/taiko/taiko-drum-inner-hit"); - - rimHit.Colour = colours.Blue; - centreHit.Colour = colours.Pink; - } - - public bool OnPressed(KeyBindingPressEvent e) - { - Drawable target = null; - Drawable back = null; - - if (e.Action == CentreAction) - { - target = centreHit; - back = centre; - } - else if (e.Action == RimAction) - { - target = rimHit; - back = rim; - } - - if (target != null) - { - const float scale_amount = 0.05f; - const float alpha_amount = 0.5f; - - const float down_time = 40; - const float up_time = 1000; - - back.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint) - .Then() - .ScaleTo(1, up_time, Easing.OutQuint); - - target.Animate( - t => t.ScaleTo(target.Scale.X - scale_amount, down_time, Easing.OutQuint), - t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint) - ).Then( - t => t.ScaleTo(1, up_time, Easing.OutQuint), - t => t.FadeOut(up_time, Easing.OutQuint) - ); - } - - return false; - } - - public void OnReleased(KeyBindingReleaseEvent e) - { - } - } - } } } From 2407eb063d4850f23d29b9fa9364722a7a84e744 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 16:51:55 +0900 Subject: [PATCH 2009/2686] Simplify `Circle` usage in default `CentreHitCirclePiece` --- .../Skinning/Default/CentreHitCirclePiece.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs index b91d5cfe8d..958f4b3a17 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs @@ -41,12 +41,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default Children = new[] { - new CircularContainer - { - RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new[] { new Box { RelativeSizeAxes = Axes.Both } } - } + new Circle { RelativeSizeAxes = Axes.Both } }; } } From 910dd3ad01ed44be94c0bc5503134b214e19bc08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 17:04:45 +0900 Subject: [PATCH 2010/2686] Move more default classes to correct namespace --- .../Default}/DefaultHitExplosion.cs | 14 ++++++-------- .../Default}/DefaultKiaiHitExplosion.cs | 6 ++---- osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 1 + osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs | 1 + 4 files changed, 10 insertions(+), 12 deletions(-) rename osu.Game.Rulesets.Taiko/{UI => Skinning/Default}/DefaultHitExplosion.cs (87%) rename osu.Game.Rulesets.Taiko/{UI => Skinning/Default}/DefaultKiaiHitExplosion.cs (96%) diff --git a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs similarity index 87% rename from osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs index 687c8f788f..58f45fda7c 100644 --- a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs @@ -1,9 +1,7 @@ +#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -12,19 +10,19 @@ using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.UI; using osuTK.Graphics; -namespace osu.Game.Rulesets.Taiko.UI +namespace osu.Game.Rulesets.Taiko.Skinning.Default { internal class DefaultHitExplosion : CircularContainer, IAnimatableHitExplosion { private readonly HitResult result; - [CanBeNull] - private Box body; + private Box? body; [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; public DefaultHitExplosion(HitResult result) { @@ -58,7 +56,7 @@ namespace osu.Game.Rulesets.Taiko.UI updateColour(); } - private void updateColour([CanBeNull] DrawableHitObject judgedObject = null) + private void updateColour(DrawableHitObject? judgedObject = null) { if (body == null) return; diff --git a/osu.Game.Rulesets.Taiko/UI/DefaultKiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultKiaiHitExplosion.cs similarity index 96% rename from osu.Game.Rulesets.Taiko/UI/DefaultKiaiHitExplosion.cs rename to osu.Game.Rulesets.Taiko/Skinning/Default/DefaultKiaiHitExplosion.cs index e91475d87b..ae68d63d97 100644 --- a/osu.Game.Rulesets.Taiko/UI/DefaultKiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultKiaiHitExplosion.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using osuTK; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -11,8 +8,9 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Rulesets.Taiko.Objects; +using osuTK; -namespace osu.Game.Rulesets.Taiko.UI +namespace osu.Game.Rulesets.Taiko.Skinning.Default { public class DefaultKiaiHitExplosion : CircularContainer { diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 046b3a6fd0..d8cdf50d75 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.UI diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index 319d8979ae..36d2e32984 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; using osuTK; From bc3382f373c83091d316b73c45cc9919952c68e9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 17:07:19 +0900 Subject: [PATCH 2011/2686] Apply NRT to many taiko classes --- .../Skinning/Default/ElongatedCirclePiece.cs | 2 -- .../Skinning/Default/RimHitCirclePiece.cs | 2 -- .../Skinning/Default/SwellSymbolPiece.cs | 2 -- .../Skinning/Default/TickPiece.cs | 2 -- .../Skinning/Legacy/LegacyBarLine.cs | 2 -- .../Skinning/Legacy/LegacyCirclePiece.cs | 6 ++---- .../Skinning/Legacy/LegacyDrumRoll.cs | 8 +++----- .../Skinning/Legacy/LegacyHit.cs | 2 -- .../Skinning/Legacy/LegacyHitExplosion.cs | 9 +++------ .../Skinning/Legacy/LegacyInputDrum.cs | 10 ++++------ .../Skinning/Legacy/LegacyTaikoScroller.cs | 8 +++----- .../Skinning/Legacy/TaikoLegacyHitTarget.cs | 4 +--- .../Legacy/TaikoLegacyPlayfieldBackgroundRight.cs | 4 +--- osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs | 2 -- osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs | 2 -- osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs | 2 -- .../UI/DrawableTaikoJudgement.cs | 2 -- osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs | 7 +++---- osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs | 2 -- .../UI/DrumSampleTriggerSource.cs | 2 -- osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 13 +++++-------- osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs | 2 -- .../UI/IAnimatableHitExplosion.cs | 2 -- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 2 -- osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs | 4 +--- .../UI/PlayfieldBackgroundLeft.cs | 2 -- .../UI/PlayfieldBackgroundRight.cs | 2 -- osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs | 2 -- osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs | 6 ++---- .../UI/TaikoMascotAnimationState.cs | 2 -- .../UI/TaikoPlayfieldAdjustmentContainer.cs | 2 -- osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs | 2 -- 32 files changed, 28 insertions(+), 93 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs index ba2679fe97..210841bca0 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs index 63269f1267..c6165495d8 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs index d19dc4c887..2f59cac3ff 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs index 7d3268f777..09c8243aac 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.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. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs index 97e0a340dd..2b528ae8ce 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs index 6bbeb0ed4c..6b2576a564 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; @@ -19,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class LegacyCirclePiece : CompositeDrawable, IHasAccentColour { - private Drawable backgroundLayer; + private Drawable backgroundLayer = null!; // required for editor blueprints (not sure why these circle pieces are zero size). public override Quad ScreenSpaceDrawQuad => backgroundLayer.ScreenSpaceDrawQuad; @@ -32,7 +30,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy [BackgroundDependencyLoader] private void load(ISkinSource skin, DrawableHitObject drawableHitObject) { - Drawable getDrawableFor(string lookup) + Drawable? getDrawableFor(string lookup) { const string normal_hit = "taikohit"; const string big_hit = "taikobig"; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs index 040d8ff965..1249231d92 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -28,11 +26,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } } - private LegacyCirclePiece headCircle; + private LegacyCirclePiece headCircle = null!; - private Sprite body; + private Sprite body = null!; - private Sprite tailCircle; + private Sprite tailCircle = null!; public LegacyDrumRoll() { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs index b4277f86bb..d93317f0e2 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.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. -#nullable disable - using osu.Framework.Allocation; using osu.Game.Skinning; using osuTK.Graphics; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs index 87ed2e2e60..ea45b69999 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs @@ -1,9 +1,7 @@ +#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; @@ -17,8 +15,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { private readonly Drawable sprite; - [CanBeNull] - private readonly Drawable strongSprite; + private readonly Drawable? strongSprite; /// /// Creates a new legacy hit explosion. @@ -29,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy /// /// The normal legacy explosion sprite. /// The strong legacy explosion sprite. - public LegacyHitExplosion(Drawable sprite, [CanBeNull] Drawable strongSprite = null) + public LegacyHitExplosion(Drawable sprite, Drawable? strongSprite = null) { this.sprite = sprite; this.strongSprite = strongSprite; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs index 101f70b97a..0abb365750 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -20,9 +18,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy /// internal class LegacyInputDrum : Container { - private Container content; - private LegacyHalfDrum left; - private LegacyHalfDrum right; + private Container content = null!; + private LegacyHalfDrum left = null!; + private LegacyHalfDrum right = null!; public LegacyInputDrum() { @@ -142,7 +140,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy public bool OnPressed(KeyBindingPressEvent e) { - Drawable target = null; + Drawable? target = null; if (e.Action == CentreAction) { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs index bd4a2f8935..4a2426bff5 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.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. -#nullable disable - using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -27,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } [BackgroundDependencyLoader(true)] - private void load(GameplayState gameplayState) + private void load(GameplayState? gameplayState) { if (gameplayState != null) ((IBindable)LastResult).BindTo(gameplayState.LastJudgementResult); @@ -91,8 +89,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private class ScrollerSprite : CompositeDrawable { - private Sprite passingSprite; - private Sprite failingSprite; + private Sprite passingSprite = null!; + private Sprite failingSprite = null!; private bool passing = true; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs index a48cdf47f6..21102f6eec 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class TaikoLegacyHitTarget : CompositeDrawable { - private Container content; + private Container content = null!; [BackgroundDependencyLoader] private void load(ISkinSource skin) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs index f425a410a4..3186f615a7 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Graphics; @@ -16,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { public class TaikoLegacyPlayfieldBackgroundRight : BeatSyncedContainer { - private Sprite kiai; + private Sprite kiai = null!; private bool kiaiDisplayed; diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs index 63314a6822..30bfb605aa 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponent.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. -#nullable disable - using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs index d231dc7e4f..bf48898dd2 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.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. -#nullable disable - namespace osu.Game.Rulesets.Taiko { public enum TaikoSkinComponents diff --git a/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs b/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs index 071808a044..cb878e8ea0 100644 --- a/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.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. -#nullable disable - using osu.Framework.Allocation; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects.Drawables; diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs index 264e4db54e..876fa207bf 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.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. -#nullable disable - using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs index 8bedca19d8..dd0b61cdf5 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.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. -#nullable disable - using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Audio.Track; @@ -24,7 +22,8 @@ namespace osu.Game.Rulesets.Taiko.UI public readonly Bindable LastResult; private readonly Dictionary animations; - private TaikoMascotAnimation currentAnimation; + + private TaikoMascotAnimation? currentAnimation; private bool lastObjectHit = true; private bool kiaiMode; @@ -40,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.UI } [BackgroundDependencyLoader(true)] - private void load(GameplayState gameplayState) + private void load(GameplayState? gameplayState) { InternalChildren = new[] { diff --git a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs index e0d5a3c680..ae37840825 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.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. -#nullable disable - using osu.Game.Rulesets.Taiko.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; diff --git a/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs b/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs index ef5bd1d7f0..3279d128d3 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.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. -#nullable disable - using System; using osu.Game.Audio; using osu.Game.Rulesets.Taiko.Objects; diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index d8cdf50d75..4836984eac 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -1,10 +1,8 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +#nullable enable +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; -using JetBrains.Annotations; using osuTK; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -30,10 +28,9 @@ namespace osu.Game.Rulesets.Taiko.UI private double? secondHitTime; - [CanBeNull] - public DrawableHitObject JudgedObject; + public DrawableHitObject? JudgedObject; - private SkinnableDrawable skinnable; + private SkinnableDrawable skinnable = null!; /// /// This constructor only exists to meet the new() type constraint of . @@ -63,7 +60,7 @@ namespace osu.Game.Rulesets.Taiko.UI skinnable.OnSkinChanged += runAnimation; } - public void Apply([CanBeNull] DrawableHitObject drawableHitObject) + public void Apply(DrawableHitObject? drawableHitObject) { JudgedObject = drawableHitObject; secondHitTime = null; diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs index 8707f7e840..badf34554c 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.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. -#nullable disable - using osu.Framework.Graphics.Pooling; using osu.Game.Rulesets.Scoring; diff --git a/osu.Game.Rulesets.Taiko/UI/IAnimatableHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/IAnimatableHitExplosion.cs index 6a9d43a0ab..cf0f5f9fb6 100644 --- a/osu.Game.Rulesets.Taiko/UI/IAnimatableHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/IAnimatableHitExplosion.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. -#nullable disable - using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Taiko.UI diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 94e7138142..6d5b6c5f5d 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index 36d2e32984..c4cff00d2a 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -23,7 +21,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly HitType hitType; - private SkinnableDrawable skinnable; + private SkinnableDrawable skinnable = null!; public override double LifetimeStart => skinnable.Drawable.LifetimeStart; diff --git a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs index db1094e100..2a8890a95d 100644 --- a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs +++ b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs index 43252e2e77..44bfdacf37 100644 --- a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs +++ b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs b/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs index f48ed2c941..6401c6d09f 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.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. -#nullable disable - using osuTK; using osuTK.Graphics; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs index 26a37fc464..de539b3cf0 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Audio.Track; @@ -120,7 +118,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(ISkinSource source) { - ISkin skin = source.FindProvider(s => getAnimationFrame(s, TaikoMascotAnimationState.Clear, 0) != null); + ISkin? skin = source.FindProvider(s => getAnimationFrame(s, TaikoMascotAnimationState.Clear, 0) != null); if (skin == null) return; @@ -137,7 +135,7 @@ namespace osu.Game.Rulesets.Taiko.UI } } - private static Texture getAnimationFrame(ISkin skin, TaikoMascotAnimationState state, int frameIndex) + private static Texture? getAnimationFrame(ISkin skin, TaikoMascotAnimationState state, int frameIndex) { var texture = skin.GetTexture($"pippidon{state.ToString().ToLowerInvariant()}{frameIndex}"); diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimationState.cs b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimationState.cs index 717f0d725a..02bf245b7b 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimationState.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimationState.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. -#nullable disable - namespace osu.Game.Rulesets.Taiko.UI { public enum TaikoMascotAnimationState diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs index 8e99a82b1b..9cf530e903 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.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. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs b/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs index a76adc495d..e6391d1386 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Taiko.Replays; From 5dfaf277229566c930d0cbedc9d970d0c2b3c507 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 17:23:45 +0900 Subject: [PATCH 2012/2686] A bit more cleanup --- osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs | 1 - osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs index ea45b69999..ff1546381b 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs @@ -1,4 +1,3 @@ -#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 4836984eac..10a7495c62 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -1,5 +1,4 @@ -#nullable enable -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; From bfa5d41d89a64ec1a559cc4d5cc5975563d95335 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 17:39:45 +0900 Subject: [PATCH 2013/2686] Fix one more case --- osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs index 58f45fda7c..b7ba76effa 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs @@ -1,4 +1,3 @@ -#nullable enable // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. From 4f8e912f063b08ed8be5afb2a513d8c804092685 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 17:53:19 +0900 Subject: [PATCH 2014/2686] Fix `APINotification` parsing failing --- osu.Game/Online/API/Requests/Responses/APINotification.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APINotification.cs b/osu.Game/Online/API/Requests/Responses/APINotification.cs index 2d9122c04b..de856c0333 100644 --- a/osu.Game/Online/API/Requests/Responses/APINotification.cs +++ b/osu.Game/Online/API/Requests/Responses/APINotification.cs @@ -2,8 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace osu.Game.Online.API.Requests.Responses { @@ -32,6 +32,6 @@ namespace osu.Game.Online.API.Requests.Responses public bool IsRead { get; set; } [JsonProperty(@"details")] - public Dictionary? Details { get; set; } + public JObject? Details { get; set; } } } From 0e502de8b473d9dda312bd4ddb590c7ce8dde1a5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 17:49:52 +0900 Subject: [PATCH 2015/2686] Rename field to match usage --- .../Visual/Editing/TestSceneEditorTestGameplay.cs | 4 ++-- osu.Game/Graphics/Containers/UserDimContainer.cs | 8 ++++---- osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs | 6 +++--- osu.Game/Screens/Edit/Editor.cs | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs index 9722c60cba..981967e413 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual.Editing // this test cares about checking the background belonging to the editor specifically, so check that using reference equality // (as `.Equals()` cannot discern between the two, as they technically share the same database GUID). var background = this.ChildrenOfType().Single(b => ReferenceEquals(b.Beatmap.BeatmapInfo, EditorBeatmap.BeatmapInfo)); - return background.DimAmount.Value == editorDim.Value && background.BlurAmount.Value == 0; + return background.DimWhenUserSettingsIgnored.Value == editorDim.Value && background.BlurAmount.Value == 0; }); AddAssert("no mods selected", () => SelectedMods.Value.Count == 0); } @@ -119,7 +119,7 @@ namespace osu.Game.Tests.Visual.Editing // this test cares about checking the background belonging to the editor specifically, so check that using reference equality // (as `.Equals()` cannot discern between the two, as they technically share the same database GUID). var background = this.ChildrenOfType().Single(b => ReferenceEquals(b.Beatmap.BeatmapInfo, EditorBeatmap.BeatmapInfo)); - return background.DimAmount.Value == editorDim.Value && background.BlurAmount.Value == 0; + return background.DimWhenUserSettingsIgnored.Value == editorDim.Value && background.BlurAmount.Value == 0; }); AddStep("start track", () => EditorClock.Start()); diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs index 62dd4e19b0..0b20159190 100644 --- a/osu.Game/Graphics/Containers/UserDimContainer.cs +++ b/osu.Game/Graphics/Containers/UserDimContainer.cs @@ -47,9 +47,9 @@ namespace osu.Game.Graphics.Containers protected Bindable UserDimLevel { get; private set; } = null!; /// - /// The amount of dim to be override if is true. + /// The amount of dim to be used when is true. /// - public Bindable DimAmount { get; set; } = new Bindable(); + public Bindable DimWhenUserSettingsIgnored { get; set; } = new Bindable(); protected Bindable LightenDuringBreaks { get; private set; } = null!; @@ -57,7 +57,7 @@ namespace osu.Game.Graphics.Containers private float breakLightening => LightenDuringBreaks.Value && IsBreakTime.Value ? BREAK_LIGHTEN_AMOUNT : 0; - protected float DimLevel => Math.Max(!IgnoreUserSettings.Value ? (float)UserDimLevel.Value - breakLightening : DimAmount.Value, 0); + protected float DimLevel => Math.Max(!IgnoreUserSettings.Value ? (float)UserDimLevel.Value - breakLightening : DimWhenUserSettingsIgnored.Value, 0); protected override Container Content => dimContent; @@ -79,7 +79,7 @@ namespace osu.Game.Graphics.Containers ShowStoryboard = config.GetBindable(OsuSetting.ShowStoryboard); UserDimLevel.ValueChanged += _ => UpdateVisuals(); - DimAmount.ValueChanged += _ => UpdateVisuals(); + DimWhenUserSettingsIgnored.ValueChanged += _ => UpdateVisuals(); LightenDuringBreaks.ValueChanged += _ => UpdateVisuals(); IsBreakTime.ValueChanged += _ => UpdateVisuals(); ShowStoryboard.ValueChanged += _ => UpdateVisuals(); diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs index 9f3e99d793..4d84a8194d 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs @@ -44,9 +44,9 @@ namespace osu.Game.Screens.Backgrounds public readonly Bindable BlurAmount = new BindableFloat(); /// - /// The amount of dim to be override if is true. + /// The amount of dim to be used when is true. /// - public readonly Bindable DimAmount = new Bindable(); + public readonly Bindable DimWhenUserSettingsIgnored = new Bindable(); internal readonly IBindable IsBreakTime = new Bindable(); @@ -63,7 +63,7 @@ namespace osu.Game.Screens.Backgrounds dimmable.IgnoreUserSettings.BindTo(IgnoreUserSettings); dimmable.IsBreakTime.BindTo(IsBreakTime); dimmable.BlurAmount.BindTo(BlurAmount); - dimmable.DimAmount.BindTo(DimAmount); + dimmable.DimWhenUserSettingsIgnored.BindTo(DimWhenUserSettingsIgnored); StoryboardReplacesBackground.BindTo(dimmable.StoryboardReplacesBackground); } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index bd0c4cfca4..990152471a 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -637,7 +637,7 @@ namespace osu.Game.Screens.Edit ApplyToBackground(b => { b.IgnoreUserSettings.Value = true; - b.DimAmount.Value = editorBackgroundDim.Value; + b.DimWhenUserSettingsIgnored.Value = editorBackgroundDim.Value; b.BlurAmount.Value = 0; }); } @@ -668,7 +668,7 @@ namespace osu.Game.Screens.Edit ApplyToBackground(b => { //b.DimAmount.UnbindAll(); - b.DimAmount.Value = 0; + b.DimWhenUserSettingsIgnored.Value = 0; }); resetTrack(); From 3ec9686e5858ad02070e3358eb971e62c449987b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 18:14:20 +0900 Subject: [PATCH 2016/2686] Fix test failures and rename configuration value to match better --- .../TestSceneLegacyBeatmapSkin.cs | 2 ++ .../Gameplay/TestSceneHitObjectAccentColour.cs | 14 +++++++++++++- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- .../Settings/Sections/Gameplay/BeatmapSettings.cs | 2 +- .../Objects/Drawables/DrawableHitObject.cs | 2 +- .../Screens/Play/PlayerSettings/VisualSettings.cs | 2 +- 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs index 1767d25e77..bb28b2b217 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs @@ -31,6 +31,8 @@ namespace osu.Game.Rulesets.Osu.Tests { config.BindWith(OsuSetting.BeatmapSkins, BeatmapSkins); config.BindWith(OsuSetting.BeatmapColours, BeatmapColours); + + config.SetValue(OsuSetting.ComboColourNormalisationAmount, 0f); } [TestCase(true, true)] diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs index 9701a32951..bc4c1d4cf2 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -13,6 +14,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Framework.Testing; using osu.Game.Audio; +using osu.Game.Configuration; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Objects.Types; @@ -25,10 +27,20 @@ namespace osu.Game.Tests.Gameplay [HeadlessTest] public class TestSceneHitObjectAccentColour : OsuTestScene { + [Resolved] + private OsuConfigManager config { get; set; } + private Container skinContainer; [SetUp] - public void Setup() => Schedule(() => Child = skinContainer = new SkinProvidingContainer(new TestSkin())); + public void Setup() + { + Schedule(() => + { + config.SetValue(OsuSetting.ComboColourNormalisationAmount, 0f); + Child = skinContainer = new SkinProvidingContainer(new TestSkin()); + }); + } [Test] public void TestChangeComboIndexBeforeLoad() diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 98776c7487..fdaad8cf70 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -175,7 +175,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.LastProcessedMetadataId, -1); - SetDefault(OsuSetting.ComboColourNormalisation, 0.2f, 0f, 1f, 0.01f); + SetDefault(OsuSetting.ComboColourNormalisationAmount, 0.2f, 0f, 1f, 0.01f); } protected override bool CheckLookupContainsPrivateInformation(OsuSetting lookup) @@ -367,6 +367,6 @@ namespace osu.Game.Configuration ShowOnlineExplicitContent, LastProcessedMetadataId, SafeAreaConsiderations, - ComboColourNormalisation, + ComboColourNormalisationAmount, } } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs index 8d64337eab..14ff6ac2b5 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - config.BindWith(OsuSetting.ComboColourNormalisation, comboColourNormalisation); + config.BindWith(OsuSetting.ComboColourNormalisationAmount, comboColourNormalisation); Children = new Drawable[] { diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 98fd73c8e9..f82a24ff01 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -175,7 +175,7 @@ namespace osu.Game.Rulesets.Objects.Drawables private void load(OsuConfigManager config, ISkinSource skinSource) { config.BindWith(OsuSetting.PositionalHitsoundsLevel, positionalHitsoundsLevel); - config.BindWith(OsuSetting.ComboColourNormalisation, comboColourBrightness); + config.BindWith(OsuSetting.ComboColourNormalisationAmount, comboColourBrightness); // Explicit non-virtual function call in case a DrawableHitObject overrides AddInternal. base.AddInternal(Samples = new PausableSkinnableSound()); diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index c837f61a09..6a7eabc6a2 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Play.PlayerSettings showStoryboardToggle.Current = config.GetBindable(OsuSetting.ShowStoryboard); beatmapSkinsToggle.Current = config.GetBindable(OsuSetting.BeatmapSkins); beatmapColorsToggle.Current = config.GetBindable(OsuSetting.BeatmapColours); - comboColourNormalisationSliderBar.Current = config.GetBindable(OsuSetting.ComboColourNormalisation); + comboColourNormalisationSliderBar.Current = config.GetBindable(OsuSetting.ComboColourNormalisationAmount); } } } From a44c7c751497d72eb33e4106a0b7baac184254a4 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Wed, 2 Nov 2022 19:56:35 +0900 Subject: [PATCH 2017/2686] range and precision for `EditorWaveformOpacity` --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index e9cfcd56c5..b832d1e310 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -172,7 +172,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full); - SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f); + SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f); SetDefault(OsuSetting.LastProcessedMetadataId, -1); } From 7073d8dd8e9f75f4756adf3fef7a9c6035db911c Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Wed, 2 Nov 2022 19:57:01 +0900 Subject: [PATCH 2018/2686] range and precision for `EditorDim` --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index b832d1e310..3c619d2ddd 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -121,7 +121,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1); SetDefault(OsuSetting.DimLevel, 0.7, 0, 1, 0.01); SetDefault(OsuSetting.BlurLevel, 0, 0, 1, 0.01); - SetDefault(OsuSetting.EditorDim, 0.25f); + SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 1f, 0.25f); SetDefault(OsuSetting.LightenDuringBreaks, true); SetDefault(OsuSetting.HitLighting, true); From ed7e3a29e2ab96234728f784ea7194d3f74ccdba Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:00:45 +0100 Subject: [PATCH 2019/2686] Add Localisation Also add Labels for what is displayed, and prefix/suffix for Labels Add a Prefix and Suffix for Values --- .../Components/BeatmapInfoDrawable.cs | 223 ++++++++++++++---- 1 file changed, 180 insertions(+), 43 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs index ae91d14830..4110086b2a 100644 --- a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs +++ b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs @@ -1,45 +1,80 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using System.Text; +using System; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Skinning.Components { [UsedImplicitly] - public class BeatmapInfoDrawable : Container, ISkinnableDrawable + public class BeatmapInfoDrawable : Container, ISkinnableDrawable, IHasTooltip { public bool UsesFixedAnchor { get; set; } [SettingSource("Tracked Beatmap Info", "Which part of the BeatmapInformation should be tracked")] public Bindable Type { get; } = new Bindable(BeatmapInfo.StarRating); + [SettingSource("Show Label", "Should a Label be shown, as to which status is currently Displayed?")] + public BindableBool ShowLabel { get; } = new BindableBool(true); + + [SettingSource("Show Value first?", "Should the Value be shown first?")] + public BindableBool ValueBeforeLabel { get; } = new BindableBool(); + + [SettingSource("Label Prefix", "Add something to be shown before the label")] + public Bindable LabelPrefix { get; set; } = new Bindable(""); + + [SettingSource("Show Label Prefix", "Should the Label Prefix be included?")] + public BindableBool ShowLabelPrefix { get; } = new BindableBool(); + + [SettingSource("Label Suffix", "Add something to be shown after the label")] + public Bindable LabelSuffix { get; set; } = new Bindable(": "); + + [SettingSource("Show Label Suffix", "Should the Label Suffix be included?")] + public BindableBool ShowLabelSuffix { get; } = new BindableBool(true); + + [SettingSource("Value Prefix", "Add something to be shown before the Value")] + public Bindable ValuePrefix { get; set; } = new Bindable(""); + + [SettingSource("Show Value Prefix", "Should the Value Prefix be included?")] + public BindableBool ShowValuePrefix { get; } = new BindableBool(); + + [SettingSource("Value Suffix", "Add something to be shown after the Value")] + public Bindable ValueSuffix { get; set; } = new Bindable(""); + + [SettingSource("Show Value Suffix", "Should the Value Suffix be included?")] + public BindableBool ShowValueSuffix { get; } = new BindableBool(); + [Resolved] - private IBindable beatmap { get; set; } + private IBindable beatmap { get; set; } = null!; private readonly OsuSpriteText text; + public LocalisableString TooltipText { get; set; } + private LocalisableString value; + private LocalisableString labelText; + public BeatmapInfoDrawable() { - AutoSizeAxes = Axes.Both; - InternalChildren = new Drawable[] { text = new OsuSpriteText { Text = "BeatInfoDrawable", - Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, Font = OsuFont.Default.With(size: 40) } }; @@ -49,6 +84,45 @@ namespace osu.Game.Skinning.Components { base.LoadComplete(); Type.BindValueChanged(update, true); + ShowLabel.BindValueChanged(ignored => updateLabel()); + ValueBeforeLabel.BindValueChanged(ignored => updateLabel()); + LabelPrefix.BindValueChanged(ignored => updateLabel()); + ShowLabelPrefix.BindValueChanged(ignored => updateLabel()); + LabelSuffix.BindValueChanged(ignored => updateLabel()); + ShowLabelSuffix.BindValueChanged(ignored => updateLabel()); + ValuePrefix.BindValueChanged(ignored => updateLabel()); + ShowValuePrefix.BindValueChanged(ignored => updateLabel()); + ValueSuffix.BindValueChanged(ignored => updateLabel()); + ShowValueSuffix.BindValueChanged(ignored => updateLabel()); + } + + private LocalisableString getLabelText() + { + if (!ShowLabel.Value) return new LocalisableString(""); + + return LocalisableString.Format("{0}{1}{2}", + ShowLabelPrefix.Value ? LabelPrefix.Value : "", + labelText, + ShowLabelSuffix.Value ? LabelSuffix.Value : ""); + } + + private LocalisableString getValueText() + { + return LocalisableString.Format("{0}{1}{2}", + ShowValuePrefix.Value ? ValuePrefix.Value : "", + value, + ShowValueSuffix.Value ? ValueSuffix.Value : ""); + } + + private void updateLabel() + { + text.Text = LocalisableString.Format( + ValueBeforeLabel.Value ? "{1}{0}" : "{0}{1}", + getLabelText(), + getValueText() + ); + Width = text.Width; + Height = text.Height; } private void update(ValueChangedEvent type) @@ -58,105 +132,167 @@ namespace osu.Game.Skinning.Components case BeatmapInfo.CircleSize: beatmap.BindValueChanged(bm => { - text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.CircleSize.ToString("F2"); + double cs = bm.NewValue.BeatmapInfo.Difficulty.CircleSize; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsCs; + value = cs.ToString("F2"); + updateLabel(); }, true); break; case BeatmapInfo.HPDrain: beatmap.BindValueChanged(bm => { - text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.DrainRate.ToString("F2"); + double hp = bm.NewValue.BeatmapInfo.Difficulty.DrainRate; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsDrain; + value = hp.ToString("F2"); + updateLabel(); }, true); break; case BeatmapInfo.Accuracy: beatmap.BindValueChanged(bm => { - text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.OverallDifficulty.ToString("F2"); + double od = bm.NewValue.BeatmapInfo.Difficulty.OverallDifficulty; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsAccuracy; + value = od.ToString("F2"); + updateLabel(); }, true); break; case BeatmapInfo.ApproachRate: beatmap.BindValueChanged(bm => { - text.Current.Value = bm.NewValue.BeatmapInfo.Difficulty.ApproachRate.ToString("F2"); + double ar = bm.NewValue.BeatmapInfo.Difficulty.ApproachRate; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsAr; + value = ar.ToString("F2"); + updateLabel(); }, true); break; case BeatmapInfo.StarRating: beatmap.BindValueChanged(bm => { - text.Current.Value = bm.NewValue.BeatmapInfo.StarRating.ToString("F2"); + double sr = bm.NewValue.BeatmapInfo.StarRating; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsStars; + value = sr.ToString("F2"); + updateLabel(); }, true); break; case BeatmapInfo.Song: beatmap.BindValueChanged(bm => { - text.Current.Value = bm.NewValue.BeatmapInfo.Metadata.Title; + string title = bm.NewValue.BeatmapInfo.Metadata.Title; + //todo: no Song Title localisation? + labelText = TooltipText = "Song Title"; + value = title; + updateLabel(); }, true); break; case BeatmapInfo.Artist: beatmap.BindValueChanged(bm => { - text.Current.Value = bm.NewValue.BeatmapInfo.Metadata.Artist; + string artist = bm.NewValue.BeatmapInfo.Metadata.Artist; + //todo: Localize Artist + labelText = "Artist"; + TooltipText = BeatmapsetsStrings.ShowDetailsByArtist(artist); + value = artist; + updateLabel(); }, true); break; case BeatmapInfo.Difficulty: beatmap.BindValueChanged(bm => { - text.Current.Value = bm.NewValue.BeatmapInfo.DifficultyName; + string diff = bm.NewValue.BeatmapInfo.DifficultyName; + //todo: no Difficulty name localisation? + labelText = TooltipText = "Difficulty"; + text.Current.Value = diff; + updateLabel(); }, true); break; case BeatmapInfo.Mapper: beatmap.BindValueChanged(bm => { - text.Current.Value = bm.NewValue.BeatmapInfo.Metadata.Author.Username; + string mapper = bm.NewValue.BeatmapInfo.Metadata.Author.Username; + //todo: is there a good alternative, to ShowDetailsMappedBy? + labelText = "Mapper"; + TooltipText = BeatmapsetsStrings.ShowDetailsMappedBy(mapper); + value = mapper; + updateLabel(); }, true); break; case BeatmapInfo.Length: beatmap.BindValueChanged(bm => { - const long ms_to_s = 1000; - double length = bm.NewValue.BeatmapInfo.Length; - double rawS = length / ms_to_s; - double rawM = rawS / 60; - double rawH = rawM / 60; - double rawD = rawH / 24; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsTotalLength(TimeSpan.FromMilliseconds(bm.NewValue.BeatmapInfo.Length).ToFormattedDuration()); + value = TimeSpan.FromMilliseconds(bm.NewValue.BeatmapInfo.Length).ToFormattedDuration(); + updateLabel(); + }, true); + break; - long s = (long)rawS % 60; - long m = (long)rawM % 60; - long h = (long)rawH % 24; - long d = (long)rawD; - StringBuilder builder = new StringBuilder(); + case BeatmapInfo.Status: + beatmap.BindValueChanged(bm => + { + BeatmapOnlineStatus status = bm.NewValue.BeatmapInfo.Status; + //todo: no Localizasion for None Beatmap Online Status + //todo: no Localization for Status? + labelText = "Status"; - if (d != 0) + switch (status) { - builder.Append(d.ToString("D2")); - builder.Append(":"); + case BeatmapOnlineStatus.Approved: + value = BeatmapsetsStrings.ShowStatusApproved; + //todo: is this correct? + TooltipText = BeatmapsetsStrings.ShowDetailsDateApproved(bm.NewValue.BeatmapSetInfo.DateRanked.ToString()); + break; + + case BeatmapOnlineStatus.Graveyard: + value = BeatmapsetsStrings.ShowStatusGraveyard; + break; + + case BeatmapOnlineStatus.Loved: + value = BeatmapsetsStrings.ShowStatusLoved; + break; + + case BeatmapOnlineStatus.None: + value = "None"; + break; + + case BeatmapOnlineStatus.Pending: + value = BeatmapsetsStrings.ShowStatusPending; + break; + + case BeatmapOnlineStatus.Qualified: + value = BeatmapsetsStrings.ShowStatusQualified; + break; + + case BeatmapOnlineStatus.Ranked: + value = BeatmapsetsStrings.ShowStatusRanked; + break; + + case BeatmapOnlineStatus.LocallyModified: + value = SongSelectStrings.LocallyModified; + break; + + case BeatmapOnlineStatus.WIP: + value = BeatmapsetsStrings.ShowStatusWip; + break; } - if (h != 0 || d != 0) - { - builder.Append(h.ToString("D2")); - builder.Append(":"); - } - - builder.Append(m.ToString("D2")); - builder.Append(":"); - builder.Append(s.ToString("D2")); - text.Current.Value = builder.ToString(); + updateLabel(); }, true); break; case BeatmapInfo.BPM: beatmap.BindValueChanged(bm => { - text.Current.Value = bm.NewValue.BeatmapInfo.BPM.ToString("F2"); + labelText = TooltipText = BeatmapsetsStrings.ShowStatsBpm; + value = bm.NewValue.BeatmapInfo.BPM.ToString("F2"); + updateLabel(); }, true); break; } @@ -175,6 +311,7 @@ namespace osu.Game.Skinning.Components Difficulty, Mapper, Length, + Status, BPM, } } From 2e5db5e25983d9d074c695c4f27020e6f31dfb83 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:24:05 +0100 Subject: [PATCH 2020/2686] Remove nullable disable from TextElement --- osu.Game/Skinning/Components/TextElement.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Skinning/Components/TextElement.cs b/osu.Game/Skinning/Components/TextElement.cs index e29ab6de58..da09aa76b2 100644 --- a/osu.Game/Skinning/Components/TextElement.cs +++ b/osu.Game/Skinning/Components/TextElement.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. -#nullable disable - using JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Graphics; From 95e2521ca46cea560e88d26c1e82f47483e8798b Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:56:55 +0100 Subject: [PATCH 2021/2686] Use more Localisations --- .../Skinning/Components/BeatmapInfoDrawable.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs index 4110086b2a..44c3914d2c 100644 --- a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs +++ b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs @@ -184,7 +184,7 @@ namespace osu.Game.Skinning.Components { string title = bm.NewValue.BeatmapInfo.Metadata.Title; //todo: no Song Title localisation? - labelText = TooltipText = "Song Title"; + labelText = TooltipText = EditorSetupStrings.Title; value = title; updateLabel(); }, true); @@ -194,8 +194,7 @@ namespace osu.Game.Skinning.Components beatmap.BindValueChanged(bm => { string artist = bm.NewValue.BeatmapInfo.Metadata.Artist; - //todo: Localize Artist - labelText = "Artist"; + labelText = EditorSetupStrings.Artist; TooltipText = BeatmapsetsStrings.ShowDetailsByArtist(artist); value = artist; updateLabel(); @@ -206,8 +205,7 @@ namespace osu.Game.Skinning.Components beatmap.BindValueChanged(bm => { string diff = bm.NewValue.BeatmapInfo.DifficultyName; - //todo: no Difficulty name localisation? - labelText = TooltipText = "Difficulty"; + labelText = TooltipText = EditorSetupStrings.DifficultyHeader; text.Current.Value = diff; updateLabel(); }, true); @@ -218,7 +216,7 @@ namespace osu.Game.Skinning.Components { string mapper = bm.NewValue.BeatmapInfo.Metadata.Author.Username; //todo: is there a good alternative, to ShowDetailsMappedBy? - labelText = "Mapper"; + labelText = AccountsStrings.NotificationsOptionsMapping; TooltipText = BeatmapsetsStrings.ShowDetailsMappedBy(mapper); value = mapper; updateLabel(); @@ -228,7 +226,7 @@ namespace osu.Game.Skinning.Components case BeatmapInfo.Length: beatmap.BindValueChanged(bm => { - labelText = TooltipText = BeatmapsetsStrings.ShowStatsTotalLength(TimeSpan.FromMilliseconds(bm.NewValue.BeatmapInfo.Length).ToFormattedDuration()); + labelText = TooltipText = ArtistStrings.TracklistLength; value = TimeSpan.FromMilliseconds(bm.NewValue.BeatmapInfo.Length).ToFormattedDuration(); updateLabel(); }, true); @@ -239,8 +237,7 @@ namespace osu.Game.Skinning.Components { BeatmapOnlineStatus status = bm.NewValue.BeatmapInfo.Status; //todo: no Localizasion for None Beatmap Online Status - //todo: no Localization for Status? - labelText = "Status"; + labelText = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault; switch (status) { From 75b5025e123f5716b6b0aff6aebe7ef8667553ee Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 2 Nov 2022 16:37:48 +0100 Subject: [PATCH 2022/2686] Fix Skin Deserialisation Test --- .../Archives/modified-default-20221102.osk | Bin 0 -> 1534 bytes osu.Game.Tests/Skins/SkinDeserialisationTest.cs | 4 +++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Resources/Archives/modified-default-20221102.osk diff --git a/osu.Game.Tests/Resources/Archives/modified-default-20221102.osk b/osu.Game.Tests/Resources/Archives/modified-default-20221102.osk new file mode 100644 index 0000000000000000000000000000000000000000..3ec328db4e8212e2cb709865362b24f83951b93e GIT binary patch literal 1534 zcmWIWW@Zs#U|`^2NN-6B{k=AO?o1$WGgyRyp*TA;PcJhsQ}v7?Uz3A?!^L?i?+t<+ zla2&jio6+_nX1E<*3i4#IPE6y!yGZWliC~`|LOn#{Vzl`#=R|W?&X`O80LDVbQ(Nn znX#yx+1rz4%;f*Sr?uTAxyVI%L+HDUVhxY@BW5nr?WLKLEw~Gv4vZmjIpK z1H`;Q403*EURu6hR&jpb>Ss@b0s=mHpYaXd6clhuUoSMIBhX97>-_odz@Q5TMg~Tg zLN1&*>wnVcw2$w_kV}l(<$7MeIw$p+UUHm0eeSgW`DU+*XQI}d?VI+U#a$tj}*2ki&Obn>bd;h|Bkv}5?LpU=713%Dt z!TEXV!Kpc^$t7S1?wuH$eaJwf^*!r<=WE_87slTzdvNqxt--MwXLd<{RJs<_k*Cm#O61*4n}CKI$QjBky+}4dvo?E9ALgL{iCd#pKZ5a%i#m^JlemmzSzU* zn>F{6i?6z5Vu9M*ZOpwIWqwccDz*t;iaE+#Ikm*syV5-8LP%rPg6fEEm$eUxY&q?i zExc6g`}RX8+cqt23Cb|jk1YMX+$reB>uR>0mVcZD|1z*|e9!){Fs)Yq$l-;;t{+)_ zD=a=GtCuWJe#_;4FMsKl&*IxI>0MR3X!LFROBL6>XIi$rUD$G}r*YRNznnSYH{PDv z&xjiK)eZ7#FMwfR1`K#HVA%U6X6AW>x;W?O7Ubup=9LtKqu}lI*zDT|B5m)v|MII{ zUpK-2QNN?!ttHXNB#gax&A!Ba)Yj7_Ra54qPU4&W;d!#tkD6<1mc2-8c3j_gU-?VH zo5i<38z27}YAcg&a6dQU!$C=n*h&6t7>rH}I%G}a+@^eaHs{O(lcpZ(3Edcw9O}jV z!s>Uy^`DF@c1}|EnwNK7^7aFvM3sdmCt6;oJazi;hx^U5SBy_QraAH4v8r8WV*agk zcT1IP*qvJw#jB1ipVF46{C3S%C>i4mS7sdL-U)uL=KT!B_ z)h7=BUU#+~ArS^MotNz}*>(JyrqrY>aUbn3+u0UquI1j?-rhSYp?rP}qcQ94nrYsq zj^8HhvXm6gSzzb+cj5D`yOyU&{H&{B5%fxWrMmC=@%GT~OMWMQ`ELLD-^VkF+3Q$E z$}TWYvrzM#p?18aC Ghz9_U=60t5 literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 989459632e..4ecf307d68 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -40,7 +40,9 @@ namespace osu.Game.Tests.Skins // Covers clicks/s counter "Archives/modified-default-20220818.osk", // Covers longest combo counter - "Archives/modified-default-20221012.osk" + "Archives/modified-default-20221012.osk", + // Covers TextElement and BeatmapInfoDrawable + "Archives/modified-default-20221102.osk" }; /// From 993439d30b173a5bdac0e22fea97c0e97bcb09a7 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 3 Nov 2022 11:28:39 +0900 Subject: [PATCH 2023/2686] Fix missed nullability --- osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs index de539b3cf0..0f214b8436 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load(ISkinSource source) { - ISkin skin = source.FindProvider(s => getAnimationFrame(s, state, 0) != null); + ISkin? skin = source.FindProvider(s => getAnimationFrame(s, state, 0) != null); if (skin == null) return; From ec4ac77f14cbf6f85281c7e634a329efafa1b92a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 13:27:54 +0900 Subject: [PATCH 2024/2686] Increase the maximum seed range for tournament client --- osu.Game.Tournament/Models/SeedingBeatmap.cs | 2 +- osu.Game.Tournament/Models/SeedingResult.cs | 2 +- osu.Game.Tournament/Models/TournamentTeam.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tournament/Models/SeedingBeatmap.cs b/osu.Game.Tournament/Models/SeedingBeatmap.cs index fb0e20556c..0ac312342c 100644 --- a/osu.Game.Tournament/Models/SeedingBeatmap.cs +++ b/osu.Game.Tournament/Models/SeedingBeatmap.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tournament.Models public Bindable Seed = new BindableInt { MinValue = 1, - MaxValue = 64 + MaxValue = 256 }; } } diff --git a/osu.Game.Tournament/Models/SeedingResult.cs b/osu.Game.Tournament/Models/SeedingResult.cs index 71e52b3324..2a404153e6 100644 --- a/osu.Game.Tournament/Models/SeedingResult.cs +++ b/osu.Game.Tournament/Models/SeedingResult.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tournament.Models public Bindable Seed = new BindableInt { MinValue = 1, - MaxValue = 64 + MaxValue = 256 }; } } diff --git a/osu.Game.Tournament/Models/TournamentTeam.cs b/osu.Game.Tournament/Models/TournamentTeam.cs index ac57f748da..1beea517d5 100644 --- a/osu.Game.Tournament/Models/TournamentTeam.cs +++ b/osu.Game.Tournament/Models/TournamentTeam.cs @@ -54,7 +54,7 @@ namespace osu.Game.Tournament.Models public Bindable LastYearPlacing = new BindableInt { MinValue = 1, - MaxValue = 64 + MaxValue = 256 }; [JsonProperty] From aef3c7918c98d3acd7cdb4bdba9e5bc0e9551054 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 12:14:37 +0900 Subject: [PATCH 2025/2686] Add total skip count to `SkipOverlay` --- .../Visual/Gameplay/TestSceneSkipOverlay.cs | 7 +++++-- osu.Game/Screens/Play/SkipOverlay.cs | 11 ++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs index 6b02449aa3..4b564f704a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs @@ -137,8 +137,11 @@ namespace osu.Game.Tests.Visual.Gameplay checkRequestCount(0); } - private void checkRequestCount(int expected) => - AddAssert($"request count is {expected}", () => requestCount == expected); + private void checkRequestCount(int expected) + { + AddAssert($"skip count is {expected}", () => skip.SkipCount, () => Is.EqualTo(expected)); + AddAssert($"request count is {expected}", () => requestCount, () => Is.EqualTo(expected)); + } private class TestSkipOverlay : SkipOverlay { diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 974d40b538..ee05fce730 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -27,6 +27,11 @@ namespace osu.Game.Screens.Play { public class SkipOverlay : CompositeDrawable, IKeyBindingHandler { + /// + /// The total number of successful skips performed by this overlay. + /// + public int SkipCount { get; private set; } + private readonly double startTime; public Action RequestSkip; @@ -124,7 +129,11 @@ namespace osu.Game.Screens.Play return; } - button.Action = () => RequestSkip?.Invoke(); + button.Action = () => + { + SkipCount++; + RequestSkip?.Invoke(); + }; fadeContainer.TriggerShow(); From 5f2f6b84b2febc80fdc166c89011c7175bba3818 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 12:27:37 +0900 Subject: [PATCH 2026/2686] Add failing test coverage of automated skip scenarios --- .../Visual/Gameplay/TestSceneSkipOverlay.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs index 4b564f704a..1bba62a5cf 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs @@ -93,6 +93,15 @@ namespace osu.Game.Tests.Visual.Gameplay checkRequestCount(1); } + [Test] + public void TestAutomaticSkipActuatesOnce() + { + createTest(); + AddStep("start automated skip", () => skip.SkipWhenReady()); + AddUntilStep("wait for button disabled", () => !skip.IsButtonVisible); + checkRequestCount(1); + } + [Test] public void TestClickOnlyActuatesOnce() { @@ -110,6 +119,16 @@ namespace osu.Game.Tests.Visual.Gameplay checkRequestCount(1); } + [Test] + public void TestAutomaticSkipActuatesMultipleTimes() + { + createTest(); + AddStep("set increment lower", () => increment = 3000); + AddStep("start automated skip", () => skip.SkipWhenReady()); + AddUntilStep("wait for button disabled", () => !skip.IsButtonVisible); + checkRequestCount(2); + } + [Test] public void TestClickOnlyActuatesMultipleTimes() { From 4154be6cdaccb5cf40f1a95b79d1ab226ddc5dd5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 12:05:00 +0900 Subject: [PATCH 2027/2686] Adjust auto-skip to skip multiple times if necessary --- osu.Game/Screens/Play/SkipOverlay.cs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index ee05fce730..99fe659bf3 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -136,20 +136,29 @@ namespace osu.Game.Screens.Play }; fadeContainer.TriggerShow(); - - if (skipQueued) - { - Scheduler.AddDelayed(() => button.TriggerClick(), 200); - skipQueued = false; - } } + /// + /// Triggers an "automated" skip to happen as soon as available. + /// public void SkipWhenReady() { - if (IsLoaded) + if (skipQueued) return; + + skipQueued = true; + attemptNextSkip(); + + void attemptNextSkip() => Scheduler.AddDelayed(() => + { + if (!button.Enabled.Value) + { + skipQueued = false; + return; + } + button.TriggerClick(); - else - skipQueued = true; + attemptNextSkip(); + }, 200); } protected override void Update() From df9f49eef21a46431f2752b29f20a1434392bfdf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 13:56:06 +0900 Subject: [PATCH 2028/2686] Move hover layer behind icon Looked bad on the "already downloaded" state where the icon becomes black. --- .../Drawables/Cards/Buttons/BeatmapCardIconButton.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs index a4beab02ed..6b9b67123e 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -78,17 +78,17 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons Anchor = Anchor.Centre, Children = new Drawable[] { - Icon = new SpriteIcon - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - }, hover = new Box { RelativeSizeAxes = Axes.Both, Colour = Color4.White.Opacity(0.1f), Blending = BlendingParameters.Additive, }, + Icon = new SpriteIcon + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + }, } }); From fc191807c6ea44659158d32476e5100058940837 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 3 Nov 2022 13:59:22 +0900 Subject: [PATCH 2029/2686] Fix velocity test failing with no audio device --- .../Timelines/Summary/Parts/TimelinePart.cs | 14 ++++++-------- osu.Game/Screens/Edit/EditorClock.cs | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs index 54914f4b23..bb5b4a6cea 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs @@ -57,15 +57,13 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts private void updateRelativeChildSize() { - // the track may not be loaded completely (only has a length once it is). - if (!beatmap.Value.Track.IsLoaded) - { - content.RelativeChildSize = Vector2.One; - Schedule(updateRelativeChildSize); - return; - } + // If the track is not loaded, assign a default sane length otherwise relative positioning becomes meaningless. + double trackLength = beatmap.Value.Track.IsLoaded ? beatmap.Value.Track.Length : 60000; + content.RelativeChildSize = new Vector2((float)Math.Max(1, trackLength), 1); - content.RelativeChildSize = new Vector2((float)Math.Max(1, beatmap.Value.Track.Length), 1); + // The track may not be loaded completely (only has a length once it is). + if (!beatmap.Value.Track.IsLoaded) + Schedule(updateRelativeChildSize); } protected virtual void LoadBeatmap(EditorBeatmap beatmap) diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index 6485f683ad..81d82130da 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Edit private readonly Bindable track = new Bindable(); - public double TrackLength => track.Value?.Length ?? 60000; + public double TrackLength => track.Value?.IsLoaded == true ? track.Value.Length : 60000; public ControlPointInfo ControlPointInfo => Beatmap.ControlPointInfo; From 66a6084d3f6a93e4e10a61ea0625a9f457b51a48 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 14:03:19 +0900 Subject: [PATCH 2030/2686] Scale in the background fill alongside the icon --- .../Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs index 6b9b67123e..af1a8eb06a 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -74,6 +74,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons RelativeSizeAxes = Axes.Both, Masking = true, CornerRadius = BeatmapCard.CORNER_RADIUS, + Scale = new Vector2(0.8f), Origin = Anchor.Centre, Anchor = Anchor.Centre, Children = new Drawable[] @@ -88,6 +89,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { Origin = Anchor.Centre, Anchor = Anchor.Centre, + Scale = new Vector2(1.2f), }, } }); @@ -127,7 +129,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons bool isHovered = IsHovered && Enabled.Value; hover.FadeTo(isHovered ? 1f : 0f, 500, Easing.OutQuint); - Icon.ScaleTo(isHovered ? 1.2f : 1, 500, Easing.OutQuint); + content.ScaleTo(isHovered ? 1 : 0.8f, 500, Easing.OutQuint); Icon.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint); } } From 07bfac40faaccdd47bbd4b96eaaa4d6789d1733c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 14:03:28 +0900 Subject: [PATCH 2031/2686] Adjust padding to avoid overlap with card border when expanded --- .../Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs index f70694bdda..9b200d62aa 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs @@ -95,7 +95,9 @@ namespace osu.Game.Beatmaps.Drawables.Cards Child = buttons = new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(3), + // Padding of 4 avoids touching the card borders when in the expanded (ie. showing difficulties) state. + // Left override allows the buttons to visually be wider and look better. + Padding = new MarginPadding(4) { Left = 2 }, Children = new BeatmapCardIconButton[] { new FavouriteButton(beatmapSet) From 62660ec92fe12dd64c42de6e7d3831e3169064eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 14:21:22 +0900 Subject: [PATCH 2032/2686] Reorganise drawables and transforms to make more sequential sense --- .../Skinning/Argon/ArgonSpinnerDisc.cs | 83 +++++++++---------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs index 3b418fcb2d..b2c804a2da 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -98,28 +98,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon AlwaysPresent = true, } }, - new Container - { - Name = @"Ring", - Masking = true, - RelativeSizeAxes = Axes.Both, - Children = new[] - { - new ArgonSpinnerRingArc - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Name = "Top Arc", - }, - new ArgonSpinnerRingArc - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Name = "Bottom Arc", - Scale = new Vector2(1, -1), - }, - } - }, ticksContainer = new Container { Anchor = Anchor.Centre, @@ -130,6 +108,29 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon }, }, new Container + { + Name = @"Ring", + Masking = true, + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(8f), + Children = new[] + { + new ArgonSpinnerRingArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Top Arc", + }, + new ArgonSpinnerRingArc + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Name = "Bottom Arc", + Scale = new Vector2(1, -1), + }, + } + }, + new Container { Name = @"Sides", RelativeSizeAxes = Axes.Both, @@ -226,6 +227,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { this.ScaleTo(initial_scale); ticksContainer.RotateTo(0); + centre.ScaleTo(0); + disc.ScaleTo(0); using (BeginDelayedSequence(spinner.TimePreempt / 2)) { @@ -233,27 +236,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon ticksContainer.RotateTo((float)(25 * spinner.Duration / 2000), spinner.TimePreempt + spinner.Duration); } - using (BeginDelayedSequence(spinner.TimePreempt + spinner.Duration + drawableHitObject.Result.TimeOffset)) - { - switch (state) - { - case ArmedState.Hit: - this.ScaleTo(initial_scale * 1.2f, 320, Easing.Out); - ticksContainer.RotateTo(ticksContainer.Rotation + 180, 320); - break; - - case ArmedState.Miss: - this.ScaleTo(initial_scale * 0.8f, 320, Easing.In); - break; - } - } - } - - using (BeginAbsoluteSequence(spinner.StartTime - spinner.TimePreempt)) - { - centre.ScaleTo(0); - disc.ScaleTo(0); - using (BeginDelayedSequence(spinner.TimePreempt / 2)) { centre.ScaleTo(0.3f, spinner.TimePreempt / 4, Easing.OutQuint); @@ -265,6 +247,21 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon disc.ScaleTo(1, spinner.TimePreempt / 2, Easing.OutQuint); } } + + using (BeginDelayedSequence(spinner.TimePreempt + spinner.Duration + drawableHitObject.Result.TimeOffset)) + { + switch (state) + { + case ArmedState.Hit: + disc.ScaleTo(initial_scale * 1.2f, 320, Easing.Out); + ticksContainer.RotateTo(ticksContainer.Rotation + 180, 320); + break; + + case ArmedState.Miss: + disc.ScaleTo(initial_scale * 0.8f, 320, Easing.In); + break; + } + } } if (drawableSpinner.Result?.TimeStarted != null) From 0868c00ee83f00af4d4eb7a43317ac9569260ca0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 14:36:11 +0900 Subject: [PATCH 2033/2686] Fix spinner centre size being updated every frame using transforms --- .../Skinning/Argon/ArgonSpinnerDisc.cs | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs index b2c804a2da..f99d4275bd 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; @@ -184,6 +183,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon updateStateTransforms(drawableSpinner, drawableSpinner.State.Value); } + private float trackingElementInterpolation; + protected override void Update() { base.Update(); @@ -203,11 +204,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } else { - fill.Alpha = (float)Interpolation.Damp(fill.Alpha, drawableSpinner.RotationTracker.Tracking ? tracking_alpha : idle_alpha, 0.98f, (float)Math.Abs(Clock.ElapsedFrameTime)); - } + trackingElementInterpolation = + (float)Interpolation.Damp(trackingElementInterpolation, drawableSpinner.RotationTracker.Tracking ? 1 : 0, 0.985f, (float)Math.Abs(Clock.ElapsedFrameTime)); - if (centre.Width == idle_centre_size && drawableSpinner.Result?.TimeStarted != null) - updateCentrePieceSize(); + fill.Alpha = trackingElementInterpolation * (tracking_alpha - idle_alpha) + idle_alpha; + centre.Size = new Vector2(trackingElementInterpolation * (tracking_centre_size - idle_centre_size) + idle_centre_size); + } const float initial_fill_scale = 0.1f; float targetScale = initial_fill_scale + (0.98f - initial_fill_scale) * drawableSpinner.Progress; @@ -263,19 +265,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } } } - - if (drawableSpinner.Result?.TimeStarted != null) - updateCentrePieceSize(); - } - - private void updateCentrePieceSize() - { - Debug.Assert(drawableSpinner.Result?.TimeStarted != null); - - Spinner spinner = drawableSpinner.HitObject; - - using (BeginAbsoluteSequence(drawableSpinner.Result.TimeStarted.Value)) - centre.ResizeTo(new Vector2(tracking_centre_size), spinner.TimePreempt / 2, Easing.OutQuint); } protected override void Dispose(bool isDisposing) From 94b1c2602eba7a75c76a7a4f4335377f5d4865aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 14:36:11 +0900 Subject: [PATCH 2034/2686] Fix spinner centre size being updated every frame using transforms --- .../Skinning/Argon/ArgonSpinnerDisc.cs | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs index 4669b5b913..d88752f025 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; @@ -138,6 +137,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon updateStateTransforms(drawableSpinner, drawableSpinner.State.Value); } + private float trackingElementInterpolation; + protected override void Update() { base.Update(); @@ -157,11 +158,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } else { - fill.Alpha = (float)Interpolation.Damp(fill.Alpha, drawableSpinner.RotationTracker.Tracking ? tracking_alpha : idle_alpha, 0.98f, (float)Math.Abs(Clock.ElapsedFrameTime)); - } + trackingElementInterpolation = + (float)Interpolation.Damp(trackingElementInterpolation, drawableSpinner.RotationTracker.Tracking ? 1 : 0, 0.985f, (float)Math.Abs(Clock.ElapsedFrameTime)); - if (centre.Width == idle_centre_size && drawableSpinner.Result?.TimeStarted != null) - updateCentrePieceSize(); + fill.Alpha = trackingElementInterpolation * (tracking_alpha - idle_alpha) + idle_alpha; + centre.Size = new Vector2(trackingElementInterpolation * (tracking_centre_size - idle_centre_size) + idle_centre_size); + } const float initial_fill_scale = 0.1f; float targetScale = initial_fill_scale + (0.98f - initial_fill_scale) * drawableSpinner.Progress; @@ -221,19 +223,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } } } - - if (drawableSpinner.Result?.TimeStarted != null) - updateCentrePieceSize(); - } - - private void updateCentrePieceSize() - { - Debug.Assert(drawableSpinner.Result?.TimeStarted != null); - - Spinner spinner = drawableSpinner.HitObject; - - using (BeginAbsoluteSequence(drawableSpinner.Result.TimeStarted.Value)) - centre.ResizeTo(new Vector2(tracking_centre_size), spinner.TimePreempt / 2, Easing.OutQuint); } protected override void Dispose(bool isDisposing) From e89d3840fc99c8f3724d674d14aad779e994bb2f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 15:11:26 +0900 Subject: [PATCH 2035/2686] Adjust completion animation --- .../Skinning/Argon/ArgonSpinnerProgressArc.cs | 14 +++++++---- .../Skinning/Argon/ArgonSpinnerRingArc.cs | 24 +++++++++++++++++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs index be7921a1f1..e998f55755 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Utils; -using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables; using osuTK.Graphics; @@ -24,8 +23,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon private DrawableSpinner spinner = null!; + private CircularProgress background = null!; + [BackgroundDependencyLoader] - private void load(DrawableHitObject drawableHitObject, OsuColour colours) + private void load(DrawableHitObject drawableHitObject) { RelativeSizeAxes = Axes.Both; @@ -33,7 +34,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon InternalChildren = new Drawable[] { - new CircularProgress + background = new CircularProgress { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -59,8 +60,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { base.Update(); - fill.Alpha = (float)Interpolation.DampContinuously(fill.Alpha, spinner.Progress > 0 ? 1 : 0, 120f, (float)Math.Abs(Time.Elapsed)); - fill.Current.Value = (float)Interpolation.DampContinuously(fill.Current.Value, arc_fill * spinner.Progress, 120f, (float)Math.Abs(Time.Elapsed)); + background.Alpha = spinner.Progress >= 1 ? 0 : 1; + + fill.Alpha = (float)Interpolation.DampContinuously(fill.Alpha, spinner.Progress > 0 && spinner.Progress < 1 ? 1 : 0, 40f, (float)Math.Abs(Time.Elapsed)); + fill.Current.Value = (float)Interpolation.DampContinuously(fill.Current.Value, spinner.Progress >= 1 ? 0 : arc_fill * spinner.Progress, 40f, (float)Math.Abs(Time.Elapsed)); + fill.Rotation = (float)(90 - fill.Current.Value * 180); } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs index ec9d7bbae5..57fb57a09e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs @@ -1,24 +1,34 @@ // 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.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Utils; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Skinning.Argon { public class ArgonSpinnerRingArc : CompositeDrawable { private const float arc_fill = 0.31f; + private const float arc_fill_complete = 0.50f; + private const float arc_radius = 0.02f; + private DrawableSpinner spinner = null!; + private CircularProgress fill = null!; + [BackgroundDependencyLoader] - private void load() + private void load(DrawableHitObject drawableHitObject) { RelativeSizeAxes = Axes.Both; - InternalChild = new CircularProgress + spinner = (DrawableSpinner)drawableHitObject; + InternalChild = fill = new CircularProgress { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -29,5 +39,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon RoundedCaps = true, }; } + + protected override void Update() + { + base.Update(); + + fill.Current.Value = (float)Interpolation.DampContinuously(fill.Current.Value, spinner.Progress >= 1 ? arc_fill_complete : arc_fill, 40f, (float)Math.Abs(Time.Elapsed)); + fill.InnerRadius = (float)Interpolation.DampContinuously(fill.InnerRadius, spinner.Progress >= 1 ? arc_radius * 2.2f : arc_radius, 40f, (float)Math.Abs(Time.Elapsed)); + + fill.Rotation = (float)(-fill.Current.Value * 180); + } } } From 56ef519cc28fc1ee5c7ca321723aa3d9370cbdd3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 15:43:06 +0900 Subject: [PATCH 2036/2686] Move `PopoverContainer` into `OnlineOverlay` to ensure correct colours --- osu.Game/OsuGameBase.cs | 9 ++------- osu.Game/Overlays/OnlineOverlay.cs | 3 ++- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index c4c2c8325d..39ddffd2d0 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -18,7 +18,6 @@ using osu.Framework.Development; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Textures; using osu.Framework.Input; using osu.Framework.Input.Handlers; @@ -358,13 +357,9 @@ namespace osu.Game (GlobalCursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both - }).WithChild(new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor) + }).WithChild(content = new OsuTooltipContainer(GlobalCursorDisplay.MenuCursor) { - RelativeSizeAxes = Axes.Both, - Child = content = new PopoverContainer - { - RelativeSizeAxes = Axes.Both, - } + RelativeSizeAxes = Axes.Both }), // to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything. globalBindings = new GlobalActionContainer(this) diff --git a/osu.Game/Overlays/OnlineOverlay.cs b/osu.Game/Overlays/OnlineOverlay.cs index 424584fbcf..24bc7a73e0 100644 --- a/osu.Game/Overlays/OnlineOverlay.cs +++ b/osu.Game/Overlays/OnlineOverlay.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online; @@ -45,7 +46,7 @@ namespace osu.Game.Overlays Children = new Drawable[] { Header.With(h => h.Depth = float.MinValue), - content = new Container + content = new PopoverContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y From 502bfa950ec94ab296fbae266e82a1e1b3a5b3ee Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Thu, 3 Nov 2022 08:05:26 +0100 Subject: [PATCH 2037/2686] Fix potential resource leak --- .../Components/BeatmapInfoDrawable.cs | 213 +++++++----------- 1 file changed, 82 insertions(+), 131 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs index 44c3914d2c..ac771af8f9 100644 --- a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs +++ b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs @@ -83,17 +83,18 @@ namespace osu.Game.Skinning.Components protected override void LoadComplete() { base.LoadComplete(); - Type.BindValueChanged(update, true); - ShowLabel.BindValueChanged(ignored => updateLabel()); - ValueBeforeLabel.BindValueChanged(ignored => updateLabel()); - LabelPrefix.BindValueChanged(ignored => updateLabel()); - ShowLabelPrefix.BindValueChanged(ignored => updateLabel()); - LabelSuffix.BindValueChanged(ignored => updateLabel()); - ShowLabelSuffix.BindValueChanged(ignored => updateLabel()); - ValuePrefix.BindValueChanged(ignored => updateLabel()); - ShowValuePrefix.BindValueChanged(ignored => updateLabel()); - ValueSuffix.BindValueChanged(ignored => updateLabel()); - ShowValueSuffix.BindValueChanged(ignored => updateLabel()); + Type.BindValueChanged(_ => updateBeatmapContent()); + beatmap.BindValueChanged(_ => updateBeatmapContent(), true); + ShowLabel.BindValueChanged(_ => updateLabel()); + ValueBeforeLabel.BindValueChanged(_ => updateLabel()); + LabelPrefix.BindValueChanged(_ => updateLabel()); + ShowLabelPrefix.BindValueChanged(_ => updateLabel()); + LabelSuffix.BindValueChanged(_ => updateLabel()); + ShowLabelSuffix.BindValueChanged(_ => updateLabel()); + ValuePrefix.BindValueChanged(_ => updateLabel()); + ShowValuePrefix.BindValueChanged(_ => updateLabel()); + ValueSuffix.BindValueChanged(_ => updateLabel()); + ShowValueSuffix.BindValueChanged(_ => updateLabel()); } private LocalisableString getLabelText() @@ -125,174 +126,124 @@ namespace osu.Game.Skinning.Components Height = text.Height; } - private void update(ValueChangedEvent type) + private void updateBeatmapContent() { - switch (type.NewValue) + switch (Type.Value) { case BeatmapInfo.CircleSize: - beatmap.BindValueChanged(bm => - { - double cs = bm.NewValue.BeatmapInfo.Difficulty.CircleSize; - labelText = TooltipText = BeatmapsetsStrings.ShowStatsCs; - value = cs.ToString("F2"); - updateLabel(); - }, true); + double cs = beatmap.Value.BeatmapInfo.Difficulty.CircleSize; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsCs; + value = cs.ToString("F2"); break; case BeatmapInfo.HPDrain: - beatmap.BindValueChanged(bm => - { - double hp = bm.NewValue.BeatmapInfo.Difficulty.DrainRate; - labelText = TooltipText = BeatmapsetsStrings.ShowStatsDrain; - value = hp.ToString("F2"); - updateLabel(); - }, true); + double hp = beatmap.Value.BeatmapInfo.Difficulty.DrainRate; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsDrain; + value = hp.ToString("F2"); break; case BeatmapInfo.Accuracy: - beatmap.BindValueChanged(bm => - { - double od = bm.NewValue.BeatmapInfo.Difficulty.OverallDifficulty; - labelText = TooltipText = BeatmapsetsStrings.ShowStatsAccuracy; - value = od.ToString("F2"); - updateLabel(); - }, true); + double od = beatmap.Value.BeatmapInfo.Difficulty.OverallDifficulty; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsAccuracy; + value = od.ToString("F2"); break; case BeatmapInfo.ApproachRate: - beatmap.BindValueChanged(bm => - { - double ar = bm.NewValue.BeatmapInfo.Difficulty.ApproachRate; - labelText = TooltipText = BeatmapsetsStrings.ShowStatsAr; - value = ar.ToString("F2"); - updateLabel(); - }, true); + double ar = beatmap.Value.BeatmapInfo.Difficulty.ApproachRate; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsAr; + value = ar.ToString("F2"); break; case BeatmapInfo.StarRating: - beatmap.BindValueChanged(bm => - { - double sr = bm.NewValue.BeatmapInfo.StarRating; - labelText = TooltipText = BeatmapsetsStrings.ShowStatsStars; - value = sr.ToString("F2"); - updateLabel(); - }, true); + double sr = beatmap.Value.BeatmapInfo.StarRating; + labelText = TooltipText = BeatmapsetsStrings.ShowStatsStars; + value = sr.ToString("F2"); break; case BeatmapInfo.Song: - beatmap.BindValueChanged(bm => - { - string title = bm.NewValue.BeatmapInfo.Metadata.Title; - //todo: no Song Title localisation? - labelText = TooltipText = EditorSetupStrings.Title; - value = title; - updateLabel(); - }, true); + string title = beatmap.Value.BeatmapInfo.Metadata.Title; + labelText = TooltipText = EditorSetupStrings.Title; + value = title; break; case BeatmapInfo.Artist: - beatmap.BindValueChanged(bm => - { - string artist = bm.NewValue.BeatmapInfo.Metadata.Artist; - labelText = EditorSetupStrings.Artist; - TooltipText = BeatmapsetsStrings.ShowDetailsByArtist(artist); - value = artist; - updateLabel(); - }, true); + string artist = beatmap.Value.BeatmapInfo.Metadata.Artist; + labelText = EditorSetupStrings.Artist; + TooltipText = BeatmapsetsStrings.ShowDetailsByArtist(artist); + value = artist; break; case BeatmapInfo.Difficulty: - beatmap.BindValueChanged(bm => - { - string diff = bm.NewValue.BeatmapInfo.DifficultyName; - labelText = TooltipText = EditorSetupStrings.DifficultyHeader; - text.Current.Value = diff; - updateLabel(); - }, true); + string diff = beatmap.Value.BeatmapInfo.DifficultyName; + labelText = TooltipText = EditorSetupStrings.DifficultyHeader; + text.Current.Value = diff; break; case BeatmapInfo.Mapper: - beatmap.BindValueChanged(bm => - { - string mapper = bm.NewValue.BeatmapInfo.Metadata.Author.Username; - //todo: is there a good alternative, to ShowDetailsMappedBy? - labelText = AccountsStrings.NotificationsOptionsMapping; - TooltipText = BeatmapsetsStrings.ShowDetailsMappedBy(mapper); - value = mapper; - updateLabel(); - }, true); + string mapper = beatmap.Value.BeatmapInfo.Metadata.Author.Username; + //todo: is there a good alternative, to NotificationsOptionsMapping? + labelText = AccountsStrings.NotificationsOptionsMapping; + TooltipText = BeatmapsetsStrings.ShowDetailsMappedBy(mapper); + value = mapper; break; case BeatmapInfo.Length: - beatmap.BindValueChanged(bm => - { - labelText = TooltipText = ArtistStrings.TracklistLength; - value = TimeSpan.FromMilliseconds(bm.NewValue.BeatmapInfo.Length).ToFormattedDuration(); - updateLabel(); - }, true); + labelText = TooltipText = ArtistStrings.TracklistLength; + value = TimeSpan.FromMilliseconds(beatmap.Value.BeatmapInfo.Length).ToFormattedDuration(); break; case BeatmapInfo.Status: - beatmap.BindValueChanged(bm => + BeatmapOnlineStatus status = beatmap.Value.BeatmapInfo.Status; + TooltipText = labelText = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault; + + switch (status) { - BeatmapOnlineStatus status = bm.NewValue.BeatmapInfo.Status; - //todo: no Localizasion for None Beatmap Online Status - labelText = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault; + case BeatmapOnlineStatus.Approved: + value = BeatmapsetsStrings.ShowStatusApproved; + break; - switch (status) - { - case BeatmapOnlineStatus.Approved: - value = BeatmapsetsStrings.ShowStatusApproved; - //todo: is this correct? - TooltipText = BeatmapsetsStrings.ShowDetailsDateApproved(bm.NewValue.BeatmapSetInfo.DateRanked.ToString()); - break; + case BeatmapOnlineStatus.Graveyard: + value = BeatmapsetsStrings.ShowStatusGraveyard; + break; - case BeatmapOnlineStatus.Graveyard: - value = BeatmapsetsStrings.ShowStatusGraveyard; - break; + case BeatmapOnlineStatus.Loved: + value = BeatmapsetsStrings.ShowStatusLoved; + break; - case BeatmapOnlineStatus.Loved: - value = BeatmapsetsStrings.ShowStatusLoved; - break; + case BeatmapOnlineStatus.None: + value = "None"; + break; - case BeatmapOnlineStatus.None: - value = "None"; - break; + case BeatmapOnlineStatus.Pending: + value = BeatmapsetsStrings.ShowStatusPending; + break; - case BeatmapOnlineStatus.Pending: - value = BeatmapsetsStrings.ShowStatusPending; - break; + case BeatmapOnlineStatus.Qualified: + value = BeatmapsetsStrings.ShowStatusQualified; + break; - case BeatmapOnlineStatus.Qualified: - value = BeatmapsetsStrings.ShowStatusQualified; - break; + case BeatmapOnlineStatus.Ranked: + value = BeatmapsetsStrings.ShowStatusRanked; + break; - case BeatmapOnlineStatus.Ranked: - value = BeatmapsetsStrings.ShowStatusRanked; - break; + case BeatmapOnlineStatus.LocallyModified: + value = SongSelectStrings.LocallyModified; + break; - case BeatmapOnlineStatus.LocallyModified: - value = SongSelectStrings.LocallyModified; - break; + case BeatmapOnlineStatus.WIP: + value = BeatmapsetsStrings.ShowStatusWip; + break; + } - case BeatmapOnlineStatus.WIP: - value = BeatmapsetsStrings.ShowStatusWip; - break; - } - - updateLabel(); - }, true); break; case BeatmapInfo.BPM: - beatmap.BindValueChanged(bm => - { - labelText = TooltipText = BeatmapsetsStrings.ShowStatsBpm; - value = bm.NewValue.BeatmapInfo.BPM.ToString("F2"); - updateLabel(); - }, true); + labelText = TooltipText = BeatmapsetsStrings.ShowStatsBpm; + value = beatmap.Value.BeatmapInfo.BPM.ToString("F2"); break; } + + updateLabel(); } } From f1c17129eb34d7e49342826e8fbd425b006d4f5f Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 3 Nov 2022 17:44:54 +0900 Subject: [PATCH 2038/2686] Add support for 'disabled' sample variation to HoverClickSounds --- .../UserInterface/TestSceneLabelledSliderBar.cs | 8 ++++++++ .../Graphics/Containers/OsuClickableContainer.cs | 2 +- .../Graphics/UserInterface/DrawableOsuMenuItem.cs | 4 +++- .../Graphics/UserInterface/HoverClickSounds.cs | 15 +++++++++++++-- osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 5 ++++- osu.Game/Graphics/UserInterface/ShearedButton.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarClock.cs | 3 +++ 8 files changed, 34 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs index e5f3aea2f7..5548375af2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs @@ -38,6 +38,14 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("revert back", () => this.ChildrenOfType>().ForEach(l => l.ResizeWidthTo(1, 200, Easing.OutQuint))); } + [Test] + public void TestDisable() + { + createSliderBar(); + AddStep("set disabled", () => this.ChildrenOfType>().ForEach(l => l.Current.Disabled = true)); + AddStep("unset disabled", () => this.ChildrenOfType>().ForEach(l => l.Current.Disabled = false)); + } + private void createSliderBar() { AddStep("create component", () => diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index 61ec9dfc24..03a1cfcc13 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -20,7 +20,7 @@ namespace osu.Game.Graphics.Containers protected override Container Content => content; - protected virtual HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet); + protected virtual HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { BindTarget = Enabled } }; public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Default) { diff --git a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs index b469c21ab0..6c8eeed391 100644 --- a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs @@ -24,6 +24,7 @@ namespace osu.Game.Graphics.UserInterface private const int transition_length = 80; private TextContainer text; + private HoverClickSounds hoverClickSounds; public DrawableOsuMenuItem(MenuItem item) : base(item) @@ -36,7 +37,7 @@ namespace osu.Game.Graphics.UserInterface BackgroundColour = Color4.Transparent; BackgroundColourHover = Color4Extensions.FromHex(@"172023"); - AddInternal(new HoverClickSounds()); + AddInternal(hoverClickSounds = new HoverClickSounds()); updateTextColour(); @@ -76,6 +77,7 @@ namespace osu.Game.Graphics.UserInterface private void updateState() { + hoverClickSounds.Enabled.Value = !Item.Action.Disabled; Alpha = Item.Action.Disabled ? 0.2f : 1; if (IsHovered && !Item.Action.Disabled) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index dab4390ede..9b4bff17e6 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Input.Events; using osu.Framework.Utils; @@ -21,6 +22,8 @@ namespace osu.Game.Graphics.UserInterface public class HoverClickSounds : HoverSounds { private Sample sampleClick; + private Sample sampleClickDisabled; + public Bindable Enabled = new Bindable(true); private readonly MouseButton[] buttons; /// @@ -41,8 +44,13 @@ namespace osu.Game.Graphics.UserInterface { if (buttons.Contains(e.Button) && Contains(e.ScreenSpaceMousePosition)) { - sampleClick.Frequency.Value = 0.99 + RNG.NextDouble(0.02); - sampleClick.Play(); + var channel = Enabled.Value ? sampleClick?.GetChannel() : sampleClickDisabled?.GetChannel(); + + if (channel != null) + { + channel.Frequency.Value = 0.99 + RNG.NextDouble(0.02); + channel.Play(); + } } return base.OnClick(e); @@ -53,6 +61,9 @@ namespace osu.Game.Graphics.UserInterface { sampleClick = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-select") ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select"); + + sampleClickDisabled = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-select-disabled") + ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select-disabled"); } } } diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 291ff644fd..88f3ccd191 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -104,7 +104,7 @@ namespace osu.Game.Graphics.UserInterface }); if (hoverSounds.HasValue) - AddInternal(new HoverClickSounds(hoverSounds.Value)); + AddInternal(new HoverClickSounds(hoverSounds.Value) { Enabled = { BindTarget = Enabled } }); } [BackgroundDependencyLoader] diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 9acb0c7f94..392740690a 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -46,6 +46,8 @@ namespace osu.Game.Graphics.UserInterface public bool PlaySamplesOnAdjust { get; set; } = true; + private readonly HoverClickSounds hoverClickSounds; + /// /// Whether to format the tooltip as a percentage or the actual value. /// @@ -127,7 +129,7 @@ namespace osu.Game.Graphics.UserInterface Current = { Value = true } }, }, - new HoverClickSounds() + hoverClickSounds = new HoverClickSounds() }; Current.DisabledChanged += disabled => { Alpha = disabled ? 0.3f : 1; }; @@ -152,6 +154,7 @@ namespace osu.Game.Graphics.UserInterface { base.LoadComplete(); CurrentNumber.BindValueChanged(current => TooltipText = getTooltipText(current.NewValue), true); + Current.DisabledChanged += disabled => hoverClickSounds.Enabled.Value = !disabled; } protected override bool OnHover(HoverEvent e) diff --git a/osu.Game/Graphics/UserInterface/ShearedButton.cs b/osu.Game/Graphics/UserInterface/ShearedButton.cs index 0c25d06cd4..e406e273e6 100644 --- a/osu.Game/Graphics/UserInterface/ShearedButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedButton.cs @@ -138,7 +138,7 @@ namespace osu.Game.Graphics.UserInterface } } - protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet); + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { BindTarget = Enabled } }; protected override void LoadComplete() { diff --git a/osu.Game/Overlays/Toolbar/ToolbarClock.cs b/osu.Game/Overlays/Toolbar/ToolbarClock.cs index c5add6eee2..9c264acbd1 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarClock.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarClock.cs @@ -13,6 +13,7 @@ using osu.Framework.Input.Events; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; using osuTK; using osuTK.Graphics; @@ -123,6 +124,8 @@ namespace osu.Game.Overlays.Toolbar base.OnHoverLost(e); } + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { Value = true } }; + private void cycleDisplayMode() { switch (clockDisplayMode.Value) From 59bbd9c460afc87ee2cc8613692fc6d0e156dfff Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 3 Nov 2022 17:47:29 +0900 Subject: [PATCH 2039/2686] Fix some components using wrong sample set --- osu.Game/Graphics/UserInterface/LoadingButton.cs | 1 + osu.Game/Overlays/Comments/CancellableCommentEditor.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/LoadingButton.cs b/osu.Game/Graphics/UserInterface/LoadingButton.cs index 8be50a4b43..44067bac8b 100644 --- a/osu.Game/Graphics/UserInterface/LoadingButton.cs +++ b/osu.Game/Graphics/UserInterface/LoadingButton.cs @@ -41,6 +41,7 @@ namespace osu.Game.Graphics.UserInterface private readonly LoadingSpinner loading; protected LoadingButton() + : base(HoverSampleSet.Button) { Add(loading = new LoadingSpinner { diff --git a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs index 853171ea4a..7ba6de86b7 100644 --- a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs +++ b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments @@ -38,6 +39,7 @@ namespace osu.Game.Overlays.Comments private readonly Box background; public CancelButton() + : base(HoverSampleSet.Button) { AutoSizeAxes = Axes.Both; Child = new CircularContainer From f75c4ba95fff8056cb4b48582d281d53183f1758 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 20:27:44 +0900 Subject: [PATCH 2040/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 8711ceec64..b3c48da2bf 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8d45ebec57..fe44ed3688 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 76d2e727c8..b5b488d82e 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + From f6c376c09077dd79713940c785c6985a802bbbbe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Nov 2022 20:29:27 +0900 Subject: [PATCH 2041/2686] Minor refactoring --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 4 +++- osu.Game/Overlays/Toolbar/ToolbarClock.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 9b4bff17e6..89d1570cd4 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -21,9 +21,11 @@ namespace osu.Game.Graphics.UserInterface /// public class HoverClickSounds : HoverSounds { + public Bindable Enabled = new Bindable(true); + private Sample sampleClick; private Sample sampleClickDisabled; - public Bindable Enabled = new Bindable(true); + private readonly MouseButton[] buttons; /// diff --git a/osu.Game/Overlays/Toolbar/ToolbarClock.cs b/osu.Game/Overlays/Toolbar/ToolbarClock.cs index 9c264acbd1..3fd37d9a62 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarClock.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarClock.cs @@ -124,7 +124,7 @@ namespace osu.Game.Overlays.Toolbar base.OnHoverLost(e); } - protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { Value = true } }; + protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet); private void cycleDisplayMode() { From a435e365ea966cae81caff8b9923b8f7ed25c77e Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Thu, 3 Nov 2022 18:54:55 +0100 Subject: [PATCH 2042/2686] Allow for the Value of BeatmapInfoDrawable to be formatted --- .../Components/BeatmapInfoDrawable.cs | 294 ++++++++++-------- 1 file changed, 159 insertions(+), 135 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs index ac771af8f9..479124a43d 100644 --- a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs +++ b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs @@ -2,12 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -20,12 +22,13 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Skinning.Components { [UsedImplicitly] - public class BeatmapInfoDrawable : Container, ISkinnableDrawable, IHasTooltip + public class BeatmapInfoDrawable : Container, ISkinnableDrawable { + private const BeatmapInfo default_beatmap_info = BeatmapInfo.StarRating; public bool UsesFixedAnchor { get; set; } - [SettingSource("Tracked Beatmap Info", "Which part of the BeatmapInformation should be tracked")] - public Bindable Type { get; } = new Bindable(BeatmapInfo.StarRating); + [SettingSource("Tracked Beatmap Info/Label", "Which part of the BeatmapInformation should be displayed. Gets overridden by complex changes to ValueFormat")] + public Bindable Type { get; } = new Bindable(default_beatmap_info); [SettingSource("Show Label", "Should a Label be shown, as to which status is currently Displayed?")] public BindableBool ShowLabel { get; } = new BindableBool(true); @@ -45,26 +48,37 @@ namespace osu.Game.Skinning.Components [SettingSource("Show Label Suffix", "Should the Label Suffix be included?")] public BindableBool ShowLabelSuffix { get; } = new BindableBool(true); - [SettingSource("Value Prefix", "Add something to be shown before the Value")] - public Bindable ValuePrefix { get; set; } = new Bindable(""); - - [SettingSource("Show Value Prefix", "Should the Value Prefix be included?")] - public BindableBool ShowValuePrefix { get; } = new BindableBool(); - - [SettingSource("Value Suffix", "Add something to be shown after the Value")] - public Bindable ValueSuffix { get; set; } = new Bindable(""); - - [SettingSource("Show Value Suffix", "Should the Value Suffix be included?")] - public BindableBool ShowValueSuffix { get; } = new BindableBool(); + [SettingSource("Value Formatting", "Bypass the restriction of 1 Info per element. Format is '{'+Type+'}' to substitue values. e.g. '{Song}' ")] + public Bindable ValueFormat { get; set; } = new Bindable("{" + default_beatmap_info + "}"); [Resolved] private IBindable beatmap { get; set; } = null!; + private readonly Dictionary valueDictionary = new Dictionary(); + private static readonly ImmutableDictionary label_dictionary; + private readonly OsuSpriteText text; - public LocalisableString TooltipText { get; set; } - private LocalisableString value; - private LocalisableString labelText; + static BeatmapInfoDrawable() + { + label_dictionary = new Dictionary + { + [BeatmapInfo.CircleSize] = BeatmapsetsStrings.ShowStatsCs, + [BeatmapInfo.Accuracy] = BeatmapsetsStrings.ShowStatsAccuracy, + [BeatmapInfo.HPDrain] = BeatmapsetsStrings.ShowStatsDrain, + [BeatmapInfo.ApproachRate] = BeatmapsetsStrings.ShowStatsAr, + [BeatmapInfo.StarRating] = BeatmapsetsStrings.ShowStatsStars, + [BeatmapInfo.Song] = EditorSetupStrings.Title, + [BeatmapInfo.Artist] = EditorSetupStrings.Artist, + [BeatmapInfo.Difficulty] = EditorSetupStrings.DifficultyHeader, + //todo: is there a good alternative, to NotificationsOptionsMapping? + [BeatmapInfo.Mapper] = AccountsStrings.NotificationsOptionsMapping, + [BeatmapInfo.Length] = ArtistStrings.TracklistLength, + [BeatmapInfo.Status] = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault, + [BeatmapInfo.BPM] = BeatmapsetsStrings.ShowStatsBpm, + [BeatmapInfo.Custom] = BeatmapInfo.Custom.ToString() + }.ToImmutableDictionary(); + } public BeatmapInfoDrawable() { @@ -78,23 +92,78 @@ namespace osu.Game.Skinning.Components Font = OsuFont.Default.With(size: 40) } }; + + foreach (var type in Enum.GetValues(typeof(BeatmapInfo)).Cast()) + { + valueDictionary[type] = type.ToString(); + } + } + + /// + /// This will return the if the format-String contains of a singular replacement of type info, or not. + /// If there is only one one replacement of type info, it will also return the prefix/suffix (or null if no prefix/suffix exists). + /// + /// The format-String to work on + /// The replacement Type to look for + /// (true, prefix, suffix), if there is only one replacement of type info. Else (false, null, null) + private static (bool, string?, string?) isOnlyPrefixedOrSuffixed(string format, BeatmapInfo info) + { + string[] s = format.Split("{" + info + "}"); + + foreach (string si in s) + { + foreach (var type in Enum.GetValues(typeof(BeatmapInfo)).Cast()) + { + if (si.Contains("{" + type + "}")) return (false, null, null); + } + } + + //Debug.WriteLine($"format:'{format}', type:{info} is only prefixed/suffixed"); + + return (true, + s.Length >= 1 ? s[0] : null, //prefix + s.Length >= 2 ? s[1] : null //suffix + ); } protected override void LoadComplete() { base.LoadComplete(); - Type.BindValueChanged(_ => updateBeatmapContent()); - beatmap.BindValueChanged(_ => updateBeatmapContent(), true); + Type.BindValueChanged(v => + { + string newDefault = "{" + v.NewValue + "}"; + bool custom = v.NewValue == BeatmapInfo.Custom; + + //If the ValueFormat is Default and the user did not change anything we should be able to just swap the strings. + //If it was Default before, it should be default after the Type is changed. + if (ValueFormat.IsDefault && !custom) + ValueFormat.Value = newDefault; + else + { + //In this if statement we decide if the ValueFormat has been trivially changed (so only been prefixed or suffixed) + (bool preOrSuffixed, string? prefix, string? suffix) = isOnlyPrefixedOrSuffixed(ValueFormat.Value, v.OldValue); + if (preOrSuffixed) + //If it has, we can keep the prefix and suffix and just change the thing that would be substituted. + ValueFormat.Value = (prefix ?? "") + newDefault + (suffix ?? ""); + //else we just keep the ValueFormat. I determine here, that the user probably knows what they are doing, and how the ValueFormat works. + } + + //Only if we could preserve the ValueFormat (so nothing was changed except a static prefix/suffix) I want to set the new Default. + ValueFormat.Default = newDefault; + updateLabel(); + }); + ValueFormat.BindValueChanged(f => updateLabel(), true); + beatmap.BindValueChanged(b => + { + UpdateBeatmapContent(b.NewValue); + updateLabel(); + }, true); ShowLabel.BindValueChanged(_ => updateLabel()); ValueBeforeLabel.BindValueChanged(_ => updateLabel()); LabelPrefix.BindValueChanged(_ => updateLabel()); ShowLabelPrefix.BindValueChanged(_ => updateLabel()); LabelSuffix.BindValueChanged(_ => updateLabel()); ShowLabelSuffix.BindValueChanged(_ => updateLabel()); - ValuePrefix.BindValueChanged(_ => updateLabel()); - ShowValuePrefix.BindValueChanged(_ => updateLabel()); - ValueSuffix.BindValueChanged(_ => updateLabel()); - ShowValueSuffix.BindValueChanged(_ => updateLabel()); } private LocalisableString getLabelText() @@ -103,16 +172,20 @@ namespace osu.Game.Skinning.Components return LocalisableString.Format("{0}{1}{2}", ShowLabelPrefix.Value ? LabelPrefix.Value : "", - labelText, + label_dictionary[Type.Value], ShowLabelSuffix.Value ? LabelSuffix.Value : ""); } private LocalisableString getValueText() { - return LocalisableString.Format("{0}{1}{2}", - ShowValuePrefix.Value ? ValuePrefix.Value : "", - value, - ShowValueSuffix.Value ? ValueSuffix.Value : ""); + string value = ValueFormat.Value; + + foreach (var type in Enum.GetValues(typeof(BeatmapInfo)).Cast()) + { + value = value.Replace("{" + type + "}", valueDictionary[type].ToString()); + } + + return value; } private void updateLabel() @@ -126,124 +199,74 @@ namespace osu.Game.Skinning.Components Height = text.Height; } - private void updateBeatmapContent() + public void UpdateBeatmapContent(WorkingBeatmap workingBeatmap) { - switch (Type.Value) + //update cs + double cs = workingBeatmap.BeatmapInfo.Difficulty.CircleSize; + valueDictionary[BeatmapInfo.CircleSize] = cs.ToString("F2"); + //update HP + double hp = workingBeatmap.BeatmapInfo.Difficulty.DrainRate; + valueDictionary[BeatmapInfo.HPDrain] = hp.ToString("F2"); + //update od + double od = workingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty; + valueDictionary[BeatmapInfo.Accuracy] = od.ToString("F2"); + //update ar + double ar = workingBeatmap.BeatmapInfo.Difficulty.ApproachRate; + valueDictionary[BeatmapInfo.ApproachRate] = ar.ToString("F2"); + //update sr + double sr = workingBeatmap.BeatmapInfo.StarRating; + valueDictionary[BeatmapInfo.StarRating] = sr.ToString("F2"); + //update song title + valueDictionary[BeatmapInfo.Song] = workingBeatmap.BeatmapInfo.Metadata.Title; + //update artist + valueDictionary[BeatmapInfo.Artist] = workingBeatmap.BeatmapInfo.Metadata.Artist; + //update difficulty name + valueDictionary[BeatmapInfo.Difficulty] = workingBeatmap.BeatmapInfo.DifficultyName; + //update mapper + valueDictionary[BeatmapInfo.Mapper] = workingBeatmap.BeatmapInfo.Metadata.Author.Username; + //update Length + valueDictionary[BeatmapInfo.Length] = TimeSpan.FromMilliseconds(workingBeatmap.BeatmapInfo.Length).ToFormattedDuration(); + //update Status + valueDictionary[BeatmapInfo.Status] = GetBetmapStatus(workingBeatmap.BeatmapInfo.Status); + //update BPM + valueDictionary[BeatmapInfo.BPM] = workingBeatmap.BeatmapInfo.BPM.ToString("F2"); + valueDictionary[BeatmapInfo.Custom] = BeatmapInfo.Custom.ToString(); + } + + public static LocalisableString GetBetmapStatus(BeatmapOnlineStatus status) + { + switch (status) { - case BeatmapInfo.CircleSize: - double cs = beatmap.Value.BeatmapInfo.Difficulty.CircleSize; - labelText = TooltipText = BeatmapsetsStrings.ShowStatsCs; - value = cs.ToString("F2"); - break; + case BeatmapOnlineStatus.Approved: + return BeatmapsetsStrings.ShowStatusApproved; - case BeatmapInfo.HPDrain: - double hp = beatmap.Value.BeatmapInfo.Difficulty.DrainRate; - labelText = TooltipText = BeatmapsetsStrings.ShowStatsDrain; - value = hp.ToString("F2"); - break; + case BeatmapOnlineStatus.Graveyard: + return BeatmapsetsStrings.ShowStatusGraveyard; - case BeatmapInfo.Accuracy: - double od = beatmap.Value.BeatmapInfo.Difficulty.OverallDifficulty; - labelText = TooltipText = BeatmapsetsStrings.ShowStatsAccuracy; - value = od.ToString("F2"); - break; + case BeatmapOnlineStatus.Loved: + return BeatmapsetsStrings.ShowStatusLoved; - case BeatmapInfo.ApproachRate: - double ar = beatmap.Value.BeatmapInfo.Difficulty.ApproachRate; - labelText = TooltipText = BeatmapsetsStrings.ShowStatsAr; - value = ar.ToString("F2"); - break; + case BeatmapOnlineStatus.None: + return "None"; - case BeatmapInfo.StarRating: - double sr = beatmap.Value.BeatmapInfo.StarRating; - labelText = TooltipText = BeatmapsetsStrings.ShowStatsStars; - value = sr.ToString("F2"); - break; + case BeatmapOnlineStatus.Pending: + return BeatmapsetsStrings.ShowStatusPending; - case BeatmapInfo.Song: - string title = beatmap.Value.BeatmapInfo.Metadata.Title; - labelText = TooltipText = EditorSetupStrings.Title; - value = title; - break; + case BeatmapOnlineStatus.Qualified: + return BeatmapsetsStrings.ShowStatusQualified; - case BeatmapInfo.Artist: - string artist = beatmap.Value.BeatmapInfo.Metadata.Artist; - labelText = EditorSetupStrings.Artist; - TooltipText = BeatmapsetsStrings.ShowDetailsByArtist(artist); - value = artist; - break; + case BeatmapOnlineStatus.Ranked: + return BeatmapsetsStrings.ShowStatusRanked; - case BeatmapInfo.Difficulty: - string diff = beatmap.Value.BeatmapInfo.DifficultyName; - labelText = TooltipText = EditorSetupStrings.DifficultyHeader; - text.Current.Value = diff; - break; + case BeatmapOnlineStatus.LocallyModified: + return SongSelectStrings.LocallyModified; - case BeatmapInfo.Mapper: - string mapper = beatmap.Value.BeatmapInfo.Metadata.Author.Username; - //todo: is there a good alternative, to NotificationsOptionsMapping? - labelText = AccountsStrings.NotificationsOptionsMapping; - TooltipText = BeatmapsetsStrings.ShowDetailsMappedBy(mapper); - value = mapper; - break; + case BeatmapOnlineStatus.WIP: + return BeatmapsetsStrings.ShowStatusWip; - case BeatmapInfo.Length: - labelText = TooltipText = ArtistStrings.TracklistLength; - value = TimeSpan.FromMilliseconds(beatmap.Value.BeatmapInfo.Length).ToFormattedDuration(); - break; - - case BeatmapInfo.Status: - BeatmapOnlineStatus status = beatmap.Value.BeatmapInfo.Status; - TooltipText = labelText = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault; - - switch (status) - { - case BeatmapOnlineStatus.Approved: - value = BeatmapsetsStrings.ShowStatusApproved; - break; - - case BeatmapOnlineStatus.Graveyard: - value = BeatmapsetsStrings.ShowStatusGraveyard; - break; - - case BeatmapOnlineStatus.Loved: - value = BeatmapsetsStrings.ShowStatusLoved; - break; - - case BeatmapOnlineStatus.None: - value = "None"; - break; - - case BeatmapOnlineStatus.Pending: - value = BeatmapsetsStrings.ShowStatusPending; - break; - - case BeatmapOnlineStatus.Qualified: - value = BeatmapsetsStrings.ShowStatusQualified; - break; - - case BeatmapOnlineStatus.Ranked: - value = BeatmapsetsStrings.ShowStatusRanked; - break; - - case BeatmapOnlineStatus.LocallyModified: - value = SongSelectStrings.LocallyModified; - break; - - case BeatmapOnlineStatus.WIP: - value = BeatmapsetsStrings.ShowStatusWip; - break; - } - - break; - - case BeatmapInfo.BPM: - labelText = TooltipText = BeatmapsetsStrings.ShowStatsBpm; - value = beatmap.Value.BeatmapInfo.BPM.ToString("F2"); - break; + default: + return @"null"; } - - updateLabel(); } } @@ -261,5 +284,6 @@ namespace osu.Game.Skinning.Components Length, Status, BPM, + Custom, } } From 37b5f4891149fa3b6eefadd02e963d4ac3f9f890 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 4 Nov 2022 03:20:24 +0300 Subject: [PATCH 2043/2686] Adjust test scene to cover failure --- .../Visual/Online/TestSceneBeatmapListingOverlay.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs index 2c9b34e4a7..1e0a09d37a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs @@ -198,13 +198,13 @@ namespace osu.Game.Tests.Visual.Online beatmapSet = CreateAPIBeatmapSet(Ruleset.Value); beatmapSet.Title = "last beatmap of first page"; - fetchFor(getManyBeatmaps(49).Append(beatmapSet).ToArray(), true); + fetchFor(getManyBeatmaps(49).Append(new APIBeatmapSet { Title = "last beatmap of first page", OnlineID = beatmapSet.OnlineID }).ToArray(), true); }); AddUntilStep("wait for loaded", () => this.ChildrenOfType().Count() == 50); - AddStep("set next page", () => setSearchResponse(getManyBeatmaps(49).Prepend(beatmapSet).ToArray(), false)); + AddStep("set next page", () => setSearchResponse(getManyBeatmaps(49).Prepend(new APIBeatmapSet { Title = "this shouldn't show up", OnlineID = beatmapSet.OnlineID }).ToArray(), false)); AddStep("scroll to end", () => overlay.ChildrenOfType().Single().ScrollToEnd()); - AddUntilStep("wait for loaded", () => this.ChildrenOfType().Count() == 99); + AddUntilStep("wait for loaded", () => this.ChildrenOfType().Count() >= 99); AddAssert("beatmap not duplicated", () => overlay.ChildrenOfType().Count(c => c.BeatmapSet.Equals(beatmapSet)) == 1); } From ac8fb4f9b2b6ef1411b9aff9ede25607e898d3a8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 4 Nov 2022 03:20:14 +0300 Subject: [PATCH 2044/2686] Fix beatmap cards still potentially showing twice in listing --- osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 238f41e53d..717a1de6b5 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -149,5 +149,8 @@ namespace osu.Game.Online.API.Requests.Responses #endregion public bool Equals(IBeatmapSetInfo? other) => other is APIBeatmapSet b && this.MatchesOnlineID(b); + + // ReSharper disable once NonReadonlyMemberInGetHashCode + public override int GetHashCode() => OnlineID.GetHashCode(); } } From e11d44d14f9f575ae591bc89eeee1414107528fd Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 2 Nov 2022 22:30:30 -0700 Subject: [PATCH 2045/2686] Add url clicking support to profile badges --- .../Online/TestSceneUserProfileOverlay.cs | 11 +++++++++-- .../Header/Components/DrawableBadge.cs | 19 ++++++++++--------- osu.Game/Users/Badge.cs | 3 +++ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index caa2d2571d..7064a08151 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -52,8 +52,15 @@ namespace osu.Game.Tests.Visual.Online { AwardedAt = DateTimeOffset.FromUnixTimeSeconds(1505741569), Description = "Outstanding help by being a voluntary test subject.", - ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg" - } + ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg", + Url = "https://osu.ppy.sh/wiki/en/People/Community_Contributors", + }, + new Badge + { + AwardedAt = DateTimeOffset.FromUnixTimeSeconds(1505741569), + Description = "Badge without a url.", + ImageUrl = "https://assets.ppy.sh/profile-badges/contributor.jpg", + }, }, Title = "osu!volunteer", Colour = "ff0000", diff --git a/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs b/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs index cf75818a0c..2ee80a7494 100644 --- a/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs @@ -1,22 +1,20 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Localisation; +using osu.Game.Graphics.Containers; +using osu.Game.Online; using osu.Game.Users; using osuTK; namespace osu.Game.Overlays.Profile.Header.Components { [LongRunningLoad] - public class DrawableBadge : CompositeDrawable, IHasTooltip + public class DrawableBadge : OsuClickableContainer { public static readonly Vector2 DRAWABLE_BADGE_SIZE = new Vector2(86, 40); @@ -29,22 +27,25 @@ namespace osu.Game.Overlays.Profile.Header.Components } [BackgroundDependencyLoader] - private void load(LargeTextureStore textures) + private void load(LargeTextureStore textures, ILinkHandler? linkHandler) { - InternalChild = new Sprite + Child = new Sprite { FillMode = FillMode.Fit, RelativeSizeAxes = Axes.Both, Texture = textures.Get(badge.ImageUrl), }; + + if (!string.IsNullOrEmpty(badge.Url)) + Action = () => linkHandler?.HandleLink(badge.Url); } protected override void LoadComplete() { base.LoadComplete(); - InternalChild.FadeInFromZero(200); + this.FadeInFromZero(200); } - public LocalisableString TooltipText => badge.Description; + public override LocalisableString TooltipText => badge.Description; } } diff --git a/osu.Game/Users/Badge.cs b/osu.Game/Users/Badge.cs index c191c25895..b87e2ddecd 100644 --- a/osu.Game/Users/Badge.cs +++ b/osu.Game/Users/Badge.cs @@ -18,5 +18,8 @@ namespace osu.Game.Users [JsonProperty("image_url")] public string ImageUrl; + + [JsonProperty("url")] + public string Url; } } From c40c70509e1909fab2488120c9e867cb76f66827 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 15:14:09 +0900 Subject: [PATCH 2046/2686] Improve song select transition to gameplay --- osu.Game/Screens/Select/BeatmapCarousel.cs | 20 +++++++++++++++++ osu.Game/Screens/Select/SongSelect.cs | 26 +++++++++++++++++----- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 3b694dbf43..2f99f6acca 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -770,6 +770,26 @@ namespace osu.Game.Screens.Select { updateItem(item); + if (!item.Item.Filtered.Value) + { + bool isSelected = item.Item.State.Value == CarouselItemState.Selected; + + // Cheap way of doing animations when entering / exiting song select. + const double half_time = 50; + const float panel_x_offset_when_inactive = 200; + + if (isSelected || AllowSelection) + { + item.Alpha = (float)Interpolation.DampContinuously(item.Alpha, 1, half_time, Clock.ElapsedFrameTime); + item.X = (float)Interpolation.DampContinuously(item.X, 0, half_time, Clock.ElapsedFrameTime); + } + else + { + item.Alpha = (float)Interpolation.DampContinuously(item.Alpha, 0, half_time, Clock.ElapsedFrameTime); + item.X = (float)Interpolation.DampContinuously(item.X, panel_x_offset_when_inactive, half_time, Clock.ElapsedFrameTime); + } + } + if (item is DrawableCarouselBeatmapSet set) { foreach (var diff in set.DrawableBeatmaps) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index f5a058e945..fe9b67a02e 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -89,6 +89,8 @@ namespace osu.Game.Screens.Select protected BeatmapCarousel Carousel { get; private set; } + private ParallaxContainer wedgeBackground; + protected Container LeftArea { get; private set; } private BeatmapInfoWedge beatmapInfoWedge; @@ -165,10 +167,12 @@ namespace osu.Game.Screens.Select { new Drawable[] { - new ParallaxContainer + wedgeBackground = new ParallaxContainer { ParallaxAmount = 0.005f, RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Child = new WedgeBackground { RelativeSizeAxes = Axes.Both, @@ -609,9 +613,15 @@ namespace osu.Game.Screens.Select } } - this.FadeIn(250); + LeftArea.MoveToX(0, 400, Easing.OutQuint); + LeftArea.FadeIn(100, Easing.OutQuint); - this.ScaleTo(1, 250, Easing.OutSine); + FilterControl.MoveToY(0, 400, Easing.OutQuint); + FilterControl.FadeIn(100, Easing.OutQuint); + + this.FadeIn(250, Easing.OutQuint); + + wedgeBackground.ScaleTo(1, 500, Easing.OutQuint); FilterControl.Activate(); } @@ -629,9 +639,15 @@ namespace osu.Game.Screens.Select endLooping(); - this.ScaleTo(1.1f, 250, Easing.InSine); + FilterControl.MoveToY(-120, 250, Easing.OutQuint); + FilterControl.FadeOut(100); - this.FadeOut(250); + LeftArea.MoveToX(-150, 1800, Easing.OutQuint); + LeftArea.FadeOut(200, Easing.OutQuint); + + wedgeBackground.ScaleTo(2.4f, 400, Easing.OutQuint); + + this.FadeOut(400, Easing.OutQuint); FilterControl.Deactivate(); base.OnSuspending(e); From 819027d61c812ad29c7dc05b9d2175e964e2bc02 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 4 Nov 2022 16:17:49 +0900 Subject: [PATCH 2047/2686] Rename to `isConvert` --- .../Difficulty/TaikoPerformanceCalculator.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 317e4a2f72..2d1b2903c9 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; // TODO: The detection of rulesets is temporary until the leftover old skills have been reworked. - bool taikoSpecificBeatmap = score.BeatmapInfo.Ruleset.OnlineID == 1; + bool isConvert = score.BeatmapInfo.Ruleset.OnlineID != 1; double multiplier = 1.13; @@ -54,8 +54,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModEasy)) multiplier *= 0.975; - double difficultyValue = computeDifficultyValue(score, taikoAttributes, taikoSpecificBeatmap); - double accuracyValue = computeAccuracyValue(score, taikoAttributes, taikoSpecificBeatmap); + double difficultyValue = computeDifficultyValue(score, taikoAttributes, isConvert); + double accuracyValue = computeAccuracyValue(score, taikoAttributes, isConvert); double totalValue = Math.Pow( Math.Pow(difficultyValue, 1.1) + @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty }; } - private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool taikoSpecificBeatmap) + private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert) { double difficultyValue = Math.Pow(5 * Math.Max(1.0, attributes.StarRating / 0.115) - 4.0, 2.25) / 1150.0; @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModEasy)) difficultyValue *= 0.985; - if (score.Mods.Any(m => m is ModHidden) && taikoSpecificBeatmap) + if (score.Mods.Any(m => m is ModHidden) && !isConvert) difficultyValue *= 1.025; if (score.Mods.Any(m => m is ModHardRock)) @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty return difficultyValue * Math.Pow(accuracy, 2.0); } - private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool taikoSpecificBeatmap) + private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert) { if (attributes.GreatHitWindow <= 0) return 0; @@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty accuracyValue *= lengthBonus; // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values. - if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden) && taikoSpecificBeatmap) + if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden) && !isConvert) accuracyValue *= Math.Max(1.0, 1.1 * lengthBonus); return accuracyValue; From dd5a3b2bf37ed0859e739849952d72490b9509dc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 16:49:21 +0900 Subject: [PATCH 2048/2686] Add one more complex test --- .../Visual/Gameplay/TestSceneBezierConverter.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs index 701f30bfd4..28a9d17882 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs @@ -134,6 +134,17 @@ namespace osu.Game.Tests.Visual.Gameplay }); } + [Test] + public void TestComplex() + { + AddStep("create path", () => + { + path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(100, 0))); + path.ControlPoints.AddRange(createSegment(PathType.Bezier, new Vector2(100, 0), new Vector2(150, 30), new Vector2(100, 100))); + path.ControlPoints.AddRange(createSegment(PathType.PerfectCurve, new Vector2(100, 100), new Vector2(25, 50), Vector2.Zero)); + }); + } + [TestCase(0, 100)] [TestCase(1, 100)] [TestCase(5, 100)] From 923d44a769c3030e84f36227f33a2739d850dca6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 17:00:58 +0900 Subject: [PATCH 2049/2686] Update dependencies --- .../osu.Game.Rulesets.EmptyFreeform.Tests.csproj | 2 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 2 +- .../osu.Game.Rulesets.EmptyScrolling.Tests.csproj | 2 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 2 +- osu.Desktop/osu.Desktop.csproj | 2 +- osu.Game.Benchmarks/osu.Game.Benchmarks.csproj | 2 +- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- .../osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 4 ++-- .../osu.Game.Tournament.Tests.csproj | 2 +- osu.Game/osu.Game.csproj | 12 ++++++------ 13 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj index 936808f38b..52b728a115 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 35e7742172..95b96adab0 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj index c1044965b5..d12403016d 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 35e7742172..95b96adab0 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj index 3f926ed45a..1f4544098b 100644 --- a/osu.Desktop/osu.Desktop.csproj +++ b/osu.Desktop/osu.Desktop.csproj @@ -27,7 +27,7 @@ - + diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj index d62d422f33..f47b069373 100644 --- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj +++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj @@ -9,7 +9,7 @@ - + diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index c9db824615..5a2e8e0bf0 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -3,7 +3,7 @@ - + WinExe diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index 0d7b03d830..be51dc0e4c 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -3,7 +3,7 @@ - + WinExe diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 1eb1c85d93..c10c3ffb15 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -4,7 +4,7 @@ - + WinExe diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 38e61f5624..6af1beff69 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -3,7 +3,7 @@ - + WinExe diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index bdf8cc5136..24969414d0 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -1,11 +1,11 @@  - + - + diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index bdef46a6b2..9f2a088a4b 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -6,7 +6,7 @@ - + WinExe diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fe44ed3688..9a6866d264 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,10 +23,10 @@ - - - - + + + + @@ -34,10 +34,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + From 2b934e0beafbffda932574cf3fb17db4bb66e0b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 17:19:03 +0900 Subject: [PATCH 2050/2686] Increase delay for changing background on returning to main menu --- osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index f8546d6ed0..a7a763f2a6 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -95,7 +95,7 @@ namespace osu.Game.Screens.Backgrounds nextTask = Scheduler.AddDelayed(() => { LoadComponentAsync(nextBackground, displayNext, cancellationTokenSource.Token); - }, 100); + }, 500); return true; } From 4bbff99f315b23b34d88be8f90962e0f3053fafb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 17:35:30 +0900 Subject: [PATCH 2051/2686] Remove unnecessary fade in `SeasonalBackground` --- osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index 5c98e22818..9d873762bf 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -111,8 +111,6 @@ namespace osu.Game.Graphics.Backgrounds private void load(LargeTextureStore textures) { Sprite.Texture = textures.Get(url) ?? textures.Get(fallback_texture_name); - // ensure we're not loading in without a transition. - this.FadeInFromZero(200, Easing.InOutSine); } public override bool Equals(Background other) From 4f14ae4e34ad3f70d0c26dedc7448006025279ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 17:36:11 +0900 Subject: [PATCH 2052/2686] Adjust transition effect for main menu backgrounds --- osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index a7a763f2a6..44b6fcce4a 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -102,7 +102,7 @@ namespace osu.Game.Screens.Backgrounds private void displayNext(Background newBackground) { - background?.FadeOut(800, Easing.InOutSine); + background?.FadeOut(800, Easing.OutQuint); background?.Expire(); AddInternal(background = newBackground); From 58396d49dc9e44a7a3dcec75a969851fd7856451 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 4 Nov 2022 16:42:59 +0900 Subject: [PATCH 2053/2686] Fix handling of local echo deduplication --- .../CreateNewPrivateMessageRequest.cs | 1 + .../Online/API/Requests/PostMessageRequest.cs | 1 + osu.Game/Online/Chat/Channel.cs | 8 ++++ osu.Game/Online/Chat/ChannelManager.cs | 48 ++++++++++++------- osu.Game/Online/Chat/Message.cs | 6 +++ .../WebSocket/WebSocketNotificationsClient.cs | 10 ++-- 6 files changed, 51 insertions(+), 23 deletions(-) diff --git a/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs b/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs index dea94bfce2..6b7192dbf4 100644 --- a/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs +++ b/osu.Game/Online/API/Requests/CreateNewPrivateMessageRequest.cs @@ -28,6 +28,7 @@ namespace osu.Game.Online.API.Requests req.AddParameter(@"target_id", user.Id.ToString()); req.AddParameter(@"message", message.Content); req.AddParameter(@"is_action", message.IsAction.ToString().ToLowerInvariant()); + req.AddParameter(@"uuid", message.Uuid); return req; } diff --git a/osu.Game/Online/API/Requests/PostMessageRequest.cs b/osu.Game/Online/API/Requests/PostMessageRequest.cs index 7b20bd9ad5..e3709d8f13 100644 --- a/osu.Game/Online/API/Requests/PostMessageRequest.cs +++ b/osu.Game/Online/API/Requests/PostMessageRequest.cs @@ -25,6 +25,7 @@ namespace osu.Game.Online.API.Requests req.Method = HttpMethod.Post; req.AddParameter(@"is_action", Message.IsAction.ToString().ToLowerInvariant()); req.AddParameter(@"message", Message.Content); + req.AddParameter(@"uuid", Message.Uuid); return req; } diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index f51ea3e8d6..9bfaecc46b 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -134,6 +134,14 @@ namespace osu.Game.Online.Chat /// public void AddNewMessages(params Message[] messages) { + foreach (var m in messages) + { + LocalEchoMessage localEcho = pendingMessages.FirstOrDefault(local => local.Uuid == m.Uuid); + + if (localEcho != null) + ReplaceMessage(localEcho, m); + } + messages = messages.Except(Messages).ToArray(); if (messages.Length == 0) return; diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index a901c15bf4..05e2fb79e8 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -85,8 +85,21 @@ namespace osu.Game.Online.Chat [BackgroundDependencyLoader] private void load() { - connector.ChannelJoined += ch => Schedule(() => joinChannel(ch)); + connector.ChannelJoined += ch => Schedule(() => + { + var localChannel = getChannel(ch); + + if (localChannel != ch) + { + localChannel.Joined.Value = true; + localChannel.Id = ch.Id; + } + + joinChannel(localChannel); + }); + connector.NewMessages += msgs => Schedule(() => addMessages(msgs)); + connector.PresenceReceived += () => Schedule(() => { if (!channelsInitialised) @@ -189,7 +202,8 @@ namespace osu.Game.Online.Chat Timestamp = DateTimeOffset.Now, ChannelId = target.Id, IsAction = isAction, - Content = text + Content = text, + Uuid = Guid.NewGuid().ToString() }; target.AddLocalEcho(message); @@ -199,13 +213,7 @@ namespace osu.Game.Online.Chat { var createNewPrivateMessageRequest = new CreateNewPrivateMessageRequest(target.Users.First(), message); - createNewPrivateMessageRequest.Success += createRes => - { - target.Id = createRes.ChannelID; - target.ReplaceMessage(message, createRes.Message); - dequeueAndRun(); - }; - + createNewPrivateMessageRequest.Success += _ => dequeueAndRun(); createNewPrivateMessageRequest.Failure += exception => { handlePostException(exception); @@ -219,12 +227,7 @@ namespace osu.Game.Online.Chat var req = new PostMessageRequest(message); - req.Success += m => - { - target.ReplaceMessage(message, m); - dequeueAndRun(); - }; - + req.Success += m => dequeueAndRun(); req.Failure += exception => { handlePostException(exception); @@ -403,7 +406,20 @@ namespace osu.Game.Online.Chat { Channel found = null; - bool lookupCondition(Channel ch) => lookup.Id > 0 ? ch.Id == lookup.Id : lookup.Name == ch.Name; + bool lookupCondition(Channel ch) + { + // If both channels have an id, use that. + if (lookup.Id > 0 && ch.Id > 0) + return ch.Id == lookup.Id; + + // In the case that the local echo is received in a new channel (i.e. one that does not yet have an ID), + // then we need to check for any existing channel with the message containing the same message matched by UUID. + if (lookup.Messages.Count > 0 && ch.Messages.Any(m => m.Uuid == lookup.Messages.Last().Uuid)) + return true; + + // As a last resort, fallback to matching by name. + return lookup.Name == ch.Name; + } var available = AvailableChannels.FirstOrDefault(lookupCondition); if (available != null) diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 25c5b0853f..9f6f9c8d6b 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -37,6 +37,12 @@ namespace osu.Game.Online.Chat set => Sender = new APIUser { Id = value }; } + /// + /// A unique identifier for this message. Sent to and from osu!web to use for deduplication. + /// + [JsonProperty(@"uuid")] + public string Uuid { get; set; } = string.Empty; + [JsonConstructor] public Message() { diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index ff0941ecba..0a93081915 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -2,9 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Net.WebSockets; using System.Text; using System.Threading; @@ -126,12 +124,10 @@ namespace osu.Game.Online.Notifications.WebSocket NewChatMessageData? messageData = JsonConvert.DeserializeObject(message.Data.ToString()); Debug.Assert(messageData != null); - List messages = messageData.Messages.Where(m => m.Sender.OnlineID != api.LocalUser.Value.OnlineID).ToList(); + foreach (var msg in messageData.Messages) + HandleJoinedChannel(new Channel(msg.Sender) { Id = msg.ChannelId, Messages = { msg } }); - foreach (var msg in messages) - HandleJoinedChannel(new Channel(msg.Sender) { Id = msg.ChannelId }); - - HandleMessages(messages); + HandleMessages(messageData.Messages); break; } From 72745656e71ef3def43ca65b709a6c2f4000b1ca Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 4 Nov 2022 18:48:34 +0900 Subject: [PATCH 2054/2686] Remove StartChat()/chat enablement --- osu.Game/Online/Chat/ChannelManager.cs | 2 -- .../Notifications/NotificationsClient.cs | 24 +------------------ .../NotificationsClientConnector.cs | 11 --------- .../WebSocket/WebSocketNotificationsClient.cs | 13 ++++------ 4 files changed, 5 insertions(+), 45 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 05e2fb79e8..77d53911d9 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -110,8 +110,6 @@ namespace osu.Game.Online.Chat } }); - connector.StartChat(); - apiState.BindTo(api.State); apiState.BindValueChanged(status => { diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs index 5c575e828d..cb5e94fb1d 100644 --- a/osu.Game/Online/Notifications/NotificationsClient.cs +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -23,7 +23,6 @@ namespace osu.Game.Online.Notifications protected readonly IAPIProvider API; - private bool enableChat; private long lastMessageId; protected NotificationsClient(IAPIProvider api) @@ -31,28 +30,7 @@ namespace osu.Game.Online.Notifications API = api; } - public bool EnableChat - { - get => enableChat; - set - { - if (enableChat == value) - return; - - enableChat = value; - - if (EnableChat) - Task.Run(StartChatAsync); - } - } - - public override async Task ConnectAsync(CancellationToken cancellationToken) - { - if (EnableChat) - await StartChatAsync(); - } - - protected virtual Task StartChatAsync() + public override Task ConnectAsync(CancellationToken cancellationToken) { API.Queue(CreateFetchMessagesRequest(0)); return Task.CompletedTask; diff --git a/osu.Game/Online/Notifications/NotificationsClientConnector.cs b/osu.Game/Online/Notifications/NotificationsClientConnector.cs index 5aa49a7783..d4c846a7a2 100644 --- a/osu.Game/Online/Notifications/NotificationsClientConnector.cs +++ b/osu.Game/Online/Notifications/NotificationsClientConnector.cs @@ -19,21 +19,11 @@ namespace osu.Game.Online.Notifications public event Action>? NewMessages; public event Action? PresenceReceived; - private bool chatStarted; - protected NotificationsClientConnector(IAPIProvider api) : base(api) { } - public void StartChat() - { - chatStarted = true; - - if (CurrentConnection is NotificationsClient client) - client.EnableChat = true; - } - protected sealed override async Task BuildConnectionAsync(CancellationToken cancellationToken) { var client = await BuildNotificationClientAsync(cancellationToken); @@ -41,7 +31,6 @@ namespace osu.Game.Online.Notifications client.ChannelJoined = c => ChannelJoined?.Invoke(c); client.NewMessages = m => NewMessages?.Invoke(m); client.PresenceReceived = () => PresenceReceived?.Invoke(); - client.EnableChat = chatStarted; return client; } diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index 0a93081915..bc4ceea993 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -22,27 +22,22 @@ namespace osu.Game.Online.Notifications.WebSocket { private readonly ClientWebSocket socket; private readonly string endpoint; - private readonly IAPIProvider api; public WebSocketNotificationsClient(ClientWebSocket socket, string endpoint, IAPIProvider api) : base(api) { this.socket = socket; this.endpoint = endpoint; - this.api = api; } public override async Task ConnectAsync(CancellationToken cancellationToken) { await socket.ConnectAsync(new Uri(endpoint), cancellationToken).ConfigureAwait(false); - runReadLoop(cancellationToken); - await base.ConnectAsync(cancellationToken); - } - - protected override async Task StartChatAsync() - { await sendMessage(new StartChatRequest(), CancellationToken.None); - await base.StartChatAsync(); + + runReadLoop(cancellationToken); + + await base.ConnectAsync(cancellationToken); } private void runReadLoop(CancellationToken cancellationToken) => Task.Run(async () => From eb836269e765549f5c76e6c0ca733442842c5c25 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 18:50:17 +0900 Subject: [PATCH 2055/2686] Allow testing settings panel with interactivity by default --- .../Visual/Settings/TestSceneSettingsPanel.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs index 9791bb6248..ad60c98e05 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs @@ -35,13 +35,19 @@ namespace osu.Game.Tests.Visual.Settings State = { Value = Visibility.Visible } }); }); + } - AddStep("reset mouse", () => InputManager.MoveMouseTo(settings)); + [Test] + public void TestBasic() + { + AddStep("do nothing", () => { }); } [Test] public void TestFiltering([Values] bool beforeLoad) { + AddStep("reset mouse", () => InputManager.MoveMouseTo(settings)); + if (beforeLoad) AddStep("set filter", () => settings.SectionsContainer.ChildrenOfType().First().Current.Value = "scaling"); @@ -67,6 +73,8 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestFilterAfterLoad() { + AddStep("reset mouse", () => InputManager.MoveMouseTo(settings)); + AddUntilStep("wait for items to load", () => settings.SectionsContainer.ChildrenOfType().Any()); AddStep("set filter", () => settings.SectionsContainer.ChildrenOfType().First().Current.Value = "scaling"); @@ -75,6 +83,8 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void ToggleVisibility() { + AddStep("reset mouse", () => InputManager.MoveMouseTo(settings)); + AddWaitStep("wait some", 5); AddToggleStep("toggle visibility", _ => settings.ToggleVisibility()); } @@ -82,6 +92,8 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestTextboxFocusAfterNestedPanelBackButton() { + AddStep("reset mouse", () => InputManager.MoveMouseTo(settings)); + AddUntilStep("sections loaded", () => settings.SectionsContainer.Children.Count > 0); AddUntilStep("top-level textbox focused", () => settings.SectionsContainer.ChildrenOfType().FirstOrDefault()?.HasFocus == true); @@ -107,6 +119,8 @@ namespace osu.Game.Tests.Visual.Settings [Test] public void TestTextboxFocusAfterNestedPanelEscape() { + AddStep("reset mouse", () => InputManager.MoveMouseTo(settings)); + AddUntilStep("sections loaded", () => settings.SectionsContainer.Children.Count > 0); AddUntilStep("top-level textbox focused", () => settings.SectionsContainer.ChildrenOfType().FirstOrDefault()?.HasFocus == true); From fa18b5f7014671f13c0f4930b3ae740755952f07 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 4 Nov 2022 18:51:00 +0900 Subject: [PATCH 2056/2686] Construct notifications client inside ChannelManager --- osu.Game.Tests/Chat/TestSceneChannelManager.cs | 2 +- osu.Game.Tests/Visual/Online/TestSceneChatLink.cs | 2 +- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 2 +- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 2 +- .../Visual/Online/TestSceneStandAloneChatDisplay.cs | 2 +- .../Components/TournamentMatchChatDisplay.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 5 +++-- osu.Game/OsuGame.cs | 6 +----- 8 files changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index 86be638781..e7eb06c795 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -151,7 +151,7 @@ namespace osu.Game.Tests.Chat public ChannelManagerContainer(IAPIProvider apiProvider) { - InternalChild = ChannelManager = new ChannelManager(apiProvider, apiProvider.GetNotificationsConnector()); + InternalChild = ChannelManager = new ChannelManager(apiProvider); } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs index 5c46cd96be..de44986001 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Online { linkColour = colours.Blue; - var chatManager = new ChannelManager(API, API.GetNotificationsConnector()); + var chatManager = new ChannelManager(API); BindableList availableChannels = (BindableList)chatManager.AvailableChannels; availableChannels.Add(new Channel { Name = "#english" }); availableChannels.Add(new Channel { Name = "#japanese" }); diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 6b2124f1f8..0b982a5745 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Online RelativeSizeAxes = Axes.Both, CachedDependencies = new (Type, object)[] { - (typeof(ChannelManager), channelManager = new ChannelManager(API, API.GetNotificationsConnector())), + (typeof(ChannelManager), channelManager = new ChannelManager(API)), }, Children = new Drawable[] { diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index cb93812bc2..57514cdf37 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -250,7 +250,7 @@ namespace osu.Game.Tests.Visual.Online public TestContainer(IAPIProvider api, Channel[] channels) { this.channels = channels; - ChannelManager = new ChannelManager(api, api.GetNotificationsConnector()); + ChannelManager = new ChannelManager(api); } [BackgroundDependencyLoader] diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index 07196cc92a..34ecad7dc1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Online { var api = parent.Get(); - Add(channelManager = new ChannelManager(api, api.GetNotificationsConnector())); + Add(channelManager = new ChannelManager(api)); var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs index 48ff45974d..ca2b400e8b 100644 --- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tournament.Components if (manager == null) { - AddInternal(manager = new ChannelManager(api, api.GetNotificationsConnector())); + AddInternal(manager = new ChannelManager(api)); Channel.BindTo(manager.CurrentChannel); } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 77d53911d9..a9603506c6 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -74,10 +74,11 @@ namespace osu.Game.Online.Chat private bool channelsInitialised; private ScheduledDelegate ackDelegate; - public ChannelManager(IAPIProvider api, NotificationsClientConnector connector) + public ChannelManager(IAPIProvider api) { this.api = api; - this.connector = connector; + + connector = api.GetNotificationsConnector(); CurrentChannel.ValueChanged += currentChannelChanged; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f36d83d5c2..3a8f202d97 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -44,7 +44,6 @@ using osu.Game.Localisation; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -using osu.Game.Online.Notifications; using osu.Game.Overlays; using osu.Game.Overlays.Music; using osu.Game.Overlays.Notifications; @@ -84,7 +83,6 @@ namespace osu.Game private ChatOverlay chatOverlay; private ChannelManager channelManager; - private NotificationsClientConnector notificationsClient; [NotNull] protected readonly NotificationOverlay Notifications = new NotificationOverlay(); @@ -680,7 +678,6 @@ namespace osu.Game { base.Dispose(isDisposing); SentryLogger.Dispose(); - notificationsClient.Dispose(); } protected override IDictionary GetFrameworkConfigDefaults() @@ -758,7 +755,6 @@ namespace osu.Game BackButton.Receptor receptor; dependencies.CacheAs(idleTracker = new GameIdleTracker(6000)); - dependencies.CacheAs(notificationsClient = API.GetNotificationsConnector()); var sessionIdleTracker = new GameIdleTracker(300000); sessionIdleTracker.IsIdle.BindValueChanged(idle => @@ -885,7 +881,7 @@ namespace osu.Game loadComponentSingleFile(dashboard = new DashboardOverlay(), overlayContent.Add, true); loadComponentSingleFile(news = new NewsOverlay(), overlayContent.Add, true); var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true); - loadComponentSingleFile(channelManager = new ChannelManager(API, notificationsClient), AddInternal, true); + loadComponentSingleFile(channelManager = new ChannelManager(API), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(new MessageNotifier(), AddInternal, true); loadComponentSingleFile(Settings = new SettingsOverlay(), leftFloatingOverlayContent.Add, true); From 8b58475ee04dcbd1ffd59b11736a7c79197df2be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 18:50:42 +0900 Subject: [PATCH 2057/2686] Update `OsuButton` hover animation to better suit immediacy of sound effects --- osu.Game/Graphics/UserInterface/OsuButton.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 88f3ccd191..9140815f32 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -4,7 +4,6 @@ #nullable disable using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -95,7 +94,7 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Colour = Color4.White.Opacity(.1f), + Colour = Color4.White, Blending = BlendingParameters.Additive, Depth = float.MinValue }, @@ -126,7 +125,7 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnClick(ClickEvent e) { if (Enabled.Value) - Background.FlashColour(BackgroundColour.Lighten(0.4f), 200); + Background.FlashColour(Color4.White, 800, Easing.OutQuint); return base.OnClick(e); } @@ -134,7 +133,11 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnHover(HoverEvent e) { if (Enabled.Value) - Hover.FadeIn(200, Easing.OutQuint); + { + Hover.FadeTo(0.2f, 40, Easing.OutQuint) + .Then() + .FadeTo(0.1f, 800, Easing.OutQuint); + } return base.OnHover(e); } @@ -143,7 +146,7 @@ namespace osu.Game.Graphics.UserInterface { base.OnHoverLost(e); - Hover.FadeOut(300); + Hover.FadeOut(800, Easing.OutQuint); } protected override bool OnMouseDown(MouseDownEvent e) From 66bbe3411628b0b9664e66ec66f15d241843b1bc Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 4 Nov 2022 18:52:57 +0900 Subject: [PATCH 2058/2686] Move polling clients to osu.Game.Tests namespace --- osu.Game/Online/API/DummyAPIAccess.cs | 2 +- .../Polling => Tests}/PollingNotificationsClient.cs | 3 ++- .../Polling => Tests}/PollingNotificationsClientConnector.cs | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) rename osu.Game/{Online/Notifications/Polling => Tests}/PollingNotificationsClient.cs (94%) rename osu.Game/{Online/Notifications/Polling => Tests}/PollingNotificationsClientConnector.cs (92%) diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 865e1e0a70..609efd8ab6 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -10,7 +10,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Notifications; -using osu.Game.Online.Notifications.Polling; +using osu.Game.Tests; using osu.Game.Users; namespace osu.Game.Online.API diff --git a/osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs b/osu.Game/Tests/PollingNotificationsClient.cs similarity index 94% rename from osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs rename to osu.Game/Tests/PollingNotificationsClient.cs index 2f343abf86..c1f032a647 100644 --- a/osu.Game/Online/Notifications/Polling/PollingNotificationsClient.cs +++ b/osu.Game/Tests/PollingNotificationsClient.cs @@ -4,8 +4,9 @@ using System.Threading; using System.Threading.Tasks; using osu.Game.Online.API; +using osu.Game.Online.Notifications; -namespace osu.Game.Online.Notifications.Polling +namespace osu.Game.Tests { /// /// A notifications client which polls for new messages every second. diff --git a/osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs b/osu.Game/Tests/PollingNotificationsClientConnector.cs similarity index 92% rename from osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs rename to osu.Game/Tests/PollingNotificationsClientConnector.cs index ff3f30edcd..823fc9d157 100644 --- a/osu.Game/Online/Notifications/Polling/PollingNotificationsClientConnector.cs +++ b/osu.Game/Tests/PollingNotificationsClientConnector.cs @@ -4,8 +4,9 @@ using System.Threading; using System.Threading.Tasks; using osu.Game.Online.API; +using osu.Game.Online.Notifications; -namespace osu.Game.Online.Notifications.Polling +namespace osu.Game.Tests { /// /// A connector for s that poll for new messages. From 1d2818dc70dbafecb5a60db70c9229917bdcc487 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 4 Nov 2022 19:02:26 +0900 Subject: [PATCH 2059/2686] Reschedule ack request on completion --- osu.Game/Online/Chat/ChannelManager.cs | 32 ++++++++++++++++++-------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index a9603506c6..035957a7c4 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -72,7 +72,7 @@ namespace osu.Game.Online.Chat private readonly IBindable apiState = new Bindable(); private bool channelsInitialised; - private ScheduledDelegate ackDelegate; + private ScheduledDelegate scheduledAck; public ChannelManager(IAPIProvider api) { @@ -112,16 +112,28 @@ namespace osu.Game.Online.Chat }); apiState.BindTo(api.State); - apiState.BindValueChanged(status => - { - ackDelegate?.Cancel(); + apiState.BindValueChanged(_ => performChatAckRequest(), true); + } - if (status.NewValue == APIState.Online) - { - Scheduler.Add(ackDelegate = new ScheduledDelegate(() => api.Queue(new ChatAckRequest()), 0, 60000)); - // Todo: Handle silences. - } - }, true); + private void performChatAckRequest() + { + if (apiState.Value != APIState.Online) + return; + + scheduledAck?.Cancel(); + + var req = new ChatAckRequest(); + req.Success += _ => scheduleNextRequest(); + req.Failure += _ => scheduleNextRequest(); + api.Queue(req); + + // Todo: Handle silences. + + void scheduleNextRequest() + { + scheduledAck?.Cancel(); + scheduledAck = Scheduler.AddDelayed(performChatAckRequest, 60000); + } } /// From a16540dc6d440f6a368b98ff6b474881eb77e5a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 18:50:52 +0900 Subject: [PATCH 2060/2686] Update `Nub` hover animation to better suit immediacy of sound effects --- osu.Game/Graphics/UserInterface/Nub.cs | 34 ++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 7a3e54ddf1..80e012f596 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -27,9 +27,6 @@ namespace osu.Game.Graphics.UserInterface private const float border_width = 3; - private const double animate_in_duration = 200; - private const double animate_out_duration = 500; - private readonly Box fill; private readonly Container main; @@ -72,7 +69,7 @@ namespace osu.Game.Graphics.UserInterface Colour = GlowColour.Opacity(0), Type = EdgeEffectType.Glow, Radius = 8, - Roundness = 5, + Roundness = 4, }; } @@ -94,13 +91,18 @@ namespace osu.Game.Graphics.UserInterface if (value) { - main.FadeColour(GlowingAccentColour, animate_in_duration, Easing.OutQuint); - main.FadeEdgeEffectTo(0.2f, animate_in_duration, Easing.OutQuint); + main.FadeColour(GlowingAccentColour.Lighten(0.5f), 40, Easing.OutQuint) + .Then() + .FadeColour(GlowingAccentColour, 800, Easing.OutQuint); + + main.FadeEdgeEffectTo(Color4.White.Opacity(0.1f), 40, Easing.OutQuint) + .Then() + .FadeEdgeEffectTo(GlowColour.Opacity(0.1f), 800, Easing.OutQuint); } else { - main.FadeEdgeEffectTo(0, animate_out_duration, Easing.OutQuint); - main.FadeColour(AccentColour, animate_out_duration, Easing.OutQuint); + main.FadeEdgeEffectTo(GlowColour.Opacity(0), 800, Easing.OutQuint); + main.FadeColour(AccentColour, 800, Easing.OutQuint); } } } @@ -163,14 +165,20 @@ namespace osu.Game.Graphics.UserInterface private void onCurrentValueChanged(ValueChangedEvent filled) { - fill.FadeTo(filled.NewValue ? 1 : 0, 200, Easing.OutQuint); + const double duration = 200; + + fill.FadeTo(filled.NewValue ? 1 : 0, duration, Easing.OutQuint); if (filled.NewValue) - main.ResizeWidthTo(1, animate_in_duration, Easing.OutElasticHalf); + { + main.ResizeWidthTo(1, duration, Easing.OutElasticHalf); + main.TransformTo(nameof(BorderThickness), filled.NewValue ? 8.5f : border_width, duration, Easing.OutElasticHalf); + } else - main.ResizeWidthTo(0.9f, animate_out_duration, Easing.OutElastic); - - main.TransformTo(nameof(BorderThickness), filled.NewValue ? 8.5f : border_width, 200, Easing.OutQuint); + { + main.ResizeWidthTo(0.75f, duration, Easing.OutQuint); + main.TransformTo(nameof(BorderThickness), border_width, duration, Easing.OutQuint); + } } } } From a2fdad4afcf8c8ee2569929ab18fd54f8bac2616 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 18:52:32 +0900 Subject: [PATCH 2061/2686] Fix slider updating glow when disabled --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 392740690a..52b907707a 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -159,7 +159,8 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnHover(HoverEvent e) { - updateGlow(); + if (!Current.Disabled) + updateGlow(); return base.OnHover(e); } From 0e350f52f5f644402aa609df9ce20b1a693ca937 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 18:58:20 +0900 Subject: [PATCH 2062/2686] Fix `SliderBar` disabled value potentially not transferring to hover sounds --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 52b907707a..d7f308c45d 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -131,8 +131,6 @@ namespace osu.Game.Graphics.UserInterface }, hoverClickSounds = new HoverClickSounds() }; - - Current.DisabledChanged += disabled => { Alpha = disabled ? 0.3f : 1; }; } [BackgroundDependencyLoader(true)] @@ -154,7 +152,12 @@ namespace osu.Game.Graphics.UserInterface { base.LoadComplete(); CurrentNumber.BindValueChanged(current => TooltipText = getTooltipText(current.NewValue), true); - Current.DisabledChanged += disabled => hoverClickSounds.Enabled.Value = !disabled; + + Current.BindDisabledChanged(disabled => + { + Alpha = disabled ? 0.3f : 1; + hoverClickSounds.Enabled.Value = !disabled; + }, true); } protected override bool OnHover(HoverEvent e) From 78bb940e6ce5df325d399146915010439513f37f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 19:01:24 +0900 Subject: [PATCH 2063/2686] Don't play hover sounds on disabled elements --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 89d1570cd4..99cec7411c 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -58,6 +58,14 @@ namespace osu.Game.Graphics.UserInterface return base.OnClick(e); } + public override void PlayHoverSample() + { + if (!Enabled.Value) + return; + + base.PlayHoverSample(); + } + [BackgroundDependencyLoader] private void load(AudioManager audio) { From f12ada9d9247db0fee8cad42d7418bef011db179 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 4 Nov 2022 19:36:24 +0900 Subject: [PATCH 2064/2686] Fix chat connecting too early --- osu.Game/Online/Chat/ChannelManager.cs | 2 ++ osu.Game/Online/HubClientConnector.cs | 3 +++ .../Online/PersistentEndpointClientConnector.cs | 13 ++++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 035957a7c4..db2436333b 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -111,6 +111,8 @@ namespace osu.Game.Online.Chat } }); + connector.Start(); + apiState.BindTo(api.State); apiState.BindValueChanged(_ => performChatAckRequest(), true); } diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index 6f246f6dd3..ca6d2932f7 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -49,6 +49,9 @@ namespace osu.Game.Online this.api = api; this.versionHash = versionHash; this.preferMessagePack = preferMessagePack; + + // Automatically start these connections. + Start(); } protected override Task BuildConnectionAsync(CancellationToken cancellationToken) diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index 11e8e870d6..2c4e127723 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -29,6 +29,7 @@ namespace osu.Game.Online private readonly Bindable isConnected = new Bindable(); private readonly SemaphoreSlim connectionLock = new SemaphoreSlim(1); private CancellationTokenSource connectCancelSource = new CancellationTokenSource(); + private bool started; /// /// Constructs a new . @@ -37,9 +38,19 @@ namespace osu.Game.Online protected PersistentEndpointClientConnector(IAPIProvider api) { API = api; - apiState.BindTo(api.State); + } + + /// + /// Attempts to connect and begins processing messages from the remote endpoint. + /// + public void Start() + { + if (started) + return; + apiState.BindValueChanged(_ => Task.Run(connectIfPossible), true); + started = true; } public Task Reconnect() From 20021551bb1ee3c4074075cea11da769e49e9e66 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 19:36:59 +0900 Subject: [PATCH 2065/2686] Fix editor selection behaviour regressions due to new path visualiser optimisation --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 36ee7c2460..434e8f5012 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -119,10 +119,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { updateVisualDefinition(); - // In the case more than a single object is selected, block hover from arriving at sliders behind this one. - // Without doing this, the path visualisers of potentially hundreds of sliders will render, which is not only - // visually noisy but also functionally useless. - return !hasSingleObjectSelected; + return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) @@ -148,7 +145,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void updateVisualDefinition() { // To reduce overhead of drawing these blueprints, only add extra detail when hovered or when only this slider is selected. - if (IsSelected && (hasSingleObjectSelected || IsHovered)) + if (IsSelected && selectedObjects.Count == 1) { if (ControlPointVisualiser == null) { From d426977f038f0e83e9c15ca952433f51ac654a02 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 4 Nov 2022 20:11:42 +0900 Subject: [PATCH 2066/2686] Handle channel joins --- .../WebSocket/WebSocketNotificationsClient.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index bc4ceea993..eefe684795 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -113,6 +113,15 @@ namespace osu.Game.Online.Notifications.WebSocket { switch (message.Event) { + case @"chat.channel.join": + Debug.Assert(message.Data != null); + + Channel? joinedChannel = JsonConvert.DeserializeObject(message.Data.ToString()); + Debug.Assert(joinedChannel != null); + + HandleJoinedChannel(joinedChannel); + break; + case @"chat.message.new": Debug.Assert(message.Data != null); From 36c08b69fe2ca08cb6a20cfec9a939fa6cde8892 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 4 Nov 2022 20:47:49 +0900 Subject: [PATCH 2067/2686] Fix failing tests --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 434e8f5012..402858b702 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -105,8 +105,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders return true; } - private bool hasSingleObjectSelected => selectedObjects.Count == 1; - protected override void Update() { base.Update(); @@ -145,7 +143,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void updateVisualDefinition() { // To reduce overhead of drawing these blueprints, only add extra detail when hovered or when only this slider is selected. - if (IsSelected && selectedObjects.Count == 1) + if (IsSelected && selectedObjects.Count < 2) { if (ControlPointVisualiser == null) { From bd512c493729fb0e8e5da9e3f911d3cab0169074 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 4 Nov 2022 19:01:52 +0300 Subject: [PATCH 2068/2686] Remove equality comparison implementation from `BeatmapCard` This turned out to be a hurdle instead as it disallows adding two beatmap cards of equal beatmap, which, while being a good behaviour in client, makes tests more complicated to work. --- osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs index 70312a1535..b9e0a4e6cb 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Beatmaps.Drawables.Cards { - public abstract class BeatmapCard : OsuClickableContainer, IEquatable + public abstract class BeatmapCard : OsuClickableContainer { public const float TRANSITION_DURATION = 400; public const float CORNER_RADIUS = 10; @@ -96,16 +96,5 @@ namespace osu.Game.Beatmaps.Drawables.Cards throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size"); } } - - public bool Equals(BeatmapCard? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - - return BeatmapSet.Equals(other.BeatmapSet); - } - - public override bool Equals(object obj) => obj is BeatmapCard other && Equals(other); - public override int GetHashCode() => BeatmapSet.GetHashCode(); } } From ce5aacb76049b3e815d4ef2248190a5549f02033 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 4 Nov 2022 19:05:03 +0300 Subject: [PATCH 2069/2686] Filter out duplicated cards using custom equality comparer instead --- osu.Game/Overlays/BeatmapListingOverlay.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index c73936da8a..32e1a00675 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -180,7 +180,7 @@ namespace osu.Game.Overlays // new results may contain beatmaps from a previous page, // this is dodgy but matches web behaviour for now. // see: https://github.com/ppy/osu-web/issues/9270 - newCards = newCards.Except(foundContent); + newCards = newCards.Except(foundContent, BeatmapCardEqualityComparer.Default); panelLoadTask = LoadComponentsAsync(newCards, loaded => { @@ -394,5 +394,21 @@ namespace osu.Game.Overlays if (shouldShowMore) filterControl.FetchNextPage(); } + + private class BeatmapCardEqualityComparer : IEqualityComparer + { + public static BeatmapCardEqualityComparer Default { get; } = new BeatmapCardEqualityComparer(); + + public bool Equals(BeatmapCard x, BeatmapCard y) + { + if (ReferenceEquals(x, y)) return true; + if (ReferenceEquals(x, null)) return false; + if (ReferenceEquals(y, null)) return false; + + return x.BeatmapSet.Equals(y.BeatmapSet); + } + + public int GetHashCode(BeatmapCard obj) => obj.BeatmapSet.GetHashCode(); + } } } From ee6f036c44f80f72007e281537093f30a419dbfe Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 4 Nov 2022 19:35:00 +0300 Subject: [PATCH 2070/2686] Add note about using `ExceptBy` once it's available --- osu.Game/Overlays/BeatmapListingOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 32e1a00675..c278c9cb93 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -180,6 +180,8 @@ namespace osu.Game.Overlays // new results may contain beatmaps from a previous page, // this is dodgy but matches web behaviour for now. // see: https://github.com/ppy/osu-web/issues/9270 + // todo: replace custom equality compraer with ExceptBy in net6.0 + // newCards = newCards.ExceptBy(foundContent.Select(c => c.BeatmapSet.OnlineID), c => c.BeatmapSet.OnlineID); newCards = newCards.Except(foundContent, BeatmapCardEqualityComparer.Default); panelLoadTask = LoadComponentsAsync(newCards, loaded => From 6c819cba02ac834a2ba3b88f154082be91798525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 4 Nov 2022 19:45:36 +0100 Subject: [PATCH 2071/2686] Add test coverage for regressed scenarios --- .../Editor/TestSceneOsuComposerSelection.cs | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs new file mode 100644 index 0000000000..800e6c0711 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs @@ -0,0 +1,117 @@ +// 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.Linq; +using NUnit.Framework; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components; +using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Tests.Beatmaps; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Rulesets.Osu.Tests.Editor +{ + [TestFixture] + public class TestSceneOsuComposerSelection : TestSceneOsuEditor + { + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false); + + [Test] + public void TestContextMenuShownCorrectlyForSelectedSlider() + { + var slider = new Slider + { + StartTime = 0, + Position = new Vector2(100, 100), + Path = new SliderPath + { + ControlPoints = + { + new PathControlPoint(), + new PathControlPoint(new Vector2(100)) + } + } + }; + AddStep("add slider", () => EditorBeatmap.Add(slider)); + + moveMouseToObject(() => slider); + AddStep("left click", () => InputManager.Click(MouseButton.Left)); + AddUntilStep("slider selected", () => EditorBeatmap.SelectedHitObjects.Single() == slider); + + AddStep("move mouse to centre", () => InputManager.MoveMouseTo(blueprintContainer.ChildrenOfType().Single().ScreenSpaceDrawQuad.Centre)); + AddStep("right click", () => InputManager.Click(MouseButton.Right)); + AddUntilStep("context menu is visible", () => contextMenuContainer.ChildrenOfType().Single().State == MenuState.Open); + } + + [Test] + public void TestSelectionIncludingSliderPreservedOnClick() + { + var firstSlider = new Slider + { + StartTime = 0, + Position = new Vector2(0, 0), + Path = new SliderPath + { + ControlPoints = + { + new PathControlPoint(), + new PathControlPoint(new Vector2(100)) + } + } + }; + var secondSlider = new Slider + { + StartTime = 1000, + Position = new Vector2(100, 100), + Path = new SliderPath + { + ControlPoints = + { + new PathControlPoint(), + new PathControlPoint(new Vector2(100, -100)) + } + } + }; + var hitCircle = new HitCircle + { + StartTime = 200, + Position = new Vector2(300, 0) + }; + + AddStep("add objects", () => EditorBeatmap.AddRange(new HitObject[] { firstSlider, secondSlider, hitCircle })); + AddStep("select last 2 objects", () => EditorBeatmap.SelectedHitObjects.AddRange(new HitObject[] { secondSlider, hitCircle })); + + moveMouseToObject(() => secondSlider); + AddStep("click left mouse", () => InputManager.Click(MouseButton.Left)); + AddAssert("selection preserved", () => EditorBeatmap.SelectedHitObjects.Count == 2); + } + + private ComposeBlueprintContainer blueprintContainer + => Editor.ChildrenOfType().First(); + + private ContextMenuContainer contextMenuContainer + => Editor.ChildrenOfType().First(); + + private void moveMouseToObject(Func targetFunc) + { + AddStep("move mouse to object", () => + { + var pos = blueprintContainer.SelectionBlueprints + .First(s => s.Item == targetFunc()) + .ChildrenOfType() + .First().ScreenSpaceDrawQuad.Centre; + + InputManager.MoveMouseTo(pos); + }); + } + } +} From 23134aea612e12b666586bd5024463c7cfabd37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 4 Nov 2022 19:48:19 +0100 Subject: [PATCH 2072/2686] Update outdated comment --- .../Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 402858b702..3718f0c6bc 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -142,7 +142,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void updateVisualDefinition() { - // To reduce overhead of drawing these blueprints, only add extra detail when hovered or when only this slider is selected. + // To reduce overhead of drawing these blueprints, only add extra detail when only this slider is selected. if (IsSelected && selectedObjects.Count < 2) { if (ControlPointVisualiser == null) From b8438dc788b144c30baf3c552d9333b4fe2d309c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 4 Nov 2022 20:01:21 +0100 Subject: [PATCH 2073/2686] Fix realm package downgrade issue in mobile projects --- osu.Android.props | 2 +- osu.iOS.props | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index b3c48da2bf..b6ddeeb41a 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -56,6 +56,6 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index b5b488d82e..b2854d7ddd 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -87,6 +87,6 @@ - + From 5931e965c5818f018950cdf505fed18ae687c05b Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 5 Nov 2022 16:16:26 +0800 Subject: [PATCH 2074/2686] Mark background prams in the `getMockWorkingBeatmap()` as nun-nullable because technically it should not accept the null background. --- .../Editing/Checks/CheckBackgroundQualityTest.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs index 1aead6d78c..295a10ba5b 100644 --- a/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckBackgroundQualityTest.cs @@ -6,7 +6,6 @@ using System.IO; using System.Linq; using Moq; using NUnit.Framework; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Rendering.Dummy; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; @@ -46,7 +45,7 @@ namespace osu.Game.Tests.Editing.Checks { // While this is a problem, it is out of scope for this check and is caught by a different one. beatmap.Metadata.BackgroundFile = string.Empty; - var context = getContext(null, new MemoryStream(Array.Empty())); + var context = getContext(null!, new MemoryStream(Array.Empty())); Assert.That(check.Run(context), Is.Empty); } @@ -116,7 +115,7 @@ namespace osu.Game.Tests.Editing.Checks stream.Verify(x => x.Close(), Times.Once()); } - private BeatmapVerifierContext getContext(Texture? background, Stream? stream = null) + private BeatmapVerifierContext getContext(Texture background, Stream? stream = null) { return new BeatmapVerifierContext(beatmap, getMockWorkingBeatmap(background, stream).Object); } @@ -126,13 +125,13 @@ namespace osu.Game.Tests.Editing.Checks /// /// The texture of the background. /// The stream representing the background file. - private Mock getMockWorkingBeatmap(Texture? background, Stream? stream = null) + private Mock getMockWorkingBeatmap(Texture background, Stream? stream = null) { stream ??= new MemoryStream(new byte[1024 * 1024]); var mock = new Mock(); mock.SetupGet(w => w.Beatmap).Returns(beatmap); - mock.SetupGet(w => w.Background).Returns(background.AsNonNull()); + mock.SetupGet(w => w.Background).Returns(background); mock.Setup(w => w.GetStream(It.IsAny())).Returns(stream); return mock; From 6062641bf4862f43bcc10378e741e2ab4eaf8d77 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 5 Nov 2022 16:17:20 +0800 Subject: [PATCH 2075/2686] Mark mock track as nun-nullable because technically it should not accept the null track. --- osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs index 8e269cbab2..61ee6a3663 100644 --- a/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckAudioQualityTest.cs @@ -5,7 +5,6 @@ using System.Linq; using Moq; using NUnit.Framework; using osu.Framework.Audio.Track; -using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; @@ -42,7 +41,7 @@ namespace osu.Game.Tests.Editing.Checks var mock = new Mock(); mock.SetupGet(w => w.Beatmap).Returns(beatmap); - mock.SetupGet(w => w.Track).Returns(default(Track?).AsNonNull()); + mock.SetupGet(w => w.Track).Returns((Track)null!); Assert.That(check.Run(new BeatmapVerifierContext(beatmap, mock.Object)), Is.Empty); } From 4d4d7cf863574619ec41902b9e5bffb181d4635d Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 5 Nov 2022 16:41:35 +0800 Subject: [PATCH 2076/2686] Remove nullable disable annotation in the cache ruleset. --- .../Editor/Checks/TestCheckBananaShowerGap.cs | 4 +--- osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.cs b/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.cs index 16361d12c6..ef34a5d664 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/Checks/TestCheckBananaShowerGap.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -18,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor.Checks [TestFixture] public class TestCheckBananaShowerGap { - private CheckBananaShowerGap check; + private CheckBananaShowerGap check = null!; [SetUp] public void Setup() diff --git a/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs b/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs index 00fd74c9a8..4b2933c0e1 100644 --- a/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.cs +++ b/osu.Game.Rulesets.Catch/Edit/Checks/CheckBananaShowerGap.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. -#nullable disable - using System; using System.Collections.Generic; using osu.Game.Beatmaps; From b0673636cae8b341d3f99a9ed6fc1318d2754341 Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 5 Nov 2022 16:44:10 +0800 Subject: [PATCH 2077/2686] Remove nullable disable annotation in the osu ruleset. --- .../Editor/Checks/CheckLowDiffOverlapsTest.cs | 4 +--- .../Editor/Checks/CheckOffscreenObjectsTest.cs | 4 +--- .../Editor/Checks/CheckTimeDistanceEqualityTest.cs | 4 +--- .../Editor/Checks/CheckTooShortSlidersTest.cs | 4 +--- .../Editor/Checks/CheckTooShortSpinnersTest.cs | 6 ++---- osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs | 2 -- osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs | 2 -- .../Edit/Checks/CheckTimeDistanceEquality.cs | 2 -- osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.cs | 2 -- osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs | 2 -- 10 files changed, 6 insertions(+), 26 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckLowDiffOverlapsTest.cs b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckLowDiffOverlapsTest.cs index 7a361b0821..d035d2bc17 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckLowDiffOverlapsTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckLowDiffOverlapsTest.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using Moq; @@ -21,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks [TestFixture] public class CheckLowDiffOverlapsTest { - private CheckLowDiffOverlaps check; + private CheckLowDiffOverlaps check = null!; [SetUp] public void Setup() diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckOffscreenObjectsTest.cs b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckOffscreenObjectsTest.cs index a778b76c67..a72aaa966c 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckOffscreenObjectsTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckOffscreenObjectsTest.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -23,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks { private static readonly Vector2 playfield_centre = OsuPlayfield.BASE_SIZE * 0.5f; - private CheckOffscreenObjects check; + private CheckOffscreenObjects check = null!; [SetUp] public void Setup() diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTimeDistanceEqualityTest.cs b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTimeDistanceEqualityTest.cs index 4e8be75779..348243326d 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTimeDistanceEqualityTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTimeDistanceEqualityTest.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using Moq; @@ -21,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks [TestFixture] public class CheckTimeDistanceEqualityTest { - private CheckTimeDistanceEquality check; + private CheckTimeDistanceEquality check = null!; [SetUp] public void Setup() diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSlidersTest.cs b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSlidersTest.cs index 39a9d5e798..2ec3637bb7 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSlidersTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSlidersTest.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -20,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks [TestFixture] public class CheckTooShortSlidersTest { - private CheckTooShortSliders check; + private CheckTooShortSliders check = null!; [SetUp] public void Setup() diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSpinnersTest.cs b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSpinnersTest.cs index d044ae732a..f215255bab 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSpinnersTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/Checks/CheckTooShortSpinnersTest.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -19,8 +17,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor.Checks [TestFixture] public class CheckTooShortSpinnersTest { - private CheckTooShortSpinners check; - private IBeatmapDifficultyInfo difficulty; + private CheckTooShortSpinners check = null!; + private IBeatmapDifficultyInfo difficulty = null!; [SetUp] public void Setup() diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs index 57e6a6ad1d..084a3e5ea1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckLowDiffOverlaps.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs index af3521c35c..a342c2a821 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckOffscreenObjects.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Checks.Components; diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.cs index 753ddba710..585bd35bd9 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTimeDistanceEquality.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.cs index 75eeb91918..159498c479 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSliders.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; diff --git a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs index 6b4dc01ab1..f0aade1b7f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.cs +++ b/osu.Game.Rulesets.Osu/Edit/Checks/CheckTooShortSpinners.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Checks.Components; From e862ba5e04d9e5d8cb3c4b96025124fd0931ff7d Mon Sep 17 00:00:00 2001 From: andy840119 Date: Sat, 5 Nov 2022 20:13:50 +0800 Subject: [PATCH 2078/2686] Fix the wrong `AsNonNull()` usage. --- osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs b/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs index 7c2b1690af..a39ef22b72 100644 --- a/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckZeroByteFilesTest.cs @@ -5,7 +5,6 @@ using System.IO; using System.Linq; using Moq; using NUnit.Framework; -using osu.Framework.Extensions.ObjectExtensions; using osu.Game.Beatmaps; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Checks; @@ -73,7 +72,7 @@ namespace osu.Game.Tests.Editing.Checks private BeatmapVerifierContext getContextMissing() { var mockWorkingBeatmap = new Mock(); - mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns(default(Stream?).AsNonNull()); + mockWorkingBeatmap.Setup(w => w.GetStream(It.IsAny())).Returns((Stream)null!); return new BeatmapVerifierContext(beatmap, mockWorkingBeatmap.Object); } From f8684f3e76df389d16ad5f694d03a8e0e03a2838 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 5 Nov 2022 22:43:26 +0900 Subject: [PATCH 2079/2686] Add script helpers to use local framework --- UseLocalFramework.ps1 | 11 +++++++++++ UseLocalFramework.sh | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 UseLocalFramework.ps1 create mode 100755 UseLocalFramework.sh diff --git a/UseLocalFramework.ps1 b/UseLocalFramework.ps1 new file mode 100644 index 0000000000..b4e240c09b --- /dev/null +++ b/UseLocalFramework.ps1 @@ -0,0 +1,11 @@ +# Run this script to use a local copy of osu-framework rather than fetching it from nuget. +# It expects the osu-framework directory to be at the same level as the osu directory +# +# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects + +$CSPROJ="osu.Game/osu.Game.csproj" +$SLN="osu.sln" + +dotnet remove $CSPROJ package ppy.osu.Framework; +dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj; +dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj diff --git a/UseLocalFramework.sh b/UseLocalFramework.sh new file mode 100755 index 0000000000..4fd1fdfd1b --- /dev/null +++ b/UseLocalFramework.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +# Run this script to use a local copy of osu-framework rather than fetching it from nuget. +# It expects the osu-framework directory to be at the same level as the osu directory +# +# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects + +CSPROJ="osu.Game/osu.Game.csproj" +SLN="osu.sln" + +dotnet remove $CSPROJ package ppy.osu.Framework +dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj +dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj + +SLNF="osu.Desktop.slnf" +tmp=$(mktemp) +jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj"]' osu.Desktop.slnf > $tmp +mv -f $tmp $SLNF From 230009570e4b3409519376fd9cc1f600dddfd16a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 5 Nov 2022 16:23:12 +0100 Subject: [PATCH 2080/2686] Add slnf support to powershell local framework script --- UseLocalFramework.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/UseLocalFramework.ps1 b/UseLocalFramework.ps1 index b4e240c09b..837685f310 100644 --- a/UseLocalFramework.ps1 +++ b/UseLocalFramework.ps1 @@ -9,3 +9,9 @@ $SLN="osu.sln" dotnet remove $CSPROJ package ppy.osu.Framework; dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj; dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj + +$SLNF=Get-Content "osu.Desktop.slnf" | ConvertFrom-Json +$TMP=New-TemporaryFile +$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj") +ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8 +Move-Item -Path $TMP -Destination "osu.Desktop.slnf" -Force From 887a3f3e2834def69ef7fa399cfd8c89444fe464 Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Sat, 5 Nov 2022 19:44:25 +0100 Subject: [PATCH 2081/2686] Fix preposition for exclusive fullscreen prompt --- osu.Game/Localisation/LayoutSettingsStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs index 9b8b207c47..3006361c9a 100644 --- a/osu.Game/Localisation/LayoutSettingsStrings.cs +++ b/osu.Game/Localisation/LayoutSettingsStrings.cs @@ -15,9 +15,9 @@ namespace osu.Game.Localisation public static LocalisableString CheckingForFullscreenCapabilities => new TranslatableString(getKey(@"checking_for_fullscreen_capabilities"), @"Checking for fullscreen capabilities..."); /// - /// "osu! is running exclusive fullscreen, guaranteeing low latency!" + /// "osu! is running in exclusive fullscreen, guaranteeing low latency!" /// - public static LocalisableString OsuIsRunningExclusiveFullscreen => new TranslatableString(getKey(@"osu_is_running_exclusive_fullscreen"), @"osu! is running exclusive fullscreen, guaranteeing low latency!"); + public static LocalisableString OsuIsRunningExclusiveFullscreen => new TranslatableString(getKey(@"osu_is_running_exclusive_fullscreen"), @"osu! is running in exclusive fullscreen, guaranteeing low latency!"); /// /// "Unable to run exclusive fullscreen. You'll still experience some input latency." From 51078bddf95177e266ce101d9ddccbcebdb5a533 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 6 Nov 2022 23:34:04 +0900 Subject: [PATCH 2082/2686] Remove unused bindable --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index f82a24ff01..15d3e63be1 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -130,7 +130,6 @@ namespace osu.Game.Rulesets.Objects.Drawables private readonly Bindable comboIndexBindable = new Bindable(); private readonly Bindable positionalHitsoundsLevel = new Bindable(); - private readonly Bindable normaliseComboColourBrightness = new Bindable(); private readonly Bindable comboColourBrightness = new Bindable(); private readonly Bindable comboIndexWithOffsetsBindable = new Bindable(); @@ -197,7 +196,6 @@ namespace osu.Game.Rulesets.Objects.Drawables comboIndexBindable.BindValueChanged(_ => UpdateComboColour()); comboIndexWithOffsetsBindable.BindValueChanged(_ => UpdateComboColour(), true); - normaliseComboColourBrightness.BindValueChanged(_ => UpdateComboColour()); comboColourBrightness.BindValueChanged(_ => UpdateComboColour()); // Apply transforms From e8603ede15ce9acd38cc02fff84851847291b529 Mon Sep 17 00:00:00 2001 From: CenTdemeern1 Date: Sun, 6 Nov 2022 14:55:16 +0100 Subject: [PATCH 2083/2686] Fix second prompt --- osu.Game/Localisation/LayoutSettingsStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/LayoutSettingsStrings.cs b/osu.Game/Localisation/LayoutSettingsStrings.cs index 3006361c9a..a5172ec774 100644 --- a/osu.Game/Localisation/LayoutSettingsStrings.cs +++ b/osu.Game/Localisation/LayoutSettingsStrings.cs @@ -20,9 +20,9 @@ namespace osu.Game.Localisation public static LocalisableString OsuIsRunningExclusiveFullscreen => new TranslatableString(getKey(@"osu_is_running_exclusive_fullscreen"), @"osu! is running in exclusive fullscreen, guaranteeing low latency!"); /// - /// "Unable to run exclusive fullscreen. You'll still experience some input latency." + /// "Unable to run in exclusive fullscreen. You may experience some input latency." /// - public static LocalisableString UnableToRunExclusiveFullscreen => new TranslatableString(getKey(@"unable_to_run_exclusive_fullscreen"), @"Unable to run exclusive fullscreen. You'll still experience some input latency."); + public static LocalisableString UnableToRunExclusiveFullscreen => new TranslatableString(getKey(@"unable_to_run_exclusive_fullscreen"), @"Unable to run in exclusive fullscreen. You may experience some input latency."); /// /// "Using fullscreen on macOS makes interacting with the menu bar and spaces no longer work, and may lead to freezes if a system dialog is presented. Using borderless is recommended." From 75bf023f1445c4a67efc3ca66b8f783a0352f0ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 6 Nov 2022 23:35:51 +0900 Subject: [PATCH 2084/2686] Fix `HSPAColour.ToColour` not being pure --- osu.Game/Graphics/HSPAColour.cs | 93 +++++++++++++++++---------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/osu.Game/Graphics/HSPAColour.cs b/osu.Game/Graphics/HSPAColour.cs index 5e3bc29b7e..18f4c6bca4 100644 --- a/osu.Game/Graphics/HSPAColour.cs +++ b/osu.Game/Graphics/HSPAColour.cs @@ -96,100 +96,101 @@ namespace osu.Game.Graphics float minOverMax = 1f - S; Color4 result = new Color4 { A = A }; + float h = H; if (minOverMax > 0f) { - if (H < 1f / 6f) + if (h < 1f / 6f) { - H = 6f * (H - 0f / 6f); - float part = 1f + H * (1f / minOverMax - 1f); + h = 6f * (h - 0f / 6f); + float part = 1f + h * (1f / minOverMax - 1f); result.B = P / MathF.Sqrt(p_r / minOverMax / minOverMax + p_g * part * part + p_b); result.R = result.B / minOverMax; - result.G = result.B + H * (result.R - result.B); + result.G = result.B + h * (result.R - result.B); } - else if (H < 2f / 6f) + else if (h < 2f / 6f) { - H = 6f * (-H + 2f / 6f); - float part = 1f + H * (1f / minOverMax - 1f); + h = 6f * (-h + 2f / 6f); + float part = 1f + h * (1f / minOverMax - 1f); result.B = P / MathF.Sqrt(p_g / minOverMax / minOverMax + p_r * part * part + p_b); result.G = result.B / minOverMax; - result.R = result.B + H * (result.G - result.B); + result.R = result.B + h * (result.G - result.B); } - else if (H < 3f / 6f) + else if (h < 3f / 6f) { - H = 6f * (H - 2f / 6f); - float part = 1f + H * (1f / minOverMax - 1f); + h = 6f * (h - 2f / 6f); + float part = 1f + h * (1f / minOverMax - 1f); result.R = P / MathF.Sqrt(p_g / minOverMax / minOverMax + p_b * part * part + p_r); result.G = result.R / minOverMax; - result.B = result.R + H * (result.G - result.R); + result.B = result.R + h * (result.G - result.R); } - else if (H < 4f / 6f) + else if (h < 4f / 6f) { - H = 6f * (-H + 4f / 6f); - float part = 1f + H * (1f / minOverMax - 1f); + h = 6f * (-h + 4f / 6f); + float part = 1f + h * (1f / minOverMax - 1f); result.R = P / MathF.Sqrt(p_b / minOverMax / minOverMax + p_g * part * part + p_r); result.B = result.R / minOverMax; - result.G = result.R + H * (result.B - result.R); + result.G = result.R + h * (result.B - result.R); } - else if (H < 5f / 6f) + else if (h < 5f / 6f) { - H = 6f * (H - 4f / 6f); - float part = 1f + H * (1f / minOverMax - 1f); + h = 6f * (h - 4f / 6f); + float part = 1f + h * (1f / minOverMax - 1f); result.G = P / MathF.Sqrt(p_b / minOverMax / minOverMax + p_r * part * part + p_g); result.B = result.G / minOverMax; - result.R = result.G + H * (result.B - result.G); + result.R = result.G + h * (result.B - result.G); } else { - H = 6f * (-H + 6f / 6f); - float part = 1f + H * (1f / minOverMax - 1f); + h = 6f * (-h + 6f / 6f); + float part = 1f + h * (1f / minOverMax - 1f); result.G = P / MathF.Sqrt(p_r / minOverMax / minOverMax + p_b * part * part + p_g); result.R = result.G / minOverMax; - result.B = result.G + H * (result.R - result.G); + result.B = result.G + h * (result.R - result.G); } } else { - if (H < 1f / 6f) + if (h < 1f / 6f) { - H = 6f * (H - 0f / 6f); - result.R = MathF.Sqrt(P * P / (p_r + p_g * H * H)); - result.G = result.R * H; + h = 6f * (h - 0f / 6f); + result.R = MathF.Sqrt(P * P / (p_r + p_g * h * h)); + result.G = result.R * h; result.B = 0f; } - else if (H < 2f / 6f) + else if (h < 2f / 6f) { - H = 6f * (-H + 2f / 6f); - result.G = MathF.Sqrt(P * P / (p_g + p_r * H * H)); - result.R = result.G * H; + h = 6f * (-h + 2f / 6f); + result.G = MathF.Sqrt(P * P / (p_g + p_r * h * h)); + result.R = result.G * h; result.B = 0f; } - else if (H < 3f / 6f) + else if (h < 3f / 6f) { - H = 6f * (H - 2f / 6f); - result.G = MathF.Sqrt(P * P / (p_g + p_b * H * H)); - result.B = result.G * H; + h = 6f * (h - 2f / 6f); + result.G = MathF.Sqrt(P * P / (p_g + p_b * h * h)); + result.B = result.G * h; result.R = 0f; } - else if (H < 4f / 6f) + else if (h < 4f / 6f) { - H = 6f * (-H + 4f / 6f); - result.B = MathF.Sqrt(P * P / (p_b + p_g * H * H)); - result.G = result.B * H; + h = 6f * (-h + 4f / 6f); + result.B = MathF.Sqrt(P * P / (p_b + p_g * h * h)); + result.G = result.B * h; result.R = 0f; } - else if (H < 5f / 6f) + else if (h < 5f / 6f) { - H = 6f * (H - 4f / 6f); - result.B = MathF.Sqrt(P * P / (p_b + p_r * H * H)); - result.R = result.B * H; + h = 6f * (h - 4f / 6f); + result.B = MathF.Sqrt(P * P / (p_b + p_r * h * h)); + result.R = result.B * h; result.G = 0f; } else { - H = 6f * (-H + 6f / 6f); - result.R = MathF.Sqrt(P * P / (p_r + p_b * H * H)); - result.B = result.R * H; + h = 6f * (-h + 6f / 6f); + result.R = MathF.Sqrt(P * P / (p_r + p_b * h * h)); + result.B = result.R * h; result.G = 0f; } } From 700f8b04690127464440568185cc8b60954d5325 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 02:13:04 +0900 Subject: [PATCH 2085/2686] Remove pointless nested if conditional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Graphics/UserInterface/Nub.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 80e012f596..db3a41e303 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -172,7 +172,7 @@ namespace osu.Game.Graphics.UserInterface if (filled.NewValue) { main.ResizeWidthTo(1, duration, Easing.OutElasticHalf); - main.TransformTo(nameof(BorderThickness), filled.NewValue ? 8.5f : border_width, duration, Easing.OutElasticHalf); + main.TransformTo(nameof(BorderThickness), 8.5f, duration, Easing.OutElasticHalf); } else { From e7b543de2f32298cc47045085bd7c10d58ed9db6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 02:19:13 +0900 Subject: [PATCH 2086/2686] Move disabled check to apply to all calls to `updateGlow()` --- osu.Game/Graphics/UserInterface/OsuSliderBar.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index d7f308c45d..4d3f4be8f6 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -162,8 +162,7 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnHover(HoverEvent e) { - if (!Current.Disabled) - updateGlow(); + updateGlow(); return base.OnHover(e); } @@ -184,7 +183,7 @@ namespace osu.Game.Graphics.UserInterface private void updateGlow() { - Nub.Glowing = IsHovered || IsDragged; + Nub.Glowing = !Current.Disabled && (IsHovered || IsDragged); } protected override void OnUserChange(T value) From b7ef9b176d3c9c0de0e116c34c73e329acc18d3f Mon Sep 17 00:00:00 2001 From: maromalo <54760464+maromalo@users.noreply.github.com> Date: Sun, 6 Nov 2022 19:59:27 -0300 Subject: [PATCH 2087/2686] Make score type consistent --- .../TestSceneSpinnerRotation.cs | 2 +- .../Gameplay/TestSceneScoreProcessor.cs | 2 +- .../Gameplay/TestSceneGameplayLeaderboard.cs | 10 +++++----- .../Graphics/UserInterface/ScoreCounter.cs | 6 +++--- .../API/Requests/Responses/SoloScoreInfo.cs | 4 ++-- .../Online/Rooms/IndexedMultiplayerScores.cs | 2 +- .../Spectator/SpectatorScoreProcessor.cs | 2 +- .../PerformanceBreakdownCalculator.cs | 2 +- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 18 +++++++++--------- osu.Game/Scoring/ScoreManager.cs | 2 +- osu.Game/Scoring/ScoringValues.cs | 4 ++-- .../OnlinePlay/Playlists/PlaylistsPlayer.cs | 2 +- .../Play/HUD/GameplayLeaderboardScore.cs | 2 +- osu.Game/Screens/Play/HUD/ILeaderboardScore.cs | 2 +- .../Play/HUD/MultiplayerGameplayLeaderboard.cs | 2 +- 15 files changed, 31 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index 5fa4e24f5e..13ea46eadf 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Osu.Tests AddAssert("player score matching expected bonus score", () => { // multipled by 2 to nullify the score multiplier. (autoplay mod selected) - double totalScore = ((ScoreExposedPlayer)Player).ScoreProcessor.TotalScore.Value * 2; + long totalScore = ((ScoreExposedPlayer)Player).ScoreProcessor.TotalScore.Value * 2; return totalScore == (int)(drawableSpinner.Result.RateAdjustedRotation / 360) * new SpinnerTick().CreateJudgement().MaxNumericResult; }); diff --git a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs index fb9d841d99..d5219f6391 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs @@ -35,7 +35,7 @@ namespace osu.Game.Tests.Gameplay // Apply a miss judgement scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new TestJudgement()) { Type = HitResult.Miss }); - Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(0.0)); + Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(0)); } [Test] diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 171ae829a9..30d2cc6423 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.Gameplay { private TestGameplayLeaderboard leaderboard; - private readonly BindableDouble playerScore = new BindableDouble(); + private readonly BindableLong playerScore = new BindableLong(); public TestSceneGameplayLeaderboard() { @@ -76,8 +76,8 @@ namespace osu.Game.Tests.Visual.Gameplay createLeaderboard(); addLocalPlayer(); - var player2Score = new BindableDouble(1234567); - var player3Score = new BindableDouble(1111111); + var player2Score = new BindableLong(1234567); + var player3Score = new BindableLong(1111111); AddStep("add player 2", () => createLeaderboardScore(player2Score, new APIUser { Username = "Player 2" })); AddStep("add player 3", () => createLeaderboardScore(player3Score, new APIUser { Username = "Player 3" })); @@ -161,9 +161,9 @@ namespace osu.Game.Tests.Visual.Gameplay }); } - private void createRandomScore(APIUser user) => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), user); + private void createRandomScore(APIUser user) => createLeaderboardScore(new BindableLong(RNG.Next(0, 5_000_000)), user); - private void createLeaderboardScore(BindableDouble score, APIUser user, bool isTracked = false) + private void createLeaderboardScore(BindableLong score, APIUser user, bool isTracked = false) { var leaderboardScore = leaderboard.Add(user, isTracked); leaderboardScore.TotalScore.BindTo(score); diff --git a/osu.Game/Graphics/UserInterface/ScoreCounter.cs b/osu.Game/Graphics/UserInterface/ScoreCounter.cs index e46e2b31ac..2efe27c842 100644 --- a/osu.Game/Graphics/UserInterface/ScoreCounter.cs +++ b/osu.Game/Graphics/UserInterface/ScoreCounter.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public abstract class ScoreCounter : RollingCounter + public abstract class ScoreCounter : RollingCounter { protected override double RollingDuration => 1000; protected override Easing RollingEasing => Easing.Out; @@ -36,10 +36,10 @@ namespace osu.Game.Graphics.UserInterface UpdateDisplay(); } - protected override double GetProportionalDuration(double currentValue, double newValue) => + protected override double GetProportionalDuration(long currentValue, long newValue) => currentValue > newValue ? currentValue - newValue : newValue - currentValue; - protected override LocalisableString FormatCount(double count) => ((long)count).ToLocalisableString(formatString); + protected override LocalisableString FormatCount(long count) => count.ToLocalisableString(formatString); protected override OsuSpriteText CreateSpriteText() => base.CreateSpriteText().With(s => s.Font = s.Font.With(fixedWidth: true)); diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 77dcfd39e3..15f4bace96 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -31,7 +31,7 @@ namespace osu.Game.Online.API.Requests.Responses public bool Passed { get; set; } [JsonProperty("total_score")] - public int TotalScore { get; set; } + public long TotalScore { get; set; } [JsonProperty("accuracy")] public double Accuracy { get; set; } @@ -213,7 +213,7 @@ namespace osu.Game.Online.API.Requests.Responses public static SoloScoreInfo ForSubmission(ScoreInfo score) => new SoloScoreInfo { Rank = score.Rank, - TotalScore = (int)score.TotalScore, + TotalScore = score.TotalScore, Accuracy = score.Accuracy, PP = score.PP, MaxCombo = score.MaxCombo, diff --git a/osu.Game/Online/Rooms/IndexedMultiplayerScores.cs b/osu.Game/Online/Rooms/IndexedMultiplayerScores.cs index 459602f1b4..59cba2340d 100644 --- a/osu.Game/Online/Rooms/IndexedMultiplayerScores.cs +++ b/osu.Game/Online/Rooms/IndexedMultiplayerScores.cs @@ -17,7 +17,7 @@ namespace osu.Game.Online.Rooms /// The total scores in the playlist item. /// [JsonProperty("total")] - public int? TotalScores { get; set; } + public long? TotalScores { get; set; } /// /// The user's score, if any. diff --git a/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs b/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs index 87f25874c5..573c504add 100644 --- a/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs +++ b/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs @@ -26,7 +26,7 @@ namespace osu.Game.Online.Spectator /// /// The current total score. /// - public readonly BindableDouble TotalScore = new BindableDouble { MinValue = 0 }; + public readonly BindableLong TotalScore = new BindableLong { MinValue = 0 }; /// /// The current accuracy. diff --git a/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs b/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs index 3fb12041d1..4f802a22a1 100644 --- a/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs @@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Difficulty // calculate total score ScoreProcessor scoreProcessor = ruleset.CreateScoreProcessor(); scoreProcessor.Mods.Value = perfectPlay.Mods; - perfectPlay.TotalScore = (long)scoreProcessor.ComputeScore(ScoringMode.Standardised, perfectPlay); + perfectPlay.TotalScore = scoreProcessor.ComputeScore(ScoringMode.Standardised, perfectPlay); // compute rank achieved // default to SS, then adjust the rank with mods diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 7456ce06bd..f619c89368 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Scoring /// /// The current total score. /// - public readonly BindableDouble TotalScore = new BindableDouble { MinValue = 0 }; + public readonly BindableLong TotalScore = new BindableLong { MinValue = 0 }; /// /// The current accuracy. @@ -267,7 +267,7 @@ namespace osu.Game.Rulesets.Scoring private void updateScore() { - Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1; + Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1; TotalScore.Value = ComputeScore(Mode.Value, currentScoringValues, maximumScoringValues); } @@ -298,7 +298,7 @@ namespace osu.Game.Rulesets.Scoring /// The to compute the total score of. /// The total score in the given . [Pure] - public double ComputeScore(ScoringMode mode, ScoreInfo scoreInfo) + public long ComputeScore(ScoringMode mode, ScoreInfo scoreInfo) { if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset)) throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\"."); @@ -316,9 +316,9 @@ namespace osu.Game.Rulesets.Scoring /// The maximum scoring values. /// The total score computed from the given scoring values. [Pure] - public double ComputeScore(ScoringMode mode, ScoringValues current, ScoringValues maximum) + public long ComputeScore(ScoringMode mode, ScoringValues current, ScoringValues maximum) { - double accuracyRatio = maximum.BaseScore > 0 ? current.BaseScore / maximum.BaseScore : 1; + double accuracyRatio = maximum.BaseScore > 0 ? (double)current.BaseScore / maximum.BaseScore : 1; double comboRatio = maximum.MaxCombo > 0 ? (double)current.MaxCombo / maximum.MaxCombo : 1; return ComputeScore(mode, accuracyRatio, comboRatio, current.BonusScore, maximum.CountBasicHitObjects); } @@ -333,7 +333,7 @@ namespace osu.Game.Rulesets.Scoring /// The total number of basic (non-tick and non-bonus) hitobjects in the beatmap. /// The total score computed from the given scoring component ratios. [Pure] - public double ComputeScore(ScoringMode mode, double accuracyRatio, double comboRatio, double bonusScore, int totalBasicHitObjects) + public long ComputeScore(ScoringMode mode, double accuracyRatio, double comboRatio, long bonusScore, int totalBasicHitObjects) { switch (mode) { @@ -341,13 +341,13 @@ namespace osu.Game.Rulesets.Scoring case ScoringMode.Standardised: double accuracyScore = accuracyPortion * accuracyRatio; double comboScore = comboPortion * comboRatio; - return (max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier; + return (long)((max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier); case ScoringMode.Classic: // This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring. // The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes. double scaledStandardised = ComputeScore(ScoringMode.Standardised, accuracyRatio, comboRatio, bonusScore, totalBasicHitObjects) / max_score; - return Math.Pow(scaledStandardised * Math.Max(1, totalBasicHitObjects), 2) * ClassicScoreMultiplier; + return (long)(Math.Pow(scaledStandardised * Math.Max(1, totalBasicHitObjects), 2) * ClassicScoreMultiplier); } } @@ -417,7 +417,7 @@ namespace osu.Game.Rulesets.Scoring score.MaximumStatistics[result] = maximumResultCounts.GetValueOrDefault(result); // Populate total score after everything else. - score.TotalScore = (long)Math.Round(ComputeScore(ScoringMode.Standardised, score)); + score.TotalScore = ComputeScore(ScoringMode.Standardised, score); } /// diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 8342d3bcc1..b2944ad219 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -99,7 +99,7 @@ namespace osu.Game.Scoring var scoreProcessor = ruleset.CreateScoreProcessor(); scoreProcessor.Mods.Value = score.Mods; - return (long)Math.Round(scoreProcessor.ComputeScore(mode, score)); + return scoreProcessor.ComputeScore(mode, score); } /// diff --git a/osu.Game/Scoring/ScoringValues.cs b/osu.Game/Scoring/ScoringValues.cs index 9bc4e6e12a..471067c9db 100644 --- a/osu.Game/Scoring/ScoringValues.cs +++ b/osu.Game/Scoring/ScoringValues.cs @@ -20,13 +20,13 @@ namespace osu.Game.Scoring /// The sum of all "basic" scoring values. See: and . /// [Key(0)] - public double BaseScore; + public long BaseScore; /// /// The sum of all "bonus" scoring values. See: and . /// [Key(1)] - public double BonusScore; + public long BonusScore; /// /// The highest achieved combo. diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs index 1c4d02bb11..2444729118 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs @@ -67,7 +67,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { await base.PrepareScoreForResultsAsync(score).ConfigureAwait(false); - Score.ScoreInfo.TotalScore = (int)Math.Round(ScoreProcessor.ComputeScore(ScoringMode.Standardised, Score.ScoreInfo)); + Score.ScoreInfo.TotalScore = ScoreProcessor.ComputeScore(ScoringMode.Standardised, Score.ScoreInfo); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 2eec8253b3..15586baab0 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -50,7 +50,7 @@ namespace osu.Game.Screens.Play.HUD private OsuSpriteText positionText, scoreText, accuracyText, comboText, usernameText; - public BindableDouble TotalScore { get; } = new BindableDouble(); + public BindableLong TotalScore { get; } = new BindableLong(); public BindableDouble Accuracy { get; } = new BindableDouble(1); public BindableInt Combo { get; } = new BindableInt(); public BindableBool HasQuit { get; } = new BindableBool(); diff --git a/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs b/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs index aa06bb08a5..428390f90c 100644 --- a/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/ILeaderboardScore.cs @@ -9,7 +9,7 @@ namespace osu.Game.Screens.Play.HUD { public interface ILeaderboardScore { - BindableDouble TotalScore { get; } + BindableLong TotalScore { get; } BindableDouble Accuracy { get; } BindableInt Combo { get; } diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 4201b3f4c9..a77d66cdd2 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -184,7 +184,7 @@ namespace osu.Game.Screens.Play.HUD continue; if (TeamScores.TryGetValue(u.Team.Value, out var team)) - team.Value += (int)Math.Round(u.ScoreProcessor.TotalScore.Value); + team.Value += u.ScoreProcessor.TotalScore.Value; } } From 8eef2ba8de2bfdce8f4c4278f0390259ab46587b Mon Sep 17 00:00:00 2001 From: maromalo <54760464+maromalo@users.noreply.github.com> Date: Sun, 6 Nov 2022 20:12:26 -0300 Subject: [PATCH 2088/2686] quality shenanigans --- osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index a77d66cdd2..4ac92056ef 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -1,7 +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 System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; From e3adf5a98502d714c6849095f257a2ad343b5038 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 7 Nov 2022 11:36:55 +0900 Subject: [PATCH 2089/2686] Handle channel parts --- osu.Game/Online/Chat/ChannelManager.cs | 2 ++ osu.Game/Online/Notifications/NotificationsClient.cs | 3 +++ .../Online/Notifications/NotificationsClientConnector.cs | 2 ++ .../WebSocket/WebSocketNotificationsClient.cs | 9 +++++++++ 4 files changed, 16 insertions(+) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index db2436333b..93033dffa0 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -99,6 +99,8 @@ namespace osu.Game.Online.Chat joinChannel(localChannel); }); + connector.ChannelParted += ch => Schedule(() => LeaveChannel(getChannel(ch))); + connector.NewMessages += msgs => Schedule(() => addMessages(msgs)); connector.PresenceReceived += () => Schedule(() => diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs index cb5e94fb1d..5182bfa0e5 100644 --- a/osu.Game/Online/Notifications/NotificationsClient.cs +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -18,6 +18,7 @@ namespace osu.Game.Online.Notifications public abstract class NotificationsClient : PersistentEndpointClient { public Action? ChannelJoined; + public Action? ChannelParted; public Action>? NewMessages; public Action? PresenceReceived; @@ -65,6 +66,8 @@ namespace osu.Game.Online.Notifications ChannelJoined?.Invoke(channel); } + protected void HandleChannelParted(Channel channel) => ChannelParted?.Invoke(channel); + protected void HandleMessages(List messages) { NewMessages?.Invoke(messages); diff --git a/osu.Game/Online/Notifications/NotificationsClientConnector.cs b/osu.Game/Online/Notifications/NotificationsClientConnector.cs index d4c846a7a2..d2c2e6673c 100644 --- a/osu.Game/Online/Notifications/NotificationsClientConnector.cs +++ b/osu.Game/Online/Notifications/NotificationsClientConnector.cs @@ -16,6 +16,7 @@ namespace osu.Game.Online.Notifications public abstract class NotificationsClientConnector : PersistentEndpointClientConnector { public event Action? ChannelJoined; + public event Action? ChannelParted; public event Action>? NewMessages; public event Action? PresenceReceived; @@ -29,6 +30,7 @@ namespace osu.Game.Online.Notifications var client = await BuildNotificationClientAsync(cancellationToken); client.ChannelJoined = c => ChannelJoined?.Invoke(c); + client.ChannelParted = c => ChannelParted?.Invoke(c); client.NewMessages = m => NewMessages?.Invoke(m); client.PresenceReceived = () => PresenceReceived?.Invoke(); diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index eefe684795..8f4b3c2f97 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -122,6 +122,15 @@ namespace osu.Game.Online.Notifications.WebSocket HandleJoinedChannel(joinedChannel); break; + case @"chat.channel.part": + Debug.Assert(message.Data != null); + + Channel? partedChannel = JsonConvert.DeserializeObject(message.Data.ToString()); + Debug.Assert(partedChannel != null); + + HandleChannelParted(partedChannel); + break; + case @"chat.message.new": Debug.Assert(message.Data != null); From cf03001c83a7f6317513fd283a7761427c050e72 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 7 Nov 2022 11:52:07 +0900 Subject: [PATCH 2090/2686] Better handling for joining channels with only ID --- .../Online/API/Requests/GetChannelRequest.cs | 19 +++++++++++++ .../Requests/Responses/GetChannelResponse.cs | 19 +++++++++++++ osu.Game/Online/Chat/ChannelManager.cs | 28 +++++-------------- .../Notifications/NotificationsClient.cs | 10 +++---- .../WebSocket/WebSocketNotificationsClient.cs | 3 +- 5 files changed, 51 insertions(+), 28 deletions(-) create mode 100644 osu.Game/Online/API/Requests/GetChannelRequest.cs create mode 100644 osu.Game/Online/API/Requests/Responses/GetChannelResponse.cs diff --git a/osu.Game/Online/API/Requests/GetChannelRequest.cs b/osu.Game/Online/API/Requests/GetChannelRequest.cs new file mode 100644 index 0000000000..5bc9cb519a --- /dev/null +++ b/osu.Game/Online/API/Requests/GetChannelRequest.cs @@ -0,0 +1,19 @@ +// 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.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetChannelRequest : APIRequest + { + private readonly long channelId; + + public GetChannelRequest(long channelId) + { + this.channelId = channelId; + } + + protected override string Target => $"chat/channels/{channelId}"; + } +} diff --git a/osu.Game/Online/API/Requests/Responses/GetChannelResponse.cs b/osu.Game/Online/API/Requests/Responses/GetChannelResponse.cs new file mode 100644 index 0000000000..24b886e74d --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/GetChannelResponse.cs @@ -0,0 +1,19 @@ +// 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 Newtonsoft.Json; +using osu.Game.Online.Chat; + +namespace osu.Game.Online.API.Requests.Responses +{ + [JsonObject(MemberSerialization.OptIn)] + public class GetChannelResponse + { + [JsonProperty(@"channel")] + public Channel Channel { get; set; } = null!; + + [JsonProperty(@"users")] + public List Users { get; set; } = null!; + } +} diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 93033dffa0..ee3194243b 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -88,15 +88,14 @@ namespace osu.Game.Online.Chat { connector.ChannelJoined += ch => Schedule(() => { - var localChannel = getChannel(ch); - - if (localChannel != ch) + if (ch.Joined.Value) + JoinChannel(ch); + else { - localChannel.Joined.Value = true; - localChannel.Id = ch.Id; + var req = new GetChannelRequest(ch.Id); + req.Success += response => JoinChannel(response.Channel); + api.Queue(req); } - - joinChannel(localChannel); }); connector.ChannelParted += ch => Schedule(() => LeaveChannel(getChannel(ch))); @@ -421,20 +420,7 @@ namespace osu.Game.Online.Chat { Channel found = null; - bool lookupCondition(Channel ch) - { - // If both channels have an id, use that. - if (lookup.Id > 0 && ch.Id > 0) - return ch.Id == lookup.Id; - - // In the case that the local echo is received in a new channel (i.e. one that does not yet have an ID), - // then we need to check for any existing channel with the message containing the same message matched by UUID. - if (lookup.Messages.Count > 0 && ch.Messages.Any(m => m.Uuid == lookup.Messages.Last().Uuid)) - return true; - - // As a last resort, fallback to matching by name. - return lookup.Name == ch.Name; - } + bool lookupCondition(Channel ch) => lookup.Id > 0 ? ch.Id == lookup.Id : ch.Name == lookup.Name; var available = AvailableChannels.FirstOrDefault(lookupCondition); if (available != null) diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs index 5182bfa0e5..c706124351 100644 --- a/osu.Game/Online/Notifications/NotificationsClient.cs +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -46,7 +46,10 @@ namespace osu.Game.Online.Notifications if (updates?.Presence != null) { foreach (var channel in updates.Presence) + { + channel.Joined.Value = true; HandleJoinedChannel(channel); + } //todo: handle left channels @@ -59,12 +62,7 @@ namespace osu.Game.Online.Notifications return fetchReq; } - protected void HandleJoinedChannel(Channel channel) - { - // we received this from the server so should mark the channel already joined. - channel.Joined.Value = true; - ChannelJoined?.Invoke(channel); - } + protected void HandleJoinedChannel(Channel channel) => ChannelJoined?.Invoke(channel); protected void HandleChannelParted(Channel channel) => ChannelParted?.Invoke(channel); diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index 8f4b3c2f97..71aec942ac 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -119,6 +119,7 @@ namespace osu.Game.Online.Notifications.WebSocket Channel? joinedChannel = JsonConvert.DeserializeObject(message.Data.ToString()); Debug.Assert(joinedChannel != null); + joinedChannel.Joined.Value = true; HandleJoinedChannel(joinedChannel); break; @@ -138,7 +139,7 @@ namespace osu.Game.Online.Notifications.WebSocket Debug.Assert(messageData != null); foreach (var msg in messageData.Messages) - HandleJoinedChannel(new Channel(msg.Sender) { Id = msg.ChannelId, Messages = { msg } }); + HandleJoinedChannel(new Channel { Id = msg.ChannelId }); HandleMessages(messageData.Messages); break; From 391840404de144367f979f4cde1ac59475c972c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 11:59:43 +0900 Subject: [PATCH 2091/2686] Play exiting transition in both directions --- osu.Game/Screens/Select/SongSelect.cs | 40 +++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index fe9b67a02e..4b2417aab4 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -633,14 +633,32 @@ namespace osu.Game.Screens.Select transferRulesetValue(); ModSelect.SelectedMods.UnbindFrom(selectedMods); + + playExitingTransition(); + base.OnSuspending(e); + } + + public override bool OnExiting(ScreenExitEvent e) + { + if (base.OnExiting(e)) + return true; + + playExitingTransition(); + return false; + } + + private void playExitingTransition() + { ModSelect.Hide(); BeatmapOptions.Hide(); + Carousel.AllowSelection = false; + endLooping(); - FilterControl.MoveToY(-120, 250, Easing.OutQuint); - FilterControl.FadeOut(100); + FilterControl.MoveToY(-120, 500, Easing.OutQuint); + FilterControl.FadeOut(200, Easing.OutQuint); LeftArea.MoveToX(-150, 1800, Easing.OutQuint); LeftArea.FadeOut(200, Easing.OutQuint); @@ -650,24 +668,6 @@ namespace osu.Game.Screens.Select this.FadeOut(400, Easing.OutQuint); FilterControl.Deactivate(); - base.OnSuspending(e); - } - - public override bool OnExiting(ScreenExitEvent e) - { - if (base.OnExiting(e)) - return true; - - beatmapInfoWedge.Hide(); - ModSelect.Hide(); - - this.FadeOut(100); - - FilterControl.Deactivate(); - - endLooping(); - - return false; } private bool isHandlingLooping; From cd8402df72f3945f0b0b56e55691e4117badb282 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 7 Nov 2022 12:11:44 +0900 Subject: [PATCH 2092/2686] Print event type to logs --- .../Notifications/WebSocket/WebSocketNotificationsClient.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index 71aec942ac..c5b11ea94a 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -69,13 +69,14 @@ namespace osu.Game.Online.Notifications.WebSocket break; } + Logger.Log($"{GetType().ReadableName()} handling event: {message.Event}"); await onMessageReceivedAsync(message); } break; case WebSocketMessageType.Binary: - throw new NotImplementedException(); + throw new NotImplementedException("Binary message type not supported."); case WebSocketMessageType.Close: throw new Exception("Connection closed by remote host."); From f931bdc5ff502518a29e7714507245c833b307cc Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 7 Nov 2022 12:25:23 +0900 Subject: [PATCH 2093/2686] Fix channel lookup not considering missing ids --- osu.Game/Online/Chat/ChannelManager.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index ee3194243b..ee6e22fbc1 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -420,7 +420,13 @@ namespace osu.Game.Online.Chat { Channel found = null; - bool lookupCondition(Channel ch) => lookup.Id > 0 ? ch.Id == lookup.Id : ch.Name == lookup.Name; + bool lookupCondition(Channel ch) + { + if (ch.Id > 0 && lookup.Id > 0) + return ch.Id == lookup.Id; + + return ch.Name == lookup.Name; + } var available = AvailableChannels.FirstOrDefault(lookupCondition); if (available != null) From 6085120dc527165241c672176cf98535d788be2a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 12:25:36 +0900 Subject: [PATCH 2094/2686] Fix incorrect handling of storyboard events with `end_time` before `start_time` --- osu.Game/Storyboards/CommandTimeline.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Storyboards/CommandTimeline.cs b/osu.Game/Storyboards/CommandTimeline.cs index d1a1edcd03..0650c97165 100644 --- a/osu.Game/Storyboards/CommandTimeline.cs +++ b/osu.Game/Storyboards/CommandTimeline.cs @@ -28,8 +28,7 @@ namespace osu.Game.Storyboards { if (endTime < startTime) { - (startTime, endTime) = (endTime, startTime); - (startValue, endValue) = (endValue, startValue); + endTime = startTime; } commands.Add(new TypedCommand { Easing = easing, StartTime = startTime, EndTime = endTime, StartValue = startValue, EndValue = endValue }); From b977fc8181372b2d999d354b0dac21f5b17f1410 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 6 Nov 2022 18:24:54 -0800 Subject: [PATCH 2095/2686] Use autosize instead of max width on fixed width timestamps --- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 1 - osu.Game/Overlays/Chat/ChatLine.cs | 43 ++++++++----------- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 76fcb80eb4..81db3f0d53 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -191,7 +191,6 @@ namespace osu.Game.Online.Chat { protected override float TextSize => 15; protected override float Spacing => 5; - protected override float TimestampWidth => 45; protected override float UsernameWidth => 75; public StandAloneMessage(Message message) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 4c425d3d4c..b7e3b183dc 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -48,8 +48,6 @@ namespace osu.Game.Overlays.Chat protected virtual float Spacing => 15; - protected virtual float TimestampWidth => 60; - protected virtual float UsernameWidth => 130; private Color4 usernameColour; @@ -93,38 +91,31 @@ namespace osu.Game.Overlays.Chat RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, ColumnDimensions = new[] { - new Dimension(GridSizeMode.Absolute, TimestampWidth + Spacing + UsernameWidth + Spacing), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, Spacing + UsernameWidth + Spacing), new Dimension(), }, Content = new[] { new Drawable[] { - new Container + timestamp = new OsuSpriteText { - RelativeSizeAxes = Axes.X, + Shadow = false, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: TextSize * 0.75f, weight: FontWeight.SemiBold, fixedWidth: true), + Colour = colourProvider?.Background1 ?? Colour4.White, + AlwaysPresent = true, + }, + new MessageSender(message.Sender) + { + Width = UsernameWidth, AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - timestamp = new OsuSpriteText - { - Shadow = false, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: TextSize * 0.75f, weight: FontWeight.SemiBold, fixedWidth: true), - MaxWidth = TimestampWidth, - Colour = colourProvider?.Background1 ?? Colour4.White, - }, - new MessageSender(message.Sender) - { - Width = UsernameWidth, - AutoSizeAxes = Axes.Y, - Origin = Anchor.TopRight, - Anchor = Anchor.TopRight, - Child = createUsername(), - Margin = new MarginPadding { Horizontal = Spacing }, - }, - }, + Origin = Anchor.TopRight, + Anchor = Anchor.TopRight, + Child = createUsername(), + Margin = new MarginPadding { Horizontal = Spacing }, }, ContentFlow = new LinkFlowContainer(t => { From 61ec0ba56654e121dc018f1a0b0b2e0d64f56708 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 6 Nov 2022 18:32:13 -0800 Subject: [PATCH 2096/2686] Make chat line timestamp adjust to 24-hour time setting --- osu.Game/Overlays/Chat/ChatLine.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index b7e3b183dc..4db02db1bc 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -5,6 +5,7 @@ using System; using System.Linq; using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -12,6 +13,7 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -60,6 +62,8 @@ namespace osu.Game.Overlays.Chat private Container? highlight; + private readonly Bindable prefer24HourTime = new Bindable(); + private bool senderHasColour => !string.IsNullOrEmpty(message.Sender.Colour); private bool messageHasColour => Message.IsAction && senderHasColour; @@ -78,7 +82,7 @@ namespace osu.Game.Overlays.Chat } [BackgroundDependencyLoader] - private void load(OverlayColourProvider? colourProvider) + private void load(OverlayColourProvider? colourProvider, OsuConfigManager configManager) { usernameColour = senderHasColour ? Color4Extensions.FromHex(message.Sender.Colour) @@ -130,6 +134,8 @@ namespace osu.Game.Overlays.Chat }, } }; + + configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime); } protected override void LoadComplete() @@ -138,6 +144,8 @@ namespace osu.Game.Overlays.Chat updateMessageContent(); FinishTransforms(true); + + prefer24HourTime.BindValueChanged(_ => updateTimestamp(), true); } /// @@ -167,7 +175,7 @@ namespace osu.Game.Overlays.Chat this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint); timestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint); - timestamp.Text = $@"{message.Timestamp.LocalDateTime:HH:mm:ss}"; + updateTimestamp(); username.Text = $@"{message.Sender.Username}"; // remove non-existent channels from the link list @@ -177,6 +185,13 @@ namespace osu.Game.Overlays.Chat ContentFlow.AddLinks(message.DisplayContent, message.Links); } + private void updateTimestamp() + { + timestamp.Text = prefer24HourTime.Value + ? $@"{message.Timestamp.LocalDateTime:HH:mm:ss}" + : $@"{message.Timestamp.LocalDateTime:hh:mm:ss tt}"; + } + private Drawable createUsername() { username = new OsuSpriteText From 76df61504f6ce6656a9ae01497329333aba8f659 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 6 Nov 2022 19:45:59 -0800 Subject: [PATCH 2097/2686] Remove unnecessary timestamp update Co-authored-by: Dean Herbert --- osu.Game/Overlays/Chat/ChatLine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 4db02db1bc..a991103fac 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -145,7 +145,7 @@ namespace osu.Game.Overlays.Chat updateMessageContent(); FinishTransforms(true); - prefer24HourTime.BindValueChanged(_ => updateTimestamp(), true); + prefer24HourTime.BindValueChanged(_ => updateTimestamp()); } /// From f6d93fcd5a76f33ab8d18388fc73743cbed5a6c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 12:54:02 +0900 Subject: [PATCH 2098/2686] Fix editor hard crash when beatmap file specified out-of-range timeline zoom value --- osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 3a93499527..8befda82e8 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -196,10 +196,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { defaultTimelineZoom = getZoomLevelForVisibleMilliseconds(6000); - float initialZoom = (float)(defaultTimelineZoom * (editorBeatmap.BeatmapInfo.TimelineZoom == 0 ? 1 : editorBeatmap.BeatmapInfo.TimelineZoom)); float minimumZoom = getZoomLevelForVisibleMilliseconds(10000); float maximumZoom = getZoomLevelForVisibleMilliseconds(500); + float initialZoom = (float)Math.Clamp(defaultTimelineZoom * (editorBeatmap.BeatmapInfo.TimelineZoom == 0 ? 1 : editorBeatmap.BeatmapInfo.TimelineZoom), minimumZoom, maximumZoom); + SetupZoom(initialZoom, minimumZoom, maximumZoom); float getZoomLevelForVisibleMilliseconds(double milliseconds) => Math.Max(1, (float)(editorClock.TrackLength / milliseconds)); From c69a4f9333016d3d20d64b7ed5889ecdeafe2734 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 14:18:43 +0900 Subject: [PATCH 2099/2686] Move major barline portion to default implementation to allow for further customisation Of note, this removes the "major" barline triangles from legacy skins. I think this is more correct, as they did not display in stable. --- .../Objects/Drawables/DrawableBarLine.cs | 89 ++---------------- .../Skinning/Default/DefaultBarLine.cs | 94 +++++++++++++++++++ .../Objects/Drawables/DrawableHitObject.cs | 2 +- 3 files changed, 104 insertions(+), 81 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Default/DefaultBarLine.cs diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs index e4806c4a12..5bfe64c73e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs @@ -1,17 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Objects; -using osuTK; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Skinning.Default; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects.Drawables @@ -28,35 +23,15 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// private const float tracker_width = 2f; - /// - /// The vertical offset of the triangles from the line tracker. - /// - private const float triangle_offset = 10f; - - /// - /// The size of the triangles. - /// - private const float triangle_size = 20f; - - /// - /// The visual line tracker. - /// - private SkinnableDrawable line; - - /// - /// Container with triangles. Only visible for major lines. - /// - private Container triangleContainer; - - private readonly Bindable major = new Bindable(); + public readonly Bindable Major = new Bindable(); public DrawableBarLine() : this(null) { } - public DrawableBarLine([CanBeNull] BarLine barLine) - : base(barLine) + public DrawableBarLine(BarLine? barLine) + : base(barLine!) { } @@ -69,69 +44,23 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables RelativeSizeAxes = Axes.Y; Width = tracker_width; - AddRangeInternal(new Drawable[] + AddInternal(new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.BarLine), _ => new DefaultBarLine()) { - line = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.BarLine), _ => new Box - { - RelativeSizeAxes = Axes.Both, - EdgeSmoothness = new Vector2(0.5f, 0), - }) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }, - triangleContainer = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Children = new[] - { - new EquilateralTriangle - { - Name = "Top", - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Position = new Vector2(0, -triangle_offset), - Size = new Vector2(-triangle_size), - EdgeSmoothness = new Vector2(1), - }, - new EquilateralTriangle - { - Name = "Bottom", - Anchor = Anchor.BottomCentre, - Origin = Anchor.TopCentre, - Position = new Vector2(0, triangle_offset), - Size = new Vector2(triangle_size), - EdgeSmoothness = new Vector2(1), - } - } - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre, }); } - protected override void LoadComplete() - { - base.LoadComplete(); - major.BindValueChanged(updateMajor, true); - } - - private void updateMajor(ValueChangedEvent major) - { - line.Alpha = major.NewValue ? 1f : 0.75f; - triangleContainer.Alpha = major.NewValue ? 1 : 0; - } - protected override void OnApply() { base.OnApply(); - major.BindTo(HitObject.MajorBindable); + Major.BindTo(HitObject.MajorBindable); } protected override void OnFree() { base.OnFree(); - major.UnbindFrom(HitObject.MajorBindable); + Major.UnbindFrom(HitObject.MajorBindable); } protected override void UpdateHitStateTransforms(ArmedState state) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultBarLine.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultBarLine.cs new file mode 100644 index 0000000000..973e685bc7 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultBarLine.cs @@ -0,0 +1,94 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osuTK; + +namespace osu.Game.Rulesets.Taiko.Skinning.Default +{ + public class DefaultBarLine : CompositeDrawable + { + /// + /// The vertical offset of the triangles from the line tracker. + /// + private const float triangle_offset = 10f; + + /// + /// The size of the triangles. + /// + private const float triangle_size = 20f; + + /// + /// Container with triangles. Only visible for major lines. + /// + private Container triangleContainer = null!; + + private Bindable major = null!; + + [BackgroundDependencyLoader] + private void load(DrawableHitObject drawableHitObject) + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + line = new Box + { + RelativeSizeAxes = Axes.Both, + EdgeSmoothness = new Vector2(0.5f, 0), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + triangleContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new EquilateralTriangle + { + Name = "Top", + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Position = new Vector2(0, -triangle_offset), + Size = new Vector2(-triangle_size), + EdgeSmoothness = new Vector2(1), + }, + new EquilateralTriangle + { + Name = "Bottom", + Anchor = Anchor.BottomCentre, + Origin = Anchor.TopCentre, + Position = new Vector2(0, triangle_offset), + Size = new Vector2(triangle_size), + EdgeSmoothness = new Vector2(1), + } + } + } + }; + + major = ((DrawableBarLine)drawableHitObject).Major.GetBoundCopy(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + major.BindValueChanged(updateMajor, true); + } + + private Box line = null!; + + private void updateMajor(ValueChangedEvent major) + { + line.Alpha = major.NewValue ? 1f : 0.75f; + triangleContainer.Alpha = major.NewValue ? 1 : 0; + } + } +} diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index e5150576f2..5062cbc3e6 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -736,7 +736,7 @@ namespace osu.Game.Rulesets.Objects.Drawables { public new TObject HitObject => (TObject)base.HitObject; - protected DrawableHitObject(TObject hitObject) + protected DrawableHitObject([CanBeNull] TObject hitObject) : base(hitObject) { } From 67e99b53448c9311e9aa65543aa94aaf5db031eb Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 7 Nov 2022 14:34:53 +0900 Subject: [PATCH 2100/2686] Lookup channels before calling HandleJoinedChannel() --- osu.Game/Online/Chat/ChannelManager.cs | 18 +++++------- .../Notifications/NotificationsClient.cs | 9 +++--- .../WebSocket/WebSocketNotificationsClient.cs | 29 ++++++++++++++++--- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index ee6e22fbc1..076f79a700 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -86,17 +86,7 @@ namespace osu.Game.Online.Chat [BackgroundDependencyLoader] private void load() { - connector.ChannelJoined += ch => Schedule(() => - { - if (ch.Joined.Value) - JoinChannel(ch); - else - { - var req = new GetChannelRequest(ch.Id); - req.Success += response => JoinChannel(response.Channel); - api.Queue(req); - } - }); + connector.ChannelJoined += ch => Schedule(() => joinChannel(ch)); connector.ChannelParted += ch => Schedule(() => LeaveChannel(getChannel(ch))); @@ -446,6 +436,12 @@ namespace osu.Game.Online.Chat if (foundSelf != null) found.Users.Remove(foundSelf); } + else + { + found.Id = lookup.Id; + found.Name = lookup.Name; + found.LastMessageId = Math.Max(found.LastMessageId ?? 0, lookup.LastMessageId ?? 0); + } if (joined == null && addToJoined) joinedChannels.Add(found); if (available == null && addToAvailable) availableChannels.Add(found); diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs index c706124351..e5f477bc1e 100644 --- a/osu.Game/Online/Notifications/NotificationsClient.cs +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -46,10 +46,7 @@ namespace osu.Game.Online.Notifications if (updates?.Presence != null) { foreach (var channel in updates.Presence) - { - channel.Joined.Value = true; HandleJoinedChannel(channel); - } //todo: handle left channels @@ -62,7 +59,11 @@ namespace osu.Game.Online.Notifications return fetchReq; } - protected void HandleJoinedChannel(Channel channel) => ChannelJoined?.Invoke(channel); + protected void HandleJoinedChannel(Channel channel) + { + channel.Joined.Value = true; + ChannelJoined?.Invoke(channel); + } protected void HandleChannelParted(Channel channel) => ChannelParted?.Invoke(channel); diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index c5b11ea94a..788847d368 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Concurrent; using System.Diagnostics; using System.Net.WebSockets; using System.Text; @@ -11,6 +12,7 @@ using Newtonsoft.Json; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Logging; using osu.Game.Online.API; +using osu.Game.Online.API.Requests; using osu.Game.Online.Chat; namespace osu.Game.Online.Notifications.WebSocket @@ -22,6 +24,7 @@ namespace osu.Game.Online.Notifications.WebSocket { private readonly ClientWebSocket socket; private readonly string endpoint; + private readonly ConcurrentDictionary channelsMap = new ConcurrentDictionary(); public WebSocketNotificationsClient(ClientWebSocket socket, string endpoint, IAPIProvider api) : base(api) @@ -110,7 +113,7 @@ namespace osu.Game.Online.Notifications.WebSocket await socket.SendAsync(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message)), WebSocketMessageType.Text, true, cancellationToken); } - private Task onMessageReceivedAsync(SocketMessage message) + private async Task onMessageReceivedAsync(SocketMessage message) { switch (message.Event) { @@ -120,7 +123,6 @@ namespace osu.Game.Online.Notifications.WebSocket Channel? joinedChannel = JsonConvert.DeserializeObject(message.Data.ToString()); Debug.Assert(joinedChannel != null); - joinedChannel.Joined.Value = true; HandleJoinedChannel(joinedChannel); break; @@ -140,13 +142,32 @@ namespace osu.Game.Online.Notifications.WebSocket Debug.Assert(messageData != null); foreach (var msg in messageData.Messages) - HandleJoinedChannel(new Channel { Id = msg.ChannelId }); + HandleJoinedChannel(await getChannel(msg.ChannelId)); HandleMessages(messageData.Messages); break; } + } - return Task.CompletedTask; + private async Task getChannel(long channelId) + { + if (channelsMap.TryGetValue(channelId, out Channel channel)) + return channel; + + var tsc = new TaskCompletionSource(); + var req = new GetChannelRequest(channelId); + + req.Success += response => + { + channelsMap[channelId] = response.Channel; + tsc.SetResult(response.Channel); + }; + + req.Failure += ex => tsc.SetException(ex); + + API.Queue(req); + + return await tsc.Task; } public override async ValueTask DisposeAsync() From fdca3c2d1c5e6d122e297bd4204b2115f081eb13 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 7 Nov 2022 14:35:42 +0900 Subject: [PATCH 2101/2686] Rename method for consistency --- osu.Game/Online/Notifications/NotificationsClient.cs | 4 ++-- .../Notifications/WebSocket/WebSocketNotificationsClient.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs index e5f477bc1e..6198707111 100644 --- a/osu.Game/Online/Notifications/NotificationsClient.cs +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -46,7 +46,7 @@ namespace osu.Game.Online.Notifications if (updates?.Presence != null) { foreach (var channel in updates.Presence) - HandleJoinedChannel(channel); + HandleChannelJoined(channel); //todo: handle left channels @@ -59,7 +59,7 @@ namespace osu.Game.Online.Notifications return fetchReq; } - protected void HandleJoinedChannel(Channel channel) + protected void HandleChannelJoined(Channel channel) { channel.Joined.Value = true; ChannelJoined?.Invoke(channel); diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index 788847d368..86836099d8 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -123,7 +123,7 @@ namespace osu.Game.Online.Notifications.WebSocket Channel? joinedChannel = JsonConvert.DeserializeObject(message.Data.ToString()); Debug.Assert(joinedChannel != null); - HandleJoinedChannel(joinedChannel); + HandleChannelJoined(joinedChannel); break; case @"chat.channel.part": @@ -142,7 +142,7 @@ namespace osu.Game.Online.Notifications.WebSocket Debug.Assert(messageData != null); foreach (var msg in messageData.Messages) - HandleJoinedChannel(await getChannel(msg.ChannelId)); + HandleChannelJoined(await getChannel(msg.ChannelId)); HandleMessages(messageData.Messages); break; From 1975385cc74e0a9a595cb1d31af2319281aa7ee9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 15:21:58 +0900 Subject: [PATCH 2102/2686] Move first tick tracking logic inside `TickPiece` --- .../Objects/Drawables/DrawableDrumRollTick.cs | 16 +++++++--- .../Skinning/Default/TickPiece.cs | 32 ++++++++++++------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index 451c5a793b..95b6384274 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -5,6 +5,7 @@ using System; using JetBrains.Annotations; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Game.Rulesets.Objects; @@ -16,6 +17,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables { public class DrawableDrumRollTick : DrawableTaikoStrongableHitObject { + public BindableBool IsFirstTick = new BindableBool(); + /// /// The hit type corresponding to the that the user pressed to hit this . /// @@ -32,14 +35,17 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables FillMode = FillMode.Fit; } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollTick), - _ => new TickPiece - { - Filled = HitObject.FirstTick - }); + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollTick), _ => new TickPiece()); public override double MaximumJudgementOffset => HitObject.HitWindow; + protected override void OnApply() + { + base.OnApply(); + + IsFirstTick.Value = HitObject.FirstTick; + } + protected override void CheckForResult(bool userTriggered, double timeOffset) { if (!userTriggered) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs index 09c8243aac..a1eaef53ba 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs @@ -1,9 +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 osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Objects.Drawables; using osuTK; using osuTK.Graphics; @@ -22,20 +26,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default /// private const float tick_size = 0.35f; - private bool filled; - - public bool Filled - { - get => filled; - set - { - filled = value; - fillBox.Alpha = filled ? 1 : 0; - } - } - private readonly Box fillBox; + private Bindable isFirstTick = null!; + public TickPiece() { Anchor = Anchor.Centre; @@ -62,5 +56,19 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default } }; } + + [Resolved] + private DrawableHitObject drawableHitObject { get; set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (drawableHitObject is DrawableDrumRollTick drumRollTick) + { + isFirstTick = drumRollTick.IsFirstTick.GetBoundCopy(); + isFirstTick.BindValueChanged(first => fillBox.Alpha = first.NewValue ? 1 : 0, true); + } + } } } From 28ab092b6f1d278f406e4e25cc812ac8184f3a74 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Mon, 7 Nov 2022 07:55:42 +0100 Subject: [PATCH 2103/2686] Simplify the whole Templating process --- .../Components/BeatmapInfoDrawable.cs | 125 +++--------------- 1 file changed, 17 insertions(+), 108 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs index 479124a43d..eda956e6d8 100644 --- a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs +++ b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs @@ -27,29 +27,11 @@ namespace osu.Game.Skinning.Components private const BeatmapInfo default_beatmap_info = BeatmapInfo.StarRating; public bool UsesFixedAnchor { get; set; } - [SettingSource("Tracked Beatmap Info/Label", "Which part of the BeatmapInformation should be displayed. Gets overridden by complex changes to ValueFormat")] + [SettingSource("Tracked Beatmap Info/Label", "Which part of the BeatmapInformation should be displayed.")] public Bindable Type { get; } = new Bindable(default_beatmap_info); - [SettingSource("Show Label", "Should a Label be shown, as to which status is currently Displayed?")] - public BindableBool ShowLabel { get; } = new BindableBool(true); - - [SettingSource("Show Value first?", "Should the Value be shown first?")] - public BindableBool ValueBeforeLabel { get; } = new BindableBool(); - - [SettingSource("Label Prefix", "Add something to be shown before the label")] - public Bindable LabelPrefix { get; set; } = new Bindable(""); - - [SettingSource("Show Label Prefix", "Should the Label Prefix be included?")] - public BindableBool ShowLabelPrefix { get; } = new BindableBool(); - - [SettingSource("Label Suffix", "Add something to be shown after the label")] - public Bindable LabelSuffix { get; set; } = new Bindable(": "); - - [SettingSource("Show Label Suffix", "Should the Label Suffix be included?")] - public BindableBool ShowLabelSuffix { get; } = new BindableBool(true); - - [SettingSource("Value Formatting", "Bypass the restriction of 1 Info per element. Format is '{'+Type+'}' to substitue values. e.g. '{Song}' ")] - public Bindable ValueFormat { get; set; } = new Bindable("{" + default_beatmap_info + "}"); + [SettingSource("Template", "Bypass the restriction of 1 Info per element. Format is '{'+Type+'}' to substitue values. e.g. '{Song}' ")] + public Bindable Template { get; set; } = new Bindable("{Label}: {Value}"); [Resolved] private IBindable beatmap { get; set; } = null!; @@ -76,7 +58,7 @@ namespace osu.Game.Skinning.Components [BeatmapInfo.Length] = ArtistStrings.TracklistLength, [BeatmapInfo.Status] = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault, [BeatmapInfo.BPM] = BeatmapsetsStrings.ShowStatsBpm, - [BeatmapInfo.Custom] = BeatmapInfo.Custom.ToString() + [BeatmapInfo.None] = BeatmapInfo.None.ToString() }.ToImmutableDictionary(); } @@ -99,102 +81,29 @@ namespace osu.Game.Skinning.Components } } - /// - /// This will return the if the format-String contains of a singular replacement of type info, or not. - /// If there is only one one replacement of type info, it will also return the prefix/suffix (or null if no prefix/suffix exists). - /// - /// The format-String to work on - /// The replacement Type to look for - /// (true, prefix, suffix), if there is only one replacement of type info. Else (false, null, null) - private static (bool, string?, string?) isOnlyPrefixedOrSuffixed(string format, BeatmapInfo info) - { - string[] s = format.Split("{" + info + "}"); - - foreach (string si in s) - { - foreach (var type in Enum.GetValues(typeof(BeatmapInfo)).Cast()) - { - if (si.Contains("{" + type + "}")) return (false, null, null); - } - } - - //Debug.WriteLine($"format:'{format}', type:{info} is only prefixed/suffixed"); - - return (true, - s.Length >= 1 ? s[0] : null, //prefix - s.Length >= 2 ? s[1] : null //suffix - ); - } - protected override void LoadComplete() { base.LoadComplete(); - Type.BindValueChanged(v => - { - string newDefault = "{" + v.NewValue + "}"; - bool custom = v.NewValue == BeatmapInfo.Custom; - - //If the ValueFormat is Default and the user did not change anything we should be able to just swap the strings. - //If it was Default before, it should be default after the Type is changed. - if (ValueFormat.IsDefault && !custom) - ValueFormat.Value = newDefault; - else - { - //In this if statement we decide if the ValueFormat has been trivially changed (so only been prefixed or suffixed) - (bool preOrSuffixed, string? prefix, string? suffix) = isOnlyPrefixedOrSuffixed(ValueFormat.Value, v.OldValue); - if (preOrSuffixed) - //If it has, we can keep the prefix and suffix and just change the thing that would be substituted. - ValueFormat.Value = (prefix ?? "") + newDefault + (suffix ?? ""); - //else we just keep the ValueFormat. I determine here, that the user probably knows what they are doing, and how the ValueFormat works. - } - - //Only if we could preserve the ValueFormat (so nothing was changed except a static prefix/suffix) I want to set the new Default. - ValueFormat.Default = newDefault; - updateLabel(); - }); - ValueFormat.BindValueChanged(f => updateLabel(), true); + Type.BindValueChanged(_ => updateLabel()); + Template.BindValueChanged(f => updateLabel(), true); beatmap.BindValueChanged(b => { UpdateBeatmapContent(b.NewValue); updateLabel(); }, true); - ShowLabel.BindValueChanged(_ => updateLabel()); - ValueBeforeLabel.BindValueChanged(_ => updateLabel()); - LabelPrefix.BindValueChanged(_ => updateLabel()); - ShowLabelPrefix.BindValueChanged(_ => updateLabel()); - LabelSuffix.BindValueChanged(_ => updateLabel()); - ShowLabelSuffix.BindValueChanged(_ => updateLabel()); - } - - private LocalisableString getLabelText() - { - if (!ShowLabel.Value) return new LocalisableString(""); - - return LocalisableString.Format("{0}{1}{2}", - ShowLabelPrefix.Value ? LabelPrefix.Value : "", - label_dictionary[Type.Value], - ShowLabelSuffix.Value ? LabelSuffix.Value : ""); - } - - private LocalisableString getValueText() - { - string value = ValueFormat.Value; - - foreach (var type in Enum.GetValues(typeof(BeatmapInfo)).Cast()) - { - value = value.Replace("{" + type + "}", valueDictionary[type].ToString()); - } - - return value; } private void updateLabel() { - text.Text = LocalisableString.Format( - ValueBeforeLabel.Value ? "{1}{0}" : "{0}{1}", - getLabelText(), - getValueText() - ); + string newText = Template.Value.Replace("{Label}", label_dictionary[Type.Value].ToString()) + .Replace("{Value}", valueDictionary[Type.Value].ToString()); + + foreach (var type in Enum.GetValues(typeof(BeatmapInfo)).Cast()) + { + newText = newText.Replace("{" + type + "}", valueDictionary[type].ToString()); + } + + text.Text = newText; Width = text.Width; Height = text.Height; } @@ -230,7 +139,7 @@ namespace osu.Game.Skinning.Components valueDictionary[BeatmapInfo.Status] = GetBetmapStatus(workingBeatmap.BeatmapInfo.Status); //update BPM valueDictionary[BeatmapInfo.BPM] = workingBeatmap.BeatmapInfo.BPM.ToString("F2"); - valueDictionary[BeatmapInfo.Custom] = BeatmapInfo.Custom.ToString(); + valueDictionary[BeatmapInfo.None] = string.Empty; } public static LocalisableString GetBetmapStatus(BeatmapOnlineStatus status) @@ -284,6 +193,6 @@ namespace osu.Game.Skinning.Components Length, Status, BPM, - Custom, + None, } } From 8745c2f0163760942e573ddae4c940c20c2b67aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 16:31:06 +0900 Subject: [PATCH 2104/2686] Split out taiko `DefaultJudgementPiece` and move animations across --- .../Skinning/Default/DefaultJudgementPiece.cs | 32 +++++++++++++++++++ .../UI/DrawableTaikoJudgement.cs | 28 ++-------------- 2 files changed, 34 insertions(+), 26 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs new file mode 100644 index 0000000000..a8cead6877 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.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.Graphics; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Taiko.Skinning.Default +{ + public class DefaultJudgementPiece : Rulesets.Judgements.DefaultJudgementPiece + { + public DefaultJudgementPiece(HitResult result) + : base(result) + { + } + + public override void PlayAnimation() + { + if (Result != HitResult.Miss) + { + this + .MoveToY(0) + .MoveToY(-100, 500); + + JudgementText + .ScaleTo(0.9f) + .ScaleTo(1, 500, Easing.OutElastic); + } + + base.PlayAnimation(); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs index 876fa207bf..dcb7dc25c0 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; +using DefaultJudgementPiece = osu.Game.Rulesets.Taiko.Skinning.Default.DefaultJudgementPiece; namespace osu.Game.Rulesets.Taiko.UI { @@ -12,31 +13,6 @@ namespace osu.Game.Rulesets.Taiko.UI /// public class DrawableTaikoJudgement : DrawableJudgement { - protected override void ApplyHitAnimations() - { - this.MoveToY(-100, 500); - base.ApplyHitAnimations(); - } - - protected override Drawable CreateDefaultJudgement(HitResult result) => new TaikoJudgementPiece(result); - - private class TaikoJudgementPiece : DefaultJudgementPiece - { - public TaikoJudgementPiece(HitResult result) - : base(result) - { - } - - public override void PlayAnimation() - { - if (Result != HitResult.Miss) - { - JudgementText.ScaleTo(0.9f); - JudgementText.ScaleTo(1, 500, Easing.OutElastic); - } - - base.PlayAnimation(); - } - } + protected override Drawable CreateDefaultJudgement(HitResult result) => new DefaultJudgementPiece(result); } } From 2b72c3833be2c8e8abc1c7dc6222914f7bea00b7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 17:05:16 +0900 Subject: [PATCH 2105/2686] Remove unnecessary centering logic in `DrawableJudgement` --- osu.Game/Rulesets/Judgements/DrawableJudgement.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 7e1196d4ca..daf7aafd77 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -168,11 +168,7 @@ namespace osu.Game.Rulesets.Judgements RemoveInternal(JudgementBody, true); AddInternal(JudgementBody = new SkinnableDrawable(new GameplaySkinComponent(type), _ => - CreateDefaultJudgement(type), confineMode: ConfineMode.NoScaling) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }); + CreateDefaultJudgement(type), confineMode: ConfineMode.NoScaling)); JudgementBody.OnSkinChanged += () => { From 564d0785171a4bc45398896216330506f32b2706 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 17:12:58 +0900 Subject: [PATCH 2106/2686] Fix much brokenness with kiai and justment sizing --- .../Skinning/Default/DefaultJudgementPiece.cs | 11 +++++++---- .../UI/DrawableTaikoJudgement.cs | 10 ++++++++++ osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 15 +++++---------- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs index a8cead6877..c85a8db788 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs @@ -11,6 +11,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default public DefaultJudgementPiece(HitResult result) : base(result) { + RelativePositionAxes = Axes.Both; } public override void PlayAnimation() @@ -18,15 +19,17 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default if (Result != HitResult.Miss) { this - .MoveToY(0) - .MoveToY(-100, 500); + .MoveToY(-0.6f) + .MoveToY(-1.5f, 500); JudgementText .ScaleTo(0.9f) .ScaleTo(1, 500, Easing.OutElastic); - } - base.PlayAnimation(); + this.FadeOutFromOne(800, Easing.OutQuint); + } + else + base.PlayAnimation(); } } } diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs index dcb7dc25c0..24d2fd7be7 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; +using osuTK; using DefaultJudgementPiece = osu.Game.Rulesets.Taiko.Skinning.Default.DefaultJudgementPiece; namespace osu.Game.Rulesets.Taiko.UI @@ -13,6 +14,15 @@ namespace osu.Game.Rulesets.Taiko.UI /// public class DrawableTaikoJudgement : DrawableJudgement { + public DrawableTaikoJudgement() + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + RelativeSizeAxes = Axes.Both; + Size = Vector2.One; + } + protected override Drawable CreateDefaultJudgement(HitResult result) => new DefaultJudgementPiece(result); } } diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index c4cff00d2a..faf107de77 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.UI JudgedObject = judgedObject; this.hitType = hitType; - Anchor = Anchor.CentreLeft; + Anchor = Anchor.Centre; Origin = Anchor.Centre; RelativeSizeAxes = Axes.Both; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index cc71ba5401..d6d4a4e3f0 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -146,13 +146,16 @@ namespace osu.Game.Rulesets.Taiko.UI kiaiExplosionContainer = new Container { Name = "Kiai hit explosions", + Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fit, }, judgementContainer = new JudgementContainer { Name = "Judgements", - RelativeSizeAxes = Axes.Y, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, }, } }, @@ -320,15 +323,7 @@ namespace osu.Game.Rulesets.Taiko.UI if (!result.Type.IsScorable()) break; - judgementContainer.Add(judgementPools[result.Type].Get(j => - { - j.Apply(result, judgedObject); - - j.Anchor = result.IsHit ? Anchor.TopLeft : Anchor.CentreLeft; - j.Origin = result.IsHit ? Anchor.BottomCentre : Anchor.Centre; - j.RelativePositionAxes = Axes.X; - j.X = result.IsHit ? judgedObject.Position.X : 0; - })); + judgementContainer.Add(judgementPools[result.Type].Get(j => j.Apply(result, judgedObject))); var type = (judgedObject.HitObject as Hit)?.Type ?? HitType.Centre; addExplosion(judgedObject, result.Type, type); From ddc2ed1542a254c619692595ac1ef7330523dc40 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 13:22:01 +0900 Subject: [PATCH 2107/2686] Fix height of playfield in taiko tests --- .../Skinning/TestSceneDrawableBarLine.cs | 6 ++--- .../Skinning/TestSceneTaikoPlayfield.cs | 24 +++++++++++++++---- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs index ad6f08dbd4..a4aa0e1fad 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning var cont = new Container { RelativeSizeAxes = Axes.Both, - Height = 0.8f, + Height = 0.2f, Anchor = Anchor.Centre, Origin = Anchor.Centre, Children = new Drawable[] @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning var cont = new Container { RelativeSizeAxes = Axes.Both, - Height = 0.8f, + Height = 0.2f, Anchor = Anchor.Centre, Origin = Anchor.Centre, Children = new Drawable[] @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning var barLine = new BarLine { Major = major, - StartTime = Time.Current + 2000, + StartTime = Time.Current + 5000, }; var cpi = new ControlPointInfo(); diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs index 52d24b567f..eff9f58751 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; @@ -25,11 +26,10 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning TimeRange = { Value = 5000 }, }; - public TestSceneTaikoPlayfield() + [SetUpSteps] + public void SetUpSteps() { TaikoBeatmap beatmap; - bool kiai = false; - AddStep("set beatmap", () => { Beatmap.Value = CreateWorkingBeatmap(beatmap = new TaikoBeatmap()); @@ -41,12 +41,28 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning AddStep("Load playfield", () => SetContents(_ => new TaikoPlayfield { + Height = 0.2f, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Height = 0.6f, })); + } + [Test] + public void TestBasic() + { + AddStep("do nothing", () => { }); + } + + [Test] + public void TestHeightChanges() + { AddRepeatStep("change height", () => this.ChildrenOfType().ForEach(p => p.Height = Math.Max(0.2f, (p.Height + 0.2f) % 1f)), 50); + } + + [Test] + public void TestKiai() + { + bool kiai = false; AddStep("Toggle kiai", () => { From baf8db8de4ae9a2b26d9401b02b66463ffd39cae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 15:45:32 +0900 Subject: [PATCH 2108/2686] Add basic setup for taiko argon skinning --- .../Argon/TaikoArgonSkinTransformer.cs | 34 +++++++++++++++++++ osu.Game.Rulesets.Taiko/TaikoRuleset.cs | 4 +++ 2 files changed, 38 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs new file mode 100644 index 0000000000..13c484af24 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -0,0 +1,34 @@ +// 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.Graphics; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class TaikoArgonSkinTransformer : SkinTransformer + { + public TaikoArgonSkinTransformer(ISkin skin) + : base(skin) + { + } + + public override Drawable? GetDrawableComponent(ISkinComponent component) + { + switch (component) + { + case TaikoSkinComponent catchComponent: + // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. + switch (catchComponent.Component) + { + case TaikoSkinComponents.CentreHit: + return Drawable.Empty(); + } + + break; + } + + return base.GetDrawableComponent(component); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index dc36bc0320..fe12cf9765 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -24,6 +24,7 @@ using osu.Game.Rulesets.Taiko.Mods; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Replays; using osu.Game.Rulesets.Taiko.Scoring; +using osu.Game.Rulesets.Taiko.Skinning.Argon; using osu.Game.Rulesets.Taiko.Skinning.Legacy; using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.UI; @@ -47,6 +48,9 @@ namespace osu.Game.Rulesets.Taiko { switch (skin) { + case ArgonSkin: + return new TaikoArgonSkinTransformer(skin); + case LegacySkin: return new TaikoLegacySkinTransformer(skin); } From bc0e9375afcc54b108246f6bb60e2b3e50425b82 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 16:52:09 +0900 Subject: [PATCH 2109/2686] Add basic argon hits --- .../Skinning/Argon/ArgonCentreCirclePiece.cs | 21 ++++ .../Skinning/Argon/ArgonCirclePiece.cs | 116 ++++++++++++++++++ .../Skinning/Argon/ArgonRimCirclePiece.cs | 21 ++++ .../Skinning/Argon/RingPiece.cs | 40 ++++++ .../Argon/TaikoArgonSkinTransformer.cs | 5 +- 5 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs new file mode 100644 index 0000000000..234d9f659a --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Colour; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonCentreCirclePiece : ArgonCirclePiece + { + [BackgroundDependencyLoader] + private void load() + { + AccentColour = ColourInfo.GradientVertical( + new Color4(241, 0, 0, 255), + new Color4(167, 0, 0, 255) + ); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs new file mode 100644 index 0000000000..b58b7455fd --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs @@ -0,0 +1,116 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Audio.Track; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; +using osu.Game.Rulesets.Objects.Drawables; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public abstract class ArgonCirclePiece : BeatSyncedContainer + { + private const double pre_beat_transition_time = 80; + + private const float flash_opacity = 0.3f; + + private ColourInfo accentColour; + + /// + /// The colour of the inner circle and outer glows. + /// + public ColourInfo AccentColour + { + get => accentColour; + set + { + accentColour = value; + ring.Colour = AccentColour.MultiplyAlpha(0.5f); + ring2.Colour = AccentColour; + } + } + + /// + /// Whether Kiai mode effects are enabled for this circle piece. + /// + public bool KiaiMode { get; set; } + + public Box FlashBox; + + private readonly RingPiece ring; + private readonly RingPiece ring2; + + protected ArgonCirclePiece() + { + RelativeSizeAxes = Axes.Both; + + EarlyActivationMilliseconds = pre_beat_transition_time; + + AddRangeInternal(new Drawable[] + { + new Circle + { + RelativeSizeAxes = Axes.Both, + Colour = new Color4(0, 22, 30, 190) + }, + ring = new RingPiece(20 / 70f), + ring2 = new RingPiece(5 / 70f), + new CircularContainer + { + Name = "Flash layer", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Children = new[] + { + FlashBox = new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + Blending = BlendingParameters.Additive, + Alpha = 0, + AlwaysPresent = true + } + }, + }, + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.Solid.AngleLeft, + Size = new Vector2(20 / 70f), + Scale = new Vector2(0.8f, 1) + } + }); + } + + [Resolved] + private DrawableHitObject drawableHitObject { get; set; } = null!; + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + if (!effectPoint.KiaiMode) + return; + + if (drawableHitObject.State.Value == ArmedState.Idle) + { + FlashBox + .FadeTo(flash_opacity) + .Then() + .FadeOut(timingPoint.BeatLength * 0.75, Easing.OutSine); + } + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs new file mode 100644 index 0000000000..5dc955c56e --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Colour; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonRimCirclePiece : ArgonCirclePiece + { + [BackgroundDependencyLoader] + private void load() + { + AccentColour = ColourInfo.GradientVertical( + new Color4(0, 161, 241, 255), + new Color4(0, 111, 167, 255) + ); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs new file mode 100644 index 0000000000..2c5d824ff5 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs @@ -0,0 +1,40 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class RingPiece : CircularContainer + { + private readonly float relativeBorderThickness; + + public RingPiece(float relativeBorderThickness) + { + this.relativeBorderThickness = relativeBorderThickness; + RelativeSizeAxes = Axes.Both; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Masking = true; + BorderColour = Color4.White; + + Child = new Box + { + AlwaysPresent = true, + Alpha = 0, + RelativeSizeAxes = Axes.Both + }; + } + + protected override void Update() + { + base.Update(); + BorderThickness = relativeBorderThickness * DrawSize.X; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index 13c484af24..f223d35b0a 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -22,7 +22,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon switch (catchComponent.Component) { case TaikoSkinComponents.CentreHit: - return Drawable.Empty(); + return new ArgonCentreCirclePiece(); + + case TaikoSkinComponents.RimHit: + return new ArgonRimCirclePiece(); } break; From 421bdd2c1a3736c0583150deb5c585f8d64771a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 13:16:51 +0900 Subject: [PATCH 2110/2686] Add playfield background implementations --- .../Argon/ArgonPlayfieldBackgroundLeft.cs | 27 ++++++++++++++++++ .../Argon/ArgonPlayfieldBackgroundRight.cs | 28 +++++++++++++++++++ .../Argon/TaikoArgonSkinTransformer.cs | 6 ++++ 3 files changed, 61 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundLeft.cs create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundRight.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundLeft.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundLeft.cs new file mode 100644 index 0000000000..ebde83b607 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundLeft.cs @@ -0,0 +1,27 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonPlayfieldBackgroundLeft : CompositeDrawable + { + public ArgonPlayfieldBackgroundLeft() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + }, + }; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundRight.cs new file mode 100644 index 0000000000..bd0f3ab276 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundRight.cs @@ -0,0 +1,28 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonPlayfieldBackgroundRight : CompositeDrawable + { + public ArgonPlayfieldBackgroundRight() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + new Box + { + Colour = Color4.Black, + Alpha = 0.7f, + RelativeSizeAxes = Axes.Both, + }, + }; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index f223d35b0a..d2a3e19f38 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -26,6 +26,12 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.RimHit: return new ArgonRimCirclePiece(); + + case TaikoSkinComponents.PlayfieldBackgroundLeft: + return new ArgonPlayfieldBackgroundLeft(); + + case TaikoSkinComponents.PlayfieldBackgroundRight: + return new ArgonPlayfieldBackgroundRight(); } break; From f1a1f29da78de9d49de56b9fda3728ccd84453b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 13:43:04 +0900 Subject: [PATCH 2111/2686] Add hit target implementation --- .../Skinning/Argon/ArgonHitTarget.cs | 72 +++++++++++++++++++ .../Argon/TaikoArgonSkinTransformer.cs | 3 + 2 files changed, 75 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitTarget.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitTarget.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitTarget.cs new file mode 100644 index 0000000000..ec2eccd595 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitTarget.cs @@ -0,0 +1,72 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Taiko.Objects; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonHitTarget : CompositeDrawable + { + /// + /// Thickness of all drawn line pieces. + /// + public ArgonHitTarget() + { + RelativeSizeAxes = Axes.Both; + Masking = true; + + const float border_thickness = 4f; + + InternalChildren = new Drawable[] + { + new Circle + { + Name = "Bar Upper", + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Y = -border_thickness, + RelativeSizeAxes = Axes.Y, + Size = new Vector2(border_thickness, (1 - TaikoStrongableHitObject.DEFAULT_STRONG_SIZE)), + }, + new Circle + { + Name = "Outer circle", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + Blending = BlendingParameters.Additive, + Alpha = 0.1f, + Size = new Vector2(TaikoHitObject.DEFAULT_SIZE), + Masking = true, + }, + new Circle + { + Name = "Inner circle", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + Blending = BlendingParameters.Additive, + Alpha = 0.1f, + Size = new Vector2(TaikoHitObject.DEFAULT_SIZE * 0.85f), + Masking = true, + }, + new Circle + { + Name = "Bar Lower", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Y, + Y = border_thickness, + Size = new Vector2(border_thickness, (1 - TaikoStrongableHitObject.DEFAULT_STRONG_SIZE)), + }, + }; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index d2a3e19f38..eec7e92511 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -32,6 +32,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.PlayfieldBackgroundRight: return new ArgonPlayfieldBackgroundRight(); + + case TaikoSkinComponents.HitTarget: + return new ArgonHitTarget(); } break; From 529e3217cfea2571d4f405836a592a988fb16a3e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 14:01:18 +0900 Subject: [PATCH 2112/2686] Add barline implementation --- .../Skinning/Argon/ArgonBarLine.cs | 83 +++++++++++++++++++ .../Argon/TaikoArgonSkinTransformer.cs | 3 + 2 files changed, 86 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonBarLine.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonBarLine.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonBarLine.cs new file mode 100644 index 0000000000..402e88b64d --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonBarLine.cs @@ -0,0 +1,83 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osuTK; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonBarLine : CompositeDrawable + { + private Container majorEdgeContainer = null!; + + private Bindable major = null!; + + [BackgroundDependencyLoader] + private void load(DrawableHitObject drawableHitObject) + { + RelativeSizeAxes = Axes.Both; + + const float line_offset = 8; + var majorPieceSize = new Vector2(6, 20); + + InternalChildren = new Drawable[] + { + line = new Box + { + RelativeSizeAxes = Axes.Both, + EdgeSmoothness = new Vector2(0.5f, 0), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + majorEdgeContainer = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new Circle + { + Name = "Top line", + Anchor = Anchor.TopCentre, + Origin = Anchor.BottomCentre, + Size = majorPieceSize, + Y = -line_offset, + }, + new Circle + { + Name = "Bottom line", + Anchor = Anchor.BottomCentre, + Origin = Anchor.TopCentre, + Size = majorPieceSize, + Y = line_offset, + }, + } + } + }; + + major = ((DrawableBarLine)drawableHitObject).Major.GetBoundCopy(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + major.BindValueChanged(updateMajor, true); + } + + private Box line = null!; + + private void updateMajor(ValueChangedEvent major) + { + line.Alpha = major.NewValue ? 1f : 0.5f; + line.Width = major.NewValue ? 1 : 0.5f; + majorEdgeContainer.Alpha = major.NewValue ? 1 : 0; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index eec7e92511..0d5c19a525 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -35,6 +35,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.HitTarget: return new ArgonHitTarget(); + + case TaikoSkinComponents.BarLine: + return new ArgonBarLine(); } break; From 66365451952639040590a7d328ce4bb8ea9853a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 15:07:33 +0900 Subject: [PATCH 2113/2686] Move taiko argon hit icon to respective centre/rim pieces --- .../Skinning/Argon/ArgonCentreCirclePiece.cs | 13 +++++++++++++ .../Skinning/Argon/ArgonCirclePiece.cs | 11 ----------- .../Skinning/Argon/ArgonRimCirclePiece.cs | 13 +++++++++++++ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs index 234d9f659a..f347863be9 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs @@ -2,7 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Sprites; +using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon @@ -16,6 +19,16 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon new Color4(241, 0, 0, 255), new Color4(167, 0, 0, 255) ); + + AddInternal(new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.Solid.AngleLeft, + Size = new Vector2(20 / 70f), + Scale = new Vector2(0.8f, 1) + }); } } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs index b58b7455fd..ba8ef12902 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs @@ -7,11 +7,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; -using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon @@ -84,15 +82,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon } }, }, - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Icon = FontAwesome.Solid.AngleLeft, - Size = new Vector2(20 / 70f), - Scale = new Vector2(0.8f, 1) - } }); } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs index 5dc955c56e..390f134d6f 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs @@ -2,7 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Sprites; +using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon @@ -16,6 +19,16 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon new Color4(0, 161, 241, 255), new Color4(0, 111, 167, 255) ); + + AddInternal(new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.Solid.AngleLeft, + Size = new Vector2(20 / 70f), + Scale = new Vector2(0.8f, 1) + }); } } } From f1556c98e3e4ccf5fe89e92f62a8f109b73db730 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 15:07:47 +0900 Subject: [PATCH 2114/2686] Add drum roll implementation --- .../Argon/ArgonElongatedCirclePiece.cs | 33 +++++++++++++++++++ .../Skinning/Argon/RingPiece.cs | 2 +- .../Argon/TaikoArgonSkinTransformer.cs | 3 ++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonElongatedCirclePiece.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonElongatedCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonElongatedCirclePiece.cs new file mode 100644 index 0000000000..f86f181b2e --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonElongatedCirclePiece.cs @@ -0,0 +1,33 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonElongatedCirclePiece : ArgonCirclePiece + { + public ArgonElongatedCirclePiece() + { + RelativeSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load() + { + AccentColour = ColourInfo.GradientVertical( + new Color4(241, 161, 0, 255), + new Color4(167, 111, 0, 255) + ); + } + + protected override void Update() + { + base.Update(); + Width = Parent.DrawSize.X + DrawHeight; + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs index 2c5d824ff5..534a1c71a3 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon protected override void Update() { base.Update(); - BorderThickness = relativeBorderThickness * DrawSize.X; + BorderThickness = relativeBorderThickness * DrawSize.Y; } } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index 0d5c19a525..64f733a969 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -38,6 +38,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.BarLine: return new ArgonBarLine(); + + case TaikoSkinComponents.DrumRollBody: + return new ArgonElongatedCirclePiece(); } break; From 938a8f865b51e2df7b2508f3a53cb15d577292a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 15:11:40 +0900 Subject: [PATCH 2115/2686] Adjust transform of taiko drum roll ticks to not scale to 0 (looks bad) --- .../Objects/Drawables/DrawableDrumRollTick.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index 95b6384274..ed89d0a14e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -74,7 +74,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables switch (state) { case ArmedState.Hit: - this.ScaleTo(0, 100, Easing.OutQuint); + this.ScaleTo(1.4f, 200, Easing.OutQuint); + this.FadeOut(200, Easing.OutQuint); break; } } From aa61eb8f4bb61f8f51fef5edb669e62913583f02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 15:17:20 +0900 Subject: [PATCH 2116/2686] Add note about taiko pooling oversight --- .../Objects/Drawables/DrawableTaikoHitObject.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index c0c80eaa4a..400c2f40b1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -133,6 +133,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override void OnApply() { base.OnApply(); + + // TODO: THIS CANNOT BE HERE, it makes pooling pointless (see https://github.com/ppy/osu/issues/21072). RecreatePieces(); } From e2046791c2aff7e07532016d8a771f5e4d3b1a3a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 15:39:24 +0900 Subject: [PATCH 2117/2686] Add argon drum roll ticks --- .../Skinning/Argon/ArgonCentreCirclePiece.cs | 2 +- .../Skinning/Argon/ArgonCirclePiece.cs | 2 + .../Skinning/Argon/ArgonRimCirclePiece.cs | 2 +- .../Skinning/Argon/ArgonTickPiece.cs | 68 +++++++++++++++++++ .../Argon/TaikoArgonSkinTransformer.cs | 3 + 5 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonTickPiece.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs index f347863be9..551a5af078 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Icon = FontAwesome.Solid.AngleLeft, - Size = new Vector2(20 / 70f), + Size = new Vector2(ICON_SIZE), Scale = new Vector2(0.8f, 1) }); } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs index ba8ef12902..8ef7b71069 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs @@ -16,6 +16,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon { public abstract class ArgonCirclePiece : BeatSyncedContainer { + public const float ICON_SIZE = 20 / 70f; + private const double pre_beat_transition_time = 80; private const float flash_opacity = 0.3f; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs index 390f134d6f..fd81221be3 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, Icon = FontAwesome.Solid.AngleLeft, - Size = new Vector2(20 / 70f), + Size = new Vector2(ICON_SIZE), Scale = new Vector2(0.8f, 1) }); } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonTickPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonTickPiece.cs new file mode 100644 index 0000000000..df63d4948e --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonTickPiece.cs @@ -0,0 +1,68 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osuTK; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonTickPiece : CompositeDrawable + { + private readonly Bindable isFirstTick = new Bindable(); + + public ArgonTickPiece() + { + const float tick_size = 1 / TaikoHitObject.DEFAULT_SIZE * ArgonCirclePiece.ICON_SIZE; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + RelativeSizeAxes = Axes.Both; + FillMode = FillMode.Fit; + Size = new Vector2(tick_size); + } + + [Resolved] + private DrawableHitObject drawableHitObject { get; set; } = null!; + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (drawableHitObject is DrawableDrumRollTick drumRollTick) + isFirstTick.BindTo(drumRollTick.IsFirstTick); + + isFirstTick.BindValueChanged(first => + { + if (first.NewValue) + { + InternalChild = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both + }; + } + else + { + InternalChild = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.Solid.AngleLeft, + Scale = new Vector2(0.8f, 1) + }; + } + }, true); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index 64f733a969..6782ae67f9 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -41,6 +41,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.DrumRollBody: return new ArgonElongatedCirclePiece(); + + case TaikoSkinComponents.DrumRollTick: + return new ArgonTickPiece(); } break; From 37cb187d2eb958167df1397dedda7a53a094f6b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 16:17:43 +0900 Subject: [PATCH 2118/2686] Move strong hit scale to `DefaultHitExplosion` --- osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs | 2 ++ osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs index b7ba76effa..2e76396a4d 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.UI; +using osuTK; using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Default @@ -74,6 +75,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default public void AnimateSecondHit() { + this.ResizeTo(new Vector2(TaikoStrongableHitObject.STRONG_SCALE), 50); } } } diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 10a7495c62..d9b6db7734 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -90,7 +90,6 @@ namespace osu.Game.Rulesets.Taiko.UI { using (BeginAbsoluteSequence(secondHitTime.Value)) { - this.ResizeTo(new Vector2(TaikoStrongableHitObject.DEFAULT_STRONG_SIZE), 50); (skinnable.Drawable as IAnimatableHitExplosion)?.AnimateSecondHit(); } } From d5c375b139f135e9ffc49ae4c9e67f8979b07865 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 16:18:03 +0900 Subject: [PATCH 2119/2686] Add argon hit explosion implementation --- .../Skinning/Argon/ArgonHitExplosion.cs | 87 +++++++++++++++++++ .../Argon/TaikoArgonSkinTransformer.cs | 9 ++ 2 files changed, 96 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitExplosion.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitExplosion.cs new file mode 100644 index 0000000000..05bb9bcb9a --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitExplosion.cs @@ -0,0 +1,87 @@ +// 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.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.UI; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonHitExplosion : CompositeDrawable, IAnimatableHitExplosion + { + private readonly TaikoSkinComponents component; + private readonly Circle outer; + + public ArgonHitExplosion(TaikoSkinComponents component) + { + this.component = component; + + RelativeSizeAxes = Axes.Both; + + InternalChildren = new Drawable[] + { + outer = new Circle + { + Name = "Outer circle", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical( + new Color4(255, 227, 236, 255), + new Color4(255, 198, 211, 255) + ), + Masking = true, + }, + new Circle + { + Name = "Inner circle", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + Size = new Vector2(0.85f), + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = new Color4(255, 132, 191, 255).Opacity(0.5f), + Radius = 45, + }, + Masking = true, + }, + }; + } + + public void Animate(DrawableHitObject drawableHitObject) + { + this.FadeOut(); + + switch (component) + { + case TaikoSkinComponents.TaikoExplosionGreat: + this.FadeIn(30, Easing.In) + .Then() + .FadeOut(450, Easing.OutQuint); + break; + + case TaikoSkinComponents.TaikoExplosionOk: + this.FadeTo(0.2f, 30, Easing.In) + .Then() + .FadeOut(200, Easing.OutQuint); + break; + } + } + + public void AnimateSecondHit() + { + outer.ResizeTo(new Vector2(TaikoStrongableHitObject.STRONG_SCALE), 500, Easing.OutQuint); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index 6782ae67f9..3b75cfff11 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -44,6 +44,15 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.DrumRollTick: return new ArgonTickPiece(); + + case TaikoSkinComponents.TaikoExplosionKiai: + // the drawable needs to expire as soon as possible to avoid accumulating empty drawables on the playfield. + return Drawable.Empty().With(d => d.Expire()); + + case TaikoSkinComponents.TaikoExplosionGreat: + case TaikoSkinComponents.TaikoExplosionMiss: + case TaikoSkinComponents.TaikoExplosionOk: + return new ArgonHitExplosion(catchComponent.Component); } break; From b15d1bc333c9a379c56e0bd7466a4b7795b9fc77 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 16:31:24 +0900 Subject: [PATCH 2120/2686] Add argon result display implementation --- .../Skinning/Argon/ArgonJudgementPiece.cs | 198 ++++++++++++++++++ .../Argon/TaikoArgonSkinTransformer.cs | 4 + 2 files changed, 202 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs new file mode 100644 index 0000000000..0ea0473023 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs @@ -0,0 +1,198 @@ +// 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.Allocation; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Utils; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + { + protected readonly HitResult Result; + + protected SpriteText JudgementText { get; private set; } = null!; + + private RingExplosion? ringExplosion; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + public ArgonJudgementPiece(HitResult result) + { + Result = result; + RelativePositionAxes = Axes.Both; + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + JudgementText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = Result.GetDescription().ToUpperInvariant(), + Colour = colours.ForHitResult(Result), + Blending = BlendingParameters.Additive, + Spacing = new Vector2(10, 0), + RelativePositionAxes = Axes.Both, + Font = OsuFont.Default.With(size: 20, weight: FontWeight.Regular), + }, + }; + + if (Result.IsHit()) + { + AddInternal(ringExplosion = new RingExplosion(Result) + { + Colour = colours.ForHitResult(Result), + RelativePositionAxes = Axes.Y, + }); + } + } + + /// + /// Plays the default animation for this judgement piece. + /// + /// + /// The base implementation only handles fade (for all result types) and misses. + /// Individual rulesets are recommended to implement their appropriate hit animations. + /// + public virtual void PlayAnimation() + { + const double duration = 800; + + switch (Result) + { + default: + JudgementText.MoveToY(-0.2f) + .MoveToY(-0.8f, duration, Easing.OutQuint); + + JudgementText + .ScaleTo(Vector2.One) + .ScaleTo(new Vector2(1.8f), duration, Easing.OutQuint); + break; + + case HitResult.Miss: + this.ScaleTo(1.6f); + this.ScaleTo(1, 100, Easing.In); + + JudgementText.MoveTo(Vector2.Zero); + JudgementText.MoveToOffset(new Vector2(0, 100), duration, Easing.InQuint); + + this.RotateTo(0); + this.RotateTo(40, duration, Easing.InQuint); + break; + } + + this.FadeOutFromOne(duration, Easing.OutQuint); + + ringExplosion?.PlayAnimation(); + } + + public Drawable? GetAboveHitObjectsProxiedContent() => null; + + private class RingExplosion : CompositeDrawable + { + private readonly float travel = 58; + + public RingExplosion(HitResult result) + { + const float thickness = 4; + + const float small_size = 9; + const float large_size = 14; + + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Blending = BlendingParameters.Additive; + + int countSmall = 0; + int countLarge = 0; + + switch (result) + { + case HitResult.Meh: + countSmall = 3; + travel *= 0.3f; + break; + + case HitResult.Ok: + case HitResult.Good: + countSmall = 4; + travel *= 0.6f; + break; + + case HitResult.Great: + case HitResult.Perfect: + countSmall = 4; + countLarge = 4; + break; + } + + for (int i = 0; i < countSmall; i++) + AddInternal(new RingPiece(thickness) { Size = new Vector2(small_size) }); + + for (int i = 0; i < countLarge; i++) + AddInternal(new RingPiece(thickness) { Size = new Vector2(large_size) }); + } + + public void PlayAnimation() + { + foreach (var c in InternalChildren) + { + const float start_position_ratio = 0.6f; + + float direction = RNG.NextSingle(0, 360); + float distance = RNG.NextSingle(travel / 2, travel); + + c.MoveTo(new Vector2( + MathF.Cos(direction) * distance * start_position_ratio, + MathF.Sin(direction) * distance * start_position_ratio + )); + + c.MoveTo(new Vector2( + MathF.Cos(direction) * distance, + MathF.Sin(direction) * distance + ), 600, Easing.OutQuint); + } + + this.FadeOutFromOne(1000, Easing.OutQuint); + } + + public class RingPiece : CircularContainer + { + public RingPiece(float thickness = 9) + { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + Masking = true; + BorderThickness = thickness; + BorderColour = Color4.White; + + Child = new Box + { + AlwaysPresent = true, + Alpha = 0, + RelativeSizeAxes = Axes.Both + }; + } + } + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index 3b75cfff11..a6e053f0df 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; +using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Skinning.Argon @@ -17,6 +18,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon { switch (component) { + case GameplaySkinComponent resultComponent: + return new ArgonJudgementPiece(resultComponent.Component); + case TaikoSkinComponent catchComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (catchComponent.Component) From d57ec4b227331f6264671cfb6776261aca76c4a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 17:29:27 +0900 Subject: [PATCH 2121/2686] Add argon input drum implementation --- .../Skinning/Argon/ArgonInputDrum.cs | 218 ++++++++++++++++++ .../Argon/TaikoArgonSkinTransformer.cs | 3 + 2 files changed, 221 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonInputDrum.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonInputDrum.cs new file mode 100644 index 0000000000..528e75aabb --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonInputDrum.cs @@ -0,0 +1,218 @@ +// 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.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Graphics; +using osu.Game.Screens.Ranking; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonInputDrum : AspectContainer + { + private const float rim_size = 0.3f; + + public ArgonInputDrum() + { + RelativeSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader] + private void load() + { + const float middle_split = 6; + + InternalChild = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Scale = new Vector2(0.9f), + Children = new Drawable[] + { + new TaikoHalfDrum(false) + { + Name = "Left Half", + Anchor = Anchor.Centre, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + RimAction = TaikoAction.LeftRim, + CentreAction = TaikoAction.LeftCentre + }, + new TaikoHalfDrum(true) + { + Name = "Right Half", + Anchor = Anchor.Centre, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + RimAction = TaikoAction.RightRim, + CentreAction = TaikoAction.RightCentre + }, + new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Masking = true, + Children = new Drawable[] + { + new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = OsuColour.Gray(38 / 255f), + Width = middle_split, + RelativeSizeAxes = Axes.Y, + }, + new Box + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Colour = OsuColour.Gray(48 / 255f), + Width = middle_split, + Height = 1 - rim_size, + RelativeSizeAxes = Axes.Y, + }, + }, + } + } + }; + } + + /// + /// A half-drum. Contains one centre and one rim hit. + /// + private class TaikoHalfDrum : CompositeDrawable, IKeyBindingHandler + { + /// + /// The key to be used for the rim of the half-drum. + /// + public TaikoAction RimAction; + + /// + /// The key to be used for the centre of the half-drum. + /// + public TaikoAction CentreAction; + + private readonly Drawable rimHit; + private readonly Drawable centreHit; + + public TaikoHalfDrum(bool flipped) + { + Anchor anchor = flipped ? Anchor.CentreLeft : Anchor.CentreRight; + + Masking = true; + + Anchor = anchor; + Origin = anchor; + + RelativeSizeAxes = Axes.Both; + // Extend maskable region for glow. + Height = 2f; + + InternalChildren = new Drawable[] + { + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Children = new[] + { + new Circle + { + Anchor = anchor, + Colour = OsuColour.Gray(51 / 255f), + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both + }, + rimHit = new Circle + { + Anchor = anchor, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal( + new Color4(227, 248, 255, 255), + new Color4(198, 245, 255, 255) + ), + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = new Color4(126, 215, 253, 170), + Radius = 50, + }, + Alpha = 0, + }, + new Circle + { + Anchor = anchor, + Origin = Anchor.Centre, + Colour = OsuColour.Gray(64 / 255f), + RelativeSizeAxes = Axes.Both, + Size = new Vector2(1 - rim_size) + }, + centreHit = new Circle + { + Anchor = anchor, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal( + new Color4(255, 227, 236, 255), + new Color4(255, 198, 211, 255) + ), + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = new Color4(255, 147, 199, 255), + Radius = 50, + }, + Size = new Vector2(1 - rim_size), + Alpha = 0, + } + }, + }, + }; + } + + public bool OnPressed(KeyBindingPressEvent e) + { + Drawable? target = null; + + if (e.Action == CentreAction) + target = centreHit; + else if (e.Action == RimAction) + target = rimHit; + + if (target != null) + { + const float alpha_amount = 0.5f; + + const float down_time = 40; + const float up_time = 750; + + target.Animate( + t => t.FadeTo(Math.Min(target.Alpha + alpha_amount, 1), down_time, Easing.OutQuint) + ).Then( + t => t.FadeOut(up_time, Easing.OutQuint) + ); + } + + return false; + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index a6e053f0df..f0d14f657d 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -37,6 +37,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.PlayfieldBackgroundRight: return new ArgonPlayfieldBackgroundRight(); + case TaikoSkinComponents.InputDrum: + return new ArgonInputDrum(); + case TaikoSkinComponents.HitTarget: return new ArgonHitTarget(); From de2dac22b86fea188daa886a01e65adcf136e2cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 18:46:04 +0900 Subject: [PATCH 2122/2686] Ensure seeding screen is refreshed on entering --- .../Screens/TeamIntro/SeedingScreen.cs | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs index 9262cab098..8bc28e1068 100644 --- a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs +++ b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs @@ -70,16 +70,16 @@ namespace osu.Game.Tournament.Screens.TeamIntro currentTeam.BindValueChanged(teamChanged, true); } - private void teamChanged(ValueChangedEvent team) => Scheduler.AddOnce(() => - { - if (team.NewValue == null) - { - mainContainer.Clear(); - return; - } + private void teamChanged(ValueChangedEvent team) => updateTeamDisplay(); - showTeam(team.NewValue); - }); + public override void Show() + { + base.Show(); + + // Changes could have been made on editor screen. + // Rather than trying to track all the possibilities (teams / players / scores) just force a full refresh. + updateTeamDisplay(); + } protected override void CurrentMatchChanged(ValueChangedEvent match) { @@ -91,14 +91,20 @@ namespace osu.Game.Tournament.Screens.TeamIntro currentTeam.Value = match.NewValue.Team1.Value; } - private void showTeam(TournamentTeam team) + private void updateTeamDisplay() => Scheduler.AddOnce(() => { + if (currentTeam.Value == null) + { + mainContainer.Clear(); + return; + } + mainContainer.Children = new Drawable[] { - new LeftInfo(team) { Position = new Vector2(55, 150), }, - new RightInfo(team) { Position = new Vector2(500, 150), }, + new LeftInfo(currentTeam.Value) { Position = new Vector2(55, 150), }, + new RightInfo(currentTeam.Value) { Position = new Vector2(500, 150), }, }; - } + }); private class RightInfo : CompositeDrawable { From 64f9d6c8916d13e225e7631b8662793d7edb3220 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 19:03:56 +0900 Subject: [PATCH 2123/2686] Fix potential cross-thread drawable operation in round editor screen --- osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs index 1b670f4b69..0bd5ddb257 100644 --- a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs @@ -256,7 +256,7 @@ namespace osu.Game.Tournament.Screens.Editors mods.BindValueChanged(modString => Model.Mods = modString.NewValue); } - private void updatePanel() + private void updatePanel() => Schedule(() => { drawableContainer.Clear(); @@ -269,7 +269,7 @@ namespace osu.Game.Tournament.Screens.Editors Width = 300 }; } - } + }); } } } From d77b6b3603e5a302efe8c960427516106f78e985 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 19:04:06 +0900 Subject: [PATCH 2124/2686] Fix seeding screen buttons crashing the game if no match is selected --- .../Screens/TeamIntro/SeedingScreen.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs index 8bc28e1068..ba75b6a2ed 100644 --- a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs +++ b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs @@ -26,6 +26,9 @@ namespace osu.Game.Tournament.Screens.TeamIntro private readonly Bindable currentTeam = new Bindable(); + private TourneyButton showFirstTeamButton; + private TourneyButton showSecondTeamButton; + [BackgroundDependencyLoader] private void load() { @@ -46,13 +49,13 @@ namespace osu.Game.Tournament.Screens.TeamIntro { Children = new Drawable[] { - new TourneyButton + showFirstTeamButton = new TourneyButton { RelativeSizeAxes = Axes.X, Text = "Show first team", Action = () => currentTeam.Value = CurrentMatch.Value.Team1.Value, }, - new TourneyButton + showSecondTeamButton = new TourneyButton { RelativeSizeAxes = Axes.X, Text = "Show second team", @@ -86,7 +89,14 @@ namespace osu.Game.Tournament.Screens.TeamIntro base.CurrentMatchChanged(match); if (match.NewValue == null) + { + showFirstTeamButton.Enabled.Value = false; + showSecondTeamButton.Enabled.Value = false; return; + } + + showFirstTeamButton.Enabled.Value = true; + showSecondTeamButton.Enabled.Value = true; currentTeam.Value = match.NewValue.Team1.Value; } From 1e2e0dea74fbbdf53b0eb04a5913b6bdd4f15a52 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 7 Nov 2022 19:04:19 +0900 Subject: [PATCH 2125/2686] Ensure seeding results get beatmaps populated if `BeatmapIno` model is null --- osu.Game.Tournament/TournamentGameBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 1861e39c60..98ba3ca60f 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -238,7 +238,7 @@ namespace osu.Game.Tournament var beatmapsRequiringPopulation = ladder.Teams .SelectMany(r => r.SeedingResults) .SelectMany(r => r.Beatmaps) - .Where(b => b.Beatmap?.OnlineID == 0 && b.ID > 0).ToList(); + .Where(b => (b.Beatmap == null || b.Beatmap.OnlineID == 0) && b.ID > 0).ToList(); if (beatmapsRequiringPopulation.Count == 0) return false; From ab650d8a1bf790616c6bbf5f2d082f2b9277497c Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Mon, 7 Nov 2022 15:22:20 +0100 Subject: [PATCH 2126/2686] Use AutoSizeAxes --- osu.Game/Skinning/Components/BeatmapInfoDrawable.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs index eda956e6d8..379bdec333 100644 --- a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs +++ b/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs @@ -64,6 +64,7 @@ namespace osu.Game.Skinning.Components public BeatmapInfoDrawable() { + AutoSizeAxes = Axes.Both; InternalChildren = new Drawable[] { text = new OsuSpriteText @@ -104,8 +105,6 @@ namespace osu.Game.Skinning.Components } text.Text = newText; - Width = text.Width; - Height = text.Height; } public void UpdateBeatmapContent(WorkingBeatmap workingBeatmap) From 7ee9018a94c0e2bfb81c9fca6d3a067d1075f437 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 8 Nov 2022 03:18:12 +0300 Subject: [PATCH 2127/2686] Always display menu cursor when game is not focused --- .../Graphics/Cursor/MenuCursorContainer.cs | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index af542989ff..adc0f81daf 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -70,7 +70,8 @@ namespace osu.Game.Graphics.Cursor private OsuGame? game { get; set; } private readonly IBindable lastInputWasMouse = new BindableBool(); - private readonly IBindable isIdle = new BindableBool(); + private readonly IBindable gameActive = new BindableBool(true); + private readonly IBindable gameIdle = new BindableBool(); protected override void LoadComplete() { @@ -81,8 +82,11 @@ namespace osu.Game.Graphics.Cursor if (game != null) { - isIdle.BindTo(game.IsIdle); - isIdle.BindValueChanged(_ => updateState()); + gameIdle.BindTo(game.IsIdle); + gameIdle.BindValueChanged(_ => updateState()); + + gameActive.BindTo(game.IsActive); + gameActive.BindValueChanged(_ => updateState()); } } @@ -90,7 +94,7 @@ namespace osu.Game.Graphics.Cursor private void updateState() { - bool combinedVisibility = State.Value == Visibility.Visible && (lastInputWasMouse.Value || !hideCursorOnNonMouseInput) && !isIdle.Value; + bool combinedVisibility = getCursorVisibility(); if (visible == combinedVisibility) return; @@ -103,6 +107,27 @@ namespace osu.Game.Graphics.Cursor PopOut(); } + private bool getCursorVisibility() + { + // do not display when explicitly set to hidden state. + if (State.Value == Visibility.Hidden) + return false; + + // only hide cursor when game is focused, otherwise it should always be displayed. + if (gameActive.Value) + { + // do not display when last input is not mouse. + if (hideCursorOnNonMouseInput && !lastInputWasMouse.Value) + return false; + + // do not display when game is idle. + if (gameIdle.Value) + return false; + } + + return true; + } + protected override void Update() { base.Update(); From 8568520c33db332cb21d479342e334809ee49104 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Tue, 8 Nov 2022 01:34:06 +0100 Subject: [PATCH 2128/2686] Fix `Prefer24HourTime` default value Will use the system culture so it always matches the rest of the OS. --- osu.Game/Configuration/OsuConfigManager.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 093eaa0f31..5137214d62 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -5,7 +5,6 @@ using System; using System.Diagnostics; -using System.Globalization; using osu.Framework.Configuration; using osu.Framework.Configuration.Tracking; using osu.Framework.Extensions; @@ -115,7 +114,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.MenuParallax, true); // See https://stackoverflow.com/a/63307411 for default sourcing. - SetDefault(OsuSetting.Prefer24HourTime, CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern.Contains(@"tt")); + SetDefault(OsuSetting.Prefer24HourTime, !CultureInfoHelper.SystemCulture.DateTimeFormat.ShortTimePattern.Contains(@"tt")); // Gameplay SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1); From 3af48352c98e1602b55fee988482122b2e2fbcba Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 8 Nov 2022 04:05:06 +0300 Subject: [PATCH 2129/2686] Fix taiko major barlines no longer rendering correctly --- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 30 ++++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index cc71ba5401..f2d7811f44 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -60,8 +60,9 @@ namespace osu.Game.Rulesets.Taiko.UI /// private BarLinePlayfield barLinePlayfield; - private Container playfieldContent; - private Container playfieldOverlay; + private Container barLineContent; + private Container hitObjectContent; + private Container overlayContent; [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -121,22 +122,20 @@ namespace osu.Game.Rulesets.Taiko.UI } } }, - new Container + barLineContent = new Container + { + Name = "Bar line content", + RelativeSizeAxes = Axes.Both, + Child = barLinePlayfield = new BarLinePlayfield(), + }, + hitObjectContent = new Container { Name = "Masked hit objects content", RelativeSizeAxes = Axes.Both, Masking = true, - Child = playfieldContent = new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - barLinePlayfield = new BarLinePlayfield(), - HitObjectContainer, - } - } + Child = HitObjectContainer, }, - playfieldOverlay = new Container + overlayContent = new Container { Name = "Elements after hit objects", RelativeSizeAxes = Axes.Both, @@ -215,8 +214,9 @@ namespace osu.Game.Rulesets.Taiko.UI // Padding is required to be updated for elements which are based on "absolute" X sized elements. // This is basically allowing for correct alignment as relative pieces move around them. rightArea.Padding = new MarginPadding { Left = inputDrum.Width }; - playfieldContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 }; - playfieldOverlay.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 }; + barLineContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 }; + hitObjectContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 }; + overlayContent.Padding = new MarginPadding { Left = HitTarget.DrawWidth / 2 }; mascot.Scale = new Vector2(DrawHeight / DEFAULT_HEIGHT); } From 2163cd212b57a1fb7e2156621973bde5251ea4e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 12:03:25 +0900 Subject: [PATCH 2130/2686] Automatically close settings and notification overlays when opening main overlay Closes #21162. --- osu.Game/OsuGame.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4f8098136f..0015de7da1 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1006,6 +1006,9 @@ namespace osu.Game if (overlay.IsPresent) return; + Settings.Hide(); + Notifications.Hide(); + // Show above all other overlays. if (overlay.IsLoaded) overlayContent.ChangeChildDepth(overlay, (float)-Clock.CurrentTime); From 64e627639762201399595de37d595fcc614db6fc Mon Sep 17 00:00:00 2001 From: maromalo <54760464+maromalo@users.noreply.github.com> Date: Tue, 8 Nov 2022 01:10:21 -0300 Subject: [PATCH 2131/2686] Fix score rounding issue --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index f619c89368..02512d857d 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -341,13 +341,13 @@ namespace osu.Game.Rulesets.Scoring case ScoringMode.Standardised: double accuracyScore = accuracyPortion * accuracyRatio; double comboScore = comboPortion * comboRatio; - return (long)((max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier); + return (long)Math.Round((max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier); case ScoringMode.Classic: // This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring. // The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes. double scaledStandardised = ComputeScore(ScoringMode.Standardised, accuracyRatio, comboRatio, bonusScore, totalBasicHitObjects) / max_score; - return (long)(Math.Pow(scaledStandardised * Math.Max(1, totalBasicHitObjects), 2) * ClassicScoreMultiplier); + return (long)Math.Round(Math.Pow(scaledStandardised * Math.Max(1, totalBasicHitObjects), 2) * ClassicScoreMultiplier); } } From b764d1bd0469f8136c4abc4c30683117f3d67d99 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 13:29:25 +0900 Subject: [PATCH 2132/2686] Decode variables earlier in flow in case they include indent logic Without this change, the `depth` calculation could be incorrect. --- osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index b8f60f0bc6..4d407bb5f0 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -79,6 +79,8 @@ namespace osu.Game.Beatmaps.Formats private void handleEvents(string line) { + decodeVariables(ref line); + int depth = 0; foreach (char c in line) @@ -91,8 +93,6 @@ namespace osu.Game.Beatmaps.Formats line = line.Substring(depth); - decodeVariables(ref line); - string[] split = line.Split(','); if (depth == 0) From 064a245c50c4e3a92e2fcbf87e7dc014864322ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 13:30:11 +0900 Subject: [PATCH 2133/2686] Don't trim whitespace from variable keys / values --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 12 +++++++++--- osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index ed7ca47cfd..6991500df5 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -130,14 +130,20 @@ namespace osu.Game.Beatmaps.Formats } } - protected KeyValuePair SplitKeyVal(string line, char separator = ':') + protected KeyValuePair SplitKeyVal(string line, char separator = ':', bool shouldTrim = true) { string[] split = line.Split(separator, 2); + if (shouldTrim) + { + for (int i = 0; i < split.Length; i++) + split[i] = split[i].Trim(); + } + return new KeyValuePair ( - split[0].Trim(), - split.Length > 1 ? split[1].Trim() : string.Empty + split[0], + split.Length > 1 ? split[1] : string.Empty ); } diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs index 4d407bb5f0..2b4f377ab6 100644 --- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs @@ -349,7 +349,7 @@ namespace osu.Game.Beatmaps.Formats private void handleVariables(string line) { - var pair = SplitKeyVal(line, '='); + var pair = SplitKeyVal(line, '=', false); variables[pair.Key] = pair.Value; } From 0b343404472d26ecbe243e7529a8615d5dd961ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 14:34:28 +0900 Subject: [PATCH 2134/2686] Fix sprites not displaying in storyboard if filename extension is missing in script --- osu.Game/Storyboards/Storyboard.cs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 473f1ce97f..8133244e89 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.IO; using System.Linq; using osu.Framework.Graphics.Textures; using osu.Game.Beatmaps; @@ -89,12 +90,31 @@ namespace osu.Game.Storyboards public DrawableStoryboard CreateDrawable(IReadOnlyList? mods = null) => new DrawableStoryboard(this, mods); + private static readonly string[] image_extensions = { @".png", @".jpg" }; + public Texture? GetTextureFromPath(string path, TextureStore textureStore) { - string? storyboardPath = BeatmapInfo.BeatmapSet?.GetPathForFile(path); + string? resolvedPath = null; - if (!string.IsNullOrEmpty(storyboardPath)) - return textureStore.Get(storyboardPath); + if (Path.HasExtension(path)) + { + resolvedPath = BeatmapInfo.BeatmapSet?.GetPathForFile(path); + } + else + { + // Just doing this extension logic locally here for simplicity. + // + // A more "sane" path may be to use the ISkinSource.GetTexture path (which will use the extensions of the underlying TextureStore), + // but comes with potential complexity (what happens if the user has beatmap skins disabled?). + foreach (string ext in image_extensions) + { + if ((resolvedPath = BeatmapInfo.BeatmapSet?.GetPathForFile($"{path}{ext}")) != null) + break; + } + } + + if (!string.IsNullOrEmpty(resolvedPath)) + return textureStore.Get(resolvedPath); return null; } From b9374cae55ade91632302f64eacef6bf9ab9f64a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 14:38:02 +0900 Subject: [PATCH 2135/2686] Hide settings/notifications regardless of `IsPresent` state of new overlay --- osu.Game/OsuGame.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 0015de7da1..7476324e11 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1002,13 +1002,13 @@ namespace osu.Game { otherOverlays.Where(o => o != overlay).ForEach(o => o.Hide()); + Settings.Hide(); + Notifications.Hide(); + // Partially visible so leave it at the current depth. if (overlay.IsPresent) return; - Settings.Hide(); - Notifications.Hide(); - // Show above all other overlays. if (overlay.IsLoaded) overlayContent.ChangeChildDepth(overlay, (float)-Clock.CurrentTime); From 4c157946941a26b1ecab092c826390dd741c3342 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 14:58:52 +0900 Subject: [PATCH 2136/2686] Add test coverage of overlay interplay --- .../Navigation/TestSceneScreenNavigation.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 8fce43f9b0..e69bdfb7ac 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -513,6 +513,40 @@ namespace osu.Game.Tests.Visual.Navigation AddWaitStep("wait two frames", 2); } + [Test] + public void TestMainOverlaysClosesNotificationOverlay() + { + ChangelogOverlay getChangelogOverlay() => Game.ChildrenOfType().FirstOrDefault(); + + AddUntilStep("Wait for options to load", () => Game.Notifications.IsLoaded); + AddStep("Show notifications", () => Game.Notifications.Show()); + AddUntilStep("wait for notifications shown", () => Game.Notifications.IsPresent && Game.Notifications.State.Value == Visibility.Visible); + AddStep("Show changelog listing", () => Game.ShowChangelogListing()); + AddUntilStep("wait for changelog shown", () => getChangelogOverlay()?.IsPresent == true && getChangelogOverlay()?.State.Value == Visibility.Visible); + AddAssert("Notifications is hidden", () => Game.Notifications.State.Value == Visibility.Hidden); + + AddStep("Show notifications", () => Game.Notifications.Show()); + AddUntilStep("wait for notifications shown", () => Game.Notifications.State.Value == Visibility.Visible); + AddUntilStep("changelog still visible", () => getChangelogOverlay().State.Value == Visibility.Visible); + } + + [Test] + public void TestMainOverlaysClosesSettingsOverlay() + { + ChangelogOverlay getChangelogOverlay() => Game.ChildrenOfType().FirstOrDefault(); + + AddUntilStep("Wait for options to load", () => Game.Settings.IsLoaded); + AddStep("Show settings", () => Game.Settings.Show()); + AddUntilStep("wait for settings shown", () => Game.Settings.IsPresent && Game.Settings.State.Value == Visibility.Visible); + AddStep("Show changelog listing", () => Game.ShowChangelogListing()); + AddUntilStep("wait for changelog shown", () => getChangelogOverlay()?.IsPresent == true && getChangelogOverlay()?.State.Value == Visibility.Visible); + AddAssert("Settings is hidden", () => Game.Settings.State.Value == Visibility.Hidden); + + AddStep("Show settings", () => Game.Settings.Show()); + AddUntilStep("wait for settings shown", () => Game.Settings.State.Value == Visibility.Visible); + AddUntilStep("changelog still visible", () => getChangelogOverlay().State.Value == Visibility.Visible); + } + [Test] public void TestOverlayClosing() { From 01803c3f13f0a46907401a5b1a3b670944d1ff09 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 15:08:52 +0900 Subject: [PATCH 2137/2686] Adjust judgement text to be more visible --- .../Skinning/Argon/ArgonJudgementPiece.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs index 0ea0473023..baaf9e41e2 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs @@ -78,12 +78,12 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon switch (Result) { default: - JudgementText.MoveToY(-0.2f) - .MoveToY(-0.8f, duration, Easing.OutQuint); + JudgementText.MoveToY(-0.6f) + .MoveToY(-1.0f, duration, Easing.OutQuint); JudgementText .ScaleTo(Vector2.One) - .ScaleTo(new Vector2(1.8f), duration, Easing.OutQuint); + .ScaleTo(new Vector2(1.4f), duration, Easing.OutQuint); break; case HitResult.Miss: From aa7d0e2c9699743d220828962d7a2c63d4433e57 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 15:19:08 +0900 Subject: [PATCH 2138/2686] Remove triangles skin specific implementation from base `DrawableHit` --- .../Objects/Drawables/DrawableHit.cs | 5 +--- .../Skinning/Default/CirclePiece.cs | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 484f125a09..02ac054b52 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -201,12 +201,9 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables break; case ArmedState.Hit: - // If we're far enough away from the left stage, we should bring outselves in front of it + // If we're far enough away from the left stage, we should bring ourselves in front of it ProxyContent(); - var flash = (MainPiece.Drawable as CirclePiece)?.FlashBox; - flash?.FadeTo(0.9f).FadeOut(300); - const float gravity_time = 300; const float gravity_travel_height = 200; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index 6b5a9ae6d2..e8edf94e76 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default private readonly Container background; - public Box FlashBox; + private readonly Box flashBox; protected CirclePiece() { @@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default Masking = true, Children = new[] { - FlashBox = new Box + flashBox = new Box { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -144,6 +144,25 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default }); } + protected override void LoadComplete() + { + base.LoadComplete(); + + drawableHitObject.ApplyCustomUpdateState += updateStateTransforms; + updateStateTransforms(drawableHitObject, drawableHitObject.State.Value); + } + + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) + { + switch (state) + { + case ArmedState.Hit: + using (BeginAbsoluteSequence(drawableHitObject.HitStateUpdateTime)) + flashBox?.FadeTo(0.9f).FadeOut(300); + break; + } + } + private const float edge_alpha_kiai = 0.5f; private void resetEdgeEffects() @@ -166,7 +185,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default if (drawableHitObject.State.Value == ArmedState.Idle) { - FlashBox + flashBox .FadeTo(flash_opacity) .Then() .FadeOut(timingPoint.BeatLength * 0.75, Easing.OutSine); From 30890644a8c417119199de6f24fcd63cd366543b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 15:21:20 +0900 Subject: [PATCH 2139/2686] Flash piece when hit --- .../Skinning/Argon/ArgonCirclePiece.cs | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs index 8ef7b71069..91f34e1f0e 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; @@ -33,17 +32,16 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon set { accentColour = value; + ring.Colour = AccentColour.MultiplyAlpha(0.5f); ring2.Colour = AccentColour; } } - /// - /// Whether Kiai mode effects are enabled for this circle piece. - /// - public bool KiaiMode { get; set; } + [Resolved] + private DrawableHitObject drawableHitObject { get; set; } = null!; - public Box FlashBox; + private readonly Drawable flash; private readonly RingPiece ring; private readonly RingPiece ring2; @@ -59,36 +57,43 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon new Circle { RelativeSizeAxes = Axes.Both, - Colour = new Color4(0, 22, 30, 190) + Colour = new Color4(0, 0, 0, 190) }, ring = new RingPiece(20 / 70f), ring2 = new RingPiece(5 / 70f), - new CircularContainer + flash = new Circle { Name = "Flash layer", Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new[] - { - FlashBox = new Box - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - Blending = BlendingParameters.Additive, - Alpha = 0, - AlwaysPresent = true - } - }, + Blending = BlendingParameters.Additive, + Alpha = 0, }, }); } - [Resolved] - private DrawableHitObject drawableHitObject { get; set; } = null!; + protected override void LoadComplete() + { + base.LoadComplete(); + + drawableHitObject.ApplyCustomUpdateState += updateStateTransforms; + updateStateTransforms(drawableHitObject, drawableHitObject.State.Value); + } + + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) + { + switch (state) + { + case ArmedState.Hit: + using (BeginAbsoluteSequence(drawableHitObject.HitStateUpdateTime)) + { + flash.FadeTo(0.9f).FadeOut(500, Easing.OutQuint); + } + + break; + } + } protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { @@ -97,7 +102,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon if (drawableHitObject.State.Value == ArmedState.Idle) { - FlashBox + flash .FadeTo(flash_opacity) .Then() .FadeOut(timingPoint.BeatLength * 0.75, Easing.OutSine); From 349d262c1820d5056282bc2a3a2014a6535a17af Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 2 Nov 2022 18:05:22 +0900 Subject: [PATCH 2140/2686] Remove commented unbind --- osu.Game/Screens/Edit/Editor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 990152471a..df3c1f7ec4 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -667,9 +667,9 @@ namespace osu.Game.Screens.Edit ApplyToBackground(b => { - //b.DimAmount.UnbindAll(); b.DimWhenUserSettingsIgnored.Value = 0; }); + resetTrack(); refetchBeatmap(); From 9650ae1329b07cf8801601186d4dae91c1fe7929 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 17:20:37 +0900 Subject: [PATCH 2141/2686] Limit editor background dim to 75% maximum --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/Screens/Edit/BackgroundDimMenuItem.cs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 3c619d2ddd..fccd1a8715 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -121,7 +121,6 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1); SetDefault(OsuSetting.DimLevel, 0.7, 0, 1, 0.01); SetDefault(OsuSetting.BlurLevel, 0, 0, 1, 0.01); - SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 1f, 0.25f); SetDefault(OsuSetting.LightenDuringBreaks, true); SetDefault(OsuSetting.HitLighting, true); @@ -172,6 +171,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full); + SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 0.75f, 0.25f); SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f); SetDefault(OsuSetting.LastProcessedMetadataId, -1); diff --git a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs index b8644ed690..b5a33f06e7 100644 --- a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs +++ b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs @@ -23,7 +23,6 @@ namespace osu.Game.Screens.Edit createMenuItem(0.25f), createMenuItem(0.5f), createMenuItem(0.75f), - createMenuItem(1f), }; this.backgroudDim = backgroudDim; From ada039151b80f73d678161ec0f10f13f0c79ffab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 18:07:06 +0900 Subject: [PATCH 2142/2686] Add the ability to toggle off hit marker displays in the editor --- .../Components/HitCircleOverlapMarker.cs | 50 +++++++++++++------ .../Edit/Blueprints/OsuSelectionBlueprint.cs | 2 +- osu.Game/Configuration/OsuConfigManager.cs | 2 + .../Edit/HitObjectSelectionBlueprint.cs | 14 ++++++ osu.Game/Screens/Edit/Editor.cs | 6 +++ 5 files changed, 59 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs index 71cdbc276e..f16b6c138e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs @@ -4,9 +4,12 @@ #nullable disable using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Utils; +using osu.Game.Configuration; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Skinning.Default; @@ -27,31 +30,45 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components private readonly RingPiece ring; + private readonly Container content; + [Resolved] private EditorClock editorClock { get; set; } + private Bindable showHitMarkers; + public HitCircleOverlapMarker() { Origin = Anchor.Centre; Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); - InternalChildren = new Drawable[] + InternalChild = content = new Container { - new Circle + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = Color4.White, - }, - ring = new RingPiece - { - BorderThickness = 4, + new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + }, + ring = new RingPiece + { + BorderThickness = 4, + } } }; } + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + showHitMarkers = config.GetBindable(OsuSetting.EditorShowHitMarkers); + } + [Resolved] private ISkinSource skin { get; set; } @@ -68,21 +85,26 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components double hitObjectTime = hitObject.StartTime; bool hasReachedObject = editorTime >= hitObjectTime; - if (hasReachedObject) + if (hasReachedObject && showHitMarkers.Value) { float alpha = Interpolation.ValueAt(editorTime, 0, 1f, hitObjectTime, hitObjectTime + FADE_OUT_EXTENSION, Easing.In); float ringScale = MathHelper.Clamp(Interpolation.ValueAt(editorTime, 0, 1f, hitObjectTime, hitObjectTime + FADE_OUT_EXTENSION / 2, Easing.OutQuint), 0, 1); ring.Scale = new Vector2(1 + 0.1f * ringScale); - Alpha = 0.9f * (1 - alpha); + content.Alpha = 0.9f * (1 - alpha); } else - Alpha = 0; + content.Alpha = 0; + } + + public override void Show() + { + // intentional no op so SelectionBlueprint Selection/Deselection logic doesn't touch us. } public override void Hide() { - // intentional no op so we are not hidden when not selected. + // intentional no op so SelectionBlueprint Selection/Deselection logic doesn't touch us. } } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs index 422287918e..11527c9537 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints protected override bool AlwaysShowWhenSelected => true; protected override bool ShouldBeAlive => base.ShouldBeAlive - || (editorClock.CurrentTime >= Item.StartTime && editorClock.CurrentTime - Item.GetEndTime() < HitCircleOverlapMarker.FADE_OUT_EXTENSION); + || (ShowHitMarkers.Value && editorClock.CurrentTime >= Item.StartTime && editorClock.CurrentTime - Item.GetEndTime() < HitCircleOverlapMarker.FADE_OUT_EXTENSION); protected OsuSelectionBlueprint(T hitObject) : base(hitObject) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index fccd1a8715..2aa369cf78 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -173,6 +173,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 0.75f, 0.25f); SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f); + SetDefault(OsuSetting.EditorShowHitMarkers, true); SetDefault(OsuSetting.LastProcessedMetadataId, -1); } @@ -367,5 +368,6 @@ namespace osu.Game.Configuration ShowOnlineExplicitContent, LastProcessedMetadataId, SafeAreaConsiderations, + EditorShowHitMarkers } } diff --git a/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs b/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs index c74fb83d58..408fbfc04f 100644 --- a/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs @@ -3,7 +3,10 @@ #nullable disable +using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics.Primitives; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; @@ -23,6 +26,11 @@ namespace osu.Game.Rulesets.Edit /// protected virtual bool AlwaysShowWhenSelected => false; + /// + /// Whether extra animations should be shown to convey hit position / state in addition to gameplay animations. + /// + protected Bindable ShowHitMarkers { get; private set; } + protected override bool ShouldBeAlive => (DrawableObject?.IsAlive == true && DrawableObject.IsPresent) || (AlwaysShowWhenSelected && State == SelectionState.Selected); protected HitObjectSelectionBlueprint(HitObject hitObject) @@ -30,6 +38,12 @@ namespace osu.Game.Rulesets.Edit { } + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + ShowHitMarkers = config.GetBindable(OsuSetting.EditorShowHitMarkers); + } + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.ReceivePositionalInputAt(screenSpacePos); public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.ScreenSpaceDrawQuad.Centre; diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index df3c1f7ec4..7f94370bb2 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -176,6 +176,7 @@ namespace osu.Game.Screens.Edit private OnScreenDisplay onScreenDisplay { get; set; } private Bindable editorBackgroundDim; + private Bindable editorHitMarkers; public Editor(EditorLoader loader = null) { @@ -262,6 +263,7 @@ namespace osu.Game.Screens.Edit OsuMenuItem redoMenuItem; editorBackgroundDim = config.GetBindable(OsuSetting.EditorDim); + editorHitMarkers = config.GetBindable(OsuSetting.EditorShowHitMarkers); AddInternal(new OsuContextMenuContainer { @@ -316,6 +318,10 @@ namespace osu.Game.Screens.Edit { new WaveformOpacityMenuItem(config.GetBindable(OsuSetting.EditorWaveformOpacity)), new BackgroundDimMenuItem(editorBackgroundDim), + new ToggleMenuItem("Show hit markers") + { + State = { BindTarget = editorHitMarkers }, + } } } } From dd4cd3cf8e5be9f5c413efa67be780a2a931e08c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 18:24:57 +0900 Subject: [PATCH 2143/2686] Move gameplay configuration to interface to allow editor overriding --- osu.Game/Configuration/IGameplaySettings.cs | 23 +++++++++++++++++++ osu.Game/Configuration/OsuConfigManager.cs | 6 ++++- osu.Game/OsuGameBase.cs | 1 + .../Objects/Drawables/DrawableHitObject.cs | 10 ++++---- 4 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Configuration/IGameplaySettings.cs diff --git a/osu.Game/Configuration/IGameplaySettings.cs b/osu.Game/Configuration/IGameplaySettings.cs new file mode 100644 index 0000000000..a35bdd20d0 --- /dev/null +++ b/osu.Game/Configuration/IGameplaySettings.cs @@ -0,0 +1,23 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; + +namespace osu.Game.Configuration +{ + /// + /// A settings provider which generally sources from (global user settings) + /// but can allow overriding settings by caching more locally. For instance, in the editor. + /// + /// + /// More settings can be moved into this interface as required. + /// + [Cached] + public interface IGameplaySettings + { + IBindable ComboColourNormalisationAmount { get; } + + IBindable PositionalHitsoundsLevel { get; } + } +} diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index fdaad8cf70..1286a07eeb 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -6,6 +6,7 @@ using System; using System.Diagnostics; using System.Globalization; +using osu.Framework.Bindables; using osu.Framework.Configuration; using osu.Framework.Configuration.Tracking; using osu.Framework.Extensions; @@ -27,7 +28,7 @@ using osu.Game.Skinning; namespace osu.Game.Configuration { [ExcludeFromDynamicCompile] - public class OsuConfigManager : IniConfigManager + public class OsuConfigManager : IniConfigManager, IGameplaySettings { public OsuConfigManager(Storage storage) : base(storage) @@ -276,6 +277,9 @@ namespace osu.Game.Configuration public Func LookupSkinName { private get; set; } = _ => @"unknown"; public Func LookupKeyBindings { get; set; } = _ => @"unknown"; + + IBindable IGameplaySettings.ComboColourNormalisationAmount => GetOriginalBindable(OsuSetting.ComboColourNormalisationAmount); + IBindable IGameplaySettings.PositionalHitsoundsLevel => GetOriginalBindable(OsuSetting.PositionalHitsoundsLevel); } // IMPORTANT: These are used in user configuration files. diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 511f492b8a..1d5f5a75e5 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -262,6 +262,7 @@ namespace osu.Game dependencies.Cache(largeStore); dependencies.CacheAs(LocalConfig); + dependencies.CacheAs(LocalConfig); InitialiseFonts(); diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 15d3e63be1..6795a07cb4 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -129,8 +129,8 @@ namespace osu.Game.Rulesets.Objects.Drawables private readonly BindableList samplesBindable = new BindableList(); private readonly Bindable comboIndexBindable = new Bindable(); - private readonly Bindable positionalHitsoundsLevel = new Bindable(); - private readonly Bindable comboColourBrightness = new Bindable(); + private readonly IBindable positionalHitsoundsLevel = new Bindable(); + private readonly IBindable comboColourBrightness = new Bindable(); private readonly Bindable comboIndexWithOffsetsBindable = new Bindable(); protected override bool RequiresChildrenUpdate => true; @@ -171,10 +171,10 @@ namespace osu.Game.Rulesets.Objects.Drawables } [BackgroundDependencyLoader] - private void load(OsuConfigManager config, ISkinSource skinSource) + private void load(IGameplaySettings gameplaySettings, ISkinSource skinSource) { - config.BindWith(OsuSetting.PositionalHitsoundsLevel, positionalHitsoundsLevel); - config.BindWith(OsuSetting.ComboColourNormalisationAmount, comboColourBrightness); + positionalHitsoundsLevel.BindTo(gameplaySettings.PositionalHitsoundsLevel); + comboColourBrightness.BindTo(gameplaySettings.ComboColourNormalisationAmount); // Explicit non-virtual function call in case a DrawableHitObject overrides AddInternal. base.AddInternal(Samples = new PausableSkinnableSound()); From 4448fcb3c876241428f2015f51f35a735fe21740 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 8 Nov 2022 18:28:48 +0900 Subject: [PATCH 2144/2686] Override combo colour brightness normalisation setting only in editor --- osu.Game/Screens/Edit/Editor.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 912681e114..65d2371551 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -59,7 +59,8 @@ namespace osu.Game.Screens.Edit { [Cached(typeof(IBeatSnapProvider))] [Cached] - public class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler, IKeyBindingHandler, IBeatSnapProvider, ISamplePlaybackDisabler, IBeatSyncProvider + public class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler, IKeyBindingHandler, IBeatSnapProvider, ISamplePlaybackDisabler, IBeatSyncProvider, + IGameplaySettings { public override float BackgroundParallaxAmount => 0.1f; @@ -99,6 +100,9 @@ namespace osu.Game.Screens.Edit [Resolved(canBeNull: true)] private INotificationOverlay notifications { get; set; } + [Resolved] + private IGameplaySettings globalGameplaySettings { get; set; } + public readonly Bindable Mode = new Bindable(); public IBindable SamplePlaybackDisabled => samplePlaybackDisabled; @@ -1031,5 +1035,11 @@ namespace osu.Game.Screens.Edit { } } + + // Combo colour normalisation should not be applied in the editor. + IBindable IGameplaySettings.ComboColourNormalisationAmount => new Bindable(); + + // Arguable. + IBindable IGameplaySettings.PositionalHitsoundsLevel => globalGameplaySettings.PositionalHitsoundsLevel; } } From d48c56818ff8ac446e67f7b0d12eb2088564c6c0 Mon Sep 17 00:00:00 2001 From: Piggey Date: Tue, 8 Nov 2022 20:02:21 +0100 Subject: [PATCH 2145/2686] change `positionText` to display "#?" if tracked score is being 51st on the leaderboard --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 4 ++++ osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 48908fb9a0..10049c7718 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -174,6 +174,10 @@ namespace osu.Game.Screens.Play.HUD orderedByScore[i].ScorePosition = i + 1; } + // change displayed potision to '#?' when there are 50 already submitted scores and tracked score is last + if (TrackedScore?.ScorePosition == Flow.Count && Flow.Count == 51) + TrackedScore.ScorePosition = null; + sorting.Validate(); } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 2eec8253b3..dc2c0620c8 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -72,10 +72,8 @@ namespace osu.Game.Screens.Play.HUD scorePosition = value; - if (scorePosition.HasValue) - positionText.Text = $"#{scorePosition.Value.FormatRank()}"; + positionText.Text = scorePosition.HasValue ? $"#{scorePosition.Value.FormatRank()}" : "#?"; - positionText.FadeTo(scorePosition.HasValue ? 1 : 0); updateState(); } } From 9da57c66a2b29a0674c10659ba500c5758d40513 Mon Sep 17 00:00:00 2001 From: Piggey Date: Tue, 8 Nov 2022 20:03:09 +0100 Subject: [PATCH 2146/2686] add visual tests --- .../Visual/Gameplay/TestSceneGameplayLeaderboard.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 171ae829a9..a385060d62 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("add many scores in one go", () => { - for (int i = 0; i < 32; i++) + for (int i = 0; i < 49; i++) createRandomScore(new APIUser { Username = $"Player {i + 1}" }); // Add player at end to force an animation down the whole list. @@ -61,6 +61,12 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for tracked score fully visible", () => leaderboard.ScreenSpaceDrawQuad.Intersects(leaderboard.TrackedScore!.ScreenSpaceDrawQuad)); + AddUntilStep("ensure player is #50", () => leaderboard.CheckPositionByUsername("You", 50)); + + AddStep("add one more player", () => createRandomScore(new APIUser { Username = "Player 50" })); + + AddUntilStep("ensure player is #?", () => leaderboard.CheckPositionByUsername("You", null)); + AddStep("change score to middle", () => playerScore.Value = 1000000); AddWaitStep("wait for movement", 5); AddUntilStep("wait for tracked score fully visible", () => leaderboard.ScreenSpaceDrawQuad.Intersects(leaderboard.TrackedScore!.ScreenSpaceDrawQuad)); From 710c224de45988649feca86275669b0e2c607d55 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 13:18:24 +0900 Subject: [PATCH 2147/2686] Remove unused `IHasMainCirclePiece` interface --- .../Objects/Drawables/DrawableHitCircle.cs | 2 +- .../Objects/Drawables/DrawableSliderRepeat.cs | 2 +- .../Objects/Drawables/DrawableSliderTail.cs | 3 +-- .../Skinning/Default/IHasMainCirclePiece.cs | 14 -------------- 4 files changed, 3 insertions(+), 18 deletions(-) delete mode 100644 osu.Game.Rulesets.Osu/Skinning/Default/IHasMainCirclePiece.cs diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 841a52da7b..d420091499 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableHitCircle : DrawableOsuHitObject, IHasMainCirclePiece, IHasApproachCircle + public class DrawableHitCircle : DrawableOsuHitObject, IHasApproachCircle { public OsuAction? HitAction => HitArea.HitAction; protected virtual OsuSkinComponents CirclePieceComponent => OsuSkinComponents.HitCircle; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 7b9c0c7e40..a02cc9227e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderRepeat : DrawableOsuHitObject, ITrackSnaking, IHasMainCirclePiece + public class DrawableSliderRepeat : DrawableOsuHitObject, ITrackSnaking { public new SliderRepeat HitObject => (SliderRepeat)base.HitObject; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index 063d297f5a..6270d6709b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -10,13 +10,12 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Osu.Skinning.Default; using osu.Game.Skinning; using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, IHasMainCirclePiece + public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking { public new SliderTailCircle HitObject => (SliderTailCircle)base.HitObject; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/IHasMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/IHasMainCirclePiece.cs deleted file mode 100644 index 0ba7998d43..0000000000 --- a/osu.Game.Rulesets.Osu/Skinning/Default/IHasMainCirclePiece.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using osu.Game.Skinning; - -namespace osu.Game.Rulesets.Osu.Skinning.Default -{ - public interface IHasMainCirclePiece - { - SkinnableDrawable CirclePiece { get; } - } -} From 5e7dc34d05c5a6ab644d88bbf7e014c012505b7a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 13:23:53 +0900 Subject: [PATCH 2148/2686] Move some non-default skin files to correct namespace --- osu.Game.Rulesets.Osu/Skinning/{Default => }/SliderBody.cs | 3 ++- .../Skinning/{Default => }/SnakingSliderBody.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) rename osu.Game.Rulesets.Osu/Skinning/{Default => }/SliderBody.cs (97%) rename osu.Game.Rulesets.Osu/Skinning/{Default => }/SnakingSliderBody.cs (99%) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs similarity index 97% rename from osu.Game.Rulesets.Osu/Skinning/Default/SliderBody.cs rename to osu.Game.Rulesets.Osu/Skinning/SliderBody.cs index 9841cc7cdf..1411b27c09 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs @@ -8,10 +8,11 @@ using System.Collections.Generic; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Lines; +using osu.Game.Rulesets.Osu.Skinning.Default; using osuTK; using osuTK.Graphics; -namespace osu.Game.Rulesets.Osu.Skinning.Default +namespace osu.Game.Rulesets.Osu.Skinning { public abstract class SliderBody : CompositeDrawable { diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs similarity index 99% rename from osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs rename to osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs index 86dd5f5c74..a4a3316927 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osuTK; -namespace osu.Game.Rulesets.Osu.Skinning.Default +namespace osu.Game.Rulesets.Osu.Skinning { /// /// A which changes its curve depending on the snaking progress. From 20b8ab324fcd92129c501e12ebb189cdca9ca02d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 13:36:46 +0900 Subject: [PATCH 2149/2686] Apply nullability to osu!taiko skinning classes --- .../Skinning/Default/CentreHitCirclePiece.cs | 2 -- osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs | 8 +++----- .../Skinning/Default/DefaultInputDrum.cs | 5 ++--- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs index 958f4b3a17..339ab35795 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index 6b5a9ae6d2..72809ffd57 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Extensions.Color4Extensions; @@ -36,6 +34,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default private const float flash_opacity = 0.3f; + [Resolved] + private DrawableHitObject drawableHitObject { get; set; } = null!; + private Color4 accentColour; /// @@ -156,9 +157,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default }; } - [Resolved] - private DrawableHitObject drawableHitObject { get; set; } - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { if (!effectPoint.KiaiMode) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs index fa60d209e7..3d0578dbc0 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable using System; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -135,8 +134,8 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default public bool OnPressed(KeyBindingPressEvent e) { - Drawable target = null; - Drawable back = null; + Drawable? target = null; + Drawable? back = null; if (e.Action == CentreAction) { From 82ff142b1b379de24550f314241ddbc82965d4c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 13:36:52 +0900 Subject: [PATCH 2150/2686] Apply nullability to osu! skinning classes --- osu.Game.Rulesets.Osu/OsuSkinComponent.cs | 2 -- osu.Game.Rulesets.Osu/OsuSkinComponents.cs | 2 -- .../Skinning/Default/CirclePiece.cs | 9 +++---- .../Skinning/Default/DefaultApproachCircle.cs | 4 +-- .../Skinning/Default/DefaultSpinner.cs | 17 ++++++------- .../Skinning/Default/DefaultSpinnerDisc.cs | 17 ++++++------- .../Skinning/Default/DrawableSliderPath.cs | 2 -- .../Skinning/Default/ExplodePiece.cs | 9 +++---- .../Skinning/Default/FlashPiece.cs | 2 -- .../Skinning/Default/GlowPiece.cs | 2 -- .../Skinning/Default/KiaiFlash.cs | 2 -- .../Skinning/Default/MainCirclePiece.cs | 7 +++--- .../Skinning/Default/ManualSliderBody.cs | 2 -- .../Skinning/Default/NumberPiece.cs | 2 -- .../Skinning/Default/PlaySliderBody.cs | 6 ++--- .../Skinning/Default/ReverseArrowPiece.cs | 4 +-- .../Default/SpinnerBackgroundLayer.cs | 2 -- .../Skinning/Default/SpinnerCentreLayer.cs | 10 +++----- .../Skinning/Default/SpinnerFill.cs | 2 -- .../Default/SpinnerRotationTracker.cs | 25 +++++++++---------- .../Skinning/Default/SpinnerSpmCalculator.cs | 7 +++--- .../Skinning/Default/SpinnerTicks.cs | 2 -- .../Skinning/Default/TrianglesPiece.cs | 2 -- .../Skinning/IHasApproachCircle.cs | 4 +-- .../Skinning/Legacy/LegacyApproachCircle.cs | 4 +-- .../Skinning/Legacy/LegacyCursor.cs | 2 -- .../Skinning/Legacy/LegacyCursorParticles.cs | 18 ++++++------- .../Skinning/Legacy/LegacyCursorTrail.cs | 9 +++---- .../Skinning/Legacy/LegacyNewStyleSpinner.cs | 14 +++++------ .../Skinning/Legacy/LegacyOldStyleSpinner.cs | 8 +++--- .../Skinning/Legacy/LegacyReverseArrow.cs | 6 ++--- .../Skinning/Legacy/LegacySliderBody.cs | 2 -- .../Legacy/LegacySliderHeadHitCircle.cs | 6 ++--- .../Skinning/Legacy/LegacySpinner.cs | 23 ++++++++--------- .../Legacy/OsuLegacySkinTransformer.cs | 6 ++--- .../Skinning/NonPlayfieldSprite.cs | 4 +-- .../Skinning/OsuSkinColour.cs | 2 -- .../Skinning/OsuSkinConfiguration.cs | 2 -- .../Skinning/SnakingSliderBody.cs | 8 +++--- 39 files changed, 94 insertions(+), 163 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponent.cs b/osu.Game.Rulesets.Osu/OsuSkinComponent.cs index 0abaf2c924..aa59bd572e 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinComponent.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinComponent.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. -#nullable disable - using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs b/osu.Game.Rulesets.Osu/OsuSkinComponents.cs index 4248cce55a..8fdf3821fa 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinComponents.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinComponents.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. -#nullable disable - namespace osu.Game.Rulesets.Osu { public enum OsuSkinComponents diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs index 40e9f69963..4a679cda2c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs @@ -1,9 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -17,9 +16,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default public class CirclePiece : CompositeDrawable { [Resolved] - private DrawableHitObject drawableObject { get; set; } + private DrawableHitObject drawableObject { get; set; } = null!; - private TrianglesPiece triangles; + private TrianglesPiece triangles = null!; public CirclePiece() { @@ -72,7 +71,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { base.Dispose(isDisposing); - if (drawableObject != null) + if (drawableObject.IsNotNull()) drawableObject.HitObjectApplied -= onHitObjectApplied; } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs index 251fd8d948..e991bc6cf3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -18,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default private readonly IBindable accentColour = new Bindable(); [Resolved] - private DrawableHitObject drawableObject { get; set; } + private DrawableHitObject drawableObject { get; set; } = null!; public DefaultApproachCircle() : base("Gameplay/osu/approachcircle") diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinner.cs index a215b3b1f0..a975030630 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinner.cs @@ -1,12 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Globalization; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; @@ -18,12 +17,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { public class DefaultSpinner : CompositeDrawable { - private DrawableSpinner drawableSpinner; + private DrawableSpinner drawableSpinner = null!; - private OsuSpriteText bonusCounter; + private OsuSpriteText bonusCounter = null!; - private Container spmContainer; - private OsuSpriteText spmCounter; + private Container spmContainer = null!; + private OsuSpriteText spmCounter = null!; public DefaultSpinner() { @@ -81,8 +80,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default }); } - private IBindable gainedBonus; - private IBindable spinsPerMinute; + private IBindable gainedBonus = null!; + private IBindable spinsPerMinute = null!; protected override void LoadComplete() { @@ -135,7 +134,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { base.Dispose(isDisposing); - if (drawableSpinner != null) + if (drawableSpinner.IsNotNull()) drawableSpinner.ApplyCustomUpdateState -= updateStateTransforms; } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs index 60489c1b22..b58daf7174 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs @@ -1,12 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Utils; @@ -21,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { public class DefaultSpinnerDisc : CompositeDrawable { - private DrawableSpinner drawableSpinner; + private DrawableSpinner drawableSpinner = null!; private const float initial_scale = 1.3f; private const float idle_alpha = 0.2f; @@ -30,15 +29,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default private Color4 normalColour; private Color4 completeColour; - private SpinnerTicks ticks; + private SpinnerTicks ticks = null!; private int wholeRotationCount; private readonly BindableBool complete = new BindableBool(); - private SpinnerFill fill; - private Container mainContainer; - private SpinnerCentreLayer centre; - private SpinnerBackgroundLayer background; + private SpinnerFill fill = null!; + private Container mainContainer = null!; + private SpinnerCentreLayer centre = null!; + private SpinnerBackgroundLayer background = null!; public DefaultSpinnerDisc() { @@ -214,7 +213,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { base.Dispose(isDisposing); - if (drawableSpinner != null) + if (drawableSpinner.IsNotNull()) drawableSpinner.ApplyCustomUpdateState -= updateStateTransforms; } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs index e3a83a9280..883524f334 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.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. -#nullable disable - using osu.Framework.Graphics.Lines; using osuTK.Graphics; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs index 6ee8a12132..f8010a9971 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs @@ -1,9 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; @@ -15,9 +14,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default public class ExplodePiece : Container { [Resolved] - private DrawableHitObject drawableObject { get; set; } + private DrawableHitObject drawableObject { get; set; } = null!; - private TrianglesPiece triangles; + private TrianglesPiece triangles = null!; public ExplodePiece() { @@ -56,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { base.Dispose(isDisposing); - if (drawableObject != null) + if (drawableObject.IsNotNull()) drawableObject.HitObjectApplied -= onHitObjectApplied; } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.cs index 98a8b39f6f..06ee64d8b3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.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. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.cs index 2360bc2238..f5e01b802e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/KiaiFlash.cs b/osu.Game.Rulesets.Osu/Skinning/Default/KiaiFlash.cs index a1cfd170a6..506f679836 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/KiaiFlash.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/KiaiFlash.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. -#nullable disable - using System; using osu.Framework.Audio.Track; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs index 4acc406ae1..6d56d21349 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; @@ -46,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default private readonly IBindable indexInCurrentCombo = new Bindable(); [Resolved] - private DrawableHitObject drawableObject { get; set; } + private DrawableHitObject drawableObject { get; set; } = null!; [BackgroundDependencyLoader] private void load() @@ -113,7 +112,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { base.Dispose(isDisposing); - if (drawableObject != null) + if (drawableObject.IsNotNull()) drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.cs index 8d8d9e0d94..d73c94eb9b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.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. -#nullable disable - using System.Collections.Generic; using osuTK; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs index f6759c1093..43d8d1e27f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.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. -#nullable disable - using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs index 6c422cf127..96af59abe2 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Rulesets.Objects.Drawables; @@ -20,10 +18,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default protected IBindable AccentColourBindable { get; private set; } = null!; - private IBindable pathVersion; + private IBindable pathVersion = null!; [Resolved(CanBeNull = true)] - private OsuRulesetConfigManager config { get; set; } + private OsuRulesetConfigManager? config { get; set; } private readonly Bindable configSnakingOut = new Bindable(); diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs index 8f682d02f6..1fce512f53 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Graphics; @@ -19,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default public class ReverseArrowPiece : BeatSyncedContainer { [Resolved] - private DrawableHitObject drawableRepeat { get; set; } + private DrawableHitObject drawableRepeat { get; set; } = null!; public ReverseArrowPiece() { diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.cs index a9b7ddf86f..a1184a15cd 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.cs index ef7b4c2c96..3dd5aed6ae 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -19,11 +17,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { public class SpinnerCentreLayer : CompositeDrawable, IHasAccentColour { - private DrawableSpinner spinner; + private DrawableSpinner spinner = null!; - private CirclePiece circle; - private GlowPiece glow; - private SpriteIcon symbol; + private CirclePiece circle = null!; + private GlowPiece glow = null!; + private SpriteIcon symbol = null!; [BackgroundDependencyLoader] private void load(DrawableHitObject drawableHitObject) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.cs index b7ec9e9799..f574ae589e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.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. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs index 97cebc3123..3a9f73404d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs @@ -1,11 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; @@ -23,6 +22,16 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default private readonly DrawableSpinner drawableSpinner; + private Vector2 mousePosition; + + private float lastAngle; + private float currentRotation; + + private bool rotationTransferred; + + [Resolved(canBeNull: true)] + private IGameplayClock? gameplayClock { get; set; } + public SpinnerRotationTracker(DrawableSpinner drawableSpinner) { this.drawableSpinner = drawableSpinner; @@ -51,16 +60,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default return base.OnMouseMove(e); } - private Vector2 mousePosition; - - private float lastAngle; - private float currentRotation; - - private bool rotationTransferred; - - [Resolved(canBeNull: true)] - private IGameplayClock gameplayClock { get; set; } - protected override void Update() { base.Update(); @@ -126,7 +125,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { base.Dispose(isDisposing); - if (drawableSpinner != null) + if (drawableSpinner.IsNotNull()) drawableSpinner.HitObjectApplied -= resetState; } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs index df72223214..9feaa0966a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs @@ -1,12 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Utils; using osu.Game.Rulesets.Objects.Drawables; @@ -26,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default private readonly Bindable result = new BindableDouble(); [Resolved] - private DrawableHitObject drawableSpinner { get; set; } + private DrawableHitObject drawableSpinner { get; set; } = null!; protected override void LoadComplete() { @@ -66,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { base.Dispose(isDisposing); - if (drawableSpinner != null) + if (drawableSpinner.IsNotNull()) drawableSpinner.HitObjectApplied -= resetState; } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.cs index b66cbe41b6..e518ae1da8 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.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. -#nullable disable - using System; using System.Linq; using osu.Framework.Extensions.Color4Extensions; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs index 7399ddbd1b..fa23c60d57 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.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. -#nullable disable - using osu.Game.Graphics.Backgrounds; namespace osu.Game.Rulesets.Osu.Skinning.Default diff --git a/osu.Game.Rulesets.Osu/Skinning/IHasApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/IHasApproachCircle.cs index 8ebab97503..5ddca03fa1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/IHasApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/IHasApproachCircle.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. -#nullable disable - using osu.Framework.Graphics; namespace osu.Game.Rulesets.Osu.Skinning @@ -15,6 +13,6 @@ namespace osu.Game.Rulesets.Osu.Skinning /// /// The approach circle drawable. /// - Drawable ApproachCircle { get; } + Drawable? ApproachCircle { get; } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs index 03406d37ff..fa5c5b84e4 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -18,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private readonly IBindable accentColour = new Bindable(); [Resolved] - private DrawableHitObject drawableObject { get; set; } + private DrawableHitObject drawableObject { get; set; } = null!; public LegacyApproachCircle() : base("Gameplay/osu/approachcircle") diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs index 4465f9c266..b2ffc171be 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Rulesets.Osu.UI.Cursor; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index ee75b8a857..a28b480753 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.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. -#nullable disable - using System; using System.Linq; using osu.Framework.Allocation; @@ -27,19 +25,19 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler { - public bool Active => breakSpewer?.Active.Value == true || kiaiSpewer?.Active.Value == true; + public bool Active => breakSpewer.Active.Value || kiaiSpewer.Active.Value; - private LegacyCursorParticleSpewer breakSpewer; - private LegacyCursorParticleSpewer kiaiSpewer; + private LegacyCursorParticleSpewer breakSpewer = null!; + private LegacyCursorParticleSpewer kiaiSpewer = null!; [Resolved(canBeNull: true)] - private Player player { get; set; } + private Player? player { get; set; } [Resolved(canBeNull: true)] - private OsuPlayfield playfield { get; set; } + private OsuPlayfield? playfield { get; set; } [Resolved(canBeNull: true)] - private GameplayState gameplayState { get; set; } + private GameplayState? gameplayState { get; set; } [BackgroundDependencyLoader] private void load(ISkinSource skin) @@ -79,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { if (playfield == null || gameplayState == null) return; - DrawableHitObject kiaiHitObject = null; + DrawableHitObject? kiaiHitObject = null; // Check whether currently in a kiai section first. This is only done as an optimisation to avoid enumerating AliveObjects when not necessary. if (gameplayState.Beatmap.ControlPointInfo.EffectPointAt(Time.Current).KiaiMode) @@ -152,7 +150,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected override bool CanSpawnParticles => base.CanSpawnParticles && cursorScreenPosition.HasValue; protected override float ParticleGravity => 240; - public LegacyCursorParticleSpewer(Texture texture, int perSecond) + public LegacyCursorParticleSpewer(Texture? texture, int perSecond) : base(texture, perSecond, particle_duration_max) { Active.BindValueChanged(_ => resetVelocityCalculation()); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs index e62754c6ce..9a59fd73b2 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -22,7 +20,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private bool disjointTrail; private double lastTrailTime; - private IBindable cursorSize; + + private IBindable cursorSize = null!; private Vector2? currentPosition; @@ -34,6 +33,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy [BackgroundDependencyLoader] private void load(OsuConfigManager config) { + cursorSize = config.GetBindable(OsuSetting.GameplayCursorSize).GetBoundCopy(); + Texture = skin.GetTexture("cursortrail"); disjointTrail = skin.GetTexture("cursormiddle") == null; @@ -54,8 +55,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy // stable "magic ratio". see OsuPlayfieldAdjustmentContainer for full explanation. Texture.ScaleAdjust *= 1.6f; } - - cursorSize = config.GetBindable(OsuSetting.GameplayCursorSize).GetBoundCopy(); } protected override double FadeDuration => disjointTrail ? 150 : 500; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs index 71c3e4c9f0..f950d3e43e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -23,15 +21,15 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy /// public class LegacyNewStyleSpinner : LegacySpinner { - private Sprite glow; - private Sprite discBottom; - private Sprite discTop; - private Sprite spinningMiddle; - private Sprite fixedMiddle; + private Sprite glow = null!; + private Sprite discBottom = null!; + private Sprite discTop = null!; + private Sprite spinningMiddle = null!; + private Sprite fixedMiddle = null!; private readonly Color4 glowColour = new Color4(3, 151, 255, 255); - private Container scaleContainer; + private Container scaleContainer = null!; [BackgroundDependencyLoader] private void load(ISkinSource source) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs index a5a765fc02..e5efb668bc 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -23,9 +21,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy /// public class LegacyOldStyleSpinner : LegacySpinner { - private Sprite disc; - private Sprite metreSprite; - private Container metre; + private Sprite disc = null!; + private Sprite metreSprite = null!; + private Container metre = null!; private bool spinnerBlink; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index ff384ee7fc..7e9626eb7f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.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. -#nullable disable - using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -16,9 +14,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy public class LegacyReverseArrow : CompositeDrawable { [Resolved(canBeNull: true)] - private DrawableHitObject drawableHitObject { get; set; } + private DrawableHitObject? drawableHitObject { get; set; } - private Drawable proxy; + private Drawable proxy = null!; [BackgroundDependencyLoader] private void load(ISkinSource skinSource) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs index dbfec14eb2..29a0745193 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.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. -#nullable disable - using System; using osu.Framework.Extensions.Color4Extensions; using osu.Game.Rulesets.Osu.Objects; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs index ab39d7c6ef..08b579697c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.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. -#nullable disable - using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -14,9 +12,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy public class LegacySliderHeadHitCircle : LegacyMainCirclePiece { [Resolved(canBeNull: true)] - private DrawableHitObject drawableHitObject { get; set; } + private DrawableHitObject? drawableHitObject { get; set; } - private Drawable proxiedOverlayLayer; + private Drawable proxiedOverlayLayer = null!; public LegacySliderHeadHitCircle() : base("sliderstartcircle") diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs index a817e5f2b7..66b195962b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs @@ -1,12 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Globalization; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -32,17 +31,17 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private const float spm_hide_offset = 50f; - protected DrawableSpinner DrawableSpinner { get; private set; } + protected DrawableSpinner DrawableSpinner { get; private set; } = null!; - public Drawable ApproachCircle { get; protected set; } + public Drawable? ApproachCircle { get; protected set; } - private Sprite spin; - private Sprite clear; + private Sprite spin = null!; + private Sprite clear = null!; - private LegacySpriteText bonusCounter; + private LegacySpriteText bonusCounter = null!; - private Sprite spmBackground; - private LegacySpriteText spmCounter; + private Sprite spmBackground = null!; + private LegacySpriteText spmCounter = null!; [BackgroundDependencyLoader] private void load(DrawableHitObject drawableHitObject, ISkinSource source) @@ -108,8 +107,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy }); } - private IBindable gainedBonus; - private IBindable spinsPerMinute; + private IBindable gainedBonus = null!; + private IBindable spinsPerMinute = null!; private readonly Bindable completed = new Bindable(); @@ -207,7 +206,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { base.Dispose(isDisposing); - if (DrawableSpinner != null) + if (DrawableSpinner.IsNotNull()) DrawableSpinner.ApplyCustomUpdateState -= UpdateStateTransforms; } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 856ccb5044..3bc2668733 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.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. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -30,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy hasHitCircle = new Lazy(() => GetTexture("hitcircle") != null); } - public override Drawable GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinComponent component) { if (component is OsuSkinComponent osuComponent) { @@ -145,7 +143,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return base.GetDrawableComponent(component); } - public override IBindable GetConfig(TLookup lookup) + public override IBindable? GetConfig(TLookup lookup) { switch (lookup) { diff --git a/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.cs b/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.cs index 0b45c770ba..2a13f07cdb 100644 --- a/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.cs +++ b/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.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. -#nullable disable - using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Rulesets.UI; @@ -15,7 +13,7 @@ namespace osu.Game.Rulesets.Osu.Skinning /// public class NonPlayfieldSprite : Sprite { - public override Texture Texture + public override Texture? Texture { get => base.Texture; set diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs b/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs index 5d8a2ff606..24f9217a5f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.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. -#nullable disable - namespace osu.Game.Rulesets.Osu.Skinning { public enum OsuSkinColour diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs b/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs index 1c0a62454b..77fea9d8f7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuSkinConfiguration.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. -#nullable disable - namespace osu.Game.Rulesets.Osu.Skinning { public enum OsuSkinConfiguration diff --git a/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs index a4a3316927..8ba9e75d19 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.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. -#nullable disable - using System; using System.Collections.Generic; using osu.Framework.Allocation; @@ -55,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.Skinning /// private Vector2 snakedPathOffset; - private DrawableSlider drawableSlider; + private DrawableSlider drawableSlider = null!; [BackgroundDependencyLoader] private void load(DrawableHitObject drawableObject) @@ -67,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.Skinning public void UpdateProgress(double completionProgress) { - if (drawableSlider?.HitObject == null) + if (drawableSlider.HitObject == null) return; Slider slider = drawableSlider.HitObject; @@ -96,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Skinning public void Refresh() { - if (drawableSlider?.HitObject == null) + if (drawableSlider.HitObject == null) return; // Generate the entire curve From a6165ea78ab06518eed3410b15869401943a4dd9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 13:37:04 +0900 Subject: [PATCH 2151/2686] Apply nullability to osu!mania skinning classes --- osu.Game.Rulesets.Mania/ManiaSkinComponent.cs | 2 -- .../Skinning/Default/DefaultBodyPiece.cs | 15 ++++++--------- .../Skinning/Default/DefaultNotePiece.cs | 5 +---- .../Skinning/Default/IHoldNoteBody.cs | 2 -- .../Skinning/Legacy/HitTargetInsetContainer.cs | 2 -- .../Skinning/Legacy/LegacyBodyPiece.cs | 17 ++++++----------- .../Skinning/Legacy/LegacyColumnBackground.cs | 6 ++---- .../Skinning/Legacy/LegacyHitExplosion.cs | 4 +--- .../Skinning/Legacy/LegacyHitTarget.cs | 4 +--- .../Skinning/Legacy/LegacyHoldNoteHeadPiece.cs | 4 +--- .../Skinning/Legacy/LegacyHoldNoteTailPiece.cs | 4 +--- .../Skinning/Legacy/LegacyKeyArea.cs | 10 ++++------ .../Legacy/LegacyManiaColumnElement.cs | 10 ++++------ .../Legacy/LegacyManiaJudgementPiece.cs | 18 +++++------------- .../Skinning/Legacy/LegacyNotePiece.cs | 16 +++++----------- .../Skinning/Legacy/LegacyStageForeground.cs | 4 +--- .../Legacy/ManiaClassicSkinTransformer.cs | 2 +- .../Skinning/ManiaSkinConfigExtensions.cs | 8 +++----- .../Skinning/ManiaSkinConfigurationLookup.cs | 2 -- 19 files changed, 42 insertions(+), 93 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs b/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs index f05edb4677..a074aab9da 100644 --- a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs +++ b/osu.Game.Rulesets.Mania/ManiaSkinComponent.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. -#nullable disable - using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania diff --git a/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs index 7476af3c3c..f0e214b190 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs @@ -1,10 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -27,8 +24,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default protected readonly Bindable AccentColour = new Bindable(); protected readonly IBindable IsHitting = new Bindable(); - protected Drawable Background { get; private set; } - private Container foregroundContainer; + protected Drawable Background { get; private set; } = null!; + private Container foregroundContainer = null!; public DefaultBodyPiece() { @@ -36,7 +33,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default } [BackgroundDependencyLoader(true)] - private void load([CanBeNull] DrawableHitObject drawableObject) + private void load(DrawableHitObject? drawableObject) { InternalChildren = new[] { @@ -74,9 +71,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default private readonly LayoutValue subtractionCache = new LayoutValue(Invalidation.DrawSize); - private BufferedContainer foregroundBuffer; - private BufferedContainer subtractionBuffer; - private Container subtractionLayer; + private BufferedContainer foregroundBuffer = null!; + private BufferedContainer subtractionBuffer = null!; + private Container subtractionLayer = null!; public ForegroundPiece() { diff --git a/osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs index 72bb05de49..569740deee 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; @@ -53,7 +50,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default } [BackgroundDependencyLoader(true)] - private void load([NotNull] IScrollingInfo scrollingInfo, [CanBeNull] DrawableHitObject drawableObject) + private void load(IScrollingInfo scrollingInfo, DrawableHitObject? drawableObject) { direction.BindTo(scrollingInfo.Direction); direction.BindValueChanged(onDirectionChanged, true); diff --git a/osu.Game.Rulesets.Mania/Skinning/Default/IHoldNoteBody.cs b/osu.Game.Rulesets.Mania/Skinning/Default/IHoldNoteBody.cs index 9168a96b95..1f290f1f1c 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Default/IHoldNoteBody.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Default/IHoldNoteBody.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. -#nullable disable - namespace osu.Game.Rulesets.Mania.Skinning.Default { /// diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs index 362a265789..3c89e2c04a 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index 49ba503cb5..52bca2aaa0 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -1,12 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Textures; @@ -20,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyBodyPiece : LegacyManiaColumnElement { - private DrawableHoldNote holdNote; + private DrawableHoldNote holdNote = null!; private readonly IBindable direction = new Bindable(); private readonly IBindable isHitting = new Bindable(); @@ -31,14 +29,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy /// private readonly Bindable missFadeTime = new Bindable(); - [CanBeNull] - private Drawable bodySprite; + private Drawable? bodySprite; - [CanBeNull] - private Drawable lightContainer; + private Drawable? lightContainer; - [CanBeNull] - private Drawable light; + private Drawable? light; public LegacyBodyPiece() { @@ -214,7 +209,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { base.Dispose(isDisposing); - if (holdNote != null) + if (holdNote.IsNotNull()) holdNote.ApplyCustomUpdateState -= applyCustomUpdateState; lightContainer?.Expire(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs index f35cedab08..0ed96cf6f1 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -21,8 +19,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { private readonly IBindable direction = new Bindable(); - private Container lightContainer; - private Sprite light; + private Container lightContainer = null!; + private Sprite light = null!; public LegacyColumnBackground() { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.cs index 278cf0707c..6b0e1e5d8a 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -23,7 +21,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy private readonly IBindable direction = new Bindable(); - private Drawable explosion; + private Drawable? explosion; public LegacyHitExplosion() { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs index 611dac30b3..ed78cb6086 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -20,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { private readonly IBindable direction = new Bindable(); - private Container directionContainer; + private Container directionContainer = null!; [BackgroundDependencyLoader] private void load(ISkinSource skin, IScrollingInfo scrollingInfo) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs index a653e2ce36..c3ed0111be 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.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. -#nullable disable - using osu.Framework.Graphics; using osu.Game.Skinning; @@ -10,7 +8,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { public class LegacyHoldNoteHeadPiece : LegacyNotePiece { - protected override Drawable GetAnimation(ISkinSource skin) + protected override Drawable? GetAnimation(ISkinSource skin) { // TODO: Should fallback to the head from default legacy skin instead of note. return GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteHeadImage) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs index 7511b008f0..13edc6e495 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.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. -#nullable disable - using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Rulesets.UI.Scrolling; @@ -20,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy : new ValueChangedEvent(ScrollingDirection.Up, ScrollingDirection.Up)); } - protected override Drawable GetAnimation(ISkinSource skin) + protected override Drawable? GetAnimation(ISkinSource skin) { // TODO: Should fallback to the head from default legacy skin instead of note. return GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.HoldNoteTailImage) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs index dfd5af89c1..e7dca3d946 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -21,12 +19,12 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { private readonly IBindable direction = new Bindable(); - private Container directionContainer; - private Sprite upSprite; - private Sprite downSprite; + private Container directionContainer = null!; + private Sprite upSprite = null!; + private Sprite downSprite = null!; [Resolved] - private Column column { get; set; } + private Column column { get; set; } = null!; public LegacyKeyArea() { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs index e227c80845..4ffef18781 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -19,15 +17,15 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy public class LegacyManiaColumnElement : CompositeDrawable { [Resolved] - protected Column Column { get; private set; } + protected Column Column { get; private set; } = null!; [Resolved] - private StageDefinition stage { get; set; } + private StageDefinition stage { get; set; } = null!; /// /// The column type identifier to use for texture lookups, in the case of no user-provided configuration. /// - protected string FallbackColumnIndex { get; private set; } + protected string FallbackColumnIndex { get; private set; } = null!; [BackgroundDependencyLoader] private void load() @@ -41,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } } - protected IBindable GetColumnSkinConfig(ISkin skin, LegacyManiaSkinConfigurationLookups lookup) + protected IBindable? GetColumnSkinConfig(ISkin skin, LegacyManiaSkinConfigurationLookups lookup) where T : notnull => skin.GetManiaSkinConfig(lookup, Column.Index); } } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs index d09a73a693..670a0aad6e 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; @@ -41,21 +39,15 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy Y = scorePosition ?? 0; - if (animation != null) + InternalChild = animation.With(d => { - InternalChild = animation.With(d => - { - d.Anchor = Anchor.Centre; - d.Origin = Anchor.Centre; - }); - } + d.Anchor = Anchor.Centre; + d.Origin = Anchor.Centre; + }); } public void PlayAnimation() { - if (animation == null) - return; - (animation as IFramedAnimation)?.GotoFrame(0); this.FadeInFromZero(20, Easing.Out) @@ -86,6 +78,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } } - public Drawable GetAboveHitObjectsProxiedContent() => null; + public Drawable? GetAboveHitObjectsProxiedContent() => null; } } diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs index 41e149ea2f..8c5a594b3b 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -21,10 +18,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { private readonly IBindable direction = new Bindable(); - private Container directionContainer; + private Container directionContainer = null!; - [CanBeNull] - private Drawable noteAnimation; + private Drawable noteAnimation = null!; private float? minimumColumnWidth; @@ -55,7 +51,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { base.Update(); - Texture texture = null; + Texture? texture = null; if (noteAnimation is Sprite sprite) texture = sprite.Texture; @@ -84,11 +80,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy } } - [CanBeNull] - protected virtual Drawable GetAnimation(ISkinSource skin) => GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage); + protected virtual Drawable? GetAnimation(ISkinSource skin) => GetAnimationFromLookup(skin, LegacyManiaSkinConfigurationLookups.NoteImage); - [CanBeNull] - protected Drawable GetAnimationFromLookup(ISkin skin, LegacyManiaSkinConfigurationLookups lookup) + protected Drawable? GetAnimationFromLookup(ISkin skin, LegacyManiaSkinConfigurationLookups lookup) { string suffix = string.Empty; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs index f7c611d551..8e72e970ab 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -17,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { private readonly IBindable direction = new Bindable(); - private Drawable sprite; + private Drawable? sprite; public LegacyStageForeground() { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaClassicSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaClassicSkinTransformer.cs index e57927897c..be3372fe58 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaClassicSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaClassicSkinTransformer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy { } - public override IBindable GetConfig(TLookup lookup) + public override IBindable? GetConfig(TLookup lookup) { if (lookup is ManiaSkinConfigurationLookup maniaLookup) { diff --git a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs index e22bf63049..0f15bfe12b 100644 --- a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.cs +++ b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigExtensions.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. -#nullable disable - using osu.Framework.Bindables; using osu.Game.Skinning; @@ -16,8 +14,8 @@ namespace osu.Game.Rulesets.Mania.Skinning /// The skin from which configuration is retrieved. /// The value to retrieve. /// If not null, denotes the index of the column to which the entry applies. - public static IBindable GetManiaSkinConfig(this ISkin skin, LegacyManiaSkinConfigurationLookups lookup, int? columnIndex = null) - => skin.GetConfig( - new ManiaSkinConfigurationLookup(lookup, columnIndex)); + public static IBindable? GetManiaSkinConfig(this ISkin skin, LegacyManiaSkinConfigurationLookups lookup, int? columnIndex = null) + where T : notnull + => skin.GetConfig(new ManiaSkinConfigurationLookup(lookup, columnIndex)); } } diff --git a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs index 59188f02f9..6c39ffdcc3 100644 --- a/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.cs +++ b/osu.Game.Rulesets.Mania/Skinning/ManiaSkinConfigurationLookup.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. -#nullable disable - using osu.Game.Rulesets.Mania.UI; using osu.Game.Skinning; From 2952dbc8fb9ffd0e7c3475dcdf5ea123431d559a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 13:37:19 +0900 Subject: [PATCH 2152/2686] Apply nullability to osu!catch skinning classes --- osu.Game.Rulesets.Catch/CatchInputManager.cs | 2 -- osu.Game.Rulesets.Catch/CatchSkinComponent.cs | 2 -- .../CatchSkinComponents.cs | 2 -- .../Skinning/CatchSkinColour.cs | 2 -- .../Skinning/CatchSkinConfiguration.cs | 2 -- .../Skinning/Default/BananaPulpFormation.cs | 2 -- .../Skinning/Default/BorderPiece.cs | 2 -- .../Skinning/Default/CatchHitObjectPiece.cs | 11 +++------ .../Skinning/Default/DefaultCatcher.cs | 2 -- .../Skinning/Default/DefaultHitExplosion.cs | 10 ++++---- .../Skinning/Default/DropletPiece.cs | 2 -- .../Skinning/Default/FruitPiece.cs | 2 -- .../Skinning/Default/FruitPulpFormation.cs | 2 -- .../Skinning/Default/HyperBorderPiece.cs | 2 -- .../Default/HyperDropletBorderPiece.cs | 2 -- .../Skinning/Default/Pulp.cs | 2 -- .../Skinning/Default/PulpFormation.cs | 2 -- .../Legacy/CatchLegacySkinTransformer.cs | 8 +++---- .../Skinning/Legacy/LegacyBananaPiece.cs | 6 ++--- .../Legacy/LegacyCatchHitObjectPiece.cs | 23 +++++++++---------- .../Skinning/Legacy/LegacyCatcherNew.cs | 9 ++++---- .../Skinning/Legacy/LegacyCatcherOld.cs | 4 +--- .../Skinning/Legacy/LegacyDropletPiece.cs | 6 ++--- .../Skinning/Legacy/LegacyFruitPiece.cs | 2 -- .../Skinning/Legacy/LegacyHitExplosion.cs | 4 +--- 25 files changed, 31 insertions(+), 82 deletions(-) diff --git a/osu.Game.Rulesets.Catch/CatchInputManager.cs b/osu.Game.Rulesets.Catch/CatchInputManager.cs index 5b62154a34..0f76953003 100644 --- a/osu.Game.Rulesets.Catch/CatchInputManager.cs +++ b/osu.Game.Rulesets.Catch/CatchInputManager.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. -#nullable disable - using System.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Input.Bindings; diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs b/osu.Game.Rulesets.Catch/CatchSkinComponent.cs index e79da667da..07c613d6ff 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponent.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. -#nullable disable - using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs index 7587de5803..371e901c69 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponents.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. -#nullable disable - namespace osu.Game.Rulesets.Catch { public enum CatchSkinComponents diff --git a/osu.Game.Rulesets.Catch/Skinning/CatchSkinColour.cs b/osu.Game.Rulesets.Catch/Skinning/CatchSkinColour.cs index d038ccb31c..4506111498 100644 --- a/osu.Game.Rulesets.Catch/Skinning/CatchSkinColour.cs +++ b/osu.Game.Rulesets.Catch/Skinning/CatchSkinColour.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. -#nullable disable - namespace osu.Game.Rulesets.Catch.Skinning { public enum CatchSkinColour diff --git a/osu.Game.Rulesets.Catch/Skinning/CatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch/Skinning/CatchSkinConfiguration.cs index 65d6acd88d..ea8d742b1a 100644 --- a/osu.Game.Rulesets.Catch/Skinning/CatchSkinConfiguration.cs +++ b/osu.Game.Rulesets.Catch/Skinning/CatchSkinConfiguration.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. -#nullable disable - namespace osu.Game.Rulesets.Catch.Skinning { public enum CatchSkinConfiguration diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.cs b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.cs index ffeed80615..ee1cc68f7d 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.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. -#nullable disable - using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Default diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs index 60a13bee59..8d8ee49af7 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.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. -#nullable disable - using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Catch.Objects; diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs index 3b8df6ee6f..e84e4d4ad2 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs @@ -1,10 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -21,19 +18,17 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default public readonly Bindable IndexInBeatmap = new Bindable(); [Resolved] - protected IHasCatchObjectState ObjectState { get; private set; } + protected IHasCatchObjectState ObjectState { get; private set; } = null!; /// /// A part of this piece that will be faded out while falling in the playfield. /// - [CanBeNull] - protected virtual Drawable BorderPiece => null; + protected virtual Drawable? BorderPiece => null; /// /// A part of this piece that will be only visible when is true. /// - [CanBeNull] - protected virtual Drawable HyperBorderPiece => null; + protected virtual Drawable? HyperBorderPiece => null; protected override void LoadComplete() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.cs index 4148fed11c..e423f21b98 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.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. -#nullable disable - using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs index 7ea99b3ed9..2650ba765b 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -18,10 +16,10 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default { public class DefaultHitExplosion : CompositeDrawable, IHitExplosion { - private CircularContainer largeFaint; - private CircularContainer smallFaint; - private CircularContainer directionalGlow1; - private CircularContainer directionalGlow2; + private CircularContainer largeFaint = null!; + private CircularContainer smallFaint = null!; + private CircularContainer directionalGlow1 = null!; + private CircularContainer directionalGlow2 = null!; [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs index b8ae062382..59e74bff74 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.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. -#nullable disable - using osu.Framework.Graphics; using osu.Game.Rulesets.Catch.Objects; using osuTK; diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs index adee960c3c..3bd8032649 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.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. -#nullable disable - using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Rulesets.Catch.Objects; diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.cs b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.cs index db51195f11..f097361d2a 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.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. -#nullable disable - using osu.Framework.Bindables; using osu.Game.Rulesets.Catch.Objects; using osuTK; diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs index 42b0b85495..c8895f32f4 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.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. -#nullable disable - using osu.Framework.Graphics; using osu.Game.Rulesets.Catch.UI; diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.cs index 29cb339625..53a487b97f 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.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. -#nullable disable - namespace osu.Game.Rulesets.Catch.Skinning.Default { public class HyperDropletBorderPiece : HyperBorderPiece diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/Pulp.cs b/osu.Game.Rulesets.Catch/Skinning/Default/Pulp.cs index 8ea54617d9..96c6233b41 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/Pulp.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/Pulp.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. -#nullable disable - using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.cs b/osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.cs index aa5ef5fb66..8753aa4077 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.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. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Framework.Graphics; diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index a73b34c9b6..ef83e67876 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.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. -#nullable disable - using System.Linq; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -27,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { } - public override Drawable GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinComponent component) { if (component is SkinnableTargetComponent targetComponent) { @@ -112,12 +110,12 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy GetTexture(@"fruit-catcher-idle") != null || GetTexture(@"fruit-catcher-idle-0") != null; - public override IBindable GetConfig(TLookup lookup) + public override IBindable? GetConfig(TLookup lookup) { switch (lookup) { case CatchSkinColour colour: - var result = (Bindable)base.GetConfig(new SkinCustomColourLookup(colour)); + var result = (Bindable?)base.GetConfig(new SkinCustomColourLookup(colour)); if (result == null) return null; diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyBananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyBananaPiece.cs index 9f64a2129e..310da8bf78 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyBananaPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyBananaPiece.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. -#nullable disable - using osu.Framework.Graphics.Textures; namespace osu.Game.Rulesets.Catch.Skinning.Legacy @@ -13,8 +11,8 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { base.LoadComplete(); - Texture texture = Skin.GetTexture("fruit-bananas"); - Texture overlayTexture = Skin.GetTexture("fruit-bananas-overlay"); + Texture? texture = Skin.GetTexture("fruit-bananas"); + Texture? overlayTexture = Skin.GetTexture("fruit-bananas-overlay"); SetTexture(texture, overlayTexture); } diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchHitObjectPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchHitObjectPiece.cs index 5a5288105d..1231ed6d5a 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchHitObjectPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchHitObjectPiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -19,19 +17,20 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { public abstract class LegacyCatchHitObjectPiece : PoolableDrawable { - public readonly Bindable AccentColour = new Bindable(); - public readonly Bindable HyperDash = new Bindable(); - public readonly Bindable IndexInBeatmap = new Bindable(); + protected readonly Bindable IndexInBeatmap = new Bindable(); + + private readonly Bindable accentColour = new Bindable(); + private readonly Bindable hyperDash = new Bindable(); private readonly Sprite colouredSprite; private readonly Sprite overlaySprite; private readonly Sprite hyperSprite; [Resolved] - protected ISkinSource Skin { get; private set; } + protected ISkinSource Skin { get; private set; } = null!; [Resolved] - protected IHasCatchObjectState ObjectState { get; private set; } + protected IHasCatchObjectState ObjectState { get; private set; } = null!; protected LegacyCatchHitObjectPiece() { @@ -65,26 +64,26 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { base.LoadComplete(); - AccentColour.BindTo(ObjectState.AccentColour); - HyperDash.BindTo(ObjectState.HyperDash); + accentColour.BindTo(ObjectState.AccentColour); + hyperDash.BindTo(ObjectState.HyperDash); IndexInBeatmap.BindTo(ObjectState.IndexInBeatmap); hyperSprite.Colour = Skin.GetConfig(CatchSkinColour.HyperDashFruit)?.Value ?? Skin.GetConfig(CatchSkinColour.HyperDash)?.Value ?? Catcher.DEFAULT_HYPER_DASH_COLOUR; - AccentColour.BindValueChanged(colour => + accentColour.BindValueChanged(colour => { colouredSprite.Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue); }, true); - HyperDash.BindValueChanged(hyper => + hyperDash.BindValueChanged(hyper => { hyperSprite.Alpha = hyper.NewValue ? 0.7f : 0; }, true); } - protected void SetTexture(Texture texture, Texture overlayTexture) + protected void SetTexture(Texture? texture, Texture? overlayTexture) { colouredSprite.Texture = texture; overlaySprite.Texture = overlayTexture; diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.cs index 93d79f00d3..667622e6f2 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -20,11 +18,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy public class LegacyCatcherNew : CompositeDrawable { [Resolved] - private Bindable currentState { get; set; } + private Bindable currentState { get; set; } = null!; private readonly Dictionary drawables = new Dictionary(); - private Drawable currentDrawable; + private Drawable currentDrawable = null!; public LegacyCatcherNew() { @@ -51,7 +49,8 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy Drawable getDrawableFor(CatcherAnimationState state) => skin.GetAnimation(@$"fruit-catcher-{state.ToString().ToLowerInvariant()}", true, true, true) ?? - skin.GetAnimation(@"fruit-catcher-idle", true, true, true); + skin.GetAnimation(@"fruit-catcher-idle", true, true, true) ?? + Empty(); } protected override void LoadComplete() diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.cs index 736e9cfddf..5f09d1e254 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -21,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy [BackgroundDependencyLoader] private void load(ISkinSource skin) { - InternalChild = skin.GetAnimation(@"fruit-ryuuta", true, true, true).With(d => + InternalChild = (skin.GetAnimation(@"fruit-ryuuta", true, true, true) ?? Empty()).With(d => { d.Anchor = Anchor.TopCentre; d.Origin = Anchor.TopCentre; diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyDropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyDropletPiece.cs index f99cedab3f..7007f1cc29 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyDropletPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyDropletPiece.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. -#nullable disable - using osu.Framework.Graphics.Textures; using osuTK; @@ -19,8 +17,8 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { base.LoadComplete(); - Texture texture = Skin.GetTexture("fruit-drop"); - Texture overlayTexture = Skin.GetTexture("fruit-drop-overlay"); + Texture? texture = Skin.GetTexture("fruit-drop"); + Texture? overlayTexture = Skin.GetTexture("fruit-drop-overlay"); SetTexture(texture, overlayTexture); } diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs index 125a96a446..f002bab219 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.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. -#nullable disable - using osu.Game.Rulesets.Catch.Objects; namespace osu.Game.Rulesets.Catch.Skinning.Legacy diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs index 8f46bdbe6e..393a1076af 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.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. -#nullable disable - using System; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -18,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy public class LegacyHitExplosion : CompositeDrawable, IHitExplosion { [Resolved] - private Catcher catcher { get; set; } + private Catcher catcher { get; set; } = null!; private const float catch_margin = (1 - Catcher.ALLOWED_CATCH_RANGE) / 2; From bf26dbffc2e48458f48d4e8433d2b96f49eacf82 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 13:44:59 +0900 Subject: [PATCH 2153/2686] Apply nullability to skinning support classes --- .../Judgements/IAnimatableJudgement.cs | 6 +-- osu.Game/Skinning/ArgonSkin.cs | 13 +++--- osu.Game/Skinning/DefaultLegacySkin.cs | 2 - osu.Game/Skinning/GameplaySkinComponent.cs | 3 +- osu.Game/Skinning/GlobalSkinColours.cs | 2 - osu.Game/Skinning/IAnimationTimeReference.cs | 2 - osu.Game/Skinning/IPooledSampleProvider.cs | 6 +-- osu.Game/Skinning/ISkinComponent.cs | 2 - osu.Game/Skinning/ISkinSource.cs | 6 +-- osu.Game/Skinning/ISkinnableDrawable.cs | 2 - osu.Game/Skinning/ISkinnableTarget.cs | 2 - osu.Game/Skinning/LegacyAccuracyCounter.cs | 2 - .../Skinning/LegacyColourCompatibility.cs | 2 - osu.Game/Skinning/LegacyComboCounter.cs | 2 - osu.Game/Skinning/LegacyFont.cs | 2 - osu.Game/Skinning/LegacyJudgementPieceNew.cs | 10 ++--- osu.Game/Skinning/LegacySkin.cs | 8 ++-- osu.Game/Skinning/SkinComboColourLookup.cs | 2 - osu.Game/Skinning/SkinConfigManager.cs | 2 - osu.Game/Skinning/SkinConfiguration.cs | 4 +- osu.Game/Skinning/SkinProvidingContainer.cs | 40 +++++++++---------- osu.Game/Skinning/SkinReloadableDrawable.cs | 9 ++--- osu.Game/Skinning/SkinUtils.cs | 4 +- osu.Game/Skinning/SkinnableSprite.cs | 16 ++++---- osu.Game/Skinning/SkinnableSpriteText.cs | 2 - osu.Game/Skinning/SkinnableTarget.cs | 2 - osu.Game/Skinning/SkinnableTargetComponent.cs | 2 - .../SkinnableTargetComponentsContainer.cs | 4 +- osu.Game/Skinning/SkinnableTargetContainer.cs | 6 +-- osu.Game/Skinning/TrianglesSkin.cs | 12 +++--- .../UnsupportedSkinComponentException.cs | 2 - 31 files changed, 60 insertions(+), 119 deletions(-) diff --git a/osu.Game/Rulesets/Judgements/IAnimatableJudgement.cs b/osu.Game/Rulesets/Judgements/IAnimatableJudgement.cs index 2bc5a62983..0aa337bc20 100644 --- a/osu.Game/Rulesets/Judgements/IAnimatableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/IAnimatableJudgement.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Framework.Graphics; namespace osu.Game.Rulesets.Judgements @@ -21,7 +18,6 @@ namespace osu.Game.Rulesets.Judgements /// /// Get proxied content which should be displayed above all hitobjects. /// - [CanBeNull] - Drawable GetAboveHitObjectsProxiedContent(); + Drawable? GetAboveHitObjectsProxiedContent(); } } diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 010e2175e1..20e4290725 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -25,7 +24,7 @@ namespace osu.Game.Skinning { public static SkinInfo CreateInfo() => new SkinInfo { - ID = osu.Game.Skinning.SkinInfo.ARGON_SKIN, + ID = Skinning.SkinInfo.ARGON_SKIN, Name = "osu! \"argon\" (2022)", Creator = "team osu!", Protected = true, @@ -68,9 +67,9 @@ namespace osu.Game.Skinning }; } - public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Textures?.Get(componentName, wrapModeS, wrapModeT); + public override Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Textures?.Get(componentName, wrapModeS, wrapModeT); - public override ISample GetSample(ISampleInfo sampleInfo) + public override ISample? GetSample(ISampleInfo sampleInfo) { foreach (string lookup in sampleInfo.LookupNames) { @@ -82,7 +81,7 @@ namespace osu.Game.Skinning return null; } - public override Drawable GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinComponent component) { if (base.GetDrawableComponent(component) is Drawable c) return c; @@ -192,7 +191,7 @@ namespace osu.Game.Skinning return null; } - public override IBindable GetConfig(TLookup lookup) + public override IBindable? GetConfig(TLookup lookup) { // todo: this code is pulled from LegacySkin and should not exist. // will likely change based on how databased storage of skin configuration goes. @@ -202,7 +201,7 @@ namespace osu.Game.Skinning switch (global) { case GlobalSkinColours.ComboColours: - return SkinUtils.As(new Bindable>(Configuration.ComboColours)); + return SkinUtils.As(new Bindable?>(Configuration.ComboColours)); } break; diff --git a/osu.Game/Skinning/DefaultLegacySkin.cs b/osu.Game/Skinning/DefaultLegacySkin.cs index b80275a1e8..fd9653e3e5 100644 --- a/osu.Game/Skinning/DefaultLegacySkin.cs +++ b/osu.Game/Skinning/DefaultLegacySkin.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. -#nullable disable - using System.Collections.Generic; using JetBrains.Annotations; using osu.Framework.IO.Stores; diff --git a/osu.Game/Skinning/GameplaySkinComponent.cs b/osu.Game/Skinning/GameplaySkinComponent.cs index cdd3638375..6f5dad2207 100644 --- a/osu.Game/Skinning/GameplaySkinComponent.cs +++ b/osu.Game/Skinning/GameplaySkinComponent.cs @@ -1,13 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Linq; namespace osu.Game.Skinning { public class GameplaySkinComponent : ISkinComponent + where T : notnull { public readonly T Component; diff --git a/osu.Game/Skinning/GlobalSkinColours.cs b/osu.Game/Skinning/GlobalSkinColours.cs index e2b5799048..f889371b98 100644 --- a/osu.Game/Skinning/GlobalSkinColours.cs +++ b/osu.Game/Skinning/GlobalSkinColours.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. -#nullable disable - namespace osu.Game.Skinning { public enum GlobalSkinColours diff --git a/osu.Game/Skinning/IAnimationTimeReference.cs b/osu.Game/Skinning/IAnimationTimeReference.cs index a65d15d24b..b6a944ddf8 100644 --- a/osu.Game/Skinning/IAnimationTimeReference.cs +++ b/osu.Game/Skinning/IAnimationTimeReference.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Textures; diff --git a/osu.Game/Skinning/IPooledSampleProvider.cs b/osu.Game/Skinning/IPooledSampleProvider.cs index 46cd824e95..3ea299f5e2 100644 --- a/osu.Game/Skinning/IPooledSampleProvider.cs +++ b/osu.Game/Skinning/IPooledSampleProvider.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using JetBrains.Annotations; using osu.Game.Audio; namespace osu.Game.Skinning @@ -18,7 +15,6 @@ namespace osu.Game.Skinning /// /// The describing the sample to retrieve. /// The . - [CanBeNull] - PoolableSkinnableSample GetPooledSample(ISampleInfo sampleInfo); + PoolableSkinnableSample? GetPooledSample(ISampleInfo sampleInfo); } } diff --git a/osu.Game/Skinning/ISkinComponent.cs b/osu.Game/Skinning/ISkinComponent.cs index 34922b98b6..4bd9f21b6b 100644 --- a/osu.Game/Skinning/ISkinComponent.cs +++ b/osu.Game/Skinning/ISkinComponent.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. -#nullable disable - namespace osu.Game.Skinning { public interface ISkinComponent diff --git a/osu.Game/Skinning/ISkinSource.cs b/osu.Game/Skinning/ISkinSource.cs index 94940fd549..89f656a12c 100644 --- a/osu.Game/Skinning/ISkinSource.cs +++ b/osu.Game/Skinning/ISkinSource.cs @@ -1,11 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; -using JetBrains.Annotations; namespace osu.Game.Skinning { @@ -24,8 +21,7 @@ namespace osu.Game.Skinning /// This should be used for cases where subsequent lookups (for related components) need to occur on the same skin. /// /// The skin to be used for subsequent lookups, or null if none is available. - [CanBeNull] - ISkin FindProvider(Func lookupFunction); + ISkin? FindProvider(Func lookupFunction); /// /// Retrieve all sources available for lookup, with highest priority source first. diff --git a/osu.Game/Skinning/ISkinnableDrawable.cs b/osu.Game/Skinning/ISkinnableDrawable.cs index ca643af17a..3fc6a2fdd8 100644 --- a/osu.Game/Skinning/ISkinnableDrawable.cs +++ b/osu.Game/Skinning/ISkinnableDrawable.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. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; diff --git a/osu.Game/Skinning/ISkinnableTarget.cs b/osu.Game/Skinning/ISkinnableTarget.cs index 17279ef178..8d4f4dd0c3 100644 --- a/osu.Game/Skinning/ISkinnableTarget.cs +++ b/osu.Game/Skinning/ISkinnableTarget.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using osu.Framework.Bindables; diff --git a/osu.Game/Skinning/LegacyAccuracyCounter.cs b/osu.Game/Skinning/LegacyAccuracyCounter.cs index ffb463faae..bdcb85456a 100644 --- a/osu.Game/Skinning/LegacyAccuracyCounter.cs +++ b/osu.Game/Skinning/LegacyAccuracyCounter.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. -#nullable disable - using osu.Framework.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Screens.Play.HUD; diff --git a/osu.Game/Skinning/LegacyColourCompatibility.cs b/osu.Game/Skinning/LegacyColourCompatibility.cs index 0673d0a8d3..38e43432ce 100644 --- a/osu.Game/Skinning/LegacyColourCompatibility.cs +++ b/osu.Game/Skinning/LegacyColourCompatibility.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. -#nullable disable - using osu.Framework.Graphics; using osuTK.Graphics; diff --git a/osu.Game/Skinning/LegacyComboCounter.cs b/osu.Game/Skinning/LegacyComboCounter.cs index bfa6d5a255..f4caef26c2 100644 --- a/osu.Game/Skinning/LegacyComboCounter.cs +++ b/osu.Game/Skinning/LegacyComboCounter.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; diff --git a/osu.Game/Skinning/LegacyFont.cs b/osu.Game/Skinning/LegacyFont.cs index f738caf3f3..d1971cb84c 100644 --- a/osu.Game/Skinning/LegacyFont.cs +++ b/osu.Game/Skinning/LegacyFont.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. -#nullable disable - namespace osu.Game.Skinning { /// diff --git a/osu.Game/Skinning/LegacyJudgementPieceNew.cs b/osu.Game/Skinning/LegacyJudgementPieceNew.cs index 2cb055d8ba..39b266ab9f 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceNew.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceNew.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. -#nullable disable - using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; @@ -20,13 +18,13 @@ namespace osu.Game.Skinning { private readonly HitResult result; - private readonly LegacyJudgementPieceOld temporaryOldStyle; + private readonly LegacyJudgementPieceOld? temporaryOldStyle; private readonly Drawable mainPiece; - private readonly ParticleExplosion particles; + private readonly ParticleExplosion? particles; - public LegacyJudgementPieceNew(HitResult result, Func createMainDrawable, Texture particleTexture) + public LegacyJudgementPieceNew(HitResult result, Func createMainDrawable, Texture? particleTexture) { this.result = result; @@ -124,6 +122,6 @@ namespace osu.Game.Skinning } } - public Drawable GetAboveHitObjectsProxiedContent() => temporaryOldStyle?.CreateProxy(); // for new style judgements, only the old style temporary display is in front of objects. + public Drawable? GetAboveHitObjectsProxiedContent() => temporaryOldStyle?.CreateProxy(); // for new style judgements, only the old style temporary display is in front of objects. } } diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index eaca0de11a..bfc60de2c9 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -9,6 +9,7 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; @@ -379,12 +380,13 @@ namespace osu.Game.Skinning return null; case GameplaySkinComponent resultComponent: - // TODO: this should be inside the judgement pieces. - Func createDrawable = () => getJudgementAnimation(resultComponent.Component); // kind of wasteful that we throw this away, but should do for now. - if (createDrawable() != null) + if (getJudgementAnimation(resultComponent.Component) != null) { + // TODO: this should be inside the judgement pieces. + Func createDrawable = () => getJudgementAnimation(resultComponent.Component).AsNonNull(); + var particle = getParticleTexture(resultComponent.Component); if (particle != null) diff --git a/osu.Game/Skinning/SkinComboColourLookup.cs b/osu.Game/Skinning/SkinComboColourLookup.cs index 2eb4af6289..33e35a96fb 100644 --- a/osu.Game/Skinning/SkinComboColourLookup.cs +++ b/osu.Game/Skinning/SkinComboColourLookup.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. -#nullable disable - using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Skinning diff --git a/osu.Game/Skinning/SkinConfigManager.cs b/osu.Game/Skinning/SkinConfigManager.cs index 8a34ab3db4..682138a2e9 100644 --- a/osu.Game/Skinning/SkinConfigManager.cs +++ b/osu.Game/Skinning/SkinConfigManager.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. -#nullable disable - using System; using osu.Framework.Configuration; diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index a9f660312e..937cca0aeb 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.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. -#nullable disable - using System.Collections.Generic; using osu.Game.Beatmaps.Formats; using osuTK.Graphics; @@ -52,7 +50,7 @@ namespace osu.Game.Skinning public List CustomComboColours { get; set; } = new List(); - public IReadOnlyList ComboColours + public IReadOnlyList? ComboColours { get { diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index 42c39e581f..5c5e9ae0fc 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -1,12 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; @@ -22,10 +19,9 @@ namespace osu.Game.Skinning /// public class SkinProvidingContainer : Container, ISkinSource { - public event Action SourceChanged; + public event Action? SourceChanged; - [CanBeNull] - protected ISkinSource ParentSource { get; private set; } + protected ISkinSource? ParentSource { get; private set; } /// /// Whether falling back to parent s is allowed in this container. @@ -52,7 +48,7 @@ namespace osu.Game.Skinning /// /// Constructs a new initialised with a single skin source. /// - public SkinProvidingContainer([CanBeNull] ISkin skin) + public SkinProvidingContainer(ISkin? skin) : this() { if (skin != null) @@ -82,7 +78,7 @@ namespace osu.Game.Skinning return dependencies; } - public ISkin FindProvider(Func lookupFunction) + public ISkin? FindProvider(Func lookupFunction) { foreach (var (skin, lookupWrapper) in skinSources) { @@ -111,11 +107,11 @@ namespace osu.Game.Skinning } } - public Drawable GetDrawableComponent(ISkinComponent component) + public Drawable? GetDrawableComponent(ISkinComponent component) { foreach (var (_, lookupWrapper) in skinSources) { - Drawable sourceDrawable; + Drawable? sourceDrawable; if ((sourceDrawable = lookupWrapper.GetDrawableComponent(component)) != null) return sourceDrawable; } @@ -126,11 +122,11 @@ namespace osu.Game.Skinning return ParentSource?.GetDrawableComponent(component); } - public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) + public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) { foreach (var (_, lookupWrapper) in skinSources) { - Texture sourceTexture; + Texture? sourceTexture; if ((sourceTexture = lookupWrapper.GetTexture(componentName, wrapModeS, wrapModeT)) != null) return sourceTexture; } @@ -141,11 +137,11 @@ namespace osu.Game.Skinning return ParentSource?.GetTexture(componentName, wrapModeS, wrapModeT); } - public ISample GetSample(ISampleInfo sampleInfo) + public ISample? GetSample(ISampleInfo sampleInfo) { foreach (var (_, lookupWrapper) in skinSources) { - ISample sourceSample; + ISample? sourceSample; if ((sourceSample = lookupWrapper.GetSample(sampleInfo)) != null) return sourceSample; } @@ -156,11 +152,13 @@ namespace osu.Game.Skinning return ParentSource?.GetSample(sampleInfo); } - public IBindable GetConfig(TLookup lookup) + public IBindable? GetConfig(TLookup lookup) + where TLookup : notnull + where TValue : notnull { foreach (var (_, lookupWrapper) in skinSources) { - IBindable bindable; + IBindable? bindable; if ((bindable = lookupWrapper.GetConfig(lookup)) != null) return bindable; } @@ -240,7 +238,7 @@ namespace osu.Game.Skinning this.provider = provider; } - public Drawable GetDrawableComponent(ISkinComponent component) + public Drawable? GetDrawableComponent(ISkinComponent component) { if (provider.AllowDrawableLookup(component)) return skin.GetDrawableComponent(component); @@ -248,7 +246,7 @@ namespace osu.Game.Skinning return null; } - public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) + public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) { if (provider.AllowTextureLookup(componentName)) return skin.GetTexture(componentName, wrapModeS, wrapModeT); @@ -256,7 +254,7 @@ namespace osu.Game.Skinning return null; } - public ISample GetSample(ISampleInfo sampleInfo) + public ISample? GetSample(ISampleInfo sampleInfo) { if (provider.AllowSampleLookup(sampleInfo)) return skin.GetSample(sampleInfo); @@ -264,7 +262,9 @@ namespace osu.Game.Skinning return null; } - public IBindable GetConfig(TLookup lookup) + public IBindable? GetConfig(TLookup lookup) + where TLookup : notnull + where TValue : notnull { switch (lookup) { diff --git a/osu.Game/Skinning/SkinReloadableDrawable.cs b/osu.Game/Skinning/SkinReloadableDrawable.cs index c6332fc4d2..f1c8388f71 100644 --- a/osu.Game/Skinning/SkinReloadableDrawable.cs +++ b/osu.Game/Skinning/SkinReloadableDrawable.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. -#nullable disable - using System; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Pooling; namespace osu.Game.Skinning @@ -17,12 +16,12 @@ namespace osu.Game.Skinning /// /// Invoked when has changed. /// - public event Action OnSkinChanged; + public event Action? OnSkinChanged; /// /// The current skin source. /// - protected ISkinSource CurrentSkin { get; private set; } + protected ISkinSource CurrentSkin { get; private set; } = null!; [BackgroundDependencyLoader] private void load(ISkinSource source) @@ -60,7 +59,7 @@ namespace osu.Game.Skinning { base.Dispose(isDisposing); - if (CurrentSkin != null) + if (CurrentSkin.IsNotNull()) CurrentSkin.SourceChanged -= onChange; OnSkinChanged = null; diff --git a/osu.Game/Skinning/SkinUtils.cs b/osu.Game/Skinning/SkinUtils.cs index 8e01bd2853..75eae82401 100644 --- a/osu.Game/Skinning/SkinUtils.cs +++ b/osu.Game/Skinning/SkinUtils.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. -#nullable disable - using osu.Framework.Bindables; namespace osu.Game.Skinning @@ -18,6 +16,6 @@ namespace osu.Game.Skinning /// The value. /// The type of value , and the type of the resulting bindable. /// The resulting bindable. - public static Bindable As(object value) => (Bindable)value; + public static Bindable? As(object? value) => (Bindable?)value; } } diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 5a39121b16..f8130f31c3 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -27,13 +25,13 @@ namespace osu.Game.Skinning protected override bool ApplySizeRestrictionsToDefault => true; [Resolved] - private TextureStore textures { get; set; } + private TextureStore textures { get; set; } = null!; [SettingSource("Sprite name", "The filename of the sprite", SettingControlType = typeof(SpriteSelectorControl))] public Bindable SpriteName { get; } = new Bindable(string.Empty); [Resolved] - private ISkinSource source { get; set; } + private ISkinSource source { get; set; } = null!; public SkinnableSprite(string textureName, ConfineMode confineMode = ConfineMode.NoScaling) : base(new SpriteComponent(textureName), confineMode) @@ -88,15 +86,15 @@ namespace osu.Game.Skinning // but that requires further thought. var highestPrioritySkin = getHighestPriorityUserSkin(((SkinnableSprite)SettingSourceObject).source.AllSources) as Skin; - string[] availableFiles = highestPrioritySkin?.SkinInfo.PerformRead(s => s.Files - .Where(f => f.Filename.EndsWith(".png", StringComparison.Ordinal) - || f.Filename.EndsWith(".jpg", StringComparison.Ordinal)) - .Select(f => f.Filename).Distinct()).ToArray(); + string[]? availableFiles = highestPrioritySkin?.SkinInfo.PerformRead(s => s.Files + .Where(f => f.Filename.EndsWith(".png", StringComparison.Ordinal) + || f.Filename.EndsWith(".jpg", StringComparison.Ordinal)) + .Select(f => f.Filename).Distinct()).ToArray(); if (availableFiles?.Length > 0) Items = availableFiles; - static ISkin getHighestPriorityUserSkin(IEnumerable skins) + static ISkin? getHighestPriorityUserSkin(IEnumerable skins) { foreach (var skin in skins) { diff --git a/osu.Game/Skinning/SkinnableSpriteText.cs b/osu.Game/Skinning/SkinnableSpriteText.cs index 3e9462b83e..2bde3c4180 100644 --- a/osu.Game/Skinning/SkinnableSpriteText.cs +++ b/osu.Game/Skinning/SkinnableSpriteText.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. -#nullable disable - using System; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; diff --git a/osu.Game/Skinning/SkinnableTarget.cs b/osu.Game/Skinning/SkinnableTarget.cs index bca0d499f7..09de8a5d71 100644 --- a/osu.Game/Skinning/SkinnableTarget.cs +++ b/osu.Game/Skinning/SkinnableTarget.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. -#nullable disable - namespace osu.Game.Skinning { public enum SkinnableTarget diff --git a/osu.Game/Skinning/SkinnableTargetComponent.cs b/osu.Game/Skinning/SkinnableTargetComponent.cs index 51af1c23c9..a17aafe6e7 100644 --- a/osu.Game/Skinning/SkinnableTargetComponent.cs +++ b/osu.Game/Skinning/SkinnableTargetComponent.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. -#nullable disable - namespace osu.Game.Skinning { public class SkinnableTargetComponent : ISkinComponent diff --git a/osu.Game/Skinning/SkinnableTargetComponentsContainer.cs b/osu.Game/Skinning/SkinnableTargetComponentsContainer.cs index dd7290a858..e38afedeb9 100644 --- a/osu.Game/Skinning/SkinnableTargetComponentsContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetComponentsContainer.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. -#nullable disable - using System; using Newtonsoft.Json; using osu.Framework.Graphics; @@ -21,7 +19,7 @@ namespace osu.Game.Skinning public bool UsesFixedAnchor { get; set; } - private readonly Action applyDefaults; + private readonly Action? applyDefaults; /// /// Construct a wrapper with defaults that should be applied once. diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index 2faaa9a905..708ad4ec47 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.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. -#nullable disable - using System; using System.Linq; using System.Threading; @@ -13,7 +11,7 @@ namespace osu.Game.Skinning { public class SkinnableTargetContainer : SkinReloadableDrawable, ISkinnableTarget { - private SkinnableTargetComponentsContainer content; + private SkinnableTargetComponentsContainer? content; public SkinnableTarget Target { get; } @@ -25,7 +23,7 @@ namespace osu.Game.Skinning public bool ComponentsLoaded { get; private set; } - private CancellationTokenSource cancellationSource; + private CancellationTokenSource? cancellationSource; public SkinnableTargetContainer(SkinnableTarget target) { diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 2c70963524..d00874aa8f 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; @@ -47,9 +45,9 @@ namespace osu.Game.Skinning this.resources = resources; } - public override Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Textures?.Get(componentName, wrapModeS, wrapModeT); + public override Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Textures?.Get(componentName, wrapModeS, wrapModeT); - public override ISample GetSample(ISampleInfo sampleInfo) + public override ISample? GetSample(ISampleInfo sampleInfo) { foreach (string lookup in sampleInfo.LookupNames) { @@ -61,7 +59,7 @@ namespace osu.Game.Skinning return null; } - public override Drawable GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinComponent component) { if (base.GetDrawableComponent(component) is Drawable c) return c; @@ -171,7 +169,7 @@ namespace osu.Game.Skinning return null; } - public override IBindable GetConfig(TLookup lookup) + public override IBindable? GetConfig(TLookup lookup) { // todo: this code is pulled from LegacySkin and should not exist. // will likely change based on how databased storage of skin configuration goes. @@ -181,7 +179,7 @@ namespace osu.Game.Skinning switch (global) { case GlobalSkinColours.ComboColours: - return SkinUtils.As(new Bindable>(Configuration.ComboColours)); + return SkinUtils.As(new Bindable?>(Configuration.ComboColours)); } break; diff --git a/osu.Game/Skinning/UnsupportedSkinComponentException.cs b/osu.Game/Skinning/UnsupportedSkinComponentException.cs index 3713b7c200..7f0dd51d5b 100644 --- a/osu.Game/Skinning/UnsupportedSkinComponentException.cs +++ b/osu.Game/Skinning/UnsupportedSkinComponentException.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. -#nullable disable - using System; namespace osu.Game.Skinning From d4251271d87b1244ac31a5ac04f75db669d739c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 13:50:39 +0900 Subject: [PATCH 2154/2686] Apply nullability to `SkinnableDrawable` --- osu.Game/Skinning/SkinnableDrawable.cs | 44 ++++++++++++-------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs index 480d66c557..c6321553c7 100644 --- a/osu.Game/Skinning/SkinnableDrawable.cs +++ b/osu.Game/Skinning/SkinnableDrawable.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. -#nullable disable - using System; using osu.Framework.Caching; using osu.Framework.Graphics; @@ -19,7 +17,7 @@ namespace osu.Game.Skinning /// /// The displayed component. /// - public Drawable Drawable { get; private set; } + public Drawable Drawable { get; private set; } = null!; /// /// Whether the drawable component should be centered in available space. @@ -43,7 +41,7 @@ namespace osu.Game.Skinning /// The namespace-complete resource name for this skinnable element. /// A function to create the default skin implementation of this element. /// How (if at all) the should be resize to fit within our own bounds. - public SkinnableDrawable(ISkinComponent component, Func defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) + public SkinnableDrawable(ISkinComponent component, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) : this(component, confineMode) { createDefault = defaultImplementation; @@ -62,7 +60,7 @@ namespace osu.Game.Skinning /// public void ResetAnimation() => (Drawable as IFramedAnimation)?.GotoFrame(0); - private readonly Func createDefault; + private readonly Func? createDefault; private readonly Cached scaling = new Cached(); @@ -77,30 +75,28 @@ namespace osu.Game.Skinning protected override void SkinChanged(ISkinSource skin) { - Drawable = skin.GetDrawableComponent(Component); + var retrieved = skin.GetDrawableComponent(Component); - isDefault = false; - - if (Drawable == null) + if (retrieved == null) { Drawable = CreateDefault(Component); isDefault = true; } - - if (Drawable != null) - { - scaling.Invalidate(); - - if (CentreComponent) - { - Drawable.Origin = Anchor.Centre; - Drawable.Anchor = Anchor.Centre; - } - - InternalChild = Drawable; - } else - ClearInternal(); + { + Drawable = retrieved; + isDefault = false; + } + + scaling.Invalidate(); + + if (CentreComponent) + { + Drawable.Origin = Anchor.Centre; + Drawable.Anchor = Anchor.Centre; + } + + InternalChild = Drawable; } protected override void Update() @@ -111,7 +107,7 @@ namespace osu.Game.Skinning { try { - if (Drawable == null || (isDefault && !ApplySizeRestrictionsToDefault)) return; + if (isDefault && !ApplySizeRestrictionsToDefault) return; switch (confineMode) { From 4457648b1cc45d0752b26730edff24e4b1829d02 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 17:42:33 +0900 Subject: [PATCH 2155/2686] Fix editor playing too many sounds when user performs a manual seek during playback --- osu.Game/Screens/Edit/Editor.cs | 48 +++++++++++++++------------------ 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index df3c1f7ec4..d7406e6289 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -234,7 +234,7 @@ namespace osu.Game.Screens.Edit AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, loadableBeatmap.GetSkin(), loadableBeatmap.BeatmapInfo)); dependencies.CacheAs(editorBeatmap); - editorBeatmap.UpdateInProgress.BindValueChanged(updateInProgress); + editorBeatmap.UpdateInProgress.BindValueChanged(_ => updateSampleDisabledState()); canSave = editorBeatmap.BeatmapInfo.Ruleset.CreateInstance() is ILegacyRuleset; @@ -659,7 +659,7 @@ namespace osu.Game.Screens.Edit if (isNewBeatmap || HasUnsavedChanges) { - samplePlaybackDisabled.Value = true; + updateSampleDisabledState(); dialogOverlay?.Push(new PromptForSaveDialog(confirmExit, confirmExitWithSave, cancelExit)); return true; } @@ -729,27 +729,6 @@ namespace osu.Game.Screens.Edit this.Exit(); } - #region Mute from update application - - private ScheduledDelegate temporaryMuteRestorationDelegate; - private bool temporaryMuteFromUpdateInProgress; - - private void updateInProgress(ValueChangedEvent obj) - { - temporaryMuteFromUpdateInProgress = true; - updateSampleDisabledState(); - - // Debounce is arbitrarily high enough to avoid flip-flopping the value each other frame. - temporaryMuteRestorationDelegate?.Cancel(); - temporaryMuteRestorationDelegate = Scheduler.AddDelayed(() => - { - temporaryMuteFromUpdateInProgress = false; - updateSampleDisabledState(); - }, 50); - } - - #endregion - #region Clipboard support private EditorMenuItem cutMenuItem; @@ -883,11 +862,28 @@ namespace osu.Game.Screens.Edit } } + [CanBeNull] + private ScheduledDelegate playbackDisabledDebounce; + private void updateSampleDisabledState() { - samplePlaybackDisabled.Value = clock.SeekingOrStopped.Value - || currentScreen is not ComposeScreen - || temporaryMuteFromUpdateInProgress; + bool shouldDisableSamples = clock.SeekingOrStopped.Value + || currentScreen is not ComposeScreen + || editorBeatmap.UpdateInProgress.Value + || dialogOverlay?.CurrentDialog != null; + + playbackDisabledDebounce?.Cancel(); + + if (shouldDisableSamples) + { + samplePlaybackDisabled.Value = true; + } + else + { + // Debounce re-enabling arbitrarily high enough to avoid flip-flopping during beatmap updates + // or rapid user seeks. + playbackDisabledDebounce = Scheduler.AddDelayed(() => samplePlaybackDisabled.Value = false, 50); + } } private void seek(UIEvent e, int direction) From ab458320c46b461de0a43c50cb8d3f654e3f9b42 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 16:45:06 +0900 Subject: [PATCH 2156/2686] Fix some lingering inspections --- .../TestSceneCatchSkinConfiguration.cs | 2 +- osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs | 2 +- .../Objects/Drawables/DrawableOsuJudgement.cs | 2 +- osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 2 +- osu.Game.Tests/Skins/LegacySkinDecoderTest.cs | 4 ++-- osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs | 3 ++- osu.Game/Skinning/PoolableSkinnableSample.cs | 3 ++- 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs index a4b2b26624..a2d4e7fb1e 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs @@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Catch.Tests public bool FlipCatcherPlate { get; set; } public TestSkin() - : base(null) + : base(null!) { } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs index 57734236da..20aed514db 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Tests hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); - Child = new SkinProvidingContainer(new TrianglesSkin(null)) + Child = new SkinProvidingContainer(new TrianglesSkin(null!)) { RelativeSizeAxes = Axes.Both, Child = drawableHitCircle = new DrawableHitCircle(hitCircle) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index e137a503a5..b4abdde911 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Lighting.Alpha = 0; - if (hitLightingEnabled && Lighting.Drawable != null) + if (hitLightingEnabled) { // todo: this animation changes slightly based on new/old legacy skin versions. Lighting.ScaleTo(0.8f).ScaleTo(1.2f, 600, Easing.Out); diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index fdd0167ed3..c6bdd25e8b 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -308,7 +308,7 @@ namespace osu.Game.Tests.Beatmaps.Formats new Color4(255, 177, 140, 255), new Color4(100, 100, 100, 255), // alpha is specified as 100, but should be ignored. }; - Assert.AreEqual(expectedColors.Length, comboColors.Count); + Assert.AreEqual(expectedColors.Length, comboColors?.Count); for (int i = 0; i < expectedColors.Length; i++) Assert.AreEqual(expectedColors[i], comboColors[i]); } diff --git a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs index 6756f27ecd..9466fdf888 100644 --- a/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs +++ b/osu.Game.Tests/Skins/LegacySkinDecoderTest.cs @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Skins new Color4(100, 100, 100, 255), // alpha is specified as 100, but should be ignored. }; - Assert.AreEqual(expectedColors.Count, comboColors.Count); + Assert.AreEqual(expectedColors.Count, comboColors?.Count); for (int i = 0; i < expectedColors.Count; i++) Assert.AreEqual(expectedColors[i], comboColors[i]); } @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Skins var comboColors = decoder.Decode(stream).ComboColours; var expectedColors = SkinConfiguration.DefaultComboColours; - Assert.AreEqual(expectedColors.Count, comboColors.Count); + Assert.AreEqual(expectedColors.Count, comboColors?.Count); for (int i = 0; i < expectedColors.Count; i++) Assert.AreEqual(expectedColors[i], comboColors[i]); } diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index b0c26f7280..3f62bd038f 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -146,7 +146,8 @@ namespace osu.Game.Tests.Skins AddStep("Disallow default colours fallback in beatmap skin", () => beatmapSource.Configuration.AllowDefaultComboColoursFallback = false); AddAssert("Check retrieved combo colours from user skin", () => - requester.GetConfig>(GlobalSkinColours.ComboColours)?.Value?.SequenceEqual(userSource.Configuration.ComboColours) ?? false); + userSource.Configuration.ComboColours != null && + (requester.GetConfig>(GlobalSkinColours.ComboColours)?.Value?.SequenceEqual(userSource.Configuration.ComboColours) ?? false)); } [Test] diff --git a/osu.Game/Skinning/PoolableSkinnableSample.cs b/osu.Game/Skinning/PoolableSkinnableSample.cs index 49bc71064c..d0a22f9656 100644 --- a/osu.Game/Skinning/PoolableSkinnableSample.cs +++ b/osu.Game/Skinning/PoolableSkinnableSample.cs @@ -9,6 +9,7 @@ using JetBrains.Annotations; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Audio; using osu.Framework.Graphics.Containers; @@ -175,7 +176,7 @@ namespace osu.Game.Skinning { base.Dispose(isDisposing); - if (CurrentSkin != null) + if (CurrentSkin.IsNotNull()) CurrentSkin.SourceChanged -= skinChangedImmediate; } From c908969d9b78f36538dc0cd2a788dfa311fc6c50 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 14:11:41 +0900 Subject: [PATCH 2157/2686] Rename `ISkinComponent` to `ISkinLookup` --- ...tchSkinComponent.cs => CatchSkinLookup.cs} | 4 ++-- .../Objects/Drawables/CaughtObject.cs | 4 ++-- .../Objects/Drawables/DrawableBanana.cs | 2 +- .../Objects/Drawables/DrawableDroplet.cs | 2 +- .../Objects/Drawables/DrawableFruit.cs | 2 +- .../Argon/CatchArgonSkinTransformer.cs | 8 +++---- .../Legacy/CatchLegacySkinTransformer.cs | 14 ++++++------ .../UI/CatchComboDisplay.cs | 2 +- osu.Game.Rulesets.Catch/UI/HitExplosion.cs | 2 +- .../UI/SkinnableCatcher.cs | 2 +- .../Skinning/TestSceneColumnBackground.cs | 4 ++-- .../Skinning/TestSceneStageBackground.cs | 2 +- .../Skinning/TestSceneStageForeground.cs | 2 +- ...niaSkinComponent.cs => ManiaSkinLookup.cs} | 6 ++--- .../Objects/Drawables/DrawableHoldNote.cs | 2 +- .../Objects/Drawables/DrawableNote.cs | 2 +- .../Argon/ManiaArgonSkinTransformer.cs | 10 ++++----- .../Legacy/ManiaLegacySkinTransformer.cs | 12 +++++----- osu.Game.Rulesets.Mania/UI/Column.cs | 4 ++-- .../UI/Components/ColumnHitObjectArea.cs | 2 +- .../UI/PoolableHitExplosion.cs | 2 +- osu.Game.Rulesets.Mania/UI/Stage.cs | 4 ++-- .../TestSceneCursorTrail.cs | 2 +- .../TestSceneGameplayCursor.cs | 2 +- .../TestSceneSkinFallbacks.cs | 4 ++-- .../Drawables/Connections/FollowPoint.cs | 2 +- .../Objects/Drawables/DrawableHitCircle.cs | 8 +++---- .../Objects/Drawables/DrawableSlider.cs | 2 +- .../Objects/Drawables/DrawableSliderBall.cs | 4 ++-- .../Objects/Drawables/DrawableSliderRepeat.cs | 2 +- .../Objects/Drawables/DrawableSliderTail.cs | 2 +- .../Objects/Drawables/DrawableSliderTick.cs | 2 +- .../Objects/Drawables/DrawableSpinner.cs | 2 +- .../{OsuSkinComponent.cs => OsuSkinLookup.cs} | 4 ++-- .../Skinning/Argon/OsuArgonSkinTransformer.cs | 10 ++++----- .../Skinning/Default/DefaultApproachCircle.cs | 4 ++-- .../Skinning/Default/NumberPiece.cs | 2 +- .../Skinning/Default/ReverseArrowPiece.cs | 2 +- .../Skinning/Legacy/LegacyApproachCircle.cs | 4 ++-- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 2 +- .../Skinning/Legacy/LegacyReverseArrow.cs | 2 +- .../Legacy/OsuLegacySkinTransformer.cs | 12 +++++----- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs | 2 +- .../UI/Cursor/OsuCursorContainer.cs | 4 ++-- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 6 ++--- .../Skinning/TestSceneTaikoScroller.cs | 2 +- .../Objects/Drawables/DrawableBarLine.cs | 2 +- .../Objects/Drawables/DrawableDrumRoll.cs | 2 +- .../Objects/Drawables/DrawableDrumRollTick.cs | 2 +- .../Objects/Drawables/DrawableHit.cs | 4 ++-- .../Objects/Drawables/DrawableSwell.cs | 2 +- .../Objects/Drawables/DrawableSwellTick.cs | 2 +- .../Legacy/TaikoLegacySkinTransformer.cs | 10 ++++----- ...ikoSkinComponent.cs => TaikoSkinLookup.cs} | 4 ++-- .../UI/DrawableTaikoRuleset.cs | 2 +- osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 2 +- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 2 +- .../UI/KiaiHitExplosion.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 8 +++---- .../TestSceneHitObjectAccentColour.cs | 2 +- .../Skinning/LegacySkinAnimationTest.cs | 2 +- .../TestSceneRulesetSkinProvidingContainer.cs | 2 +- .../TestSceneBeatmapSkinLookupDisables.cs | 12 +++++----- .../Skins/TestSceneSkinConfigurationLookup.cs | 2 +- .../Skins/TestSceneSkinProvidingContainer.cs | 2 +- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 2 +- .../Gameplay/TestSceneSkinnableDrawable.cs | 22 +++++++++---------- .../Gameplay/TestSceneSkinnableSound.cs | 2 +- .../Rulesets/Judgements/DrawableJudgement.cs | 2 +- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 2 +- osu.Game/Skinning/ArgonSkin.cs | 12 +++++----- .../Skinning/BeatmapSkinProvidingContainer.cs | 2 +- ...SkinComponent.cs => GameplaySkinLookup.cs} | 4 ++-- osu.Game/Skinning/ISkin.cs | 4 ++-- osu.Game/Skinning/ISkinComponent.cs | 10 --------- osu.Game/Skinning/ISkinLookup.cs | 21 ++++++++++++++++++ osu.Game/Skinning/LegacyBeatmapSkin.cs | 6 ++--- osu.Game/Skinning/LegacySkin.cs | 12 +++++----- osu.Game/Skinning/ResourceStoreBackedSkin.cs | 2 +- osu.Game/Skinning/Skin.cs | 6 ++--- osu.Game/Skinning/SkinManager.cs | 2 +- osu.Game/Skinning/SkinProvidingContainer.cs | 14 ++++++------ osu.Game/Skinning/SkinTransformer.cs | 2 +- osu.Game/Skinning/SkinnableDrawable.cs | 20 ++++++++--------- osu.Game/Skinning/SkinnableSprite.cs | 16 +++++++------- osu.Game/Skinning/SkinnableSpriteText.cs | 4 ++-- osu.Game/Skinning/SkinnableTargetContainer.cs | 2 +- ...tComponent.cs => SkinnableTargetLookup.cs} | 4 ++-- osu.Game/Skinning/TrianglesSkin.cs | 12 +++++----- .../UnsupportedSkinComponentException.cs | 4 ++-- 90 files changed, 224 insertions(+), 213 deletions(-) rename osu.Game.Rulesets.Catch/{CatchSkinComponent.cs => CatchSkinLookup.cs} (76%) rename osu.Game.Rulesets.Mania/{ManiaSkinComponent.cs => ManiaSkinLookup.cs} (79%) rename osu.Game.Rulesets.Osu/{OsuSkinComponent.cs => OsuSkinLookup.cs} (76%) rename osu.Game.Rulesets.Taiko/{TaikoSkinComponent.cs => TaikoSkinLookup.cs} (75%) rename osu.Game/Skinning/{GameplaySkinComponent.cs => GameplaySkinLookup.cs} (85%) delete mode 100644 osu.Game/Skinning/ISkinComponent.cs create mode 100644 osu.Game/Skinning/ISkinLookup.cs rename osu.Game/Skinning/{SkinnableTargetComponent.cs => SkinnableTargetLookup.cs} (73%) diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs b/osu.Game.Rulesets.Catch/CatchSkinLookup.cs similarity index 76% rename from osu.Game.Rulesets.Catch/CatchSkinComponent.cs rename to osu.Game.Rulesets.Catch/CatchSkinLookup.cs index 07c613d6ff..65bfc7ee30 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponent.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinLookup.cs @@ -5,9 +5,9 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch { - public class CatchSkinComponent : GameplaySkinComponent + public class CatchSkinLookup : GameplaySkinLookup { - public CatchSkinComponent(CatchSkinComponents component) + public CatchSkinLookup(CatchSkinComponents component) : base(component) { } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs index ddfbb34435..20d348fe3d 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs @@ -37,8 +37,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables public override bool RemoveWhenNotAlive => true; - protected CaughtObject(CatchSkinComponents skinComponent, Func defaultImplementation) - : base(new CatchSkinComponent(skinComponent), defaultImplementation) + protected CaughtObject(CatchSkinComponents skinComponent, Func defaultImplementation) + : base(new CatchSkinLookup(skinComponent), defaultImplementation) { Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs index b46a452bd0..a2b32ea9e4 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables private void load() { ScalingContainer.Child = new SkinnableDrawable( - new CatchSkinComponent(CatchSkinComponents.Banana), + new CatchSkinLookup(CatchSkinComponents.Banana), _ => new BananaPiece()); } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs index d367ad0a00..210a4495e4 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables private void load() { ScalingContainer.Child = new SkinnableDrawable( - new CatchSkinComponent(CatchSkinComponents.Droplet), + new CatchSkinLookup(CatchSkinComponents.Droplet), _ => new DropletPiece()); } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs index ce4c7e5aff..6359a5b35c 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables private void load() { ScalingContainer.Child = new SkinnableDrawable( - new CatchSkinComponent(CatchSkinComponents.Fruit), + new CatchSkinLookup(CatchSkinComponents.Fruit), _ => new FruitPiece()); } diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs index 8dae0a2b78..606cd339a9 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs @@ -13,11 +13,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - switch (component) + switch (lookup) { - case CatchSkinComponent catchComponent: + case CatchSkinLookup catchComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (catchComponent.Component) { @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon break; } - return base.GetDrawableComponent(component); + return base.GetDrawableComponent(lookup); } } } diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index ef83e67876..5fda40d8c0 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -25,14 +25,14 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - if (component is SkinnableTargetComponent targetComponent) + if (lookup is SkinnableTargetLookup targetComponent) { switch (targetComponent.Target) { case SkinnableTarget.MainHUDComponents: - var components = base.GetDrawableComponent(component) as SkinnableTargetComponentsContainer; + var components = base.GetDrawableComponent(lookup) as SkinnableTargetComponentsContainer; if (providesComboCounter && components != null) { @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy } } - if (component is CatchSkinComponent catchSkinComponent) + if (lookup is CatchSkinLookup catchSkinComponent) { switch (catchSkinComponent.Component) { @@ -95,11 +95,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy return null; default: - throw new UnsupportedSkinComponentException(component); + throw new UnsupportedSkinComponentException(lookup); } } - return base.GetDrawableComponent(component); + return base.GetDrawableComponent(lookup); } private bool hasOldStyleCatcherSprite() => @@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { case CatchSkinConfiguration.FlipCatcherPlate: // Don't flip catcher plate contents if the catcher is provided by this legacy skin. - if (GetDrawableComponent(new CatchSkinComponent(CatchSkinComponents.Catcher)) != null) + if (GetDrawableComponent(new CatchSkinLookup(CatchSkinComponents.Catcher)) != null) return (IBindable)new Bindable(); break; diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs index a5b7d8d0af..802e837746 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.UI private readonly IBindable showCombo = new BindableBool(true); public CatchComboDisplay() - : base(new CatchSkinComponent(CatchSkinComponents.CatchComboCounter), _ => Empty()) + : base(new CatchSkinLookup(CatchSkinComponents.CatchComboCounter), _ => Empty()) { } diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs index 1ea188d463..fb55864c49 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.UI Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; - InternalChild = skinnableExplosion = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) + InternalChild = skinnableExplosion = new SkinnableDrawable(new CatchSkinLookup(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) { CentreComponent = false, Anchor = Anchor.BottomCentre, diff --git a/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs b/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs index 25bbc814bf..2e07e39943 100644 --- a/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs +++ b/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.UI public readonly Bindable AnimationState = new Bindable(); public SkinnableCatcher() - : base(new CatchSkinComponent(CatchSkinComponents.Catcher), _ => new DefaultCatcher()) + : base(new CatchSkinLookup(CatchSkinComponents.Catcher), _ => new DefaultCatcher()) { Anchor = Anchor.TopCentre; // Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling. diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs index cd26e2a9de..8dc8e72479 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning { RelativeSizeAxes = Axes.Both, Width = 0.5f, - Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) + Child = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both } @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning { RelativeSizeAxes = Axes.Both, Width = 0.5f, - Child = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) + Child = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both } diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs index 0744d7e2e7..19ccf20870 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground), + SetContents(_ => new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground()) { Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs index 979c90c802..171d2951be 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(_ => new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground), _ => null) + SetContents(_ => new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.StageForeground), _ => null) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs b/osu.Game.Rulesets.Mania/ManiaSkinLookup.cs similarity index 79% rename from osu.Game.Rulesets.Mania/ManiaSkinComponent.cs rename to osu.Game.Rulesets.Mania/ManiaSkinLookup.cs index a074aab9da..6e6d00fee6 100644 --- a/osu.Game.Rulesets.Mania/ManiaSkinComponent.cs +++ b/osu.Game.Rulesets.Mania/ManiaSkinLookup.cs @@ -5,13 +5,13 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania { - public class ManiaSkinComponent : GameplaySkinComponent + public class ManiaSkinLookup : GameplaySkinLookup { /// - /// Creates a new . + /// Creates a new . /// /// The component. - public ManiaSkinComponent(ManiaSkinComponents component) + public ManiaSkinLookup(ManiaSkinComponents component) : base(component) { } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 14dbc432ff..5b003e3c19 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables headContainer = new Container { RelativeSizeAxes = Axes.Both } } }, - bodyPiece = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HoldNoteBody), _ => new DefaultBodyPiece + bodyPiece = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.HoldNoteBody), _ => new DefaultBodyPiece { RelativeSizeAxes = Axes.Both, }) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index 3c8b1b53b7..25347d3dfa 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { rulesetConfig?.BindWith(ManiaRulesetSetting.TimingBasedNoteColouring, configTimingBasedNoteColouring); - AddInternal(headPiece = new SkinnableDrawable(new ManiaSkinComponent(Component), _ => new DefaultNotePiece()) + AddInternal(headPiece = new SkinnableDrawable(new ManiaSkinLookup(Component), _ => new DefaultNotePiece()) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index ae313e0b91..cf9f9f36f0 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -22,14 +22,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon this.beatmap = (ManiaBeatmap)beatmap; } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - switch (component) + switch (lookup) { - case GameplaySkinComponent resultComponent: + case GameplaySkinLookup resultComponent: return new ArgonJudgementPiece(resultComponent.Component); - case ManiaSkinComponent maniaComponent: + case ManiaSkinLookup maniaComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (maniaComponent.Component) { @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon break; } - return base.GetDrawableComponent(component); + return base.GetDrawableComponent(lookup); } public override IBindable? GetConfig(TLookup lookup) diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index a07dbea368..5b7ccc7bb6 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -74,14 +74,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy }); } - public override Drawable GetDrawableComponent(ISkinComponent component) + public override Drawable GetDrawableComponent(ISkinLookup lookup) { - switch (component) + switch (lookup) { - case GameplaySkinComponent resultComponent: + case GameplaySkinLookup resultComponent: return getResult(resultComponent.Component); - case ManiaSkinComponent maniaComponent: + case ManiaSkinLookup maniaComponent: if (!isLegacySkin.Value || !hasKeyTexture.Value) return null; @@ -120,11 +120,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy return new LegacyStageForeground(); default: - throw new UnsupportedSkinComponentException(component); + throw new UnsupportedSkinComponentException(lookup); } } - return base.GetDrawableComponent(component); + return base.GetDrawableComponent(lookup); } private Drawable getResult(HitResult result) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 3d46bdaa7b..4eed75a90d 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Mania.UI skin.SourceChanged += onSourceChanged; onSourceChanged(); - Drawable background = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) + Drawable background = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both, }; @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Mania.UI // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements background.CreateProxy(), HitObjectArea, - keyArea = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) + keyArea = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) { RelativeSizeAxes = Axes.Both, }, diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs index b26b62f8a5..d02e4afc81 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components RelativeSizeAxes = Axes.Both, Depth = 2, }, - hitTarget = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitTarget), _ => new DefaultHitTarget()) + hitTarget = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.HitTarget), _ => new DefaultHitTarget()) { RelativeSizeAxes = Axes.X, Depth = 1 diff --git a/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs b/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs index a7b94f9f22..faf345545d 100644 --- a/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.UI [BackgroundDependencyLoader] private void load() { - InternalChild = skinnableExplosion = new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) + InternalChild = skinnableExplosion = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index 1273cb3d32..5d08e38aef 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.UI AutoSizeAxes = Axes.X, Children = new Drawable[] { - new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground()) + new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground()) { RelativeSizeAxes = Axes.Both }, @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Mania.UI RelativeSizeAxes = Axes.Y, } }, - new SkinnableDrawable(new ManiaSkinComponent(ManiaSkinComponents.StageForeground), _ => null) + new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.StageForeground), _ => null) { RelativeSizeAxes = Axes.Both }, diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs index d3e70a0a01..aeadbea510 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.Tests RelativeSizeAxes = Axes.Both; } - public Drawable GetDrawableComponent(ISkinComponent component) => null; + public Drawable GetDrawableComponent(ISkinLookup lookup) => null; public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs index 360815afbf..f88948ce13 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Osu.Tests private class TopLeftCursorSkin : ISkin { - public Drawable GetDrawableComponent(ISkinComponent component) => null; + public Drawable GetDrawableComponent(ISkinLookup lookup) => null; public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null; public ISample GetSample(ISampleInfo sampleInfo) => null; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs index 036f90b962..c012dae635 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs @@ -149,11 +149,11 @@ namespace osu.Game.Rulesets.Osu.Tests this.identifier = identifier; } - public Drawable GetDrawableComponent(ISkinComponent component) + public Drawable GetDrawableComponent(ISkinLookup lookup) { if (!enabled) return null; - if (component is OsuSkinComponent osuComponent && osuComponent.Component == OsuSkinComponents.SliderBody) + if (lookup is OsuSkinLookup osuComponent && osuComponent.Component == OsuSkinComponents.SliderBody) return null; return new OsuSpriteText diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs index 36d8ba0189..22037c873c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections { Origin = Anchor.Centre; - InternalChild = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.FollowPoint), _ => new CircularContainer + InternalChild = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.FollowPoint), _ => new CircularContainer { Masking = true, AutoSizeAxes = Axes.Both, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index d420091499..bcb3ccae41 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -81,12 +81,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - CirclePiece = new SkinnableDrawable(new OsuSkinComponent(CirclePieceComponent), _ => new MainCirclePiece()) + CirclePiece = new SkinnableDrawable(new OsuSkinLookup(CirclePieceComponent), _ => new MainCirclePiece()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - ApproachCircle = new ProxyableSkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ApproachCircle), _ => new DefaultApproachCircle()) + ApproachCircle = new ProxyableSkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.ApproachCircle), _ => new DefaultApproachCircle()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -278,8 +278,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { public override bool RemoveWhenNotAlive => false; - public ProxyableSkinnableDrawable(ISkinComponent component, Func defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) - : base(component, defaultImplementation, confineMode) + public ProxyableSkinnableDrawable(ISkinLookup lookup, Func defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) + : base(lookup, defaultImplementation, confineMode) { } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 785d15c15b..3fdbc3dacd 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - Body = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBody), _ => new DefaultSliderBody(), confineMode: ConfineMode.NoScaling), + Body = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderBody), _ => new DefaultSliderBody(), confineMode: ConfineMode.NoScaling), tailContainer = new Container { RelativeSizeAxes = Axes.Both }, tickContainer = new Container { RelativeSizeAxes = Axes.Both }, repeatContainer = new Container { RelativeSizeAxes = Axes.Both }, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs index 9966ad3a90..86d41f0cbf 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Children = new[] { - new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderFollowCircle), _ => new DefaultFollowCircle()) + new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderFollowCircle), _ => new DefaultFollowCircle()) { Origin = Anchor.Centre, Anchor = Anchor.Centre, @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables RelativeSizeAxes = Axes.Both, Masking = true }, - ball = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBall), _ => new DefaultSliderBall()) + ball = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderBall), _ => new DefaultSliderBall()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index a02cc9227e..1b8a17b6df 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Children = new Drawable[] { // no default for this; only visible in legacy skins. - CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) + CirclePiece = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index 6270d6709b..e8c6e80109 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Children = new Drawable[] { // no default for this; only visible in legacy skins. - CirclePiece = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) + CirclePiece = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) } }, }); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs index 4bd98fc8b2..f591cd15d4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Origin = Anchor.Centre; - AddInternal(scaleContainer = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderScorePoint), _ => new CircularContainer + AddInternal(scaleContainer = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderScorePoint), _ => new CircularContainer { Masking = true, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 6ae9d5bc34..7d0e29bd93 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables RelativeSizeAxes = Axes.Y, Children = new Drawable[] { - Body = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SpinnerBody), _ => new DefaultSpinner()), + Body = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SpinnerBody), _ => new DefaultSpinner()), RotationTracker = new SpinnerRotationTracker(this) } }, diff --git a/osu.Game.Rulesets.Osu/OsuSkinComponent.cs b/osu.Game.Rulesets.Osu/OsuSkinLookup.cs similarity index 76% rename from osu.Game.Rulesets.Osu/OsuSkinComponent.cs rename to osu.Game.Rulesets.Osu/OsuSkinLookup.cs index aa59bd572e..4048e95e4b 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinComponent.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinLookup.cs @@ -5,9 +5,9 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu { - public class OsuSkinComponent : GameplaySkinComponent + public class OsuSkinLookup : GameplaySkinLookup { - public OsuSkinComponent(OsuSkinComponents component) + public OsuSkinLookup(OsuSkinComponents component) : base(component) { } diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index bf507db50c..bf664bb606 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -14,14 +14,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - switch (component) + switch (lookup) { - case GameplaySkinComponent resultComponent: + case GameplaySkinLookup resultComponent: return new ArgonJudgementPiece(resultComponent.Component); - case OsuSkinComponent osuComponent: + case OsuSkinLookup osuComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (osuComponent.Component) { @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon break; } - return base.GetDrawableComponent(component); + return base.GetDrawableComponent(lookup); } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs index e991bc6cf3..2b2c31dcf7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs @@ -35,9 +35,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default accentColour.BindValueChanged(colour => Colour = colour.NewValue, true); } - protected override Drawable CreateDefault(ISkinComponent component) + protected override Drawable CreateDefault(ISkinLookup lookup) { - var drawable = base.CreateDefault(component); + var drawable = base.CreateDefault(lookup); // Although this is a non-legacy component, osu-resources currently stores approach circle as a legacy-like texture. // See LegacyApproachCircle for documentation as to why this is required. diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs index 43d8d1e27f..39e07ebb99 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default Colour = Color4.White.Opacity(0.5f), }, }, - number = new SkinnableSpriteText(new OsuSkinComponent(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText + number = new SkinnableSpriteText(new OsuSkinLookup(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText { Font = OsuFont.Numeric.With(size: 40), UseFullGlyphHeight = false, diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs index 1fce512f53..338e7abcfc 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); - Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon + Child = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon { RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs index fa5c5b84e4..20a1e3064e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs @@ -35,9 +35,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy accentColour.BindValueChanged(colour => Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true); } - protected override Drawable CreateDefault(ISkinComponent component) + protected override Drawable CreateDefault(ISkinLookup lookup) { - var drawable = base.CreateDefault(component); + var drawable = base.CreateDefault(lookup); // account for the sprite being used for the default approach circle being taken from stable, // when hitcircles have 5px padding on each size. this should be removed if we update the sprite. diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index a6e62b83e4..357be4cda8 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (hasNumber) { - OverlayLayer.Add(hitCircleText = new SkinnableSpriteText(new OsuSkinComponent(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText + OverlayLayer.Add(hitCircleText = new SkinnableSpriteText(new OsuSkinLookup(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText { Font = OsuFont.Numeric.With(size: 40), UseFullGlyphHeight = false, diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 7e9626eb7f..f374af1cba 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { AutoSizeAxes = Axes.Both; - string lookupName = new OsuSkinComponent(OsuSkinComponents.ReverseArrow).LookupName; + string lookupName = new OsuSkinLookup(OsuSkinComponents.ReverseArrow).LookupName; var skin = skinSource.FindProvider(s => s.GetTexture(lookupName) != null); InternalChild = skin?.GetAnimation(lookupName, true, true) ?? Empty(); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 3bc2668733..2faa2d678e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -28,17 +28,17 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy hasHitCircle = new Lazy(() => GetTexture("hitcircle") != null); } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - if (component is OsuSkinComponent osuComponent) + if (lookup is OsuSkinLookup osuComponent) { switch (osuComponent.Component) { case OsuSkinComponents.FollowPoint: - return this.GetAnimation(component.LookupName, true, true, true, startAtCurrentTime: false); + return this.GetAnimation(lookup.LookupName, true, true, true, startAtCurrentTime: false); case OsuSkinComponents.SliderScorePoint: - return this.GetAnimation(component.LookupName, false, false); + return this.GetAnimation(lookup.LookupName, false, false); case OsuSkinComponents.SliderFollowCircle: var followCircleContent = this.GetAnimation("sliderfollowcircle", true, true, true); @@ -136,11 +136,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return new LegacyApproachCircle(); default: - throw new UnsupportedSkinComponentException(component); + throw new UnsupportedSkinComponentException(lookup); } } - return base.GetDrawableComponent(component); + return base.GetDrawableComponent(lookup); } public override IBindable? GetConfig(TLookup lookup) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs index 15ef7e538b..78b920c771 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = cursorSprite = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling) + Child = cursorSprite = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling) { Origin = Anchor.Centre, Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 533db3ddfe..396492c104 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -47,8 +47,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor RelativeSizeAxes = Axes.Both, Children = new[] { - cursorTrail = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling), - new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorParticles), confineMode: ConfineMode.NoScaling), + cursorTrail = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling), + new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.CursorParticles), confineMode: ConfineMode.NoScaling), } }; } diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index beba834e88..2616bb0325 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.UI { if (e.Action == OsuAction.Smoke) { - AddInternal(currentSegmentSkinnable = new SmokeSkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.CursorSmoke), _ => new DefaultSmokeSegment())); + AddInternal(currentSegmentSkinnable = new SmokeSkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.CursorSmoke), _ => new DefaultSmokeSegment())); // Add initial position immediately. addPosition(); @@ -68,8 +68,8 @@ namespace osu.Game.Rulesets.Osu.UI public override double LifetimeStart => Drawable.LifetimeStart; public override double LifetimeEnd => Drawable.LifetimeEnd; - public SmokeSkinnableDrawable(ISkinComponent component, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) - : base(component, defaultImplementation, confineMode) + public SmokeSkinnableDrawable(ISkinLookup lookup, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) + : base(lookup, defaultImplementation, confineMode) { } } diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs index 954b4be7f3..3076172d46 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning public TestSceneTaikoScroller() { AddStep("Load scroller", () => SetContents(_ => - new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Scroller), _ => Empty()) + new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.Scroller), _ => Empty()) { Clock = new FramedClock(clock), Height = 0.4f, diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs index e4806c4a12..715add7914 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables AddRangeInternal(new Drawable[] { - line = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.BarLine), _ => new Box + line = new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.BarLine), _ => new Box { RelativeSizeAxes = Axes.Both, EdgeSmoothness = new Vector2(0.5f, 0), diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 98dad96cf6..f5ebecdee5 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return base.CreateNestedHitObject(hitObject); } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollBody), + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.DrumRollBody), _ => new ElongatedCirclePiece()); public override bool OnPressed(KeyBindingPressEvent e) => false; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index 451c5a793b..1ec2562f67 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables FillMode = FillMode.Fit; } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollTick), + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.DrumRollTick), _ => new TickPiece { Filled = HitObject.FirstTick diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 484f125a09..0fe17f81f5 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -90,8 +90,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } protected override SkinnableDrawable CreateMainPiece() => HitObject.Type == HitType.Centre - ? new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.CentreHit), _ => new CentreHitCirclePiece(), confineMode: ConfineMode.ScaleToFit) - : new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.RimHit), _ => new RimHitCirclePiece(), confineMode: ConfineMode.ScaleToFit); + ? new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.CentreHit), _ => new CentreHitCirclePiece(), confineMode: ConfineMode.ScaleToFit) + : new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.RimHit), _ => new RimHitCirclePiece(), confineMode: ConfineMode.ScaleToFit); public override IEnumerable GetSamples() { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index a6f6edba09..5b498e4cb3 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Swell), + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.Swell), _ => new SwellCirclePiece { // to allow for rotation transform diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index b2a54176fb..4d915c91d3 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public override bool OnPressed(KeyBindingPressEvent e) => false; - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.DrumRollTick), + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.DrumRollTick), _ => new TickPiece()); } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 020cdab4dc..6cf7d3da0a 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -27,16 +27,16 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy hasExplosion = new Lazy(() => GetTexture(getHitName(TaikoSkinComponents.TaikoExplosionGreat)) != null); } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - if (component is GameplaySkinComponent) + if (lookup is GameplaySkinLookup) { // if a taiko skin is providing explosion sprites, hide the judgements completely if (hasExplosion.Value) return Drawable.Empty().With(d => d.Expire()); } - if (component is TaikoSkinComponent taikoComponent) + if (lookup is TaikoSkinLookup taikoComponent) { switch (taikoComponent.Component) { @@ -130,11 +130,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy return new DrawableTaikoMascot(); default: - throw new UnsupportedSkinComponentException(component); + throw new UnsupportedSkinComponentException(lookup); } } - return base.GetDrawableComponent(component); + return base.GetDrawableComponent(lookup); } private string getHitName(TaikoSkinComponents component) diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs b/osu.Game.Rulesets.Taiko/TaikoSkinLookup.cs similarity index 75% rename from osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs rename to osu.Game.Rulesets.Taiko/TaikoSkinLookup.cs index 30bfb605aa..cb8bbd8b18 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponent.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinLookup.cs @@ -5,9 +5,9 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko { - public class TaikoSkinComponent : GameplaySkinComponent + public class TaikoSkinLookup : GameplaySkinLookup { - public TaikoSkinComponent(TaikoSkinComponents component) + public TaikoSkinLookup(TaikoSkinComponents component) : base(component) { } diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 58e703b8be..db45c8bb70 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Taiko.UI { new BarLineGenerator(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar)); - FrameStableComponents.Add(scroller = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Scroller), _ => Empty()) + FrameStableComponents.Add(scroller = new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.Scroller), _ => Empty()) { RelativeSizeAxes = Axes.X, Depth = float.MaxValue diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 10a7495c62..560f7b1748 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load() { - InternalChild = skinnable = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(result)), _ => new DefaultHitExplosion(result)); + InternalChild = skinnable = new SkinnableDrawable(new TaikoSkinLookup(getComponentName(result)), _ => new DefaultHitExplosion(result)); skinnable.OnSkinChanged += runAnimation; } diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 6d5b6c5f5d..4458fb1bc0 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.UI { Children = new Drawable[] { - new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.InputDrum), _ => new DefaultInputDrum()) + new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.InputDrum), _ => new DefaultInputDrum()) { RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index c4cff00d2a..b0d853f1f1 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load() { - Child = skinnable = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.TaikoExplosionKiai), _ => new DefaultKiaiHitExplosion(hitType)); + Child = skinnable = new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.TaikoExplosionKiai), _ => new DefaultKiaiHitExplosion(hitType)); } } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index f2d7811f44..0de7bf233d 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Taiko.UI InternalChildren = new[] { - new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.PlayfieldBackgroundRight), _ => new PlayfieldBackgroundRight()), + new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.PlayfieldBackgroundRight), _ => new PlayfieldBackgroundRight()), new Container { Name = "Left overlay", @@ -86,11 +86,11 @@ namespace osu.Game.Rulesets.Taiko.UI BorderColour = colours.Gray0, Children = new[] { - new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.PlayfieldBackgroundLeft), _ => new PlayfieldBackgroundLeft()), + new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.PlayfieldBackgroundLeft), _ => new PlayfieldBackgroundLeft()), inputDrum.CreateProxy(), } }, - mascot = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.Mascot), _ => Empty()) + mascot = new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.Mascot), _ => Empty()) { Origin = Anchor.BottomLeft, Anchor = Anchor.TopLeft, @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Taiko.UI { RelativeSizeAxes = Axes.Both, }, - HitTarget = new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.HitTarget), _ => new TaikoHitTarget()) + HitTarget = new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.HitTarget), _ => new TaikoHitTarget()) { RelativeSizeAxes = Axes.Both, } diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs index 9701a32951..fc72fddcae 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -126,7 +126,7 @@ namespace osu.Game.Tests.Gameplay Color4.Green }; - public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotImplementedException(); + public Drawable GetDrawableComponent(ISkinLookup lookup) => throw new NotImplementedException(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs index 6297d9cdc7..9e03663a49 100644 --- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs @@ -73,7 +73,7 @@ namespace osu.Game.Tests.NonVisual.Skinning return lookup_names.Contains(componentName) ? renderer.WhitePixel : null; } - public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException(); + public Drawable GetDrawableComponent(ISkinLookup lookup) => throw new NotSupportedException(); public ISample GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException(); public IBindable GetConfig(TLookup lookup) => throw new NotSupportedException(); } diff --git a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs index 320373699d..6f14b933ee 100644 --- a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs +++ b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs @@ -78,7 +78,7 @@ namespace osu.Game.Tests.Rulesets OnLoadAsync?.Invoke(); } - public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component); + public Drawable GetDrawableComponent(ISkinLookup lookup) => skin.GetDrawableComponent(lookup); public Texture GetTexture(string componentName, WrapMode wrapModeS = default, WrapMode wrapModeT = default) => skin.GetTexture(componentName); diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs index 004e253c1f..7c02d34b1c 100644 --- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs +++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Skins string expected = allowBeatmapLookups ? "beatmap" : "user"; - AddAssert($"Check lookup is from {expected}", () => requester.GetDrawableComponent(new TestSkinComponent())?.Name == expected); + AddAssert($"Check lookup is from {expected}", () => requester.GetDrawableComponent(new TestSkinLookup())?.Name == expected); } [TestCase(false)] @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Skins ISkin expected() => allowBeatmapLookups ? beatmapSource : userSource; - AddAssert("Check lookup is from correct source", () => requester.FindProvider(s => s.GetDrawableComponent(new TestSkinComponent()) != null) == expected()); + AddAssert("Check lookup is from correct source", () => requester.FindProvider(s => s.GetDrawableComponent(new TestSkinLookup()) != null) == expected()); } public class UserSkinSource : LegacySkin @@ -69,7 +69,7 @@ namespace osu.Game.Tests.Skins { } - public override Drawable GetDrawableComponent(ISkinComponent component) + public override Drawable GetDrawableComponent(ISkinLookup lookup) { return new Container { Name = "user" }; } @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Skins { } - public override Drawable GetDrawableComponent(ISkinComponent component) + public override Drawable GetDrawableComponent(ISkinLookup lookup) { return new Container { Name = "beatmap" }; } @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Skins this.skin = skin; } - public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component); + public Drawable GetDrawableComponent(ISkinLookup lookup) => skin.GetDrawableComponent(lookup); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT); @@ -109,7 +109,7 @@ namespace osu.Game.Tests.Skins public ISkin FindProvider(Func lookupFunction) => skin.FindProvider(lookupFunction); } - private class TestSkinComponent : ISkinComponent + private class TestSkinLookup : ISkinLookup { public string LookupName => string.Empty; } diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index 3f62bd038f..4cbc1cf4df 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -221,7 +221,7 @@ namespace osu.Game.Tests.Skins this.skin = skin; } - public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component); + public Drawable GetDrawableComponent(ISkinLookup lookup) => skin.GetDrawableComponent(lookup); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT); diff --git a/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs b/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs index f7c88643fe..712d5ce969 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Skins this.renderer = renderer; } - public Drawable GetDrawableComponent(ISkinComponent component) => throw new System.NotImplementedException(); + public Drawable GetDrawableComponent(ISkinLookup lookup) => throw new System.NotImplementedException(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 01cc856a4a..6fe6a85b8f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual.Gameplay var actualInfo = actualComponentsContainer.CreateSkinnableInfo(); - var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource.GetDrawableComponent(new SkinnableTargetComponent(target)); + var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource.GetDrawableComponent(new SkinnableTargetLookup(target)); if (expectedComponentsContainer == null) return false; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs index d4fba76c37..81c5211878 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs @@ -164,7 +164,7 @@ namespace osu.Game.Tests.Visual.Gameplay { private bool allow = true; - protected override bool AllowDrawableLookup(ISkinComponent component) => allow; + protected override bool AllowDrawableLookup(ISkinLookup lookup) => allow; public void Disable() { @@ -182,8 +182,8 @@ namespace osu.Game.Tests.Visual.Gameplay { public new Drawable Drawable => base.Drawable; - public ExposedSkinnableDrawable(string name, Func defaultImplementation, ConfineMode confineMode = ConfineMode.ScaleToFit) - : base(new TestSkinComponent(name), defaultImplementation, confineMode) + public ExposedSkinnableDrawable(string name, Func defaultImplementation, ConfineMode confineMode = ConfineMode.ScaleToFit) + : base(new TestSkinLookup(name), defaultImplementation, confineMode) { } } @@ -251,8 +251,8 @@ namespace osu.Game.Tests.Visual.Gameplay public new Drawable Drawable => base.Drawable; public int SkinChangedCount { get; private set; } - public SkinConsumer(string name, Func defaultImplementation) - : base(new TestSkinComponent(name), defaultImplementation) + public SkinConsumer(string name, Func defaultImplementation) + : base(new TestSkinLookup(name), defaultImplementation) { } @@ -288,8 +288,8 @@ namespace osu.Game.Tests.Visual.Gameplay this.size = size; } - public Drawable GetDrawableComponent(ISkinComponent componentName) => - componentName.LookupName == "available" + public Drawable GetDrawableComponent(ISkinLookup lookupName) => + lookupName.LookupName == "available" ? new DrawWidthBox { Colour = Color4.Yellow, @@ -306,7 +306,7 @@ namespace osu.Game.Tests.Visual.Gameplay private class SecondarySource : ISkin { - public Drawable GetDrawableComponent(ISkinComponent componentName) => new SecondarySourceBox(); + public Drawable GetDrawableComponent(ISkinLookup lookupName) => new SecondarySourceBox(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); @@ -318,7 +318,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached(typeof(ISkinSource))] private class SkinSourceContainer : Container, ISkinSource { - public Drawable GetDrawableComponent(ISkinComponent componentName) => new BaseSourceBox(); + public Drawable GetDrawableComponent(ISkinLookup lookupName) => new BaseSourceBox(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); @@ -337,9 +337,9 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class TestSkinComponent : ISkinComponent + private class TestSkinLookup : ISkinLookup { - public TestSkinComponent(string name) + public TestSkinLookup(string name) { LookupName = name; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs index 0ba112ec40..43206ac591 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs @@ -142,7 +142,7 @@ namespace osu.Game.Tests.Visual.Gameplay IBindable ISamplePlaybackDisabler.SamplePlaybackDisabled => SamplePlaybackDisabled; - public Drawable GetDrawableComponent(ISkinComponent component) => source?.GetDrawableComponent(component); + public Drawable GetDrawableComponent(ISkinLookup lookup) => source?.GetDrawableComponent(lookup); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => source?.GetTexture(componentName, wrapModeS, wrapModeT); public ISample GetSample(ISampleInfo sampleInfo) => source?.GetSample(sampleInfo); public IBindable GetConfig(TLookup lookup) => source?.GetConfig(lookup); diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 7e1196d4ca..bfcdd384a0 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -167,7 +167,7 @@ namespace osu.Game.Rulesets.Judgements if (JudgementBody != null) RemoveInternal(JudgementBody, true); - AddInternal(JudgementBody = new SkinnableDrawable(new GameplaySkinComponent(type), _ => + AddInternal(JudgementBody = new SkinnableDrawable(new GameplaySkinLookup(type), _ => CreateDefaultJudgement(type), confineMode: ConfineMode.NoScaling) { Anchor = Anchor.Centre, diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index a106a60379..bc63ad063c 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -53,7 +53,7 @@ namespace osu.Game.Screens.Edit #region Delegated ISkin implementation - public Drawable GetDrawableComponent(ISkinComponent component) => Skin.GetDrawableComponent(component); + public Drawable GetDrawableComponent(ISkinLookup lookup) => Skin.GetDrawableComponent(lookup); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Skin.GetTexture(componentName, wrapModeS, wrapModeT); public ISample GetSample(ISampleInfo sampleInfo) => Skin.GetSample(sampleInfo); public IBindable GetConfig(TLookup lookup) => Skin.GetConfig(lookup); diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 20e4290725..f65cee8a69 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -81,14 +81,14 @@ namespace osu.Game.Skinning return null; } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - if (base.GetDrawableComponent(component) is Drawable c) + if (base.GetDrawableComponent(lookup) is Drawable c) return c; - switch (component) + switch (lookup) { - case SkinnableTargetComponent target: + case SkinnableTargetLookup target: switch (target.Target) { case SkinnableTarget.SongSelect: @@ -178,14 +178,14 @@ namespace osu.Game.Skinning return null; } - switch (component.LookupName) + switch (lookup.LookupName) { // Temporary until default skin has a valid hit lighting. case @"lighting": return Drawable.Empty(); } - if (GetTexture(component.LookupName) is Texture t) + if (GetTexture(lookup.LookupName) is Texture t) return new Sprite { Texture = t }; return null; diff --git a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs index f0caef9fa1..ec9d52f5c6 100644 --- a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs +++ b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs @@ -43,7 +43,7 @@ namespace osu.Game.Skinning } } - protected override bool AllowDrawableLookup(ISkinComponent component) + protected override bool AllowDrawableLookup(ISkinLookup lookup) { if (beatmapSkins == null) throw new InvalidOperationException($"{nameof(BeatmapSkinProvidingContainer)} needs to be loaded before being consumed."); diff --git a/osu.Game/Skinning/GameplaySkinComponent.cs b/osu.Game/Skinning/GameplaySkinLookup.cs similarity index 85% rename from osu.Game/Skinning/GameplaySkinComponent.cs rename to osu.Game/Skinning/GameplaySkinLookup.cs index 6f5dad2207..cec9dbde7d 100644 --- a/osu.Game/Skinning/GameplaySkinComponent.cs +++ b/osu.Game/Skinning/GameplaySkinLookup.cs @@ -5,12 +5,12 @@ using System.Linq; namespace osu.Game.Skinning { - public class GameplaySkinComponent : ISkinComponent + public class GameplaySkinLookup : ISkinLookup where T : notnull { public readonly T Component; - public GameplaySkinComponent(T component) + public GameplaySkinLookup(T component) { Component = component; } diff --git a/osu.Game/Skinning/ISkin.cs b/osu.Game/Skinning/ISkin.cs index c093dc2f32..c352dfef5c 100644 --- a/osu.Game/Skinning/ISkin.cs +++ b/osu.Game/Skinning/ISkin.cs @@ -17,9 +17,9 @@ namespace osu.Game.Skinning /// /// Retrieve a component implementation. /// - /// The requested component. + /// The requested component. /// A drawable representation for the requested component, or null if unavailable. - Drawable? GetDrawableComponent(ISkinComponent component); + Drawable? GetDrawableComponent(ISkinLookup lookup); /// /// Retrieve a . diff --git a/osu.Game/Skinning/ISkinComponent.cs b/osu.Game/Skinning/ISkinComponent.cs deleted file mode 100644 index 4bd9f21b6b..0000000000 --- a/osu.Game/Skinning/ISkinComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -// 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.Skinning -{ - public interface ISkinComponent - { - string LookupName { get; } - } -} diff --git a/osu.Game/Skinning/ISkinLookup.cs b/osu.Game/Skinning/ISkinLookup.cs new file mode 100644 index 0000000000..4daea35e82 --- /dev/null +++ b/osu.Game/Skinning/ISkinLookup.cs @@ -0,0 +1,21 @@ +// 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.Skinning +{ + /// + /// A lookup type which can be used with . + /// + /// + /// Implementations of should match on types implementing this interface + /// to scope particular lookup variations. Using this, a ruleset or skin implementation could make its own lookup + /// type to scope away from more global contexts. + /// + /// More commonly, a ruleset could make use of to do a simple lookup based on + /// a provided enum. + /// + public interface ISkinLookup + { + string LookupName { get; } + } +} diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index e8414b4c11..2aa76b5871 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -43,9 +43,9 @@ namespace osu.Game.Skinning return new RealmBackedResourceStore(beatmapInfo.BeatmapSet.ToLive(resources.RealmAccess), resources.Files, resources.RealmAccess); } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - if (component is SkinnableTargetComponent targetComponent) + if (lookup is SkinnableTargetLookup targetComponent) { switch (targetComponent.Target) { @@ -59,7 +59,7 @@ namespace osu.Game.Skinning } } - return base.GetDrawableComponent(component); + return base.GetDrawableComponent(lookup); } public override IBindable? GetConfig(TLookup lookup) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index bfc60de2c9..97833d0e28 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -322,14 +322,14 @@ namespace osu.Game.Skinning return null; } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - if (base.GetDrawableComponent(component) is Drawable c) + if (base.GetDrawableComponent(lookup) is Drawable c) return c; - switch (component) + switch (lookup) { - case SkinnableTargetComponent target: + case SkinnableTargetLookup target: switch (target.Target) { case SkinnableTarget.MainHUDComponents: @@ -379,7 +379,7 @@ namespace osu.Game.Skinning return null; - case GameplaySkinComponent resultComponent: + case GameplaySkinLookup resultComponent: // kind of wasteful that we throw this away, but should do for now. if (getJudgementAnimation(resultComponent.Component) != null) @@ -397,7 +397,7 @@ namespace osu.Game.Skinning return null; - case SkinnableSprite.SpriteComponent sprite: + case SkinnableSprite.SpriteLookup sprite: return this.GetAnimation(sprite.LookupName, false, false); } diff --git a/osu.Game/Skinning/ResourceStoreBackedSkin.cs b/osu.Game/Skinning/ResourceStoreBackedSkin.cs index efdbb0a207..1b846438f5 100644 --- a/osu.Game/Skinning/ResourceStoreBackedSkin.cs +++ b/osu.Game/Skinning/ResourceStoreBackedSkin.cs @@ -27,7 +27,7 @@ namespace osu.Game.Skinning samples = audio.GetSampleStore(new NamespacedResourceStore(resources, @"Samples")); } - public Drawable? GetDrawableComponent(ISkinComponent component) => null; + public Drawable? GetDrawableComponent(ISkinLookup lookup) => null; public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => textures.Get(componentName, wrapModeS, wrapModeT); diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index dd43e4dc54..a14b1e1359 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -154,11 +154,11 @@ namespace osu.Game.Skinning DrawableComponentInfo[targetContainer.Target] = targetContainer.CreateSkinnableInfo().ToArray(); } - public virtual Drawable? GetDrawableComponent(ISkinComponent component) + public virtual Drawable? GetDrawableComponent(ISkinLookup lookup) { - switch (component) + switch (lookup) { - case SkinnableTargetComponent target: + case SkinnableTargetLookup target: if (!DrawableComponentInfo.TryGetValue(target.Target, out var skinnableInfo)) return null; diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 0e66278fc0..bd4078b985 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -201,7 +201,7 @@ namespace osu.Game.Skinning public event Action SourceChanged; - public Drawable GetDrawableComponent(ISkinComponent component) => lookupWithFallback(s => s.GetDrawableComponent(component)); + public Drawable GetDrawableComponent(ISkinLookup lookup) => lookupWithFallback(s => s.GetDrawableComponent(lookup)); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => lookupWithFallback(s => s.GetTexture(componentName, wrapModeS, wrapModeT)); diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index 5c5e9ae0fc..0ed5c6b736 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -28,7 +28,7 @@ namespace osu.Game.Skinning /// protected virtual bool AllowFallingBackToParent => true; - protected virtual bool AllowDrawableLookup(ISkinComponent component) => true; + protected virtual bool AllowDrawableLookup(ISkinLookup lookup) => true; protected virtual bool AllowTextureLookup(string componentName) => true; @@ -107,19 +107,19 @@ namespace osu.Game.Skinning } } - public Drawable? GetDrawableComponent(ISkinComponent component) + public Drawable? GetDrawableComponent(ISkinLookup lookup) { foreach (var (_, lookupWrapper) in skinSources) { Drawable? sourceDrawable; - if ((sourceDrawable = lookupWrapper.GetDrawableComponent(component)) != null) + if ((sourceDrawable = lookupWrapper.GetDrawableComponent(lookup)) != null) return sourceDrawable; } if (!AllowFallingBackToParent) return null; - return ParentSource?.GetDrawableComponent(component); + return ParentSource?.GetDrawableComponent(lookup); } public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) @@ -238,10 +238,10 @@ namespace osu.Game.Skinning this.provider = provider; } - public Drawable? GetDrawableComponent(ISkinComponent component) + public Drawable? GetDrawableComponent(ISkinLookup lookup) { - if (provider.AllowDrawableLookup(component)) - return skin.GetDrawableComponent(component); + if (provider.AllowDrawableLookup(lookup)) + return skin.GetDrawableComponent(lookup); return null; } diff --git a/osu.Game/Skinning/SkinTransformer.cs b/osu.Game/Skinning/SkinTransformer.cs index 4da60f1e43..9772d98fde 100644 --- a/osu.Game/Skinning/SkinTransformer.cs +++ b/osu.Game/Skinning/SkinTransformer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Skinning Skin = skin ?? throw new ArgumentNullException(nameof(skin)); } - public virtual Drawable? GetDrawableComponent(ISkinComponent component) => Skin.GetDrawableComponent(component); + public virtual Drawable? GetDrawableComponent(ISkinLookup lookup) => Skin.GetDrawableComponent(lookup); public virtual Texture? GetTexture(string componentName) => GetTexture(componentName, default, default); diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs index c6321553c7..4398dda413 100644 --- a/osu.Game/Skinning/SkinnableDrawable.cs +++ b/osu.Game/Skinning/SkinnableDrawable.cs @@ -31,25 +31,25 @@ namespace osu.Game.Skinning set => base.AutoSizeAxes = value; } - protected readonly ISkinComponent Component; + protected readonly ISkinLookup Lookup; private readonly ConfineMode confineMode; /// /// Create a new skinnable drawable. /// - /// The namespace-complete resource name for this skinnable element. + /// The namespace-complete resource name for this skinnable element. /// A function to create the default skin implementation of this element. /// How (if at all) the should be resize to fit within our own bounds. - public SkinnableDrawable(ISkinComponent component, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) - : this(component, confineMode) + public SkinnableDrawable(ISkinLookup lookup, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) + : this(lookup, confineMode) { createDefault = defaultImplementation; } - protected SkinnableDrawable(ISkinComponent component, ConfineMode confineMode = ConfineMode.NoScaling) + protected SkinnableDrawable(ISkinLookup lookup, ConfineMode confineMode = ConfineMode.NoScaling) { - Component = component; + Lookup = lookup; this.confineMode = confineMode; RelativeSizeAxes = Axes.Both; @@ -60,13 +60,13 @@ namespace osu.Game.Skinning /// public void ResetAnimation() => (Drawable as IFramedAnimation)?.GotoFrame(0); - private readonly Func? createDefault; + private readonly Func? createDefault; private readonly Cached scaling = new Cached(); private bool isDefault; - protected virtual Drawable CreateDefault(ISkinComponent component) => createDefault?.Invoke(component) ?? Empty(); + protected virtual Drawable CreateDefault(ISkinLookup lookup) => createDefault?.Invoke(lookup) ?? Empty(); /// /// Whether to apply size restrictions (specified via ) to the default implementation. @@ -75,11 +75,11 @@ namespace osu.Game.Skinning protected override void SkinChanged(ISkinSource skin) { - var retrieved = skin.GetDrawableComponent(Component); + var retrieved = skin.GetDrawableComponent(Lookup); if (retrieved == null) { - Drawable = CreateDefault(Component); + Drawable = CreateDefault(Lookup); isDefault = true; } else diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index f8130f31c3..8f456fce0a 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -34,42 +34,42 @@ namespace osu.Game.Skinning private ISkinSource source { get; set; } = null!; public SkinnableSprite(string textureName, ConfineMode confineMode = ConfineMode.NoScaling) - : base(new SpriteComponent(textureName), confineMode) + : base(new SpriteLookup(textureName), confineMode) { SpriteName.Value = textureName; } public SkinnableSprite() - : base(new SpriteComponent(string.Empty), ConfineMode.NoScaling) + : base(new SpriteLookup(string.Empty), ConfineMode.NoScaling) { RelativeSizeAxes = Axes.None; AutoSizeAxes = Axes.Both; SpriteName.BindValueChanged(name => { - ((SpriteComponent)Component).LookupName = name.NewValue ?? string.Empty; + ((SpriteLookup)Lookup).LookupName = name.NewValue ?? string.Empty; if (IsLoaded) SkinChanged(CurrentSkin); }); } - protected override Drawable CreateDefault(ISkinComponent component) + protected override Drawable CreateDefault(ISkinLookup lookup) { - var texture = textures.Get(component.LookupName); + var texture = textures.Get(lookup.LookupName); if (texture == null) - return new SpriteNotFound(component.LookupName); + return new SpriteNotFound(lookup.LookupName); return new Sprite { Texture = texture }; } public bool UsesFixedAnchor { get; set; } - internal class SpriteComponent : ISkinComponent + internal class SpriteLookup : ISkinLookup { public string LookupName { get; set; } - public SpriteComponent(string textureName) + public SpriteLookup(string textureName) { LookupName = textureName; } diff --git a/osu.Game/Skinning/SkinnableSpriteText.cs b/osu.Game/Skinning/SkinnableSpriteText.cs index 2bde3c4180..8cc48a76ed 100644 --- a/osu.Game/Skinning/SkinnableSpriteText.cs +++ b/osu.Game/Skinning/SkinnableSpriteText.cs @@ -9,8 +9,8 @@ namespace osu.Game.Skinning { public class SkinnableSpriteText : SkinnableDrawable, IHasText { - public SkinnableSpriteText(ISkinComponent component, Func defaultImplementation, ConfineMode confineMode = ConfineMode.NoScaling) - : base(component, defaultImplementation, confineMode) + public SkinnableSpriteText(ISkinLookup lookup, Func defaultImplementation, ConfineMode confineMode = ConfineMode.NoScaling) + : base(lookup, defaultImplementation, confineMode) { } diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index 708ad4ec47..b0262ce07a 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -39,7 +39,7 @@ namespace osu.Game.Skinning components.Clear(); ComponentsLoaded = false; - content = CurrentSkin.GetDrawableComponent(new SkinnableTargetComponent(Target)) as SkinnableTargetComponentsContainer; + content = CurrentSkin.GetDrawableComponent(new SkinnableTargetLookup(Target)) as SkinnableTargetComponentsContainer; cancellationSource?.Cancel(); cancellationSource = null; diff --git a/osu.Game/Skinning/SkinnableTargetComponent.cs b/osu.Game/Skinning/SkinnableTargetLookup.cs similarity index 73% rename from osu.Game/Skinning/SkinnableTargetComponent.cs rename to osu.Game/Skinning/SkinnableTargetLookup.cs index a17aafe6e7..df03123e85 100644 --- a/osu.Game/Skinning/SkinnableTargetComponent.cs +++ b/osu.Game/Skinning/SkinnableTargetLookup.cs @@ -3,13 +3,13 @@ namespace osu.Game.Skinning { - public class SkinnableTargetComponent : ISkinComponent + public class SkinnableTargetLookup : ISkinLookup { public readonly SkinnableTarget Target; public string LookupName => Target.ToString(); - public SkinnableTargetComponent(SkinnableTarget target) + public SkinnableTargetLookup(SkinnableTarget target) { Target = target; } diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index d00874aa8f..32b4b6b4d4 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -59,14 +59,14 @@ namespace osu.Game.Skinning return null; } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - if (base.GetDrawableComponent(component) is Drawable c) + if (base.GetDrawableComponent(lookup) is Drawable c) return c; - switch (component) + switch (lookup) { - case SkinnableTargetComponent target: + case SkinnableTargetLookup target: switch (target.Target) { case SkinnableTarget.SongSelect: @@ -156,14 +156,14 @@ namespace osu.Game.Skinning return null; } - switch (component.LookupName) + switch (lookup.LookupName) { // Temporary until default skin has a valid hit lighting. case @"lighting": return Drawable.Empty(); } - if (GetTexture(component.LookupName) is Texture t) + if (GetTexture(lookup.LookupName) is Texture t) return new Sprite { Texture = t }; return null; diff --git a/osu.Game/Skinning/UnsupportedSkinComponentException.cs b/osu.Game/Skinning/UnsupportedSkinComponentException.cs index 7f0dd51d5b..32fc6661b0 100644 --- a/osu.Game/Skinning/UnsupportedSkinComponentException.cs +++ b/osu.Game/Skinning/UnsupportedSkinComponentException.cs @@ -7,8 +7,8 @@ namespace osu.Game.Skinning { public class UnsupportedSkinComponentException : Exception { - public UnsupportedSkinComponentException(ISkinComponent component) - : base($@"Unsupported component type: {component.GetType()} (lookup: ""{component.LookupName}"").") + public UnsupportedSkinComponentException(ISkinLookup lookup) + : base($@"Unsupported component type: {lookup.GetType()} (lookup: ""{lookup.LookupName}"").") { } } From e75c3b3f94fa17bd18ff58e0c9ec2419453e606d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 16:03:29 +0900 Subject: [PATCH 2158/2686] Rename `SkinnableTarget` to `GlobalSkinLookup` --- .../Legacy/CatchLegacySkinTransformer.cs | 6 ++--- .../Skins/SkinDeserialisationTest.cs | 16 ++++++------- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 6 ++--- osu.Game/Screens/Play/HUDOverlay.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- osu.Game/Skinning/ArgonSkin.cs | 8 +++---- osu.Game/Skinning/Editor/SkinEditor.cs | 2 +- osu.Game/Skinning/GlobalSkinLookup.cs | 23 +++++++++++++++++++ osu.Game/Skinning/ISkinnableDrawable.cs | 5 ++++ osu.Game/Skinning/ISkinnableTarget.cs | 2 +- osu.Game/Skinning/LegacyBeatmapSkin.cs | 6 ++--- osu.Game/Skinning/LegacySkin.cs | 6 ++--- osu.Game/Skinning/Skin.cs | 10 ++++---- osu.Game/Skinning/SkinnableTarget.cs | 11 --------- osu.Game/Skinning/SkinnableTargetContainer.cs | 6 ++--- osu.Game/Skinning/SkinnableTargetLookup.cs | 17 -------------- osu.Game/Skinning/TrianglesSkin.cs | 8 +++---- 17 files changed, 68 insertions(+), 68 deletions(-) create mode 100644 osu.Game/Skinning/GlobalSkinLookup.cs delete mode 100644 osu.Game/Skinning/SkinnableTarget.cs delete mode 100644 osu.Game/Skinning/SkinnableTargetLookup.cs diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 5fda40d8c0..83a8a37676 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -27,11 +27,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - if (lookup is SkinnableTargetLookup targetComponent) + if (lookup is GlobalSkinLookup targetComponent) { - switch (targetComponent.Target) + switch (targetComponent.Lookup) { - case SkinnableTarget.MainHUDComponents: + case GlobalSkinLookup.LookupType.MainHUDComponents: var components = base.GetDrawableComponent(lookup) as SkinnableTargetComponentsContainer; if (providesComboCounter && components != null) diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 989459632e..4398d870a0 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Skins var skin = new TestSkin(new SkinInfo(), null, storage); Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2)); - Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents], Has.Length.EqualTo(9)); + Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(9)); } } @@ -93,10 +93,10 @@ namespace osu.Game.Tests.Skins var skin = new TestSkin(new SkinInfo(), null, storage); Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2)); - Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents], Has.Length.EqualTo(6)); - Assert.That(skin.DrawableComponentInfo[SkinnableTarget.SongSelect], Has.Length.EqualTo(1)); + Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(6)); + Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.SongSelect], Has.Length.EqualTo(1)); - var skinnableInfo = skin.DrawableComponentInfo[SkinnableTarget.SongSelect].First(); + var skinnableInfo = skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.SongSelect].First(); Assert.That(skinnableInfo.Type, Is.EqualTo(typeof(SkinnableSprite))); Assert.That(skinnableInfo.Settings.First().Key, Is.EqualTo("sprite_name")); @@ -107,10 +107,10 @@ namespace osu.Game.Tests.Skins using (var storage = new ZipArchiveReader(stream)) { var skin = new TestSkin(new SkinInfo(), null, storage); - Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents], Has.Length.EqualTo(8)); - Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); - Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); - Assert.That(skin.DrawableComponentInfo[SkinnableTarget.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); + Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(8)); + Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); + Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); + Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 6fe6a85b8f..69a50a1cd1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -40,7 +40,7 @@ namespace osu.Game.Tests.Visual.Gameplay { CreateSkinTest(TrianglesSkin.CreateInfo(), () => new LegacyBeatmapSkin(new BeatmapInfo(), null)); AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded)); - AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(SkinnableTarget.MainHUDComponents, skinManager.CurrentSkin.Value)); + AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(GlobalSkinLookup.LookupType.MainHUDComponents, skinManager.CurrentSkin.Value)); } protected void CreateSkinTest(SkinInfo gameCurrentSkin, Func getBeatmapSkin) @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Gameplay }); } - protected bool AssertComponentsFromExpectedSource(SkinnableTarget target, ISkin expectedSource) + protected bool AssertComponentsFromExpectedSource(GlobalSkinLookup.LookupType target, ISkin expectedSource) { var actualComponentsContainer = Player.ChildrenOfType().First(s => s.Target == target) .ChildrenOfType().SingleOrDefault(); @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual.Gameplay var actualInfo = actualComponentsContainer.CreateSkinnableInfo(); - var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource.GetDrawableComponent(new SkinnableTargetLookup(target)); + var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource.GetDrawableComponent(new GlobalSkinLookup(target)); if (expectedComponentsContainer == null) return false; diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 2791f5ff8f..932ebe7d18 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -391,7 +391,7 @@ namespace osu.Game.Screens.Play private OsuConfigManager config { get; set; } public MainComponentsContainer() - : base(SkinnableTarget.MainHUDComponents) + : base(GlobalSkinLookup.LookupType.MainHUDComponents) { RelativeSizeAxes = Axes.Both; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 4b2417aab4..e525d5a368 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -250,7 +250,7 @@ namespace osu.Game.Screens.Select } } }, - new SkinnableTargetContainer(SkinnableTarget.SongSelect) + new SkinnableTargetContainer(GlobalSkinLookup.LookupType.SongSelect) { RelativeSizeAxes = Axes.Both, }, diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index f65cee8a69..7aaf1a0e89 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -88,10 +88,10 @@ namespace osu.Game.Skinning switch (lookup) { - case SkinnableTargetLookup target: - switch (target.Target) + case GlobalSkinLookup globalLookup: + switch (globalLookup.Lookup) { - case SkinnableTarget.SongSelect: + case GlobalSkinLookup.LookupType.SongSelect: var songSelectComponents = new SkinnableTargetComponentsContainer(_ => { // do stuff when we need to. @@ -99,7 +99,7 @@ namespace osu.Game.Skinning return songSelectComponents; - case SkinnableTarget.MainHUDComponents: + case GlobalSkinLookup.LookupType.MainHUDComponents: var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index c1ff161f25..fdc8b6b2ad 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -314,7 +314,7 @@ namespace osu.Game.Skinning.Editor private ISkinnableTarget getFirstTarget() => availableTargets.FirstOrDefault(); - private ISkinnableTarget getTarget(SkinnableTarget target) + private ISkinnableTarget getTarget(GlobalSkinLookup.LookupType target) { return availableTargets.FirstOrDefault(c => c.Target == target); } diff --git a/osu.Game/Skinning/GlobalSkinLookup.cs b/osu.Game/Skinning/GlobalSkinLookup.cs new file mode 100644 index 0000000000..c63c0315a3 --- /dev/null +++ b/osu.Game/Skinning/GlobalSkinLookup.cs @@ -0,0 +1,23 @@ +// 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.Skinning +{ + public class GlobalSkinLookup : ISkinLookup + { + public readonly LookupType Lookup; + + public string LookupName => Lookup.ToString(); + + public GlobalSkinLookup(LookupType lookup) + { + Lookup = lookup; + } + + public enum LookupType + { + MainHUDComponents, + SongSelect + } + } +} diff --git a/osu.Game/Skinning/ISkinnableDrawable.cs b/osu.Game/Skinning/ISkinnableDrawable.cs index 3fc6a2fdd8..1ecd6f967e 100644 --- a/osu.Game/Skinning/ISkinnableDrawable.cs +++ b/osu.Game/Skinning/ISkinnableDrawable.cs @@ -5,12 +5,17 @@ using System; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics; +using osu.Game.Configuration; namespace osu.Game.Skinning { /// /// Denotes a drawable which, as a drawable, can be adjusted via skinning specifications. /// + /// + /// Attaching this interface to any will make it serialisable to skin settings. + /// Adding annotated bindables will also serialise these settings alongside each instance. + /// public interface ISkinnableDrawable : IDrawable { /// diff --git a/osu.Game/Skinning/ISkinnableTarget.cs b/osu.Game/Skinning/ISkinnableTarget.cs index 8d4f4dd0c3..b1a0f6714b 100644 --- a/osu.Game/Skinning/ISkinnableTarget.cs +++ b/osu.Game/Skinning/ISkinnableTarget.cs @@ -18,7 +18,7 @@ namespace osu.Game.Skinning /// /// The definition of this target. /// - SkinnableTarget Target { get; } + GlobalSkinLookup.LookupType Target { get; } /// /// A bindable list of components which are being tracked by this skinnable target. diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 2aa76b5871..1d6ded6fee 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -45,11 +45,11 @@ namespace osu.Game.Skinning public override Drawable? GetDrawableComponent(ISkinLookup lookup) { - if (lookup is SkinnableTargetLookup targetComponent) + if (lookup is GlobalSkinLookup targetComponent) { - switch (targetComponent.Target) + switch (targetComponent.Lookup) { - case SkinnableTarget.MainHUDComponents: + case GlobalSkinLookup.LookupType.MainHUDComponents: // this should exist in LegacySkin instead, but there isn't a fallback skin for LegacySkins yet. // therefore keep the check here until fallback default legacy skin is supported. if (!this.HasFont(LegacyFont.Score)) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 97833d0e28..75957bb560 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -329,10 +329,10 @@ namespace osu.Game.Skinning switch (lookup) { - case SkinnableTargetLookup target: - switch (target.Target) + case GlobalSkinLookup target: + switch (target.Lookup) { - case SkinnableTarget.MainHUDComponents: + case GlobalSkinLookup.LookupType.MainHUDComponents: var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index a14b1e1359..67b74229bb 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -37,9 +37,9 @@ namespace osu.Game.Skinning public SkinConfiguration Configuration { get; set; } - public IDictionary DrawableComponentInfo => drawableComponentInfo; + public IDictionary DrawableComponentInfo => drawableComponentInfo; - private readonly Dictionary drawableComponentInfo = new Dictionary(); + private readonly Dictionary drawableComponentInfo = new Dictionary(); public abstract ISample? GetSample(ISampleInfo sampleInfo); @@ -97,7 +97,7 @@ namespace osu.Game.Skinning Configuration = new SkinConfiguration(); // skininfo files may be null for default skin. - foreach (SkinnableTarget skinnableTarget in Enum.GetValues(typeof(SkinnableTarget))) + foreach (GlobalSkinLookup.LookupType skinnableTarget in Enum.GetValues(typeof(GlobalSkinLookup.LookupType))) { string filename = $"{skinnableTarget}.json"; @@ -158,8 +158,8 @@ namespace osu.Game.Skinning { switch (lookup) { - case SkinnableTargetLookup target: - if (!DrawableComponentInfo.TryGetValue(target.Target, out var skinnableInfo)) + case GlobalSkinLookup target: + if (!DrawableComponentInfo.TryGetValue(target.Lookup, out var skinnableInfo)) return null; var components = new List(); diff --git a/osu.Game/Skinning/SkinnableTarget.cs b/osu.Game/Skinning/SkinnableTarget.cs deleted file mode 100644 index 09de8a5d71..0000000000 --- a/osu.Game/Skinning/SkinnableTarget.cs +++ /dev/null @@ -1,11 +0,0 @@ -// 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.Skinning -{ - public enum SkinnableTarget - { - MainHUDComponents, - SongSelect - } -} diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index b0262ce07a..bea29b0da3 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -13,7 +13,7 @@ namespace osu.Game.Skinning { private SkinnableTargetComponentsContainer? content; - public SkinnableTarget Target { get; } + public GlobalSkinLookup.LookupType Target { get; } public IBindableList Components => components; @@ -25,7 +25,7 @@ namespace osu.Game.Skinning private CancellationTokenSource? cancellationSource; - public SkinnableTargetContainer(SkinnableTarget target) + public SkinnableTargetContainer(GlobalSkinLookup.LookupType target) { Target = target; } @@ -39,7 +39,7 @@ namespace osu.Game.Skinning components.Clear(); ComponentsLoaded = false; - content = CurrentSkin.GetDrawableComponent(new SkinnableTargetLookup(Target)) as SkinnableTargetComponentsContainer; + content = CurrentSkin.GetDrawableComponent(new GlobalSkinLookup(Target)) as SkinnableTargetComponentsContainer; cancellationSource?.Cancel(); cancellationSource = null; diff --git a/osu.Game/Skinning/SkinnableTargetLookup.cs b/osu.Game/Skinning/SkinnableTargetLookup.cs deleted file mode 100644 index df03123e85..0000000000 --- a/osu.Game/Skinning/SkinnableTargetLookup.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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.Skinning -{ - public class SkinnableTargetLookup : ISkinLookup - { - public readonly SkinnableTarget Target; - - public string LookupName => Target.ToString(); - - public SkinnableTargetLookup(SkinnableTarget target) - { - Target = target; - } - } -} diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 32b4b6b4d4..e3729136b9 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -66,10 +66,10 @@ namespace osu.Game.Skinning switch (lookup) { - case SkinnableTargetLookup target: - switch (target.Target) + case GlobalSkinLookup target: + switch (target.Lookup) { - case SkinnableTarget.SongSelect: + case GlobalSkinLookup.LookupType.SongSelect: var songSelectComponents = new SkinnableTargetComponentsContainer(_ => { // do stuff when we need to. @@ -77,7 +77,7 @@ namespace osu.Game.Skinning return songSelectComponents; - case SkinnableTarget.MainHUDComponents: + case GlobalSkinLookup.LookupType.MainHUDComponents: var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); From 1aa0e40f2f4111d6c52e6aca33fb8190662689b2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 16:04:56 +0900 Subject: [PATCH 2159/2686] Add "Component" prefix to lookup naming --- ...nLookup.cs => CatchSkinComponentLookup.cs} | 4 ++-- .../Objects/Drawables/CaughtObject.cs | 4 ++-- .../Objects/Drawables/DrawableBanana.cs | 2 +- .../Objects/Drawables/DrawableDroplet.cs | 2 +- .../Objects/Drawables/DrawableFruit.cs | 2 +- .../Argon/CatchArgonSkinTransformer.cs | 4 ++-- .../Legacy/CatchLegacySkinTransformer.cs | 10 ++++----- .../UI/CatchComboDisplay.cs | 2 +- osu.Game.Rulesets.Catch/UI/HitExplosion.cs | 2 +- .../UI/SkinnableCatcher.cs | 2 +- .../Skinning/TestSceneColumnBackground.cs | 4 ++-- .../Skinning/TestSceneStageBackground.cs | 2 +- .../Skinning/TestSceneStageForeground.cs | 2 +- ...nLookup.cs => ManiaSkinComponentLookup.cs} | 6 ++--- .../Objects/Drawables/DrawableHoldNote.cs | 2 +- .../Objects/Drawables/DrawableNote.cs | 2 +- .../Argon/ManiaArgonSkinTransformer.cs | 6 ++--- .../Legacy/ManiaLegacySkinTransformer.cs | 6 ++--- osu.Game.Rulesets.Mania/UI/Column.cs | 4 ++-- .../UI/Components/ColumnHitObjectArea.cs | 2 +- .../UI/PoolableHitExplosion.cs | 2 +- osu.Game.Rulesets.Mania/UI/Stage.cs | 4 ++-- .../TestSceneCursorTrail.cs | 2 +- .../TestSceneGameplayCursor.cs | 2 +- .../TestSceneSkinFallbacks.cs | 4 ++-- .../Drawables/Connections/FollowPoint.cs | 2 +- .../Objects/Drawables/DrawableHitCircle.cs | 6 ++--- .../Objects/Drawables/DrawableSlider.cs | 2 +- .../Objects/Drawables/DrawableSliderBall.cs | 4 ++-- .../Objects/Drawables/DrawableSliderRepeat.cs | 2 +- .../Objects/Drawables/DrawableSliderTail.cs | 2 +- .../Objects/Drawables/DrawableSliderTick.cs | 2 +- .../Objects/Drawables/DrawableSpinner.cs | 2 +- ...kinLookup.cs => OsuSkinComponentLookup.cs} | 4 ++-- .../Skinning/Argon/OsuArgonSkinTransformer.cs | 6 ++--- .../Skinning/Default/DefaultApproachCircle.cs | 2 +- .../Skinning/Default/NumberPiece.cs | 2 +- .../Skinning/Default/ReverseArrowPiece.cs | 2 +- .../Skinning/Legacy/LegacyApproachCircle.cs | 2 +- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 2 +- .../Skinning/Legacy/LegacyReverseArrow.cs | 2 +- .../Legacy/OsuLegacySkinTransformer.cs | 4 ++-- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs | 2 +- .../UI/Cursor/OsuCursorContainer.cs | 4 ++-- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 4 ++-- .../Skinning/TestSceneTaikoScroller.cs | 2 +- .../Objects/Drawables/DrawableBarLine.cs | 2 +- .../Objects/Drawables/DrawableDrumRoll.cs | 2 +- .../Objects/Drawables/DrawableDrumRollTick.cs | 2 +- .../Objects/Drawables/DrawableHit.cs | 4 ++-- .../Objects/Drawables/DrawableSwell.cs | 2 +- .../Objects/Drawables/DrawableSwellTick.cs | 2 +- .../Legacy/TaikoLegacySkinTransformer.cs | 6 ++--- ...nLookup.cs => TaikoSkinComponentLookup.cs} | 4 ++-- .../UI/DrawableTaikoRuleset.cs | 2 +- osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 2 +- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 2 +- .../UI/KiaiHitExplosion.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 8 +++---- .../TestSceneHitObjectAccentColour.cs | 2 +- .../Skinning/LegacySkinAnimationTest.cs | 2 +- .../TestSceneRulesetSkinProvidingContainer.cs | 2 +- .../Skins/SkinDeserialisationTest.cs | 16 +++++++------- .../TestSceneBeatmapSkinLookupDisables.cs | 12 +++++----- .../Skins/TestSceneSkinConfigurationLookup.cs | 2 +- .../Skins/TestSceneSkinProvidingContainer.cs | 2 +- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 6 ++--- .../Gameplay/TestSceneSkinnableDrawable.cs | 22 +++++++++---------- .../Gameplay/TestSceneSkinnableSound.cs | 2 +- .../Rulesets/Judgements/DrawableJudgement.cs | 2 +- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 2 +- osu.Game/Screens/Play/HUDOverlay.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- osu.Game/Skinning/ArgonSkin.cs | 8 +++---- .../Skinning/BeatmapSkinProvidingContainer.cs | 2 +- osu.Game/Skinning/Editor/SkinEditor.cs | 2 +- ...okup.cs => GameplaySkinComponentLookup.cs} | 4 ++-- ...Lookup.cs => GlobalSkinComponentLookup.cs} | 4 ++-- osu.Game/Skinning/ISkin.cs | 2 +- ...ISkinLookup.cs => ISkinComponentLookup.cs} | 4 ++-- osu.Game/Skinning/ISkinnableTarget.cs | 2 +- osu.Game/Skinning/LegacyBeatmapSkin.cs | 6 ++--- osu.Game/Skinning/LegacySkin.cs | 10 ++++----- osu.Game/Skinning/ResourceStoreBackedSkin.cs | 2 +- osu.Game/Skinning/Skin.cs | 10 ++++----- osu.Game/Skinning/SkinManager.cs | 2 +- osu.Game/Skinning/SkinProvidingContainer.cs | 6 ++--- osu.Game/Skinning/SkinTransformer.cs | 2 +- osu.Game/Skinning/SkinnableDrawable.cs | 16 +++++++------- osu.Game/Skinning/SkinnableSprite.cs | 12 +++++----- osu.Game/Skinning/SkinnableSpriteText.cs | 2 +- osu.Game/Skinning/SkinnableTargetContainer.cs | 6 ++--- osu.Game/Skinning/TrianglesSkin.cs | 8 +++---- .../UnsupportedSkinComponentException.cs | 2 +- 94 files changed, 186 insertions(+), 186 deletions(-) rename osu.Game.Rulesets.Catch/{CatchSkinLookup.cs => CatchSkinComponentLookup.cs} (74%) rename osu.Game.Rulesets.Mania/{ManiaSkinLookup.cs => ManiaSkinComponentLookup.cs} (77%) rename osu.Game.Rulesets.Osu/{OsuSkinLookup.cs => OsuSkinComponentLookup.cs} (73%) rename osu.Game.Rulesets.Taiko/{TaikoSkinLookup.cs => TaikoSkinComponentLookup.cs} (73%) rename osu.Game/Skinning/{GameplaySkinLookup.cs => GameplaySkinComponentLookup.cs} (83%) rename osu.Game/Skinning/{GlobalSkinLookup.cs => GlobalSkinComponentLookup.cs} (78%) rename osu.Game/Skinning/{ISkinLookup.cs => ISkinComponentLookup.cs} (88%) diff --git a/osu.Game.Rulesets.Catch/CatchSkinLookup.cs b/osu.Game.Rulesets.Catch/CatchSkinComponentLookup.cs similarity index 74% rename from osu.Game.Rulesets.Catch/CatchSkinLookup.cs rename to osu.Game.Rulesets.Catch/CatchSkinComponentLookup.cs index 65bfc7ee30..149aae1cb4 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinLookup.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponentLookup.cs @@ -5,9 +5,9 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch { - public class CatchSkinLookup : GameplaySkinLookup + public class CatchSkinComponentLookup : GameplaySkinComponentLookup { - public CatchSkinLookup(CatchSkinComponents component) + public CatchSkinComponentLookup(CatchSkinComponents component) : base(component) { } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs index 20d348fe3d..8ac5eac227 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs @@ -37,8 +37,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables public override bool RemoveWhenNotAlive => true; - protected CaughtObject(CatchSkinComponents skinComponent, Func defaultImplementation) - : base(new CatchSkinLookup(skinComponent), defaultImplementation) + protected CaughtObject(CatchSkinComponents skinComponent, Func defaultImplementation) + : base(new CatchSkinComponentLookup(skinComponent), defaultImplementation) { Origin = Anchor.Centre; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs index a2b32ea9e4..80a4150d98 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables private void load() { ScalingContainer.Child = new SkinnableDrawable( - new CatchSkinLookup(CatchSkinComponents.Banana), + new CatchSkinComponentLookup(CatchSkinComponents.Banana), _ => new BananaPiece()); } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs index 210a4495e4..a81d87480a 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables private void load() { ScalingContainer.Child = new SkinnableDrawable( - new CatchSkinLookup(CatchSkinComponents.Droplet), + new CatchSkinComponentLookup(CatchSkinComponents.Droplet), _ => new DropletPiece()); } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs index 6359a5b35c..d7fd79929b 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables private void load() { ScalingContainer.Child = new SkinnableDrawable( - new CatchSkinLookup(CatchSkinComponents.Fruit), + new CatchSkinComponentLookup(CatchSkinComponents.Fruit), _ => new FruitPiece()); } diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs index 606cd339a9..520c2de248 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/CatchArgonSkinTransformer.cs @@ -13,11 +13,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { } - public override Drawable? GetDrawableComponent(ISkinLookup lookup) + public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { switch (lookup) { - case CatchSkinLookup catchComponent: + case CatchSkinComponentLookup catchComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (catchComponent.Component) { diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 83a8a37676..08ac55508a 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -25,13 +25,13 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { } - public override Drawable? GetDrawableComponent(ISkinLookup lookup) + public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { - if (lookup is GlobalSkinLookup targetComponent) + if (lookup is GlobalSkinComponentLookup targetComponent) { switch (targetComponent.Lookup) { - case GlobalSkinLookup.LookupType.MainHUDComponents: + case GlobalSkinComponentLookup.LookupType.MainHUDComponents: var components = base.GetDrawableComponent(lookup) as SkinnableTargetComponentsContainer; if (providesComboCounter && components != null) @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy } } - if (lookup is CatchSkinLookup catchSkinComponent) + if (lookup is CatchSkinComponentLookup catchSkinComponent) { switch (catchSkinComponent.Component) { @@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { case CatchSkinConfiguration.FlipCatcherPlate: // Don't flip catcher plate contents if the catcher is provided by this legacy skin. - if (GetDrawableComponent(new CatchSkinLookup(CatchSkinComponents.Catcher)) != null) + if (GetDrawableComponent(new CatchSkinComponentLookup(CatchSkinComponents.Catcher)) != null) return (IBindable)new Bindable(); break; diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs index 802e837746..03f0bc6a55 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.UI private readonly IBindable showCombo = new BindableBool(true); public CatchComboDisplay() - : base(new CatchSkinLookup(CatchSkinComponents.CatchComboCounter), _ => Empty()) + : base(new CatchSkinComponentLookup(CatchSkinComponents.CatchComboCounter), _ => Empty()) { } diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs index fb55864c49..9b32893efe 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.UI Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; - InternalChild = skinnableExplosion = new SkinnableDrawable(new CatchSkinLookup(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) + InternalChild = skinnableExplosion = new SkinnableDrawable(new CatchSkinComponentLookup(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) { CentreComponent = false, Anchor = Anchor.BottomCentre, diff --git a/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs b/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs index 2e07e39943..fa6ccf6bd6 100644 --- a/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs +++ b/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Catch.UI public readonly Bindable AnimationState = new Bindable(); public SkinnableCatcher() - : base(new CatchSkinLookup(CatchSkinComponents.Catcher), _ => new DefaultCatcher()) + : base(new CatchSkinComponentLookup(CatchSkinComponents.Catcher), _ => new DefaultCatcher()) { Anchor = Anchor.TopCentre; // Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling. diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs index 8dc8e72479..3dece20308 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs @@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning { RelativeSizeAxes = Axes.Both, Width = 0.5f, - Child = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) + Child = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both } @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning { RelativeSizeAxes = Axes.Both, Width = 0.5f, - Child = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) + Child = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both } diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs index 19ccf20870..5c8e038eed 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(_ => new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.StageBackground), + SetContents(_ => new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground()) { Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs index 171d2951be..f9c17ee7f4 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning [BackgroundDependencyLoader] private void load() { - SetContents(_ => new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.StageForeground), _ => null) + SetContents(_ => new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.StageForeground), _ => null) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Mania/ManiaSkinLookup.cs b/osu.Game.Rulesets.Mania/ManiaSkinComponentLookup.cs similarity index 77% rename from osu.Game.Rulesets.Mania/ManiaSkinLookup.cs rename to osu.Game.Rulesets.Mania/ManiaSkinComponentLookup.cs index 6e6d00fee6..c9ee5af809 100644 --- a/osu.Game.Rulesets.Mania/ManiaSkinLookup.cs +++ b/osu.Game.Rulesets.Mania/ManiaSkinComponentLookup.cs @@ -5,13 +5,13 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania { - public class ManiaSkinLookup : GameplaySkinLookup + public class ManiaSkinComponentLookup : GameplaySkinComponentLookup { /// - /// Creates a new . + /// Creates a new . /// /// The component. - public ManiaSkinLookup(ManiaSkinComponents component) + public ManiaSkinComponentLookup(ManiaSkinComponents component) : base(component) { } diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 5b003e3c19..c68eec610c 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables headContainer = new Container { RelativeSizeAxes = Axes.Both } } }, - bodyPiece = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.HoldNoteBody), _ => new DefaultBodyPiece + bodyPiece = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.HoldNoteBody), _ => new DefaultBodyPiece { RelativeSizeAxes = Axes.Both, }) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index 25347d3dfa..cf3149b065 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables { rulesetConfig?.BindWith(ManiaRulesetSetting.TimingBasedNoteColouring, configTimingBasedNoteColouring); - AddInternal(headPiece = new SkinnableDrawable(new ManiaSkinLookup(Component), _ => new DefaultNotePiece()) + AddInternal(headPiece = new SkinnableDrawable(new ManiaSkinComponentLookup(Component), _ => new DefaultNotePiece()) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index cf9f9f36f0..eb7f63fbe2 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -22,14 +22,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon this.beatmap = (ManiaBeatmap)beatmap; } - public override Drawable? GetDrawableComponent(ISkinLookup lookup) + public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { switch (lookup) { - case GameplaySkinLookup resultComponent: + case GameplaySkinComponentLookup resultComponent: return new ArgonJudgementPiece(resultComponent.Component); - case ManiaSkinLookup maniaComponent: + case ManiaSkinComponentLookup maniaComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (maniaComponent.Component) { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs index 5b7ccc7bb6..f8519beb22 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/ManiaLegacySkinTransformer.cs @@ -74,14 +74,14 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy }); } - public override Drawable GetDrawableComponent(ISkinLookup lookup) + public override Drawable GetDrawableComponent(ISkinComponentLookup lookup) { switch (lookup) { - case GameplaySkinLookup resultComponent: + case GameplaySkinComponentLookup resultComponent: return getResult(resultComponent.Component); - case ManiaSkinLookup maniaComponent: + case ManiaSkinComponentLookup maniaComponent: if (!isLegacySkin.Value || !hasKeyTexture.Value) return null; diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 4eed75a90d..de7424773b 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Mania.UI skin.SourceChanged += onSourceChanged; onSourceChanged(); - Drawable background = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) + Drawable background = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground()) { RelativeSizeAxes = Axes.Both, }; @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Mania.UI // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements background.CreateProxy(), HitObjectArea, - keyArea = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) + keyArea = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea()) { RelativeSizeAxes = Axes.Both, }, diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs index d02e4afc81..e5a9ca1e85 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components RelativeSizeAxes = Axes.Both, Depth = 2, }, - hitTarget = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.HitTarget), _ => new DefaultHitTarget()) + hitTarget = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.HitTarget), _ => new DefaultHitTarget()) { RelativeSizeAxes = Axes.X, Depth = 1 diff --git a/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs b/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs index faf345545d..8e5c8f9b75 100644 --- a/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.UI [BackgroundDependencyLoader] private void load() { - InternalChild = skinnableExplosion = new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) + InternalChild = skinnableExplosion = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index 5d08e38aef..8aeaa9cf35 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.UI AutoSizeAxes = Axes.X, Children = new Drawable[] { - new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground()) + new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.StageBackground), _ => new DefaultStageBackground()) { RelativeSizeAxes = Axes.Both }, @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Mania.UI RelativeSizeAxes = Axes.Y, } }, - new SkinnableDrawable(new ManiaSkinLookup(ManiaSkinComponents.StageForeground), _ => null) + new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.StageForeground), _ => null) { RelativeSizeAxes = Axes.Both }, diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs index aeadbea510..30f0891344 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.Tests RelativeSizeAxes = Axes.Both; } - public Drawable GetDrawableComponent(ISkinLookup lookup) => null; + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => null; public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs index f88948ce13..628082c2a9 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Osu.Tests private class TopLeftCursorSkin : ISkin { - public Drawable GetDrawableComponent(ISkinLookup lookup) => null; + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => null; public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null; public ISample GetSample(ISampleInfo sampleInfo) => null; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs index c012dae635..878150e467 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs @@ -149,11 +149,11 @@ namespace osu.Game.Rulesets.Osu.Tests this.identifier = identifier; } - public Drawable GetDrawableComponent(ISkinLookup lookup) + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) { if (!enabled) return null; - if (lookup is OsuSkinLookup osuComponent && osuComponent.Component == OsuSkinComponents.SliderBody) + if (lookup is OsuSkinComponentLookup osuComponent && osuComponent.Component == OsuSkinComponents.SliderBody) return null; return new OsuSpriteText diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs index 22037c873c..8c95da9be1 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections { Origin = Anchor.Centre; - InternalChild = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.FollowPoint), _ => new CircularContainer + InternalChild = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.FollowPoint), _ => new CircularContainer { Masking = true, AutoSizeAxes = Axes.Both, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index bcb3ccae41..6201199cc3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -81,12 +81,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - CirclePiece = new SkinnableDrawable(new OsuSkinLookup(CirclePieceComponent), _ => new MainCirclePiece()) + CirclePiece = new SkinnableDrawable(new OsuSkinComponentLookup(CirclePieceComponent), _ => new MainCirclePiece()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - ApproachCircle = new ProxyableSkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.ApproachCircle), _ => new DefaultApproachCircle()) + ApproachCircle = new ProxyableSkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.ApproachCircle), _ => new DefaultApproachCircle()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -278,7 +278,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { public override bool RemoveWhenNotAlive => false; - public ProxyableSkinnableDrawable(ISkinLookup lookup, Func defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) + public ProxyableSkinnableDrawable(ISkinComponentLookup lookup, Func defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) : base(lookup, defaultImplementation, confineMode) { } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index 3fdbc3dacd..a4745b365b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - Body = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderBody), _ => new DefaultSliderBody(), confineMode: ConfineMode.NoScaling), + Body = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.SliderBody), _ => new DefaultSliderBody(), confineMode: ConfineMode.NoScaling), tailContainer = new Container { RelativeSizeAxes = Axes.Both }, tickContainer = new Container { RelativeSizeAxes = Axes.Both }, repeatContainer = new Container { RelativeSizeAxes = Axes.Both }, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs index 86d41f0cbf..35d5c1f478 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Children = new[] { - new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderFollowCircle), _ => new DefaultFollowCircle()) + new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.SliderFollowCircle), _ => new DefaultFollowCircle()) { Origin = Anchor.Centre, Anchor = Anchor.Centre, @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables RelativeSizeAxes = Axes.Both, Masking = true }, - ball = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderBall), _ => new DefaultSliderBall()) + ball = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.SliderBall), _ => new DefaultSliderBall()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 1b8a17b6df..08602e168c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Children = new Drawable[] { // no default for this; only visible in legacy skins. - CirclePiece = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) + CirclePiece = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index e8c6e80109..a59cd92d62 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Children = new Drawable[] { // no default for this; only visible in legacy skins. - CirclePiece = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) + CirclePiece = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.SliderTailHitCircle), _ => Empty()) } }, }); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs index f591cd15d4..563c7e85aa 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Origin = Anchor.Centre; - AddInternal(scaleContainer = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SliderScorePoint), _ => new CircularContainer + AddInternal(scaleContainer = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.SliderScorePoint), _ => new CircularContainer { Masking = true, Origin = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 7d0e29bd93..83a9408570 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables RelativeSizeAxes = Axes.Y, Children = new Drawable[] { - Body = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.SpinnerBody), _ => new DefaultSpinner()), + Body = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.SpinnerBody), _ => new DefaultSpinner()), RotationTracker = new SpinnerRotationTracker(this) } }, diff --git a/osu.Game.Rulesets.Osu/OsuSkinLookup.cs b/osu.Game.Rulesets.Osu/OsuSkinComponentLookup.cs similarity index 73% rename from osu.Game.Rulesets.Osu/OsuSkinLookup.cs rename to osu.Game.Rulesets.Osu/OsuSkinComponentLookup.cs index 4048e95e4b..81d5811f85 100644 --- a/osu.Game.Rulesets.Osu/OsuSkinLookup.cs +++ b/osu.Game.Rulesets.Osu/OsuSkinComponentLookup.cs @@ -5,9 +5,9 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu { - public class OsuSkinLookup : GameplaySkinLookup + public class OsuSkinComponentLookup : GameplaySkinComponentLookup { - public OsuSkinLookup(OsuSkinComponents component) + public OsuSkinComponentLookup(OsuSkinComponents component) : base(component) { } diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index bf664bb606..86194d2c43 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -14,14 +14,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { } - public override Drawable? GetDrawableComponent(ISkinLookup lookup) + public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { switch (lookup) { - case GameplaySkinLookup resultComponent: + case GameplaySkinComponentLookup resultComponent: return new ArgonJudgementPiece(resultComponent.Component); - case OsuSkinLookup osuComponent: + case OsuSkinComponentLookup osuComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (osuComponent.Component) { diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs index 2b2c31dcf7..3a67ad526e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default accentColour.BindValueChanged(colour => Colour = colour.NewValue, true); } - protected override Drawable CreateDefault(ISkinLookup lookup) + protected override Drawable CreateDefault(ISkinComponentLookup lookup) { var drawable = base.CreateDefault(lookup); diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs index 39e07ebb99..60cfecfb5a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default Colour = Color4.White.Opacity(0.5f), }, }, - number = new SkinnableSpriteText(new OsuSkinLookup(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText + number = new SkinnableSpriteText(new OsuSkinComponentLookup(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText { Font = OsuFont.Numeric.With(size: 40), UseFullGlyphHeight = false, diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs index 338e7abcfc..222e8d4348 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); - Child = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon + Child = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon { RelativeSizeAxes = Axes.Both, Blending = BlendingParameters.Additive, diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs index 20a1e3064e..4dd4f9562a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy accentColour.BindValueChanged(colour => Colour = LegacyColourCompatibility.DisallowZeroAlpha(colour.NewValue), true); } - protected override Drawable CreateDefault(ISkinLookup lookup) + protected override Drawable CreateDefault(ISkinComponentLookup lookup) { var drawable = base.CreateDefault(lookup); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index 357be4cda8..e155c1b816 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (hasNumber) { - OverlayLayer.Add(hitCircleText = new SkinnableSpriteText(new OsuSkinLookup(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText + OverlayLayer.Add(hitCircleText = new SkinnableSpriteText(new OsuSkinComponentLookup(OsuSkinComponents.HitCircleText), _ => new OsuSpriteText { Font = OsuFont.Numeric.With(size: 40), UseFullGlyphHeight = false, diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index f374af1cba..773cc7ae3c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { AutoSizeAxes = Axes.Both; - string lookupName = new OsuSkinLookup(OsuSkinComponents.ReverseArrow).LookupName; + string lookupName = new OsuSkinComponentLookup(OsuSkinComponents.ReverseArrow).LookupName; var skin = skinSource.FindProvider(s => s.GetTexture(lookupName) != null); InternalChild = skin?.GetAnimation(lookupName, true, true) ?? Empty(); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 2faa2d678e..ab0e9ab1c0 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -28,9 +28,9 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy hasHitCircle = new Lazy(() => GetTexture("hitcircle") != null); } - public override Drawable? GetDrawableComponent(ISkinLookup lookup) + public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { - if (lookup is OsuSkinLookup osuComponent) + if (lookup is OsuSkinComponentLookup osuComponent) { switch (osuComponent.Component) { diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs index 78b920c771..6d435f01b0 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs @@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, Anchor = Anchor.Centre, - Child = cursorSprite = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling) + Child = cursorSprite = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.Cursor), _ => new DefaultCursor(), confineMode: ConfineMode.NoScaling) { Origin = Anchor.Centre, Anchor = Anchor.Centre, diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 396492c104..26fe08972e 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -47,8 +47,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor RelativeSizeAxes = Axes.Both, Children = new[] { - cursorTrail = new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling), - new SkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.CursorParticles), confineMode: ConfineMode.NoScaling), + cursorTrail = new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.CursorTrail), _ => new DefaultCursorTrail(), confineMode: ConfineMode.NoScaling), + new SkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.CursorParticles), confineMode: ConfineMode.NoScaling), } }; } diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index 2616bb0325..bf5618dc90 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.UI { if (e.Action == OsuAction.Smoke) { - AddInternal(currentSegmentSkinnable = new SmokeSkinnableDrawable(new OsuSkinLookup(OsuSkinComponents.CursorSmoke), _ => new DefaultSmokeSegment())); + AddInternal(currentSegmentSkinnable = new SmokeSkinnableDrawable(new OsuSkinComponentLookup(OsuSkinComponents.CursorSmoke), _ => new DefaultSmokeSegment())); // Add initial position immediately. addPosition(); @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.UI public override double LifetimeStart => Drawable.LifetimeStart; public override double LifetimeEnd => Drawable.LifetimeEnd; - public SmokeSkinnableDrawable(ISkinLookup lookup, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) + public SmokeSkinnableDrawable(ISkinComponentLookup lookup, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) : base(lookup, defaultImplementation, confineMode) { } diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs index 3076172d46..a9304b01ad 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning public TestSceneTaikoScroller() { AddStep("Load scroller", () => SetContents(_ => - new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.Scroller), _ => Empty()) + new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Scroller), _ => Empty()) { Clock = new FramedClock(clock), Height = 0.4f, diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs index 715add7914..f6c541982e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables AddRangeInternal(new Drawable[] { - line = new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.BarLine), _ => new Box + line = new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.BarLine), _ => new Box { RelativeSizeAxes = Axes.Both, EdgeSmoothness = new Vector2(0.5f, 0), diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index f5ebecdee5..0bb14c791e 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -115,7 +115,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables return base.CreateNestedHitObject(hitObject); } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.DrumRollBody), + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollBody), _ => new ElongatedCirclePiece()); public override bool OnPressed(KeyBindingPressEvent e) => false; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index 1ec2562f67..8dbcbf1ffc 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables FillMode = FillMode.Fit; } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.DrumRollTick), + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollTick), _ => new TickPiece { Filled = HitObject.FirstTick diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 0fe17f81f5..1e39c69acf 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -90,8 +90,8 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } protected override SkinnableDrawable CreateMainPiece() => HitObject.Type == HitType.Centre - ? new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.CentreHit), _ => new CentreHitCirclePiece(), confineMode: ConfineMode.ScaleToFit) - : new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.RimHit), _ => new RimHitCirclePiece(), confineMode: ConfineMode.ScaleToFit); + ? new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.CentreHit), _ => new CentreHitCirclePiece(), confineMode: ConfineMode.ScaleToFit) + : new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.RimHit), _ => new RimHitCirclePiece(), confineMode: ConfineMode.ScaleToFit); public override IEnumerable GetSamples() { diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 5b498e4cb3..753f85f23f 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables targetRing.BorderColour = colours.YellowDark.Opacity(0.25f); } - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.Swell), + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Swell), _ => new SwellCirclePiece { // to allow for rotation transform diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index 4d915c91d3..5d44fce254 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables public override bool OnPressed(KeyBindingPressEvent e) => false; - protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.DrumRollTick), + protected override SkinnableDrawable CreateMainPiece() => new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.DrumRollTick), _ => new TickPiece()); } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 6cf7d3da0a..7bf99306f0 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -27,16 +27,16 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy hasExplosion = new Lazy(() => GetTexture(getHitName(TaikoSkinComponents.TaikoExplosionGreat)) != null); } - public override Drawable? GetDrawableComponent(ISkinLookup lookup) + public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { - if (lookup is GameplaySkinLookup) + if (lookup is GameplaySkinComponentLookup) { // if a taiko skin is providing explosion sprites, hide the judgements completely if (hasExplosion.Value) return Drawable.Empty().With(d => d.Expire()); } - if (lookup is TaikoSkinLookup taikoComponent) + if (lookup is TaikoSkinComponentLookup taikoComponent) { switch (taikoComponent.Component) { diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinLookup.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponentLookup.cs similarity index 73% rename from osu.Game.Rulesets.Taiko/TaikoSkinLookup.cs rename to osu.Game.Rulesets.Taiko/TaikoSkinComponentLookup.cs index cb8bbd8b18..c35971e9fd 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinLookup.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponentLookup.cs @@ -5,9 +5,9 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko { - public class TaikoSkinLookup : GameplaySkinLookup + public class TaikoSkinComponentLookup : GameplaySkinComponentLookup { - public TaikoSkinLookup(TaikoSkinComponents component) + public TaikoSkinComponentLookup(TaikoSkinComponents component) : base(component) { } diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index db45c8bb70..c3d93a344d 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Taiko.UI { new BarLineGenerator(Beatmap).BarLines.ForEach(bar => Playfield.Add(bar)); - FrameStableComponents.Add(scroller = new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.Scroller), _ => Empty()) + FrameStableComponents.Add(scroller = new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Scroller), _ => Empty()) { RelativeSizeAxes = Axes.X, Depth = float.MaxValue diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 560f7b1748..d2b5811b56 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load() { - InternalChild = skinnable = new SkinnableDrawable(new TaikoSkinLookup(getComponentName(result)), _ => new DefaultHitExplosion(result)); + InternalChild = skinnable = new SkinnableDrawable(new TaikoSkinComponentLookup(getComponentName(result)), _ => new DefaultHitExplosion(result)); skinnable.OnSkinChanged += runAnimation; } diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 4458fb1bc0..2f42a5aaf6 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.UI { Children = new Drawable[] { - new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.InputDrum), _ => new DefaultInputDrum()) + new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.InputDrum), _ => new DefaultInputDrum()) { RelativeSizeAxes = Axes.Y, AutoSizeAxes = Axes.X, diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index b0d853f1f1..d2427b952c 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Taiko.UI [BackgroundDependencyLoader] private void load() { - Child = skinnable = new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.TaikoExplosionKiai), _ => new DefaultKiaiHitExplosion(hitType)); + Child = skinnable = new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.TaikoExplosionKiai), _ => new DefaultKiaiHitExplosion(hitType)); } } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 0de7bf233d..11349d8bd3 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Taiko.UI InternalChildren = new[] { - new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.PlayfieldBackgroundRight), _ => new PlayfieldBackgroundRight()), + new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.PlayfieldBackgroundRight), _ => new PlayfieldBackgroundRight()), new Container { Name = "Left overlay", @@ -86,11 +86,11 @@ namespace osu.Game.Rulesets.Taiko.UI BorderColour = colours.Gray0, Children = new[] { - new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.PlayfieldBackgroundLeft), _ => new PlayfieldBackgroundLeft()), + new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.PlayfieldBackgroundLeft), _ => new PlayfieldBackgroundLeft()), inputDrum.CreateProxy(), } }, - mascot = new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.Mascot), _ => Empty()) + mascot = new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.Mascot), _ => Empty()) { Origin = Anchor.BottomLeft, Anchor = Anchor.TopLeft, @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Taiko.UI { RelativeSizeAxes = Axes.Both, }, - HitTarget = new SkinnableDrawable(new TaikoSkinLookup(TaikoSkinComponents.HitTarget), _ => new TaikoHitTarget()) + HitTarget = new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.HitTarget), _ => new TaikoHitTarget()) { RelativeSizeAxes = Axes.Both, } diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs index fc72fddcae..cccf640e27 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -126,7 +126,7 @@ namespace osu.Game.Tests.Gameplay Color4.Green }; - public Drawable GetDrawableComponent(ISkinLookup lookup) => throw new NotImplementedException(); + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => throw new NotImplementedException(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs index 9e03663a49..5c247bace9 100644 --- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs @@ -73,7 +73,7 @@ namespace osu.Game.Tests.NonVisual.Skinning return lookup_names.Contains(componentName) ? renderer.WhitePixel : null; } - public Drawable GetDrawableComponent(ISkinLookup lookup) => throw new NotSupportedException(); + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => throw new NotSupportedException(); public ISample GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException(); public IBindable GetConfig(TLookup lookup) => throw new NotSupportedException(); } diff --git a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs index 6f14b933ee..a29fc9f1fb 100644 --- a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs +++ b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs @@ -78,7 +78,7 @@ namespace osu.Game.Tests.Rulesets OnLoadAsync?.Invoke(); } - public Drawable GetDrawableComponent(ISkinLookup lookup) => skin.GetDrawableComponent(lookup); + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => skin.GetDrawableComponent(lookup); public Texture GetTexture(string componentName, WrapMode wrapModeS = default, WrapMode wrapModeT = default) => skin.GetTexture(componentName); diff --git a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs index 4398d870a0..cd6895b176 100644 --- a/osu.Game.Tests/Skins/SkinDeserialisationTest.cs +++ b/osu.Game.Tests/Skins/SkinDeserialisationTest.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Skins var skin = new TestSkin(new SkinInfo(), null, storage); Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2)); - Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(9)); + Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(9)); } } @@ -93,10 +93,10 @@ namespace osu.Game.Tests.Skins var skin = new TestSkin(new SkinInfo(), null, storage); Assert.That(skin.DrawableComponentInfo, Has.Count.EqualTo(2)); - Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(6)); - Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.SongSelect], Has.Length.EqualTo(1)); + Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(6)); + Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.SongSelect], Has.Length.EqualTo(1)); - var skinnableInfo = skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.SongSelect].First(); + var skinnableInfo = skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.SongSelect].First(); Assert.That(skinnableInfo.Type, Is.EqualTo(typeof(SkinnableSprite))); Assert.That(skinnableInfo.Settings.First().Key, Is.EqualTo("sprite_name")); @@ -107,10 +107,10 @@ namespace osu.Game.Tests.Skins using (var storage = new ZipArchiveReader(stream)) { var skin = new TestSkin(new SkinInfo(), null, storage); - Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(8)); - Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); - Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); - Assert.That(skin.DrawableComponentInfo[GlobalSkinLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); + Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents], Has.Length.EqualTo(8)); + Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(UnstableRateCounter))); + Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(ColourHitErrorMeter))); + Assert.That(skin.DrawableComponentInfo[GlobalSkinComponentLookup.LookupType.MainHUDComponents].Select(i => i.Type), Contains.Item(typeof(LegacySongProgress))); } } diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs index 7c02d34b1c..a31c624f78 100644 --- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs +++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Skins string expected = allowBeatmapLookups ? "beatmap" : "user"; - AddAssert($"Check lookup is from {expected}", () => requester.GetDrawableComponent(new TestSkinLookup())?.Name == expected); + AddAssert($"Check lookup is from {expected}", () => requester.GetDrawableComponent(new TestSkinComponentLookup())?.Name == expected); } [TestCase(false)] @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Skins ISkin expected() => allowBeatmapLookups ? beatmapSource : userSource; - AddAssert("Check lookup is from correct source", () => requester.FindProvider(s => s.GetDrawableComponent(new TestSkinLookup()) != null) == expected()); + AddAssert("Check lookup is from correct source", () => requester.FindProvider(s => s.GetDrawableComponent(new TestSkinComponentLookup()) != null) == expected()); } public class UserSkinSource : LegacySkin @@ -69,7 +69,7 @@ namespace osu.Game.Tests.Skins { } - public override Drawable GetDrawableComponent(ISkinLookup lookup) + public override Drawable GetDrawableComponent(ISkinComponentLookup lookup) { return new Container { Name = "user" }; } @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Skins { } - public override Drawable GetDrawableComponent(ISkinLookup lookup) + public override Drawable GetDrawableComponent(ISkinComponentLookup lookup) { return new Container { Name = "beatmap" }; } @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Skins this.skin = skin; } - public Drawable GetDrawableComponent(ISkinLookup lookup) => skin.GetDrawableComponent(lookup); + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => skin.GetDrawableComponent(lookup); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT); @@ -109,7 +109,7 @@ namespace osu.Game.Tests.Skins public ISkin FindProvider(Func lookupFunction) => skin.FindProvider(lookupFunction); } - private class TestSkinLookup : ISkinLookup + private class TestSkinComponentLookup : ISkinComponentLookup { public string LookupName => string.Empty; } diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index 4cbc1cf4df..8c6f137dc0 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -221,7 +221,7 @@ namespace osu.Game.Tests.Skins this.skin = skin; } - public Drawable GetDrawableComponent(ISkinLookup lookup) => skin.GetDrawableComponent(lookup); + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => skin.GetDrawableComponent(lookup); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT); diff --git a/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs b/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs index 712d5ce969..ad71296a11 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Skins this.renderer = renderer; } - public Drawable GetDrawableComponent(ISkinLookup lookup) => throw new System.NotImplementedException(); + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => throw new System.NotImplementedException(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 69a50a1cd1..8ad97eb33c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -40,7 +40,7 @@ namespace osu.Game.Tests.Visual.Gameplay { CreateSkinTest(TrianglesSkin.CreateInfo(), () => new LegacyBeatmapSkin(new BeatmapInfo(), null)); AddUntilStep("wait for hud load", () => Player.ChildrenOfType().All(c => c.ComponentsLoaded)); - AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(GlobalSkinLookup.LookupType.MainHUDComponents, skinManager.CurrentSkin.Value)); + AddAssert("hud from default skin", () => AssertComponentsFromExpectedSource(GlobalSkinComponentLookup.LookupType.MainHUDComponents, skinManager.CurrentSkin.Value)); } protected void CreateSkinTest(SkinInfo gameCurrentSkin, Func getBeatmapSkin) @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Gameplay }); } - protected bool AssertComponentsFromExpectedSource(GlobalSkinLookup.LookupType target, ISkin expectedSource) + protected bool AssertComponentsFromExpectedSource(GlobalSkinComponentLookup.LookupType target, ISkin expectedSource) { var actualComponentsContainer = Player.ChildrenOfType().First(s => s.Target == target) .ChildrenOfType().SingleOrDefault(); @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual.Gameplay var actualInfo = actualComponentsContainer.CreateSkinnableInfo(); - var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource.GetDrawableComponent(new GlobalSkinLookup(target)); + var expectedComponentsContainer = (SkinnableTargetComponentsContainer)expectedSource.GetDrawableComponent(new GlobalSkinComponentLookup(target)); if (expectedComponentsContainer == null) return false; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs index 81c5211878..e050273652 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs @@ -164,7 +164,7 @@ namespace osu.Game.Tests.Visual.Gameplay { private bool allow = true; - protected override bool AllowDrawableLookup(ISkinLookup lookup) => allow; + protected override bool AllowDrawableLookup(ISkinComponentLookup lookup) => allow; public void Disable() { @@ -182,8 +182,8 @@ namespace osu.Game.Tests.Visual.Gameplay { public new Drawable Drawable => base.Drawable; - public ExposedSkinnableDrawable(string name, Func defaultImplementation, ConfineMode confineMode = ConfineMode.ScaleToFit) - : base(new TestSkinLookup(name), defaultImplementation, confineMode) + public ExposedSkinnableDrawable(string name, Func defaultImplementation, ConfineMode confineMode = ConfineMode.ScaleToFit) + : base(new TestSkinComponentLookup(name), defaultImplementation, confineMode) { } } @@ -251,8 +251,8 @@ namespace osu.Game.Tests.Visual.Gameplay public new Drawable Drawable => base.Drawable; public int SkinChangedCount { get; private set; } - public SkinConsumer(string name, Func defaultImplementation) - : base(new TestSkinLookup(name), defaultImplementation) + public SkinConsumer(string name, Func defaultImplementation) + : base(new TestSkinComponentLookup(name), defaultImplementation) { } @@ -288,8 +288,8 @@ namespace osu.Game.Tests.Visual.Gameplay this.size = size; } - public Drawable GetDrawableComponent(ISkinLookup lookupName) => - lookupName.LookupName == "available" + public Drawable GetDrawableComponent(ISkinComponentLookup componentLookupName) => + componentLookupName.LookupName == "available" ? new DrawWidthBox { Colour = Color4.Yellow, @@ -306,7 +306,7 @@ namespace osu.Game.Tests.Visual.Gameplay private class SecondarySource : ISkin { - public Drawable GetDrawableComponent(ISkinLookup lookupName) => new SecondarySourceBox(); + public Drawable GetDrawableComponent(ISkinComponentLookup componentLookupName) => new SecondarySourceBox(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); @@ -318,7 +318,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Cached(typeof(ISkinSource))] private class SkinSourceContainer : Container, ISkinSource { - public Drawable GetDrawableComponent(ISkinLookup lookupName) => new BaseSourceBox(); + public Drawable GetDrawableComponent(ISkinComponentLookup componentLookupName) => new BaseSourceBox(); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException(); @@ -337,9 +337,9 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class TestSkinLookup : ISkinLookup + private class TestSkinComponentLookup : ISkinComponentLookup { - public TestSkinLookup(string name) + public TestSkinComponentLookup(string name) { LookupName = name; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs index 43206ac591..8122d8defb 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs @@ -142,7 +142,7 @@ namespace osu.Game.Tests.Visual.Gameplay IBindable ISamplePlaybackDisabler.SamplePlaybackDisabled => SamplePlaybackDisabled; - public Drawable GetDrawableComponent(ISkinLookup lookup) => source?.GetDrawableComponent(lookup); + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => source?.GetDrawableComponent(lookup); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => source?.GetTexture(componentName, wrapModeS, wrapModeT); public ISample GetSample(ISampleInfo sampleInfo) => source?.GetSample(sampleInfo); public IBindable GetConfig(TLookup lookup) => source?.GetConfig(lookup); diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index bfcdd384a0..6fc1deaf11 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -167,7 +167,7 @@ namespace osu.Game.Rulesets.Judgements if (JudgementBody != null) RemoveInternal(JudgementBody, true); - AddInternal(JudgementBody = new SkinnableDrawable(new GameplaySkinLookup(type), _ => + AddInternal(JudgementBody = new SkinnableDrawable(new GameplaySkinComponentLookup(type), _ => CreateDefaultJudgement(type), confineMode: ConfineMode.NoScaling) { Anchor = Anchor.Centre, diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index bc63ad063c..80239504d8 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -53,7 +53,7 @@ namespace osu.Game.Screens.Edit #region Delegated ISkin implementation - public Drawable GetDrawableComponent(ISkinLookup lookup) => Skin.GetDrawableComponent(lookup); + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => Skin.GetDrawableComponent(lookup); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => Skin.GetTexture(componentName, wrapModeS, wrapModeT); public ISample GetSample(ISampleInfo sampleInfo) => Skin.GetSample(sampleInfo); public IBindable GetConfig(TLookup lookup) => Skin.GetConfig(lookup); diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 932ebe7d18..fa38eeb9aa 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -391,7 +391,7 @@ namespace osu.Game.Screens.Play private OsuConfigManager config { get; set; } public MainComponentsContainer() - : base(GlobalSkinLookup.LookupType.MainHUDComponents) + : base(GlobalSkinComponentLookup.LookupType.MainHUDComponents) { RelativeSizeAxes = Axes.Both; } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index e525d5a368..1add51e725 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -250,7 +250,7 @@ namespace osu.Game.Screens.Select } } }, - new SkinnableTargetContainer(GlobalSkinLookup.LookupType.SongSelect) + new SkinnableTargetContainer(GlobalSkinComponentLookup.LookupType.SongSelect) { RelativeSizeAxes = Axes.Both, }, diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 7aaf1a0e89..c3361093a9 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -81,17 +81,17 @@ namespace osu.Game.Skinning return null; } - public override Drawable? GetDrawableComponent(ISkinLookup lookup) + public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { if (base.GetDrawableComponent(lookup) is Drawable c) return c; switch (lookup) { - case GlobalSkinLookup globalLookup: + case GlobalSkinComponentLookup globalLookup: switch (globalLookup.Lookup) { - case GlobalSkinLookup.LookupType.SongSelect: + case GlobalSkinComponentLookup.LookupType.SongSelect: var songSelectComponents = new SkinnableTargetComponentsContainer(_ => { // do stuff when we need to. @@ -99,7 +99,7 @@ namespace osu.Game.Skinning return songSelectComponents; - case GlobalSkinLookup.LookupType.MainHUDComponents: + case GlobalSkinComponentLookup.LookupType.MainHUDComponents: var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); diff --git a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs index ec9d52f5c6..e14287c318 100644 --- a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs +++ b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs @@ -43,7 +43,7 @@ namespace osu.Game.Skinning } } - protected override bool AllowDrawableLookup(ISkinLookup lookup) + protected override bool AllowDrawableLookup(ISkinComponentLookup lookup) { if (beatmapSkins == null) throw new InvalidOperationException($"{nameof(BeatmapSkinProvidingContainer)} needs to be loaded before being consumed."); diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index fdc8b6b2ad..410f5d9347 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -314,7 +314,7 @@ namespace osu.Game.Skinning.Editor private ISkinnableTarget getFirstTarget() => availableTargets.FirstOrDefault(); - private ISkinnableTarget getTarget(GlobalSkinLookup.LookupType target) + private ISkinnableTarget getTarget(GlobalSkinComponentLookup.LookupType target) { return availableTargets.FirstOrDefault(c => c.Target == target); } diff --git a/osu.Game/Skinning/GameplaySkinLookup.cs b/osu.Game/Skinning/GameplaySkinComponentLookup.cs similarity index 83% rename from osu.Game/Skinning/GameplaySkinLookup.cs rename to osu.Game/Skinning/GameplaySkinComponentLookup.cs index cec9dbde7d..2d1dec4691 100644 --- a/osu.Game/Skinning/GameplaySkinLookup.cs +++ b/osu.Game/Skinning/GameplaySkinComponentLookup.cs @@ -5,12 +5,12 @@ using System.Linq; namespace osu.Game.Skinning { - public class GameplaySkinLookup : ISkinLookup + public class GameplaySkinComponentLookup : ISkinComponentLookup where T : notnull { public readonly T Component; - public GameplaySkinLookup(T component) + public GameplaySkinComponentLookup(T component) { Component = component; } diff --git a/osu.Game/Skinning/GlobalSkinLookup.cs b/osu.Game/Skinning/GlobalSkinComponentLookup.cs similarity index 78% rename from osu.Game/Skinning/GlobalSkinLookup.cs rename to osu.Game/Skinning/GlobalSkinComponentLookup.cs index c63c0315a3..3d8b61eba2 100644 --- a/osu.Game/Skinning/GlobalSkinLookup.cs +++ b/osu.Game/Skinning/GlobalSkinComponentLookup.cs @@ -3,13 +3,13 @@ namespace osu.Game.Skinning { - public class GlobalSkinLookup : ISkinLookup + public class GlobalSkinComponentLookup : ISkinComponentLookup { public readonly LookupType Lookup; public string LookupName => Lookup.ToString(); - public GlobalSkinLookup(LookupType lookup) + public GlobalSkinComponentLookup(LookupType lookup) { Lookup = lookup; } diff --git a/osu.Game/Skinning/ISkin.cs b/osu.Game/Skinning/ISkin.cs index c352dfef5c..45be5582f6 100644 --- a/osu.Game/Skinning/ISkin.cs +++ b/osu.Game/Skinning/ISkin.cs @@ -19,7 +19,7 @@ namespace osu.Game.Skinning /// /// The requested component. /// A drawable representation for the requested component, or null if unavailable. - Drawable? GetDrawableComponent(ISkinLookup lookup); + Drawable? GetDrawableComponent(ISkinComponentLookup lookup); /// /// Retrieve a . diff --git a/osu.Game/Skinning/ISkinLookup.cs b/osu.Game/Skinning/ISkinComponentLookup.cs similarity index 88% rename from osu.Game/Skinning/ISkinLookup.cs rename to osu.Game/Skinning/ISkinComponentLookup.cs index 4daea35e82..ae56fb0b1c 100644 --- a/osu.Game/Skinning/ISkinLookup.cs +++ b/osu.Game/Skinning/ISkinComponentLookup.cs @@ -11,10 +11,10 @@ namespace osu.Game.Skinning /// to scope particular lookup variations. Using this, a ruleset or skin implementation could make its own lookup /// type to scope away from more global contexts. /// - /// More commonly, a ruleset could make use of to do a simple lookup based on + /// More commonly, a ruleset could make use of to do a simple lookup based on /// a provided enum. /// - public interface ISkinLookup + public interface ISkinComponentLookup { string LookupName { get; } } diff --git a/osu.Game/Skinning/ISkinnableTarget.cs b/osu.Game/Skinning/ISkinnableTarget.cs index b1a0f6714b..57c78bfe1c 100644 --- a/osu.Game/Skinning/ISkinnableTarget.cs +++ b/osu.Game/Skinning/ISkinnableTarget.cs @@ -18,7 +18,7 @@ namespace osu.Game.Skinning /// /// The definition of this target. /// - GlobalSkinLookup.LookupType Target { get; } + GlobalSkinComponentLookup.LookupType Target { get; } /// /// A bindable list of components which are being tracked by this skinnable target. diff --git a/osu.Game/Skinning/LegacyBeatmapSkin.cs b/osu.Game/Skinning/LegacyBeatmapSkin.cs index 1d6ded6fee..8407b144f8 100644 --- a/osu.Game/Skinning/LegacyBeatmapSkin.cs +++ b/osu.Game/Skinning/LegacyBeatmapSkin.cs @@ -43,13 +43,13 @@ namespace osu.Game.Skinning return new RealmBackedResourceStore(beatmapInfo.BeatmapSet.ToLive(resources.RealmAccess), resources.Files, resources.RealmAccess); } - public override Drawable? GetDrawableComponent(ISkinLookup lookup) + public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { - if (lookup is GlobalSkinLookup targetComponent) + if (lookup is GlobalSkinComponentLookup targetComponent) { switch (targetComponent.Lookup) { - case GlobalSkinLookup.LookupType.MainHUDComponents: + case GlobalSkinComponentLookup.LookupType.MainHUDComponents: // this should exist in LegacySkin instead, but there isn't a fallback skin for LegacySkins yet. // therefore keep the check here until fallback default legacy skin is supported. if (!this.HasFont(LegacyFont.Score)) diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 75957bb560..98618e3dcd 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -322,17 +322,17 @@ namespace osu.Game.Skinning return null; } - public override Drawable? GetDrawableComponent(ISkinLookup lookup) + public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { if (base.GetDrawableComponent(lookup) is Drawable c) return c; switch (lookup) { - case GlobalSkinLookup target: + case GlobalSkinComponentLookup target: switch (target.Lookup) { - case GlobalSkinLookup.LookupType.MainHUDComponents: + case GlobalSkinComponentLookup.LookupType.MainHUDComponents: var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); @@ -379,7 +379,7 @@ namespace osu.Game.Skinning return null; - case GameplaySkinLookup resultComponent: + case GameplaySkinComponentLookup resultComponent: // kind of wasteful that we throw this away, but should do for now. if (getJudgementAnimation(resultComponent.Component) != null) @@ -397,7 +397,7 @@ namespace osu.Game.Skinning return null; - case SkinnableSprite.SpriteLookup sprite: + case SkinnableSprite.SpriteComponentLookup sprite: return this.GetAnimation(sprite.LookupName, false, false); } diff --git a/osu.Game/Skinning/ResourceStoreBackedSkin.cs b/osu.Game/Skinning/ResourceStoreBackedSkin.cs index 1b846438f5..f5c6192ba5 100644 --- a/osu.Game/Skinning/ResourceStoreBackedSkin.cs +++ b/osu.Game/Skinning/ResourceStoreBackedSkin.cs @@ -27,7 +27,7 @@ namespace osu.Game.Skinning samples = audio.GetSampleStore(new NamespacedResourceStore(resources, @"Samples")); } - public Drawable? GetDrawableComponent(ISkinLookup lookup) => null; + public Drawable? GetDrawableComponent(ISkinComponentLookup lookup) => null; public Texture? GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => textures.Get(componentName, wrapModeS, wrapModeT); diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index 67b74229bb..e222b9017c 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -37,9 +37,9 @@ namespace osu.Game.Skinning public SkinConfiguration Configuration { get; set; } - public IDictionary DrawableComponentInfo => drawableComponentInfo; + public IDictionary DrawableComponentInfo => drawableComponentInfo; - private readonly Dictionary drawableComponentInfo = new Dictionary(); + private readonly Dictionary drawableComponentInfo = new Dictionary(); public abstract ISample? GetSample(ISampleInfo sampleInfo); @@ -97,7 +97,7 @@ namespace osu.Game.Skinning Configuration = new SkinConfiguration(); // skininfo files may be null for default skin. - foreach (GlobalSkinLookup.LookupType skinnableTarget in Enum.GetValues(typeof(GlobalSkinLookup.LookupType))) + foreach (GlobalSkinComponentLookup.LookupType skinnableTarget in Enum.GetValues(typeof(GlobalSkinComponentLookup.LookupType))) { string filename = $"{skinnableTarget}.json"; @@ -154,11 +154,11 @@ namespace osu.Game.Skinning DrawableComponentInfo[targetContainer.Target] = targetContainer.CreateSkinnableInfo().ToArray(); } - public virtual Drawable? GetDrawableComponent(ISkinLookup lookup) + public virtual Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { switch (lookup) { - case GlobalSkinLookup target: + case GlobalSkinComponentLookup target: if (!DrawableComponentInfo.TryGetValue(target.Lookup, out var skinnableInfo)) return null; diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index bd4078b985..4a5277f3bf 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -201,7 +201,7 @@ namespace osu.Game.Skinning public event Action SourceChanged; - public Drawable GetDrawableComponent(ISkinLookup lookup) => lookupWithFallback(s => s.GetDrawableComponent(lookup)); + public Drawable GetDrawableComponent(ISkinComponentLookup lookup) => lookupWithFallback(s => s.GetDrawableComponent(lookup)); public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => lookupWithFallback(s => s.GetTexture(componentName, wrapModeS, wrapModeT)); diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index 0ed5c6b736..e7d0683005 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -28,7 +28,7 @@ namespace osu.Game.Skinning /// protected virtual bool AllowFallingBackToParent => true; - protected virtual bool AllowDrawableLookup(ISkinLookup lookup) => true; + protected virtual bool AllowDrawableLookup(ISkinComponentLookup lookup) => true; protected virtual bool AllowTextureLookup(string componentName) => true; @@ -107,7 +107,7 @@ namespace osu.Game.Skinning } } - public Drawable? GetDrawableComponent(ISkinLookup lookup) + public Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { foreach (var (_, lookupWrapper) in skinSources) { @@ -238,7 +238,7 @@ namespace osu.Game.Skinning this.provider = provider; } - public Drawable? GetDrawableComponent(ISkinLookup lookup) + public Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { if (provider.AllowDrawableLookup(lookup)) return skin.GetDrawableComponent(lookup); diff --git a/osu.Game/Skinning/SkinTransformer.cs b/osu.Game/Skinning/SkinTransformer.cs index 9772d98fde..e05961d404 100644 --- a/osu.Game/Skinning/SkinTransformer.cs +++ b/osu.Game/Skinning/SkinTransformer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Skinning Skin = skin ?? throw new ArgumentNullException(nameof(skin)); } - public virtual Drawable? GetDrawableComponent(ISkinLookup lookup) => Skin.GetDrawableComponent(lookup); + public virtual Drawable? GetDrawableComponent(ISkinComponentLookup lookup) => Skin.GetDrawableComponent(lookup); public virtual Texture? GetTexture(string componentName) => GetTexture(componentName, default, default); diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs index 4398dda413..15d371cdd5 100644 --- a/osu.Game/Skinning/SkinnableDrawable.cs +++ b/osu.Game/Skinning/SkinnableDrawable.cs @@ -31,7 +31,7 @@ namespace osu.Game.Skinning set => base.AutoSizeAxes = value; } - protected readonly ISkinLookup Lookup; + protected readonly ISkinComponentLookup ComponentLookup; private readonly ConfineMode confineMode; @@ -41,15 +41,15 @@ namespace osu.Game.Skinning /// The namespace-complete resource name for this skinnable element. /// A function to create the default skin implementation of this element. /// How (if at all) the should be resize to fit within our own bounds. - public SkinnableDrawable(ISkinLookup lookup, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) + public SkinnableDrawable(ISkinComponentLookup lookup, Func? defaultImplementation = null, ConfineMode confineMode = ConfineMode.NoScaling) : this(lookup, confineMode) { createDefault = defaultImplementation; } - protected SkinnableDrawable(ISkinLookup lookup, ConfineMode confineMode = ConfineMode.NoScaling) + protected SkinnableDrawable(ISkinComponentLookup lookup, ConfineMode confineMode = ConfineMode.NoScaling) { - Lookup = lookup; + ComponentLookup = lookup; this.confineMode = confineMode; RelativeSizeAxes = Axes.Both; @@ -60,13 +60,13 @@ namespace osu.Game.Skinning /// public void ResetAnimation() => (Drawable as IFramedAnimation)?.GotoFrame(0); - private readonly Func? createDefault; + private readonly Func? createDefault; private readonly Cached scaling = new Cached(); private bool isDefault; - protected virtual Drawable CreateDefault(ISkinLookup lookup) => createDefault?.Invoke(lookup) ?? Empty(); + protected virtual Drawable CreateDefault(ISkinComponentLookup lookup) => createDefault?.Invoke(lookup) ?? Empty(); /// /// Whether to apply size restrictions (specified via ) to the default implementation. @@ -75,11 +75,11 @@ namespace osu.Game.Skinning protected override void SkinChanged(ISkinSource skin) { - var retrieved = skin.GetDrawableComponent(Lookup); + var retrieved = skin.GetDrawableComponent(ComponentLookup); if (retrieved == null) { - Drawable = CreateDefault(Lookup); + Drawable = CreateDefault(ComponentLookup); isDefault = true; } else diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 8f456fce0a..43fec11b14 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -34,26 +34,26 @@ namespace osu.Game.Skinning private ISkinSource source { get; set; } = null!; public SkinnableSprite(string textureName, ConfineMode confineMode = ConfineMode.NoScaling) - : base(new SpriteLookup(textureName), confineMode) + : base(new SpriteComponentLookup(textureName), confineMode) { SpriteName.Value = textureName; } public SkinnableSprite() - : base(new SpriteLookup(string.Empty), ConfineMode.NoScaling) + : base(new SpriteComponentLookup(string.Empty), ConfineMode.NoScaling) { RelativeSizeAxes = Axes.None; AutoSizeAxes = Axes.Both; SpriteName.BindValueChanged(name => { - ((SpriteLookup)Lookup).LookupName = name.NewValue ?? string.Empty; + ((SpriteComponentLookup)ComponentLookup).LookupName = name.NewValue ?? string.Empty; if (IsLoaded) SkinChanged(CurrentSkin); }); } - protected override Drawable CreateDefault(ISkinLookup lookup) + protected override Drawable CreateDefault(ISkinComponentLookup lookup) { var texture = textures.Get(lookup.LookupName); @@ -65,11 +65,11 @@ namespace osu.Game.Skinning public bool UsesFixedAnchor { get; set; } - internal class SpriteLookup : ISkinLookup + internal class SpriteComponentLookup : ISkinComponentLookup { public string LookupName { get; set; } - public SpriteLookup(string textureName) + public SpriteComponentLookup(string textureName) { LookupName = textureName; } diff --git a/osu.Game/Skinning/SkinnableSpriteText.cs b/osu.Game/Skinning/SkinnableSpriteText.cs index 8cc48a76ed..c01cec2f0c 100644 --- a/osu.Game/Skinning/SkinnableSpriteText.cs +++ b/osu.Game/Skinning/SkinnableSpriteText.cs @@ -9,7 +9,7 @@ namespace osu.Game.Skinning { public class SkinnableSpriteText : SkinnableDrawable, IHasText { - public SkinnableSpriteText(ISkinLookup lookup, Func defaultImplementation, ConfineMode confineMode = ConfineMode.NoScaling) + public SkinnableSpriteText(ISkinComponentLookup lookup, Func defaultImplementation, ConfineMode confineMode = ConfineMode.NoScaling) : base(lookup, defaultImplementation, confineMode) { } diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index bea29b0da3..a8038f5f5c 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -13,7 +13,7 @@ namespace osu.Game.Skinning { private SkinnableTargetComponentsContainer? content; - public GlobalSkinLookup.LookupType Target { get; } + public GlobalSkinComponentLookup.LookupType Target { get; } public IBindableList Components => components; @@ -25,7 +25,7 @@ namespace osu.Game.Skinning private CancellationTokenSource? cancellationSource; - public SkinnableTargetContainer(GlobalSkinLookup.LookupType target) + public SkinnableTargetContainer(GlobalSkinComponentLookup.LookupType target) { Target = target; } @@ -39,7 +39,7 @@ namespace osu.Game.Skinning components.Clear(); ComponentsLoaded = false; - content = CurrentSkin.GetDrawableComponent(new GlobalSkinLookup(Target)) as SkinnableTargetComponentsContainer; + content = CurrentSkin.GetDrawableComponent(new GlobalSkinComponentLookup(Target)) as SkinnableTargetComponentsContainer; cancellationSource?.Cancel(); cancellationSource = null; diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index e3729136b9..3df85b6880 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -59,17 +59,17 @@ namespace osu.Game.Skinning return null; } - public override Drawable? GetDrawableComponent(ISkinLookup lookup) + public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { if (base.GetDrawableComponent(lookup) is Drawable c) return c; switch (lookup) { - case GlobalSkinLookup target: + case GlobalSkinComponentLookup target: switch (target.Lookup) { - case GlobalSkinLookup.LookupType.SongSelect: + case GlobalSkinComponentLookup.LookupType.SongSelect: var songSelectComponents = new SkinnableTargetComponentsContainer(_ => { // do stuff when we need to. @@ -77,7 +77,7 @@ namespace osu.Game.Skinning return songSelectComponents; - case GlobalSkinLookup.LookupType.MainHUDComponents: + case GlobalSkinComponentLookup.LookupType.MainHUDComponents: var skinnableTargetWrapper = new SkinnableTargetComponentsContainer(container => { var score = container.OfType().FirstOrDefault(); diff --git a/osu.Game/Skinning/UnsupportedSkinComponentException.cs b/osu.Game/Skinning/UnsupportedSkinComponentException.cs index 32fc6661b0..1fb6641668 100644 --- a/osu.Game/Skinning/UnsupportedSkinComponentException.cs +++ b/osu.Game/Skinning/UnsupportedSkinComponentException.cs @@ -7,7 +7,7 @@ namespace osu.Game.Skinning { public class UnsupportedSkinComponentException : Exception { - public UnsupportedSkinComponentException(ISkinLookup lookup) + public UnsupportedSkinComponentException(ISkinComponentLookup lookup) : base($@"Unsupported component type: {lookup.GetType()} (lookup: ""{lookup.LookupName}"").") { } From e19ba65f9186afab21aec536a636d7d152636dde Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Nov 2022 16:39:33 +0900 Subject: [PATCH 2160/2686] Remove `LookupName` from base `ISkinComponentLookup` --- .../Legacy/OsuLegacySkinTransformer.cs | 4 ++-- .../Gameplay/TestSceneSkinnableDrawable.cs | 2 +- osu.Game/Skinning/ArgonSkin.cs | 21 +++++++++---------- .../Skinning/GlobalSkinComponentLookup.cs | 2 -- osu.Game/Skinning/ISkinComponentLookup.cs | 1 - osu.Game/Skinning/SkinnableSprite.cs | 4 ++-- osu.Game/Skinning/TrianglesSkin.cs | 21 +++++++++---------- .../UnsupportedSkinComponentException.cs | 2 +- 8 files changed, 26 insertions(+), 31 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index ab0e9ab1c0..620540b8ef 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -35,10 +35,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy switch (osuComponent.Component) { case OsuSkinComponents.FollowPoint: - return this.GetAnimation(lookup.LookupName, true, true, true, startAtCurrentTime: false); + return this.GetAnimation("followpoint", true, true, true, startAtCurrentTime: false); case OsuSkinComponents.SliderScorePoint: - return this.GetAnimation(lookup.LookupName, false, false); + return this.GetAnimation("sliderscorepoint", false, false); case OsuSkinComponents.SliderFollowCircle: var followCircleContent = this.GetAnimation("sliderfollowcircle", true, true, true); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs index e050273652..97974d2368 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs @@ -289,7 +289,7 @@ namespace osu.Game.Tests.Visual.Gameplay } public Drawable GetDrawableComponent(ISkinComponentLookup componentLookupName) => - componentLookupName.LookupName == "available" + (componentLookupName as TestSkinComponentLookup)?.LookupName == "available" ? new DrawWidthBox { Colour = Color4.Yellow, diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index c3361093a9..a2eb07eba3 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -7,7 +7,6 @@ using JetBrains.Annotations; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Audio; using osu.Game.Beatmaps.Formats; @@ -88,6 +87,16 @@ namespace osu.Game.Skinning switch (lookup) { + case SkinnableSprite.SpriteComponentLookup spriteLookup: + switch (spriteLookup.LookupName) + { + // Temporary until default skin has a valid hit lighting. + case @"lighting": + return Drawable.Empty(); + } + + break; + case GlobalSkinComponentLookup globalLookup: switch (globalLookup.Lookup) { @@ -178,16 +187,6 @@ namespace osu.Game.Skinning return null; } - switch (lookup.LookupName) - { - // Temporary until default skin has a valid hit lighting. - case @"lighting": - return Drawable.Empty(); - } - - if (GetTexture(lookup.LookupName) is Texture t) - return new Sprite { Texture = t }; - return null; } diff --git a/osu.Game/Skinning/GlobalSkinComponentLookup.cs b/osu.Game/Skinning/GlobalSkinComponentLookup.cs index 3d8b61eba2..7dcc3c4f14 100644 --- a/osu.Game/Skinning/GlobalSkinComponentLookup.cs +++ b/osu.Game/Skinning/GlobalSkinComponentLookup.cs @@ -7,8 +7,6 @@ namespace osu.Game.Skinning { public readonly LookupType Lookup; - public string LookupName => Lookup.ToString(); - public GlobalSkinComponentLookup(LookupType lookup) { Lookup = lookup; diff --git a/osu.Game/Skinning/ISkinComponentLookup.cs b/osu.Game/Skinning/ISkinComponentLookup.cs index ae56fb0b1c..be4043d7cf 100644 --- a/osu.Game/Skinning/ISkinComponentLookup.cs +++ b/osu.Game/Skinning/ISkinComponentLookup.cs @@ -16,6 +16,5 @@ namespace osu.Game.Skinning /// public interface ISkinComponentLookup { - string LookupName { get; } } } diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 43fec11b14..7fd0e43562 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -55,10 +55,10 @@ namespace osu.Game.Skinning protected override Drawable CreateDefault(ISkinComponentLookup lookup) { - var texture = textures.Get(lookup.LookupName); + var texture = textures.Get(((SpriteComponentLookup)lookup).LookupName); if (texture == null) - return new SpriteNotFound(lookup.LookupName); + return new SpriteNotFound(((SpriteComponentLookup)lookup).LookupName); return new Sprite { Texture = texture }; } diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 3df85b6880..2075cfb6f2 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -7,7 +7,6 @@ using JetBrains.Annotations; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Game.Audio; using osu.Game.Beatmaps.Formats; @@ -66,6 +65,16 @@ namespace osu.Game.Skinning switch (lookup) { + case SkinnableSprite.SpriteComponentLookup spriteLookup: + switch (spriteLookup.LookupName) + { + // Temporary until default skin has a valid hit lighting. + case @"lighting": + return Drawable.Empty(); + } + + break; + case GlobalSkinComponentLookup target: switch (target.Lookup) { @@ -156,16 +165,6 @@ namespace osu.Game.Skinning return null; } - switch (lookup.LookupName) - { - // Temporary until default skin has a valid hit lighting. - case @"lighting": - return Drawable.Empty(); - } - - if (GetTexture(lookup.LookupName) is Texture t) - return new Sprite { Texture = t }; - return null; } diff --git a/osu.Game/Skinning/UnsupportedSkinComponentException.cs b/osu.Game/Skinning/UnsupportedSkinComponentException.cs index 1fb6641668..b8dfb7a31d 100644 --- a/osu.Game/Skinning/UnsupportedSkinComponentException.cs +++ b/osu.Game/Skinning/UnsupportedSkinComponentException.cs @@ -8,7 +8,7 @@ namespace osu.Game.Skinning public class UnsupportedSkinComponentException : Exception { public UnsupportedSkinComponentException(ISkinComponentLookup lookup) - : base($@"Unsupported component type: {lookup.GetType()} (lookup: ""{lookup.LookupName}"").") + : base($@"Unsupported component type: {lookup.GetType()} (lookup: ""{lookup}"").") { } } From 533a2db5ea34df67750886e8aa0632a7f9dc5071 Mon Sep 17 00:00:00 2001 From: Samaoo Date: Wed, 9 Nov 2022 18:48:47 +0100 Subject: [PATCH 2161/2686] fix inaccurate tablet area dimensions when applying aspect ratio --- .../Overlays/Settings/Sections/Input/TabletSettings.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index f1e216f538..a9eeae7cc7 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -308,9 +309,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input // if lock is applied (or the specified values were out of range) aim to adjust the axis the user was not adjusting to conform. if (sizeChanged == sizeX) - sizeY.Value = (int)(areaSize.Value.X / aspectRatio.Value); + sizeY.Value = (int)Math.Round(areaSize.Value.X / aspectRatio.Value); else - sizeX.Value = (int)(areaSize.Value.Y * aspectRatio.Value); + sizeX.Value = (int)Math.Round(areaSize.Value.Y * aspectRatio.Value); } finally { @@ -324,12 +325,12 @@ namespace osu.Game.Overlays.Settings.Sections.Input { aspectLock.Value = false; - int proposedHeight = (int)(sizeX.Value / aspectRatio); + int proposedHeight = (int)Math.Round(sizeX.Value / aspectRatio); if (proposedHeight < sizeY.MaxValue) sizeY.Value = proposedHeight; else - sizeX.Value = (int)(sizeY.Value * aspectRatio); + sizeX.Value = (int)Math.Round(sizeY.Value * aspectRatio); updateAspectRatio(); From 3909e5730ea1168709d15331b6a780bdd1c86b6f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 9 Nov 2022 21:33:28 +0300 Subject: [PATCH 2162/2686] Rename test steps Co-authored-by: Joseph Madamba --- osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index e69bdfb7ac..d58887c090 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -518,7 +518,7 @@ namespace osu.Game.Tests.Visual.Navigation { ChangelogOverlay getChangelogOverlay() => Game.ChildrenOfType().FirstOrDefault(); - AddUntilStep("Wait for options to load", () => Game.Notifications.IsLoaded); + AddUntilStep("Wait for notifications to load", () => Game.Notifications.IsLoaded); AddStep("Show notifications", () => Game.Notifications.Show()); AddUntilStep("wait for notifications shown", () => Game.Notifications.IsPresent && Game.Notifications.State.Value == Visibility.Visible); AddStep("Show changelog listing", () => Game.ShowChangelogListing()); @@ -535,7 +535,7 @@ namespace osu.Game.Tests.Visual.Navigation { ChangelogOverlay getChangelogOverlay() => Game.ChildrenOfType().FirstOrDefault(); - AddUntilStep("Wait for options to load", () => Game.Settings.IsLoaded); + AddUntilStep("Wait for settings to load", () => Game.Settings.IsLoaded); AddStep("Show settings", () => Game.Settings.Show()); AddUntilStep("wait for settings shown", () => Game.Settings.IsPresent && Game.Settings.State.Value == Visibility.Visible); AddStep("Show changelog listing", () => Game.ShowChangelogListing()); From ab53fb17d390fc8cc8667d720b5e8f7c8a5b9142 Mon Sep 17 00:00:00 2001 From: Piggey Date: Wed, 9 Nov 2022 19:53:36 +0100 Subject: [PATCH 2163/2686] change displayed text from `#?` to `-` --- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index dc2c0620c8..062b31e05a 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -72,7 +72,7 @@ namespace osu.Game.Screens.Play.HUD scorePosition = value; - positionText.Text = scorePosition.HasValue ? $"#{scorePosition.Value.FormatRank()}" : "#?"; + positionText.Text = scorePosition.HasValue ? $"#{scorePosition.Value.FormatRank()}" : "-"; updateState(); } From 0011f4e7be99561ac22a3eb8d07cd32adce71ed3 Mon Sep 17 00:00:00 2001 From: Piggey Date: Wed, 9 Nov 2022 19:59:04 +0100 Subject: [PATCH 2164/2686] fix comment lol --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 10049c7718..c8631880ac 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -174,7 +174,7 @@ namespace osu.Game.Screens.Play.HUD orderedByScore[i].ScorePosition = i + 1; } - // change displayed potision to '#?' when there are 50 already submitted scores and tracked score is last + // change displayed potision to '-' when there are 50 already submitted scores and tracked score is last if (TrackedScore?.ScorePosition == Flow.Count && Flow.Count == 51) TrackedScore.ScorePosition = null; From be81c658af8f20cf7618c73011f8c55a4f627798 Mon Sep 17 00:00:00 2001 From: Samaoo Date: Wed, 9 Nov 2022 20:14:01 +0100 Subject: [PATCH 2165/2686] move tablet area calculations to functions --- .../Settings/Sections/Input/TabletSettings.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index a9eeae7cc7..59c7ff04a2 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -309,9 +309,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input // if lock is applied (or the specified values were out of range) aim to adjust the axis the user was not adjusting to conform. if (sizeChanged == sizeX) - sizeY.Value = (int)Math.Round(areaSize.Value.X / aspectRatio.Value); + sizeY.Value = getHeight(areaSize.Value.X, aspectRatio.Value); else - sizeX.Value = (int)Math.Round(areaSize.Value.Y * aspectRatio.Value); + sizeX.Value = getWidth(areaSize.Value.Y, aspectRatio.Value); } finally { @@ -325,12 +325,12 @@ namespace osu.Game.Overlays.Settings.Sections.Input { aspectLock.Value = false; - int proposedHeight = (int)Math.Round(sizeX.Value / aspectRatio); + int proposedHeight = getHeight(sizeX.Value, aspectRatio); if (proposedHeight < sizeY.MaxValue) sizeY.Value = proposedHeight; else - sizeX.Value = (int)Math.Round(sizeY.Value * aspectRatio); + sizeX.Value = getWidth(sizeY.Value, aspectRatio); updateAspectRatio(); @@ -341,5 +341,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input private void updateAspectRatio() => aspectRatio.Value = currentAspectRatio; private float currentAspectRatio => sizeX.Value / sizeY.Value; + + private static int getHeight(float width, float aspectRatio) => (int)Math.Round(width / aspectRatio); + + private static int getWidth(float height, float aspectRatio) => (int)Math.Round(height * aspectRatio); } } From 1f8824a75495d826d2544dbfd930a29138af9610 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 10 Nov 2022 16:14:40 +0900 Subject: [PATCH 2166/2686] 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 b6ddeeb41a..8237a570ff 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9a6866d264..09b1bb7162 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index b2854d7ddd..4264d9220e 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 6303b88e5666a4d7527bb8ed3cfc0da602913386 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Thu, 10 Nov 2022 14:31:24 +0100 Subject: [PATCH 2167/2686] Fix NRT causing CI failure --- osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index 612756ba08..ccde8e6ac9 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs @@ -159,7 +159,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default { case ArmedState.Hit: using (BeginAbsoluteSequence(drawableHitObject.HitStateUpdateTime)) - flashBox?.FadeTo(0.9f).FadeOut(300); + flashBox.FadeTo(0.9f).FadeOut(300); break; } } From efc0325bef884e3c12c2a4d5ee1217ad28f36b0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 10 Nov 2022 23:41:15 +0900 Subject: [PATCH 2168/2686] Fix nullability issue --- osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index 612756ba08..ccde8e6ac9 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs @@ -159,7 +159,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default { case ArmedState.Hit: using (BeginAbsoluteSequence(drawableHitObject.HitStateUpdateTime)) - flashBox?.FadeTo(0.9f).FadeOut(300); + flashBox.FadeTo(0.9f).FadeOut(300); break; } } From 83a3f1b82e85e981c2117448686bd1c6ad471b67 Mon Sep 17 00:00:00 2001 From: maromalo <54760464+maromalo@users.noreply.github.com> Date: Thu, 10 Nov 2022 14:15:20 -0300 Subject: [PATCH 2169/2686] Add computeRawScore() --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 02512d857d..2b6e40b94e 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -339,16 +339,21 @@ namespace osu.Game.Rulesets.Scoring { default: case ScoringMode.Standardised: - double accuracyScore = accuracyPortion * accuracyRatio; - double comboScore = comboPortion * comboRatio; - return (long)Math.Round((max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier); + return (long)Math.Round(computeRawScore()); case ScoringMode.Classic: // This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring. // The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes. - double scaledStandardised = ComputeScore(ScoringMode.Standardised, accuracyRatio, comboRatio, bonusScore, totalBasicHitObjects) / max_score; + double scaledStandardised = computeRawScore() / max_score; return (long)Math.Round(Math.Pow(scaledStandardised * Math.Max(1, totalBasicHitObjects), 2) * ClassicScoreMultiplier); } + + double computeRawScore() + { + double accuracyScore = accuracyPortion * accuracyRatio; + double comboScore = comboPortion * comboRatio; + return (max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier; + } } private ScoreRank rankFrom(double acc) From 5b1e39abd5d522e1c4dc6f2486bc43bb6b13f731 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Thu, 10 Nov 2022 22:56:24 +0100 Subject: [PATCH 2170/2686] Fix parsing of `Language` when using default system locale --- osu.Game/Extensions/LanguageExtensions.cs | 25 +++++++++++++++++++ .../Overlays/FirstRunSetup/ScreenWelcome.cs | 10 +++++--- .../Sections/General/LanguageSettings.cs | 18 ++++++------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/osu.Game/Extensions/LanguageExtensions.cs b/osu.Game/Extensions/LanguageExtensions.cs index b67e7fb6fc..04231c384c 100644 --- a/osu.Game/Extensions/LanguageExtensions.cs +++ b/osu.Game/Extensions/LanguageExtensions.cs @@ -3,6 +3,8 @@ using System; using System.Globalization; +using osu.Framework.Configuration; +using osu.Framework.Localisation; using osu.Game.Localisation; namespace osu.Game.Extensions @@ -29,5 +31,28 @@ namespace osu.Game.Extensions /// Whether the parsing succeeded. public static bool TryParseCultureCode(string cultureCode, out Language language) => Enum.TryParse(cultureCode.Replace("-", "_"), out language); + + /// + /// Parses the that is specified in , + /// or if that is not valid, the language of the current as exposed by . + /// + /// The current . + /// The current of the . + /// The parsed language. + public static Language GetLanguageFor(string frameworkLocale, LocalisationParameters localisationParameters) + { + // the usual case when the user has changed the language + if (TryParseCultureCode(frameworkLocale, out var language)) + return language; + + if (localisationParameters.Store != null) + { + // startup case, locale not explicitly set, or the set language was removed in an update + if (TryParseCultureCode(localisationParameters.Store.EffectiveCulture.Name, out language)) + return language; + } + + return Language.en; + } } } diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs index cb1e96d2f2..992f538e82 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -63,11 +63,12 @@ namespace osu.Game.Overlays.FirstRunSetup private class LanguageSelectionFlow : FillFlowContainer { private Bindable frameworkLocale = null!; + private IBindable localisationParameters = null!; private ScheduledDelegate? updateSelectedDelegate; [BackgroundDependencyLoader] - private void load(FrameworkConfigManager frameworkConfig) + private void load(FrameworkConfigManager frameworkConfig, LocalisationManager localisation) { Direction = FillDirection.Full; Spacing = new Vector2(5); @@ -80,10 +81,11 @@ namespace osu.Game.Overlays.FirstRunSetup }); frameworkLocale = frameworkConfig.GetBindable(FrameworkSetting.Locale); - frameworkLocale.BindValueChanged(locale => + + localisationParameters = localisation.CurrentParameters.GetBoundCopy(); + localisationParameters.BindValueChanged(p => { - if (!LanguageExtensions.TryParseCultureCode(locale.NewValue, out var language)) - language = Language.en; + var language = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, p.NewValue); // Changing language may cause a short period of blocking the UI thread while the new glyphs are loaded. // Scheduling ensures the button animation plays smoothly after any blocking operation completes. diff --git a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs index 0f77e6609b..b7e3bd90b0 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Configuration; @@ -16,15 +14,17 @@ namespace osu.Game.Overlays.Settings.Sections.General { public class LanguageSettings : SettingsSubsection { - private SettingsDropdown languageSelection; - private Bindable frameworkLocale; + private SettingsDropdown languageSelection = null!; + private Bindable frameworkLocale = null!; + private IBindable localisationParameters = null!; protected override LocalisableString Header => GeneralSettingsStrings.LanguageHeader; [BackgroundDependencyLoader] - private void load(FrameworkConfigManager frameworkConfig, OsuConfigManager config) + private void load(FrameworkConfigManager frameworkConfig, OsuConfigManager config, LocalisationManager localisation) { frameworkLocale = frameworkConfig.GetBindable(FrameworkSetting.Locale); + localisationParameters = localisation.CurrentParameters.GetBoundCopy(); Children = new Drawable[] { @@ -44,12 +44,8 @@ namespace osu.Game.Overlays.Settings.Sections.General }, }; - frameworkLocale.BindValueChanged(locale => - { - if (!LanguageExtensions.TryParseCultureCode(locale.NewValue, out var language)) - language = Language.en; - languageSelection.Current.Value = language; - }, true); + localisationParameters.BindValueChanged(p + => languageSelection.Current.Value = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, p.NewValue), true); languageSelection.Current.BindValueChanged(val => frameworkLocale.Value = val.NewValue.ToCultureCode()); } From 6ac19615fa2669c53a86d6aee51c19f90e7158dd Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 11 Nov 2022 14:55:41 +0900 Subject: [PATCH 2171/2686] Fix test failure --- osu.Game.Tests/Chat/TestSceneChannelManager.cs | 12 +++++++++++- osu.Game/Online/Chat/Channel.cs | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index e7eb06c795..32fc2604ba 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -55,6 +55,14 @@ namespace osu.Game.Tests.Chat case MarkChannelAsReadRequest markRead: handleMarkChannelAsReadRequest(markRead); return true; + + case GetUpdatesRequest updatesRequest: + updatesRequest.TriggerSuccess(new GetUpdatesResponse + { + Messages = sentMessages.ToList(), + Presence = new List() + }); + return true; } return false; @@ -95,6 +103,7 @@ namespace osu.Game.Tests.Chat }); AddStep("post message", () => channelManager.PostMessage("Something interesting")); + AddUntilStep("message postesd", () => !channel.Messages.Any(m => m is LocalMessage)); AddStep("post /help command", () => channelManager.PostCommand("help", channel)); AddStep("post /me command with no action", () => channelManager.PostCommand("me", channel)); @@ -115,7 +124,8 @@ namespace osu.Game.Tests.Chat Content = request.Message.Content, Links = request.Message.Links, Timestamp = request.Message.Timestamp, - Sender = request.Message.Sender + Sender = request.Message.Sender, + Uuid = request.Message.Uuid }; sentMessages.Add(message); diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index 9bfaecc46b..ada9e22027 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -179,6 +179,10 @@ namespace osu.Game.Online.Chat throw new InvalidOperationException("Attempted to add the same message again"); Messages.Add(final); + + if (final.Id > LastMessageId) + LastMessageId = final.Id; + PendingMessageResolved?.Invoke(echo, final); } From 392d4e778eaf3fd4dd3ad433260154bdaff5cbf4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Nov 2022 17:07:37 +0900 Subject: [PATCH 2172/2686] Change default beatmap listing key binding to `Ctrl`+`B` --- osu.Game/Input/Bindings/GlobalActionContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index a58c6723ef..ebdc446ec8 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -78,7 +78,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(InputKey.F8, GlobalAction.ToggleChat), new KeyBinding(InputKey.F6, GlobalAction.ToggleNowPlaying), new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial), - new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleBeatmapListing), + new KeyBinding(new[] { InputKey.Control, InputKey.B }, GlobalAction.ToggleBeatmapListing), new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings), new KeyBinding(new[] { InputKey.Control, InputKey.N }, GlobalAction.ToggleNotifications), }; From 0af4bdaf5c3d0acc1b532770adb7a122c303ca48 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Nov 2022 18:29:15 +0900 Subject: [PATCH 2173/2686] Add back removed configuration elements --- osu.Game/Configuration/OsuConfigManager.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 1286a07eeb..3cabd6a21b 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -172,7 +172,9 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full); - SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f); + SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 0.75f, 0.25f); + SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f); + SetDefault(OsuSetting.EditorShowHitMarkers, true); SetDefault(OsuSetting.LastProcessedMetadataId, -1); @@ -294,6 +296,7 @@ namespace osu.Game.Configuration GameplayCursorDuringTouch, DimLevel, BlurLevel, + EditorDim, LightenDuringBreaks, ShowStoryboard, KeyOverlay, @@ -366,6 +369,7 @@ namespace osu.Game.Configuration GameplayDisableWinKey, SeasonalBackgroundMode, EditorWaveformOpacity, + EditorShowHitMarkers, DiscordRichPresence, AutomaticallyDownloadWhenSpectating, ShowOnlineExplicitContent, From 151dd7c62f8c516a11f416883630c9e057785160 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Nov 2022 22:10:27 +0900 Subject: [PATCH 2174/2686] Fix one more reverted change --- osu.Game/Configuration/OsuConfigManager.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 3cabd6a21b..6cbb677a64 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -5,7 +5,6 @@ using System; using System.Diagnostics; -using System.Globalization; using osu.Framework.Bindables; using osu.Framework.Configuration; using osu.Framework.Configuration.Tracking; @@ -116,7 +115,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.MenuParallax, true); // See https://stackoverflow.com/a/63307411 for default sourcing. - SetDefault(OsuSetting.Prefer24HourTime, CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern.Contains(@"tt")); + SetDefault(OsuSetting.Prefer24HourTime, !CultureInfoHelper.SystemCulture.DateTimeFormat.ShortTimePattern.Contains(@"tt")); // Gameplay SetDefault(OsuSetting.PositionalHitsoundsLevel, 0.2f, 0, 1); From 173f557376e8c8d14b660b8389ea0769cd93971d Mon Sep 17 00:00:00 2001 From: Samaoo Date: Fri, 11 Nov 2022 17:14:34 +0100 Subject: [PATCH 2175/2686] fix tablet aspect ratio values --- .../Sections/Input/TabletAreaSelection.cs | 22 +++++++++---------- .../Settings/Sections/Input/TabletSettings.cs | 6 ++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index cd6554e52d..3b5190d13b 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -125,11 +125,11 @@ namespace osu.Game.Overlays.Settings.Sections.Input { usableAreaContainer.ResizeTo(val.NewValue, 100, Easing.OutQuint); - int x = (int)val.NewValue.X; - int y = (int)val.NewValue.Y; + int x = (int)Math.Round(val.NewValue.X); + int y = (int)Math.Round(val.NewValue.Y); int commonDivider = greatestCommonDivider(x, y); - usableAreaText.Text = $"{(float)x / commonDivider}:{(float)y / commonDivider}"; + usableAreaText.Text = $"{x / commonDivider}:{y / commonDivider}"; checkBounds(); }, true); @@ -212,17 +212,17 @@ namespace osu.Game.Overlays.Settings.Sections.Input { base.Update(); - if (!(tablet.Value?.Size is Vector2 size)) - return; + if (tablet.Value?.Size is Vector2 size) + { + float maxDimension = size.LengthFast; - float maxDimension = size.LengthFast; + float fitX = maxDimension / (DrawWidth - Padding.Left - Padding.Right); + float fitY = maxDimension / DrawHeight; - float fitX = maxDimension / (DrawWidth - Padding.Left - Padding.Right); - float fitY = maxDimension / DrawHeight; + float adjust = MathF.Max(fitX, fitY); - float adjust = MathF.Max(fitX, fitY); - - tabletContainer.Scale = new Vector2(1 / adjust); + tabletContainer.Scale = new Vector2(1 / adjust); + } } } } diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 59c7ff04a2..8f92bb16f5 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -325,7 +325,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { aspectLock.Value = false; - int proposedHeight = getHeight(sizeX.Value, aspectRatio); + float proposedHeight = getHeight(sizeX.Value, aspectRatio); if (proposedHeight < sizeY.MaxValue) sizeY.Value = proposedHeight; @@ -342,8 +342,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input private float currentAspectRatio => sizeX.Value / sizeY.Value; - private static int getHeight(float width, float aspectRatio) => (int)Math.Round(width / aspectRatio); + private static float getHeight(float width, float aspectRatio) => (float)Math.Round(width / aspectRatio); - private static int getWidth(float height, float aspectRatio) => (int)Math.Round(height * aspectRatio); + private static float getWidth(float height, float aspectRatio) => (float)Math.Round(height * aspectRatio); } } From 268011be9e39ca553477e55a283b832117b2d197 Mon Sep 17 00:00:00 2001 From: Samaoo Date: Fri, 11 Nov 2022 17:56:50 +0100 Subject: [PATCH 2176/2686] use MathF --- osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 8f92bb16f5..0f96ef3ac7 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -342,8 +342,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input private float currentAspectRatio => sizeX.Value / sizeY.Value; - private static float getHeight(float width, float aspectRatio) => (float)Math.Round(width / aspectRatio); + private static float getHeight(float width, float aspectRatio) => MathF.Round(width / aspectRatio); - private static float getWidth(float height, float aspectRatio) => (float)Math.Round(height * aspectRatio); + private static float getWidth(float height, float aspectRatio) => MathF.Round(height * aspectRatio); } } From 7ef11cab8b76ea75ec5f1671fa0dbc6f73685361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 12 Nov 2022 02:10:10 +0900 Subject: [PATCH 2177/2686] Adjust taiko argon transformer to new naming --- .../Skinning/Argon/TaikoArgonSkinTransformer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index f0d14f657d..379c675a0f 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -14,14 +14,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon { } - public override Drawable? GetDrawableComponent(ISkinComponent component) + public override Drawable? GetDrawableComponent(ISkinComponentLookup component) { switch (component) { - case GameplaySkinComponent resultComponent: + case GameplaySkinComponentLookup resultComponent: return new ArgonJudgementPiece(resultComponent.Component); - case TaikoSkinComponent catchComponent: + case TaikoSkinComponentLookup catchComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. switch (catchComponent.Component) { From 6a4c97b4f119bb91e73eb48c832691665da4fffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 12 Nov 2022 02:20:19 +0900 Subject: [PATCH 2178/2686] Fix code inspection --- osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs index 91f34e1f0e..22f96da61e 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon EarlyActivationMilliseconds = pre_beat_transition_time; - AddRangeInternal(new Drawable[] + AddRangeInternal(new[] { new Circle { From 8b8147c3212d4475992f48df3ab3498b17c9925c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 12 Nov 2022 03:05:03 +0900 Subject: [PATCH 2179/2686] Rename `{catch -> taiko}Component` --- .../Skinning/Argon/TaikoArgonSkinTransformer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index 379c675a0f..6d1087793d 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -21,9 +21,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case GameplaySkinComponentLookup resultComponent: return new ArgonJudgementPiece(resultComponent.Component); - case TaikoSkinComponentLookup catchComponent: + case TaikoSkinComponentLookup taikoComponent: // TODO: Once everything is finalised, consider throwing UnsupportedSkinComponentException on missing entries. - switch (catchComponent.Component) + switch (taikoComponent.Component) { case TaikoSkinComponents.CentreHit: return new ArgonCentreCirclePiece(); @@ -59,7 +59,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.TaikoExplosionGreat: case TaikoSkinComponents.TaikoExplosionMiss: case TaikoSkinComponents.TaikoExplosionOk: - return new ArgonHitExplosion(catchComponent.Component); + return new ArgonHitExplosion(taikoComponent.Component); } break; From b0314c67aa6f21aaae6e9b32be23ceac8b86cafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 12 Nov 2022 14:16:46 +0900 Subject: [PATCH 2180/2686] Fix failing gameplay bindings test --- .../Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs index 5bd879de14..c3d7bde68f 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs @@ -56,6 +56,7 @@ namespace osu.Game.Tests.Visual.Navigation PushAndConfirm(() => new PlaySongSelect()); AddUntilStep("wait for selection", () => !Game.Beatmap.IsDefault); + AddUntilStep("wait for carousel load", () => songSelect.BeatmapSetsLoaded); AddStep("enter gameplay", () => InputManager.Key(Key.Enter)); @@ -92,6 +93,8 @@ namespace osu.Game.Tests.Visual.Navigation .AsEnumerable() .First(k => k.RulesetName == "osu" && k.ActionInt == 0); + private Screens.Select.SongSelect songSelect => Game.ScreenStack.CurrentScreen as Screens.Select.SongSelect; + private Player player => Game.ScreenStack.CurrentScreen as Player; private KeyCounter keyCounter => player.ChildrenOfType().First(); From 7a860fb460895486499e8ed897f36d8d30e98c16 Mon Sep 17 00:00:00 2001 From: Samaoo Date: Sat, 12 Nov 2022 08:49:03 +0100 Subject: [PATCH 2181/2686] address reviews --- .../Sections/Input/TabletAreaSelection.cs | 16 ++++++++-------- .../Settings/Sections/Input/TabletSettings.cs | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index 3b5190d13b..708cd5900a 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -212,17 +212,17 @@ namespace osu.Game.Overlays.Settings.Sections.Input { base.Update(); - if (tablet.Value?.Size is Vector2 size) - { - float maxDimension = size.LengthFast; + if (!(tablet.Value?.Size is Vector2 size)) + return; - float fitX = maxDimension / (DrawWidth - Padding.Left - Padding.Right); - float fitY = maxDimension / DrawHeight; + float maxDimension = size.LengthFast; - float adjust = MathF.Max(fitX, fitY); + float fitX = maxDimension / (DrawWidth - Padding.Left - Padding.Right); + float fitY = maxDimension / DrawHeight; - tabletContainer.Scale = new Vector2(1 / adjust); - } + float adjust = MathF.Max(fitX, fitY); + + tabletContainer.Scale = new Vector2(1 / adjust); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 0f96ef3ac7..4cafb5c377 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -342,8 +342,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input private float currentAspectRatio => sizeX.Value / sizeY.Value; - private static float getHeight(float width, float aspectRatio) => MathF.Round(width / aspectRatio); + private static float getHeight(float width, float aspectRatio) => width / aspectRatio; - private static float getWidth(float height, float aspectRatio) => MathF.Round(height * aspectRatio); + private static float getWidth(float height, float aspectRatio) => height * aspectRatio; } } From 4ff17cb4bdb617f7301363380d3424d099d57eb9 Mon Sep 17 00:00:00 2001 From: Samaoo Date: Sat, 12 Nov 2022 08:52:33 +0100 Subject: [PATCH 2182/2686] remove unused using directive --- osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 4cafb5c377..21a65862f7 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; From fa8e38d9d61cc867f9ff37e991693df6b936bb39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Mu=CC=88ller-Ho=CC=88hne?= Date: Sat, 12 Nov 2022 17:05:29 +0900 Subject: [PATCH 2183/2686] Target rounded fragment shader Compatibility with osu-framework change https://github.com/ppy/osu-framework/pull/5512 --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 2 -- osu.Game/Graphics/Backgrounds/Triangles.cs | 2 +- osu.Game/Graphics/Sprites/LogoAnimation.cs | 1 - osu.Game/Screens/Loader.cs | 4 +--- osu.Game/Screens/Menu/LogoVisualisation.cs | 2 +- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 46c8e7c02a..3bc17c0849 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -49,7 +49,6 @@ namespace osu.Game.Rulesets.Osu.Skinning private const float max_rotation = 0.25f; public IShader? TextureShader { get; private set; } - public IShader? RoundedTextureShader { get; private set; } protected Texture? Texture { get; set; } @@ -69,7 +68,6 @@ namespace osu.Game.Rulesets.Osu.Skinning [BackgroundDependencyLoader] private void load(ShaderManager shaders) { - RoundedTextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE); } diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 1166a86814..986f5d3ac5 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -103,7 +103,7 @@ namespace osu.Game.Graphics.Backgrounds private void load(IRenderer renderer, ShaderManager shaders) { texture = renderer.WhitePixel; - shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); + shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE); } protected override void LoadComplete() diff --git a/osu.Game/Graphics/Sprites/LogoAnimation.cs b/osu.Game/Graphics/Sprites/LogoAnimation.cs index 7debdc7a37..5233a3d67f 100644 --- a/osu.Game/Graphics/Sprites/LogoAnimation.cs +++ b/osu.Game/Graphics/Sprites/LogoAnimation.cs @@ -17,7 +17,6 @@ namespace osu.Game.Graphics.Sprites private void load(ShaderManager shaders) { TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, @"LogoAnimation"); - RoundedTextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, @"LogoAnimation"); // Masking isn't supported for now } private float animationProgress; diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index afba00274c..ac22fdce71 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -125,13 +125,11 @@ namespace osu.Game.Screens [BackgroundDependencyLoader] private void load(ShaderManager manager) { - loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED)); - loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.BLUR)); loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE)); + loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.BLUR)); loadTargets.Add(manager.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE)); - loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_3, FragmentShaderDescriptor.TEXTURE_ROUNDED)); loadTargets.Add(manager.Load(VertexShaderDescriptor.TEXTURE_3, FragmentShaderDescriptor.TEXTURE)); } diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index c7bda4d8f8..4a20d7cb2b 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -89,7 +89,7 @@ namespace osu.Game.Screens.Menu private void load(IRenderer renderer, ShaderManager shaders) { texture = renderer.WhitePixel; - shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE_ROUNDED); + shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE); } private readonly float[] temporalAmplitudes = new float[ChannelAmplitudes.AMPLITUDES_SIZE]; From aef25df80844444e517f9bdd9be2bab17dc5a979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 12 Nov 2022 17:06:08 +0900 Subject: [PATCH 2184/2686] Add helper scripts for using local resources --- UseLocalResources.ps1 | 12 ++++++++++++ UseLocalResources.sh | 11 +++++++++++ 2 files changed, 23 insertions(+) create mode 100644 UseLocalResources.ps1 create mode 100755 UseLocalResources.sh diff --git a/UseLocalResources.ps1 b/UseLocalResources.ps1 new file mode 100644 index 0000000000..f9d9df01bb --- /dev/null +++ b/UseLocalResources.ps1 @@ -0,0 +1,12 @@ +$CSPROJ="osu.Game/osu.Game.csproj" +$SLN="osu.sln" + +dotnet remove $CSPROJ package ppy.osu.Game.Resources; +dotnet sln $SLN add ../osu-resources/osu.Game.Resources/osu.Game.Resources.csproj +dotnet add $CSPROJ reference ../osu-resources/osu.Game.Resources/osu.Game.Resources.csproj + +$SLNF=Get-Content "osu.Desktop.slnf" | ConvertFrom-Json +$TMP=New-TemporaryFile +$SLNF.solution.projects += ("../osu-resources/osu.Game.Resources/osu.Game.Resources.csproj") +ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8 +Move-Item -Path $TMP -Destination "osu.Desktop.slnf" -Force diff --git a/UseLocalResources.sh b/UseLocalResources.sh new file mode 100755 index 0000000000..6d9d2b6016 --- /dev/null +++ b/UseLocalResources.sh @@ -0,0 +1,11 @@ +CSPROJ="osu.Game/osu.Game.csproj" +SLN="osu.sln" + +dotnet remove $CSPROJ package ppy.osu.Game.Resources; +dotnet sln $SLN add ../osu-resources/osu.Game.Resources/osu.Game.Resources.csproj +dotnet add $CSPROJ reference ../osu-resources/osu.Game.Resources/osu.Game.Resources.csproj + +SLNF="osu.Desktop.slnf" +TMP=$(mktemp) +jq '.solution.projects += ["../osu-resources/osu.Game.Resources/osu.Game.Resources.csproj"]' $SLNF > $TMP +mv -f $TMP $SLNF From 9ef43ebd837e44f8f8cb3c3c5629ec44c7adcb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Mu=CC=88ller-Ho=CC=88hne?= Date: Sat, 12 Nov 2022 21:24:12 +0900 Subject: [PATCH 2185/2686] Fix compilation after framework-side PR updates --- osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs | 6 ++---- osu.Game/Graphics/Sprites/LogoAnimation.cs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 3bc17c0849..c19ed3fb35 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -245,18 +245,16 @@ namespace osu.Game.Rulesets.Osu.Skinning texture ??= renderer.WhitePixel; RectangleF textureRect = texture.GetTextureRect(); - var shader = GetAppropriateShader(renderer); - renderer.SetBlend(BlendingParameters.Additive); renderer.PushLocalMatrix(DrawInfo.Matrix); - shader.Bind(); + TextureShader.Bind(); texture.Bind(); for (int i = 0; i < points.Count; i++) drawPointQuad(points[i], textureRect, i + firstVisiblePointIndex); - shader.Unbind(); + TextureShader.Unbind(); renderer.PopLocalMatrix(); } diff --git a/osu.Game/Graphics/Sprites/LogoAnimation.cs b/osu.Game/Graphics/Sprites/LogoAnimation.cs index 5233a3d67f..097de4dfcb 100644 --- a/osu.Game/Graphics/Sprites/LogoAnimation.cs +++ b/osu.Game/Graphics/Sprites/LogoAnimation.cs @@ -57,7 +57,7 @@ namespace osu.Game.Graphics.Sprites protected override void Blit(IRenderer renderer) { - GetAppropriateShader(renderer).GetUniform("progress").UpdateValue(ref progress); + TextureShader.GetUniform("progress").UpdateValue(ref progress); base.Blit(renderer); } From ace4099079889f8b220d8e8514167870dac0cad8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 12 Nov 2022 21:41:10 +0900 Subject: [PATCH 2186/2686] Update ack code after incorrect merge --- osu.Game/Online/Chat/ChannelManager.cs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 0aa86fb9d1..bb388b7461 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -116,20 +116,7 @@ namespace osu.Game.Online.Chat if (apiState.Value != APIState.Online) return; - scheduledAck?.Cancel(); - - var req = new ChatAckRequest(); - req.Success += _ => scheduleNextRequest(); - req.Failure += _ => scheduleNextRequest(); - api.Queue(req); - - // Todo: Handle silences. - - void scheduleNextRequest() - { - scheduledAck?.Cancel(); - scheduledAck = Scheduler.AddDelayed(performChatAckRequest, 60000); - } + SendAck(); } /// @@ -416,6 +403,7 @@ namespace osu.Game.Online.Chat SinceSilenceId = lastSilenceId }; + req.Failure += _ => scheduleNextRequest(); req.Success += ack => { foreach (var silence in ack.Silences) @@ -424,9 +412,17 @@ namespace osu.Game.Online.Chat channel.RemoveMessagesFromUser(silence.UserId); lastSilenceId = Math.Max(lastSilenceId ?? 0, silence.Id); } + + scheduleNextRequest(); }; api.Queue(req); + + void scheduleNextRequest() + { + scheduledAck?.Cancel(); + scheduledAck = Scheduler.AddDelayed(performChatAckRequest, 60000); + } } /// From 6a3665a6fde45b4f66e977cd79aa5a6670ebd3d8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 12 Nov 2022 22:09:27 +0900 Subject: [PATCH 2187/2686] Remove excess logging on `WebSocketNotificaitonsClient` --- .../Notifications/WebSocket/WebSocketNotificationsClient.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index 86836099d8..d8d78297e3 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -72,7 +72,6 @@ namespace osu.Game.Online.Notifications.WebSocket break; } - Logger.Log($"{GetType().ReadableName()} handling event: {message.Event}"); await onMessageReceivedAsync(message); } From bfb939cbd0ae1b1528d23534457a26178cf340d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 12 Nov 2022 22:24:27 +0900 Subject: [PATCH 2188/2686] Expand on why call needs to be made every 10 minutes --- osu.Game/Online/Chat/ChannelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index bb388b7461..ebfe44bd66 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -393,7 +393,7 @@ namespace osu.Game.Online.Chat /// /// Sends an acknowledgement request to the API. /// This marks the user as online to receive messages from public channels, while also returning a list of silenced users. - /// It needs to be called at least once every 10 minutes. + /// It needs to be called at least once every 10 minutes to remain visibly marked as online. /// public void SendAck() { From 143c94612872c8ea6c804d51b956f3f6a59e1ce5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 12 Nov 2022 23:02:37 +0900 Subject: [PATCH 2189/2686] Simplify ack re-perform flow --- osu.Game/Online/Chat/ChannelManager.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index ebfe44bd66..8f1d2db36c 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -108,15 +108,7 @@ namespace osu.Game.Online.Chat connector.Start(); apiState.BindTo(api.State); - apiState.BindValueChanged(_ => performChatAckRequest(), true); - } - - private void performChatAckRequest() - { - if (apiState.Value != APIState.Online) - return; - - SendAck(); + apiState.BindValueChanged(_ => SendAck(), true); } /// @@ -397,6 +389,9 @@ namespace osu.Game.Online.Chat /// public void SendAck() { + if (apiState.Value != APIState.Online) + return; + var req = new ChatAckRequest { SinceMessageId = lastMessageId, @@ -421,7 +416,7 @@ namespace osu.Game.Online.Chat void scheduleNextRequest() { scheduledAck?.Cancel(); - scheduledAck = Scheduler.AddDelayed(performChatAckRequest, 60000); + scheduledAck = Scheduler.AddDelayed(SendAck, 60000); } } From 22d8a1160e28bae031040fa5376dcfaa0caf219b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 12 Nov 2022 23:32:05 +0900 Subject: [PATCH 2190/2686] Fix last silence ID being updated too often, causing most silences to be missed --- osu.Game/Online/API/Requests/ChatAckRequest.cs | 5 +++-- osu.Game/Online/Chat/ChannelManager.cs | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/ChatAckRequest.cs b/osu.Game/Online/API/Requests/ChatAckRequest.cs index 78f51e21c0..01b0c142dc 100644 --- a/osu.Game/Online/API/Requests/ChatAckRequest.cs +++ b/osu.Game/Online/API/Requests/ChatAckRequest.cs @@ -9,14 +9,15 @@ namespace osu.Game.Online.API.Requests { public class ChatAckRequest : APIRequest { - public long SinceMessageId; + public long? SinceMessageId; public uint? SinceSilenceId; protected override WebRequest CreateWebRequest() { var req = base.CreateWebRequest(); req.Method = HttpMethod.Post; - req.AddParameter(@"since", SinceMessageId.ToString()); + if (SinceMessageId != null) + req.AddParameter(@"since", SinceMessageId.ToString()); if (SinceSilenceId != null) req.AddParameter(@"history_since", SinceSilenceId.Value.ToString()); return req; diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 8f1d2db36c..25a53360f0 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -74,7 +74,7 @@ namespace osu.Game.Online.Chat private bool channelsInitialised; private ScheduledDelegate scheduledAck; - private long lastMessageId; + private long? lastSilenceMessageId; private uint? lastSilenceId; public ChannelManager(IAPIProvider api) @@ -332,7 +332,7 @@ namespace osu.Game.Online.Chat foreach (var group in messages.GroupBy(m => m.ChannelId)) channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); - lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId; + lastSilenceMessageId ??= messages.LastOrDefault()?.Id; } private void initializeChannels() @@ -394,7 +394,7 @@ namespace osu.Game.Online.Chat var req = new ChatAckRequest { - SinceMessageId = lastMessageId, + SinceMessageId = lastSilenceMessageId, SinceSilenceId = lastSilenceId }; From f343ba611139c98a0424f95c8a07dd0ee4d03b7d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 12 Nov 2022 23:35:21 +0900 Subject: [PATCH 2191/2686] Add xmldoc for chat ack request --- osu.Game/Online/API/Requests/ChatAckRequest.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Online/API/Requests/ChatAckRequest.cs b/osu.Game/Online/API/Requests/ChatAckRequest.cs index 01b0c142dc..306b5acc1d 100644 --- a/osu.Game/Online/API/Requests/ChatAckRequest.cs +++ b/osu.Game/Online/API/Requests/ChatAckRequest.cs @@ -7,6 +7,17 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { + /// + /// A request which should be sent occasionally while interested in chat and online state. + /// + /// This will: + /// - Mark the user as "online" (for 10 minutes since the last invocation). + /// - Return any silences since the last invocation (if either or is not null). + /// + /// For silence handling, a should be provided as soon as a message is received by the client. + /// From that point forward, should be preferred after the first + /// arrives in a response from the ack request. Specifying both parameters will prioritise the latter. + /// public class ChatAckRequest : APIRequest { public long? SinceMessageId; From c5cb4e4e7d754a7d076a3d91fac2ae7c841c19dd Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sat, 12 Nov 2022 17:48:35 +0000 Subject: [PATCH 2192/2686] Add winner of Triangles mapping competition as a bundled beatmap https://osu.ppy.sh/home/news/2022-10-06-results-triangles --- osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs b/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs index 80af4108c7..053ac8fc17 100644 --- a/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs +++ b/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs @@ -136,7 +136,9 @@ namespace osu.Game.Beatmaps.Drawables private static readonly string[] always_bundled_beatmaps = { // This thing is 40mb, I'm not sure we want it here... - @"1388906 Raphlesia & BilliumMoto - My Love.osz" + @"1388906 Raphlesia & BilliumMoto - My Love.osz", + // Winner of Triangles mapping competition: https://osu.ppy.sh/home/news/2022-10-06-results-triangles + @"1841885 cYsmix - triangles.osz", }; private static readonly string[] bundled_osu = From eae853072298e1251f8a0cfdeecb2cead746fa23 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 13 Nov 2022 12:46:20 +0900 Subject: [PATCH 2193/2686] Fix `SkinnableSprite` lookups broken in lazer-first skins Regressed with removal of local `GetTexture` calls in https://github.com/ppy/osu/commit/e19ba65f9186afab21aec536a636d7d152636dde --- osu.Game/Skinning/ArgonSkin.cs | 13 +++---------- osu.Game/Skinning/LegacySkin.cs | 3 --- osu.Game/Skinning/Skin.cs | 4 ++++ osu.Game/Skinning/TrianglesSkin.cs | 13 +++---------- 4 files changed, 10 insertions(+), 23 deletions(-) diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index a2eb07eba3..6a0c4a23e5 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -82,21 +82,14 @@ namespace osu.Game.Skinning public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { + // Temporary until default skin has a valid hit lighting. + if ((lookup as SkinnableSprite.SpriteComponentLookup)?.LookupName == @"lighting") return Drawable.Empty(); + if (base.GetDrawableComponent(lookup) is Drawable c) return c; switch (lookup) { - case SkinnableSprite.SpriteComponentLookup spriteLookup: - switch (spriteLookup.LookupName) - { - // Temporary until default skin has a valid hit lighting. - case @"lighting": - return Drawable.Empty(); - } - - break; - case GlobalSkinComponentLookup globalLookup: switch (globalLookup.Lookup) { diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 98618e3dcd..ea223d172d 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -396,9 +396,6 @@ namespace osu.Game.Skinning } return null; - - case SkinnableSprite.SpriteComponentLookup sprite: - return this.GetAnimation(sprite.LookupName, false, false); } return null; diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs index e222b9017c..25d1dc903c 100644 --- a/osu.Game/Skinning/Skin.cs +++ b/osu.Game/Skinning/Skin.cs @@ -158,6 +158,10 @@ namespace osu.Game.Skinning { switch (lookup) { + // This fallback is important for user skins which use SkinnableSprites. + case SkinnableSprite.SpriteComponentLookup sprite: + return this.GetAnimation(sprite.LookupName, false, false); + case GlobalSkinComponentLookup target: if (!DrawableComponentInfo.TryGetValue(target.Lookup, out var skinnableInfo)) return null; diff --git a/osu.Game/Skinning/TrianglesSkin.cs b/osu.Game/Skinning/TrianglesSkin.cs index 2075cfb6f2..62ef94691b 100644 --- a/osu.Game/Skinning/TrianglesSkin.cs +++ b/osu.Game/Skinning/TrianglesSkin.cs @@ -60,21 +60,14 @@ namespace osu.Game.Skinning public override Drawable? GetDrawableComponent(ISkinComponentLookup lookup) { + // Temporary until default skin has a valid hit lighting. + if ((lookup as SkinnableSprite.SpriteComponentLookup)?.LookupName == @"lighting") return Drawable.Empty(); + if (base.GetDrawableComponent(lookup) is Drawable c) return c; switch (lookup) { - case SkinnableSprite.SpriteComponentLookup spriteLookup: - switch (spriteLookup.LookupName) - { - // Temporary until default skin has a valid hit lighting. - case @"lighting": - return Drawable.Empty(); - } - - break; - case GlobalSkinComponentLookup target: switch (target.Lookup) { From 887b6832c9435fce99ad7d10095a26f52fcec572 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 13 Nov 2022 16:15:30 +0900 Subject: [PATCH 2194/2686] 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 8237a570ff..085b71d131 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 09b1bb7162..8f9fe0f9f7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 4264d9220e..e8ccc9cb3a 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 236cc0bdaf10861546efe3b328ac01d63cd546c5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 13 Nov 2022 16:21:28 +0900 Subject: [PATCH 2195/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 085b71d131..5f3fb858ee 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8f9fe0f9f7..858cac1dac 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index e8ccc9cb3a..25217b872b 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + From 3f8c4a5dfff5c094c2bb4ce6100da4f636a2a037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=E1=BB=93=20Nguy=C3=AAn=20Minh?= Date: Sun, 13 Nov 2022 17:09:43 +0700 Subject: [PATCH 2196/2686] Stack Catch dash/normal touch input vertically --- .../UI/CatchTouchInputMapper.cs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index e6736d6c93..12d695393f 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -35,6 +35,8 @@ namespace osu.Game.Rulesets.Catch.UI private void load(CatchInputManager catchInputManager, OsuColour colours) { const float width = 0.15f; + // Ratio between normal move area height and total input height + const float normal_area_height_ratio = 0.45f; keyBindingContainer = catchInputManager.KeyBindingContainer; @@ -54,18 +56,18 @@ namespace osu.Game.Rulesets.Catch.UI Width = width, Children = new Drawable[] { - leftDashBox = new InputArea(TouchCatchAction.DashLeft, trackedActionSources) - { - RelativeSizeAxes = Axes.Both, - Width = 0.5f, - }, leftBox = new InputArea(TouchCatchAction.MoveLeft, trackedActionSources) { RelativeSizeAxes = Axes.Both, - Width = 0.5f, + Height = normal_area_height_ratio, Colour = colours.Gray9, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + }, + leftDashBox = new InputArea(TouchCatchAction.DashLeft, trackedActionSources) + { + RelativeSizeAxes = Axes.Both, + Height = 1 - normal_area_height_ratio, }, } }, @@ -80,15 +82,15 @@ namespace osu.Game.Rulesets.Catch.UI rightBox = new InputArea(TouchCatchAction.MoveRight, trackedActionSources) { RelativeSizeAxes = Axes.Both, - Width = 0.5f, + Height = normal_area_height_ratio, Colour = colours.Gray9, + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, }, rightDashBox = new InputArea(TouchCatchAction.DashRight, trackedActionSources) { RelativeSizeAxes = Axes.Both, - Width = 0.5f, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, + Height = 1 - normal_area_height_ratio, }, } }, From 81c9ea98e2119997b22181161974642d826c5f63 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 13 Nov 2022 14:59:17 +0300 Subject: [PATCH 2197/2686] Implement TrianglesV2 component --- .../TestSceneTriangleBorderShader.cs | 59 ++++ .../TestSceneTrianglesBackground.cs | 43 +++ osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 313 ++++++++++++++++++ 3 files changed, 415 insertions(+) create mode 100644 osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs create mode 100644 osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs create mode 100644 osu.Game/Graphics/Backgrounds/TrianglesV2.cs diff --git a/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs b/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs new file mode 100644 index 0000000000..470962088e --- /dev/null +++ b/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics; +using osuTK; +using osuTK.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Rendering; + +namespace osu.Game.Tests.Visual.Background +{ + public class TestSceneTriangleBorderShader : OsuTestScene + { + public TestSceneTriangleBorderShader() + { + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.DarkGreen + }, + new TriangleBorder + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(100) + } + }; + } + + private class TriangleBorder : Sprite + { + [BackgroundDependencyLoader] + private void load(ShaderManager shaders, IRenderer renderer) + { + TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, "TriangleBorder"); + Texture = renderer.WhitePixel; + } + + protected override DrawNode CreateDrawNode() => new TriangleBorderDrawNode(this); + + private class TriangleBorderDrawNode : SpriteDrawNode + { + public TriangleBorderDrawNode(TriangleBorder source) + : base(source) + { + } + + protected override bool CanDrawOpaqueInterior => false; + } + } + } +} diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs new file mode 100644 index 0000000000..a40d363dbe --- /dev/null +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.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.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osuTK; +using osuTK.Graphics; +using osu.Game.Graphics.Backgrounds; + +namespace osu.Game.Tests.Visual.Background +{ + public class TestSceneTrianglesBackground : OsuTestScene + { + public TestSceneTrianglesBackground() + { + AddRange(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Gray + }, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(200), + Masking = true, + CornerRadius = 40, + Child = new TrianglesV2 + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + ColourTop = Color4.Red, + ColourBottom = Color4.Orange + } + } + }); + } + } +} diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs new file mode 100644 index 0000000000..89ec7d2ad5 --- /dev/null +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -0,0 +1,313 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using osu.Framework.Utils; +using osuTK; +using System; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Textures; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Allocation; +using System.Collections.Generic; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Rendering.Vertices; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp; +using osuTK.Graphics; +using osu.Framework.Bindables; +using osu.Framework.Graphics; + +namespace osu.Game.Graphics.Backgrounds +{ + public class TrianglesV2 : Drawable + { + private const float triangle_size = 100; + private const float base_velocity = 50; + private const int texture_height = 128; + + private readonly Bindable colourTop = new Bindable(Color4.White); + private readonly Bindable colourBottom = new Bindable(Color4.Black); + + public Color4 ColourTop + { + get => colourTop.Value; + set => colourTop.Value = value; + } + + public Color4 ColourBottom + { + get => colourBottom.Value; + set => colourBottom.Value = value; + } + + /// + /// Whether we should create new triangles as others expire. + /// + protected virtual bool CreateNewTriangles => true; + + /// + /// The amount of triangles we want compared to the default distribution. + /// + protected virtual float SpawnRatio => 1; + + private float triangleScale = 1; + + /// + /// The relative velocity of the triangles. Default is 1. + /// + public float Velocity = 1; + + private readonly List parts = new List(); + + [Resolved] + private IRenderer renderer { get; set; } + + private Random stableRandom; + private IShader shader; + private Texture texture; + + /// + /// Construct a new triangle visualisation. + /// + /// An optional seed to stabilise random positions / attributes. Note that this does not guarantee stable playback when seeking in time. + public TrianglesV2(int? seed = null) + { + if (seed != null) + stableRandom = new Random(seed.Value); + } + + [BackgroundDependencyLoader] + private void load(ShaderManager shaders) + { + shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, "TriangleBorder"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + colourTop.BindValueChanged(_ => updateTexture()); + colourBottom.BindValueChanged(_ => updateTexture(), true); + + addTriangles(true); + } + + private void updateTexture() + { + var image = new Image(texture_height, 1); + + texture = renderer.CreateTexture(1, texture_height, true); + + for (int i = 0; i < texture_height; i++) + { + float ratio = (float)i / texture_height; + + image[i, 0] = new Rgba32( + colourBottom.Value.R * ratio + colourTop.Value.R * (1f - ratio), + colourBottom.Value.G * ratio + colourTop.Value.G * (1f - ratio), + colourBottom.Value.B * ratio + colourTop.Value.B * (1f - ratio), + 1f + ); + } + + texture.SetData(new TextureUpload(image)); + Invalidate(Invalidation.DrawNode); + } + + public float TriangleScale + { + get => triangleScale; + set + { + float change = value / triangleScale; + triangleScale = value; + + for (int i = 0; i < parts.Count; i++) + { + TriangleParticle newParticle = parts[i]; + newParticle.Scale *= change; + parts[i] = newParticle; + } + } + } + + protected override void Update() + { + base.Update(); + + Invalidate(Invalidation.DrawNode); + + if (CreateNewTriangles) + addTriangles(false); + + float elapsedSeconds = (float)Time.Elapsed / 1000; + // Since position is relative, the velocity needs to scale inversely with DrawHeight. + // Since we will later multiply by the scale of individual triangles we normalize by + // dividing by triangleScale. + float movedDistance = -elapsedSeconds * Velocity * base_velocity / (DrawHeight * triangleScale); + + for (int i = 0; i < parts.Count; i++) + { + TriangleParticle newParticle = parts[i]; + + // Scale moved distance by the size of the triangle. Smaller triangles should move more slowly. + newParticle.Position.Y += Math.Max(0.5f, parts[i].Scale) * movedDistance; + + parts[i] = newParticle; + + float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * 0.866f / DrawHeight; + if (bottomPos < 0) + parts.RemoveAt(i); + } + } + + /// + /// Clears and re-initialises triangles according to a given seed. + /// + /// An optional seed to stabilise random positions / attributes. Note that this does not guarantee stable playback when seeking in time. + public void Reset(int? seed = null) + { + if (seed != null) + stableRandom = new Random(seed.Value); + + parts.Clear(); + addTriangles(true); + } + + protected int AimCount { get; private set; } + + private void addTriangles(bool randomY) + { + // Limited by the maximum size of QuadVertexBuffer for safety. + const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2); + + AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio); + + for (int i = 0; i < AimCount - parts.Count; i++) + parts.Add(createTriangle(randomY)); + } + + private TriangleParticle createTriangle(bool randomY) + { + TriangleParticle particle = CreateTriangle(); + + particle.Position = new Vector2(nextRandom(), randomY ? nextRandom() : 1); + + return particle; + } + + /// + /// Creates a triangle particle with a random scale. + /// + /// The triangle particle. + protected virtual TriangleParticle CreateTriangle() + { + const float std_dev = 0.16f; + const float mean = 0.5f; + + float u1 = 1 - nextRandom(); //uniform(0,1] random floats + float u2 = 1 - nextRandom(); + float randStdNormal = (float)(Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2)); // random normal(0,1) + float scale = Math.Max(triangleScale * (mean + std_dev * randStdNormal), 0.1f); // random normal(mean,stdDev^2) + + return new TriangleParticle { Scale = scale }; + } + + private float nextRandom() => (float)(stableRandom?.NextDouble() ?? RNG.NextSingle()); + + protected override DrawNode CreateDrawNode() => new TrianglesDrawNode(this); + + private class TrianglesDrawNode : DrawNode + { + protected new TrianglesV2 Source => (TrianglesV2)base.Source; + + private IShader shader; + private Texture texture; + + private readonly List parts = new List(); + private Vector2 size; + + private IVertexBatch vertexBatch; + + public TrianglesDrawNode(TrianglesV2 source) + : base(source) + { + } + + public override void ApplyState() + { + base.ApplyState(); + + shader = Source.shader; + texture = Source.texture; + size = Source.DrawSize; + + parts.Clear(); + parts.AddRange(Source.parts); + } + + public override void Draw(IRenderer renderer) + { + base.Draw(renderer); + + if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount)) + { + vertexBatch?.Dispose(); + vertexBatch = renderer.CreateQuadBatch(Source.AimCount, 1); + } + + shader.Bind(); + + foreach (TriangleParticle particle in parts) + { + var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * 0.866f); + + Vector2 topLeft = particle.Position * size + new Vector2(-offset.X, 0f); + Vector2 topRight = particle.Position * size + new Vector2(offset.X, 0); + Vector2 bottomLeft = particle.Position * size + new Vector2(-offset.X, offset.Y); + Vector2 bottomRight = particle.Position * size + new Vector2(offset.X, offset.Y); + + var drawQuad = new Quad( + Vector2Extensions.Transform(topLeft, DrawInfo.Matrix), + Vector2Extensions.Transform(topRight, DrawInfo.Matrix), + Vector2Extensions.Transform(bottomLeft, DrawInfo.Matrix), + Vector2Extensions.Transform(bottomRight, DrawInfo.Matrix) + ); + + var tRect = new Quad( + topLeft.X / size.X, + topLeft.Y / size.Y * texture_height, + (topRight.X - topLeft.X) / size.X, + (bottomRight.Y - topRight.Y) / size.Y * texture_height + ).AABBFloat; + + renderer.DrawQuad(texture, drawQuad, DrawColourInfo.Colour, tRect, vertexBatch.AddAction, textureCoords: tRect); + } + + shader.Unbind(); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + vertexBatch?.Dispose(); + } + } + + protected struct TriangleParticle + { + /// + /// The position of the top vertex of the triangle. + /// + public Vector2 Position; + + /// + /// The scale of the triangle. + /// + public float Scale; + } + } +} From 4578a968131a0c0ca68732fa1c0420ddd0c9d2fb Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 13 Nov 2022 08:18:44 -0800 Subject: [PATCH 2198/2686] Fix beatmap card expanded content not blocking clicks from behind --- .../Beatmaps/Drawables/Cards/ExpandedContentScrollContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Beatmaps/Drawables/Cards/ExpandedContentScrollContainer.cs b/osu.Game/Beatmaps/Drawables/Cards/ExpandedContentScrollContainer.cs index a80a7998a5..c0ed6ac1a9 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/ExpandedContentScrollContainer.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/ExpandedContentScrollContainer.cs @@ -59,6 +59,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards return base.OnScroll(e); } + protected override bool OnClick(ClickEvent e) => true; + private class ExpandedContentScrollbar : OsuScrollbar { public ExpandedContentScrollbar(Direction scrollDir) From 56fd1f95b150b51ca839e08a4fbf31d8b97d1c9b Mon Sep 17 00:00:00 2001 From: Susko3 Date: Sun, 13 Nov 2022 18:47:28 +0100 Subject: [PATCH 2199/2686] Fix `FallbackSampleStore.GetAsync` fallback logic --- osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs index ad52b4affc..c50f63c3b2 100644 --- a/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs +++ b/osu.Game/Rulesets/UI/DrawableRulesetDependencies.cs @@ -115,7 +115,11 @@ namespace osu.Game.Rulesets.UI public Sample Get(string name) => primary.Get(name) ?? fallback.Get(name); - public Task GetAsync(string name, CancellationToken cancellationToken = default) => primary.GetAsync(name, cancellationToken) ?? fallback.GetAsync(name, cancellationToken); + public async Task GetAsync(string name, CancellationToken cancellationToken = default) + { + return await primary.GetAsync(name, cancellationToken).ConfigureAwait(false) + ?? await fallback.GetAsync(name, cancellationToken).ConfigureAwait(false); + } public Stream GetStream(string name) => primary.GetStream(name) ?? fallback.GetStream(name); From a8c95c39ad0dd19791f025497f27d61fbf77adf6 Mon Sep 17 00:00:00 2001 From: Dario Headley Date: Mon, 14 Nov 2022 16:18:36 +0100 Subject: [PATCH 2200/2686] Exclude sliderticks from the " freeze " --- osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs index bea5d4f5d9..0a1aab9ef1 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFreezeFrame.cs @@ -56,6 +56,8 @@ namespace osu.Game.Rulesets.Osu.Mods { switch (nested) { + //Freezing the SliderTicks doesnt play well with snaking sliders + case SliderTick: //SliderRepeat wont layer correctly if preempt is changed. case SliderRepeat: break; From 576f462f59e9cd6110582a611a01a25ebc71c057 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Nov 2022 00:53:38 +0900 Subject: [PATCH 2201/2686] Add pooling support to `BarHitErrorMeter` --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index e7b2ce1672..5fca8e2c51 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -11,6 +11,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Configuration; @@ -23,6 +24,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { + [Cached] public class BarHitErrorMeter : HitErrorMeter { private const int judgement_line_width = 14; @@ -44,6 +46,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [SettingSource("Label style", "How to show early/late extremities")] public Bindable LabelStyle { get; } = new Bindable(LabelStyles.Icons); + private readonly DrawablePool judgementLinePool = new DrawablePool(50, 100); + private SpriteIcon arrow; private UprightAspectMaintainingContainer labelEarly; private UprightAspectMaintainingContainer labelLate; @@ -88,6 +92,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters Margin = new MarginPadding(2), Children = new Drawable[] { + judgementLinePool, colourBars = new Container { Name = "colour axis", @@ -403,11 +408,12 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - judgementsContainer.Add(new JudgementLine + judgementLinePool.Get(drawableJudgement => { - JudgementLineThickness = { BindTarget = JudgementLineThickness }, - Y = getRelativeJudgementPosition(judgement.TimeOffset), - Colour = GetColourForHitResult(judgement.Type), + drawableJudgement.Y = getRelativeJudgementPosition(judgement.TimeOffset); + drawableJudgement.Colour = GetColourForHitResult(judgement.Type); + + judgementsContainer.Add(drawableJudgement); }); arrow.MoveToY( @@ -417,7 +423,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private float getRelativeJudgementPosition(double value) => Math.Clamp((float)((value / maxHitWindow) + 1) / 2, 0, 1); - internal class JudgementLine : CompositeDrawable + internal class JudgementLine : PoolableDrawable { public readonly BindableNumber JudgementLineThickness = new BindableFloat(); @@ -437,18 +443,27 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }; } + [Resolved] + private BarHitErrorMeter barHitErrorMeter { get; set; } + protected override void LoadComplete() { + base.LoadComplete(); + + JudgementLineThickness.BindTo(barHitErrorMeter.JudgementLineThickness); + JudgementLineThickness.BindValueChanged(thickness => Height = thickness.NewValue, true); + } + + protected override void PrepareForUse() + { + base.PrepareForUse(); + const int judgement_fade_in_duration = 100; const int judgement_fade_out_duration = 5000; - base.LoadComplete(); - Alpha = 0; Width = 0; - JudgementLineThickness.BindValueChanged(thickness => Height = thickness.NewValue, true); - this .FadeTo(0.6f, judgement_fade_in_duration, Easing.OutQuint) .ResizeWidthTo(1, judgement_fade_in_duration, Easing.OutQuint) From a86b50d62afd9cd279622f39d31505423ecee6fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Nov 2022 01:07:53 +0900 Subject: [PATCH 2202/2686] Apply nullability to `BarHitErrorMeter` --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 5fca8e2c51..23e9c86adc 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.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. -#nullable disable - using System; using System.Linq; using osu.Framework.Allocation; @@ -27,8 +25,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [Cached] public class BarHitErrorMeter : HitErrorMeter { - private const int judgement_line_width = 14; - [SettingSource("Judgement line thickness", "How thick the individual lines should be.")] public BindableNumber JudgementLineThickness { get; } = new BindableNumber(4) { @@ -46,30 +42,33 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters [SettingSource("Label style", "How to show early/late extremities")] public Bindable LabelStyle { get; } = new Bindable(LabelStyles.Icons); - private readonly DrawablePool judgementLinePool = new DrawablePool(50, 100); + private const int judgement_line_width = 14; - private SpriteIcon arrow; - private UprightAspectMaintainingContainer labelEarly; - private UprightAspectMaintainingContainer labelLate; + private const int max_concurrent_judgements = 50; - private Container colourBarsEarly; - private Container colourBarsLate; - - private Container judgementsContainer; + private const int centre_marker_size = 8; private double maxHitWindow; private double floatingAverage; - private Container colourBars; - private Container arrowContainer; - private (HitResult result, double length)[] hitWindows; + private readonly DrawablePool judgementLinePool = new DrawablePool(50, 100); - private const int max_concurrent_judgements = 50; + private SpriteIcon arrow = null!; + private UprightAspectMaintainingContainer labelEarly = null!; + private UprightAspectMaintainingContainer labelLate = null!; - private Drawable[] centreMarkerDrawables; + private Container colourBarsEarly = null!; + private Container colourBarsLate = null!; - private const int centre_marker_size = 8; + private Container judgementsContainer = null!; + + private Container colourBars = null!; + private Container arrowContainer = null!; + + private (HitResult result, double length)[] hitWindows = null!; + + private Drawable[]? centreMarkerDrawables; public BarHitErrorMeter() { @@ -427,6 +426,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { public readonly BindableNumber JudgementLineThickness = new BindableFloat(); + [Resolved] + private BarHitErrorMeter barHitErrorMeter { get; set; } = null!; + public JudgementLine() { RelativeSizeAxes = Axes.X; @@ -443,9 +445,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }; } - [Resolved] - private BarHitErrorMeter barHitErrorMeter { get; set; } - protected override void LoadComplete() { base.LoadComplete(); From aef6ee23eb871d7c7ae1550b4d451527a623d630 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Nov 2022 01:34:22 +0900 Subject: [PATCH 2203/2686] Apply pooling support to `ColourHitErrorMeter` --- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index dadec7c06b..6bf3ad0b28 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -3,9 +3,11 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Shapes; using osu.Game.Configuration; using osu.Game.Rulesets.Judgements; @@ -15,6 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { + [Cached] public class ColourHitErrorMeter : HitErrorMeter { private const int animation_duration = 200; @@ -82,7 +85,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { base.LoadComplete(); - JudgementCount.BindValueChanged(count => + JudgementCount.BindValueChanged(_ => { removeExtraJudgements(); updateMetrics(); @@ -91,11 +94,14 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters JudgementSpacing.BindValueChanged(_ => updateMetrics(), true); } + private readonly DrawablePool judgementLinePool = new DrawablePool(50); + public void Push(Color4 colour) { - Add(new HitErrorShape(colour, drawable_judgement_size) + judgementLinePool.Get(shape => { - Shape = { BindTarget = JudgementShape }, + shape.Colour = colour; + Add(shape); }); removeExtraJudgements(); @@ -116,32 +122,32 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - public class HitErrorShape : Container + public class HitErrorShape : PoolableDrawable { public bool IsRemoved { get; private set; } public readonly Bindable Shape = new Bindable(); - private readonly Color4 colour; + [Resolved] + private ColourHitErrorMeter hitErrorMeter { get; set; } = null!; private Container content = null!; - public HitErrorShape(Color4 colour, int size) + public HitErrorShape() { - this.colour = colour; - Size = new Vector2(size); + Size = new Vector2(drawable_judgement_size); } protected override void LoadComplete() { base.LoadComplete(); - Child = content = new Container + InternalChild = content = new Container { RelativeSizeAxes = Axes.Both, - Colour = colour }; + Shape.BindTo(hitErrorMeter.JudgementShape); Shape.BindValueChanged(shape => { switch (shape.NewValue) @@ -155,17 +161,27 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters break; } }, true); + } - content.FadeInFromZero(animation_duration, Easing.OutQuint); - content.MoveToY(-DrawSize.Y); - content.MoveToY(0, animation_duration, Easing.OutQuint); + protected override void PrepareForUse() + { + base.PrepareForUse(); + + IsRemoved = false; + + this.FadeIn(); + + content.FadeInFromZero(animation_duration, Easing.OutQuint) + .MoveToY(-DrawSize.Y) + .MoveToY(0, animation_duration, Easing.OutQuint); } public void Remove() { IsRemoved = true; - this.FadeOut(animation_duration, Easing.OutQuint).Expire(); + this.FadeOut(animation_duration, Easing.OutQuint) + .Expire(); } } From 59a8603728e280e8cd75e620a89ac7ba4d478bf6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Nov 2022 11:33:19 +0900 Subject: [PATCH 2204/2686] Ensure flowing animation starts correctly from zero --- .../Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 6bf3ad0b28..b82afe18a6 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -169,7 +169,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters IsRemoved = false; - this.FadeIn(); + this.FadeIn() + // On pool re-use, start flow animation from (0,0). + .MoveTo(Vector2.Zero); content.FadeInFromZero(animation_duration, Easing.OutQuint) .MoveToY(-DrawSize.Y) From 308ed1abd1353631d98f1c868fd010d0c989b807 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Nov 2022 11:55:33 +0900 Subject: [PATCH 2205/2686] Fix number of judgements shown potentially exceeding upper limit --- .../Visual/Gameplay/TestSceneHitErrorMeter.cs | 5 +---- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 17 ++++++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index 7c668adba5..b90b9b437d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -163,10 +163,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for bars to disappear", () => !this.ChildrenOfType().Any()); AddUntilStep("ensure max circles not exceeded", () => - { - return this.ChildrenOfType() - .All(m => m.ChildrenOfType().Count() <= max_displayed_judgements); - }); + this.ChildrenOfType().First().ChildrenOfType().Count(), () => Is.LessThanOrEqualTo(max_displayed_judgements)); AddStep("show displays", () => { diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index b82afe18a6..86ba85168f 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -102,9 +102,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { shape.Colour = colour; Add(shape); - }); - removeExtraJudgements(); + removeExtraJudgements(); + }); } private void removeExtraJudgements() @@ -167,17 +167,20 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { base.PrepareForUse(); - IsRemoved = false; - - this.FadeIn() + this.FadeInFromZero(animation_duration, Easing.OutQuint) // On pool re-use, start flow animation from (0,0). .MoveTo(Vector2.Zero); - content.FadeInFromZero(animation_duration, Easing.OutQuint) - .MoveToY(-DrawSize.Y) + content.MoveToY(-DrawSize.Y) .MoveToY(0, animation_duration, Easing.OutQuint); } + protected override void FreeAfterUse() + { + base.FreeAfterUse(); + IsRemoved = false; + } + public void Remove() { IsRemoved = true; From 489dca79a115060fe76cfa08d5a94b0886eec923 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Nov 2022 12:05:38 +0900 Subject: [PATCH 2206/2686] Remove upper limit for pooling --- osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 23e9c86adc..c9f1571dfe 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -52,7 +52,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private double floatingAverage; - private readonly DrawablePool judgementLinePool = new DrawablePool(50, 100); + private readonly DrawablePool judgementLinePool = new DrawablePool(50); private SpriteIcon arrow = null!; private UprightAspectMaintainingContainer labelEarly = null!; From 333165e0528f2f48d427d8cf215efcd01bfb886e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Nov 2022 10:54:37 +0300 Subject: [PATCH 2207/2686] Add test scene for Triangles --- .../TestSceneTrianglesBackground.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs new file mode 100644 index 0000000000..81a3249efb --- /dev/null +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs @@ -0,0 +1,40 @@ +// 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.Graphics.Backgrounds; +using osu.Framework.Graphics; +using osuTK.Graphics; +using osu.Framework.Graphics.Shapes; + +namespace osu.Game.Tests.Visual.Background +{ + public class TestSceneTrianglesBackground : OsuTestScene + { + private readonly Triangles triangles; + + public TestSceneTrianglesBackground() + { + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black + }, + triangles = new Triangles + { + RelativeSizeAxes = Axes.Both, + ColourLight = Color4.White, + ColourDark = Color4.Gray + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + AddSliderStep("Triangle scale", 0f, 10f, 1f, s => triangles.TriangleScale = s); + } + } +} From ebff8443340c66acf7fd41deb1feaf7ef1e14080 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Nov 2022 11:06:28 +0300 Subject: [PATCH 2208/2686] Reset triangles on scale change --- osu.Game/Graphics/Backgrounds/Triangles.cs | 34 ++++++++-------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 986f5d3ac5..b5e77ec638 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Lists; +using osu.Framework.Bindables; namespace osu.Game.Graphics.Backgrounds { @@ -69,7 +70,13 @@ namespace osu.Game.Graphics.Backgrounds /// protected virtual float SpawnRatio => 1; - private float triangleScale = 1; + private readonly BindableFloat triangleScale = new BindableFloat(1f); + + public float TriangleScale + { + get => triangleScale.Value; + set => triangleScale.Value = value; + } /// /// Whether we should drop-off alpha values of triangles more quickly to improve @@ -109,24 +116,7 @@ namespace osu.Game.Graphics.Backgrounds protected override void LoadComplete() { base.LoadComplete(); - addTriangles(true); - } - - public float TriangleScale - { - get => triangleScale; - set - { - float change = value / triangleScale; - triangleScale = value; - - for (int i = 0; i < parts.Count; i++) - { - TriangleParticle newParticle = parts[i]; - newParticle.Scale *= change; - parts[i] = newParticle; - } - } + triangleScale.BindValueChanged(_ => Reset(), true); } protected override void Update() @@ -147,7 +137,7 @@ namespace osu.Game.Graphics.Backgrounds // Since position is relative, the velocity needs to scale inversely with DrawHeight. // Since we will later multiply by the scale of individual triangles we normalize by // dividing by triangleScale. - float movedDistance = -elapsedSeconds * Velocity * base_velocity / (DrawHeight * triangleScale); + float movedDistance = -elapsedSeconds * Velocity * base_velocity / (DrawHeight * TriangleScale); for (int i = 0; i < parts.Count; i++) { @@ -185,7 +175,7 @@ namespace osu.Game.Graphics.Backgrounds // Limited by the maximum size of QuadVertexBuffer for safety. const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2); - AimCount = (int)Math.Min(max_triangles, (DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio)); + AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.002f / (TriangleScale * TriangleScale) * SpawnRatio); for (int i = 0; i < AimCount - parts.Count; i++) parts.Add(createTriangle(randomY)); @@ -214,7 +204,7 @@ namespace osu.Game.Graphics.Backgrounds float u1 = 1 - nextRandom(); //uniform(0,1] random floats float u2 = 1 - nextRandom(); float randStdNormal = (float)(Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2)); // random normal(0,1) - float scale = Math.Max(triangleScale * (mean + std_dev * randStdNormal), 0.1f); // random normal(mean,stdDev^2) + float scale = Math.Max(TriangleScale * (mean + std_dev * randStdNormal), 0.1f); // random normal(mean,stdDev^2) return new TriangleParticle { Scale = scale }; } From c7dc6db124653d628860137d40c7c1c419af9133 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Nov 2022 11:32:05 +0300 Subject: [PATCH 2209/2686] Fix incorrect number of added triangles --- osu.Game/Graphics/Backgrounds/Triangles.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index b5e77ec638..433b264468 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -177,7 +177,9 @@ namespace osu.Game.Graphics.Backgrounds AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.002f / (TriangleScale * TriangleScale) * SpawnRatio); - for (int i = 0; i < AimCount - parts.Count; i++) + int currentCount = parts.Count; + + for (int i = 0; i < AimCount - currentCount; i++) parts.Add(createTriangle(randomY)); } From f27a5f977d91bc57f40a9f0316f0ec70aae07df5 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Nov 2022 11:49:53 +0300 Subject: [PATCH 2210/2686] Improve triangles distribution --- osu.Game/Graphics/Backgrounds/Triangles.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 433b264468..e2434bb665 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -187,13 +187,27 @@ namespace osu.Game.Graphics.Backgrounds { TriangleParticle particle = CreateTriangle(); - particle.Position = new Vector2(nextRandom(), randomY ? nextRandom() : 1); + particle.Position = getRandomPosition(randomY, particle.Scale); particle.ColourShade = nextRandom(); particle.Colour = CreateTriangleShade(particle.ColourShade); return particle; } + private Vector2 getRandomPosition(bool randomY, float scale) + { + float y = 1; + + if (randomY) + { + // since triangles are drawn from the top - allow them to be positioned a bit above the screen + float maxOffset = triangle_size * scale * 0.866f / DrawHeight; + y = Interpolation.ValueAt(nextRandom(), -maxOffset, 1f, 0f, 1f); + } + + return new Vector2(nextRandom(), y); + } + /// /// Creates a triangle particle with a random scale. /// From 233d45e18508eac8e5544534cdb65f773d02be9c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Nov 2022 18:22:27 +0900 Subject: [PATCH 2211/2686] Fix argon swells incorrectly flashing on every hit --- .../Skinning/Argon/ArgonCirclePiece.cs | 8 ++++++-- osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs index 22f96da61e..c22c0e9e79 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Taiko.Objects; using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon @@ -81,12 +82,15 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon updateStateTransforms(drawableHitObject, drawableHitObject.State.Value); } - private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) + private void updateStateTransforms(DrawableHitObject h, ArmedState state) { + if (h.HitObject is not Hit) + return; + switch (state) { case ArmedState.Hit: - using (BeginAbsoluteSequence(drawableHitObject.HitStateUpdateTime)) + using (BeginAbsoluteSequence(h.HitStateUpdateTime)) { flash.FadeTo(0.9f).FadeOut(500, Easing.OutQuint); } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index ccde8e6ac9..7ddc413d98 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs @@ -153,12 +153,15 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default updateStateTransforms(drawableHitObject, drawableHitObject.State.Value); } - private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) + private void updateStateTransforms(DrawableHitObject h, ArmedState state) { + if (h.HitObject is not Hit) + return; + switch (state) { case ArmedState.Hit: - using (BeginAbsoluteSequence(drawableHitObject.HitStateUpdateTime)) + using (BeginAbsoluteSequence(h.HitStateUpdateTime)) flashBox.FadeTo(0.9f).FadeOut(300); break; } From e8d170e7728ac7427dcb483a7969dfcc8ceeddac Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Tue, 15 Nov 2022 20:55:55 +0800 Subject: [PATCH 2212/2686] disable certain options when no beatmap is selected --- osu.Game/Screens/Select/PlaySongSelect.cs | 12 +++++++++++- osu.Game/Screens/Select/SongSelect.cs | 22 +++++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 94e4215175..9c590114d5 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -14,6 +14,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; +using osu.Game.Screens.Select.Options; using osu.Game.Users; using osu.Game.Utils; using osuTK.Input; @@ -33,10 +34,12 @@ namespace osu.Game.Screens.Select private PlayBeatmapDetailArea playBeatmapDetailArea = null!; + protected BeatmapOptionsButton? editOptionButton; + [BackgroundDependencyLoader] private void load(OsuColour colours) { - BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit()); + editOptionButton = BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit()); } protected void PresentScore(ScoreInfo score) => @@ -142,5 +145,12 @@ namespace osu.Game.Screens.Select playerLoader = null; } } + + protected override void OnBeatmapOptionsButtonDisabledChanged(bool disabled) + { + base.OnBeatmapOptionsButtonDisabledChanged(disabled); + + if (editOptionButton != null) editOptionButton.Disabled = disabled; + } } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 1add51e725..72645c23be 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -116,6 +116,10 @@ namespace osu.Game.Screens.Select private double audioFeedbackLastPlaybackTime; + protected BeatmapOptionsButton deleteOptionButton; + + protected BeatmapOptionsButton clearOptionButton; + [CanBeNull] private IDisposable modSelectOverlayRegistration; @@ -285,9 +289,9 @@ namespace osu.Game.Screens.Select Footer.AddButton(button, overlay); BeatmapOptions.AddButton(@"Manage", @"collections", FontAwesome.Solid.Book, colours.Green, () => manageCollectionsDialog?.Show()); - BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo)); BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null); - BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo)); + deleteOptionButton = BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo)); + clearOptionButton = BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo)); } sampleChangeDifficulty = audio.Samples.Get(@"SongSelect/select-difficulty"); @@ -412,7 +416,13 @@ namespace osu.Game.Screens.Select private void updateCarouselSelection(ValueChangedEvent e = null) { var beatmap = e?.NewValue ?? Beatmap.Value; - if (beatmap is DummyWorkingBeatmap || !this.IsCurrentScreen()) return; + + if (beatmap is DummyWorkingBeatmap || !this.IsCurrentScreen()) + { + OnBeatmapOptionsButtonDisabledChanged(true); + return; + } + OnBeatmapOptionsButtonDisabledChanged(false); Logger.Log($"Song select working beatmap updated to {beatmap}"); @@ -647,6 +657,12 @@ namespace osu.Game.Screens.Select return false; } + protected virtual void OnBeatmapOptionsButtonDisabledChanged(bool disabled) + { + deleteOptionButton.Disabled = disabled; + clearOptionButton.Disabled = disabled; + } + private void playExitingTransition() { ModSelect.Hide(); From 1186ed3e32acad13312db54a5a18ee0cf56257c0 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Tue, 15 Nov 2022 20:56:18 +0800 Subject: [PATCH 2213/2686] add disable --- .../Select/Options/BeatmapOptionsButton.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index 69800c4e86..7d9792d950 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -31,6 +31,31 @@ namespace osu.Game.Screens.Select.Options private readonly OsuSpriteText secondLine; private readonly Container box; + private readonly float disabledAlpha = 0.5f; + + private bool disabled; + + public bool Disabled + { + get => disabled; + set + { + disabled = value; + + if (disabled) + { + firstLine.Alpha = disabledAlpha; + secondLine.Alpha = disabledAlpha; + iconText.Alpha = disabledAlpha; + return; + } + + firstLine.Alpha = 1; + secondLine.Alpha = 1; + iconText.Alpha = 1; + } + } + public Color4 ButtonColour { get => background.Colour; @@ -57,18 +82,24 @@ namespace osu.Game.Screens.Select.Options protected override bool OnMouseDown(MouseDownEvent e) { + if (disabled) return true; + flash.FadeTo(0.1f, 1000, Easing.OutQuint); return base.OnMouseDown(e); } protected override void OnMouseUp(MouseUpEvent e) { + if (disabled) return; + flash.FadeTo(0, 1000, Easing.OutQuint); base.OnMouseUp(e); } protected override bool OnClick(ClickEvent e) { + if (disabled) return true; + flash.ClearTransforms(); flash.Alpha = 0.9f; flash.FadeOut(800, Easing.OutExpo); From 5973bb1956ae05fc8bb73921feb84acb1d3119b7 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Tue, 15 Nov 2022 20:57:31 +0800 Subject: [PATCH 2214/2686] AddButton now returns the button --- osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs index 8785dac0aa..139d9e60b5 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs @@ -66,7 +66,7 @@ namespace osu.Game.Screens.Select.Options /// Colour of the button. /// Icon of the button. /// Binding the button does. - public void AddButton(LocalisableString firstLine, string secondLine, IconUsage icon, Color4 colour, Action action) + public BeatmapOptionsButton AddButton(LocalisableString firstLine, string secondLine, IconUsage icon, Color4 colour, Action action) { var button = new BeatmapOptionsButton { @@ -82,6 +82,8 @@ namespace osu.Game.Screens.Select.Options }; buttonsContainer.Add(button); + + return button; } protected override void PopIn() From 7aec5ca1e8586b2d14e4deac47ceb79ff2a3a574 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Tue, 15 Nov 2022 20:57:42 +0800 Subject: [PATCH 2215/2686] visual tests --- .../SongSelect/TestScenePlaySongSelect.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 63532fdba8..db49afe79d 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -37,6 +37,7 @@ using osu.Game.Screens.Select; using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Filter; using osu.Game.Tests.Resources; +using osu.Game.Screens.Select.Options; using osuTK.Input; namespace osu.Game.Tests.Visual.SongSelect @@ -1055,6 +1056,24 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("mod overlay hidden", () => songSelect!.ModSelect.State.Value == Visibility.Hidden); } + [Test] + public void TestBeatmapOptionsButtonDisable() + { + createSongSelect(); + + addRulesetImportStep(0); + + AddAssert("delete option enabled", () => songSelect!.DeleteOptionButton.Disabled == false); + AddAssert("clear option enabled", () => songSelect!.ClearOptionButton.Disabled == false); + AddAssert("edit option enabled", () => songSelect!.EditOptionButton?.Disabled == false); + + AddStep("delete all beatmaps", () => manager.Delete()); + + AddAssert("delete option disabled", () => songSelect!.DeleteOptionButton.Disabled == true); + AddAssert("clear option disabled", () => songSelect!.ClearOptionButton.Disabled == true); + AddAssert("edit option disabled", () => songSelect!.EditOptionButton?.Disabled == true); + } + private void waitForInitialSelection() { AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault); @@ -1142,6 +1161,12 @@ namespace osu.Game.Tests.Visual.SongSelect public new BeatmapCarousel Carousel => base.Carousel; public new ModSelectOverlay ModSelect => base.ModSelect; + public BeatmapOptionsButton DeleteOptionButton => base.deleteOptionButton; + + public BeatmapOptionsButton ClearOptionButton => base.clearOptionButton; + + public BeatmapOptionsButton? EditOptionButton => base.editOptionButton; + public new void PresentScore(ScoreInfo score) => base.PresentScore(score); protected override bool OnStart() From 52ecd894db8ca4b44758c5a28ac6ccf2d54ee760 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Nov 2022 22:20:08 +0900 Subject: [PATCH 2216/2686] Move equilateral triangle ratio to constant --- osu.Game/Graphics/Backgrounds/Triangles.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index e2434bb665..09d137011c 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -26,6 +26,11 @@ namespace osu.Game.Graphics.Backgrounds private const float triangle_size = 100; private const float base_velocity = 50; + /// + /// sqrt(3) / 2 + /// + private const float equilateral_triangle_ratio = 0.866f; + /// /// How many screen-space pixels are smoothed over. /// Same behavior as Sprite's EdgeSmoothness. @@ -149,7 +154,7 @@ namespace osu.Game.Graphics.Backgrounds parts[i] = newParticle; - float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * 0.866f / DrawHeight; + float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * equilateral_triangle_ratio / DrawHeight; if (bottomPos < 0) parts.RemoveAt(i); } @@ -201,7 +206,7 @@ namespace osu.Game.Graphics.Backgrounds if (randomY) { // since triangles are drawn from the top - allow them to be positioned a bit above the screen - float maxOffset = triangle_size * scale * 0.866f / DrawHeight; + float maxOffset = triangle_size * scale * equilateral_triangle_ratio / DrawHeight; y = Interpolation.ValueAt(nextRandom(), -maxOffset, 1f, 0f, 1f); } @@ -290,7 +295,7 @@ namespace osu.Game.Graphics.Backgrounds foreach (TriangleParticle particle in parts) { - var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * 0.866f); + var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * equilateral_triangle_ratio); var triangle = new Triangle( Vector2Extensions.Transform(particle.Position * size, DrawInfo.Matrix), From 70f50c1319f13a63bcbccc2b2e50d13b4d59d174 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Nov 2022 22:46:20 +0900 Subject: [PATCH 2217/2686] Add test scene covering taiko swell --- .../Skinning/TestSceneDrawableSwell.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs new file mode 100644 index 0000000000..b8c0f6f11e --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.Objects.Drawables; + +namespace osu.Game.Rulesets.Taiko.Tests.Skinning +{ + [TestFixture] + public class TestSceneDrawableSwell : TaikoSkinnableTestScene + { + [Test] + public void TestHits() + { + AddStep("Centre hit", () => SetContents(_ => new DrawableSwell(createHitAtCurrentTime()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + })); + } + + private Swell createHitAtCurrentTime() + { + var hit = new Swell + { + StartTime = Time.Current + 3000, + EndTime = Time.Current + 6000, + }; + + hit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + + return hit; + } + } +} From 9101ad0cbd399f4faa7957792e5efe5d31811932 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Wed, 16 Nov 2022 09:42:40 +0800 Subject: [PATCH 2218/2686] fixed naming --- .../Visual/SongSelect/TestScenePlaySongSelect.cs | 6 +++--- osu.Game/Screens/Select/PlaySongSelect.cs | 6 +++--- osu.Game/Screens/Select/SongSelect.cs | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index db49afe79d..1892eaaf3b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -1161,11 +1161,11 @@ namespace osu.Game.Tests.Visual.SongSelect public new BeatmapCarousel Carousel => base.Carousel; public new ModSelectOverlay ModSelect => base.ModSelect; - public BeatmapOptionsButton DeleteOptionButton => base.deleteOptionButton; + public new BeatmapOptionsButton DeleteOptionButton => base.DeleteOptionButton; - public BeatmapOptionsButton ClearOptionButton => base.clearOptionButton; + public new BeatmapOptionsButton ClearOptionButton => base.ClearOptionButton; - public BeatmapOptionsButton? EditOptionButton => base.editOptionButton; + public new BeatmapOptionsButton? EditOptionButton => base.EditOptionButton; public new void PresentScore(ScoreInfo score) => base.PresentScore(score); diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 9c590114d5..e61c0c4c59 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -34,12 +34,12 @@ namespace osu.Game.Screens.Select private PlayBeatmapDetailArea playBeatmapDetailArea = null!; - protected BeatmapOptionsButton? editOptionButton; + protected BeatmapOptionsButton? EditOptionButton; [BackgroundDependencyLoader] private void load(OsuColour colours) { - editOptionButton = BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit()); + EditOptionButton = BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit()); } protected void PresentScore(ScoreInfo score) => @@ -150,7 +150,7 @@ namespace osu.Game.Screens.Select { base.OnBeatmapOptionsButtonDisabledChanged(disabled); - if (editOptionButton != null) editOptionButton.Disabled = disabled; + if (EditOptionButton != null) EditOptionButton.Disabled = disabled; } } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 72645c23be..c91912ec85 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -116,9 +116,9 @@ namespace osu.Game.Screens.Select private double audioFeedbackLastPlaybackTime; - protected BeatmapOptionsButton deleteOptionButton; + protected BeatmapOptionsButton DeleteOptionButton; - protected BeatmapOptionsButton clearOptionButton; + protected BeatmapOptionsButton ClearOptionButton; [CanBeNull] private IDisposable modSelectOverlayRegistration; @@ -290,8 +290,8 @@ namespace osu.Game.Screens.Select BeatmapOptions.AddButton(@"Manage", @"collections", FontAwesome.Solid.Book, colours.Green, () => manageCollectionsDialog?.Show()); BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null); - deleteOptionButton = BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo)); - clearOptionButton = BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo)); + DeleteOptionButton = BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo)); + ClearOptionButton = BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo)); } sampleChangeDifficulty = audio.Samples.Get(@"SongSelect/select-difficulty"); @@ -659,8 +659,8 @@ namespace osu.Game.Screens.Select protected virtual void OnBeatmapOptionsButtonDisabledChanged(bool disabled) { - deleteOptionButton.Disabled = disabled; - clearOptionButton.Disabled = disabled; + DeleteOptionButton.Disabled = disabled; + ClearOptionButton.Disabled = disabled; } private void playExitingTransition() From 46c7451ede328a01cb6465ad144f7545cd524f24 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Wed, 16 Nov 2022 09:57:23 +0800 Subject: [PATCH 2219/2686] remove redundant code --- .../Visual/SongSelect/TestScenePlaySongSelect.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 1892eaaf3b..51c4c5e661 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -1063,14 +1063,14 @@ namespace osu.Game.Tests.Visual.SongSelect addRulesetImportStep(0); - AddAssert("delete option enabled", () => songSelect!.DeleteOptionButton.Disabled == false); - AddAssert("clear option enabled", () => songSelect!.ClearOptionButton.Disabled == false); + AddAssert("delete option enabled", () => !songSelect!.DeleteOptionButton.Disabled); + AddAssert("clear option enabled", () => !songSelect!.ClearOptionButton.Disabled); AddAssert("edit option enabled", () => songSelect!.EditOptionButton?.Disabled == false); AddStep("delete all beatmaps", () => manager.Delete()); - AddAssert("delete option disabled", () => songSelect!.DeleteOptionButton.Disabled == true); - AddAssert("clear option disabled", () => songSelect!.ClearOptionButton.Disabled == true); + AddAssert("delete option disabled", () => songSelect!.DeleteOptionButton.Disabled); + AddAssert("clear option disabled", () => songSelect!.ClearOptionButton.Disabled); AddAssert("edit option disabled", () => songSelect!.EditOptionButton?.Disabled == true); } From 1fb8357e93e92cf08d17604f3cbba26a2a8167ff Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Wed, 16 Nov 2022 09:58:32 +0800 Subject: [PATCH 2220/2686] change `disabledAlpha` from `readonly` to `const` --- osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index 7d9792d950..1fc5b2bc74 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Select.Options private readonly OsuSpriteText secondLine; private readonly Container box; - private readonly float disabledAlpha = 0.5f; + private const float disabledAlpha = 0.5f; private bool disabled; From 55edd6c9078b0d17a1b68de387f3f4727eb120e7 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Wed, 16 Nov 2022 09:58:49 +0800 Subject: [PATCH 2221/2686] add space --- osu.Game/Screens/Select/SongSelect.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index c91912ec85..0341a9bb07 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -422,6 +422,7 @@ namespace osu.Game.Screens.Select OnBeatmapOptionsButtonDisabledChanged(true); return; } + OnBeatmapOptionsButtonDisabledChanged(false); Logger.Log($"Song select working beatmap updated to {beatmap}"); From 5d8d8ffce506d469ca05ea91ccdad4bffb2ff649 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Wed, 16 Nov 2022 10:09:51 +0800 Subject: [PATCH 2222/2686] fix naming --- osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index 1fc5b2bc74..73bc68f6b0 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Select.Options private readonly OsuSpriteText secondLine; private readonly Container box; - private const float disabledAlpha = 0.5f; + private const float disabled_alpha = 0.5f; private bool disabled; @@ -44,9 +44,9 @@ namespace osu.Game.Screens.Select.Options if (disabled) { - firstLine.Alpha = disabledAlpha; - secondLine.Alpha = disabledAlpha; - iconText.Alpha = disabledAlpha; + firstLine.Alpha = disabled_alpha; + secondLine.Alpha = disabled_alpha; + iconText.Alpha = disabled_alpha; return; } From bb762d813150b7d0a89d5e851a719b574f2bae1f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Nov 2022 15:45:26 +0900 Subject: [PATCH 2223/2686] Fix "reset to full area" button not always working correctly --- .../Overlays/Settings/Sections/Input/TabletSettings.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 59c7ff04a2..de52a1f938 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -111,9 +111,10 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux) { t.NewLine(); - var formattedSource = MessageFormatter.FormatText(localisation.GetLocalisedBindableString(TabletSettingsStrings.NoTabletDetectedDescription(RuntimeInfo.OS == RuntimeInfo.Platform.Windows - ? @"https://opentabletdriver.net/Wiki/FAQ/Windows" - : @"https://opentabletdriver.net/Wiki/FAQ/Linux")).Value); + var formattedSource = MessageFormatter.FormatText(localisation.GetLocalisedBindableString(TabletSettingsStrings.NoTabletDetectedDescription( + RuntimeInfo.OS == RuntimeInfo.Platform.Windows + ? @"https://opentabletdriver.net/Wiki/FAQ/Windows" + : @"https://opentabletdriver.net/Wiki/FAQ/Linux")).Value); t.AddLinks(formattedSource.Text, formattedSource.Links); } }), @@ -274,6 +275,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input sizeY.Default = sizeY.MaxValue = tab.Size.Y; areaSize.Default = new Vector2(sizeX.Default, sizeY.Default); + areaOffset.Default = new Vector2(offsetX.Default, offsetY.Default); }), true); } From 45f47cce77358ee53b5478e2508eef2fc6287a3c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Nov 2022 16:13:52 +0900 Subject: [PATCH 2224/2686] Add basic osu!taiko "argon" swell visual --- .../Skinning/Argon/ArgonSwellCirclePiece.cs | 34 +++++++++++++++++++ .../Argon/TaikoArgonSkinTransformer.cs | 3 ++ 2 files changed, 37 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwellCirclePiece.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwellCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwellCirclePiece.cs new file mode 100644 index 0000000000..82a6e34128 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwellCirclePiece.cs @@ -0,0 +1,34 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Sprites; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Taiko.Skinning.Argon +{ + public class ArgonSwellCirclePiece : ArgonCirclePiece + { + [BackgroundDependencyLoader] + private void load() + { + AccentColour = ColourInfo.GradientVertical( + new Color4(240, 201, 0, 255), + new Color4(167, 139, 0, 255) + ); + + AddInternal(new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.Solid.Asterisk, + Size = new Vector2(ICON_SIZE), + Scale = new Vector2(0.8f, 1) + }); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index 6d1087793d..a5d091a1c8 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -60,6 +60,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon case TaikoSkinComponents.TaikoExplosionMiss: case TaikoSkinComponents.TaikoExplosionOk: return new ArgonHitExplosion(taikoComponent.Component); + + case TaikoSkinComponents.Swell: + return new ArgonSwellCirclePiece(); } break; From ee6fffec5f08bb6d34cae5e7fefb7184eae4132a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Nov 2022 17:54:49 +0900 Subject: [PATCH 2225/2686] Fix combo colour normalisation setting not applying to editor test play --- .../Screens/Edit/GameplayTest/EditorPlayer.cs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs index 94975b6b5e..7fc62b3c14 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs @@ -1,23 +1,25 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Screens; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Overlays; using osu.Game.Screens.Play; namespace osu.Game.Screens.Edit.GameplayTest { - public class EditorPlayer : Player + public class EditorPlayer : Player, IGameplaySettings { private readonly Editor editor; private readonly EditorState editorState; [Resolved] - private MusicController musicController { get; set; } + private MusicController musicController { get; set; } = null!; + + private OsuConfigManager config = null!; public EditorPlayer(Editor editor) : base(new PlayerConfiguration { ShowResults = false }) @@ -26,6 +28,14 @@ namespace osu.Game.Screens.Edit.GameplayTest editorState = editor.GetState(); } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + // needs to be populated before BDL to work correctly. + config = parent.Get(); + + return base.CreateChildDependencies(parent); + } + protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) { var masterGameplayClockContainer = new MasterGameplayClockContainer(beatmap, gameplayStart); @@ -74,5 +84,9 @@ namespace osu.Game.Screens.Edit.GameplayTest editor.RestoreState(editorState); return base.OnExiting(e); } + + // Editor overrides but we actually want to use game-wide settings here. + public IBindable ComboColourNormalisationAmount => ((IGameplaySettings)config).ComboColourNormalisationAmount; + public IBindable PositionalHitsoundsLevel => ((IGameplaySettings)config).PositionalHitsoundsLevel; } } From bda32d71bf3f2f9467875a5d0a06574bc713153d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 16 Nov 2022 14:53:55 +0300 Subject: [PATCH 2226/2686] Change test scene name --- .../TestSceneTrianglesV2Background.cs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs new file mode 100644 index 0000000000..59922377b0 --- /dev/null +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.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.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osuTK; +using osuTK.Graphics; +using osu.Game.Graphics.Backgrounds; + +namespace osu.Game.Tests.Visual.Background +{ + public class TestSceneTrianglesV2Background : OsuTestScene + { + public TestSceneTrianglesV2Background() + { + AddRange(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Gray + }, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(200), + Masking = true, + CornerRadius = 40, + Child = new TrianglesV2 + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + ColourTop = Color4.Red, + ColourBottom = Color4.Orange + } + } + }); + } + } +} From 109aa37dd873f5dc56872c13208accc0a490eb93 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 16 Nov 2022 15:02:09 +0300 Subject: [PATCH 2227/2686] Apply fixes from original Triangles --- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 57 +++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 89ec7d2ad5..01e4a39431 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -27,6 +27,11 @@ namespace osu.Game.Graphics.Backgrounds private const float base_velocity = 50; private const int texture_height = 128; + /// + /// sqrt(3) / 2 + /// + private const float equilateral_triangle_ratio = 0.866f; + private readonly Bindable colourTop = new Bindable(Color4.White); private readonly Bindable colourBottom = new Bindable(Color4.Black); @@ -52,7 +57,13 @@ namespace osu.Game.Graphics.Backgrounds /// protected virtual float SpawnRatio => 1; - private float triangleScale = 1; + private readonly BindableFloat triangleScale = new BindableFloat(1f); + + public float TriangleScale + { + get => triangleScale.Value; + set => triangleScale.Value = value; + } /// /// The relative velocity of the triangles. Default is 1. @@ -91,7 +102,7 @@ namespace osu.Game.Graphics.Backgrounds colourTop.BindValueChanged(_ => updateTexture()); colourBottom.BindValueChanged(_ => updateTexture(), true); - addTriangles(true); + triangleScale.BindValueChanged(_ => Reset(), true); } private void updateTexture() @@ -116,23 +127,6 @@ namespace osu.Game.Graphics.Backgrounds Invalidate(Invalidation.DrawNode); } - public float TriangleScale - { - get => triangleScale; - set - { - float change = value / triangleScale; - triangleScale = value; - - for (int i = 0; i < parts.Count; i++) - { - TriangleParticle newParticle = parts[i]; - newParticle.Scale *= change; - parts[i] = newParticle; - } - } - } - protected override void Update() { base.Update(); @@ -146,7 +140,7 @@ namespace osu.Game.Graphics.Backgrounds // Since position is relative, the velocity needs to scale inversely with DrawHeight. // Since we will later multiply by the scale of individual triangles we normalize by // dividing by triangleScale. - float movedDistance = -elapsedSeconds * Velocity * base_velocity / (DrawHeight * triangleScale); + float movedDistance = -elapsedSeconds * Velocity * base_velocity / (DrawHeight * TriangleScale); for (int i = 0; i < parts.Count; i++) { @@ -157,7 +151,7 @@ namespace osu.Game.Graphics.Backgrounds parts[i] = newParticle; - float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * 0.866f / DrawHeight; + float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * equilateral_triangle_ratio / DrawHeight; if (bottomPos < 0) parts.RemoveAt(i); } @@ -183,9 +177,11 @@ namespace osu.Game.Graphics.Backgrounds // Limited by the maximum size of QuadVertexBuffer for safety. const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2); - AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.002f / (triangleScale * triangleScale) * SpawnRatio); + AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.002f / (TriangleScale * TriangleScale) * SpawnRatio); - for (int i = 0; i < AimCount - parts.Count; i++) + int currentCount = parts.Count; + + for (int i = 0; i < AimCount - currentCount; i++) parts.Add(createTriangle(randomY)); } @@ -193,7 +189,16 @@ namespace osu.Game.Graphics.Backgrounds { TriangleParticle particle = CreateTriangle(); - particle.Position = new Vector2(nextRandom(), randomY ? nextRandom() : 1); + float y = 1; + + if (randomY) + { + // since triangles are drawn from the top - allow them to be positioned a bit above the screen + float maxOffset = triangle_size * particle.Scale * equilateral_triangle_ratio / DrawHeight; + y = Interpolation.ValueAt(nextRandom(), -maxOffset, 1f, 0f, 1f); + } + + particle.Position = new Vector2(nextRandom(), y); return particle; } @@ -210,7 +215,7 @@ namespace osu.Game.Graphics.Backgrounds float u1 = 1 - nextRandom(); //uniform(0,1] random floats float u2 = 1 - nextRandom(); float randStdNormal = (float)(Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2)); // random normal(0,1) - float scale = Math.Max(triangleScale * (mean + std_dev * randStdNormal), 0.1f); // random normal(mean,stdDev^2) + float scale = Math.Max(TriangleScale * (mean + std_dev * randStdNormal), 0.1f); // random normal(mean,stdDev^2) return new TriangleParticle { Scale = scale }; } @@ -262,7 +267,7 @@ namespace osu.Game.Graphics.Backgrounds foreach (TriangleParticle particle in parts) { - var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * 0.866f); + var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * equilateral_triangle_ratio); Vector2 topLeft = particle.Position * size + new Vector2(-offset.X, 0f); Vector2 topRight = particle.Position * size + new Vector2(offset.X, 0); From cc4f05f3d3ce98a33f3c51a2779d42930f4cc480 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 16 Nov 2022 15:12:57 +0300 Subject: [PATCH 2228/2686] Replace Scale with SpeedMultiplier --- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 35 +++++++------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 01e4a39431..da31c6112b 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -57,14 +57,6 @@ namespace osu.Game.Graphics.Backgrounds /// protected virtual float SpawnRatio => 1; - private readonly BindableFloat triangleScale = new BindableFloat(1f); - - public float TriangleScale - { - get => triangleScale.Value; - set => triangleScale.Value = value; - } - /// /// The relative velocity of the triangles. Default is 1. /// @@ -102,7 +94,7 @@ namespace osu.Game.Graphics.Backgrounds colourTop.BindValueChanged(_ => updateTexture()); colourBottom.BindValueChanged(_ => updateTexture(), true); - triangleScale.BindValueChanged(_ => Reset(), true); + addTriangles(true); } private void updateTexture() @@ -138,20 +130,17 @@ namespace osu.Game.Graphics.Backgrounds float elapsedSeconds = (float)Time.Elapsed / 1000; // Since position is relative, the velocity needs to scale inversely with DrawHeight. - // Since we will later multiply by the scale of individual triangles we normalize by - // dividing by triangleScale. - float movedDistance = -elapsedSeconds * Velocity * base_velocity / (DrawHeight * TriangleScale); + float movedDistance = -elapsedSeconds * Velocity * base_velocity / DrawHeight; for (int i = 0; i < parts.Count; i++) { TriangleParticle newParticle = parts[i]; - // Scale moved distance by the size of the triangle. Smaller triangles should move more slowly. - newParticle.Position.Y += Math.Max(0.5f, parts[i].Scale) * movedDistance; + newParticle.Position.Y += Math.Max(0.5f, parts[i].SpeedMultiplier) * movedDistance; parts[i] = newParticle; - float bottomPos = parts[i].Position.Y + triangle_size * parts[i].Scale * equilateral_triangle_ratio / DrawHeight; + float bottomPos = parts[i].Position.Y + triangle_size * equilateral_triangle_ratio / DrawHeight; if (bottomPos < 0) parts.RemoveAt(i); } @@ -177,7 +166,7 @@ namespace osu.Game.Graphics.Backgrounds // Limited by the maximum size of QuadVertexBuffer for safety. const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2); - AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.002f / (TriangleScale * TriangleScale) * SpawnRatio); + AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.001f * SpawnRatio); int currentCount = parts.Count; @@ -194,7 +183,7 @@ namespace osu.Game.Graphics.Backgrounds if (randomY) { // since triangles are drawn from the top - allow them to be positioned a bit above the screen - float maxOffset = triangle_size * particle.Scale * equilateral_triangle_ratio / DrawHeight; + float maxOffset = triangle_size * equilateral_triangle_ratio / DrawHeight; y = Interpolation.ValueAt(nextRandom(), -maxOffset, 1f, 0f, 1f); } @@ -204,7 +193,7 @@ namespace osu.Game.Graphics.Backgrounds } /// - /// Creates a triangle particle with a random scale. + /// Creates a triangle particle with a random speed multiplier. /// /// The triangle particle. protected virtual TriangleParticle CreateTriangle() @@ -215,9 +204,9 @@ namespace osu.Game.Graphics.Backgrounds float u1 = 1 - nextRandom(); //uniform(0,1] random floats float u2 = 1 - nextRandom(); float randStdNormal = (float)(Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2)); // random normal(0,1) - float scale = Math.Max(TriangleScale * (mean + std_dev * randStdNormal), 0.1f); // random normal(mean,stdDev^2) + float speedMultiplier = Math.Max(mean + std_dev * randStdNormal, 0.1f); // random normal(mean,stdDev^2) - return new TriangleParticle { Scale = scale }; + return new TriangleParticle { SpeedMultiplier = speedMultiplier }; } private float nextRandom() => (float)(stableRandom?.NextDouble() ?? RNG.NextSingle()); @@ -267,7 +256,7 @@ namespace osu.Game.Graphics.Backgrounds foreach (TriangleParticle particle in parts) { - var offset = triangle_size * new Vector2(particle.Scale * 0.5f, particle.Scale * equilateral_triangle_ratio); + var offset = triangle_size * new Vector2(0.5f, equilateral_triangle_ratio); Vector2 topLeft = particle.Position * size + new Vector2(-offset.X, 0f); Vector2 topRight = particle.Position * size + new Vector2(offset.X, 0); @@ -310,9 +299,9 @@ namespace osu.Game.Graphics.Backgrounds public Vector2 Position; /// - /// The scale of the triangle. + /// The speed multiplier of the triangle. /// - public float Scale; + public float SpeedMultiplier; } } } From 13cf3fc40c7940b7cbbb2a759eff206bed97349f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 16 Nov 2022 15:17:50 +0300 Subject: [PATCH 2229/2686] Make SpawnRatio public --- .../Background/TestSceneTrianglesV2Background.cs | 13 +++++++++++-- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 12 +++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs index 59922377b0..f6207c46a5 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs @@ -12,6 +12,8 @@ namespace osu.Game.Tests.Visual.Background { public class TestSceneTrianglesV2Background : OsuTestScene { + private readonly TrianglesV2 triangles; + public TestSceneTrianglesV2Background() { AddRange(new Drawable[] @@ -25,10 +27,10 @@ namespace osu.Game.Tests.Visual.Background { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(200), + Size = new Vector2(500), Masking = true, CornerRadius = 40, - Child = new TrianglesV2 + Child = triangles = new TrianglesV2 { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -39,5 +41,12 @@ namespace osu.Game.Tests.Visual.Background } }); } + + protected override void LoadComplete() + { + base.LoadComplete(); + + AddSliderStep("Spawn ratio", 0f, 2f, 1f, s => triangles.SpawnRatio = s); + } } } diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index da31c6112b..0c4bf59732 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -52,10 +52,16 @@ namespace osu.Game.Graphics.Backgrounds /// protected virtual bool CreateNewTriangles => true; + private readonly BindableFloat spawnRatio = new BindableFloat(1f); + /// /// The amount of triangles we want compared to the default distribution. /// - protected virtual float SpawnRatio => 1; + public float SpawnRatio + { + get => spawnRatio.Value; + set => spawnRatio.Value = value; + } /// /// The relative velocity of the triangles. Default is 1. @@ -94,7 +100,7 @@ namespace osu.Game.Graphics.Backgrounds colourTop.BindValueChanged(_ => updateTexture()); colourBottom.BindValueChanged(_ => updateTexture(), true); - addTriangles(true); + spawnRatio.BindValueChanged(_ => Reset(), true); } private void updateTexture() @@ -166,7 +172,7 @@ namespace osu.Game.Graphics.Backgrounds // Limited by the maximum size of QuadVertexBuffer for safety. const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2); - AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.001f * SpawnRatio); + AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.0005f * SpawnRatio); int currentCount = parts.Count; From 7a28a7f2a0d7c337a88d8fad0d4d2b721040fe25 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Nov 2022 01:32:54 +0300 Subject: [PATCH 2230/2686] Move `IGameplaySettings` override to compose screen to keep test mode unaffected --- osu.Game/Configuration/IGameplaySettings.cs | 2 +- osu.Game/Screens/Edit/Compose/ComposeScreen.cs | 13 ++++++++++++- osu.Game/Screens/Edit/Editor.cs | 12 +----------- .../Screens/Edit/GameplayTest/EditorPlayer.cs | 18 +----------------- 4 files changed, 15 insertions(+), 30 deletions(-) diff --git a/osu.Game/Configuration/IGameplaySettings.cs b/osu.Game/Configuration/IGameplaySettings.cs index a35bdd20d0..8d66535017 100644 --- a/osu.Game/Configuration/IGameplaySettings.cs +++ b/osu.Game/Configuration/IGameplaySettings.cs @@ -8,7 +8,7 @@ namespace osu.Game.Configuration { /// /// A settings provider which generally sources from (global user settings) - /// but can allow overriding settings by caching more locally. For instance, in the editor. + /// but can allow overriding settings by caching more locally. For instance, in the editor compose screen. /// /// /// More settings can be moved into this interface as required. diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 3d18b00e75..d3c330c6d7 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Platform; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Extensions; using osu.Game.IO.Serialization; using osu.Game.Rulesets; @@ -19,7 +20,7 @@ using osu.Game.Screens.Edit.Compose.Components.Timeline; namespace osu.Game.Screens.Edit.Compose { - public class ComposeScreen : EditorScreenWithTimeline + public class ComposeScreen : EditorScreenWithTimeline, IGameplaySettings { [Resolved] private GameHost host { get; set; } @@ -27,6 +28,9 @@ namespace osu.Game.Screens.Edit.Compose [Resolved] private EditorClock clock { get; set; } + [Resolved] + private IGameplaySettings globalGameplaySettings { get; set; } + private Bindable clipboard { get; set; } private HitObjectComposer composer; @@ -157,5 +161,12 @@ namespace osu.Game.Screens.Edit.Compose } #endregion + + // Combo colour normalisation should not be applied in the editor. + // Note this doesn't affect editor test mode. + IBindable IGameplaySettings.ComboColourNormalisationAmount => new Bindable(); + + // Arguable. + IBindable IGameplaySettings.PositionalHitsoundsLevel => globalGameplaySettings.PositionalHitsoundsLevel; } } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index bb390dfbf3..4c44117581 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -58,8 +58,7 @@ namespace osu.Game.Screens.Edit { [Cached(typeof(IBeatSnapProvider))] [Cached] - public class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler, IKeyBindingHandler, IBeatSnapProvider, ISamplePlaybackDisabler, IBeatSyncProvider, - IGameplaySettings + public class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler, IKeyBindingHandler, IBeatSnapProvider, ISamplePlaybackDisabler, IBeatSyncProvider { public override float BackgroundParallaxAmount => 0.1f; @@ -99,9 +98,6 @@ namespace osu.Game.Screens.Edit [Resolved(canBeNull: true)] private INotificationOverlay notifications { get; set; } - [Resolved] - private IGameplaySettings globalGameplaySettings { get; set; } - public readonly Bindable Mode = new Bindable(); public IBindable SamplePlaybackDisabled => samplePlaybackDisabled; @@ -1045,11 +1041,5 @@ namespace osu.Game.Screens.Edit { } } - - // Combo colour normalisation should not be applied in the editor. - IBindable IGameplaySettings.ComboColourNormalisationAmount => new Bindable(); - - // Arguable. - IBindable IGameplaySettings.PositionalHitsoundsLevel => globalGameplaySettings.PositionalHitsoundsLevel; } } diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs index 7fc62b3c14..393ed4ef2e 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs @@ -2,16 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Screens; using osu.Game.Beatmaps; -using osu.Game.Configuration; using osu.Game.Overlays; using osu.Game.Screens.Play; namespace osu.Game.Screens.Edit.GameplayTest { - public class EditorPlayer : Player, IGameplaySettings + public class EditorPlayer : Player { private readonly Editor editor; private readonly EditorState editorState; @@ -19,8 +17,6 @@ namespace osu.Game.Screens.Edit.GameplayTest [Resolved] private MusicController musicController { get; set; } = null!; - private OsuConfigManager config = null!; - public EditorPlayer(Editor editor) : base(new PlayerConfiguration { ShowResults = false }) { @@ -28,14 +24,6 @@ namespace osu.Game.Screens.Edit.GameplayTest editorState = editor.GetState(); } - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - // needs to be populated before BDL to work correctly. - config = parent.Get(); - - return base.CreateChildDependencies(parent); - } - protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) { var masterGameplayClockContainer = new MasterGameplayClockContainer(beatmap, gameplayStart); @@ -84,9 +72,5 @@ namespace osu.Game.Screens.Edit.GameplayTest editor.RestoreState(editorState); return base.OnExiting(e); } - - // Editor overrides but we actually want to use game-wide settings here. - public IBindable ComboColourNormalisationAmount => ((IGameplaySettings)config).ComboColourNormalisationAmount; - public IBindable PositionalHitsoundsLevel => ((IGameplaySettings)config).PositionalHitsoundsLevel; } } From 0e46614c573cb45a0d08dee817c6f82798b9c9fd Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Nov 2022 03:54:35 +0300 Subject: [PATCH 2231/2686] Revert beatmap option button state changes --- .../SongSelect/TestScenePlaySongSelect.cs | 7 ----- .../Select/Options/BeatmapOptionsButton.cs | 29 ------------------- .../Select/Options/BeatmapOptionsOverlay.cs | 4 +-- osu.Game/Screens/Select/PlaySongSelect.cs | 11 +------ osu.Game/Screens/Select/SongSelect.cs | 22 ++------------ 5 files changed, 4 insertions(+), 69 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 51c4c5e661..614ecca6d2 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -1063,15 +1063,8 @@ namespace osu.Game.Tests.Visual.SongSelect addRulesetImportStep(0); - AddAssert("delete option enabled", () => !songSelect!.DeleteOptionButton.Disabled); - AddAssert("clear option enabled", () => !songSelect!.ClearOptionButton.Disabled); - AddAssert("edit option enabled", () => songSelect!.EditOptionButton?.Disabled == false); - AddStep("delete all beatmaps", () => manager.Delete()); - AddAssert("delete option disabled", () => songSelect!.DeleteOptionButton.Disabled); - AddAssert("clear option disabled", () => songSelect!.ClearOptionButton.Disabled); - AddAssert("edit option disabled", () => songSelect!.EditOptionButton?.Disabled == true); } private void waitForInitialSelection() diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index 73bc68f6b0..f41ee63a51 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -33,29 +33,6 @@ namespace osu.Game.Screens.Select.Options private const float disabled_alpha = 0.5f; - private bool disabled; - - public bool Disabled - { - get => disabled; - set - { - disabled = value; - - if (disabled) - { - firstLine.Alpha = disabled_alpha; - secondLine.Alpha = disabled_alpha; - iconText.Alpha = disabled_alpha; - return; - } - - firstLine.Alpha = 1; - secondLine.Alpha = 1; - iconText.Alpha = 1; - } - } - public Color4 ButtonColour { get => background.Colour; @@ -82,24 +59,18 @@ namespace osu.Game.Screens.Select.Options protected override bool OnMouseDown(MouseDownEvent e) { - if (disabled) return true; - flash.FadeTo(0.1f, 1000, Easing.OutQuint); return base.OnMouseDown(e); } protected override void OnMouseUp(MouseUpEvent e) { - if (disabled) return; - flash.FadeTo(0, 1000, Easing.OutQuint); base.OnMouseUp(e); } protected override bool OnClick(ClickEvent e) { - if (disabled) return true; - flash.ClearTransforms(); flash.Alpha = 0.9f; flash.FadeOut(800, Easing.OutExpo); diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs index 139d9e60b5..8785dac0aa 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs @@ -66,7 +66,7 @@ namespace osu.Game.Screens.Select.Options /// Colour of the button. /// Icon of the button. /// Binding the button does. - public BeatmapOptionsButton AddButton(LocalisableString firstLine, string secondLine, IconUsage icon, Color4 colour, Action action) + public void AddButton(LocalisableString firstLine, string secondLine, IconUsage icon, Color4 colour, Action action) { var button = new BeatmapOptionsButton { @@ -82,8 +82,6 @@ namespace osu.Game.Screens.Select.Options }; buttonsContainer.Add(button); - - return button; } protected override void PopIn() diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index e61c0c4c59..8718e8ad07 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -34,12 +34,10 @@ namespace osu.Game.Screens.Select private PlayBeatmapDetailArea playBeatmapDetailArea = null!; - protected BeatmapOptionsButton? EditOptionButton; - [BackgroundDependencyLoader] private void load(OsuColour colours) { - EditOptionButton = BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit()); + BeatmapOptions.AddButton(@"Edit", @"beatmap", FontAwesome.Solid.PencilAlt, colours.Yellow, () => Edit()); } protected void PresentScore(ScoreInfo score) => @@ -145,12 +143,5 @@ namespace osu.Game.Screens.Select playerLoader = null; } } - - protected override void OnBeatmapOptionsButtonDisabledChanged(bool disabled) - { - base.OnBeatmapOptionsButtonDisabledChanged(disabled); - - if (EditOptionButton != null) EditOptionButton.Disabled = disabled; - } } } diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 0341a9bb07..062ad17cb1 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -116,10 +116,6 @@ namespace osu.Game.Screens.Select private double audioFeedbackLastPlaybackTime; - protected BeatmapOptionsButton DeleteOptionButton; - - protected BeatmapOptionsButton ClearOptionButton; - [CanBeNull] private IDisposable modSelectOverlayRegistration; @@ -290,8 +286,8 @@ namespace osu.Game.Screens.Select BeatmapOptions.AddButton(@"Manage", @"collections", FontAwesome.Solid.Book, colours.Green, () => manageCollectionsDialog?.Show()); BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null); - DeleteOptionButton = BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo)); - ClearOptionButton = BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo)); + BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo)); + BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo)); } sampleChangeDifficulty = audio.Samples.Get(@"SongSelect/select-difficulty"); @@ -417,14 +413,6 @@ namespace osu.Game.Screens.Select { var beatmap = e?.NewValue ?? Beatmap.Value; - if (beatmap is DummyWorkingBeatmap || !this.IsCurrentScreen()) - { - OnBeatmapOptionsButtonDisabledChanged(true); - return; - } - - OnBeatmapOptionsButtonDisabledChanged(false); - Logger.Log($"Song select working beatmap updated to {beatmap}"); if (!Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) @@ -658,12 +646,6 @@ namespace osu.Game.Screens.Select return false; } - protected virtual void OnBeatmapOptionsButtonDisabledChanged(bool disabled) - { - DeleteOptionButton.Disabled = disabled; - ClearOptionButton.Disabled = disabled; - } - private void playExitingTransition() { ModSelect.Hide(); From 039ab83a46eefad0a61d7dff787c389eef07f38d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Nov 2022 03:57:27 +0300 Subject: [PATCH 2232/2686] Disable beatmap options button when none selected --- .../SongSelect/TestScenePlaySongSelect.cs | 12 ++---- .../SongSelect/TestSceneSongSelectFooter.cs | 8 ++++ osu.Game/Screens/Select/Footer.cs | 14 ++++++- osu.Game/Screens/Select/FooterButton.cs | 41 ++++++++++++++++--- osu.Game/Screens/Select/PlaySongSelect.cs | 1 - osu.Game/Screens/Select/SongSelect.cs | 14 ++++++- 6 files changed, 72 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 614ecca6d2..b6b9e8926b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -37,7 +37,6 @@ using osu.Game.Screens.Select; using osu.Game.Screens.Select.Carousel; using osu.Game.Screens.Select.Filter; using osu.Game.Tests.Resources; -using osu.Game.Screens.Select.Options; using osuTK.Input; namespace osu.Game.Tests.Visual.SongSelect @@ -1057,14 +1056,15 @@ namespace osu.Game.Tests.Visual.SongSelect } [Test] - public void TestBeatmapOptionsButtonDisable() + public void TestBeatmapOptionsDisabled() { createSongSelect(); addRulesetImportStep(0); + AddAssert("options enabled", () => songSelect.ChildrenOfType().Single().Enabled.Value); AddStep("delete all beatmaps", () => manager.Delete()); - + AddAssert("options disabled", () => !songSelect.ChildrenOfType().Single().Enabled.Value); } private void waitForInitialSelection() @@ -1154,12 +1154,6 @@ namespace osu.Game.Tests.Visual.SongSelect public new BeatmapCarousel Carousel => base.Carousel; public new ModSelectOverlay ModSelect => base.ModSelect; - public new BeatmapOptionsButton DeleteOptionButton => base.DeleteOptionButton; - - public new BeatmapOptionsButton ClearOptionButton => base.ClearOptionButton; - - public new BeatmapOptionsButton? EditOptionButton => base.EditOptionButton; - public new void PresentScore(ScoreInfo score) => base.PresentScore(score); protected override bool OnStart() diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs index cb78fbfe35..0a88abface 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs @@ -3,8 +3,10 @@ #nullable disable +using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; +using osu.Framework.Testing; using osu.Game.Screens.Select; using osuTK; using osuTK.Input; @@ -43,6 +45,12 @@ namespace osu.Game.Tests.Visual.SongSelect InputManager.MoveMouseTo(Vector2.Zero); }); + [Test] + public void TestState() + { + AddRepeatStep("toggle options state", () => this.ChildrenOfType().Last().Enabled.Toggle(), 20); + } + [Test] public void TestFooterRandom() { diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs index 86fe76c0c6..f9fc2890b0 100644 --- a/osu.Game/Screens/Select/Footer.cs +++ b/osu.Game/Screens/Select/Footer.cs @@ -57,7 +57,18 @@ namespace osu.Game.Screens.Select } } - private void updateModeLight() => modeLight.FadeColour(buttons.FirstOrDefault(b => b.IsHovered)?.SelectedColour ?? Color4.Transparent, TRANSITION_LENGTH, Easing.OutQuint); + private void updateModeLight() + { + var selectedButton = buttons.FirstOrDefault(b => b.Enabled.Value && b.IsHovered); + + if (selectedButton != null) + { + modeLight.FadeIn(TRANSITION_LENGTH, Easing.OutQuint); + modeLight.FadeColour(selectedButton.SelectedColour, TRANSITION_LENGTH, Easing.OutQuint); + } + else + modeLight.FadeOut(TRANSITION_LENGTH, Easing.OutQuint); + } public Footer() { @@ -78,6 +89,7 @@ namespace osu.Game.Screens.Select RelativeSizeAxes = Axes.X, Height = 3, Position = new Vector2(0, -3), + Colour = Color4.Black, }, new FillFlowContainer { diff --git a/osu.Game/Screens/Select/FooterButton.cs b/osu.Game/Screens/Select/FooterButton.cs index 3f8cf2e13a..230cdfc13e 100644 --- a/osu.Game/Screens/Select/FooterButton.cs +++ b/osu.Game/Screens/Select/FooterButton.cs @@ -120,10 +120,18 @@ namespace osu.Game.Screens.Select }; } + protected override void LoadComplete() + { + base.LoadComplete(); + Enabled.BindValueChanged(_ => updateDisplay(), true); + } + public Action Hovered; public Action HoverLost; public GlobalAction? Hotkey; + private bool mouseDown; + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -140,32 +148,38 @@ namespace osu.Game.Screens.Select protected override bool OnHover(HoverEvent e) { Hovered?.Invoke(); - light.ScaleTo(new Vector2(1, 2), Footer.TRANSITION_LENGTH, Easing.OutQuint); - light.FadeColour(SelectedColour, Footer.TRANSITION_LENGTH, Easing.OutQuint); + updateDisplay(); return true; } protected override void OnHoverLost(HoverLostEvent e) { HoverLost?.Invoke(); - light.ScaleTo(new Vector2(1, 1), Footer.TRANSITION_LENGTH, Easing.OutQuint); - light.FadeColour(DeselectedColour, Footer.TRANSITION_LENGTH, Easing.OutQuint); + updateDisplay(); } protected override bool OnMouseDown(MouseDownEvent e) { - box.FadeTo(0.3f, Footer.TRANSITION_LENGTH * 2, Easing.OutQuint); + if (!Enabled.Value) + return true; + + mouseDown = true; + updateDisplay(); return base.OnMouseDown(e); } protected override void OnMouseUp(MouseUpEvent e) { - box.FadeOut(Footer.TRANSITION_LENGTH, Easing.OutQuint); + mouseDown = false; + updateDisplay(); base.OnMouseUp(e); } protected override bool OnClick(ClickEvent e) { + if (!Enabled.Value) + return true; + box.ClearTransforms(); box.Alpha = 1; box.FadeOut(Footer.TRANSITION_LENGTH * 3, Easing.OutQuint); @@ -184,5 +198,20 @@ namespace osu.Game.Screens.Select } public virtual void OnReleased(KeyBindingReleaseEvent e) { } + + private void updateDisplay() + { + this.FadeTo(Enabled.Value ? 1 : 0.25f, Footer.TRANSITION_LENGTH, Easing.OutQuint); + + light.ScaleTo(Enabled.Value && IsHovered ? new Vector2(1, 2) : new Vector2(1), Footer.TRANSITION_LENGTH, Easing.OutQuint); + light.FadeColour(Enabled.Value && IsHovered ? SelectedColour : DeselectedColour, Footer.TRANSITION_LENGTH, Easing.OutQuint); + + box.FadeTo(Enabled.Value & mouseDown ? 0.3f : 0f, Footer.TRANSITION_LENGTH * 2, Easing.OutQuint); + + if (Enabled.Value && IsHovered) + Hovered?.Invoke(); + else + HoverLost?.Invoke(); + } } } diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 8718e8ad07..94e4215175 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -14,7 +14,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; -using osu.Game.Screens.Select.Options; using osu.Game.Users; using osu.Game.Utils; using osuTK.Input; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 062ad17cb1..6b0ab2b4cb 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -112,6 +112,8 @@ namespace osu.Game.Screens.Select protected BeatmapDetailArea BeatmapDetails { get; private set; } + private FooterButtonOptions beatmapOptionsButton; + private readonly Bindable decoupledRuleset = new Bindable(); private double audioFeedbackLastPlaybackTime; @@ -314,7 +316,7 @@ namespace osu.Game.Screens.Select NextRandom = () => Carousel.SelectNextRandom(), PreviousRandom = Carousel.SelectPreviousRandom }, null), - (new FooterButtonOptions(), BeatmapOptions) + (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) }; protected virtual ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay(); @@ -738,6 +740,16 @@ namespace osu.Game.Screens.Select beatmapInfoWedge.Beatmap = beatmap; BeatmapDetails.Beatmap = beatmap; + + bool beatmapSelected = beatmap is not DummyWorkingBeatmap; + + if (beatmapSelected) + beatmapOptionsButton.Enabled.Value = true; + else + { + beatmapOptionsButton.Enabled.Value = false; + BeatmapOptions.Hide(); + } } private readonly WeakReference lastTrack = new WeakReference(null); From 55beaf5d931d7964348ae5e8e44839ff2c8cbb3e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Nov 2022 04:05:15 +0300 Subject: [PATCH 2233/2686] Revert buttons order change --- osu.Game/Screens/Select/SongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 6b0ab2b4cb..57ba751b54 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -287,8 +287,8 @@ namespace osu.Game.Screens.Select Footer.AddButton(button, overlay); BeatmapOptions.AddButton(@"Manage", @"collections", FontAwesome.Solid.Book, colours.Green, () => manageCollectionsDialog?.Show()); - BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null); BeatmapOptions.AddButton(@"Delete", @"all difficulties", FontAwesome.Solid.Trash, colours.Pink, () => delete(Beatmap.Value.BeatmapSetInfo)); + BeatmapOptions.AddButton(@"Remove", @"from unplayed", FontAwesome.Regular.TimesCircle, colours.Purple, null); BeatmapOptions.AddButton(@"Clear", @"local scores", FontAwesome.Solid.Eraser, colours.Purple, () => clearScores(Beatmap.Value.BeatmapInfo)); } From 87b4fee10fc3477c2fd7619270f571e84da7a3cd Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Nov 2022 04:05:21 +0300 Subject: [PATCH 2234/2686] Remove leftover constant --- osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index f41ee63a51..69800c4e86 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -31,8 +31,6 @@ namespace osu.Game.Screens.Select.Options private readonly OsuSpriteText secondLine; private readonly Container box; - private const float disabled_alpha = 0.5f; - public Color4 ButtonColour { get => background.Colour; From bfcd9e0f45bf3b8f424073aea7da4e5f150e16ed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 12:32:35 +0900 Subject: [PATCH 2235/2686] Don't seek to current editor location when location is close to (or before) the first object --- osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs index 393ed4ef2e..251feecf28 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.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.Linq; using osu.Framework.Allocation; using osu.Framework.Screens; using osu.Game.Beatmaps; @@ -27,7 +28,12 @@ namespace osu.Game.Screens.Edit.GameplayTest protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart) { var masterGameplayClockContainer = new MasterGameplayClockContainer(beatmap, gameplayStart); - masterGameplayClockContainer.Reset(editorState.Time); + + // Only reset the time to the current point if the editor is later than the normal start time (and the first object). + // This allows more sane test playing from the start of the beatmap (ie. correctly adding lead-in time). + if (editorState.Time > gameplayStart && editorState.Time > DrawableRuleset.Objects.FirstOrDefault()?.StartTime) + masterGameplayClockContainer.Reset(editorState.Time); + return masterGameplayClockContainer; } From a4e713a61f7ab1b99cbbcfd28e74a0a971c965e2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 12:36:24 +0900 Subject: [PATCH 2236/2686] When returning to the editor after test play, use the original editor time rather than the point of exit --- osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs index 393ed4ef2e..e8ba7ad548 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs @@ -68,7 +68,6 @@ namespace osu.Game.Screens.Edit.GameplayTest { musicController.Stop(); - editorState.Time = GameplayClockContainer.CurrentTime; editor.RestoreState(editorState); return base.OnExiting(e); } From adab9f0e48d1cc17aa1a8d5f939d76f3881f5905 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 13:34:40 +0900 Subject: [PATCH 2237/2686] Catch and gracefully handle file/directory enumeration failures during stable import Closes https://github.com/ppy/osu/issues/21214. --- osu.Game/Database/LegacyBeatmapImporter.cs | 47 ++++++++++++++++------ 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/osu.Game/Database/LegacyBeatmapImporter.cs b/osu.Game/Database/LegacyBeatmapImporter.cs index 0955461609..c7e6fa2404 100644 --- a/osu.Game/Database/LegacyBeatmapImporter.cs +++ b/osu.Game/Database/LegacyBeatmapImporter.cs @@ -1,11 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using System.Collections.Generic; +using System.IO; using System.Linq; using osu.Framework.IO.Stores; +using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Beatmaps; using osu.Game.IO; @@ -22,22 +23,42 @@ namespace osu.Game.Database { // make sure the directory exists if (!storage.ExistsDirectory(string.Empty)) - yield break; + return Array.Empty(); - foreach (string directory in storage.GetDirectories(string.Empty)) + List paths = new List(); + + try { - var directoryStorage = storage.GetStorageForDirectory(directory); - - if (!directoryStorage.GetFiles(string.Empty).ExcludeSystemFileNames().Any()) + foreach (string directory in storage.GetDirectories(string.Empty)) { - // if a directory doesn't contain files, attempt looking for beatmaps inside of that directory. - // this is a special behaviour in stable for beatmaps only, see https://github.com/ppy/osu/issues/18615. - foreach (string subDirectory in GetStableImportPaths(directoryStorage)) - yield return subDirectory; + var directoryStorage = storage.GetStorageForDirectory(directory); + + try + { + if (!directoryStorage.GetFiles(string.Empty).ExcludeSystemFileNames().Any()) + { + // if a directory doesn't contain files, attempt looking for beatmaps inside of that directory. + // this is a special behaviour in stable for beatmaps only, see https://github.com/ppy/osu/issues/18615. + foreach (string subDirectory in GetStableImportPaths(directoryStorage)) + paths.Add(subDirectory); + } + else + paths.Add(storage.GetFullPath(directory)); + } + catch (IOException e) + { + // Catch any errors when enumerating files + Logger.Log($"Error when enumerating files in {directoryStorage.GetFullPath(string.Empty)}: {e}"); + } } - else - yield return storage.GetFullPath(directory); } + catch (IOException e) + { + // Catch any errors when enumerating directories + Logger.Log($"Error when enumerating directories in {storage.GetFullPath(string.Empty)}: {e}"); + } + + return paths; } public LegacyBeatmapImporter(IModelImporter importer) From 1050d7da3400ba08ca3a5361b645a53feddd3ccc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 13:36:16 +0900 Subject: [PATCH 2238/2686] Use more generic exception type (issue reported `AggegateException`) --- osu.Game/Database/LegacyBeatmapImporter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Database/LegacyBeatmapImporter.cs b/osu.Game/Database/LegacyBeatmapImporter.cs index c7e6fa2404..887797fe2d 100644 --- a/osu.Game/Database/LegacyBeatmapImporter.cs +++ b/osu.Game/Database/LegacyBeatmapImporter.cs @@ -45,14 +45,14 @@ namespace osu.Game.Database else paths.Add(storage.GetFullPath(directory)); } - catch (IOException e) + catch (Exception e) { // Catch any errors when enumerating files Logger.Log($"Error when enumerating files in {directoryStorage.GetFullPath(string.Empty)}: {e}"); } } } - catch (IOException e) + catch (Exception e) { // Catch any errors when enumerating directories Logger.Log($"Error when enumerating directories in {storage.GetFullPath(string.Empty)}: {e}"); From 5ceb7ecc41c761e2e51c0d1d49534f23cbdc788d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 17 Nov 2022 13:56:27 +0900 Subject: [PATCH 2239/2686] Remove unused using --- osu.Game/Database/LegacyBeatmapImporter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Database/LegacyBeatmapImporter.cs b/osu.Game/Database/LegacyBeatmapImporter.cs index 887797fe2d..20add54949 100644 --- a/osu.Game/Database/LegacyBeatmapImporter.cs +++ b/osu.Game/Database/LegacyBeatmapImporter.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using osu.Framework.IO.Stores; using osu.Framework.Logging; From 12606122e3dd9e10980d548f3c0c3dbd5558e94e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 13:59:07 +0900 Subject: [PATCH 2240/2686] Fix sliders not correctly taking on full available length after changing curve type --- .../Blueprints/Sliders/Components/PathControlPointVisualiser.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 94655f3cf7..c7e3516d62 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -248,6 +248,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components break; } + slider.Path.ExpectedDistance.Value = null; piece.ControlPoint.Type = type; } From bd2e0dc82b05fb61b1ed4671f0cc3c3ccb02680b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 15:09:41 +0900 Subject: [PATCH 2241/2686] Move "keybindings" keyword to correct section Without this, things like tablet settings would show when searching for bindings, even though these settings have nothing to do with key bindings. --- osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs | 4 ++++ osu.Game/Overlays/Settings/Sections/InputSection.cs | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs index b92746a65a..2f4840a384 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs @@ -3,6 +3,8 @@ #nullable disable +using System.Collections.Generic; +using System.Linq; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Localisation; @@ -13,6 +15,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input { protected override LocalisableString Header => BindingSettingsStrings.ShortcutAndGameplayBindings; + public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "keybindings" }); + public BindingSettings(KeyBindingPanel keyConfig) { Children = new Drawable[] diff --git a/osu.Game/Overlays/Settings/Sections/InputSection.cs b/osu.Game/Overlays/Settings/Sections/InputSection.cs index a8fe3d04be..4d75537f6b 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSection.cs @@ -3,8 +3,6 @@ #nullable disable -using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; @@ -22,8 +20,6 @@ namespace osu.Game.Overlays.Settings.Sections public override LocalisableString Header => InputSettingsStrings.InputSectionHeader; - public override IEnumerable FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "keybindings" }); - public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.Solid.Keyboard From d1b21164006dd08ee56ee1d1e935871e73eab543 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 15:23:20 +0900 Subject: [PATCH 2242/2686] Auto-advance binding for ruleset key bindings --- .../Settings/Sections/Input/KeyBindingRow.cs | 17 ++++++++++++----- .../Sections/Input/KeyBindingsSubsection.cs | 19 ++++++++++++++++++- .../Input/VariantBindingsSubsection.cs | 2 ++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index c91a6a48d4..12fd6f0746 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -33,6 +33,11 @@ namespace osu.Game.Overlays.Settings.Sections.Input { public class KeyBindingRow : Container, IFilterable { + /// + /// Invoked when binding of this row finalises with a change being written. + /// + public Action BindingFinalised { get; set; } + private readonly object action; private readonly IEnumerable bindings; @@ -153,7 +158,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input Spacing = new Vector2(5), Children = new Drawable[] { - new CancelButton { Action = finalise }, + new CancelButton { Action = () => finalise(false) }, new ClearButton { Action = clear }, }, }, @@ -240,7 +245,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } if (bindTarget.IsHovered) - finalise(); + finalise(false); // prevent updating bind target before clear button's action else if (!cancelAndClearButtons.Any(b => b.IsHovered)) updateBindTarget(); @@ -377,10 +382,10 @@ namespace osu.Game.Overlays.Settings.Sections.Input return; bindTarget.UpdateKeyCombination(InputKey.None); - finalise(); + finalise(false); } - private void finalise() + private void finalise(bool changedKey = true) { if (bindTarget != null) { @@ -393,6 +398,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input { // schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.) bindTarget = null; + if (changedKey) + BindingFinalised?.Invoke(this); }); } @@ -417,7 +424,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input protected override void OnFocusLost(FocusLostEvent e) { - finalise(); + finalise(false); base.OnFocusLost(e); } diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs index 628fe08607..a3f378e3c9 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs @@ -19,6 +19,12 @@ namespace osu.Game.Overlays.Settings.Sections.Input { public abstract class KeyBindingsSubsection : SettingsSubsection { + /// + /// After a successful binding, automatically select the next binding row to make quickly + /// binding a large set of keys easier on the user. + /// + protected virtual bool AutoAdvanceTarget => false; + protected IEnumerable Defaults; public RulesetInfo Ruleset { get; protected set; } @@ -49,7 +55,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input Add(new KeyBindingRow(defaultGroup.Key, bindings.Where(b => b.ActionInt.Equals(intKey)).ToList()) { AllowMainMouseButtons = Ruleset != null, - Defaults = defaultGroup.Select(d => d.KeyCombination) + Defaults = defaultGroup.Select(d => d.KeyCombination), + BindingFinalised = bindingCompleted }); } @@ -58,6 +65,16 @@ namespace osu.Game.Overlays.Settings.Sections.Input Action = () => Children.OfType().ForEach(k => k.RestoreDefaults()) }); } + + private void bindingCompleted(KeyBindingRow sender) + { + if (AutoAdvanceTarget) + { + var next = Children.SkipWhile(c => c != sender).Skip(1).FirstOrDefault(); + if (next != null) + GetContainingInputManager().ChangeFocus(next); + } + } } public class ResetButton : DangerousSettingsButton diff --git a/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs index a0f069b3bb..a6f6c28463 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs @@ -8,6 +8,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input { public class VariantBindingsSubsection : KeyBindingsSubsection { + protected override bool AutoAdvanceTarget => true; + protected override LocalisableString Header { get; } public VariantBindingsSubsection(RulesetInfo ruleset, int variant) From 4773979e52d9a35f284d8da651ed60df8d7c12d5 Mon Sep 17 00:00:00 2001 From: nanashi-1 Date: Thu, 17 Nov 2022 16:15:34 +0800 Subject: [PATCH 2243/2686] add condition --- osu.Game/Screens/Select/SongSelect.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 57ba751b54..5d5019567a 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -414,6 +414,7 @@ namespace osu.Game.Screens.Select private void updateCarouselSelection(ValueChangedEvent e = null) { var beatmap = e?.NewValue ?? Beatmap.Value; + if (beatmap is DummyWorkingBeatmap || !this.IsCurrentScreen()) return; Logger.Log($"Song select working beatmap updated to {beatmap}"); From dea2a6ed8d0465303f8ca4140f57371f91c99fd9 Mon Sep 17 00:00:00 2001 From: Piggey Date: Thu, 17 Nov 2022 12:12:36 +0100 Subject: [PATCH 2244/2686] override `sort()` function in `SoloGameplayLeaderboard` --- .../Screens/Play/HUD/GameplayLeaderboard.cs | 6 +----- .../Play/HUD/SoloGameplayLeaderboard.cs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index c8631880ac..2a47964118 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -158,7 +158,7 @@ namespace osu.Game.Screens.Play.HUD } } - private void sort() + protected virtual void sort() { if (sorting.IsValid) return; @@ -174,10 +174,6 @@ namespace osu.Game.Screens.Play.HUD orderedByScore[i].ScorePosition = i + 1; } - // change displayed potision to '-' when there are 50 already submitted scores and tracked score is last - if (TrackedScore?.ScorePosition == Flow.Count && Flow.Count == 51) - TrackedScore.ScorePosition = null; - sorting.Validate(); } diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index ab3cf2950c..bf9cdc8db7 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Game.Configuration; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; +using osu.Game.Screens.Select; using osu.Game.Users; namespace osu.Game.Screens.Play.HUD @@ -16,6 +17,7 @@ namespace osu.Game.Screens.Play.HUD public class SoloGameplayLeaderboard : GameplayLeaderboard { private const int duration = 100; + private const int max_online_scores = 50; // BAD! private readonly Bindable configVisibility = new Bindable(); private readonly IUser trackingUser; @@ -42,10 +44,15 @@ namespace osu.Game.Screens.Play.HUD this.trackingUser = trackingUser; } + private PlayBeatmapDetailArea.TabType scoresType; + [BackgroundDependencyLoader] private void load(OsuConfigManager config) { config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility); + + // a way to differentiate scores taken from online ranking to local scores + scoresType = config.Get(OsuSetting.BeatmapDetailTab); } protected override void LoadComplete() @@ -93,6 +100,18 @@ namespace osu.Game.Screens.Play.HUD local.DisplayOrder.Value = long.MaxValue; } + protected override void sort() + { + base.sort(); + + if (scoresType != PlayBeatmapDetailArea.TabType.Local) + { + // change displayed potision to '-' when there are 50 already submitted scores and tracked score is last + if (TrackedScore?.ScorePosition == Flow.Count && Flow.Count > max_online_scores) + TrackedScore.ScorePosition = null; + } + } + private void updateVisibility() => this.FadeTo(AlwaysVisible.Value || configVisibility.Value ? 1 : 0, duration); } From a1af663682cce72d49244c194f072a6a1f064fe5 Mon Sep 17 00:00:00 2001 From: Dragon Date: Sun, 13 Nov 2022 20:49:26 +0100 Subject: [PATCH 2245/2686] Implemented previous messages lookup in the ChatTextBox.cs --- osu.Game/Overlays/Chat/ChatTextBox.cs | 57 +++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/osu.Game/Overlays/Chat/ChatTextBox.cs b/osu.Game/Overlays/Chat/ChatTextBox.cs index 887eb96c15..fc4c2ae727 100644 --- a/osu.Game/Overlays/Chat/ChatTextBox.cs +++ b/osu.Game/Overlays/Chat/ChatTextBox.cs @@ -1,14 +1,23 @@ // 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 osu.Framework.Bindables; +using osu.Framework.Input.Events; using osu.Game.Graphics.UserInterface; using osu.Game.Resources.Localisation.Web; +using osuTK.Input; namespace osu.Game.Overlays.Chat { public class ChatTextBox : FocusedTextBox { + private readonly List messageHistory = new List(); + + private int messageIndex = -1; + + private string originalMessage = string.Empty; + public readonly BindableBool ShowSearch = new BindableBool(); public override bool HandleLeftRightArrows => !ShowSearch.Value; @@ -28,11 +37,59 @@ namespace osu.Game.Overlays.Chat }, true); } + protected override bool OnKeyDown(KeyDownEvent e) + { + /* Behavior: + * add when on last element -> last element stays + * subtract when on first element -> sets to original text + * reset indexing when Text is set to Empty + */ + + switch (e.Key) + { + case Key.Up: + if (messageIndex == -1) + originalMessage = Text; + + if (messageIndex == messageHistory.Count - 1) + return true; + + Text = messageHistory[++messageIndex]; + + return true; + + case Key.Down: + if (messageIndex == -1) + return true; + + if (messageIndex == 0) + { + messageIndex = -1; + Text = originalMessage; + return true; + } + + Text = messageHistory[--messageIndex]; + + return true; + } + + bool onKeyDown = base.OnKeyDown(e); + + if (string.IsNullOrEmpty(Text)) + messageIndex = -1; + + return onKeyDown; + } + protected override void Commit() { if (ShowSearch.Value) return; + messageHistory.Insert(0, Text); + messageIndex = -1; + base.Commit(); } } From b9590320b750d64ed532ce0621f54019940c1f4c Mon Sep 17 00:00:00 2001 From: Dragon Date: Sun, 13 Nov 2022 22:34:02 +0100 Subject: [PATCH 2246/2686] Moved implementation to ChatRecentTextBox.cs and derived ChatTextBox.cs and StandAloneChatDisplay.cs from it. --- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 14 ++-- osu.Game/Overlays/Chat/ChatRecentTextBox.cs | 74 +++++++++++++++++++ osu.Game/Overlays/Chat/ChatTextBox.cs | 60 +-------------- 3 files changed, 83 insertions(+), 65 deletions(-) create mode 100644 osu.Game/Overlays/Chat/ChatRecentTextBox.cs diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 81db3f0d53..de0387e017 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Chat; using osu.Game.Resources.Localisation.Web; using osuTK.Graphics; @@ -120,17 +119,20 @@ namespace osu.Game.Online.Chat AddInternal(drawableChannel); } - public class ChatTextBox : FocusedTextBox + public class ChatTextBox : ChatRecentTextBox { protected override bool OnKeyDown(KeyDownEvent e) { // Chat text boxes are generally used in places where they retain focus, but shouldn't block interaction with other // elements on the same screen. - switch (e.Key) + if (!HoldFocus) { - case Key.Up: - case Key.Down: - return false; + switch (e.Key) + { + case Key.Up: + case Key.Down: + return false; + } } return base.OnKeyDown(e); diff --git a/osu.Game/Overlays/Chat/ChatRecentTextBox.cs b/osu.Game/Overlays/Chat/ChatRecentTextBox.cs new file mode 100644 index 0000000000..87bc3ee48c --- /dev/null +++ b/osu.Game/Overlays/Chat/ChatRecentTextBox.cs @@ -0,0 +1,74 @@ +// 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 osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; +using osuTK.Input; + +namespace osu.Game.Overlays.Chat +{ + public class ChatRecentTextBox : FocusedTextBox + { + private readonly List messageHistory = new List(); + + private int messageIndex = -1; + + private string originalMessage = string.Empty; + + protected override bool OnKeyDown(KeyDownEvent e) + { + /* Behavior: + * add when on last element -> last element stays + * subtract when on first element -> sets to original text + * reset indexing when Text is set to Empty + */ + + switch (e.Key) + { + case Key.Up: + if (messageIndex == -1) + originalMessage = Text; + + if (messageIndex == messageHistory.Count - 1) + return true; + + Text = messageHistory[++messageIndex]; + + return true; + + case Key.Down: + if (messageIndex == -1) + return true; + + if (messageIndex == 0) + { + messageIndex = -1; + Text = originalMessage; + return true; + } + + Text = messageHistory[--messageIndex]; + + return true; + } + + bool onKeyDown = base.OnKeyDown(e); + + if (string.IsNullOrEmpty(Text)) + messageIndex = -1; + + return onKeyDown; + } + + protected override void Commit() + { + if (!string.IsNullOrEmpty(Text)) + messageHistory.Insert(0, Text); + + messageIndex = -1; + + base.Commit(); + } + } +} diff --git a/osu.Game/Overlays/Chat/ChatTextBox.cs b/osu.Game/Overlays/Chat/ChatTextBox.cs index fc4c2ae727..d3c1a4ad8b 100644 --- a/osu.Game/Overlays/Chat/ChatTextBox.cs +++ b/osu.Game/Overlays/Chat/ChatTextBox.cs @@ -1,23 +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.Collections.Generic; using osu.Framework.Bindables; -using osu.Framework.Input.Events; -using osu.Game.Graphics.UserInterface; using osu.Game.Resources.Localisation.Web; -using osuTK.Input; namespace osu.Game.Overlays.Chat { - public class ChatTextBox : FocusedTextBox + public class ChatTextBox : ChatRecentTextBox { - private readonly List messageHistory = new List(); - - private int messageIndex = -1; - - private string originalMessage = string.Empty; - public readonly BindableBool ShowSearch = new BindableBool(); public override bool HandleLeftRightArrows => !ShowSearch.Value; @@ -37,59 +27,11 @@ namespace osu.Game.Overlays.Chat }, true); } - protected override bool OnKeyDown(KeyDownEvent e) - { - /* Behavior: - * add when on last element -> last element stays - * subtract when on first element -> sets to original text - * reset indexing when Text is set to Empty - */ - - switch (e.Key) - { - case Key.Up: - if (messageIndex == -1) - originalMessage = Text; - - if (messageIndex == messageHistory.Count - 1) - return true; - - Text = messageHistory[++messageIndex]; - - return true; - - case Key.Down: - if (messageIndex == -1) - return true; - - if (messageIndex == 0) - { - messageIndex = -1; - Text = originalMessage; - return true; - } - - Text = messageHistory[--messageIndex]; - - return true; - } - - bool onKeyDown = base.OnKeyDown(e); - - if (string.IsNullOrEmpty(Text)) - messageIndex = -1; - - return onKeyDown; - } - protected override void Commit() { if (ShowSearch.Value) return; - messageHistory.Insert(0, Text); - messageIndex = -1; - base.Commit(); } } From 6d83af01e21228e56753d200e7aee0c94e0b2e67 Mon Sep 17 00:00:00 2001 From: Terochi Date: Tue, 15 Nov 2022 13:06:02 +0100 Subject: [PATCH 2247/2686] Moved and renamed MessageHistoryTextBox.cs for better fit. --- .../UserInterface/MessageHistoryTextBox.cs} | 21 +++++++++++-------- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 3 ++- osu.Game/Overlays/Chat/ChatTextBox.cs | 3 ++- 3 files changed, 16 insertions(+), 11 deletions(-) rename osu.Game/{Overlays/Chat/ChatRecentTextBox.cs => Graphics/UserInterface/MessageHistoryTextBox.cs} (82%) diff --git a/osu.Game/Overlays/Chat/ChatRecentTextBox.cs b/osu.Game/Graphics/UserInterface/MessageHistoryTextBox.cs similarity index 82% rename from osu.Game/Overlays/Chat/ChatRecentTextBox.cs rename to osu.Game/Graphics/UserInterface/MessageHistoryTextBox.cs index 87bc3ee48c..45497e0451 100644 --- a/osu.Game/Overlays/Chat/ChatRecentTextBox.cs +++ b/osu.Game/Graphics/UserInterface/MessageHistoryTextBox.cs @@ -3,12 +3,11 @@ using System.Collections.Generic; using osu.Framework.Input.Events; -using osu.Game.Graphics.UserInterface; using osuTK.Input; -namespace osu.Game.Overlays.Chat +namespace osu.Game.Graphics.UserInterface { - public class ChatRecentTextBox : FocusedTextBox + public class MessageHistoryTextBox : FocusedTextBox { private readonly List messageHistory = new List(); @@ -16,6 +15,15 @@ namespace osu.Game.Overlays.Chat private string originalMessage = string.Empty; + public MessageHistoryTextBox() + { + Current.ValueChanged += text => + { + if (string.IsNullOrEmpty(text.NewValue)) + messageIndex = -1; + }; + } + protected override bool OnKeyDown(KeyDownEvent e) { /* Behavior: @@ -53,12 +61,7 @@ namespace osu.Game.Overlays.Chat return true; } - bool onKeyDown = base.OnKeyDown(e); - - if (string.IsNullOrEmpty(Text)) - messageIndex = -1; - - return onKeyDown; + return base.OnKeyDown(e); } protected override void Commit() diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index de0387e017..fe279d50a9 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Chat; using osu.Game.Resources.Localisation.Web; using osuTK.Graphics; @@ -119,7 +120,7 @@ namespace osu.Game.Online.Chat AddInternal(drawableChannel); } - public class ChatTextBox : ChatRecentTextBox + public class ChatTextBox : MessageHistoryTextBox { protected override bool OnKeyDown(KeyDownEvent e) { diff --git a/osu.Game/Overlays/Chat/ChatTextBox.cs b/osu.Game/Overlays/Chat/ChatTextBox.cs index d3c1a4ad8b..26ff4a5b4e 100644 --- a/osu.Game/Overlays/Chat/ChatTextBox.cs +++ b/osu.Game/Overlays/Chat/ChatTextBox.cs @@ -2,11 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Bindables; +using osu.Game.Graphics.UserInterface; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Chat { - public class ChatTextBox : ChatRecentTextBox + public class ChatTextBox : MessageHistoryTextBox { public readonly BindableBool ShowSearch = new BindableBool(); From a79af6671eceb918dd598a0c60d997030f57fdcb Mon Sep 17 00:00:00 2001 From: Terochi Date: Tue, 15 Nov 2022 13:07:05 +0100 Subject: [PATCH 2248/2686] Added SetUp for new tests. --- .../Online/TestSceneChatManipulation.cs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs b/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs new file mode 100644 index 0000000000..6de2584c72 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs @@ -0,0 +1,74 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays.Chat; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public class TestSceneChatManipulation : OsuTestScene + { + private ChatTextBox box; + private OsuSpriteText text; + + [SetUp] + public void SetUp() + { + Schedule(() => + { + Children = new Drawable[] + { + box = new ChatTextBox + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Width = 0.99f, + }, + text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.X, + Width = 0.99f, + Y = -box.Height, + Font = OsuFont.Default.With(size: 20), + } + }; + box.OnCommit += (_, __) => + { + text.Text = $"{nameof(box.OnCommit)}: {box.Text}"; + box.Text = string.Empty; + box.TakeFocus(); + text.FadeOutFromOne(1000, Easing.InQuint); + }; + }); + } + + [Test] + public void TestReachingLimitOfMessages() + { + } + + [Test] + public void TestStayOnLastIndex() + { + } + + [Test] + public void TestKeepOriginalMessage() + { + } + + [Test] + public void TestResetIndexOnEmpty() + { + } + } +} From 3d4962e1810e3f53e22125cf1012a5c036dade05 Mon Sep 17 00:00:00 2001 From: Terochi Date: Tue, 15 Nov 2022 16:12:24 +0100 Subject: [PATCH 2249/2686] Added functioning tests. --- .../Online/TestSceneChatManipulation.cs | 59 +++++++++++++++++-- ...ageHistoryTextBox.cs => HistoryTextBox.cs} | 32 +++++----- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 2 +- osu.Game/Overlays/Chat/ChatTextBox.cs | 2 +- 4 files changed, 69 insertions(+), 26 deletions(-) rename osu.Game/Graphics/UserInterface/{MessageHistoryTextBox.cs => HistoryTextBox.cs} (62%) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs b/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs index 6de2584c72..4fe0cb685e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs @@ -3,16 +3,18 @@ #nullable disable +using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Overlays.Chat; +using osuTK.Input; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneChatManipulation : OsuTestScene + public class TestSceneChatManipulation : OsuManualInputManagerTestScene { private ChatTextBox box; private OsuSpriteText text; @@ -41,6 +43,7 @@ namespace osu.Game.Tests.Visual.Online Font = OsuFont.Default.With(size: 20), } }; + box.OnCommit += (_, __) => { text.Text = $"{nameof(box.OnCommit)}: {box.Text}"; @@ -48,27 +51,71 @@ namespace osu.Game.Tests.Visual.Online box.TakeFocus(); text.FadeOutFromOne(1000, Easing.InQuint); }; - }); - } - [Test] - public void TestReachingLimitOfMessages() - { + box.TakeFocus(); + }); } [Test] public void TestStayOnLastIndex() { + addMessages(2); + AddRepeatStep("Move to last", () => InputManager.Key(Key.Up), 2); + + string lastText = string.Empty; + AddStep("Move up", () => + { + lastText = box.Text; + InputManager.Key(Key.Up); + }); + + AddAssert("Text hasn't changed", () => lastText == box.Text); } [Test] public void TestKeepOriginalMessage() { + addMessages(1); + AddStep("Start writing", () => box.Text = "A random 文, ..."); + + AddStep("Move up", () => InputManager.Key(Key.Up)); + AddStep("Rewrite old message", () => box.Text = "Old Message"); + + AddStep("Move back down", () => InputManager.Key(Key.Down)); + AddAssert("Text back to previous", () => box.Text == "A random 文, ..."); } [Test] public void TestResetIndexOnEmpty() { + addMessages(2); + AddRepeatStep("Move up", () => InputManager.Key(Key.Up), 2); + AddStep("Remove text", () => box.Text = string.Empty); + + AddStep("Move up again", () => InputManager.Key(Key.Up)); + AddAssert("Back to first message", () => box.Text == "Message 2"); + } + + [Test] + public void TestReachingLimitOfMessages() + { + addMessages(100); + AddAssert("List is full of <100-1>", () => + Enumerable.Range(0, 100).Select(number => $"Message {100 - number}").SequenceEqual(box.MessageHistory)); + + addMessages(2); + AddAssert("List is full of <102-3>", () => + Enumerable.Range(0, 100).Select(number => $"Message {102 - number}").SequenceEqual(box.MessageHistory)); + } + + private void addMessages(int count) + { + int iterations = 0; + AddRepeatStep("Add messages", () => + { + box.Text = $"Message {++iterations}"; + InputManager.Key(Key.Enter); + }, count); } } } diff --git a/osu.Game/Graphics/UserInterface/MessageHistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs similarity index 62% rename from osu.Game/Graphics/UserInterface/MessageHistoryTextBox.cs rename to osu.Game/Graphics/UserInterface/HistoryTextBox.cs index 45497e0451..1b553576d5 100644 --- a/osu.Game/Graphics/UserInterface/MessageHistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -7,56 +7,52 @@ using osuTK.Input; namespace osu.Game.Graphics.UserInterface { - public class MessageHistoryTextBox : FocusedTextBox + public class HistoryTextBox : FocusedTextBox { private readonly List messageHistory = new List(); - private int messageIndex = -1; + public IReadOnlyList MessageHistory => messageHistory; + + private int historyIndex = -1; private string originalMessage = string.Empty; - public MessageHistoryTextBox() + public HistoryTextBox() { Current.ValueChanged += text => { if (string.IsNullOrEmpty(text.NewValue)) - messageIndex = -1; + historyIndex = -1; }; } protected override bool OnKeyDown(KeyDownEvent e) { - /* Behavior: - * add when on last element -> last element stays - * subtract when on first element -> sets to original text - * reset indexing when Text is set to Empty - */ - switch (e.Key) { case Key.Up: - if (messageIndex == -1) + if (historyIndex == -1) originalMessage = Text; - if (messageIndex == messageHistory.Count - 1) + if (historyIndex == messageHistory.Count - 1) return true; - Text = messageHistory[++messageIndex]; + Text = messageHistory[++historyIndex]; return true; case Key.Down: - if (messageIndex == -1) + if (historyIndex == -1) return true; - if (messageIndex == 0) + if (historyIndex == 0) { - messageIndex = -1; + historyIndex = -1; Text = originalMessage; return true; } - Text = messageHistory[--messageIndex]; + Text = messageHistory[--historyIndex]; return true; } @@ -69,7 +65,7 @@ namespace osu.Game.Graphics.UserInterface if (!string.IsNullOrEmpty(Text)) messageHistory.Insert(0, Text); - messageIndex = -1; + historyIndex = -1; base.Commit(); } diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index fe279d50a9..03728b427f 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -120,7 +120,7 @@ namespace osu.Game.Online.Chat AddInternal(drawableChannel); } - public class ChatTextBox : MessageHistoryTextBox + public class ChatTextBox : HistoryTextBox { protected override bool OnKeyDown(KeyDownEvent e) { diff --git a/osu.Game/Overlays/Chat/ChatTextBox.cs b/osu.Game/Overlays/Chat/ChatTextBox.cs index 26ff4a5b4e..f0bdbce08d 100644 --- a/osu.Game/Overlays/Chat/ChatTextBox.cs +++ b/osu.Game/Overlays/Chat/ChatTextBox.cs @@ -7,7 +7,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Chat { - public class ChatTextBox : MessageHistoryTextBox + public class ChatTextBox : HistoryTextBox { public readonly BindableBool ShowSearch = new BindableBool(); From 44c3e71746b43337ad8cbaab0410e73d8f959d54 Mon Sep 17 00:00:00 2001 From: Terochi Date: Tue, 15 Nov 2022 18:10:43 +0100 Subject: [PATCH 2250/2686] Reversed indexing --- .../Graphics/UserInterface/HistoryTextBox.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index 1b553576d5..96c0734d63 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -13,7 +13,7 @@ namespace osu.Game.Graphics.UserInterface public IReadOnlyList MessageHistory => messageHistory; - private int historyIndex = -1; + private int historyIndex; private string originalMessage = string.Empty; @@ -22,7 +22,7 @@ namespace osu.Game.Graphics.UserInterface Current.ValueChanged += text => { if (string.IsNullOrEmpty(text.NewValue)) - historyIndex = -1; + historyIndex = messageHistory.Count; }; } @@ -31,28 +31,28 @@ namespace osu.Game.Graphics.UserInterface switch (e.Key) { case Key.Up: - if (historyIndex == -1) + if (historyIndex == messageHistory.Count) originalMessage = Text; - if (historyIndex == messageHistory.Count - 1) + if (historyIndex == 0) return true; - Text = messageHistory[++historyIndex]; + Text = messageHistory[--historyIndex]; return true; case Key.Down: - if (historyIndex == -1) + if (historyIndex == messageHistory.Count) return true; - if (historyIndex == 0) + if (historyIndex == messageHistory.Count - 1) { - historyIndex = -1; + historyIndex = messageHistory.Count; Text = originalMessage; return true; } - Text = messageHistory[--historyIndex]; + Text = messageHistory[++historyIndex]; return true; } @@ -63,9 +63,9 @@ namespace osu.Game.Graphics.UserInterface protected override void Commit() { if (!string.IsNullOrEmpty(Text)) - messageHistory.Insert(0, Text); + messageHistory.Add(Text); - historyIndex = -1; + historyIndex = messageHistory.Count; base.Commit(); } From 5253f5309e0224ef993786ffb84fd9d7a64f212e Mon Sep 17 00:00:00 2001 From: Terochi Date: Tue, 15 Nov 2022 23:51:57 +0100 Subject: [PATCH 2251/2686] Added more tests for new features --- .../Online/TestSceneChatManipulation.cs | 75 ++++++++++++++++++- .../Graphics/UserInterface/HistoryTextBox.cs | 57 ++++++++++---- 2 files changed, 116 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs b/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs index 4fe0cb685e..efa4cd41b3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs @@ -8,7 +8,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Overlays.Chat; +using osu.Game.Graphics.UserInterface; using osuTK.Input; namespace osu.Game.Tests.Visual.Online @@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Online [TestFixture] public class TestSceneChatManipulation : OsuManualInputManagerTestScene { - private ChatTextBox box; + private HistoryTextBox box; private OsuSpriteText text; [SetUp] @@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual.Online { Children = new Drawable[] { - box = new ChatTextBox + box = new HistoryTextBox(5) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -56,6 +56,75 @@ namespace osu.Game.Tests.Visual.Online }); } + [Test] + public void TestEmptyHistory() + { + const string temp = "Temp message"; + AddStep("Set text", () => box.Text = temp); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Text is the same", () => box.Text == temp); + + AddStep("Move Up", () => InputManager.Key(Key.Up)); + AddAssert("Text is the same", () => box.Text == temp); + } + + [Test] + public void TestPartialHistory() + { + addMessages(2); + + const string temp = "Temp message"; + AddStep("Set text", () => box.Text = temp); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Text is the same", () => box.Text == temp); + + AddRepeatStep("Move Up", () => InputManager.Key(Key.Up), 2); + AddAssert("Same as 1st message", () => box.Text == "Message 1"); + + AddStep("Move Up", () => InputManager.Key(Key.Up)); + AddAssert("Text is the same", () => box.Text == "Message 1"); + + AddRepeatStep("Move down", () => InputManager.Key(Key.Down), 2); + AddAssert("Same as temp message", () => box.Text == temp); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Text is the same", () => box.Text == temp); + } + + [Test] + public void TestFullHistory() + { + addMessages(5); + AddAssert("History saved as <1-5>", () => + Enumerable.Range(1, 5).Select(number => $"Message {number}").SequenceEqual(box.MessageHistory)); + + const string temp = "Temp message"; + AddStep("Set text", () => box.Text = temp); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Text is the same", () => box.Text == temp); + + addMessages(2); + AddAssert("Overwrote history to <3-7>", () => + Enumerable.Range(3, 5).Select(number => $"Message {number}").SequenceEqual(box.MessageHistory)); + + AddStep("Set text", () => box.Text = temp); + + AddRepeatStep("Move Up", () => InputManager.Key(Key.Up), 5); + AddAssert("Same as 3rd message", () => box.Text == "Message 3"); + + AddStep("Move Up", () => InputManager.Key(Key.Up)); + AddAssert("Text is the same", () => box.Text == "Message 3"); + + AddRepeatStep("Move down", () => InputManager.Key(Key.Down), 4); + AddAssert("Same as previous message", () => box.Text == "Message 7"); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Same as temp message", () => box.Text == temp); + } + [Test] public void TestStayOnLastIndex() { diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index 96c0734d63..c91e5dcb41 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.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.Input.Events; using osuTK.Input; @@ -9,50 +10,71 @@ namespace osu.Game.Graphics.UserInterface { public class HistoryTextBox : FocusedTextBox { - private readonly List messageHistory = new List(); + private readonly int historyLimit; + + private readonly List messageHistory; public IReadOnlyList MessageHistory => messageHistory; - private int historyIndex; + private int startIndex; private string originalMessage = string.Empty; + private int nullIndex => -1; + private int historyIndex = -1; + private int endIndex => (messageHistory.Count + startIndex - 1) % Math.Max(1, messageHistory.Count); - public HistoryTextBox() + public HistoryTextBox(int historyLimit = 100) { + this.historyLimit = historyLimit; + messageHistory = new List(historyLimit); + Current.ValueChanged += text => { if (string.IsNullOrEmpty(text.NewValue)) - historyIndex = messageHistory.Count; + historyIndex = nullIndex; }; } + public string GetOldMessage(int index) + { + if (index < 0 || index >= messageHistory.Count) + throw new ArgumentOutOfRangeException(); + + return messageHistory[(startIndex + index) % messageHistory.Count]; + } + protected override bool OnKeyDown(KeyDownEvent e) { switch (e.Key) { case Key.Up: - if (historyIndex == messageHistory.Count) + if (historyIndex == nullIndex) + { + historyIndex = endIndex; originalMessage = Text; + } - if (historyIndex == 0) + if (historyIndex == startIndex) return true; - Text = messageHistory[--historyIndex]; + historyIndex = (historyLimit + historyIndex - 1) % historyLimit; + Text = messageHistory[historyIndex]; return true; case Key.Down: - if (historyIndex == messageHistory.Count) + if (historyIndex == nullIndex) return true; - if (historyIndex == messageHistory.Count - 1) + if (historyIndex == endIndex) { - historyIndex = messageHistory.Count; + historyIndex = nullIndex; Text = originalMessage; return true; } - Text = messageHistory[++historyIndex]; + historyIndex = (historyIndex + 1) % historyLimit; + Text = messageHistory[historyIndex]; return true; } @@ -63,9 +85,18 @@ namespace osu.Game.Graphics.UserInterface protected override void Commit() { if (!string.IsNullOrEmpty(Text)) - messageHistory.Add(Text); + { + if (messageHistory.Count == historyLimit) + { + messageHistory[startIndex++] = Text; + } + else + { + messageHistory.Add(Text); + } + } - historyIndex = messageHistory.Count; + historyIndex = nullIndex; base.Commit(); } From 19dc31c7ae6c3b5a2ad6bdd3422e1d60eb5ec8d5 Mon Sep 17 00:00:00 2001 From: Terochi Date: Wed, 16 Nov 2022 13:12:43 +0100 Subject: [PATCH 2252/2686] Changed tests. --- .../Online/TestSceneChatManipulation.cs | 75 +++++++------------ 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs b/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs index efa4cd41b3..3bff321d0d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs @@ -6,6 +6,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; +using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -19,6 +20,8 @@ namespace osu.Game.Tests.Visual.Online private HistoryTextBox box; private OsuSpriteText text; + private int messageCounter; + [SetUp] public void SetUp() { @@ -52,6 +55,8 @@ namespace osu.Game.Tests.Visual.Online text.FadeOutFromOne(1000, Easing.InQuint); }; + messageCounter = 0; + box.TakeFocus(); }); } @@ -97,8 +102,8 @@ namespace osu.Game.Tests.Visual.Online public void TestFullHistory() { addMessages(5); - AddAssert("History saved as <1-5>", () => - Enumerable.Range(1, 5).Select(number => $"Message {number}").SequenceEqual(box.MessageHistory)); + AddAssert("History saved as <5-1>", () => + Enumerable.Range(0, 5).Select(number => $"Message {5 - number}").SequenceEqual(box.MessageHistory)); const string temp = "Temp message"; AddStep("Set text", () => box.Text = temp); @@ -107,8 +112,8 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Text is the same", () => box.Text == temp); addMessages(2); - AddAssert("Overwrote history to <3-7>", () => - Enumerable.Range(3, 5).Select(number => $"Message {number}").SequenceEqual(box.MessageHistory)); + AddAssert("Overrode history to <7-3>", () => + Enumerable.Range(0, 5).Select(number => $"Message {7 - number}").SequenceEqual(box.MessageHistory)); AddStep("Set text", () => box.Text = temp); @@ -126,63 +131,41 @@ namespace osu.Game.Tests.Visual.Online } [Test] - public void TestStayOnLastIndex() + public void TestOverrideFullHistory() { - addMessages(2); - AddRepeatStep("Move to last", () => InputManager.Key(Key.Up), 2); + addMessages(5); + AddAssert("History saved as <5-1>", () => + Enumerable.Range(0, 5).Select(number => $"Message {5 - number}").SequenceEqual(box.MessageHistory)); - string lastText = string.Empty; - AddStep("Move up", () => - { - lastText = box.Text; - InputManager.Key(Key.Up); - }); - - AddAssert("Text hasn't changed", () => lastText == box.Text); + addMessages(6); + AddAssert("Overrode history to <11-7>", () => + Enumerable.Range(0, 5).Select(number => $"Message {11 - number}").SequenceEqual(box.MessageHistory)); } [Test] - public void TestKeepOriginalMessage() - { - addMessages(1); - AddStep("Start writing", () => box.Text = "A random 文, ..."); - - AddStep("Move up", () => InputManager.Key(Key.Up)); - AddStep("Rewrite old message", () => box.Text = "Old Message"); - - AddStep("Move back down", () => InputManager.Key(Key.Down)); - AddAssert("Text back to previous", () => box.Text == "A random 文, ..."); - } - - [Test] - public void TestResetIndexOnEmpty() + public void TestResetIndex() { addMessages(2); - AddRepeatStep("Move up", () => InputManager.Key(Key.Up), 2); + + AddRepeatStep("Move Up", () => InputManager.Key(Key.Up), 2); + AddAssert("Same as 1st message", () => box.Text == "Message 1"); + AddStep("Remove text", () => box.Text = string.Empty); + AddStep("Move Up", () => InputManager.Key(Key.Up)); + AddAssert("Same as previous message", () => box.Text == "Message 2"); - AddStep("Move up again", () => InputManager.Key(Key.Up)); - AddAssert("Back to first message", () => box.Text == "Message 2"); - } - - [Test] - public void TestReachingLimitOfMessages() - { - addMessages(100); - AddAssert("List is full of <100-1>", () => - Enumerable.Range(0, 100).Select(number => $"Message {100 - number}").SequenceEqual(box.MessageHistory)); - - addMessages(2); - AddAssert("List is full of <102-3>", () => - Enumerable.Range(0, 100).Select(number => $"Message {102 - number}").SequenceEqual(box.MessageHistory)); + AddStep("Move Up", () => InputManager.Key(Key.Up)); + AddStep("Select text", () => InputManager.Keys(PlatformAction.SelectAll)); + AddStep("Replace text", () => box.Text = "New text"); + AddStep("Move Up", () => InputManager.Key(Key.Up)); + AddAssert("Same as previous message", () => box.Text == "Message 2"); } private void addMessages(int count) { - int iterations = 0; AddRepeatStep("Add messages", () => { - box.Text = $"Message {++iterations}"; + box.Text = $"Message {++messageCounter}"; InputManager.Key(Key.Enter); }, count); } From 0100c01b82f547ced0d3b040fbba14d88b13847e Mon Sep 17 00:00:00 2001 From: Terochi Date: Wed, 16 Nov 2022 13:16:01 +0100 Subject: [PATCH 2253/2686] Implemented finite limit of stored history. --- .../Graphics/UserInterface/HistoryTextBox.cs | 64 +++++++++++-------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index c91e5dcb41..6c9df5aca2 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using osu.Framework.Input.Events; using osuTK.Input; @@ -12,16 +13,23 @@ namespace osu.Game.Graphics.UserInterface { private readonly int historyLimit; + private bool everythingSelected; + + public int HistoryLength => messageHistory.Count; + private readonly List messageHistory; - public IReadOnlyList MessageHistory => messageHistory; + public IReadOnlyList MessageHistory => + Enumerable.Range(0, HistoryLength).Select(GetOldMessage).ToList(); + + private string originalMessage = string.Empty; + + private int historyIndex = -1; private int startIndex; - private string originalMessage = string.Empty; - private int nullIndex => -1; - private int historyIndex = -1; - private int endIndex => (messageHistory.Count + startIndex - 1) % Math.Max(1, messageHistory.Count); + private int getNormalizedIndex(int index) => + (HistoryLength + startIndex - index - 1) % HistoryLength; public HistoryTextBox(int historyLimit = 100) { @@ -30,17 +38,27 @@ namespace osu.Game.Graphics.UserInterface Current.ValueChanged += text => { - if (string.IsNullOrEmpty(text.NewValue)) - historyIndex = nullIndex; + if (string.IsNullOrEmpty(text.NewValue) || everythingSelected) + { + historyIndex = -1; + everythingSelected = false; + } }; } + protected override void OnTextSelectionChanged(TextSelectionType selectionType) + { + everythingSelected = SelectedText == Text; + + base.OnTextSelectionChanged(selectionType); + } + public string GetOldMessage(int index) { - if (index < 0 || index >= messageHistory.Count) + if (index < 0 || index >= HistoryLength) throw new ArgumentOutOfRangeException(); - return messageHistory[(startIndex + index) % messageHistory.Count]; + return HistoryLength == 0 ? string.Empty : messageHistory[getNormalizedIndex(index)]; } protected override bool OnKeyDown(KeyDownEvent e) @@ -48,33 +66,28 @@ namespace osu.Game.Graphics.UserInterface switch (e.Key) { case Key.Up: - if (historyIndex == nullIndex) - { - historyIndex = endIndex; - originalMessage = Text; - } - - if (historyIndex == startIndex) + if (historyIndex == HistoryLength - 1) return true; - historyIndex = (historyLimit + historyIndex - 1) % historyLimit; - Text = messageHistory[historyIndex]; + if (historyIndex == -1) + originalMessage = Text; + + Text = messageHistory[getNormalizedIndex(++historyIndex)]; return true; case Key.Down: - if (historyIndex == nullIndex) + if (historyIndex == -1) return true; - if (historyIndex == endIndex) + if (historyIndex == 0) { - historyIndex = nullIndex; + historyIndex = -1; Text = originalMessage; return true; } - historyIndex = (historyIndex + 1) % historyLimit; - Text = messageHistory[historyIndex]; + Text = messageHistory[getNormalizedIndex(--historyIndex)]; return true; } @@ -86,9 +99,10 @@ namespace osu.Game.Graphics.UserInterface { if (!string.IsNullOrEmpty(Text)) { - if (messageHistory.Count == historyLimit) + if (HistoryLength == historyLimit) { messageHistory[startIndex++] = Text; + startIndex %= historyLimit; } else { @@ -96,7 +110,7 @@ namespace osu.Game.Graphics.UserInterface } } - historyIndex = nullIndex; + historyIndex = -1; base.Commit(); } From a9747d367cc9a7321c414622a89777e89f321ca0 Mon Sep 17 00:00:00 2001 From: Dragon Date: Thu, 17 Nov 2022 10:18:17 +0100 Subject: [PATCH 2254/2686] Cleaning up --- .../TestSceneHistoryTextBox.cs} | 23 ++++++------- .../Graphics/UserInterface/HistoryTextBox.cs | 34 +++++++++---------- 2 files changed, 28 insertions(+), 29 deletions(-) rename osu.Game.Tests/Visual/{Online/TestSceneChatManipulation.cs => UserInterface/TestSceneHistoryTextBox.cs} (95%) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs similarity index 95% rename from osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs index 3bff321d0d..f27711f512 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatManipulation.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs @@ -12,16 +12,18 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osuTK.Input; -namespace osu.Game.Tests.Visual.Online +namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneChatManipulation : OsuManualInputManagerTestScene + public class TestSceneHistoryTextBox : OsuManualInputManagerTestScene { - private HistoryTextBox box; - private OsuSpriteText text; + private const string temp = "Temp message"; private int messageCounter; + private HistoryTextBox box; + private OsuSpriteText text; + [SetUp] public void SetUp() { @@ -49,6 +51,9 @@ namespace osu.Game.Tests.Visual.Online box.OnCommit += (_, __) => { + if (string.IsNullOrEmpty(box.Text)) + return; + text.Text = $"{nameof(box.OnCommit)}: {box.Text}"; box.Text = string.Empty; box.TakeFocus(); @@ -64,7 +69,6 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestEmptyHistory() { - const string temp = "Temp message"; AddStep("Set text", () => box.Text = temp); AddStep("Move down", () => InputManager.Key(Key.Down)); @@ -78,8 +82,6 @@ namespace osu.Game.Tests.Visual.Online public void TestPartialHistory() { addMessages(2); - - const string temp = "Temp message"; AddStep("Set text", () => box.Text = temp); AddStep("Move down", () => InputManager.Key(Key.Down)); @@ -102,21 +104,18 @@ namespace osu.Game.Tests.Visual.Online public void TestFullHistory() { addMessages(5); + AddStep("Set text", () => box.Text = temp); AddAssert("History saved as <5-1>", () => Enumerable.Range(0, 5).Select(number => $"Message {5 - number}").SequenceEqual(box.MessageHistory)); - const string temp = "Temp message"; - AddStep("Set text", () => box.Text = temp); - AddStep("Move down", () => InputManager.Key(Key.Down)); AddAssert("Text is the same", () => box.Text == temp); addMessages(2); + AddStep("Set text", () => box.Text = temp); AddAssert("Overrode history to <7-3>", () => Enumerable.Range(0, 5).Select(number => $"Message {7 - number}").SequenceEqual(box.MessageHistory)); - AddStep("Set text", () => box.Text = temp); - AddRepeatStep("Move Up", () => InputManager.Key(Key.Up), 5); AddAssert("Same as 3rd message", () => box.Text == "Message 3"); diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index 6c9df5aca2..bebe21da47 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -12,27 +12,27 @@ namespace osu.Game.Graphics.UserInterface public class HistoryTextBox : FocusedTextBox { private readonly int historyLimit; - - private bool everythingSelected; - - public int HistoryLength => messageHistory.Count; - private readonly List messageHistory; public IReadOnlyList MessageHistory => Enumerable.Range(0, HistoryLength).Select(GetOldMessage).ToList(); - private string originalMessage = string.Empty; - - private int historyIndex = -1; + public int HistoryLength => messageHistory.Count; private int startIndex; + private int selectedIndex = -1; + + private string originalMessage = string.Empty; + private bool everythingSelected; private int getNormalizedIndex(int index) => (HistoryLength + startIndex - index - 1) % HistoryLength; public HistoryTextBox(int historyLimit = 100) { + if (historyLimit <= 0) + throw new ArgumentOutOfRangeException(); + this.historyLimit = historyLimit; messageHistory = new List(historyLimit); @@ -40,7 +40,7 @@ namespace osu.Game.Graphics.UserInterface { if (string.IsNullOrEmpty(text.NewValue) || everythingSelected) { - historyIndex = -1; + selectedIndex = -1; everythingSelected = false; } }; @@ -66,28 +66,28 @@ namespace osu.Game.Graphics.UserInterface switch (e.Key) { case Key.Up: - if (historyIndex == HistoryLength - 1) + if (selectedIndex == HistoryLength - 1) return true; - if (historyIndex == -1) + if (selectedIndex == -1) originalMessage = Text; - Text = messageHistory[getNormalizedIndex(++historyIndex)]; + Text = messageHistory[getNormalizedIndex(++selectedIndex)]; return true; case Key.Down: - if (historyIndex == -1) + if (selectedIndex == -1) return true; - if (historyIndex == 0) + if (selectedIndex == 0) { - historyIndex = -1; + selectedIndex = -1; Text = originalMessage; return true; } - Text = messageHistory[getNormalizedIndex(--historyIndex)]; + Text = messageHistory[getNormalizedIndex(--selectedIndex)]; return true; } @@ -110,7 +110,7 @@ namespace osu.Game.Graphics.UserInterface } } - historyIndex = -1; + selectedIndex = -1; base.Commit(); } From a25c94d567e9bdc4407e9882b0917bd85c6ba2ed Mon Sep 17 00:00:00 2001 From: Dragon Date: Thu, 17 Nov 2022 11:35:13 +0100 Subject: [PATCH 2255/2686] Replacing structure to use LimitedCapacityQueue.cs --- .../UserInterface/TestSceneHistoryTextBox.cs | 11 +-- .../Graphics/UserInterface/HistoryTextBox.cs | 70 +++++++------------ 2 files changed, 31 insertions(+), 50 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs index f27711f512..862777c500 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.UserInterface } }; - box.OnCommit += (_, __) => + box.OnCommit += (_, _) => { if (string.IsNullOrEmpty(box.Text)) return; @@ -70,6 +70,7 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestEmptyHistory() { AddStep("Set text", () => box.Text = temp); + AddAssert("History is empty", () => !box.GetMessageHistory().Any()); AddStep("Move down", () => InputManager.Key(Key.Down)); AddAssert("Text is the same", () => box.Text == temp); @@ -106,7 +107,7 @@ namespace osu.Game.Tests.Visual.UserInterface addMessages(5); AddStep("Set text", () => box.Text = temp); AddAssert("History saved as <5-1>", () => - Enumerable.Range(0, 5).Select(number => $"Message {5 - number}").SequenceEqual(box.MessageHistory)); + Enumerable.Range(0, 5).Select(number => $"Message {5 - number}").SequenceEqual(box.GetMessageHistory())); AddStep("Move down", () => InputManager.Key(Key.Down)); AddAssert("Text is the same", () => box.Text == temp); @@ -114,7 +115,7 @@ namespace osu.Game.Tests.Visual.UserInterface addMessages(2); AddStep("Set text", () => box.Text = temp); AddAssert("Overrode history to <7-3>", () => - Enumerable.Range(0, 5).Select(number => $"Message {7 - number}").SequenceEqual(box.MessageHistory)); + Enumerable.Range(0, 5).Select(number => $"Message {7 - number}").SequenceEqual(box.GetMessageHistory())); AddRepeatStep("Move Up", () => InputManager.Key(Key.Up), 5); AddAssert("Same as 3rd message", () => box.Text == "Message 3"); @@ -134,11 +135,11 @@ namespace osu.Game.Tests.Visual.UserInterface { addMessages(5); AddAssert("History saved as <5-1>", () => - Enumerable.Range(0, 5).Select(number => $"Message {5 - number}").SequenceEqual(box.MessageHistory)); + Enumerable.Range(0, 5).Select(number => $"Message {5 - number}").SequenceEqual(box.GetMessageHistory())); addMessages(6); AddAssert("Overrode history to <11-7>", () => - Enumerable.Range(0, 5).Select(number => $"Message {11 - number}").SequenceEqual(box.MessageHistory)); + Enumerable.Range(0, 5).Select(number => $"Message {11 - number}").SequenceEqual(box.GetMessageHistory())); } [Test] diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index bebe21da47..17858ea16d 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -1,46 +1,44 @@ // 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 osu.Framework.Input.Events; +using osu.Game.Rulesets.Difficulty.Utils; using osuTK.Input; namespace osu.Game.Graphics.UserInterface { public class HistoryTextBox : FocusedTextBox { - private readonly int historyLimit; - private readonly List messageHistory; + private readonly LimitedCapacityQueue messageHistory; - public IReadOnlyList MessageHistory => - Enumerable.Range(0, HistoryLength).Select(GetOldMessage).ToList(); + public IEnumerable GetMessageHistory() + { + if (HistoryCount == 0) + yield break; - public int HistoryLength => messageHistory.Count; + for (int i = HistoryCount - 1; i >= 0; i--) + yield return messageHistory[i]; + } - private int startIndex; - private int selectedIndex = -1; + public int HistoryCount => messageHistory.Count; + + private int selectedIndex; private string originalMessage = string.Empty; private bool everythingSelected; - private int getNormalizedIndex(int index) => - (HistoryLength + startIndex - index - 1) % HistoryLength; + public string GetOldMessage(int index) => messageHistory[HistoryCount - index - 1]; - public HistoryTextBox(int historyLimit = 100) + public HistoryTextBox(int capacity = 100) { - if (historyLimit <= 0) - throw new ArgumentOutOfRangeException(); - - this.historyLimit = historyLimit; - messageHistory = new List(historyLimit); + messageHistory = new LimitedCapacityQueue(capacity); Current.ValueChanged += text => { if (string.IsNullOrEmpty(text.NewValue) || everythingSelected) { - selectedIndex = -1; + selectedIndex = HistoryCount; everythingSelected = false; } }; @@ -53,41 +51,33 @@ namespace osu.Game.Graphics.UserInterface base.OnTextSelectionChanged(selectionType); } - public string GetOldMessage(int index) - { - if (index < 0 || index >= HistoryLength) - throw new ArgumentOutOfRangeException(); - - return HistoryLength == 0 ? string.Empty : messageHistory[getNormalizedIndex(index)]; - } - protected override bool OnKeyDown(KeyDownEvent e) { switch (e.Key) { case Key.Up: - if (selectedIndex == HistoryLength - 1) + if (selectedIndex == 0) return true; - if (selectedIndex == -1) + if (selectedIndex == HistoryCount) originalMessage = Text; - Text = messageHistory[getNormalizedIndex(++selectedIndex)]; + Text = messageHistory[--selectedIndex]; return true; case Key.Down: - if (selectedIndex == -1) + if (selectedIndex == HistoryCount) return true; - if (selectedIndex == 0) + if (selectedIndex == HistoryCount - 1) { - selectedIndex = -1; + selectedIndex = HistoryCount; Text = originalMessage; return true; } - Text = messageHistory[getNormalizedIndex(--selectedIndex)]; + Text = messageHistory[++selectedIndex]; return true; } @@ -98,19 +88,9 @@ namespace osu.Game.Graphics.UserInterface protected override void Commit() { if (!string.IsNullOrEmpty(Text)) - { - if (HistoryLength == historyLimit) - { - messageHistory[startIndex++] = Text; - startIndex %= historyLimit; - } - else - { - messageHistory.Add(Text); - } - } + messageHistory.Enqueue(Text); - selectedIndex = -1; + selectedIndex = HistoryCount; base.Commit(); } From fa00fc5c6d2ee22f393087a921c7b637f1f3823a Mon Sep 17 00:00:00 2001 From: Piggey Date: Thu, 17 Nov 2022 13:27:56 +0100 Subject: [PATCH 2256/2686] change scoresType to be a bindable --- osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index bf9cdc8db7..39f584efd5 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Play.HUD this.trackingUser = trackingUser; } - private PlayBeatmapDetailArea.TabType scoresType; + private Bindable scoresType = new Bindable(); [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -52,7 +52,7 @@ namespace osu.Game.Screens.Play.HUD config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility); // a way to differentiate scores taken from online ranking to local scores - scoresType = config.Get(OsuSetting.BeatmapDetailTab); + scoresType = config.GetBindable(OsuSetting.BeatmapDetailTab); } protected override void LoadComplete() @@ -104,7 +104,7 @@ namespace osu.Game.Screens.Play.HUD { base.sort(); - if (scoresType != PlayBeatmapDetailArea.TabType.Local) + if (scoresType.Value != PlayBeatmapDetailArea.TabType.Local) { // change displayed potision to '-' when there are 50 already submitted scores and tracked score is last if (TrackedScore?.ScorePosition == Flow.Count && Flow.Count > max_online_scores) From 5e4ade3bee2ee0c77e49a00d4ce13a014c72dcb3 Mon Sep 17 00:00:00 2001 From: Piggey Date: Thu, 17 Nov 2022 13:28:04 +0100 Subject: [PATCH 2257/2686] add tests --- .../TestSceneSoloGameplayLeaderboard.cs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index 60ed0012ae..edda0ab416 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -15,6 +15,7 @@ using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.Gameplay { @@ -26,6 +27,7 @@ namespace osu.Game.Tests.Visual.Gameplay private readonly BindableList scores = new BindableList(); private readonly Bindable configVisibility = new Bindable(); + private readonly Bindable beatmapTabType = new Bindable(); private SoloGameplayLeaderboard leaderboard = null!; @@ -33,6 +35,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void load(OsuConfigManager config) { config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility); + config.BindWith(OsuSetting.BeatmapDetailTab, beatmapTabType); } [SetUpSteps] @@ -70,6 +73,25 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value); } + [Test] + public void TestTrackedScorePosition() + { + AddStep("change TabType to global", () => beatmapTabType.Value = PlayBeatmapDetailArea.TabType.Global); + AddUntilStep("tracked player is #50", () => leaderboard.TrackedScore?.ScorePosition! == 50); + + AddStep("change TabType to local", () => beatmapTabType.Value = PlayBeatmapDetailArea.TabType.Local); + AddUntilStep("tracked player is #50", () => leaderboard.TrackedScore?.ScorePosition! == 50); + + AddStep("add one more score", () => scores.Add(new ScoreInfo { User = new APIUser { Username = "New player 1" }, TotalScore = RNG.Next(600000, 1000000) })); + AddUntilStep("tracked player is #51", () => leaderboard.TrackedScore?.ScorePosition! == 51); + + AddStep("change TabType to global", () => beatmapTabType.Value = PlayBeatmapDetailArea.TabType.Global); + AddUntilStep("tracked player is -", () => leaderboard.TrackedScore?.ScorePosition! == null); + + AddStep("change TabType to country", () => beatmapTabType.Value = PlayBeatmapDetailArea.TabType.Country); + AddUntilStep("tracked player is -", () => leaderboard.TrackedScore?.ScorePosition! == null); + } + [Test] public void TestVisibility() { @@ -86,7 +108,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("leaderboard still visible", () => leaderboard.Alpha == 1); } - private static List createSampleScores() + private static List createSampleScores(int numRandScores = 50) { return new[] { @@ -95,7 +117,7 @@ namespace osu.Game.Tests.Visual.Gameplay new ScoreInfo { User = new APIUser { Username = @"spaceman_atlas" }, TotalScore = RNG.Next(500000, 1000000) }, new ScoreInfo { User = new APIUser { Username = @"frenzibyte" }, TotalScore = RNG.Next(500000, 1000000) }, new ScoreInfo { User = new APIUser { Username = @"Susko3" }, TotalScore = RNG.Next(500000, 1000000) }, - }.Concat(Enumerable.Range(0, 50).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 1000000 - i * 10000 })).ToList(); + }.Concat(Enumerable.Range(0, 49 - 5).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 1000000 - i * 10000 })).ToList(); } } } From 20d87fbed4c9bc1079a4da3d94a4eb2ada093ad5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 23:05:34 +0900 Subject: [PATCH 2258/2686] Eagerly dispose of triangles intro textures to avoid holding for full length of game session --- osu.Game/Screens/Menu/IntroTriangles.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 05a6d25303..4ec877b85a 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -224,8 +224,8 @@ namespace osu.Game.Screens.Menu { rulesetsScale.ScaleTo(0.8f, 1000); rulesets.FadeIn().ScaleTo(1).TransformSpacingTo(new Vector2(200, 0)); - welcomeText.FadeOut(); - triangles.FadeOut(); + welcomeText.FadeOut().Expire(); + triangles.FadeOut().Expire(); } using (BeginDelayedSequence(rulesets_2)) @@ -307,7 +307,7 @@ namespace osu.Game.Screens.Menu } [BackgroundDependencyLoader] - private void load(TextureStore textures) + private void load(LargeTextureStore textures) { InternalChildren = new Drawable[] { From a3e8cc1663be4dab2ebfa9cbd59f0f5adec95da5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 23:41:35 +0900 Subject: [PATCH 2259/2686] Mark beatmap listing placeholder textures as large --- osu.Game/Overlays/BeatmapListingOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index c278c9cb93..b78a432194 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -287,7 +287,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(TextureStore textures) + private void load(LargeTextureStore textures) { AddInternal(new FillFlowContainer { @@ -332,7 +332,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(TextureStore textures) + private void load(LargeTextureStore textures) { AddInternal(new FillFlowContainer { From 63c185551111aafdcabfc89cd093349ebd420065 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 23:41:49 +0900 Subject: [PATCH 2260/2686] Avoid loading beatmap listing placeholders until required --- osu.Game/Overlays/BeatmapListingOverlay.cs | 43 ++++------------------ 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index b78a432194..5e922973ec 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -41,11 +41,8 @@ namespace osu.Game.Overlays private IBindable apiUser; - private Drawable currentContent; private Container panelTarget; private FillFlowContainer foundContent; - private NotFoundDrawable notFoundContent; - private SupporterRequiredDrawable supporterRequiredContent; private BeatmapListingFilterControl filterControl; public BeatmapListingOverlay() @@ -86,11 +83,6 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.X, Masking = true, Padding = new MarginPadding { Horizontal = 20 }, - Children = new Drawable[] - { - notFoundContent = new NotFoundDrawable(), - supporterRequiredContent = new SupporterRequiredDrawable(), - } } }, }, @@ -107,7 +99,7 @@ namespace osu.Game.Overlays apiUser.BindValueChanged(_ => Schedule(() => { if (api.IsLoggedIn) - addContentToResultsArea(Drawable.Empty()); + replaceResultsAreaContent(Drawable.Empty()); })); } @@ -155,8 +147,9 @@ namespace osu.Game.Overlays if (searchResult.Type == BeatmapListingFilterControl.SearchResultType.SupporterOnlyFilters) { - supporterRequiredContent.UpdateText(searchResult.SupporterOnlyFiltersUsed); - addContentToResultsArea(supporterRequiredContent); + var supporterOnly = new SupporterRequiredDrawable(); + supporterOnly.UpdateText(searchResult.SupporterOnlyFiltersUsed); + replaceResultsAreaContent(supporterOnly); return; } @@ -167,13 +160,13 @@ namespace osu.Game.Overlays //No matches case if (!newCards.Any()) { - addContentToResultsArea(notFoundContent); + replaceResultsAreaContent(new NotFoundDrawable()); return; } var content = createCardContainerFor(newCards); - panelLoadTask = LoadComponentAsync(foundContent = content, addContentToResultsArea, (cancellationToken = new CancellationTokenSource()).Token); + panelLoadTask = LoadComponentAsync(foundContent = content, replaceResultsAreaContent, (cancellationToken = new CancellationTokenSource()).Token); } else { @@ -221,36 +214,16 @@ namespace osu.Game.Overlays return content; } - private void addContentToResultsArea(Drawable content) + private void replaceResultsAreaContent(Drawable content) { Loading.Hide(); lastFetchDisplayedTime = Time.Current; - if (content == currentContent) - return; - - var lastContent = currentContent; - - if (lastContent != null) - { - lastContent.FadeOut(); - if (!isPlaceholderContent(lastContent)) - lastContent.Expire(); - } - - if (!content.IsAlive) - panelTarget.Add(content); + panelTarget.Child = content; content.FadeInFromZero(); - currentContent = content; } - /// - /// Whether is a static placeholder reused multiple times by this overlay. - /// - private bool isPlaceholderContent(Drawable drawable) - => drawable == notFoundContent || drawable == supporterRequiredContent; - private void onCardSizeChanged() { if (foundContent?.IsAlive != true || !foundContent.Any()) From 73e4827d36a57e72a8e26a1ab31882939f19a6a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Nov 2022 23:55:40 +0900 Subject: [PATCH 2261/2686] Avoid loading overlay headers until first open Also switches them to use non-atlased target as they won't benefit much from atlasing. --- osu.Game/Overlays/OverlayHeaderBackground.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/OverlayHeaderBackground.cs b/osu.Game/Overlays/OverlayHeaderBackground.cs index c47f16272f..540b28d9b2 100644 --- a/osu.Game/Overlays/OverlayHeaderBackground.cs +++ b/osu.Game/Overlays/OverlayHeaderBackground.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays Height = 80; RelativeSizeAxes = Axes.X; Masking = true; - InternalChild = new Background(textureName); + InternalChild = new DelayedLoadWrapper(() => new Background(textureName)); } private class Background : Sprite @@ -36,10 +36,16 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(TextureStore textures) + private void load(LargeTextureStore textures) { Texture = textures.Get(textureName); } + + protected override void LoadComplete() + { + base.LoadComplete(); + this.FadeInFromZero(500, Easing.OutQuint); + } } } } From b37e9c0266088f187329c47b9490eb5e889798fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 00:01:53 +0900 Subject: [PATCH 2262/2686] Fix news post images never unloading from memory after first display --- .../Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs | 7 +------ osu.Game/Overlays/News/NewsCard.cs | 7 ++----- osu.Game/Overlays/News/NewsPostBackground.cs | 7 +++++++ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs b/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs index 8f5c942b6e..1d904526fd 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs @@ -119,22 +119,17 @@ namespace osu.Game.Overlays.Dashboard.Home.News [BackgroundDependencyLoader] private void load(GameHost host) { - NewsPostBackground bg; - - Child = new DelayedLoadWrapper(bg = new NewsPostBackground(post.FirstImage) + Child = new DelayedLoadUnloadWrapper(() => new NewsPostBackground(post.FirstImage) { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fill, Anchor = Anchor.Centre, Origin = Anchor.Centre, - Alpha = 0 }) { RelativeSizeAxes = Axes.Both }; - bg.OnLoadComplete += d => d.FadeIn(250, Easing.In); - TooltipText = "view in browser"; Action = () => host.OpenUrlExternally("https://osu.ppy.sh/home/news/" + post.Slug); diff --git a/osu.Game/Overlays/News/NewsCard.cs b/osu.Game/Overlays/News/NewsCard.cs index eb76522e11..c8e0b0c7ef 100644 --- a/osu.Game/Overlays/News/NewsCard.cs +++ b/osu.Game/Overlays/News/NewsCard.cs @@ -49,7 +49,6 @@ namespace osu.Game.Overlays.News Action = () => host.OpenUrlExternally("https://osu.ppy.sh/home/news/" + post.Slug); } - NewsPostBackground bg; AddRange(new Drawable[] { background = new Box @@ -71,14 +70,14 @@ namespace osu.Game.Overlays.News CornerRadius = 6, Children = new Drawable[] { - new DelayedLoadWrapper(bg = new NewsPostBackground(post.FirstImage) + new DelayedLoadUnloadWrapper(() => new NewsPostBackground(post.FirstImage) { RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fill, Anchor = Anchor.Centre, Origin = Anchor.Centre, Alpha = 0 - }) + }, timeBeforeUnload: 5000) { RelativeSizeAxes = Axes.Both }, @@ -116,8 +115,6 @@ namespace osu.Game.Overlays.News IdleColour = colourProvider.Background4; HoverColour = colourProvider.Background3; - bg.OnLoadComplete += d => d.FadeIn(250, Easing.In); - main.AddParagraph(post.Title, t => t.Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold)); main.AddParagraph(post.Preview, t => t.Font = OsuFont.GetFont(size: 12)); // Should use sans-serif font main.AddParagraph("by ", t => t.Font = OsuFont.GetFont(size: 12)); diff --git a/osu.Game/Overlays/News/NewsPostBackground.cs b/osu.Game/Overlays/News/NewsPostBackground.cs index bddca8f7ec..b77623842c 100644 --- a/osu.Game/Overlays/News/NewsPostBackground.cs +++ b/osu.Game/Overlays/News/NewsPostBackground.cs @@ -4,6 +4,7 @@ #nullable disable using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; @@ -25,6 +26,12 @@ namespace osu.Game.Overlays.News Texture = store.Get(createUrl(sourceUrl)); } + protected override void LoadComplete() + { + base.LoadComplete(); + this.FadeInFromZero(500, Easing.OutQuint); + } + private string createUrl(string source) { if (string.IsNullOrEmpty(source)) From eb8f6626abebab7e24ccb8afe34303c3c87f5a06 Mon Sep 17 00:00:00 2001 From: Piggey Date: Thu, 17 Nov 2022 21:38:09 +0100 Subject: [PATCH 2263/2686] revert changes from `GameplayLeaderboard` tests --- .../Visual/Gameplay/TestSceneGameplayLeaderboard.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index a385060d62..171ae829a9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("add many scores in one go", () => { - for (int i = 0; i < 49; i++) + for (int i = 0; i < 32; i++) createRandomScore(new APIUser { Username = $"Player {i + 1}" }); // Add player at end to force an animation down the whole list. @@ -61,12 +61,6 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for tracked score fully visible", () => leaderboard.ScreenSpaceDrawQuad.Intersects(leaderboard.TrackedScore!.ScreenSpaceDrawQuad)); - AddUntilStep("ensure player is #50", () => leaderboard.CheckPositionByUsername("You", 50)); - - AddStep("add one more player", () => createRandomScore(new APIUser { Username = "Player 50" })); - - AddUntilStep("ensure player is #?", () => leaderboard.CheckPositionByUsername("You", null)); - AddStep("change score to middle", () => playerScore.Value = 1000000); AddWaitStep("wait for movement", 5); AddUntilStep("wait for tracked score fully visible", () => leaderboard.ScreenSpaceDrawQuad.Intersects(leaderboard.TrackedScore!.ScreenSpaceDrawQuad)); From 53769479c772acdfe5aadc324a9a9d7e88e9c097 Mon Sep 17 00:00:00 2001 From: Piggey Date: Thu, 17 Nov 2022 21:42:15 +0100 Subject: [PATCH 2264/2686] oh oops --- .../Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index edda0ab416..fc1a67e285 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -108,7 +108,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("leaderboard still visible", () => leaderboard.Alpha == 1); } - private static List createSampleScores(int numRandScores = 50) + private static List createSampleScores() { return new[] { @@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.Gameplay new ScoreInfo { User = new APIUser { Username = @"spaceman_atlas" }, TotalScore = RNG.Next(500000, 1000000) }, new ScoreInfo { User = new APIUser { Username = @"frenzibyte" }, TotalScore = RNG.Next(500000, 1000000) }, new ScoreInfo { User = new APIUser { Username = @"Susko3" }, TotalScore = RNG.Next(500000, 1000000) }, - }.Concat(Enumerable.Range(0, 49 - 5).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 1000000 - i * 10000 })).ToList(); + }.Concat(Enumerable.Range(0, 44).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 1000000 - i * 10000 })).ToList(); } } } From eb691266c1e8c9dd71bb44452e9a6871105974d3 Mon Sep 17 00:00:00 2001 From: Piggey Date: Thu, 17 Nov 2022 21:50:39 +0100 Subject: [PATCH 2265/2686] cleanup --- osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 39f584efd5..bf83c9a3c6 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -39,13 +39,13 @@ namespace osu.Game.Screens.Play.HUD /// public readonly Bindable AlwaysVisible = new Bindable(true); + private Bindable scoresType = new Bindable(); + public SoloGameplayLeaderboard(IUser trackingUser) { this.trackingUser = trackingUser; } - private Bindable scoresType = new Bindable(); - [BackgroundDependencyLoader] private void load(OsuConfigManager config) { From 93c2280754d8bb859eb26914e90fa7e5eaf69313 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 10:35:05 +0900 Subject: [PATCH 2266/2686] Fix supporter filters text not being set correctly --- osu.Game/Overlays/BeatmapListingOverlay.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 5e922973ec..2d9583b864 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -147,8 +147,7 @@ namespace osu.Game.Overlays if (searchResult.Type == BeatmapListingFilterControl.SearchResultType.SupporterOnlyFilters) { - var supporterOnly = new SupporterRequiredDrawable(); - supporterOnly.UpdateText(searchResult.SupporterOnlyFiltersUsed); + var supporterOnly = new SupporterRequiredDrawable(searchResult.SupporterOnlyFiltersUsed); replaceResultsAreaContent(supporterOnly); return; } @@ -297,11 +296,15 @@ namespace osu.Game.Overlays { private LinkFlowContainer supporterRequiredText; - public SupporterRequiredDrawable() + private readonly List filtersUsed; + + public SupporterRequiredDrawable(List filtersUsed) { RelativeSizeAxes = Axes.X; Height = 225; Alpha = 0; + + this.filtersUsed = filtersUsed; } [BackgroundDependencyLoader] @@ -333,14 +336,9 @@ namespace osu.Game.Overlays }, } }); - } - - public void UpdateText(List filters) - { - supporterRequiredText.Clear(); supporterRequiredText.AddText( - BeatmapsStrings.ListingSearchSupporterFilterQuoteDefault(string.Join(" and ", filters), "").ToString(), + BeatmapsStrings.ListingSearchSupporterFilterQuoteDefault(string.Join(" and ", filtersUsed), "").ToString(), t => { t.Font = OsuFont.GetFont(size: 16); From b53f9baf6a8d034dd36fd3a2d271205119dbb362 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 11:21:12 +0900 Subject: [PATCH 2267/2686] Fix `NowPlayingOverlay` loading background texture too early (and permanently) --- osu.Game/Overlays/NowPlayingOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 900b4bebf0..949f1e7b96 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -100,7 +100,7 @@ namespace osu.Game.Overlays }, Children = new[] { - background = new Background(), + background = Empty(), title = new OsuSpriteText { Origin = Anchor.BottomCentre, @@ -413,7 +413,7 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(TextureStore textures) + private void load(LargeTextureStore textures) { sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4"); } From 82829867db1522a7a255b97fbc8c17a1083a84c7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Nov 2022 07:07:56 +0300 Subject: [PATCH 2268/2686] Fix beatmap options test failure due to no beatmap being selected --- osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index d58887c090..e500efede3 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -436,6 +436,8 @@ namespace osu.Game.Tests.Visual.Navigation { AddUntilStep("Wait for toolbar to load", () => Game.Toolbar.IsLoaded); + AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely()); + TestPlaySongSelect songSelect = null; PushAndConfirm(() => songSelect = new TestPlaySongSelect()); From a5d22195f2bdd39bb030f2536b93af908070131e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 13:45:46 +0900 Subject: [PATCH 2269/2686] Fix potential incorrect connection state resulting in null reference --- osu.Game/Online/PersistentEndpointClientConnector.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index 2c4e127723..be76644745 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -145,7 +145,9 @@ namespace osu.Game.Online private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken) { - isConnected.Value = false; + bool hasBeenCancelled = cancellationToken.IsCancellationRequested; + + await disconnect(true); if (ex != null) await handleErrorAndDelay(ex, cancellationToken).ConfigureAwait(false); @@ -153,7 +155,7 @@ namespace osu.Game.Online Logger.Log($"{ClientName} disconnected", LoggingTarget.Network); // make sure a disconnect wasn't triggered (and this is still the active connection). - if (!cancellationToken.IsCancellationRequested) + if (!hasBeenCancelled) await Task.Run(connect, default).ConfigureAwait(false); } @@ -174,7 +176,9 @@ namespace osu.Game.Online } finally { + isConnected.Value = false; CurrentConnection = null; + if (takeLock) connectionLock.Release(); } From 551192b413ab59053383107a336b9a72a98e9df2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 18 Nov 2022 13:55:37 +0900 Subject: [PATCH 2270/2686] Refactor a bit for readability --- .../Overlays/Settings/Sections/Input/KeyBindingRow.cs | 10 +++++----- .../Settings/Sections/Input/KeyBindingsSubsection.cs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 12fd6f0746..832aa759d0 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -34,9 +34,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input public class KeyBindingRow : Container, IFilterable { /// - /// Invoked when binding of this row finalises with a change being written. + /// Invoked when the binding of this row is updated with a change being written. /// - public Action BindingFinalised { get; set; } + public Action BindingUpdated { get; set; } private readonly object action; private readonly IEnumerable bindings; @@ -385,7 +385,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input finalise(false); } - private void finalise(bool changedKey = true) + private void finalise(bool hasChanged = true) { if (bindTarget != null) { @@ -398,8 +398,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input { // schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.) bindTarget = null; - if (changedKey) - BindingFinalised?.Invoke(this); + if (hasChanged) + BindingUpdated?.Invoke(this); }); } diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs index a3f378e3c9..98d569948f 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs @@ -56,7 +56,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { AllowMainMouseButtons = Ruleset != null, Defaults = defaultGroup.Select(d => d.KeyCombination), - BindingFinalised = bindingCompleted + BindingUpdated = onBindingUpdated }); } @@ -66,7 +66,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input }); } - private void bindingCompleted(KeyBindingRow sender) + private void onBindingUpdated(KeyBindingRow sender) { if (AutoAdvanceTarget) { From e4d134a82057b3d6f05feab5f6251612488a61d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 14:07:40 +0900 Subject: [PATCH 2271/2686] Reduce time waited on a score submission token from 60 to 30s --- osu.Game/Screens/Play/SubmittingPlayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index 345bd5a134..fb296d7988 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Play api.Queue(req); // Generally a timeout would not happen here as APIAccess will timeout first. - if (!tcs.Task.Wait(60000)) + if (!tcs.Task.Wait(30000)) req.TriggerFailure(new InvalidOperationException("Token retrieval timed out (request never run)")); return true; From 964ceddf83360c24ae0cabc4e895e537237bc2c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 14:21:37 +0900 Subject: [PATCH 2272/2686] Fix API queue only being flushed once while in a failing state --- osu.Game/Online/API/APIAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 8ac2e2d453..65f78e1fd7 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -419,7 +419,7 @@ namespace osu.Game.Online.API failureCount++; log.Add($@"API failure count is now {failureCount}"); - if (failureCount >= 3 && State.Value == APIState.Online) + if (failureCount >= 3) { state.Value = APIState.Failing; flushQueue(); From d47c46d1443be45ad90ca2e70780b21a94aa1080 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 18 Nov 2022 14:16:12 +0900 Subject: [PATCH 2273/2686] Compute raw score in-line Saves on an allocation (though it seems to only be a ValueType so it shouldn't be a big deal) and a tail-call. --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 2b6e40b94e..899d149cbc 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -335,24 +335,21 @@ namespace osu.Game.Rulesets.Scoring [Pure] public long ComputeScore(ScoringMode mode, double accuracyRatio, double comboRatio, long bonusScore, int totalBasicHitObjects) { + double accuracyScore = accuracyPortion * accuracyRatio; + double comboScore = comboPortion * comboRatio; + double rawScore = (max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier; + switch (mode) { default: case ScoringMode.Standardised: - return (long)Math.Round(computeRawScore()); + return (long)Math.Round(rawScore); case ScoringMode.Classic: // This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring. // The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes. - double scaledStandardised = computeRawScore() / max_score; - return (long)Math.Round(Math.Pow(scaledStandardised * Math.Max(1, totalBasicHitObjects), 2) * ClassicScoreMultiplier); - } - - double computeRawScore() - { - double accuracyScore = accuracyPortion * accuracyRatio; - double comboScore = comboPortion * comboRatio; - return (max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier; + double scaledRawScore = rawScore / max_score; + return (long)Math.Round(Math.Pow(scaledRawScore * Math.Max(1, totalBasicHitObjects), 2) * ClassicScoreMultiplier); } } From 5fc0d45675475d0932c15f566ba5c131d81ab406 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 14:29:10 +0900 Subject: [PATCH 2274/2686] Fix triangle button flash effect looking incorrect --- osu.Game/Graphics/UserInterface/OsuButton.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 9140815f32..dae5de2d65 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -4,6 +4,7 @@ #nullable disable using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -69,6 +70,8 @@ namespace osu.Game.Graphics.UserInterface protected Box Background; protected SpriteText SpriteText; + private readonly Box flashLayer; + public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Button) { Height = 40; @@ -99,6 +102,14 @@ namespace osu.Game.Graphics.UserInterface Depth = float.MinValue }, SpriteText = CreateText(), + flashLayer = new Box + { + RelativeSizeAxes = Axes.Both, + Blending = BlendingParameters.Additive, + Depth = float.MinValue, + Colour = Color4.White.Opacity(0.5f), + Alpha = 0, + }, } }); @@ -125,7 +136,7 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnClick(ClickEvent e) { if (Enabled.Value) - Background.FlashColour(Color4.White, 800, Easing.OutQuint); + flashLayer.FadeOutFromOne(800, Easing.OutQuint); return base.OnClick(e); } From b0faa009c1d6262a08a5f6bd0b0256b6101cfb7c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 2 Nov 2022 11:30:29 +0900 Subject: [PATCH 2275/2686] Add some debugging for multiplayer test failures --- .../Online/Multiplayer/MultiplayerClient.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 75334952f0..b39781ebc2 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Newtonsoft.Json; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Development; @@ -727,13 +728,20 @@ namespace osu.Game.Online.Multiplayer if (Room == null) return; - Debug.Assert(APIRoom != null); + try + { + Debug.Assert(APIRoom != null); - Room.Playlist[Room.Playlist.IndexOf(Room.Playlist.Single(existing => existing.ID == item.ID))] = item; + Room.Playlist[Room.Playlist.IndexOf(Room.Playlist.Single(existing => existing.ID == item.ID))] = item; - int existingIndex = APIRoom.Playlist.IndexOf(APIRoom.Playlist.Single(existing => existing.ID == item.ID)); - APIRoom.Playlist.RemoveAt(existingIndex); - APIRoom.Playlist.Insert(existingIndex, createPlaylistItem(item)); + int existingIndex = APIRoom.Playlist.IndexOf(APIRoom.Playlist.Single(existing => existing.ID == item.ID)); + APIRoom.Playlist.RemoveAt(existingIndex); + APIRoom.Playlist.Insert(existingIndex, createPlaylistItem(item)); + } + catch (Exception ex) + { + throw new AggregateException($"Item: {JsonConvert.SerializeObject(createPlaylistItem(item))}\n\nRoom:{JsonConvert.SerializeObject(APIRoom)}", ex); + } ItemChanged?.Invoke(item); RoomUpdated?.Invoke(); From 45f5849301c2c8b990a179485ac9a1d1fc470bcb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 15:33:13 +0900 Subject: [PATCH 2276/2686] Add more test coverage to `TestSceneKeyBindingPanel` --- .../Settings/TestSceneKeyBindingPanel.cs | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index d7d073e908..99b8be0114 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -40,6 +40,33 @@ namespace osu.Game.Tests.Visual.Settings AddWaitStep("wait for scroll", 5); } + [Test] + public void TestBindingSingleKey() + { + scrollToAndStartBinding("Increase volume"); + AddStep("press k", () => InputManager.Key(Key.K)); + checkBinding("Increase volume", "K"); + } + + [Test] + public void TestBindingSingleModifier() + { + scrollToAndStartBinding("Increase volume"); + AddStep("press shift", () => InputManager.PressKey(Key.ShiftLeft)); + AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft)); + checkBinding("Increase volume", "LShift"); + } + + [Test] + public void TestBindingSingleKeyWithModifier() + { + scrollToAndStartBinding("Increase volume"); + AddStep("press shift", () => InputManager.PressKey(Key.ShiftLeft)); + AddStep("press k", () => InputManager.Key(Key.K)); + AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft)); + checkBinding("Increase volume", "LShift-K"); + } + [Test] public void TestBindingMouseWheelToNonGameplay() { @@ -169,7 +196,8 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", + () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0))); } [Test] @@ -198,7 +226,8 @@ namespace osu.Game.Tests.Visual.Settings AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType>().First().Alpha == 0); - AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0))); + AddAssert("binding cleared", + () => settingsKeyBindingRow.ChildrenOfType().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0))); } [Test] @@ -256,8 +285,8 @@ namespace osu.Game.Tests.Visual.Settings var firstRow = panel.ChildrenOfType().First(r => r.ChildrenOfType().Any(s => s.Text.ToString() == name)); var firstButton = firstRow.ChildrenOfType().First(); - return firstButton.Text.Text == keyName; - }); + return firstButton.Text.Text.ToString(); + }, () => Is.EqualTo(keyName)); } private void scrollToAndStartBinding(string name) From cb8275ee755d23d109e61d164282bc08bf529cfd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 15:34:26 +0900 Subject: [PATCH 2277/2686] Add failing test coverage to `TestSceneKeyBindingPanel` for multiple non-modifiers being bound --- .../Visual/Settings/TestSceneKeyBindingPanel.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 99b8be0114..bd54591b9b 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -40,6 +40,16 @@ namespace osu.Game.Tests.Visual.Settings AddWaitStep("wait for scroll", 5); } + [Test] + public void TestBindingTwoNonModifiers() + { + AddStep("press j", () => InputManager.PressKey(Key.J)); + scrollToAndStartBinding("Increase volume"); + AddStep("press k", () => InputManager.Key(Key.K)); + AddStep("release j", () => InputManager.ReleaseKey(Key.J)); + checkBinding("Increase volume", "K"); + } + [Test] public void TestBindingSingleKey() { From e658efbefa9a6452da5b36d894bf6840342ba9f5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 15:20:46 +0900 Subject: [PATCH 2278/2686] Fix being able to bind two non-modifier keys to the same binding --- .../Settings/Sections/Input/KeyBindingRow.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index c91a6a48d4..6ce8a188e6 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -226,7 +226,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromMouseButton(e.Button)); return true; } @@ -252,7 +252,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { if (bindTarget.IsHovered) { - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta)); + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta), KeyCombination.FromScrollDelta(e.ScrollDelta).First()); finalise(); return true; } @@ -263,10 +263,10 @@ namespace osu.Game.Overlays.Settings.Sections.Input protected override bool OnKeyDown(KeyDownEvent e) { - if (!HasFocus) + if (!HasFocus || e.Repeat) return false; - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromKey(e.Key)); if (!isModifier(e.Key)) finalise(); return true; @@ -288,7 +288,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (!HasFocus) return false; - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromJoystickButton(e.Button)); finalise(); return true; @@ -310,7 +310,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (!HasFocus) return false; - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromMidiKey(e.Key)); finalise(); return true; @@ -332,7 +332,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (!HasFocus) return false; - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromTabletAuxiliaryButton(e.Button)); finalise(); return true; @@ -354,7 +354,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (!HasFocus) return false; - bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState)); + bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromTabletPenButton(e.Button)); finalise(); return true; @@ -563,6 +563,14 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } + /// + /// Update from a key combination, only allowing a single non-modifier key to be specified. + /// + /// A generated from the full input state. + /// The key which triggered this update, and should be used as the binding. + public void UpdateKeyCombination(KeyCombination fullState, InputKey triggerKey) => + UpdateKeyCombination(new KeyCombination(fullState.Keys.Where(KeyCombination.IsModifierKey).Append(triggerKey))); + public void UpdateKeyCombination(KeyCombination newCombination) { if (KeyBinding.RulesetName != null && !RealmKeyBindingStore.CheckValidForGameplay(newCombination)) From 90cd38632391e799b43cf865d1b8fcad1df54cc3 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Nov 2022 09:40:08 +0300 Subject: [PATCH 2279/2686] Fix timeline potentially scrolling at extents while not dragging --- .../Components/Timeline/TimelineHitObjectBlueprint.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs index 974e240552..20ef128ee9 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs @@ -436,8 +436,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { base.OnDragEnd(e); - OnDragHandled?.Invoke(null); + dragOperation?.Cancel(); + dragOperation = null; + changeHandler?.EndChange(); + OnDragHandled?.Invoke(null); } } From e2aca8dc9073694983188ed10637879f16975b90 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Nov 2022 09:46:50 +0300 Subject: [PATCH 2280/2686] Suppress nullable warning for now --- osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs b/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs index 1df3d336ee..e7fdb52d2f 100644 --- a/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs +++ b/osu.Game.Tests/Database/LegacyBeatmapImporterTest.cs @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Database private class TestLegacyBeatmapImporter : LegacyBeatmapImporter { public TestLegacyBeatmapImporter() - : base(null) + : base(null!) { } From d17c091d639cbf330d9cd1e535ec267074c6c5b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 15:47:31 +0900 Subject: [PATCH 2281/2686] Move constant to a better location --- osu.Game/Online/API/Requests/GetScoresRequest.cs | 2 ++ osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index 966e69938c..7d1d26b75d 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -16,6 +16,8 @@ namespace osu.Game.Online.API.Requests { public class GetScoresRequest : APIRequest { + public const int MAX_SCORES_PER_REQUEST = 50; + private readonly IBeatmapInfo beatmapInfo; private readonly BeatmapLeaderboardScope scope; private readonly IRulesetInfo ruleset; diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index bf83c9a3c6..243634ee36 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Configuration; +using osu.Game.Online.API.Requests; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Select; @@ -17,7 +18,6 @@ namespace osu.Game.Screens.Play.HUD public class SoloGameplayLeaderboard : GameplayLeaderboard { private const int duration = 100; - private const int max_online_scores = 50; // BAD! private readonly Bindable configVisibility = new Bindable(); private readonly IUser trackingUser; @@ -107,7 +107,7 @@ namespace osu.Game.Screens.Play.HUD if (scoresType.Value != PlayBeatmapDetailArea.TabType.Local) { // change displayed potision to '-' when there are 50 already submitted scores and tracked score is last - if (TrackedScore?.ScorePosition == Flow.Count && Flow.Count > max_online_scores) + if (TrackedScore?.ScorePosition == Flow.Count && Flow.Count > GetScoresRequest.MAX_SCORES_PER_REQUEST) TrackedScore.ScorePosition = null; } } From e4f522aad1344084857a42659c51a33baea05bc6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 15:47:37 +0900 Subject: [PATCH 2282/2686] Fix inspections / typos --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 4 ++-- osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 2a47964118..7e8c2401dd 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Play.HUD { base.LoadComplete(); - Scheduler.AddDelayed(sort, 1000, true); + Scheduler.AddDelayed(Sort, 1000, true); } /// @@ -158,7 +158,7 @@ namespace osu.Game.Screens.Play.HUD } } - protected virtual void sort() + protected virtual void Sort() { if (sorting.IsValid) return; diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 243634ee36..0a2f72121d 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -100,13 +100,13 @@ namespace osu.Game.Screens.Play.HUD local.DisplayOrder.Value = long.MaxValue; } - protected override void sort() + protected override void Sort() { - base.sort(); + base.Sort(); if (scoresType.Value != PlayBeatmapDetailArea.TabType.Local) { - // change displayed potision to '-' when there are 50 already submitted scores and tracked score is last + // change displayed position to '-' when there are 50 already submitted scores and tracked score is last if (TrackedScore?.ScorePosition == Flow.Count && Flow.Count > GetScoresRequest.MAX_SCORES_PER_REQUEST) TrackedScore.ScorePosition = null; } From 20af8217f4d738bbe7a8019ba236e928c4ffe170 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 15:50:41 +0900 Subject: [PATCH 2283/2686] Tidy up bindable flow --- .../Screens/Play/HUD/SoloGameplayLeaderboard.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 0a2f72121d..e9e015f96d 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -20,6 +20,9 @@ namespace osu.Game.Screens.Play.HUD private const int duration = 100; private readonly Bindable configVisibility = new Bindable(); + + private readonly Bindable scoreSource = new Bindable(); + private readonly IUser trackingUser; public readonly IBindableList Scores = new BindableList(); @@ -39,8 +42,6 @@ namespace osu.Game.Screens.Play.HUD /// public readonly Bindable AlwaysVisible = new Bindable(true); - private Bindable scoresType = new Bindable(); - public SoloGameplayLeaderboard(IUser trackingUser) { this.trackingUser = trackingUser; @@ -50,14 +51,13 @@ namespace osu.Game.Screens.Play.HUD private void load(OsuConfigManager config) { config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility); - - // a way to differentiate scores taken from online ranking to local scores - scoresType = config.GetBindable(OsuSetting.BeatmapDetailTab); + config.BindWith(OsuSetting.BeatmapDetailTab, scoreSource); } protected override void LoadComplete() { base.LoadComplete(); + Scores.BindCollectionChanged((_, _) => Scheduler.AddOnce(showScores), true); // Alpha will be updated via `updateVisibility` below. @@ -104,9 +104,9 @@ namespace osu.Game.Screens.Play.HUD { base.Sort(); - if (scoresType.Value != PlayBeatmapDetailArea.TabType.Local) + // change displayed position to '-' when there are 50 already submitted scores and tracked score is last + if (scoreSource.Value != PlayBeatmapDetailArea.TabType.Local) { - // change displayed position to '-' when there are 50 already submitted scores and tracked score is last if (TrackedScore?.ScorePosition == Flow.Count && Flow.Count > GetScoresRequest.MAX_SCORES_PER_REQUEST) TrackedScore.ScorePosition = null; } From aff218dfd528d9900246248a990d2b9312271054 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 15:52:39 +0900 Subject: [PATCH 2284/2686] Redirect through validity function rather than overriding `Sort` --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 8 +++++--- osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs | 10 +++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 7e8c2401dd..47b67fba00 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -62,7 +62,7 @@ namespace osu.Game.Screens.Play.HUD { base.LoadComplete(); - Scheduler.AddDelayed(Sort, 1000, true); + Scheduler.AddDelayed(sort, 1000, true); } /// @@ -158,7 +158,7 @@ namespace osu.Game.Screens.Play.HUD } } - protected virtual void Sort() + private void sort() { if (sorting.IsValid) return; @@ -171,12 +171,14 @@ namespace osu.Game.Screens.Play.HUD for (int i = 0; i < Flow.Count; i++) { Flow.SetLayoutPosition(orderedByScore[i], i); - orderedByScore[i].ScorePosition = i + 1; + orderedByScore[i].ScorePosition = CheckValidScorePosition(i + 1) ? i + 1 : null; } sorting.Validate(); } + protected virtual bool CheckValidScorePosition(int i) => true; + private class InputDisabledScrollContainer : OsuScrollContainer { public InputDisabledScrollContainer() diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index e9e015f96d..0df3200adb 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -100,16 +100,16 @@ namespace osu.Game.Screens.Play.HUD local.DisplayOrder.Value = long.MaxValue; } - protected override void Sort() + protected override bool CheckValidScorePosition(int i) { - base.Sort(); - // change displayed position to '-' when there are 50 already submitted scores and tracked score is last if (scoreSource.Value != PlayBeatmapDetailArea.TabType.Local) { - if (TrackedScore?.ScorePosition == Flow.Count && Flow.Count > GetScoresRequest.MAX_SCORES_PER_REQUEST) - TrackedScore.ScorePosition = null; + if (i == Flow.Count && Flow.Count > GetScoresRequest.MAX_SCORES_PER_REQUEST) + return false; } + + return base.CheckValidScorePosition(i); } private void updateVisibility() => From 0a520c979ed9d0cae8dd8c32f83702b41c026283 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 15:59:40 +0900 Subject: [PATCH 2285/2686] Update test to split out per-type tests --- .../TestSceneSoloGameplayLeaderboard.cs | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index fc1a67e285..d357c52d8a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -73,23 +73,17 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value); } - [Test] - public void TestTrackedScorePosition() + [TestCase(PlayBeatmapDetailArea.TabType.Local, 51)] + [TestCase(PlayBeatmapDetailArea.TabType.Global, null)] + [TestCase(PlayBeatmapDetailArea.TabType.Country, null)] + [TestCase(PlayBeatmapDetailArea.TabType.Friends, null)] + public void TestTrackedScorePosition(PlayBeatmapDetailArea.TabType tabType, int? expectedOverflowIndex) { - AddStep("change TabType to global", () => beatmapTabType.Value = PlayBeatmapDetailArea.TabType.Global); - AddUntilStep("tracked player is #50", () => leaderboard.TrackedScore?.ScorePosition! == 50); - - AddStep("change TabType to local", () => beatmapTabType.Value = PlayBeatmapDetailArea.TabType.Local); - AddUntilStep("tracked player is #50", () => leaderboard.TrackedScore?.ScorePosition! == 50); + AddStep($"change TabType to {tabType}", () => beatmapTabType.Value = tabType); + AddUntilStep("tracked player is #50", () => leaderboard.TrackedScore?.ScorePosition, () => Is.EqualTo(50)); AddStep("add one more score", () => scores.Add(new ScoreInfo { User = new APIUser { Username = "New player 1" }, TotalScore = RNG.Next(600000, 1000000) })); - AddUntilStep("tracked player is #51", () => leaderboard.TrackedScore?.ScorePosition! == 51); - - AddStep("change TabType to global", () => beatmapTabType.Value = PlayBeatmapDetailArea.TabType.Global); - AddUntilStep("tracked player is -", () => leaderboard.TrackedScore?.ScorePosition! == null); - - AddStep("change TabType to country", () => beatmapTabType.Value = PlayBeatmapDetailArea.TabType.Country); - AddUntilStep("tracked player is -", () => leaderboard.TrackedScore?.ScorePosition! == null); + AddUntilStep($"tracked player is #{expectedOverflowIndex}", () => leaderboard.TrackedScore?.ScorePosition, () => Is.EqualTo(expectedOverflowIndex)); } [Test] From d59befc9d3a5bd740f1d6a965d58a36cc9ce8d0c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 16:08:27 +0900 Subject: [PATCH 2286/2686] Fix initial visual state of positions before `sort` runs --- osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index bbde247c21..0d03d8d090 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -62,17 +62,21 @@ namespace osu.Game.Screens.Play.HUD private int? scorePosition; + private bool scorePositionIsSet; + public int? ScorePosition { get => scorePosition; set { - if (value == scorePosition) + // We always want to run once, as the incoming value may be null and require a visual update to "-". + if (value == scorePosition && scorePositionIsSet) return; scorePosition = value; positionText.Text = scorePosition.HasValue ? $"#{scorePosition.Value.FormatRank()}" : "-"; + scorePositionIsSet = true; updateState(); } From 7c08cff297d3d7c6f31ce52a074397d219a0832b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 16:10:32 +0900 Subject: [PATCH 2287/2686] Make new test more resilient to false passes --- .../Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index d357c52d8a..7ad4ec2f85 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -83,7 +83,13 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("tracked player is #50", () => leaderboard.TrackedScore?.ScorePosition, () => Is.EqualTo(50)); AddStep("add one more score", () => scores.Add(new ScoreInfo { User = new APIUser { Username = "New player 1" }, TotalScore = RNG.Next(600000, 1000000) })); - AddUntilStep($"tracked player is #{expectedOverflowIndex}", () => leaderboard.TrackedScore?.ScorePosition, () => Is.EqualTo(expectedOverflowIndex)); + + AddUntilStep("wait for sort", () => leaderboard.ChildrenOfType().First().ScorePosition != null); + + if (expectedOverflowIndex == null) + AddUntilStep($"tracked player has null position", () => leaderboard.TrackedScore?.ScorePosition, () => Is.Null); + else + AddUntilStep($"tracked player is #{expectedOverflowIndex}", () => leaderboard.TrackedScore?.ScorePosition, () => Is.EqualTo(expectedOverflowIndex)); } [Test] From 95908ec023c18d884e6254df3afd60993cb25e10 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 18:13:00 +0900 Subject: [PATCH 2288/2686] 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 5f3fb858ee..8212707d44 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 858cac1dac..f81d9d27b4 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 25217b872b..cd70f1c432 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 06ce8130c2002d9ebd2bfa5ad95b7597e195bbc0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 16 Nov 2022 18:47:58 +0900 Subject: [PATCH 2289/2686] Apply changes in line with framework NRT updates --- osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs | 6 +++--- osu.Game/Collections/CollectionDropdown.cs | 5 +++-- osu.Game/Overlays/ChatOverlay.cs | 6 +++--- osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs | 6 +++--- .../Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs | 5 ++--- .../Screens/Play/PlayerSettings/BeatmapOffsetControl.cs | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs index dd0b61cdf5..c5cf09d449 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Taiko.UI public class DrawableTaikoMascot : BeatSyncedContainer { public readonly Bindable State; - public readonly Bindable LastResult; + public readonly Bindable LastResult; private readonly Dictionary animations; @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Taiko.UI Origin = Anchor = Anchor.BottomLeft; State = new Bindable(startingState); - LastResult = new Bindable(); + LastResult = new Bindable(); animations = new Dictionary(); } @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Taiko.UI LastResult.BindValueChanged(onNewResult); } - private void onNewResult(ValueChangedEvent resultChangedEvent) + private void onNewResult(ValueChangedEvent resultChangedEvent) { var result = resultChangedEvent.NewValue; if (result == null) diff --git a/osu.Game/Collections/CollectionDropdown.cs b/osu.Game/Collections/CollectionDropdown.cs index 71341f51a4..f203d49900 100644 --- a/osu.Game/Collections/CollectionDropdown.cs +++ b/osu.Game/Collections/CollectionDropdown.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; @@ -100,7 +101,7 @@ namespace osu.Game.Collections private void selectionChanged(ValueChangedEvent filter) { // May be null during .Clear(). - if (filter.NewValue == null) + if (filter.NewValue.IsNull()) return; // Never select the manage collection filter - rollback to the previous filter. @@ -112,7 +113,7 @@ namespace osu.Game.Collections return; } - var newCollection = filter.NewValue?.Collection; + var newCollection = filter.NewValue.Collection; // This dropdown be weird. // We only care about filtering if the actual collection has changed. diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index c491c0c695..e9d28dcf28 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -64,7 +64,7 @@ namespace osu.Game.Overlays private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); [Cached] - private readonly Bindable currentChannel = new Bindable(); + private readonly Bindable currentChannel = new Bindable(); private readonly IBindableList availableChannels = new BindableList(); private readonly IBindableList joinedChannels = new BindableList(); @@ -293,7 +293,7 @@ namespace osu.Game.Overlays base.OnFocus(e); } - private void currentChannelChanged(ValueChangedEvent channel) + private void currentChannelChanged(ValueChangedEvent channel) { Channel? newChannel = channel.NewValue; @@ -402,7 +402,7 @@ namespace osu.Game.Overlays { List overlayChannels = channelList.Channels.ToList(); - if (overlayChannels.Count < 2) + if (overlayChannels.Count < 2 || currentChannel.Value == null) return; int currentIndex = overlayChannels.IndexOf(currentChannel.Value); diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 43d68653ad..a34f8f0c1b 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -188,7 +188,7 @@ namespace osu.Game.Overlays.FirstRunSetup public IEnumerable HandledExtensions { get; } = new[] { string.Empty }; - private readonly Bindable currentDirectory = new Bindable(); + private readonly Bindable currentDirectory = new Bindable(); [Resolved(canBeNull: true)] // Can't really be null but required to handle potential of disposal before DI completes. private OsuGameBase? game { get; set; } @@ -206,7 +206,7 @@ namespace osu.Game.Overlays.FirstRunSetup currentDirectory.Value = new DirectoryInfo(fullPath); } - private void onDirectorySelected(ValueChangedEvent directory) + private void onDirectorySelected(ValueChangedEvent directory) { if (directory.NewValue == null) { @@ -247,7 +247,7 @@ namespace osu.Game.Overlays.FirstRunSetup private class DirectoryChooserPopover : OsuPopover { - public DirectoryChooserPopover(Bindable currentDirectory) + public DirectoryChooserPopover(Bindable currentDirectory) { Child = new Container { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs index 58ccb24f7a..d2a57f21db 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs @@ -5,13 +5,12 @@ using osu.Framework.Bindables; using osu.Framework.Screens; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Components; -using PlaylistItem = osu.Game.Online.Rooms.PlaylistItem; namespace osu.Game.Screens.OnlinePlay.Lounge { public class LoungeBackgroundScreen : OnlinePlayBackgroundScreen { - public readonly Bindable SelectedRoom = new Bindable(); + public readonly Bindable SelectedRoom = new Bindable(); private readonly BindableList playlist = new BindableList(); public LoungeBackgroundScreen() @@ -20,7 +19,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge playlist.BindCollectionChanged((_, _) => PlaylistItem = playlist.GetCurrentItem()); } - private void onSelectedRoomChanged(ValueChangedEvent room) + private void onSelectedRoomChanged(ValueChangedEvent room) { if (room.OldValue != null) playlist.UnbindFrom(room.OldValue.Playlist); diff --git a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs index 537f4d811a..fc89effe1b 100644 --- a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs +++ b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs @@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play.PlayerSettings { public class BeatmapOffsetControl : CompositeDrawable { - public Bindable ReferenceScore { get; } = new Bindable(); + public Bindable ReferenceScore { get; } = new Bindable(); public BindableDouble Current { get; } = new BindableDouble { @@ -176,7 +176,7 @@ namespace osu.Game.Screens.Play.PlayerSettings } } - private void scoreChanged(ValueChangedEvent score) + private void scoreChanged(ValueChangedEvent score) { referenceScoreContainer.Clear(); From b86b45b6d25800d3117e2a01862c734cd17a1dbe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Nov 2022 21:13:21 +0900 Subject: [PATCH 2290/2686] Fix excess string interpolation --- .../Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index 7ad4ec2f85..881870921c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for sort", () => leaderboard.ChildrenOfType().First().ScorePosition != null); if (expectedOverflowIndex == null) - AddUntilStep($"tracked player has null position", () => leaderboard.TrackedScore?.ScorePosition, () => Is.Null); + AddUntilStep("tracked player has null position", () => leaderboard.TrackedScore?.ScorePosition, () => Is.Null); else AddUntilStep($"tracked player is #{expectedOverflowIndex}", () => leaderboard.TrackedScore?.ScorePosition, () => Is.EqualTo(expectedOverflowIndex)); } From 1be8c6bd9c4d48d62fb421d5fda37e332705302e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Nov 2022 17:19:32 +0300 Subject: [PATCH 2291/2686] Fix "perform from screen" not considering screen load state --- osu.Game/PerformFromMenuRunner.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/PerformFromMenuRunner.cs b/osu.Game/PerformFromMenuRunner.cs index eae13fe5d0..158350b43d 100644 --- a/osu.Game/PerformFromMenuRunner.cs +++ b/osu.Game/PerformFromMenuRunner.cs @@ -89,6 +89,10 @@ namespace osu.Game // check if we are already at a valid target screen. if (validScreens.Any(t => t.IsAssignableFrom(type))) { + if (!((Drawable)current).IsLoaded) + // wait until screen is loaded before invoking action. + return true; + finalAction(current); Cancel(); return true; From 8943819ee70d5e69e7b4c26b712af06067a3b206 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Nov 2022 17:49:03 +0300 Subject: [PATCH 2292/2686] Add test coverage --- .../Navigation/TestScenePerformFromScreen.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs index d1b1ce5c4b..ce0543875b 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs @@ -4,6 +4,7 @@ #nullable disable using System.Linq; +using System.Threading; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; @@ -85,6 +86,19 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("did perform", () => actionPerformed); } + [Test] + public void TestPerformEnsuresScreenIsLoaded() + { + TestLoadBlockingScreen screen = null; + + AddStep("push blocking screen", () => Game.ScreenStack.Push(screen = new TestLoadBlockingScreen())); + AddStep("perform", () => Game.PerformFromScreen(_ => actionPerformed = true, new[] { typeof(TestLoadBlockingScreen) })); + AddAssert("action not performed", () => !actionPerformed); + + AddStep("allow load", () => screen.LoadEvent.Set()); + AddUntilStep("action performed", () => actionPerformed); + } + [Test] public void TestOverlaysAlwaysClosed() { @@ -270,5 +284,16 @@ namespace osu.Game.Tests.Visual.Navigation return base.OnExiting(e); } } + + public class TestLoadBlockingScreen : OsuScreen + { + public readonly ManualResetEventSlim LoadEvent = new ManualResetEventSlim(); + + [BackgroundDependencyLoader] + private void load() + { + LoadEvent.Wait(10000); + } + } } } From d587f29351f64b1a2bbabf7dd82cbdba2374b2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 18 Nov 2022 21:02:23 +0100 Subject: [PATCH 2293/2686] Update tests to reflect desired behaviour --- .../Visual/Editing/TestSceneEditorTestGameplay.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs index 981967e413..ee6c322ee3 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs @@ -178,7 +178,7 @@ namespace osu.Game.Tests.Visual.Editing } [Test] - public void TestSharedClockState() + public void TestClockTimeTransferIsOneDirectional() { AddStep("seek to 00:01:00", () => EditorClock.Seek(60_000)); AddStep("click test gameplay button", () => @@ -195,15 +195,15 @@ namespace osu.Game.Tests.Visual.Editing GameplayClockContainer gameplayClockContainer = null; AddStep("fetch gameplay clock", () => gameplayClockContainer = editorPlayer.ChildrenOfType().First()); AddUntilStep("gameplay clock running", () => gameplayClockContainer.IsRunning); + // when the gameplay test is entered, the clock is expected to continue from where it was in the main editor... AddAssert("gameplay time past 00:01:00", () => gameplayClockContainer.CurrentTime >= 60_000); - double timeAtPlayerExit = 0; AddWaitStep("wait some", 5); - AddStep("store time before exit", () => timeAtPlayerExit = gameplayClockContainer.CurrentTime); AddStep("exit player", () => editorPlayer.Exit()); AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor); - AddAssert("time is past player exit", () => EditorClock.CurrentTime >= timeAtPlayerExit); + // but when exiting from gameplay test back to editor, the expectation is that the editor time should revert to what it was at the point of initiating the gameplay test. + AddAssert("time reverted to 00:01:00", () => EditorClock.CurrentTime, () => Is.EqualTo(60_000)); } public override void TearDownSteps() From e8ca9f5dc584eccf74370977db246788385535c0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 19 Nov 2022 00:19:49 +0300 Subject: [PATCH 2294/2686] Rework BarGraph to use Quads --- osu.Game/Graphics/UserInterface/Bar.cs | 12 +- osu.Game/Graphics/UserInterface/BarGraph.cs | 211 +++++++++++++++++--- 2 files changed, 188 insertions(+), 35 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/Bar.cs b/osu.Game/Graphics/UserInterface/Bar.cs index 3c87b166ac..e9a20761b3 100644 --- a/osu.Game/Graphics/UserInterface/Bar.cs +++ b/osu.Game/Graphics/UserInterface/Bar.cs @@ -109,15 +109,11 @@ namespace osu.Game.Graphics.UserInterface } } - [Flags] public enum BarDirection { - LeftToRight = 1, - RightToLeft = 1 << 1, - TopToBottom = 1 << 2, - BottomToTop = 1 << 3, - - Vertical = TopToBottom | BottomToTop, - Horizontal = LeftToRight | RightToLeft, + LeftToRight, + RightToLeft, + TopToBottom, + BottomToTop } } diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 2e9fd6734f..45eeba11d5 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -5,15 +5,23 @@ using osuTK; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using System.Collections.Generic; using System.Linq; -using osu.Framework.Extensions.EnumExtensions; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Textures; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Utils; +using System; namespace osu.Game.Graphics.UserInterface { - public class BarGraph : FillFlowContainer + public class BarGraph : Drawable { + private const int resize_duration = 250; + private const Easing easing = Easing.InOutCubic; + /// /// Manually sets the max value, if null is instead used /// @@ -21,22 +29,21 @@ namespace osu.Game.Graphics.UserInterface private BarDirection direction = BarDirection.BottomToTop; - public new BarDirection Direction + public BarDirection Direction { get => direction; set { - direction = value; - base.Direction = direction.HasFlagFast(BarDirection.Horizontal) ? FillDirection.Vertical : FillDirection.Horizontal; + if (direction == value) + return; - foreach (var bar in Children) - { - bar.Size = direction.HasFlagFast(BarDirection.Horizontal) ? new Vector2(1, 1.0f / Children.Count) : new Vector2(1.0f / Children.Count, 1); - bar.Direction = direction; - } + direction = value; + Invalidate(Invalidation.DrawNode); } } + private IEnumerable bars; + /// /// A list of floats that defines the length of each /// @@ -44,38 +51,188 @@ namespace osu.Game.Graphics.UserInterface { set { - List bars = Children.ToList(); + List newBars = bars?.ToList() ?? new List(); - foreach (var bar in value.Select((length, index) => new { Value = length, Bar = bars.Count > index ? bars[index] : null })) + int newCount = value.Count(); + + float size = newCount; + if (size != 0) + size = 1.0f / size; + + foreach (var bar in value.Select((length, index) => new { Value = length, Bar = newBars.Count > index ? newBars[index] : null })) { float length = MaxValue ?? value.Max(); if (length != 0) - length = bar.Value / length; - - float size = value.Count(); - if (size != 0) - size = 1.0f / size; + length = Math.Max(0f, bar.Value / length); if (bar.Bar != null) { - bar.Bar.Length = length; - bar.Bar.Size = direction.HasFlagFast(BarDirection.Horizontal) ? new Vector2(1, size) : new Vector2(size, 1); + bar.Bar.OldValue = bar.Bar.Value; + + bar.Bar.Value = length; + bar.Bar.ShortSide = size; } else { - Add(new Bar + newBars.Add(new BarDescriptor { - RelativeSizeAxes = Axes.Both, - Size = direction.HasFlagFast(BarDirection.Horizontal) ? new Vector2(1, size) : new Vector2(size, 1), - Length = length, - Direction = Direction, + Value = length, + ShortSide = size }); } } - //I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards - RemoveRange(Children.Where((_, index) => index >= value.Count()).ToList(), true); + if (newBars.Count > newCount) + newBars.RemoveRange(newCount, newBars.Count - newCount); + + bars = newBars; + + animationStartTime = Clock.CurrentTime; + animationComplete = false; } } + + private double animationStartTime; + private bool animationComplete; + + private IShader shader = null!; + private Texture texture = null!; + + [BackgroundDependencyLoader] + private void load(IRenderer renderer, ShaderManager shaders) + { + texture = renderer.WhitePixel; + shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE); + } + + protected override void Update() + { + base.Update(); + + if (noBars) + return; + + double currentTime = Clock.CurrentTime; + + if (currentTime < animationStartTime + resize_duration) + { + foreach (var bar in bars) + bar.IntermediateValue = Interpolation.ValueAt(currentTime, bar.OldValue, bar.Value, animationStartTime, animationStartTime + resize_duration, easing); + + Invalidate(Invalidation.DrawNode); + return; + } + else if (!animationComplete) + { + foreach (var bar in bars) + bar.IntermediateValue = bar.Value; + + Invalidate(Invalidation.DrawNode); + + animationComplete = true; + return; + } + } + + private bool noBars => bars?.Any() != true; + + protected override DrawNode CreateDrawNode() => new BarGraphDrawNode(this); + + private class BarGraphDrawNode : DrawNode + { + public new BarGraph Source => (BarGraph)base.Source; + + public BarGraphDrawNode(BarGraph source) + : base(source) + { + } + + private IShader shader = null!; + private Texture texture = null!; + private Vector2 drawSize; + private BarDirection direction; + + private readonly List bars = new List(); + + public override void ApplyState() + { + base.ApplyState(); + + shader = Source.shader; + texture = Source.texture; + drawSize = Source.DrawSize; + direction = Source.direction; + + bars.Clear(); + + if (Source.noBars) + return; + + bars.AddRange(Source.bars); + } + + public override void Draw(IRenderer renderer) + { + base.Draw(renderer); + + if (!bars.Any()) + return; + + shader.Bind(); + + for (int i = 0; i < bars.Count; i++) + { + var bar = bars[i]; + + float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? bar.IntermediateValue : bar.ShortSide); + float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? bar.IntermediateValue : bar.ShortSide); + + Vector2 topLeft; + + switch (direction) + { + default: + case BarDirection.LeftToRight: + topLeft = new Vector2(0, i * barHeight); + break; + + case BarDirection.RightToLeft: + topLeft = new Vector2(drawSize.X - barWidth, i * barHeight); + break; + + case BarDirection.TopToBottom: + topLeft = new Vector2(i * barWidth, 0); + break; + + case BarDirection.BottomToTop: + topLeft = new Vector2(i * barWidth, drawSize.Y - barHeight); + break; + } + + Vector2 topRight = topLeft + new Vector2(barWidth, 0); + Vector2 bottomLeft = topLeft + new Vector2(0, barHeight); + Vector2 bottomRight = bottomLeft + new Vector2(barWidth, 0); + + var drawQuad = new Quad( + Vector2Extensions.Transform(topLeft, DrawInfo.Matrix), + Vector2Extensions.Transform(topRight, DrawInfo.Matrix), + Vector2Extensions.Transform(bottomLeft, DrawInfo.Matrix), + Vector2Extensions.Transform(bottomRight, DrawInfo.Matrix) + ); + + renderer.DrawQuad(texture, drawQuad, DrawColourInfo.Colour); + } + + shader.Unbind(); + } + } + + private class BarDescriptor + { + public float OldValue { get; set; } + public float Value { get; set; } + public float IntermediateValue { get; set; } + public float ShortSide { get; set; } + } } } From 016de2f5a03b34395eb0c71eae5660f42566952c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Nov 2022 05:07:10 +0300 Subject: [PATCH 2295/2686] Fix editor not always playing hitsounds with clock offsets applied --- osu.Game/Screens/Edit/EditorClock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index 81d82130da..f83874e4a0 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -270,7 +270,7 @@ namespace osu.Game.Screens.Edit { IsSeeking &= Transforms.Any(); - if (track.Value?.IsRunning != true) + if (!IsRunning) { // seeking in the editor can happen while the track isn't running. // in this case we always want to expose ourselves as seeking (to avoid sample playback). From 290369db47ab44f24b01e5db3cce97f045f57ddf Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Nov 2022 06:40:20 +0300 Subject: [PATCH 2296/2686] Hide scroll speed slider on rulesets which don't support it --- osu.Game/Screens/Edit/Timing/EffectSection.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Edit/Timing/EffectSection.cs b/osu.Game/Screens/Edit/Timing/EffectSection.cs index f7e59a75f1..9ba3634311 100644 --- a/osu.Game/Screens/Edit/Timing/EffectSection.cs +++ b/osu.Game/Screens/Edit/Timing/EffectSection.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Screens.Edit.Timing { @@ -41,6 +42,12 @@ namespace osu.Game.Screens.Edit.Timing omitBarLine.Current.BindValueChanged(_ => saveChanges()); scrollSpeedSlider.Current.BindValueChanged(_ => saveChanges()); + // adjusting scroll speed on osu/catch rulesets results in undefined behaviour during legacy beatmap decoding, and generally shouldn't be shown. + // todo: there should be proper way to identify such rulesets, but this should do for now. + var ruleset = Beatmap.BeatmapInfo.Ruleset; + if (ruleset.OnlineID == 0 || ruleset.OnlineID == 2) + scrollSpeedSlider.Hide(); + void saveChanges() { if (!isRebinding) ChangeHandler?.SaveState(); From ca67689a36339a8be554e39d017367873e244017 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Nov 2022 07:44:28 +0300 Subject: [PATCH 2297/2686] Fix intermittent present beatmap test failures --- .../Navigation/TestScenePresentBeatmap.cs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs index 6469962b08..02b348b439 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs @@ -7,12 +7,14 @@ using System; using System.Linq; using NUnit.Framework; using osu.Framework.Screens; +using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Extensions; using osu.Game.Rulesets; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Menu; +using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.Navigation { @@ -55,6 +57,7 @@ namespace osu.Game.Tests.Visual.Navigation presentAndConfirm(firstImport); var secondImport = importBeatmap(3); + confirmBeatmapInSongSelect(secondImport); presentAndConfirm(secondImport); // Test presenting same beatmap more than once @@ -74,6 +77,7 @@ namespace osu.Game.Tests.Visual.Navigation presentAndConfirm(firstImport); var secondImport = importBeatmap(3, new ManiaRuleset().RulesetInfo); + confirmBeatmapInSongSelect(secondImport); presentAndConfirm(secondImport); presentSecondDifficultyAndConfirm(firstImport, 1); @@ -134,13 +138,22 @@ namespace osu.Game.Tests.Visual.Navigation return () => imported; } + private void confirmBeatmapInSongSelect(Func getImport) + { + AddUntilStep("beatmap in song select", () => + { + var songSelect = (Screens.Select.SongSelect)Game.ScreenStack.CurrentScreen; + return songSelect.ChildrenOfType().Single().BeatmapSets.Any(b => b.MatchesOnlineID(getImport())); + }); + } + private void presentAndConfirm(Func getImport) { AddStep("present beatmap", () => Game.PresentBeatmap(getImport())); - AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect); - AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.MatchesOnlineID(getImport())); - AddAssert("correct ruleset selected", () => Game.Ruleset.Value.Equals(getImport().Beatmaps.First().Ruleset)); + AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect songSelect && songSelect.IsLoaded); + AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.OnlineID, () => Is.EqualTo(getImport().OnlineID)); + AddAssert("correct ruleset selected", () => Game.Ruleset.Value, () => Is.EqualTo(getImport().Beatmaps.First().Ruleset)); } private void presentSecondDifficultyAndConfirm(Func getImport, int importedID) @@ -148,9 +161,9 @@ namespace osu.Game.Tests.Visual.Navigation Predicate pred = b => b.OnlineID == importedID * 2048; AddStep("present difficulty", () => Game.PresentBeatmap(getImport(), pred)); - AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect); - AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineID == importedID * 2048); - AddAssert("correct ruleset selected", () => Game.Ruleset.Value.Equals(getImport().Beatmaps.First().Ruleset)); + AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect songSelect && songSelect.IsLoaded); + AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineID, () => Is.EqualTo(importedID * 2048)); + AddAssert("correct ruleset selected", () => Game.Ruleset.Value, () => Is.EqualTo(getImport().Beatmaps.First().Ruleset)); } } } From 11f5fddc1f4a803ac3f737b7c628730d9ee23359 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 19 Nov 2022 09:57:52 +0300 Subject: [PATCH 2298/2686] Remove redundant returns --- osu.Game/Graphics/UserInterface/BarGraph.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 45eeba11d5..b82911ea56 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -120,7 +120,6 @@ namespace osu.Game.Graphics.UserInterface bar.IntermediateValue = Interpolation.ValueAt(currentTime, bar.OldValue, bar.Value, animationStartTime, animationStartTime + resize_duration, easing); Invalidate(Invalidation.DrawNode); - return; } else if (!animationComplete) { @@ -130,7 +129,6 @@ namespace osu.Game.Graphics.UserInterface Invalidate(Invalidation.DrawNode); animationComplete = true; - return; } } From 9b8f98735cdc642ab7ea5d050bab9f96e77de491 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 19 Nov 2022 10:16:58 +0300 Subject: [PATCH 2299/2686] Use struct for bars description --- osu.Game/Graphics/UserInterface/BarGraph.cs | 55 +++++++++++---------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index b82911ea56..efc5eace0d 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -42,7 +42,7 @@ namespace osu.Game.Graphics.UserInterface } } - private IEnumerable bars; + private readonly List bars = new List(); /// /// A list of floats that defines the length of each @@ -51,30 +51,31 @@ namespace osu.Game.Graphics.UserInterface { set { - List newBars = bars?.ToList() ?? new List(); - int newCount = value.Count(); float size = newCount; if (size != 0) size = 1.0f / size; - foreach (var bar in value.Select((length, index) => new { Value = length, Bar = newBars.Count > index ? newBars[index] : null })) + float maxLength = MaxValue ?? value.Max(); + + foreach (var bar in value.Select((length, index) => new { Value = length, Index = index })) { - float length = MaxValue ?? value.Max(); - if (length != 0) - length = Math.Max(0f, bar.Value / length); + float length = maxLength == 0 ? 0 : Math.Max(0f, bar.Value / maxLength); - if (bar.Bar != null) + if (bar.Index < bars.Count) { - bar.Bar.OldValue = bar.Bar.Value; + BarStruct b = bars[bar.Index]; - bar.Bar.Value = length; - bar.Bar.ShortSide = size; + b.OldValue = b.Value; + b.Value = length; + b.ShortSide = size; + + bars[bar.Index] = b; } else { - newBars.Add(new BarDescriptor + bars.Add(new BarStruct { Value = length, ShortSide = size @@ -82,10 +83,8 @@ namespace osu.Game.Graphics.UserInterface } } - if (newBars.Count > newCount) - newBars.RemoveRange(newCount, newBars.Count - newCount); - - bars = newBars; + if (bars.Count > newCount) + bars.RemoveRange(newCount, bars.Count - newCount); animationStartTime = Clock.CurrentTime; animationComplete = false; @@ -109,22 +108,30 @@ namespace osu.Game.Graphics.UserInterface { base.Update(); - if (noBars) + if (!bars.Any()) return; double currentTime = Clock.CurrentTime; if (currentTime < animationStartTime + resize_duration) { - foreach (var bar in bars) + for (int i = 0; i < bars.Count(); i++) + { + BarStruct bar = bars[i]; bar.IntermediateValue = Interpolation.ValueAt(currentTime, bar.OldValue, bar.Value, animationStartTime, animationStartTime + resize_duration, easing); + bars[i] = bar; + } Invalidate(Invalidation.DrawNode); } else if (!animationComplete) { - foreach (var bar in bars) + for (int i = 0; i < bars.Count(); i++) + { + BarStruct bar = bars[i]; bar.IntermediateValue = bar.Value; + bars[i] = bar; + } Invalidate(Invalidation.DrawNode); @@ -132,8 +139,6 @@ namespace osu.Game.Graphics.UserInterface } } - private bool noBars => bars?.Any() != true; - protected override DrawNode CreateDrawNode() => new BarGraphDrawNode(this); private class BarGraphDrawNode : DrawNode @@ -150,7 +155,7 @@ namespace osu.Game.Graphics.UserInterface private Vector2 drawSize; private BarDirection direction; - private readonly List bars = new List(); + private readonly List bars = new List(); public override void ApplyState() { @@ -162,10 +167,6 @@ namespace osu.Game.Graphics.UserInterface direction = Source.direction; bars.Clear(); - - if (Source.noBars) - return; - bars.AddRange(Source.bars); } @@ -225,7 +226,7 @@ namespace osu.Game.Graphics.UserInterface } } - private class BarDescriptor + private struct BarStruct { public float OldValue { get; set; } public float Value { get; set; } From 05992d3aa8eabf806e2fdcf2074effd819719cf2 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 19 Nov 2022 10:23:37 +0300 Subject: [PATCH 2300/2686] CI fix --- osu.Game/Graphics/UserInterface/BarGraph.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index efc5eace0d..8552c2196c 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -115,7 +115,7 @@ namespace osu.Game.Graphics.UserInterface if (currentTime < animationStartTime + resize_duration) { - for (int i = 0; i < bars.Count(); i++) + for (int i = 0; i < bars.Count; i++) { BarStruct bar = bars[i]; bar.IntermediateValue = Interpolation.ValueAt(currentTime, bar.OldValue, bar.Value, animationStartTime, animationStartTime + resize_duration, easing); @@ -126,7 +126,7 @@ namespace osu.Game.Graphics.UserInterface } else if (!animationComplete) { - for (int i = 0; i < bars.Count(); i++) + for (int i = 0; i < bars.Count; i++) { BarStruct bar = bars[i]; bar.IntermediateValue = bar.Value; From 0239103b6b0f24b6b5d956794be01575d3d1a7ed Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 19 Nov 2022 11:33:14 +0300 Subject: [PATCH 2301/2686] Fix BeatmapOverlay crashing test scene --- osu.Game/Graphics/UserInterface/BarGraph.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 8552c2196c..56a2a4f579 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -57,7 +57,7 @@ namespace osu.Game.Graphics.UserInterface if (size != 0) size = 1.0f / size; - float maxLength = MaxValue ?? value.Max(); + float maxLength = MaxValue ?? (newCount == 0 ? 0 : value.Max()); foreach (var bar in value.Select((length, index) => new { Value = length, Index = index })) { From 2e3af97892906e02abb53fc7417570ae92c919a3 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 19 Nov 2022 12:13:36 +0300 Subject: [PATCH 2302/2686] Remove unused using --- osu.Game/Screens/Edit/Timing/EffectSection.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/EffectSection.cs b/osu.Game/Screens/Edit/Timing/EffectSection.cs index 9ba3634311..8d12317ee9 100644 --- a/osu.Game/Screens/Edit/Timing/EffectSection.cs +++ b/osu.Game/Screens/Edit/Timing/EffectSection.cs @@ -8,7 +8,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Screens.Edit.Timing { From eff6c7be6499aecd6ecf7bfb3faf999334b04d41 Mon Sep 17 00:00:00 2001 From: Terochi Date: Sat, 19 Nov 2022 16:53:35 +0100 Subject: [PATCH 2303/2686] Removed unnecessary methods, changed tests, and moved LimitedCapacityQueue.cs to a more generic namespace. --- .../Difficulty/Skills/Rhythm.cs | 2 +- .../NonVisual/LimitedCapacityQueueTest.cs | 2 +- .../UserInterface/TestSceneHistoryTextBox.cs | 24 ++----------------- .../Graphics/UserInterface/HistoryTextBox.cs | 14 +---------- .../Utils/LimitedCapacityQueue.cs | 2 +- 5 files changed, 6 insertions(+), 38 deletions(-) rename osu.Game/{Rulesets/Difficulty => }/Utils/LimitedCapacityQueue.cs (98%) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs index 4a2b97a4cb..ff187a133a 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs @@ -6,10 +6,10 @@ using System; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; -using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Utils; namespace osu.Game.Rulesets.Taiko.Difficulty.Skills { diff --git a/osu.Game.Tests/NonVisual/LimitedCapacityQueueTest.cs b/osu.Game.Tests/NonVisual/LimitedCapacityQueueTest.cs index 8cd26901c5..8809ce3adc 100644 --- a/osu.Game.Tests/NonVisual/LimitedCapacityQueueTest.cs +++ b/osu.Game.Tests/NonVisual/LimitedCapacityQueueTest.cs @@ -5,7 +5,7 @@ using System; using NUnit.Framework; -using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Utils; namespace osu.Game.Tests.NonVisual { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs index 862777c500..8918e53056 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Input; @@ -21,8 +18,8 @@ namespace osu.Game.Tests.Visual.UserInterface private int messageCounter; - private HistoryTextBox box; - private OsuSpriteText text; + private HistoryTextBox box = null!; + private OsuSpriteText text = null!; [SetUp] public void SetUp() @@ -70,7 +67,6 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestEmptyHistory() { AddStep("Set text", () => box.Text = temp); - AddAssert("History is empty", () => !box.GetMessageHistory().Any()); AddStep("Move down", () => InputManager.Key(Key.Down)); AddAssert("Text is the same", () => box.Text == temp); @@ -106,16 +102,12 @@ namespace osu.Game.Tests.Visual.UserInterface { addMessages(5); AddStep("Set text", () => box.Text = temp); - AddAssert("History saved as <5-1>", () => - Enumerable.Range(0, 5).Select(number => $"Message {5 - number}").SequenceEqual(box.GetMessageHistory())); AddStep("Move down", () => InputManager.Key(Key.Down)); AddAssert("Text is the same", () => box.Text == temp); addMessages(2); AddStep("Set text", () => box.Text = temp); - AddAssert("Overrode history to <7-3>", () => - Enumerable.Range(0, 5).Select(number => $"Message {7 - number}").SequenceEqual(box.GetMessageHistory())); AddRepeatStep("Move Up", () => InputManager.Key(Key.Up), 5); AddAssert("Same as 3rd message", () => box.Text == "Message 3"); @@ -130,18 +122,6 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("Same as temp message", () => box.Text == temp); } - [Test] - public void TestOverrideFullHistory() - { - addMessages(5); - AddAssert("History saved as <5-1>", () => - Enumerable.Range(0, 5).Select(number => $"Message {5 - number}").SequenceEqual(box.GetMessageHistory())); - - addMessages(6); - AddAssert("Overrode history to <11-7>", () => - Enumerable.Range(0, 5).Select(number => $"Message {11 - number}").SequenceEqual(box.GetMessageHistory())); - } - [Test] public void TestResetIndex() { diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index 17858ea16d..e9da67e553 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -1,9 +1,8 @@ // 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 osu.Framework.Input.Events; -using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Utils; using osuTK.Input; namespace osu.Game.Graphics.UserInterface @@ -12,15 +11,6 @@ namespace osu.Game.Graphics.UserInterface { private readonly LimitedCapacityQueue messageHistory; - public IEnumerable GetMessageHistory() - { - if (HistoryCount == 0) - yield break; - - for (int i = HistoryCount - 1; i >= 0; i--) - yield return messageHistory[i]; - } - public int HistoryCount => messageHistory.Count; private int selectedIndex; @@ -28,8 +18,6 @@ namespace osu.Game.Graphics.UserInterface private string originalMessage = string.Empty; private bool everythingSelected; - public string GetOldMessage(int index) => messageHistory[HistoryCount - index - 1]; - public HistoryTextBox(int capacity = 100) { messageHistory = new LimitedCapacityQueue(capacity); diff --git a/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityQueue.cs b/osu.Game/Utils/LimitedCapacityQueue.cs similarity index 98% rename from osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityQueue.cs rename to osu.Game/Utils/LimitedCapacityQueue.cs index d20eb5e885..86a106a678 100644 --- a/osu.Game/Rulesets/Difficulty/Utils/LimitedCapacityQueue.cs +++ b/osu.Game/Utils/LimitedCapacityQueue.cs @@ -7,7 +7,7 @@ using System; using System.Collections; using System.Collections.Generic; -namespace osu.Game.Rulesets.Difficulty.Utils +namespace osu.Game.Utils { /// /// An indexed queue with limited capacity. From 6f449a583e57230e3af26dd8d40ab6051dc036b9 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 19 Nov 2022 23:27:48 +0300 Subject: [PATCH 2304/2686] Handle empty values as a separate case --- osu.Game.Tests/Visual/Online/TestSceneGraph.cs | 2 ++ osu.Game/Graphics/UserInterface/BarGraph.cs | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneGraph.cs index 2f3331b141..8b0536651d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneGraph.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneGraph.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; @@ -32,6 +33,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("values from 1-10", () => graph.Values = Enumerable.Range(1, 10).Select(i => (float)i)); AddStep("values from 1-100", () => graph.Values = Enumerable.Range(1, 100).Select(i => (float)i)); AddStep("reversed values from 1-10", () => graph.Values = Enumerable.Range(1, 10).Reverse().Select(i => (float)i)); + AddStep("empty values", () => graph.Values = Array.Empty()); AddStep("Bottom to top", () => graph.Direction = BarDirection.BottomToTop); AddStep("Top to bottom", () => graph.Direction = BarDirection.TopToBottom); AddStep("Left to right", () => graph.Direction = BarDirection.LeftToRight); diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 56a2a4f579..c9bffc605e 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -51,13 +51,18 @@ namespace osu.Game.Graphics.UserInterface { set { + if (!value.Any()) + { + bars.Clear(); + Invalidate(Invalidation.DrawNode); + return; + } + int newCount = value.Count(); - float size = newCount; - if (size != 0) - size = 1.0f / size; + float size = 1.0f / newCount; - float maxLength = MaxValue ?? (newCount == 0 ? 0 : value.Max()); + float maxLength = MaxValue ?? value.Max(); foreach (var bar in value.Select((length, index) => new { Value = length, Index = index })) { From f1201454b723cf9f00df4729d0390adecaa0da84 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 19 Nov 2022 23:29:50 +0300 Subject: [PATCH 2305/2686] Use value tuples --- osu.Game/Graphics/UserInterface/BarGraph.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index c9bffc605e..f2352c91da 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -64,7 +64,7 @@ namespace osu.Game.Graphics.UserInterface float maxLength = MaxValue ?? value.Max(); - foreach (var bar in value.Select((length, index) => new { Value = length, Index = index })) + foreach (var bar in value.Select((length, index) => (Value: length, Index: index))) { float length = maxLength == 0 ? 0 : Math.Max(0f, bar.Value / maxLength); From 67ee9f39154dae692caa3c96d8a5b7cfb1fc5643 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 19 Nov 2022 23:34:55 +0300 Subject: [PATCH 2306/2686] Naming adjustments --- osu.Game/Graphics/UserInterface/BarGraph.cs | 40 ++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index f2352c91da..661057cbde 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -42,7 +42,7 @@ namespace osu.Game.Graphics.UserInterface } } - private readonly List bars = new List(); + private readonly List bars = new List(); /// /// A list of floats that defines the length of each @@ -70,20 +70,20 @@ namespace osu.Game.Graphics.UserInterface if (bar.Index < bars.Count) { - BarStruct b = bars[bar.Index]; + BarInfo b = bars[bar.Index]; - b.OldValue = b.Value; - b.Value = length; - b.ShortSide = size; + b.InitialLength = b.FinalLength; + b.FinalLength = length; + b.Breadth = size; bars[bar.Index] = b; } else { - bars.Add(new BarStruct + bars.Add(new BarInfo { - Value = length, - ShortSide = size + FinalLength = length, + Breadth = size }); } } @@ -122,8 +122,8 @@ namespace osu.Game.Graphics.UserInterface { for (int i = 0; i < bars.Count; i++) { - BarStruct bar = bars[i]; - bar.IntermediateValue = Interpolation.ValueAt(currentTime, bar.OldValue, bar.Value, animationStartTime, animationStartTime + resize_duration, easing); + BarInfo bar = bars[i]; + bar.InstantaneousLength = Interpolation.ValueAt(currentTime, bar.InitialLength, bar.FinalLength, animationStartTime, animationStartTime + resize_duration, easing); bars[i] = bar; } @@ -133,8 +133,8 @@ namespace osu.Game.Graphics.UserInterface { for (int i = 0; i < bars.Count; i++) { - BarStruct bar = bars[i]; - bar.IntermediateValue = bar.Value; + BarInfo bar = bars[i]; + bar.InstantaneousLength = bar.FinalLength; bars[i] = bar; } @@ -160,7 +160,7 @@ namespace osu.Game.Graphics.UserInterface private Vector2 drawSize; private BarDirection direction; - private readonly List bars = new List(); + private readonly List bars = new List(); public override void ApplyState() { @@ -188,8 +188,8 @@ namespace osu.Game.Graphics.UserInterface { var bar = bars[i]; - float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? bar.IntermediateValue : bar.ShortSide); - float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? bar.IntermediateValue : bar.ShortSide); + float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? bar.InstantaneousLength : bar.Breadth); + float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? bar.InstantaneousLength : bar.Breadth); Vector2 topLeft; @@ -231,12 +231,12 @@ namespace osu.Game.Graphics.UserInterface } } - private struct BarStruct + private struct BarInfo { - public float OldValue { get; set; } - public float Value { get; set; } - public float IntermediateValue { get; set; } - public float ShortSide { get; set; } + public float InitialLength { get; set; } + public float FinalLength { get; set; } + public float InstantaneousLength { get; set; } + public float Breadth { get; set; } } } } From 6c62cfb8301e5e6f29f64a17ec0323d5a23caca0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 19 Nov 2022 23:40:02 +0300 Subject: [PATCH 2307/2686] Store barBreadth as a separate float --- osu.Game/Graphics/UserInterface/BarGraph.cs | 22 +++++++++------------ 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 661057cbde..404b925372 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -43,6 +43,7 @@ namespace osu.Game.Graphics.UserInterface } private readonly List bars = new List(); + private float barBreadth; /// /// A list of floats that defines the length of each @@ -60,7 +61,7 @@ namespace osu.Game.Graphics.UserInterface int newCount = value.Count(); - float size = 1.0f / newCount; + barBreadth = 1.0f / newCount; float maxLength = MaxValue ?? value.Max(); @@ -74,18 +75,12 @@ namespace osu.Game.Graphics.UserInterface b.InitialLength = b.FinalLength; b.FinalLength = length; - b.Breadth = size; bars[bar.Index] = b; + continue; } - else - { - bars.Add(new BarInfo - { - FinalLength = length, - Breadth = size - }); - } + + bars.Add(new BarInfo { FinalLength = length }); } if (bars.Count > newCount) @@ -159,6 +154,7 @@ namespace osu.Game.Graphics.UserInterface private Texture texture = null!; private Vector2 drawSize; private BarDirection direction; + private float barBreadth; private readonly List bars = new List(); @@ -170,6 +166,7 @@ namespace osu.Game.Graphics.UserInterface texture = Source.texture; drawSize = Source.DrawSize; direction = Source.direction; + barBreadth = Source.barBreadth; bars.Clear(); bars.AddRange(Source.bars); @@ -188,8 +185,8 @@ namespace osu.Game.Graphics.UserInterface { var bar = bars[i]; - float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? bar.InstantaneousLength : bar.Breadth); - float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? bar.InstantaneousLength : bar.Breadth); + float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? bar.InstantaneousLength : barBreadth); + float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? bar.InstantaneousLength : barBreadth); Vector2 topLeft; @@ -236,7 +233,6 @@ namespace osu.Game.Graphics.UserInterface public float InitialLength { get; set; } public float FinalLength { get; set; } public float InstantaneousLength { get; set; } - public float Breadth { get; set; } } } } From 2cb966b47cad8127fb828fb440698cb9724a6c97 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 20 Nov 2022 01:20:57 +0300 Subject: [PATCH 2308/2686] Rework BarsInfo struct --- osu.Game/Graphics/UserInterface/BarGraph.cs | 134 ++++++++++++-------- 1 file changed, 83 insertions(+), 51 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 404b925372..6df0302d1c 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -42,7 +42,8 @@ namespace osu.Game.Graphics.UserInterface } } - private readonly List bars = new List(); + private readonly BarsInfo bars = new BarsInfo(0); + private float barBreadth; /// @@ -71,16 +72,11 @@ namespace osu.Game.Graphics.UserInterface if (bar.Index < bars.Count) { - BarInfo b = bars[bar.Index]; - - b.InitialLength = b.FinalLength; - b.FinalLength = length; - - bars[bar.Index] = b; + bars.UpdateLength(bar.Index, length); continue; } - bars.Add(new BarInfo { FinalLength = length }); + bars.AddBar(length); } if (bars.Count > newCount) @@ -108,31 +104,19 @@ namespace osu.Game.Graphics.UserInterface { base.Update(); - if (!bars.Any()) + if (!bars.Any) return; double currentTime = Clock.CurrentTime; if (currentTime < animationStartTime + resize_duration) { - for (int i = 0; i < bars.Count; i++) - { - BarInfo bar = bars[i]; - bar.InstantaneousLength = Interpolation.ValueAt(currentTime, bar.InitialLength, bar.FinalLength, animationStartTime, animationStartTime + resize_duration, easing); - bars[i] = bar; - } - + bars.Animate(animationStartTime, currentTime); Invalidate(Invalidation.DrawNode); } else if (!animationComplete) { - for (int i = 0; i < bars.Count; i++) - { - BarInfo bar = bars[i]; - bar.InstantaneousLength = bar.FinalLength; - bars[i] = bar; - } - + bars.FinishAnimation(); Invalidate(Invalidation.DrawNode); animationComplete = true; @@ -155,8 +139,7 @@ namespace osu.Game.Graphics.UserInterface private Vector2 drawSize; private BarDirection direction; private float barBreadth; - - private readonly List bars = new List(); + private BarsInfo bars; public override void ApplyState() { @@ -167,26 +150,19 @@ namespace osu.Game.Graphics.UserInterface drawSize = Source.DrawSize; direction = Source.direction; barBreadth = Source.barBreadth; - - bars.Clear(); - bars.AddRange(Source.bars); + bars = Source.bars; } public override void Draw(IRenderer renderer) { base.Draw(renderer); - if (!bars.Any()) - return; - shader.Bind(); for (int i = 0; i < bars.Count; i++) { - var bar = bars[i]; - - float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? bar.InstantaneousLength : barBreadth); - float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? bar.InstantaneousLength : barBreadth); + float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? bars.InstantaneousLength(i) : barBreadth); + float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? bars.InstantaneousLength(i) : barBreadth); Vector2 topLeft; @@ -210,29 +186,85 @@ namespace osu.Game.Graphics.UserInterface break; } - Vector2 topRight = topLeft + new Vector2(barWidth, 0); - Vector2 bottomLeft = topLeft + new Vector2(0, barHeight); - Vector2 bottomRight = bottomLeft + new Vector2(barWidth, 0); - - var drawQuad = new Quad( - Vector2Extensions.Transform(topLeft, DrawInfo.Matrix), - Vector2Extensions.Transform(topRight, DrawInfo.Matrix), - Vector2Extensions.Transform(bottomLeft, DrawInfo.Matrix), - Vector2Extensions.Transform(bottomRight, DrawInfo.Matrix) - ); - - renderer.DrawQuad(texture, drawQuad, DrawColourInfo.Colour); + renderer.DrawQuad( + texture, + new Quad( + Vector2Extensions.Transform(topLeft, DrawInfo.Matrix), + Vector2Extensions.Transform(topLeft + new Vector2(barWidth, 0), DrawInfo.Matrix), + Vector2Extensions.Transform(topLeft + new Vector2(0, barHeight), DrawInfo.Matrix), + Vector2Extensions.Transform(topLeft + new Vector2(barWidth, barHeight), DrawInfo.Matrix) + ), + DrawColourInfo.Colour); } shader.Unbind(); } } - private struct BarInfo + private struct BarsInfo { - public float InitialLength { get; set; } - public float FinalLength { get; set; } - public float InstantaneousLength { get; set; } + private readonly List initialLengths; + private readonly List finalLengths; + private readonly List instantaneousLengths; + + public bool Any => initialLengths.Any(); + + public int Count => initialLengths.Count; + + public BarsInfo(int initialCount) + { + initialLengths = new List(); + finalLengths = new List(); + instantaneousLengths = new List(); + + for (int i = 0; i < initialCount; i++) + { + initialLengths.Add(0); + finalLengths.Add(0); + instantaneousLengths.Add(0); + } + } + + public float InstantaneousLength(int index) => instantaneousLengths[index]; + + public void UpdateLength(int index, float newLength) + { + initialLengths[index] = finalLengths[index]; + finalLengths[index] = newLength; + } + + public void AddBar(float finalLength) + { + initialLengths.Add(0); + finalLengths.Add(finalLength); + instantaneousLengths.Add(0); + } + + public void Clear() + { + initialLengths.Clear(); + finalLengths.Clear(); + instantaneousLengths.Clear(); + } + + public void RemoveRange(int index, int count) + { + initialLengths.RemoveRange(index, count); + finalLengths.RemoveRange(index, count); + instantaneousLengths.RemoveRange(index, count); + } + + public void Animate(double animationStartTime, double currentTime) + { + for (int i = 0; i < Count; i++) + instantaneousLengths[i] = Interpolation.ValueAt(currentTime, initialLengths[i], finalLengths[i], animationStartTime, animationStartTime + resize_duration, easing); + } + + public void FinishAnimation() + { + for (int i = 0; i < Count; i++) + instantaneousLengths[i] = finalLengths[i]; + } } } } From fbfcf49ea6cc7c1639887fc5669da01493ea5d3c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 20 Nov 2022 02:13:54 +0300 Subject: [PATCH 2309/2686] Remove readonly modifier from struct fields --- osu.Game/Graphics/UserInterface/BarGraph.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 6df0302d1c..4e1d708531 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -203,9 +203,9 @@ namespace osu.Game.Graphics.UserInterface private struct BarsInfo { - private readonly List initialLengths; - private readonly List finalLengths; - private readonly List instantaneousLengths; + private List initialLengths; + private List finalLengths; + private List instantaneousLengths; public bool Any => initialLengths.Any(); From fcb52ee237ad57a57beb949304d85e640f4ac53e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 20 Nov 2022 02:28:07 +0300 Subject: [PATCH 2310/2686] Make BarsInfo a readonly struct --- osu.Game/Graphics/UserInterface/BarGraph.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 4e1d708531..50c634455b 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -42,7 +42,7 @@ namespace osu.Game.Graphics.UserInterface } } - private readonly BarsInfo bars = new BarsInfo(0); + private BarsInfo bars = new BarsInfo(0); private float barBreadth; @@ -201,11 +201,11 @@ namespace osu.Game.Graphics.UserInterface } } - private struct BarsInfo + private readonly struct BarsInfo { - private List initialLengths; - private List finalLengths; - private List instantaneousLengths; + private readonly List initialLengths; + private readonly List finalLengths; + private readonly List instantaneousLengths; public bool Any => initialLengths.Any(); From 58296bd4f007bcae3bf485583a7bff9cb07046ed Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Nov 2022 04:11:09 +0300 Subject: [PATCH 2311/2686] Introduce `IDrawableScrollingRuleset` for editor consumption --- .../UI/Scrolling/DrawableScrollingRuleset.cs | 4 +++- .../UI/Scrolling/IDrawableScrollingRuleset.cs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 68469d083c..2cb57966e7 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// A type of that supports a . /// s inside this will scroll within the playfield. /// - public abstract class DrawableScrollingRuleset : DrawableRuleset, IKeyBindingHandler + public abstract class DrawableScrollingRuleset : DrawableRuleset, IDrawableScrollingRuleset, IKeyBindingHandler where TObject : HitObject { /// @@ -66,6 +66,8 @@ namespace osu.Game.Rulesets.UI.Scrolling protected virtual ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Sequential; + ScrollVisualisationMethod IDrawableScrollingRuleset.VisualisationMethod => VisualisationMethod; + /// /// Whether the player can change . /// diff --git a/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs new file mode 100644 index 0000000000..6955ef26e5 --- /dev/null +++ b/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable +using osu.Game.Configuration; + +namespace osu.Game.Rulesets.UI.Scrolling +{ + /// + /// An interface for scrolling-based s. + /// + public interface IDrawableScrollingRuleset + { + ScrollVisualisationMethod VisualisationMethod { get; } + } +} From 4b0ba86bd0488c3a1b58f3b5fbf51dcf731ad142 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Nov 2022 04:12:50 +0300 Subject: [PATCH 2312/2686] Identify scrolling rulesets using temporary `DrawableRuleset` instances --- osu.Game/Screens/Edit/Timing/EffectSection.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/EffectSection.cs b/osu.Game/Screens/Edit/Timing/EffectSection.cs index 8d12317ee9..9be663bb26 100644 --- a/osu.Game/Screens/Edit/Timing/EffectSection.cs +++ b/osu.Game/Screens/Edit/Timing/EffectSection.cs @@ -7,7 +7,9 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Screens.Edit.Timing { @@ -41,10 +43,8 @@ namespace osu.Game.Screens.Edit.Timing omitBarLine.Current.BindValueChanged(_ => saveChanges()); scrollSpeedSlider.Current.BindValueChanged(_ => saveChanges()); - // adjusting scroll speed on osu/catch rulesets results in undefined behaviour during legacy beatmap decoding, and generally shouldn't be shown. - // todo: there should be proper way to identify such rulesets, but this should do for now. - var ruleset = Beatmap.BeatmapInfo.Ruleset; - if (ruleset.OnlineID == 0 || ruleset.OnlineID == 2) + var drawableRuleset = Beatmap.BeatmapInfo.Ruleset.CreateInstance().CreateDrawableRulesetWith(Beatmap.PlayableBeatmap); + if (drawableRuleset is not IDrawableScrollingRuleset scrollingRuleset || scrollingRuleset.VisualisationMethod == ScrollVisualisationMethod.Constant) scrollSpeedSlider.Hide(); void saveChanges() From 36141cb2a4ef2452879cd2932aade19668f8fb35 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 20 Nov 2022 05:14:07 +0300 Subject: [PATCH 2313/2686] Make BarsInfo a class --- osu.Game/Graphics/UserInterface/BarGraph.cs | 64 ++++++++++----------- 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 50c634455b..498a480c06 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -42,9 +42,7 @@ namespace osu.Game.Graphics.UserInterface } } - private BarsInfo bars = new BarsInfo(0); - - private float barBreadth; + private readonly BarsInfo bars = new BarsInfo(); /// /// A list of floats that defines the length of each @@ -62,7 +60,7 @@ namespace osu.Game.Graphics.UserInterface int newCount = value.Count(); - barBreadth = 1.0f / newCount; + bars.Breadth = 1.0f / newCount; float maxLength = MaxValue ?? value.Max(); @@ -139,7 +137,8 @@ namespace osu.Game.Graphics.UserInterface private Vector2 drawSize; private BarDirection direction; private float barBreadth; - private BarsInfo bars; + + private readonly List lengths = new List(); public override void ApplyState() { @@ -149,8 +148,10 @@ namespace osu.Game.Graphics.UserInterface texture = Source.texture; drawSize = Source.DrawSize; direction = Source.direction; - barBreadth = Source.barBreadth; - bars = Source.bars; + barBreadth = Source.bars.Breadth; + + lengths.Clear(); + lengths.AddRange(Source.bars.InstantaneousLengths); } public override void Draw(IRenderer renderer) @@ -159,10 +160,10 @@ namespace osu.Game.Graphics.UserInterface shader.Bind(); - for (int i = 0; i < bars.Count; i++) + for (int i = 0; i < lengths.Count; i++) { - float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? bars.InstantaneousLength(i) : barBreadth); - float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? bars.InstantaneousLength(i) : barBreadth); + float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? lengths[i] : barBreadth); + float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? lengths[i] : barBreadth); Vector2 topLeft; @@ -201,31 +202,18 @@ namespace osu.Game.Graphics.UserInterface } } - private readonly struct BarsInfo + private class BarsInfo { - private readonly List initialLengths; - private readonly List finalLengths; - private readonly List instantaneousLengths; + public bool Any => Count > 0; - public bool Any => initialLengths.Any(); + public int Count { get; private set; } - public int Count => initialLengths.Count; + public float Breadth { get; set; } - public BarsInfo(int initialCount) - { - initialLengths = new List(); - finalLengths = new List(); - instantaneousLengths = new List(); + public List InstantaneousLengths { get; } = new List(); - for (int i = 0; i < initialCount; i++) - { - initialLengths.Add(0); - finalLengths.Add(0); - instantaneousLengths.Add(0); - } - } - - public float InstantaneousLength(int index) => instantaneousLengths[index]; + private readonly List initialLengths = new List(); + private readonly List finalLengths = new List(); public void UpdateLength(int index, float newLength) { @@ -237,33 +225,39 @@ namespace osu.Game.Graphics.UserInterface { initialLengths.Add(0); finalLengths.Add(finalLength); - instantaneousLengths.Add(0); + InstantaneousLengths.Add(0); + + Count++; } public void Clear() { initialLengths.Clear(); finalLengths.Clear(); - instantaneousLengths.Clear(); + InstantaneousLengths.Clear(); + + Count = 0; } public void RemoveRange(int index, int count) { initialLengths.RemoveRange(index, count); finalLengths.RemoveRange(index, count); - instantaneousLengths.RemoveRange(index, count); + InstantaneousLengths.RemoveRange(index, count); + + Count -= count; } public void Animate(double animationStartTime, double currentTime) { for (int i = 0; i < Count; i++) - instantaneousLengths[i] = Interpolation.ValueAt(currentTime, initialLengths[i], finalLengths[i], animationStartTime, animationStartTime + resize_duration, easing); + InstantaneousLengths[i] = Interpolation.ValueAt(currentTime, initialLengths[i], finalLengths[i], animationStartTime, animationStartTime + resize_duration, easing); } public void FinishAnimation() { for (int i = 0; i < Count; i++) - instantaneousLengths[i] = finalLengths[i]; + InstantaneousLengths[i] = finalLengths[i]; } } } From b3667821ebfb0b18f5d7a3b0e1cddd156e185f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Nov 2022 10:07:32 +0100 Subject: [PATCH 2314/2686] Add failing test case --- .../Visual/SongSelect/TestSceneBeatmapCarousel.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index eacaf7f92e..d4d9f89c6a 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -11,6 +11,7 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -118,6 +119,15 @@ namespace osu.Game.Tests.Visual.SongSelect } } + [Test] + public void TestDeletion() + { + loadBeatmaps(count: 5, randomDifficulties: true); + + AddStep("remove first set", () => carousel.RemoveBeatmapSet(carousel.Items.Select(item => item.Item).OfType().First().BeatmapSet)); + AddUntilStep("4 beatmap sets visible", () => this.ChildrenOfType().Count(set => set.Alpha > 0) == 4); + } + [Test] public void TestScrollPositionMaintainedOnDelete() { From 7b274083d340fe2571ca22a8339097f9f814f27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Nov 2022 10:08:34 +0100 Subject: [PATCH 2315/2686] Fix phantom beatmap sets appearing on carousel after delete/update Regressed in c40c70509e1909fab2488120c9e867cb76f66827. As it turns out, `item.Item.Filtered.Value` is not the only condition that should be checked to determine if a carousel item should be hidden or not - `item.Item.State.Value != CarouselItemState.Collapsed` should also be true. This was even available as the `item.Item.Visible` convenience property, which is used in this commit. Failing to check `item.Item.State.Value` led to setting non-zero alpha on collapsed carousel items, leading to phantom beatmap sets appearing, as the alpha was set in the entire carousel's `Update()` method, thus firing every frame. --- osu.Game/Screens/Select/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 2f99f6acca..752a1ede64 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -770,7 +770,7 @@ namespace osu.Game.Screens.Select { updateItem(item); - if (!item.Item.Filtered.Value) + if (item.Item.Visible) { bool isSelected = item.Item.State.Value == CarouselItemState.Selected; From 33b2fe46d950fc125035290b8663ffbfc2858d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Nov 2022 12:29:41 +0100 Subject: [PATCH 2316/2686] Add xmldoc to `HistoryTextBox` --- osu.Game/Graphics/UserInterface/HistoryTextBox.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index e9da67e553..5d2cd18e9b 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -7,6 +7,12 @@ using osuTK.Input; namespace osu.Game.Graphics.UserInterface { + /// + /// A which additionally retains a history of text committed, up to a limit + /// (100 by default, specified in constructor). + /// The history of committed text can be navigated using up/down arrows. + /// This resembles the operation of command-line terminals. + /// public class HistoryTextBox : FocusedTextBox { private readonly LimitedCapacityQueue messageHistory; @@ -18,6 +24,13 @@ namespace osu.Game.Graphics.UserInterface private string originalMessage = string.Empty; private bool everythingSelected; + /// + /// Creates a new . + /// + /// + /// The maximum number of committed lines to keep in history. + /// When exceeded, the oldest lines in history will be dropped to make space for new ones. + /// public HistoryTextBox(int capacity = 100) { messageHistory = new LimitedCapacityQueue(capacity); From 793d5b117ec39f0de154d47811d4578d0debc6f1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 20 Nov 2022 15:20:35 +0300 Subject: [PATCH 2317/2686] Fix timing screen test scene not creating editor beatmap properly --- .../Visual/Editing/TestSceneTimingScreen.cs | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs index 03c184c27d..e7805bf393 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs @@ -3,14 +3,15 @@ #nullable disable +using System; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Overlays; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Osu; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Timing; using osu.Game.Screens.Edit.Timing.RowAttributes; @@ -21,10 +22,6 @@ namespace osu.Game.Tests.Visual.Editing [TestFixture] public class TestSceneTimingScreen : EditorClockTestScene { - [Cached(typeof(EditorBeatmap))] - [Cached(typeof(IBeatSnapProvider))] - private readonly EditorBeatmap editorBeatmap; - [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); @@ -32,21 +29,27 @@ namespace osu.Game.Tests.Visual.Editing protected override bool ScrollUsingMouseWheel => false; - public TestSceneTimingScreen() - { - editorBeatmap = new EditorBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)); - } - protected override void LoadComplete() { base.LoadComplete(); - Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); + Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); Beatmap.Disabled = true; - Child = timingScreen = new TimingScreen + var editorBeatmap = new EditorBeatmap(Beatmap.Value.GetPlayableBeatmap(Ruleset.Value)); + + Child = new DependencyProvidingContainer { - State = { Value = Visibility.Visible }, + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] + { + (typeof(EditorBeatmap), editorBeatmap), + (typeof(IBeatSnapProvider), editorBeatmap) + }, + Child = timingScreen = new TimingScreen + { + State = { Value = Visibility.Visible }, + }, }; } From 0f382590e6caa7e58f85ac30840289ea9c4b93f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 20 Nov 2022 15:31:51 +0100 Subject: [PATCH 2318/2686] Remove unnecessary `#nullable disable` --- osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs index 6955ef26e5..f3a3bb18bd 100644 --- a/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/IDrawableScrollingRuleset.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable using osu.Game.Configuration; namespace osu.Game.Rulesets.UI.Scrolling From 9040dfbd4ee5b40bff38d5dc8552727a1063d1ae Mon Sep 17 00:00:00 2001 From: RATCM Date: Sun, 20 Nov 2022 17:39:46 +0100 Subject: [PATCH 2319/2686] Match leaderboard filter behaviour to web --- osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 161d4847bf..5c31d83adb 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -204,10 +204,11 @@ namespace osu.Game.Screens.Select.Leaderboards } else if (filterMods) { - // otherwise find all the scores that have *any* of the currently selected mods (similar to how web applies mod filters) + // otherwise find all the scores that have all of the currently selected mods (similar to how web applies mod filters) // we're creating and using a string list representation of selected mods so that it can be translated into the DB query itself var selectedMods = mods.Value.Select(m => m.Acronym); - scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym))); + + scores = scores.Where(s => s.Mods.Select(m => m.Acronym).SequenceEqual(selectedMods)); } scores = scoreManager.OrderByTotalScore(scores.Detach()); From d20a357c0e6b46837d4afe054a6efebbaa480e20 Mon Sep 17 00:00:00 2001 From: RATCM Date: Sun, 20 Nov 2022 19:24:51 +0100 Subject: [PATCH 2320/2686] Fixed ordering bug --- osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 5c31d83adb..0761a034d8 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -206,9 +206,9 @@ namespace osu.Game.Screens.Select.Leaderboards { // otherwise find all the scores that have all of the currently selected mods (similar to how web applies mod filters) // we're creating and using a string list representation of selected mods so that it can be translated into the DB query itself - var selectedMods = mods.Value.Select(m => m.Acronym); + var selectedMods = mods.Value.Select(m => m.Acronym).ToHashSet(); - scores = scores.Where(s => s.Mods.Select(m => m.Acronym).SequenceEqual(selectedMods)); + scores = scores.Where(s => selectedMods.SetEquals(s.Mods.Select(m => m.Acronym))); } scores = scoreManager.OrderByTotalScore(scores.Detach()); From f5fbb7c8dee5c1114b2f392a49a4f708574231cb Mon Sep 17 00:00:00 2001 From: RATCM Date: Sun, 20 Nov 2022 19:27:40 +0100 Subject: [PATCH 2321/2686] Changed comments --- osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 0761a034d8..4cc3a30a1e 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -205,7 +205,7 @@ namespace osu.Game.Screens.Select.Leaderboards else if (filterMods) { // otherwise find all the scores that have all of the currently selected mods (similar to how web applies mod filters) - // we're creating and using a string list representation of selected mods so that it can be translated into the DB query itself + // we're creating and using a string HashSet representation of selected mods so that it can be translated into the DB query itself var selectedMods = mods.Value.Select(m => m.Acronym).ToHashSet(); scores = scores.Where(s => selectedMods.SetEquals(s.Mods.Select(m => m.Acronym))); From 18c79dfda3f08552dbdb518a90cd2e68b863de56 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 20 Nov 2022 23:00:13 +0300 Subject: [PATCH 2322/2686] Move all the logic into BarsInfo class --- osu.Game/Graphics/UserInterface/BarGraph.cs | 74 +++++++++------------ 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 498a480c06..3f356c0225 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -58,27 +58,9 @@ namespace osu.Game.Graphics.UserInterface return; } - int newCount = value.Count(); - - bars.Breadth = 1.0f / newCount; - float maxLength = MaxValue ?? value.Max(); - foreach (var bar in value.Select((length, index) => (Value: length, Index: index))) - { - float length = maxLength == 0 ? 0 : Math.Max(0f, bar.Value / maxLength); - - if (bar.Index < bars.Count) - { - bars.UpdateLength(bar.Index, length); - continue; - } - - bars.AddBar(length); - } - - if (bars.Count > newCount) - bars.RemoveRange(newCount, bars.Count - newCount); + bars.SetLengths(value.Select(v => maxLength == 0 ? 0 : Math.Max(0f, v / maxLength)).ToArray()); animationStartTime = Clock.CurrentTime; animationComplete = false; @@ -208,44 +190,48 @@ namespace osu.Game.Graphics.UserInterface public int Count { get; private set; } - public float Breadth { get; set; } + public float Breadth { get; private set; } public List InstantaneousLengths { get; } = new List(); private readonly List initialLengths = new List(); private readonly List finalLengths = new List(); - public void UpdateLength(int index, float newLength) + public void Clear() => SetLengths(Array.Empty()); + + public void SetLengths(float[] newLengths) { - initialLengths[index] = finalLengths[index]; - finalLengths[index] = newLength; - } + int newCount = newLengths.Length; - public void AddBar(float finalLength) - { - initialLengths.Add(0); - finalLengths.Add(finalLength); - InstantaneousLengths.Add(0); + for (int i = 0; i < newCount; i++) + { + // If we have an old bar at this index - change it's length + if (i < Count) + { + initialLengths[i] = finalLengths[i]; + finalLengths[i] = newLengths[i]; - Count++; - } + continue; + } - public void Clear() - { - initialLengths.Clear(); - finalLengths.Clear(); - InstantaneousLengths.Clear(); + // If exceeded old bars count - add new one + initialLengths.Add(0); + finalLengths.Add(newLengths[i]); + InstantaneousLengths.Add(0); + } - Count = 0; - } + // Remove excessive bars + if (Count > newCount) + { + int barsToRemove = Count - newCount; - public void RemoveRange(int index, int count) - { - initialLengths.RemoveRange(index, count); - finalLengths.RemoveRange(index, count); - InstantaneousLengths.RemoveRange(index, count); + initialLengths.RemoveRange(newCount, barsToRemove); + finalLengths.RemoveRange(newCount, barsToRemove); + InstantaneousLengths.RemoveRange(newCount, barsToRemove); + } - Count -= count; + Count = newCount; + Breadth = Count == 0 ? 0 : (1f / Count); } public void Animate(double animationStartTime, double currentTime) From a431b793b9e5ad4b8d69db3c8a62417c2c340942 Mon Sep 17 00:00:00 2001 From: vegguid <75315940+vegguid@users.noreply.github.com> Date: Sun, 20 Nov 2022 23:18:19 +0100 Subject: [PATCH 2323/2686] Added PreferOriginalMetadataLanguage to FirstRunSetup --- osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs index cb1e96d2f2..907da0429d 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -18,6 +18,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Localisation; +using osu.Game.Overlays.Settings; using osuTK; namespace osu.Game.Overlays.FirstRunSetup @@ -26,7 +27,7 @@ namespace osu.Game.Overlays.FirstRunSetup public class ScreenWelcome : FirstRunSetupScreen { [BackgroundDependencyLoader] - private void load() + private void load(FrameworkConfigManager frameworkConfig) { Content.Children = new Drawable[] { @@ -52,6 +53,11 @@ namespace osu.Game.Overlays.FirstRunSetup }, } }, + new SettingsCheckbox + { + LabelText = GeneralSettingsStrings.PreferOriginalMetadataLanguage, + Current = frameworkConfig.GetBindable(FrameworkSetting.ShowUnicode) + }, new LanguageSelectionFlow { RelativeSizeAxes = Axes.X, From 815cd56f13fe0bf62e1b9c6783b69d0dbc7f3c95 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Sun, 20 Nov 2022 16:50:15 -0800 Subject: [PATCH 2324/2686] Add support for nonsquare smoke textures --- .../Skinning/SmokeSegment.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index c19ed3fb35..66d74ae13e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -52,11 +52,13 @@ namespace osu.Game.Rulesets.Osu.Skinning protected Texture? Texture { get; set; } - private float radius => Texture?.DisplayWidth * 0.165f ?? 3; + private float height => Texture?.DisplayHeight * 0.165f ?? 3; + + private float width => Texture?.DisplayWidth * 0.165f ?? 3; protected readonly List SmokePoints = new List(); - private float pointInterval => radius * 7f / 8; + private float pointInterval => width * 7f / 8; private double smokeStartTime { get; set; } = double.MinValue; @@ -179,7 +181,8 @@ namespace osu.Game.Rulesets.Osu.Skinning private readonly List points = new List(); private IVertexBatch? quadBatch; - private float radius; + private float width; + private float height; private Vector2 drawSize; private Texture? texture; private int rotationSeed; @@ -202,7 +205,8 @@ namespace osu.Game.Rulesets.Osu.Skinning { base.ApplyState(); - radius = Source.radius; + width = Source.width; + height = Source.height; drawSize = Source.DrawSize; texture = Source.Texture; @@ -334,11 +338,13 @@ namespace osu.Game.Rulesets.Osu.Skinning var dir = PointDirection(point, index); var ortho = dir.PerpendicularLeft; + dir *= scale * width; + ortho *= scale * height; - var localTopLeft = point.Position + (radius * scale * (-ortho - dir)); - var localTopRight = point.Position + (radius * scale * (-ortho + dir)); - var localBotLeft = point.Position + (radius * scale * (ortho - dir)); - var localBotRight = point.Position + (radius * scale * (ortho + dir)); + var localTopLeft = point.Position - ortho - dir; + var localTopRight = point.Position - ortho + dir; + var localBotLeft = point.Position + ortho - dir; + var localBotRight = point.Position + ortho + dir; quadBatch.Add(new TexturedVertex2D { From d0ff5be7e646d54e78f123ed7c763615b012c9c9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 12:15:40 +0900 Subject: [PATCH 2325/2686] Fix `TestSceneTabletSettings` falling off the bottom of the screen --- .../Visual/Settings/TestSceneTabletSettings.cs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index d1d3748c26..84f5ce7627 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Testing; using osu.Framework.Utils; +using osu.Game.Graphics.Containers; using osu.Game.Overlays; using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings.Sections.Input; @@ -36,12 +37,17 @@ namespace osu.Game.Tests.Visual.Settings Children = new Drawable[] { - settings = new TabletSettings(tabletHandler) + new OsuScrollContainer(Direction.Vertical) { - RelativeSizeAxes = Axes.None, - Width = SettingsPanel.PANEL_WIDTH, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = settings = new TabletSettings(tabletHandler) + { + RelativeSizeAxes = Axes.None, + Width = SettingsPanel.PANEL_WIDTH, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + } } }; }); From c7ae83768751d64635c287733bc727038616f8f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 12:45:54 +0900 Subject: [PATCH 2326/2686] Increase maximum aspect ratio for tablet settings to 23:9 / 2.55 --- osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index f7c372a037..b6efa00cdb 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -45,9 +45,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input private GameHost host { get; set; } /// - /// Based on ultrawide monitor configurations. + /// Based on ultrawide monitor configurations, plus a bit of lenience for users which are intentionally aiming for higher horizontal velocity. /// - private const float largest_feasible_aspect_ratio = 21f / 9; + private const float largest_feasible_aspect_ratio = 23f / 9; private readonly BindableNumber aspectRatio = new BindableFloat(1) { From fa7b45dfb133dca53206c105c83fbaafeb6810bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 13:51:49 +0900 Subject: [PATCH 2327/2686] Fix chat day separator not being added on pending message resolution Closes #21316. --- osu.Game/Overlays/Chat/DrawableChannel.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 544daf7d2c..7f9be1a782 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -134,8 +134,7 @@ namespace osu.Game.Overlays.Chat foreach (var message in displayMessages) { - if (lastMessage == null || lastMessage.Timestamp.ToLocalTime().Date != message.Timestamp.ToLocalTime().Date) - ChatLineFlow.Add(CreateDaySeparator(message.Timestamp)); + addDaySeparatorIfRequired(lastMessage, message); ChatLineFlow.Add(CreateChatLine(message)); lastMessage = message; @@ -183,10 +182,18 @@ namespace osu.Game.Overlays.Chat ChatLineFlow.Remove(found, false); found.Message = updated; + + addDaySeparatorIfRequired(chatLines.LastOrDefault()?.Message, updated); ChatLineFlow.Add(found); } }); + private void addDaySeparatorIfRequired(Message lastMessage, Message message) + { + if (lastMessage == null || lastMessage.Timestamp.ToLocalTime().Date != message.Timestamp.ToLocalTime().Date) + ChatLineFlow.Add(CreateDaySeparator(message.Timestamp)); + } + private void messageRemoved(Message removed) => Schedule(() => { chatLines.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); From e53b4321ffa1eb91524558e15f786a8476b92905 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 14:01:10 +0900 Subject: [PATCH 2328/2686] Ensure two day separators are not added in a row --- osu.Game/Overlays/Chat/DrawableChannel.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 7f9be1a782..3d2eafd973 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -191,7 +191,15 @@ namespace osu.Game.Overlays.Chat private void addDaySeparatorIfRequired(Message lastMessage, Message message) { if (lastMessage == null || lastMessage.Timestamp.ToLocalTime().Date != message.Timestamp.ToLocalTime().Date) + { + // A day separator is displayed even if no messages are in the channel. + // If there are no messages after it, the simplest way to ensure it is fresh is to remove it + // and add a new one instead. + if (ChatLineFlow.LastOrDefault() is DaySeparator ds) + ChatLineFlow.Remove(ds, true); + ChatLineFlow.Add(CreateDaySeparator(message.Timestamp)); + } } private void messageRemoved(Message removed) => Schedule(() => From 93a189603a3bffd446fa5561a411b08c05ad232d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 14:20:36 +0900 Subject: [PATCH 2329/2686] Hide spinner ticks / bonus from results screen when not applicable to score --- osu.Game/Scoring/ScoreInfo.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index 1b36ae176d..a9ced62c95 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -296,6 +296,13 @@ namespace osu.Game.Scoring break; } + case HitResult.LargeBonus: + case HitResult.SmallBonus: + if (MaximumStatistics.TryGetValue(r.result, out int count) && count > 0) + yield return new HitResultDisplayStatistic(r.result, value, null, r.displayName); + + break; + case HitResult.SmallTickMiss: case HitResult.LargeTickMiss: break; From 40f2da364c1f6753bef8bbf3ae6d976dbbed406f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 14:34:35 +0900 Subject: [PATCH 2330/2686] Limit how far before the first hitobject that barlines can be generated --- osu.Game/Rulesets/Objects/BarLineGenerator.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/BarLineGenerator.cs b/osu.Game/Rulesets/Objects/BarLineGenerator.cs index c2709db747..185088878c 100644 --- a/osu.Game/Rulesets/Objects/BarLineGenerator.cs +++ b/osu.Game/Rulesets/Objects/BarLineGenerator.cs @@ -27,7 +27,10 @@ namespace osu.Game.Rulesets.Objects if (beatmap.HitObjects.Count == 0) return; + HitObject firstObject = beatmap.HitObjects.First(); HitObject lastObject = beatmap.HitObjects.Last(); + + double firstHitTime = firstObject.StartTime; double lastHitTime = 1 + lastObject.GetEndTime(); var timingPoints = beatmap.ControlPointInfo.TimingPoints; @@ -41,10 +44,14 @@ namespace osu.Game.Rulesets.Objects EffectControlPoint currentEffectPoint = beatmap.ControlPointInfo.EffectPointAt(currentTimingPoint.Time); int currentBeat = 0; + // Don't generate barlines before the hit object or t=0 (whichever is earliest). Some beatmaps use very unrealistic values here (although none are ranked). + // I'm not sure we ever want barlines to appear before the first hitobject, but let's keep some degree of compatibility for now. + // Of note, this will still differ from stable if the first timing control point is t<0 and is not near the first hitobject. + double startTime = Math.Max(Math.Min(0, firstHitTime), currentTimingPoint.Time); + // Stop on the next timing point, or if there is no next timing point stop slightly past the last object double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time : lastHitTime + currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; - double startTime = currentTimingPoint.Time; double barLength = currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; if (currentEffectPoint.OmitFirstBarLine) From 981264b011d95332c2d3ac059bdeae4411e5a34d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 14:51:41 +0900 Subject: [PATCH 2331/2686] Avoid crashing when a system audio device provides a `null` name --- .../Settings/Sections/Audio/AudioDevicesSettings.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index 7cb9efa1b9..9b53d62272 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -59,7 +59,11 @@ namespace osu.Game.Overlays.Settings.Sections.Audio // the dropdown. BASS does not give us a simple mechanism to select // specific audio devices in such a case anyways. Such // functionality would require involved OS-specific code. - dropdown.Items = deviceItems.Distinct().ToList(); + dropdown.Items = deviceItems + // Dropdown doesn't like null items. Somehow we are seeing some arrive here (see https://github.com/ppy/osu/issues/21271) + .Where(i => i != null) + .Distinct() + .ToList(); } protected override void Dispose(bool isDisposing) From 9a330c3cdbcf8d275d957216efe43e9bd4e727e8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 14:56:58 +0900 Subject: [PATCH 2332/2686] Apply nullability and clean up conditionals --- .../TestSceneTriangleBorderShader.cs | 2 -- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 25 ++++++++++--------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs b/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs index 470962088e..41a1d9b42e 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Shapes; diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 0c4bf59732..4da227d5d6 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.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. -#nullable disable - using osu.Framework.Utils; using osuTK; using System; @@ -71,11 +69,12 @@ namespace osu.Game.Graphics.Backgrounds private readonly List parts = new List(); [Resolved] - private IRenderer renderer { get; set; } + private IRenderer renderer { get; set; } = null!; - private Random stableRandom; - private IShader shader; - private Texture texture; + private Random? stableRandom; + + private IShader shader = null!; + private Texture texture = null!; /// /// Construct a new triangle visualisation. @@ -116,8 +115,7 @@ namespace osu.Game.Graphics.Backgrounds image[i, 0] = new Rgba32( colourBottom.Value.R * ratio + colourTop.Value.R * (1f - ratio), colourBottom.Value.G * ratio + colourTop.Value.G * (1f - ratio), - colourBottom.Value.B * ratio + colourTop.Value.B * (1f - ratio), - 1f + colourBottom.Value.B * ratio + colourTop.Value.B * (1f - ratio) ); } @@ -223,13 +221,13 @@ namespace osu.Game.Graphics.Backgrounds { protected new TrianglesV2 Source => (TrianglesV2)base.Source; - private IShader shader; - private Texture texture; + private IShader shader = null!; + private Texture texture = null!; private readonly List parts = new List(); private Vector2 size; - private IVertexBatch vertexBatch; + private IVertexBatch? vertexBatch; public TrianglesDrawNode(TrianglesV2 source) : base(source) @@ -252,7 +250,10 @@ namespace osu.Game.Graphics.Backgrounds { base.Draw(renderer); - if (Source.AimCount > 0 && (vertexBatch == null || vertexBatch.Size != Source.AimCount)) + if (Source.AimCount == 0) + return; + + if (vertexBatch == null || vertexBatch.Size != Source.AimCount) { vertexBatch?.Dispose(); vertexBatch = renderer.CreateQuadBatch(Source.AimCount, 1); From 5c640d15a0e15edd1749a57da7d6d537797bd4ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 15:17:54 +0900 Subject: [PATCH 2333/2686] Stop requesting messages as part of initial chat presence --- osu.Game/Online/API/Requests/GetUpdatesRequest.cs | 1 + osu.Game/Online/Notifications/NotificationsClient.cs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/GetUpdatesRequest.cs b/osu.Game/Online/API/Requests/GetUpdatesRequest.cs index ce2689d262..529c579996 100644 --- a/osu.Game/Online/API/Requests/GetUpdatesRequest.cs +++ b/osu.Game/Online/API/Requests/GetUpdatesRequest.cs @@ -25,6 +25,7 @@ namespace osu.Game.Online.API.Requests var req = base.CreateWebRequest(); if (channel != null) req.AddParameter(@"channel", channel.Id.ToString()); req.AddParameter(@"since", since.ToString()); + req.AddParameter(@"includes[]", "presence"); return req; } diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs index 6198707111..5654fa6396 100644 --- a/osu.Game/Online/Notifications/NotificationsClient.cs +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -67,8 +67,11 @@ namespace osu.Game.Online.Notifications protected void HandleChannelParted(Channel channel) => ChannelParted?.Invoke(channel); - protected void HandleMessages(List messages) + protected void HandleMessages(List? messages) { + if (messages == null) + return; + NewMessages?.Invoke(messages); lastMessageId = Math.Max(lastMessageId, messages.LastOrDefault()?.Id ?? 0); } From efd73ea9dac00cc875cd91560df520c0c2797fdb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 15:22:57 +0900 Subject: [PATCH 2334/2686] Rename method to suit better --- osu.Game/Online/Notifications/NotificationsClient.cs | 4 ++-- osu.Game/Tests/PollingNotificationsClient.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Notifications/NotificationsClient.cs b/osu.Game/Online/Notifications/NotificationsClient.cs index 5654fa6396..5762e0e588 100644 --- a/osu.Game/Online/Notifications/NotificationsClient.cs +++ b/osu.Game/Online/Notifications/NotificationsClient.cs @@ -33,11 +33,11 @@ namespace osu.Game.Online.Notifications public override Task ConnectAsync(CancellationToken cancellationToken) { - API.Queue(CreateFetchMessagesRequest(0)); + API.Queue(CreateInitialFetchRequest(0)); return Task.CompletedTask; } - protected APIRequest CreateFetchMessagesRequest(long? lastMessageId = null) + protected APIRequest CreateInitialFetchRequest(long? lastMessageId = null) { var fetchReq = new GetUpdatesRequest(lastMessageId ?? this.lastMessageId); diff --git a/osu.Game/Tests/PollingNotificationsClient.cs b/osu.Game/Tests/PollingNotificationsClient.cs index c1f032a647..571a7a1ed1 100644 --- a/osu.Game/Tests/PollingNotificationsClient.cs +++ b/osu.Game/Tests/PollingNotificationsClient.cs @@ -24,7 +24,7 @@ namespace osu.Game.Tests { while (!cancellationToken.IsCancellationRequested) { - await API.PerformAsync(CreateFetchMessagesRequest()); + await API.PerformAsync(CreateInitialFetchRequest()); await Task.Delay(1000, cancellationToken); } }, cancellationToken); From 462a213ffc616a3c92569776d66d28d7f569a311 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 15:23:04 +0900 Subject: [PATCH 2335/2686] Add TODO note about handling initial silences --- osu.Game/Online/API/Requests/GetUpdatesResponse.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Online/API/Requests/GetUpdatesResponse.cs b/osu.Game/Online/API/Requests/GetUpdatesResponse.cs index 61f6a8664d..7e030ce922 100644 --- a/osu.Game/Online/API/Requests/GetUpdatesResponse.cs +++ b/osu.Game/Online/API/Requests/GetUpdatesResponse.cs @@ -16,5 +16,7 @@ namespace osu.Game.Online.API.Requests [JsonProperty] public List Messages; + + // TODO: Handle Silences here (will need to add to includes[] in the request). } } From 3da21e596af9f376bc54eb8259bd8e0fc533d90f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 16:06:36 +0900 Subject: [PATCH 2336/2686] Add support for storyboards with incorrect path specifications (`\\` instead of `\`) Closes https://github.com/ppy/osu/issues/21204. --- osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index 6991500df5..a4e15f790a 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -147,7 +147,11 @@ namespace osu.Game.Beatmaps.Formats ); } - protected string CleanFilename(string path) => path.Trim('"').ToStandardisedPath(); + protected string CleanFilename(string path) => path + // User error which is supported by stable (https://github.com/ppy/osu/issues/21204) + .Replace(@"\\", @"\") + .Trim('"') + .ToStandardisedPath(); public enum Section { From 14a4de36f4cbd269f40b982930c9aedd8dbbba59 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 21 Nov 2022 10:20:35 +0300 Subject: [PATCH 2337/2686] Expose thickness property --- .../TestSceneTriangleBorderShader.cs | 41 ++++++++++++++++++- .../TestSceneTrianglesV2Background.cs | 1 + osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 18 ++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs b/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs index 41a1d9b42e..64512bc651 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs @@ -14,6 +14,8 @@ namespace osu.Game.Tests.Visual.Background { public class TestSceneTriangleBorderShader : OsuTestScene { + private readonly TriangleBorder border; + public TestSceneTriangleBorderShader() { Children = new Drawable[] @@ -23,7 +25,7 @@ namespace osu.Game.Tests.Visual.Background RelativeSizeAxes = Axes.Both, Colour = Color4.DarkGreen }, - new TriangleBorder + border = new TriangleBorder { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -32,8 +34,27 @@ namespace osu.Game.Tests.Visual.Background }; } + protected override void LoadComplete() + { + base.LoadComplete(); + + AddSliderStep("Thickness", 0f, 1f, 0.02f, t => border.Thickness = t); + } + private class TriangleBorder : Sprite { + private float thickness = 0.02f; + + public float Thickness + { + get => thickness; + set + { + thickness = value; + Invalidate(Invalidation.DrawNode); + } + } + [BackgroundDependencyLoader] private void load(ShaderManager shaders, IRenderer renderer) { @@ -45,11 +66,29 @@ namespace osu.Game.Tests.Visual.Background private class TriangleBorderDrawNode : SpriteDrawNode { + public new TriangleBorder Source => (TriangleBorder)base.Source; + public TriangleBorderDrawNode(TriangleBorder source) : base(source) { } + private float thickness; + + public override void ApplyState() + { + base.ApplyState(); + + thickness = Source.thickness; + } + + public override void Draw(IRenderer renderer) + { + TextureShader.GetUniform("thickness").UpdateValue(ref thickness); + + base.Draw(renderer); + } + protected override bool CanDrawOpaqueInterior => false; } } diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs index f6207c46a5..e8abc573cd 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs @@ -47,6 +47,7 @@ namespace osu.Game.Tests.Visual.Background base.LoadComplete(); AddSliderStep("Spawn ratio", 0f, 2f, 1f, s => triangles.SpawnRatio = s); + AddSliderStep("Thickness", 0f, 1f, 0.02f, t => triangles.Thickness = t); } } } diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 4da227d5d6..ca920bdd66 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -45,6 +45,21 @@ namespace osu.Game.Graphics.Backgrounds set => colourBottom.Value = value; } + private float thickness = 0.02f; + + public float Thickness + { + get => thickness; + set + { + if (thickness == value) + return; + + thickness = value; + // No need for invalidation since it's happening in Update() + } + } + /// /// Whether we should create new triangles as others expire. /// @@ -226,6 +241,7 @@ namespace osu.Game.Graphics.Backgrounds private readonly List parts = new List(); private Vector2 size; + private float thickness; private IVertexBatch? vertexBatch; @@ -241,6 +257,7 @@ namespace osu.Game.Graphics.Backgrounds shader = Source.shader; texture = Source.texture; size = Source.DrawSize; + thickness = Source.thickness; parts.Clear(); parts.AddRange(Source.parts); @@ -260,6 +277,7 @@ namespace osu.Game.Graphics.Backgrounds } shader.Bind(); + shader.GetUniform("thickness").UpdateValue(ref thickness); foreach (TriangleParticle particle in parts) { From ec8532951c7547fc3d30943debf081962f52b170 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 21 Nov 2022 10:32:19 +0300 Subject: [PATCH 2338/2686] Make Thickness property auto --- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index ca920bdd66..5fc32ff704 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -45,20 +45,7 @@ namespace osu.Game.Graphics.Backgrounds set => colourBottom.Value = value; } - private float thickness = 0.02f; - - public float Thickness - { - get => thickness; - set - { - if (thickness == value) - return; - - thickness = value; - // No need for invalidation since it's happening in Update() - } - } + public float Thickness { get; set; } = 0.02f; // No need for invalidation since it's happening in Update() /// /// Whether we should create new triangles as others expire. @@ -257,7 +244,7 @@ namespace osu.Game.Graphics.Backgrounds shader = Source.shader; texture = Source.texture; size = Source.DrawSize; - thickness = Source.thickness; + thickness = Source.Thickness; parts.Clear(); parts.AddRange(Source.parts); From 8f942f130b82b6ec5c37018a4d67d745eb160a28 Mon Sep 17 00:00:00 2001 From: Terochi Date: Mon, 21 Nov 2022 09:32:44 +0100 Subject: [PATCH 2339/2686] Variant 1: edit changes history, empty text resets index --- .../UserInterface/TestSceneHistoryTextBox.cs | 59 ++++--------------- .../Graphics/UserInterface/HistoryTextBox.cs | 18 ++---- osu.Game/Utils/LimitedCapacityQueue.cs | 7 +++ 3 files changed, 24 insertions(+), 60 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs index 8918e53056..6ead7bc168 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs @@ -3,7 +3,6 @@ using NUnit.Framework; using osu.Framework.Graphics; -using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -64,62 +63,32 @@ namespace osu.Game.Tests.Visual.UserInterface } [Test] - public void TestEmptyHistory() + public void TestChangedHistory() { + addMessages(2); AddStep("Set text", () => box.Text = temp); + AddStep("Move up", () => InputManager.Key(Key.Up)); + AddStep("Change text", () => box.Text = "New message"); AddStep("Move down", () => InputManager.Key(Key.Down)); - AddAssert("Text is the same", () => box.Text == temp); - - AddStep("Move Up", () => InputManager.Key(Key.Up)); - AddAssert("Text is the same", () => box.Text == temp); + AddStep("Move up", () => InputManager.Key(Key.Up)); + AddAssert("Changes kept", () => box.Text == "New message"); } [Test] - public void TestPartialHistory() + public void TestInputOnEdge() { addMessages(2); AddStep("Set text", () => box.Text = temp); AddStep("Move down", () => InputManager.Key(Key.Down)); - AddAssert("Text is the same", () => box.Text == temp); + AddAssert("Text unchanged", () => box.Text == temp); - AddRepeatStep("Move Up", () => InputManager.Key(Key.Up), 2); + AddRepeatStep("Move up", () => InputManager.Key(Key.Up), 2); AddAssert("Same as 1st message", () => box.Text == "Message 1"); - AddStep("Move Up", () => InputManager.Key(Key.Up)); - AddAssert("Text is the same", () => box.Text == "Message 1"); - - AddRepeatStep("Move down", () => InputManager.Key(Key.Down), 2); - AddAssert("Same as temp message", () => box.Text == temp); - - AddStep("Move down", () => InputManager.Key(Key.Down)); - AddAssert("Text is the same", () => box.Text == temp); - } - - [Test] - public void TestFullHistory() - { - addMessages(5); - AddStep("Set text", () => box.Text = temp); - - AddStep("Move down", () => InputManager.Key(Key.Down)); - AddAssert("Text is the same", () => box.Text == temp); - - addMessages(2); - AddStep("Set text", () => box.Text = temp); - - AddRepeatStep("Move Up", () => InputManager.Key(Key.Up), 5); - AddAssert("Same as 3rd message", () => box.Text == "Message 3"); - - AddStep("Move Up", () => InputManager.Key(Key.Up)); - AddAssert("Text is the same", () => box.Text == "Message 3"); - - AddRepeatStep("Move down", () => InputManager.Key(Key.Down), 4); - AddAssert("Same as previous message", () => box.Text == "Message 7"); - - AddStep("Move down", () => InputManager.Key(Key.Down)); - AddAssert("Same as temp message", () => box.Text == temp); + AddStep("Move up", () => InputManager.Key(Key.Up)); + AddAssert("Text unchanged", () => box.Text == "Message 1"); } [Test] @@ -133,12 +102,6 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Remove text", () => box.Text = string.Empty); AddStep("Move Up", () => InputManager.Key(Key.Up)); AddAssert("Same as previous message", () => box.Text == "Message 2"); - - AddStep("Move Up", () => InputManager.Key(Key.Up)); - AddStep("Select text", () => InputManager.Keys(PlatformAction.SelectAll)); - AddStep("Replace text", () => box.Text = "New text"); - AddStep("Move Up", () => InputManager.Key(Key.Up)); - AddAssert("Same as previous message", () => box.Text == "Message 2"); } private void addMessages(int count) diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index 5d2cd18e9b..b0ca5beb66 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -22,7 +22,6 @@ namespace osu.Game.Graphics.UserInterface private int selectedIndex; private string originalMessage = string.Empty; - private bool everythingSelected; /// /// Creates a new . @@ -37,21 +36,11 @@ namespace osu.Game.Graphics.UserInterface Current.ValueChanged += text => { - if (string.IsNullOrEmpty(text.NewValue) || everythingSelected) - { + if (string.IsNullOrEmpty(text.NewValue)) selectedIndex = HistoryCount; - everythingSelected = false; - } }; } - protected override void OnTextSelectionChanged(TextSelectionType selectionType) - { - everythingSelected = SelectedText == Text; - - base.OnTextSelectionChanged(selectionType); - } - protected override bool OnKeyDown(KeyDownEvent e) { switch (e.Key) @@ -62,6 +51,8 @@ namespace osu.Game.Graphics.UserInterface if (selectedIndex == HistoryCount) originalMessage = Text; + else if (!string.IsNullOrEmpty(Text)) + messageHistory[selectedIndex] = Text; Text = messageHistory[--selectedIndex]; @@ -71,6 +62,9 @@ namespace osu.Game.Graphics.UserInterface if (selectedIndex == HistoryCount) return true; + if (!string.IsNullOrEmpty(Text)) + messageHistory[selectedIndex] = Text; + if (selectedIndex == HistoryCount - 1) { selectedIndex = HistoryCount; diff --git a/osu.Game/Utils/LimitedCapacityQueue.cs b/osu.Game/Utils/LimitedCapacityQueue.cs index 86a106a678..8f3b36a059 100644 --- a/osu.Game/Utils/LimitedCapacityQueue.cs +++ b/osu.Game/Utils/LimitedCapacityQueue.cs @@ -103,6 +103,13 @@ namespace osu.Game.Utils return array[(start + index) % capacity]; } + set + { + if (index < 0 || index >= Count) + throw new ArgumentOutOfRangeException(nameof(index)); + + array[(start + index) % capacity] = value; + } } /// From 672e1cd45bfc1ad6d495ad833d02c7ae7a9e7b40 Mon Sep 17 00:00:00 2001 From: Terochi Date: Mon, 21 Nov 2022 09:38:33 +0100 Subject: [PATCH 2340/2686] Variant 2: edit changes history, cannot reset index (similar to stable) --- .../Visual/UserInterface/TestSceneHistoryTextBox.cs | 2 +- osu.Game/Graphics/UserInterface/HistoryTextBox.cs | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs index 6ead7bc168..e0f734fce0 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs @@ -101,7 +101,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Remove text", () => box.Text = string.Empty); AddStep("Move Up", () => InputManager.Key(Key.Up)); - AddAssert("Same as previous message", () => box.Text == "Message 2"); + AddAssert("Text unchanged", () => box.Text == string.Empty); } private void addMessages(int count) diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index b0ca5beb66..6791812b98 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -33,12 +33,6 @@ namespace osu.Game.Graphics.UserInterface public HistoryTextBox(int capacity = 100) { messageHistory = new LimitedCapacityQueue(capacity); - - Current.ValueChanged += text => - { - if (string.IsNullOrEmpty(text.NewValue)) - selectedIndex = HistoryCount; - }; } protected override bool OnKeyDown(KeyDownEvent e) From 58288275a6f38291a283840ec12e6009f8479332 Mon Sep 17 00:00:00 2001 From: Terochi Date: Mon, 21 Nov 2022 09:43:36 +0100 Subject: [PATCH 2341/2686] Variant 3: cannot change history, cannot reset index (the "default") --- .../Visual/UserInterface/TestSceneHistoryTextBox.cs | 2 +- osu.Game/Graphics/UserInterface/HistoryTextBox.cs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs index e0f734fce0..414c1276e1 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs @@ -72,7 +72,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Change text", () => box.Text = "New message"); AddStep("Move down", () => InputManager.Key(Key.Down)); AddStep("Move up", () => InputManager.Key(Key.Up)); - AddAssert("Changes kept", () => box.Text == "New message"); + AddAssert("Changes lost", () => box.Text == "Message 2"); } [Test] diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index 6791812b98..290457564b 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -45,8 +45,6 @@ namespace osu.Game.Graphics.UserInterface if (selectedIndex == HistoryCount) originalMessage = Text; - else if (!string.IsNullOrEmpty(Text)) - messageHistory[selectedIndex] = Text; Text = messageHistory[--selectedIndex]; @@ -56,9 +54,6 @@ namespace osu.Game.Graphics.UserInterface if (selectedIndex == HistoryCount) return true; - if (!string.IsNullOrEmpty(Text)) - messageHistory[selectedIndex] = Text; - if (selectedIndex == HistoryCount - 1) { selectedIndex = HistoryCount; From 7dc7729ac2464c9967c1deff87056d1721897626 Mon Sep 17 00:00:00 2001 From: Terochi Date: Mon, 21 Nov 2022 10:11:26 +0100 Subject: [PATCH 2342/2686] Variant 4: cannot change history, empty text/everything selected resets index (current with bug fix) --- .../UserInterface/TestSceneHistoryTextBox.cs | 9 +++++- .../Graphics/UserInterface/HistoryTextBox.cs | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs index 414c1276e1..29f1e29b55 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using osu.Framework.Graphics; +using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -101,7 +102,13 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Remove text", () => box.Text = string.Empty); AddStep("Move Up", () => InputManager.Key(Key.Up)); - AddAssert("Text unchanged", () => box.Text == string.Empty); + AddAssert("Same as previous message", () => box.Text == "Message 2"); + + AddStep("Move Up", () => InputManager.Key(Key.Up)); + AddStep("Select text", () => InputManager.Keys(PlatformAction.SelectAll)); + AddStep("Replace text", () => box.Text = "New text"); + AddStep("Move Up", () => InputManager.Key(Key.Up)); + AddAssert("Same as previous message", () => box.Text == "Message 2"); } private void addMessages(int count) diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index 290457564b..f2b975226c 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -22,6 +22,7 @@ namespace osu.Game.Graphics.UserInterface private int selectedIndex; private string originalMessage = string.Empty; + private bool everythingSelected; /// /// Creates a new . @@ -33,6 +34,29 @@ namespace osu.Game.Graphics.UserInterface public HistoryTextBox(int capacity = 100) { messageHistory = new LimitedCapacityQueue(capacity); + + Current.ValueChanged += text => + { + if (string.IsNullOrEmpty(text.NewValue) || everythingSelected) + { + selectedIndex = HistoryCount; + everythingSelected = false; + } + }; + } + + protected override void OnTextDeselected() + { + base.OnTextDeselected(); + + everythingSelected = false; + } + + protected override void OnTextSelectionChanged(TextSelectionType selectionType) + { + base.OnTextSelectionChanged(selectionType); + + everythingSelected = SelectedText == Text; } protected override bool OnKeyDown(KeyDownEvent e) @@ -43,6 +67,8 @@ namespace osu.Game.Graphics.UserInterface if (selectedIndex == 0) return true; + everythingSelected = false; + if (selectedIndex == HistoryCount) originalMessage = Text; @@ -54,6 +80,8 @@ namespace osu.Game.Graphics.UserInterface if (selectedIndex == HistoryCount) return true; + everythingSelected = false; + if (selectedIndex == HistoryCount - 1) { selectedIndex = HistoryCount; From d81ef541bc8ff8f49119b4491a6842277c60983c Mon Sep 17 00:00:00 2001 From: Terochi Date: Mon, 21 Nov 2022 10:17:28 +0100 Subject: [PATCH 2343/2686] Variant 5: cannot change history, edit resets index --- .../UserInterface/TestSceneHistoryTextBox.cs | 9 +------- .../Graphics/UserInterface/HistoryTextBox.cs | 22 +------------------ 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs index 29f1e29b55..78b1bdb18c 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs @@ -3,7 +3,6 @@ using NUnit.Framework; using osu.Framework.Graphics; -using osu.Framework.Input; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -100,13 +99,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddRepeatStep("Move Up", () => InputManager.Key(Key.Up), 2); AddAssert("Same as 1st message", () => box.Text == "Message 1"); - AddStep("Remove text", () => box.Text = string.Empty); - AddStep("Move Up", () => InputManager.Key(Key.Up)); - AddAssert("Same as previous message", () => box.Text == "Message 2"); - - AddStep("Move Up", () => InputManager.Key(Key.Up)); - AddStep("Select text", () => InputManager.Keys(PlatformAction.SelectAll)); - AddStep("Replace text", () => box.Text = "New text"); + AddStep("Change text", () => box.Text = "New message"); AddStep("Move Up", () => InputManager.Key(Key.Up)); AddAssert("Same as previous message", () => box.Text == "Message 2"); } diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index f2b975226c..0958e1832e 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -22,7 +22,6 @@ namespace osu.Game.Graphics.UserInterface private int selectedIndex; private string originalMessage = string.Empty; - private bool everythingSelected; /// /// Creates a new . @@ -37,28 +36,13 @@ namespace osu.Game.Graphics.UserInterface Current.ValueChanged += text => { - if (string.IsNullOrEmpty(text.NewValue) || everythingSelected) + if (selectedIndex != HistoryCount && text.NewValue != messageHistory[selectedIndex]) { selectedIndex = HistoryCount; - everythingSelected = false; } }; } - protected override void OnTextDeselected() - { - base.OnTextDeselected(); - - everythingSelected = false; - } - - protected override void OnTextSelectionChanged(TextSelectionType selectionType) - { - base.OnTextSelectionChanged(selectionType); - - everythingSelected = SelectedText == Text; - } - protected override bool OnKeyDown(KeyDownEvent e) { switch (e.Key) @@ -67,8 +51,6 @@ namespace osu.Game.Graphics.UserInterface if (selectedIndex == 0) return true; - everythingSelected = false; - if (selectedIndex == HistoryCount) originalMessage = Text; @@ -80,8 +62,6 @@ namespace osu.Game.Graphics.UserInterface if (selectedIndex == HistoryCount) return true; - everythingSelected = false; - if (selectedIndex == HistoryCount - 1) { selectedIndex = HistoryCount; From b404b87f6830824d104362dc33a1cc640547912b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 21 Nov 2022 18:26:53 +0900 Subject: [PATCH 2344/2686] Realign white line on argon hold note ends to match hit target --- .../Skinning/Argon/ArgonHoldNoteTailPiece.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs index e1068c6cd8..00cd37b6cf 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs @@ -38,6 +38,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon }, new Container { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, Height = 0.82f, Masking = true, @@ -54,6 +56,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { RelativeSizeAxes = Axes.X, Height = ArgonNotePiece.CORNER_RADIUS * 2, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, }, }; } From ff5cb116f03ef2850b5d5dd68533da5bb5a1b059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 21 Nov 2022 19:27:06 +0100 Subject: [PATCH 2345/2686] Fix weird scroll container sizing --- osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index 84f5ce7627..5e75bd7bc1 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -39,8 +39,7 @@ namespace osu.Game.Tests.Visual.Settings { new OsuScrollContainer(Direction.Vertical) { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.Both, Child = settings = new TabletSettings(tabletHandler) { RelativeSizeAxes = Axes.None, From 735cac3104f4ba43eaa9fbdb0d909f506dfe58ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 21 Nov 2022 20:56:38 +0100 Subject: [PATCH 2346/2686] Rewrite rank graph test to use more modern style --- .../Visual/Online/TestSceneRankGraph.cs | 87 ++++++++++++------- 1 file changed, 58 insertions(+), 29 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs index 1b1a5c7c6a..304c710b10 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs @@ -1,13 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; @@ -23,33 +22,14 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); - public TestSceneRankGraph() + private RankGraph graph = null!; + + private const int history_length = 89; + + [SetUpSteps] + public void SetUpSteps() { - RankGraph graph; - - int[] data = new int[89]; - int[] dataWithZeros = new int[89]; - int[] smallData = new int[89]; - int[] edgyData = new int[89]; - - for (int i = 0; i < 89; i++) - data[i] = dataWithZeros[i] = (i + 1) * 1000; - - for (int i = 20; i < 60; i++) - dataWithZeros[i] = 0; - - for (int i = 79; i < 89; i++) - smallData[i] = 100000 - i * 1000; - - bool edge = true; - - for (int i = 0; i < 20; i++) - { - edgyData[i] = 100000 + (edge ? 1000 : -1000) * (i + 1); - edge = !edge; - } - - Add(new Container + AddStep("create graph", () => Child = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -67,8 +47,14 @@ namespace osu.Game.Tests.Visual.Online } } }); + } + [Test] + public void TestNullUser() => AddStep("null user", () => graph.Statistics.Value = null); + + [Test] + public void TestRankOnly() => AddStep("rank only", () => { graph.Statistics.Value = new UserStatistics @@ -78,6 +64,14 @@ namespace osu.Game.Tests.Visual.Online }; }); + [Test] + public void TestWithRankHistory() + { + int[] data = new int[history_length]; + + for (int i = 0; i < history_length; i++) + data[i] = (i + 1) * 1000; + AddStep("with rank history", () => { graph.Statistics.Value = new UserStatistics @@ -86,10 +80,22 @@ namespace osu.Game.Tests.Visual.Online PP = 12345, RankHistory = new APIRankHistory { - Data = data, + Data = data } }; }); + } + + [Test] + public void TestRanksWithZeroValues() + { + int[] dataWithZeros = new int[history_length]; + + for (int i = 0; i < history_length; i++) + { + if (i < 20 || i >= 60) + dataWithZeros[i] = (i + 1) * 1000; + } AddStep("with zero values", () => { @@ -103,6 +109,15 @@ namespace osu.Game.Tests.Visual.Online } }; }); + } + + [Test] + public void TestSmallAmountOfData() + { + int[] smallData = new int[history_length]; + + for (int i = history_length - 10; i < history_length; i++) + smallData[i] = 100000 - i * 1000; AddStep("small amount of data", () => { @@ -116,6 +131,20 @@ namespace osu.Game.Tests.Visual.Online } }; }); + } + + [Test] + public void TestHistoryWithEdges() + { + int[] edgyData = new int[89]; + + bool edge = true; + + for (int i = 0; i < 20; i++) + { + edgyData[i] = 100000 + (edge ? 1000 : -1000) * (i + 1); + edge = !edge; + } AddStep("graph with edges", () => { From 1777a6013619b021c078224ff02c86aad21014ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 21 Nov 2022 20:58:52 +0100 Subject: [PATCH 2347/2686] Add failing assertions --- .../Visual/Online/TestSceneRankGraph.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs index 304c710b10..ce4d11800b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.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.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -8,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Testing; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Profile.Header.Components; @@ -50,11 +52,15 @@ namespace osu.Game.Tests.Visual.Online } [Test] - public void TestNullUser() => + public void TestNullUser() + { AddStep("null user", () => graph.Statistics.Value = null); + AddAssert("line graph hidden", () => this.ChildrenOfType().All(graph => graph.Alpha == 0)); + } [Test] - public void TestRankOnly() => + public void TestRankOnly() + { AddStep("rank only", () => { graph.Statistics.Value = new UserStatistics @@ -63,6 +69,8 @@ namespace osu.Game.Tests.Visual.Online PP = 12345, }; }); + AddAssert("line graph hidden", () => this.ChildrenOfType().All(graph => graph.Alpha == 0)); + } [Test] public void TestWithRankHistory() @@ -84,6 +92,7 @@ namespace osu.Game.Tests.Visual.Online } }; }); + AddAssert("line graph shown", () => this.ChildrenOfType().All(graph => graph.Alpha == 1)); } [Test] @@ -109,6 +118,7 @@ namespace osu.Game.Tests.Visual.Online } }; }); + AddAssert("line graph shown", () => this.ChildrenOfType().All(graph => graph.Alpha == 1)); } [Test] @@ -131,6 +141,7 @@ namespace osu.Game.Tests.Visual.Online } }; }); + AddAssert("line graph shown", () => this.ChildrenOfType().All(graph => graph.Alpha == 1)); } [Test] @@ -158,6 +169,7 @@ namespace osu.Game.Tests.Visual.Online } }; }); + AddAssert("line graph shown", () => this.ChildrenOfType().All(graph => graph.Alpha == 1)); } } } From 41039340cfcaf81dee840f56812a1f0f6974fa96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 21 Nov 2022 21:00:06 +0100 Subject: [PATCH 2348/2686] Fix rank graphs not showing in test due to unset `IsRanked` --- osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs index ce4d11800b..d05f1f02f7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs @@ -65,6 +65,7 @@ namespace osu.Game.Tests.Visual.Online { graph.Statistics.Value = new UserStatistics { + IsRanked = true, GlobalRank = 123456, PP = 12345, }; @@ -84,6 +85,7 @@ namespace osu.Game.Tests.Visual.Online { graph.Statistics.Value = new UserStatistics { + IsRanked = true, GlobalRank = 89000, PP = 12345, RankHistory = new APIRankHistory @@ -110,6 +112,7 @@ namespace osu.Game.Tests.Visual.Online { graph.Statistics.Value = new UserStatistics { + IsRanked = true, GlobalRank = 89000, PP = 12345, RankHistory = new APIRankHistory @@ -133,6 +136,7 @@ namespace osu.Game.Tests.Visual.Online { graph.Statistics.Value = new UserStatistics { + IsRanked = true, GlobalRank = 12000, PP = 12345, RankHistory = new APIRankHistory @@ -161,6 +165,7 @@ namespace osu.Game.Tests.Visual.Online { graph.Statistics.Value = new UserStatistics { + IsRanked = true, GlobalRank = 12000, PP = 12345, RankHistory = new APIRankHistory From 4084a2b0669509433826e2676711c000a3be2b9a Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 21 Nov 2022 18:57:59 -0800 Subject: [PATCH 2349/2686] Highlight `ChatLine` username on hover --- osu.Game/Overlays/Chat/ChatLine.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index a991103fac..af5fa89ca1 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -23,6 +23,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osuTK; using osuTK.Graphics; +using osu.Framework.Input.Events; namespace osu.Game.Overlays.Chat { @@ -291,6 +292,20 @@ namespace osu.Game.Overlays.Chat return items.ToArray(); } } + + protected override bool OnHover(HoverEvent e) + { + this.FadeColour(new Color4(1.4f, 1.4f, 1.4f, 1), 150, Easing.OutQuint); + + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + base.OnHoverLost(e); + + this.FadeColour(Color4.White, 250, Easing.OutQuint); + } } private static readonly Color4[] username_colours = From 1632df1f4db4a9aea047548f3ad6205ebdfd4eda Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Nov 2022 14:51:17 +0900 Subject: [PATCH 2350/2686] Update `DifficultyBindable` to match new bindable spec --- osu.Game/Rulesets/Mods/DifficultyBindable.cs | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Mods/DifficultyBindable.cs b/osu.Game/Rulesets/Mods/DifficultyBindable.cs index 34e9fe40a3..2b3ba1dd13 100644 --- a/osu.Game/Rulesets/Mods/DifficultyBindable.cs +++ b/osu.Game/Rulesets/Mods/DifficultyBindable.cs @@ -99,22 +99,31 @@ namespace osu.Game.Rulesets.Mods CurrentNumber.MaxValue = ExtendedLimits.Value && extendedMaxValue != null ? extendedMaxValue.Value : maxValue; } + public override void CopyTo(Bindable them) + { + if (!(them is DifficultyBindable otherDifficultyBindable)) + throw new InvalidOperationException($"Cannot copy to a non-{nameof(DifficultyBindable)}."); + + base.CopyTo(them); + + otherDifficultyBindable.ReadCurrentFromDifficulty = ReadCurrentFromDifficulty; + + // the following max value copies are only safe as long as these values are effectively constants. + otherDifficultyBindable.MaxValue = maxValue; + otherDifficultyBindable.ExtendedMaxValue = extendedMaxValue; + } + public override void BindTo(Bindable them) { if (!(them is DifficultyBindable otherDifficultyBindable)) throw new InvalidOperationException($"Cannot bind to a non-{nameof(DifficultyBindable)}."); - ReadCurrentFromDifficulty = otherDifficultyBindable.ReadCurrentFromDifficulty; - - // the following max value copies are only safe as long as these values are effectively constants. - MaxValue = otherDifficultyBindable.maxValue; - ExtendedMaxValue = otherDifficultyBindable.extendedMaxValue; + base.BindTo(them); ExtendedLimits.BindTarget = otherDifficultyBindable.ExtendedLimits; // the actual values need to be copied after the max value constraints. CurrentNumber.BindTarget = otherDifficultyBindable.CurrentNumber; - base.BindTo(them); } public override void UnbindFrom(IUnbindable them) From 57723107dd313833902032268921f779346f5472 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Nov 2022 16:15:32 +0900 Subject: [PATCH 2351/2686] Fix osu!mania hold notes occasionally getting in a visually incorrect hit state To correctly end a mania hold note, `endHold()` needs to be called. This was not happening in a very specific scenario: - The hold note's head is not hit - The user pressed the column's key within the hold note's tail's window, but does so to hit the next object (a note in proximity to the hold note's tail). - The hit policy forces a miss on the hold note, but `endHold()` is not called - `CheckForResult` is not called after this point due to `Judged` being `true`. Closes #21311. --- .../Objects/Drawables/DrawableHoldNote.cs | 14 ++++++++++++-- .../Objects/Drawables/DrawableManiaHitObject.cs | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index c68eec610c..86d4ad0a36 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -262,14 +262,24 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables tick.MissForcefully(); } - ApplyResult(r => r.Type = Tail.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult); - endHold(); + if (Tail.IsHit) + ApplyResult(r => r.Type = r.Judgement.MaxResult); + else + MissForcefully(); } if (Tail.Judged && !Tail.IsHit) HoldBrokenTime = Time.Current; } + public override void MissForcefully() + { + base.MissForcefully(); + + // Important that this is always called when a result is applied. + endHold(); + } + public bool OnPressed(KeyBindingPressEvent e) { if (AllJudged) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 73dc937a00..51f8ab1cf8 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// /// Causes this to get missed, disregarding all conditions in implementations of . /// - public void MissForcefully() => ApplyResult(r => r.Type = r.Judgement.MinResult); + public virtual void MissForcefully() => ApplyResult(r => r.Type = r.Judgement.MinResult); } public abstract class DrawableManiaHitObject : DrawableManiaHitObject From c1b193149c67b061c7c5597b953f5e5b0aa487de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Nov 2022 17:09:10 +0900 Subject: [PATCH 2352/2686] Add test coverage of input near end of hold note with nearby subsequent note Covers the scenarios mentioned in #21371. Turns out this seems mostly okay already, so there are no fixes applied here. --- .../TestSceneHoldNoteInput.cs | 165 +++++++++++++++++- 1 file changed, 160 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs index 0296303867..0cba2076be 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs @@ -23,6 +23,15 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests { + /// + /// Diagrams in this class are represented as: + /// - : time + /// O : note + /// [ ] : hold note + /// + /// x : button press + /// o : button release + /// public class TestSceneHoldNoteInput : RateAdjustedBeatmapTestScene { private const double time_before_head = 250; @@ -223,6 +232,149 @@ namespace osu.Game.Rulesets.Mania.Tests assertTailJudgement(HitResult.Meh); } + /// + /// -----[ ]-O------------- + /// xo o + /// + [Test] + public void TestPressAndReleaseJustBeforeTailWithNearbyNoteAndCloseByHead() + { + Note note; + + const int duration = 50; + + var beatmap = new Beatmap + { + HitObjects = + { + // hold note is very short, to make the head still in range + new HoldNote + { + StartTime = time_head, + Duration = duration, + Column = 0, + }, + { + // Next note within tail lenience + note = new Note + { + StartTime = time_head + duration + 10 + } + } + }, + BeatmapInfo = + { + Difficulty = new BeatmapDifficulty { SliderTickRate = 4 }, + Ruleset = new ManiaRuleset().RulesetInfo + }, + }; + + performTest(new List + { + new ManiaReplayFrame(time_head + duration, ManiaAction.Key1), + new ManiaReplayFrame(time_head + duration + 10), + }, beatmap); + + assertHeadJudgement(HitResult.Good); + assertTailJudgement(HitResult.Perfect); + + assertHitObjectJudgement(note, HitResult.Miss); + } + + /// + /// -----[ ]--O-- + /// xo o + /// + [Test] + public void TestPressAndReleaseJustBeforeTailWithNearbyNote() + { + Note note; + + var beatmap = new Beatmap + { + HitObjects = + { + new HoldNote + { + StartTime = time_head, + Duration = time_tail - time_head, + Column = 0, + }, + { + // Next note within tail lenience + note = new Note + { + StartTime = time_tail + 50 + } + } + }, + BeatmapInfo = + { + Difficulty = new BeatmapDifficulty { SliderTickRate = 4 }, + Ruleset = new ManiaRuleset().RulesetInfo + }, + }; + + performTest(new List + { + new ManiaReplayFrame(time_tail - 10, ManiaAction.Key1), + new ManiaReplayFrame(time_tail), + }, beatmap); + + assertHeadJudgement(HitResult.Miss); + assertTickJudgement(HitResult.LargeTickMiss); + assertTailJudgement(HitResult.Miss); + + assertHitObjectJudgement(note, HitResult.Good); + } + + /// + /// -----[ ]--O-- + /// xo o + /// + [Test] + public void TestPressAndReleaseJustAfterTailWithNearbyNote() + { + Note note; + + var beatmap = new Beatmap + { + HitObjects = + { + new HoldNote + { + StartTime = time_head, + Duration = time_tail - time_head, + Column = 0, + }, + { + // Next note within tail lenience + note = new Note + { + StartTime = time_tail + 50 + } + } + }, + BeatmapInfo = + { + Difficulty = new BeatmapDifficulty { SliderTickRate = 4 }, + Ruleset = new ManiaRuleset().RulesetInfo + }, + }; + + performTest(new List + { + new ManiaReplayFrame(time_tail + 10, ManiaAction.Key1), + new ManiaReplayFrame(time_tail + 20), + }, beatmap); + + assertHeadJudgement(HitResult.Miss); + assertTickJudgement(HitResult.LargeTickMiss); + assertTailJudgement(HitResult.Miss); + + assertHitObjectJudgement(note, HitResult.Great); + } + /// /// -----[ ]----- /// xo o @@ -351,20 +503,23 @@ namespace osu.Game.Rulesets.Mania.Tests .All(j => j.Type.IsHit())); } + private void assertHitObjectJudgement(HitObject hitObject, HitResult result) + => AddAssert($"object judged as {result}", () => judgementResults.First(j => j.HitObject == hitObject).Type, () => Is.EqualTo(result)); + private void assertHeadJudgement(HitResult result) - => AddAssert($"head judged as {result}", () => judgementResults.First(j => j.HitObject is Note).Type == result); + => AddAssert($"head judged as {result}", () => judgementResults.First(j => j.HitObject is Note).Type, () => Is.EqualTo(result)); private void assertTailJudgement(HitResult result) - => AddAssert($"tail judged as {result}", () => judgementResults.Single(j => j.HitObject is TailNote).Type == result); + => AddAssert($"tail judged as {result}", () => judgementResults.Single(j => j.HitObject is TailNote).Type, () => Is.EqualTo(result)); private void assertNoteJudgement(HitResult result) - => AddAssert($"hold note judged as {result}", () => judgementResults.Single(j => j.HitObject is HoldNote).Type == result); + => AddAssert($"hold note judged as {result}", () => judgementResults.Single(j => j.HitObject is HoldNote).Type, () => Is.EqualTo(result)); private void assertTickJudgement(HitResult result) - => AddAssert($"any tick judged as {result}", () => judgementResults.Where(j => j.HitObject is HoldNoteTick).Any(j => j.Type == result)); + => AddAssert($"any tick judged as {result}", () => judgementResults.Where(j => j.HitObject is HoldNoteTick).Select(j => j.Type), () => Does.Contain(result)); private void assertLastTickJudgement(HitResult result) - => AddAssert($"last tick judged as {result}", () => judgementResults.Last(j => j.HitObject is HoldNoteTick).Type == result); + => AddAssert($"last tick judged as {result}", () => judgementResults.Last(j => j.HitObject is HoldNoteTick).Type, () => Is.EqualTo(result)); private ScoreAccessibleReplayPlayer currentPlayer; From a2b505f4c09f94854a5ef3f6dedc831ad6452a3c Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Tue, 22 Nov 2022 00:31:22 -0800 Subject: [PATCH 2353/2686] Use a direct `Lighten` instead of >1f Color4 values --- osu.Game/Overlays/Chat/ChatLine.cs | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index af5fa89ca1..bfbffabd2b 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -61,6 +61,8 @@ namespace osu.Game.Overlays.Chat private OsuSpriteText username = null!; + private Drawable usernameColouredDrawable = null!; + private Container? highlight; private readonly Bindable prefer24HourTime = new Bindable(); @@ -89,6 +91,10 @@ namespace osu.Game.Overlays.Chat ? Color4Extensions.FromHex(message.Sender.Colour) : username_colours[message.Sender.Id % username_colours.Length]; + // this can be either the username sprite text or a container + // around it depending on which branch is taken in createUsername() + var usernameDrawable = createUsername(); + InternalChild = new GridContainer { RelativeSizeAxes = Axes.X, @@ -113,13 +119,13 @@ namespace osu.Game.Overlays.Chat Colour = colourProvider?.Background1 ?? Colour4.White, AlwaysPresent = true, }, - new MessageSender(message.Sender) + new MessageSender(message.Sender, usernameColouredDrawable) { Width = UsernameWidth, AutoSizeAxes = Axes.Y, Origin = Anchor.TopRight, Anchor = Anchor.TopRight, - Child = createUsername(), + Child = usernameDrawable, Margin = new MarginPadding { Horizontal = Spacing }, }, ContentFlow = new LinkFlowContainer(t => @@ -198,7 +204,6 @@ namespace osu.Game.Overlays.Chat username = new OsuSpriteText { Shadow = false, - Colour = senderHasColour ? colours.ChatBlue : usernameColour, Truncate = true, EllipsisString = "…", Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Bold, italics: true), @@ -208,7 +213,13 @@ namespace osu.Game.Overlays.Chat }; if (!senderHasColour) + { + usernameColouredDrawable = username; + usernameColouredDrawable.Colour = usernameColour; return username; + } + + username.Colour = colours.ChatBlue; // Background effect return new Container @@ -233,7 +244,7 @@ namespace osu.Game.Overlays.Chat CornerRadius = 4, Children = new Drawable[] { - new Box + usernameColouredDrawable = new Box { RelativeSizeAxes = Axes.Both, Colour = usernameColour, @@ -252,15 +263,19 @@ namespace osu.Game.Overlays.Chat private class MessageSender : OsuClickableContainer, IHasContextMenu { private readonly APIUser sender; + private readonly Drawable colouredDrawable; + private readonly Color4 defaultColour; private Action startChatAction = null!; [Resolved] private IAPIProvider api { get; set; } = null!; - public MessageSender(APIUser sender) + public MessageSender(APIUser sender, Drawable colouredDrawable) { this.sender = sender; + this.colouredDrawable = colouredDrawable; + defaultColour = colouredDrawable.Colour; } [BackgroundDependencyLoader] @@ -295,7 +310,7 @@ namespace osu.Game.Overlays.Chat protected override bool OnHover(HoverEvent e) { - this.FadeColour(new Color4(1.4f, 1.4f, 1.4f, 1), 150, Easing.OutQuint); + colouredDrawable.FadeColour(defaultColour.Lighten(0.4f), 150, Easing.OutQuint); return base.OnHover(e); } @@ -304,7 +319,7 @@ namespace osu.Game.Overlays.Chat { base.OnHoverLost(e); - this.FadeColour(Color4.White, 250, Easing.OutQuint); + colouredDrawable.FadeColour(defaultColour, 250, Easing.OutQuint); } } From de163b2bb55752d48b405a5fd3ed3f2f6104b172 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 22 Nov 2022 19:48:55 +0900 Subject: [PATCH 2354/2686] Change song select to only allow volume adjusting if alt is held while scrolling --- osu.Game/Screens/Select/SongSelect.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 5d5019567a..18ea0f69a2 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -304,6 +304,16 @@ namespace osu.Game.Screens.Select modSelectOverlayRegistration = OverlayManager?.RegisterBlockingOverlay(ModSelect); } + protected override bool OnScroll(ScrollEvent e) + { + // Match stable behaviour of only alt-scroll adjusting volume. + // Supporting scroll adjust without a modifier key just feels bad, since there are so many scrollable elements on the screen. + if (!e.CurrentState.Keyboard.AltPressed) + return true; + + return base.OnScroll(e); + } + /// /// Creates the buttons to be displayed in the footer. /// From 76bb529cfa750daf08d15f61f32e034b49ecbd83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 21 Nov 2022 20:30:42 +0100 Subject: [PATCH 2355/2686] Add test for local echo adding day separator --- .../Visual/Online/TestSceneDrawableChannel.cs | 87 +++++++++++++++++++ osu.Game/Online/Chat/StandAloneChatDisplay.cs | 4 +- osu.Game/Overlays/Chat/DaySeparator.cs | 8 +- 3 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs new file mode 100644 index 0000000000..dc1e00ee8f --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs @@ -0,0 +1,87 @@ +// 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.Linq; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Chat; +using osu.Game.Overlays.Chat; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public class TestSceneDrawableChannel : OsuTestScene + { + private Channel channel = null!; + private DrawableChannel drawableChannel = null!; + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create channel", () => channel = new Channel + { + Id = 1, + Name = "Test channel" + }); + AddStep("create drawable channel", () => Child = drawableChannel = new DrawableChannel(channel) + { + RelativeSizeAxes = Axes.Both + }); + } + + [Test] + public void TestDaySeparators() + { + var localUser = new APIUser + { + Id = 3, + Username = "LocalUser" + }; + string uuid = Guid.NewGuid().ToString(); + AddStep("add local echo message", () => channel.AddLocalEcho(new LocalEchoMessage + { + Sender = localUser, + Content = "Hi there all!", + Timestamp = new DateTimeOffset(2022, 11, 21, 20, 11, 13, TimeSpan.Zero), + Uuid = uuid + })); + AddUntilStep("one day separator present", () => drawableChannel.ChildrenOfType().Count() == 1); + + AddStep("add two prior messages to channel", () => channel.AddNewMessages( + new Message(1) + { + Sender = new APIUser + { + Id = 1, + Username = "TestUser" + }, + Content = "This is a message", + Timestamp = new DateTimeOffset(2021, 10, 10, 13, 33, 23, TimeSpan.Zero), + }, + new Message(2) + { + Sender = new APIUser + { + Id = 2, + Username = "TestUser2" + }, + Content = "This is another message", + Timestamp = new DateTimeOffset(2021, 10, 11, 13, 33, 23, TimeSpan.Zero) + })); + AddUntilStep("three day separators present", () => drawableChannel.ChildrenOfType().Count() == 3); + + AddStep("resolve pending message", () => channel.ReplaceMessage(channel.Messages.OfType().Single(), new Message(3) + { + Sender = localUser, + Content = "Hi there all!", + Timestamp = new DateTimeOffset(2022, 11, 22, 20, 11, 16, TimeSpan.Zero), + Uuid = uuid + })); + AddUntilStep("three day separators present", () => drawableChannel.ChildrenOfType().Count() == 3); + AddAssert("last day separator is from correct day", () => drawableChannel.ChildrenOfType().Last().Date.Date == new DateTime(2022, 11, 22)); + } + } +} diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 81db3f0d53..e45a14136d 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -174,8 +174,8 @@ namespace osu.Game.Online.Chat protected override float Spacing => 5; protected override float DateAlign => 125; - public StandAloneDaySeparator(DateTimeOffset time) - : base(time) + public StandAloneDaySeparator(DateTimeOffset date) + : base(date) { } diff --git a/osu.Game/Overlays/Chat/DaySeparator.cs b/osu.Game/Overlays/Chat/DaySeparator.cs index be0b53785c..d68f325738 100644 --- a/osu.Game/Overlays/Chat/DaySeparator.cs +++ b/osu.Game/Overlays/Chat/DaySeparator.cs @@ -22,14 +22,14 @@ namespace osu.Game.Overlays.Chat protected virtual float Spacing => 15; - private readonly DateTimeOffset time; + public readonly DateTimeOffset Date; [Resolved(CanBeNull = true)] private OverlayColourProvider? colourProvider { get; set; } - public DaySeparator(DateTimeOffset time) + public DaySeparator(DateTimeOffset date) { - this.time = time; + Date = date; Height = 40; } @@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Chat { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Text = time.ToLocalTime().ToLocalisableString(@"dd MMMM yyyy").ToUpper(), + Text = Date.ToLocalTime().ToLocalisableString(@"dd MMMM yyyy").ToUpper(), Font = OsuFont.Torus.With(size: TextSize, weight: FontWeight.SemiBold), Colour = colourProvider?.Content1 ?? Colour4.White, }, From 5343f6922cbfdae09fb87654e2aa1d198a71c270 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Tue, 22 Nov 2022 17:22:00 +0100 Subject: [PATCH 2356/2686] Add legacy circle piece animations based on combo --- .../Skinning/Legacy/LegacyCirclePiece.cs | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs index 6b2576a564..2a260b8cb3 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs @@ -2,13 +2,16 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Animations; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; +using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Screens.Play; using osu.Game.Skinning; using osuTK; using osuTK.Graphics; @@ -18,6 +21,13 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy public class LegacyCirclePiece : CompositeDrawable, IHasAccentColour { private Drawable backgroundLayer = null!; + private Drawable? foregroundLayer; + + private Bindable currentCombo { get; } = new BindableInt(); + + private int animationFrame; + private int multiplier; + private double beatLength; // required for editor blueprints (not sure why these circle pieces are zero size). public override Quad ScreenSpaceDrawQuad => backgroundLayer.ScreenSpaceDrawQuad; @@ -27,6 +37,12 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy RelativeSizeAxes = Axes.Both; } + [Resolved] + private GameplayState? gameplayState { get; set; } + + [Resolved] + private IBeatSyncProvider? beatSyncProvider { get; set; } + [BackgroundDependencyLoader] private void load(ISkinSource skin, DrawableHitObject drawableHitObject) { @@ -45,7 +61,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy // backgroundLayer is guaranteed to exist due to the pre-check in TaikoLegacySkinTransformer. AddInternal(backgroundLayer = new LegacyKiaiFlashingDrawable(() => getDrawableFor("circle"))); - var foregroundLayer = getDrawableFor("circleoverlay"); + foregroundLayer = getDrawableFor("circleoverlay"); if (foregroundLayer != null) AddInternal(foregroundLayer); @@ -58,6 +74,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy c.Anchor = Anchor.Centre; c.Origin = Anchor.Centre; } + + if (gameplayState != null) + currentCombo.BindTo(gameplayState.ScoreProcessor.Combo); } protected override void LoadComplete() @@ -74,6 +93,29 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy // This ensures they are scaled relative to each other but also match the expected DrawableHit size. foreach (var c in InternalChildren) c.Scale = new Vector2(DrawHeight / 128); + + if (currentCombo.Value >= 150) + { + multiplier = 2; + } + else if (currentCombo.Value >= 50) + { + multiplier = 1; + } + else + { + (foregroundLayer as IFramedAnimation)?.GotoFrame(0); + return; + } + + if (beatSyncProvider?.ControlPoints != null) + { + beatLength = beatSyncProvider.ControlPoints.TimingPointAt(LifetimeStart).BeatLength; + + animationFrame = Time.Current % ((beatLength * 2) / multiplier) >= beatLength / multiplier ? 0 : 1; + + (foregroundLayer as IFramedAnimation)?.GotoFrame(animationFrame); + } } private Color4 accentColour; From db34fa99b1adc5a1d422da1b93e129fdcda31dbd Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Tue, 22 Nov 2022 17:22:34 +0100 Subject: [PATCH 2357/2686] Add tests and clean up inefficient code --- .../Skinning/TestSceneDrawableDrumRoll.cs | 25 ++++++++- .../Skinning/TestSceneDrawableDrumRollKiai.cs | 30 ---------- .../Skinning/TestSceneDrawableHit.cs | 55 +++++++++++++++++++ .../Skinning/TestSceneDrawableHitKiai.cs | 30 ---------- 4 files changed, 79 insertions(+), 61 deletions(-) delete mode 100644 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRollKiai.cs delete mode 100644 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHitKiai.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs index e42dc254ac..7a3439d8eb 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning }; [Test] - public void DrumrollTest() + public void TestDrumroll() { AddStep("Drum roll", () => SetContents(_ => { @@ -57,6 +57,14 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning })); } + [Test] + public void TestDrumrollKiai() + { + AddStep("Create beatmap", createBeatmap); + + TestDrumroll(); + } + private DrumRoll createDrumRollAtCurrentTime(bool strong = false) { var drumroll = new DrumRoll @@ -73,5 +81,20 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning return drumroll; } + + private void createBeatmap() + { + var controlPointInfo = new ControlPointInfo(); + + controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); + controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); + + Beatmap.Value = CreateWorkingBeatmap(new Beatmap + { + ControlPointInfo = controlPointInfo + }); + + Beatmap.Value.Track.Start(); + } } } diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRollKiai.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRollKiai.cs deleted file mode 100644 index 53977150e7..0000000000 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRollKiai.cs +++ /dev/null @@ -1,30 +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 NUnit.Framework; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Beatmaps; - -namespace osu.Game.Rulesets.Taiko.Tests.Skinning -{ - [TestFixture] - public class TestSceneDrawableDrumRollKiai : TestSceneDrawableDrumRoll - { - [SetUp] - public void SetUp() => Schedule(() => - { - var controlPointInfo = new ControlPointInfo(); - - controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); - controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); - - Beatmap.Value = CreateWorkingBeatmap(new Beatmap - { - ControlPointInfo = controlPointInfo - }); - - // track needs to be playing for BeatSyncedContainer to work. - Beatmap.Value.Track.Start(); - }); - } -} diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs index eb2b6c1d74..3902a3123b 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs @@ -4,17 +4,23 @@ #nullable disable using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Objects.Drawables; +using osu.Game.Screens.Play; +using osu.Game.Tests.Gameplay; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { [TestFixture] public class TestSceneDrawableHit : TaikoSkinnableTestScene { + [Cached] + private GameplayState gameplayState = TestGameplayState.Create(new TaikoRuleset()); + [Test] public void TestHits() { @@ -43,6 +49,38 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning })); } + [Test] + public void TestHitKiai() + { + AddStep("Create beatmap", () => createBeatmap(true)); + + TestHits(); + } + + [Test] + public void TestHitAnimationSlow() + { + AddStep("Create beatmap", () => createBeatmap(false)); + + AddStep("Reset combo", () => gameplayState.ScoreProcessor.Combo.Value = 0); + + AddRepeatStep("Increase combo", () => gameplayState.ScoreProcessor.Combo.Value++, 50); + + TestHits(); + } + + [Test] + public void TestHitAnimationFast() + { + AddStep("Create beatmap", () => createBeatmap(false)); + + AddStep("Reset combo", () => gameplayState.ScoreProcessor.Combo.Value = 0); + + AddRepeatStep("Increase combo", () => gameplayState.ScoreProcessor.Combo.Value++, 150); + + TestHits(); + } + private Hit createHitAtCurrentTime(bool strong = false, bool rim = false) { var hit = new Hit @@ -56,5 +94,22 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning return hit; } + + private void createBeatmap(bool includeKiai) + { + var controlPointInfo = new ControlPointInfo(); + + controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); + + if (includeKiai) + controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); + + Beatmap.Value = CreateWorkingBeatmap(new Beatmap + { + ControlPointInfo = controlPointInfo + }); + + Beatmap.Value.Track.Start(); + } } } diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHitKiai.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHitKiai.cs deleted file mode 100644 index fac0530749..0000000000 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHitKiai.cs +++ /dev/null @@ -1,30 +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 NUnit.Framework; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; - -namespace osu.Game.Rulesets.Taiko.Tests.Skinning -{ - [TestFixture] - public class TestSceneDrawableHitKiai : TestSceneDrawableHit - { - [SetUp] - public void SetUp() => Schedule(() => - { - var controlPointInfo = new ControlPointInfo(); - - controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); - controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); - - Beatmap.Value = CreateWorkingBeatmap(new Beatmap - { - ControlPointInfo = controlPointInfo - }); - - // track needs to be playing for BeatSyncedContainer to work. - Beatmap.Value.Track.Start(); - }); - } -} From 39934bccd6f78d7d328b1b7b9901147304a9c08b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Nov 2022 19:47:41 +0100 Subject: [PATCH 2358/2686] Add back removed test coverage --- .../UserInterface/TestSceneHistoryTextBox.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs index 78b1bdb18c..8ed5dd43cc 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs @@ -62,6 +62,68 @@ namespace osu.Game.Tests.Visual.UserInterface }); } + [Test] + public void TestEmptyHistory() + { + AddStep("Set text", () => box.Text = temp); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Text is unchanged", () => box.Text == temp); + + AddStep("Move up", () => InputManager.Key(Key.Up)); + AddAssert("Text is unchanged", () => box.Text == temp); + } + + [Test] + public void TestPartialHistory() + { + addMessages(3); + AddStep("Set text", () => box.Text = temp); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Text is unchanged", () => box.Text == temp); + + AddRepeatStep("Move up", () => InputManager.Key(Key.Up), 3); + AddAssert("Same as 1st message", () => box.Text == "Message 1"); + + AddStep("Move up", () => InputManager.Key(Key.Up)); + AddAssert("Same as 1st message", () => box.Text == "Message 1"); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Same as 2nd message", () => box.Text == "Message 2"); + + AddRepeatStep("Move down", () => InputManager.Key(Key.Down), 2); + AddAssert("Temporary message restored", () => box.Text == temp); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Text is unchanged", () => box.Text == temp); + } + + [Test] + public void TestFullHistory() + { + addMessages(7); + AddStep("Set text", () => box.Text = temp); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Text is unchanged", () => box.Text == temp); + + AddRepeatStep("Move up", () => InputManager.Key(Key.Up), 5); + AddAssert("Same as 3rd message", () => box.Text == "Message 3"); + + AddStep("Move up", () => InputManager.Key(Key.Up)); + AddAssert("Same as 3rd message", () => box.Text == "Message 3"); + + AddRepeatStep("Move down", () => InputManager.Key(Key.Down), 4); + AddAssert("Same as 7th message", () => box.Text == "Message 7"); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Temporary message restored", () => box.Text == temp); + + AddStep("Move down", () => InputManager.Key(Key.Down)); + AddAssert("Text is unchanged", () => box.Text == temp); + } + [Test] public void TestChangedHistory() { From 8dbc38e17a83e3737c17b0faa72dc047a5fd95f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Nov 2022 20:14:22 +0100 Subject: [PATCH 2359/2686] Remove unused setter --- osu.Game/Utils/LimitedCapacityQueue.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/osu.Game/Utils/LimitedCapacityQueue.cs b/osu.Game/Utils/LimitedCapacityQueue.cs index 8f3b36a059..86a106a678 100644 --- a/osu.Game/Utils/LimitedCapacityQueue.cs +++ b/osu.Game/Utils/LimitedCapacityQueue.cs @@ -103,13 +103,6 @@ namespace osu.Game.Utils return array[(start + index) % capacity]; } - set - { - if (index < 0 || index >= Count) - throw new ArgumentOutOfRangeException(nameof(index)); - - array[(start + index) % capacity] = value; - } } /// From 5a5b0ed4ef67ded0211486baf887ac251645b931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Nov 2022 20:28:41 +0100 Subject: [PATCH 2360/2686] Restructure tests not to call each other Bit weird to have tests call other tests. Private helper methods is better, if unavoidable. --- .../Skinning/TestSceneDrawableDrumRoll.cs | 18 ++--- .../Skinning/TestSceneDrawableHit.cs | 68 +++++++++---------- 2 files changed, 40 insertions(+), 46 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs index 7a3439d8eb..25cb3f7886 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs @@ -26,8 +26,10 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning }; [Test] - public void TestDrumroll() + public void TestDrumroll([Values] bool withKiai) { + AddStep("set up beatmap", () => setUpBeatmap(withKiai)); + AddStep("Drum roll", () => SetContents(_ => { var hoc = new ScrollingHitObjectContainer(); @@ -57,14 +59,6 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning })); } - [Test] - public void TestDrumrollKiai() - { - AddStep("Create beatmap", createBeatmap); - - TestDrumroll(); - } - private DrumRoll createDrumRollAtCurrentTime(bool strong = false) { var drumroll = new DrumRoll @@ -82,12 +76,14 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning return drumroll; } - private void createBeatmap() + private void setUpBeatmap(bool withKiai) { var controlPointInfo = new ControlPointInfo(); controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); - controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); + + if (withKiai) + controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); Beatmap.Value = CreateWorkingBeatmap(new Beatmap { diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs index 3902a3123b..b13255b31c 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs @@ -22,7 +22,37 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning private GameplayState gameplayState = TestGameplayState.Create(new TaikoRuleset()); [Test] - public void TestHits() + public void TestHits([Values] bool withKiai) + { + AddStep("Create beatmap", () => setUpBeatmap(withKiai)); + addHitSteps(); + } + + [Test] + public void TestHitAnimationSlow() + { + AddStep("Create beatmap", () => setUpBeatmap(false)); + + AddStep("Reset combo", () => gameplayState.ScoreProcessor.Combo.Value = 0); + + AddRepeatStep("Increase combo", () => gameplayState.ScoreProcessor.Combo.Value++, 50); + + addHitSteps(); + } + + [Test] + public void TestHitAnimationFast() + { + AddStep("Create beatmap", () => setUpBeatmap(false)); + + AddStep("Reset combo", () => gameplayState.ScoreProcessor.Combo.Value = 0); + + AddRepeatStep("Increase combo", () => gameplayState.ScoreProcessor.Combo.Value++, 150); + + addHitSteps(); + } + + private void addHitSteps() { AddStep("Centre hit", () => SetContents(_ => new DrawableHit(createHitAtCurrentTime()) { @@ -49,38 +79,6 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning })); } - [Test] - public void TestHitKiai() - { - AddStep("Create beatmap", () => createBeatmap(true)); - - TestHits(); - } - - [Test] - public void TestHitAnimationSlow() - { - AddStep("Create beatmap", () => createBeatmap(false)); - - AddStep("Reset combo", () => gameplayState.ScoreProcessor.Combo.Value = 0); - - AddRepeatStep("Increase combo", () => gameplayState.ScoreProcessor.Combo.Value++, 50); - - TestHits(); - } - - [Test] - public void TestHitAnimationFast() - { - AddStep("Create beatmap", () => createBeatmap(false)); - - AddStep("Reset combo", () => gameplayState.ScoreProcessor.Combo.Value = 0); - - AddRepeatStep("Increase combo", () => gameplayState.ScoreProcessor.Combo.Value++, 150); - - TestHits(); - } - private Hit createHitAtCurrentTime(bool strong = false, bool rim = false) { var hit = new Hit @@ -95,13 +93,13 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning return hit; } - private void createBeatmap(bool includeKiai) + private void setUpBeatmap(bool withKiai) { var controlPointInfo = new ControlPointInfo(); controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); - if (includeKiai) + if (withKiai) controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); Beatmap.Value = CreateWorkingBeatmap(new Beatmap From 8ac0a759f01b92c665d6108fc1271e5f70590475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Nov 2022 20:30:27 +0100 Subject: [PATCH 2361/2686] Set combo immediately rather than via repeat steps Doesn't help anyone to be waiting literal minutes for combo to hit 50 or 150 in a test scene supposed to quickly visually demonstrate a component. Doesn't help for CI runtime, either. --- .../Skinning/TestSceneDrawableHit.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs index b13255b31c..65a59be89b 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs @@ -33,10 +33,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning { AddStep("Create beatmap", () => setUpBeatmap(false)); - AddStep("Reset combo", () => gameplayState.ScoreProcessor.Combo.Value = 0); - - AddRepeatStep("Increase combo", () => gameplayState.ScoreProcessor.Combo.Value++, 50); - + AddStep("Set 50 combo", () => gameplayState.ScoreProcessor.Combo.Value = 50); addHitSteps(); } @@ -45,10 +42,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning { AddStep("Create beatmap", () => setUpBeatmap(false)); - AddStep("Reset combo", () => gameplayState.ScoreProcessor.Combo.Value = 0); - - AddRepeatStep("Increase combo", () => gameplayState.ScoreProcessor.Combo.Value++, 150); - + AddStep("Set 150 combo", () => gameplayState.ScoreProcessor.Combo.Value = 150); addHitSteps(); } From 38f2a27f537e12d9deef306e327715983afecb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Nov 2022 20:34:43 +0100 Subject: [PATCH 2362/2686] Split animation logic to its own method Also add a guard, to bypass all of it if the foreground layer is not in fact animatable. --- .../Skinning/Legacy/LegacyCirclePiece.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs index 2a260b8cb3..c8dc29f444 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs @@ -26,7 +26,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private Bindable currentCombo { get; } = new BindableInt(); private int animationFrame; - private int multiplier; private double beatLength; // required for editor blueprints (not sure why these circle pieces are zero size). @@ -94,6 +93,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy foreach (var c in InternalChildren) c.Scale = new Vector2(DrawHeight / 128); + if (foregroundLayer is IFramedAnimation animatableForegroundLayer) + animateForegroundLayer(animatableForegroundLayer); + } + + private void animateForegroundLayer(IFramedAnimation animatableForegroundLayer) + { + int multiplier; + if (currentCombo.Value >= 150) { multiplier = 2; @@ -104,7 +111,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } else { - (foregroundLayer as IFramedAnimation)?.GotoFrame(0); + animatableForegroundLayer.GotoFrame(0); return; } @@ -114,7 +121,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy animationFrame = Time.Current % ((beatLength * 2) / multiplier) >= beatLength / multiplier ? 0 : 1; - (foregroundLayer as IFramedAnimation)?.GotoFrame(animationFrame); + animatableForegroundLayer.GotoFrame(animationFrame); } } From ce7af0df637b3098c8e5eca1d9d137bc5fe2ed94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Nov 2022 20:39:22 +0100 Subject: [PATCH 2363/2686] Always use current timing point for circle piece animation Using `LifetimeStart` seemed arbitrary and wrong not only in a compatibility-with-stable sense, but also in a general sanity sense (why would each object potentially be using a different timing point to animate?) --- osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs index c8dc29f444..03d89d269b 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs @@ -117,7 +117,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy if (beatSyncProvider?.ControlPoints != null) { - beatLength = beatSyncProvider.ControlPoints.TimingPointAt(LifetimeStart).BeatLength; + beatLength = beatSyncProvider.ControlPoints.TimingPointAt(Time.Current).BeatLength; animationFrame = Time.Current % ((beatLength * 2) / multiplier) >= beatLength / multiplier ? 0 : 1; From 675e32df5761cd81c7365aa7aaac7116bcd6da9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Nov 2022 20:43:22 +0100 Subject: [PATCH 2364/2686] Add test steps for testing combo reset to 0 --- osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs index 65a59be89b..adfd27c5d6 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs @@ -35,6 +35,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning AddStep("Set 50 combo", () => gameplayState.ScoreProcessor.Combo.Value = 50); addHitSteps(); + AddStep("Reset combo", () => gameplayState.ScoreProcessor.Combo.Value = 0); } [Test] @@ -44,6 +45,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning AddStep("Set 150 combo", () => gameplayState.ScoreProcessor.Combo.Value = 150); addHitSteps(); + AddStep("Reset combo", () => gameplayState.ScoreProcessor.Combo.Value = 0); } private void addHitSteps() From 6e9d163c7240eba2964e4043229fa5f7bdcacf0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 22 Nov 2022 20:56:07 +0100 Subject: [PATCH 2365/2686] Specify `canBeNull: true` in `[Resolved]` for now --- osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs index 03d89d269b..a5867ff51c 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs @@ -36,10 +36,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy RelativeSizeAxes = Axes.Both; } - [Resolved] + [Resolved(canBeNull: true)] private GameplayState? gameplayState { get; set; } - [Resolved] + [Resolved(canBeNull: true)] private IBeatSyncProvider? beatSyncProvider { get; set; } [BackgroundDependencyLoader] From d146f86511ac3b34e995c586ad6889cc2c2ef194 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 15:39:56 +0900 Subject: [PATCH 2366/2686] Fix crash when hitting 'T' to tap timing while no timing point is selected --- osu.Game/Screens/Edit/Timing/TapButton.cs | 3 +++ osu.Game/Screens/Edit/Timing/TapTimingControl.cs | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 151c3cea2e..2944eea4fe 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -295,6 +295,9 @@ namespace osu.Game.Screens.Edit.Timing private void handleTap() { + if (selectedGroup?.Value == null) + return; + tapTimings.Add(Clock.CurrentTime); if (tapTimings.Count > initial_taps_to_ignore + max_taps_to_consider) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index abc73851e4..daa3168746 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -183,12 +183,18 @@ namespace osu.Game.Screens.Edit.Timing private void start() { + if (selectedGroup.Value == null) + return; + editorClock.Seek(selectedGroup.Value.Time); editorClock.Start(); } private void reset() { + if (selectedGroup.Value == null) + return; + editorClock.Stop(); editorClock.Seek(selectedGroup.Value.Time); } From 9b9b8a597773e9a4dfab256422c268056ad6878d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 15:59:31 +0900 Subject: [PATCH 2367/2686] Add ability to seek between control points in editor using down/up arrows Matches stable. Addresses #21376. --- .../Visual/Editing/TestSceneEditorSeeking.cs | 21 +++++++++++++++++++ osu.Game/Screens/Edit/Editor.cs | 18 ++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs index 924396ce03..14679ae01d 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs @@ -25,6 +25,7 @@ namespace osu.Game.Tests.Visual.Editing beatmap.ControlPointInfo.Clear(); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }); beatmap.ControlPointInfo.Add(2000, new TimingControlPoint { BeatLength = 500 }); + beatmap.ControlPointInfo.Add(20000, new TimingControlPoint { BeatLength = 500 }); return beatmap; } @@ -116,6 +117,26 @@ namespace osu.Game.Tests.Visual.Editing pressAndCheckTime(Key.Right, 3000); } + [Test] + public void TestSeekBetweenControlPoints() + { + AddStep("seek to 0", () => EditorClock.Seek(0)); + AddAssert("time is 0", () => EditorClock.CurrentTime == 0); + + // already at first control point, noop + pressAndCheckTime(Key.Down, 0); + + pressAndCheckTime(Key.Up, 2000); + + pressAndCheckTime(Key.Up, 20000); + // at last control point, noop + pressAndCheckTime(Key.Up, 20000); + + pressAndCheckTime(Key.Down, 2000); + pressAndCheckTime(Key.Down, 0); + pressAndCheckTime(Key.Down, 0); + } + private void pressAndCheckTime(Key key, double expectedTime) { AddStep($"press {key}", () => InputManager.Key(key)); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 4c44117581..7c0e021ff9 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -499,6 +499,14 @@ namespace osu.Game.Screens.Edit seek(e, 1); return true; + case Key.Down: + seekControlPoint(-1); + return true; + + case Key.Up: + seekControlPoint(1); + return true; + // Track traversal keys. // Matching osu-stable implementations. case Key.Z: @@ -892,6 +900,16 @@ namespace osu.Game.Screens.Edit } } + private void seekControlPoint(int direction) + { + var found = direction < 1 + ? editorBeatmap.ControlPointInfo.AllControlPoints.LastOrDefault(p => p.Time < clock.CurrentTime) + : editorBeatmap.ControlPointInfo.AllControlPoints.FirstOrDefault(p => p.Time > clock.CurrentTime); + + if (found != null) + clock.Seek(found.Time); + } + private void seek(UIEvent e, int direction) { double amount = e.ShiftPressed ? 4 : 1; From b89689a34a4dd719c18b73b29180463170f5a7e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 16:31:50 +0900 Subject: [PATCH 2368/2686] Rename class and reword settings text/tooltips to avoid clashing with other naming --- ...nfoDrawable.cs => BeatmapAttributeText.cs} | 83 +++++++++---------- osu.Game/Skinning/Components/TextElement.cs | 2 +- 2 files changed, 42 insertions(+), 43 deletions(-) rename osu.Game/Skinning/Components/{BeatmapInfoDrawable.cs => BeatmapAttributeText.cs} (57%) diff --git a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs similarity index 57% rename from osu.Game/Skinning/Components/BeatmapInfoDrawable.cs rename to osu.Game/Skinning/Components/BeatmapAttributeText.cs index 379bdec333..6520130e75 100644 --- a/osu.Game/Skinning/Components/BeatmapInfoDrawable.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -22,47 +22,46 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Skinning.Components { [UsedImplicitly] - public class BeatmapInfoDrawable : Container, ISkinnableDrawable + public class BeatmapAttributeText : Container, ISkinnableDrawable { - private const BeatmapInfo default_beatmap_info = BeatmapInfo.StarRating; public bool UsesFixedAnchor { get; set; } - [SettingSource("Tracked Beatmap Info/Label", "Which part of the BeatmapInformation should be displayed.")] - public Bindable Type { get; } = new Bindable(default_beatmap_info); + [SettingSource("Attribute", "The attribute to be displayed.")] + public Bindable Attribute { get; } = new Bindable(BeatmapAttribute.StarRating); - [SettingSource("Template", "Bypass the restriction of 1 Info per element. Format is '{'+Type+'}' to substitue values. e.g. '{Song}' ")] + [SettingSource("Template", "Supports {Label} and {Value}, but also including arbitrary attributes like {StarRating} (see attribute list for supported values).")] public Bindable Template { get; set; } = new Bindable("{Label}: {Value}"); [Resolved] private IBindable beatmap { get; set; } = null!; - private readonly Dictionary valueDictionary = new Dictionary(); - private static readonly ImmutableDictionary label_dictionary; + private readonly Dictionary valueDictionary = new Dictionary(); + private static readonly ImmutableDictionary label_dictionary; private readonly OsuSpriteText text; - static BeatmapInfoDrawable() + static BeatmapAttributeText() { - label_dictionary = new Dictionary + label_dictionary = new Dictionary { - [BeatmapInfo.CircleSize] = BeatmapsetsStrings.ShowStatsCs, - [BeatmapInfo.Accuracy] = BeatmapsetsStrings.ShowStatsAccuracy, - [BeatmapInfo.HPDrain] = BeatmapsetsStrings.ShowStatsDrain, - [BeatmapInfo.ApproachRate] = BeatmapsetsStrings.ShowStatsAr, - [BeatmapInfo.StarRating] = BeatmapsetsStrings.ShowStatsStars, - [BeatmapInfo.Song] = EditorSetupStrings.Title, - [BeatmapInfo.Artist] = EditorSetupStrings.Artist, - [BeatmapInfo.Difficulty] = EditorSetupStrings.DifficultyHeader, + [BeatmapAttribute.CircleSize] = BeatmapsetsStrings.ShowStatsCs, + [BeatmapAttribute.Accuracy] = BeatmapsetsStrings.ShowStatsAccuracy, + [BeatmapAttribute.HPDrain] = BeatmapsetsStrings.ShowStatsDrain, + [BeatmapAttribute.ApproachRate] = BeatmapsetsStrings.ShowStatsAr, + [BeatmapAttribute.StarRating] = BeatmapsetsStrings.ShowStatsStars, + [BeatmapAttribute.Song] = EditorSetupStrings.Title, + [BeatmapAttribute.Artist] = EditorSetupStrings.Artist, + [BeatmapAttribute.Difficulty] = EditorSetupStrings.DifficultyHeader, //todo: is there a good alternative, to NotificationsOptionsMapping? - [BeatmapInfo.Mapper] = AccountsStrings.NotificationsOptionsMapping, - [BeatmapInfo.Length] = ArtistStrings.TracklistLength, - [BeatmapInfo.Status] = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault, - [BeatmapInfo.BPM] = BeatmapsetsStrings.ShowStatsBpm, - [BeatmapInfo.None] = BeatmapInfo.None.ToString() + [BeatmapAttribute.Mapper] = AccountsStrings.NotificationsOptionsMapping, + [BeatmapAttribute.Length] = ArtistStrings.TracklistLength, + [BeatmapAttribute.Status] = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault, + [BeatmapAttribute.BPM] = BeatmapsetsStrings.ShowStatsBpm, + [BeatmapAttribute.None] = BeatmapAttribute.None.ToString() }.ToImmutableDictionary(); } - public BeatmapInfoDrawable() + public BeatmapAttributeText() { AutoSizeAxes = Axes.Both; InternalChildren = new Drawable[] @@ -76,7 +75,7 @@ namespace osu.Game.Skinning.Components } }; - foreach (var type in Enum.GetValues(typeof(BeatmapInfo)).Cast()) + foreach (var type in Enum.GetValues(typeof(BeatmapAttribute)).Cast()) { valueDictionary[type] = type.ToString(); } @@ -85,7 +84,7 @@ namespace osu.Game.Skinning.Components protected override void LoadComplete() { base.LoadComplete(); - Type.BindValueChanged(_ => updateLabel()); + Attribute.BindValueChanged(_ => updateLabel()); Template.BindValueChanged(f => updateLabel(), true); beatmap.BindValueChanged(b => { @@ -96,10 +95,10 @@ namespace osu.Game.Skinning.Components private void updateLabel() { - string newText = Template.Value.Replace("{Label}", label_dictionary[Type.Value].ToString()) - .Replace("{Value}", valueDictionary[Type.Value].ToString()); + string newText = Template.Value.Replace("{Label}", label_dictionary[Attribute.Value].ToString()) + .Replace("{Value}", valueDictionary[Attribute.Value].ToString()); - foreach (var type in Enum.GetValues(typeof(BeatmapInfo)).Cast()) + foreach (var type in Enum.GetValues(typeof(BeatmapAttribute)).Cast()) { newText = newText.Replace("{" + type + "}", valueDictionary[type].ToString()); } @@ -111,34 +110,34 @@ namespace osu.Game.Skinning.Components { //update cs double cs = workingBeatmap.BeatmapInfo.Difficulty.CircleSize; - valueDictionary[BeatmapInfo.CircleSize] = cs.ToString("F2"); + valueDictionary[BeatmapAttribute.CircleSize] = cs.ToString("F2"); //update HP double hp = workingBeatmap.BeatmapInfo.Difficulty.DrainRate; - valueDictionary[BeatmapInfo.HPDrain] = hp.ToString("F2"); + valueDictionary[BeatmapAttribute.HPDrain] = hp.ToString("F2"); //update od double od = workingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty; - valueDictionary[BeatmapInfo.Accuracy] = od.ToString("F2"); + valueDictionary[BeatmapAttribute.Accuracy] = od.ToString("F2"); //update ar double ar = workingBeatmap.BeatmapInfo.Difficulty.ApproachRate; - valueDictionary[BeatmapInfo.ApproachRate] = ar.ToString("F2"); + valueDictionary[BeatmapAttribute.ApproachRate] = ar.ToString("F2"); //update sr double sr = workingBeatmap.BeatmapInfo.StarRating; - valueDictionary[BeatmapInfo.StarRating] = sr.ToString("F2"); + valueDictionary[BeatmapAttribute.StarRating] = sr.ToString("F2"); //update song title - valueDictionary[BeatmapInfo.Song] = workingBeatmap.BeatmapInfo.Metadata.Title; + valueDictionary[BeatmapAttribute.Song] = workingBeatmap.BeatmapInfo.Metadata.Title; //update artist - valueDictionary[BeatmapInfo.Artist] = workingBeatmap.BeatmapInfo.Metadata.Artist; + valueDictionary[BeatmapAttribute.Artist] = workingBeatmap.BeatmapInfo.Metadata.Artist; //update difficulty name - valueDictionary[BeatmapInfo.Difficulty] = workingBeatmap.BeatmapInfo.DifficultyName; + valueDictionary[BeatmapAttribute.Difficulty] = workingBeatmap.BeatmapInfo.DifficultyName; //update mapper - valueDictionary[BeatmapInfo.Mapper] = workingBeatmap.BeatmapInfo.Metadata.Author.Username; + valueDictionary[BeatmapAttribute.Mapper] = workingBeatmap.BeatmapInfo.Metadata.Author.Username; //update Length - valueDictionary[BeatmapInfo.Length] = TimeSpan.FromMilliseconds(workingBeatmap.BeatmapInfo.Length).ToFormattedDuration(); + valueDictionary[BeatmapAttribute.Length] = TimeSpan.FromMilliseconds(workingBeatmap.BeatmapInfo.Length).ToFormattedDuration(); //update Status - valueDictionary[BeatmapInfo.Status] = GetBetmapStatus(workingBeatmap.BeatmapInfo.Status); + valueDictionary[BeatmapAttribute.Status] = GetBetmapStatus(workingBeatmap.BeatmapInfo.Status); //update BPM - valueDictionary[BeatmapInfo.BPM] = workingBeatmap.BeatmapInfo.BPM.ToString("F2"); - valueDictionary[BeatmapInfo.None] = string.Empty; + valueDictionary[BeatmapAttribute.BPM] = workingBeatmap.BeatmapInfo.BPM.ToString("F2"); + valueDictionary[BeatmapAttribute.None] = string.Empty; } public static LocalisableString GetBetmapStatus(BeatmapOnlineStatus status) @@ -178,7 +177,7 @@ namespace osu.Game.Skinning.Components } } - public enum BeatmapInfo + public enum BeatmapAttribute { CircleSize, HPDrain, diff --git a/osu.Game/Skinning/Components/TextElement.cs b/osu.Game/Skinning/Components/TextElement.cs index da09aa76b2..1e618a7f82 100644 --- a/osu.Game/Skinning/Components/TextElement.cs +++ b/osu.Game/Skinning/Components/TextElement.cs @@ -16,7 +16,7 @@ namespace osu.Game.Skinning.Components { public bool UsesFixedAnchor { get; set; } - [SettingSource("Displayed Text", "What text should be displayed")] + [SettingSource("Text", "The text to be displayed.")] public Bindable Text { get; } = new Bindable("Circles!"); public TextElement() From 27473262af2757a9142922c46221700c585fc6b5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 16:39:13 +0900 Subject: [PATCH 2369/2686] Rename attributes in enum to match better with user expectations --- .../Components/BeatmapAttributeText.cs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index 6520130e75..a3b0ed7168 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -8,6 +8,8 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; @@ -18,6 +20,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Localisation; using osu.Game.Resources.Localisation.Web; +using osu.Game.Screens.Select.Filter; namespace osu.Game.Skinning.Components { @@ -36,6 +39,7 @@ namespace osu.Game.Skinning.Components private IBindable beatmap { get; set; } = null!; private readonly Dictionary valueDictionary = new Dictionary(); + private static readonly ImmutableDictionary label_dictionary; private readonly OsuSpriteText text; @@ -49,15 +53,13 @@ namespace osu.Game.Skinning.Components [BeatmapAttribute.HPDrain] = BeatmapsetsStrings.ShowStatsDrain, [BeatmapAttribute.ApproachRate] = BeatmapsetsStrings.ShowStatsAr, [BeatmapAttribute.StarRating] = BeatmapsetsStrings.ShowStatsStars, - [BeatmapAttribute.Song] = EditorSetupStrings.Title, + [BeatmapAttribute.Title] = EditorSetupStrings.Title, [BeatmapAttribute.Artist] = EditorSetupStrings.Artist, - [BeatmapAttribute.Difficulty] = EditorSetupStrings.DifficultyHeader, - //todo: is there a good alternative, to NotificationsOptionsMapping? - [BeatmapAttribute.Mapper] = AccountsStrings.NotificationsOptionsMapping, - [BeatmapAttribute.Length] = ArtistStrings.TracklistLength, - [BeatmapAttribute.Status] = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault, + [BeatmapAttribute.DifficultyName] = EditorSetupStrings.DifficultyHeader, + [BeatmapAttribute.Creator] = EditorSetupStrings.Creator, + [BeatmapAttribute.Length] = ArtistStrings.TracklistLength.ToTitle(), + [BeatmapAttribute.RankedStatus] = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault, [BeatmapAttribute.BPM] = BeatmapsetsStrings.ShowStatsBpm, - [BeatmapAttribute.None] = BeatmapAttribute.None.ToString() }.ToImmutableDictionary(); } @@ -124,20 +126,19 @@ namespace osu.Game.Skinning.Components double sr = workingBeatmap.BeatmapInfo.StarRating; valueDictionary[BeatmapAttribute.StarRating] = sr.ToString("F2"); //update song title - valueDictionary[BeatmapAttribute.Song] = workingBeatmap.BeatmapInfo.Metadata.Title; + valueDictionary[BeatmapAttribute.Title] = workingBeatmap.BeatmapInfo.Metadata.Title; //update artist valueDictionary[BeatmapAttribute.Artist] = workingBeatmap.BeatmapInfo.Metadata.Artist; //update difficulty name - valueDictionary[BeatmapAttribute.Difficulty] = workingBeatmap.BeatmapInfo.DifficultyName; + valueDictionary[BeatmapAttribute.DifficultyName] = workingBeatmap.BeatmapInfo.DifficultyName; //update mapper - valueDictionary[BeatmapAttribute.Mapper] = workingBeatmap.BeatmapInfo.Metadata.Author.Username; + valueDictionary[BeatmapAttribute.Creator] = workingBeatmap.BeatmapInfo.Metadata.Author.Username; //update Length valueDictionary[BeatmapAttribute.Length] = TimeSpan.FromMilliseconds(workingBeatmap.BeatmapInfo.Length).ToFormattedDuration(); //update Status - valueDictionary[BeatmapAttribute.Status] = GetBetmapStatus(workingBeatmap.BeatmapInfo.Status); + valueDictionary[BeatmapAttribute.RankedStatus] = GetBetmapStatus(workingBeatmap.BeatmapInfo.Status); //update BPM valueDictionary[BeatmapAttribute.BPM] = workingBeatmap.BeatmapInfo.BPM.ToString("F2"); - valueDictionary[BeatmapAttribute.None] = string.Empty; } public static LocalisableString GetBetmapStatus(BeatmapOnlineStatus status) @@ -184,13 +185,12 @@ namespace osu.Game.Skinning.Components Accuracy, ApproachRate, StarRating, - Song, + Title, Artist, - Difficulty, - Mapper, + DifficultyName, + Creator, Length, - Status, + RankedStatus, BPM, - None, } } From a8af83e62a0709d32f30215f044443f2fe07fc67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 16:49:39 +0900 Subject: [PATCH 2370/2686] Move label initialisation out of ctor --- .../Components/BeatmapAttributeText.cs | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index a3b0ed7168..1d6661d26e 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -20,7 +20,6 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Localisation; using osu.Game.Resources.Localisation.Web; -using osu.Game.Screens.Select.Filter; namespace osu.Game.Skinning.Components { @@ -40,29 +39,24 @@ namespace osu.Game.Skinning.Components private readonly Dictionary valueDictionary = new Dictionary(); - private static readonly ImmutableDictionary label_dictionary; + private static readonly ImmutableDictionary label_dictionary = new Dictionary + { + [BeatmapAttribute.CircleSize] = BeatmapsetsStrings.ShowStatsCs, + [BeatmapAttribute.Accuracy] = BeatmapsetsStrings.ShowStatsAccuracy, + [BeatmapAttribute.HPDrain] = BeatmapsetsStrings.ShowStatsDrain, + [BeatmapAttribute.ApproachRate] = BeatmapsetsStrings.ShowStatsAr, + [BeatmapAttribute.StarRating] = BeatmapsetsStrings.ShowStatsStars, + [BeatmapAttribute.Title] = EditorSetupStrings.Title, + [BeatmapAttribute.Artist] = EditorSetupStrings.Artist, + [BeatmapAttribute.DifficultyName] = EditorSetupStrings.DifficultyHeader, + [BeatmapAttribute.Creator] = EditorSetupStrings.Creator, + [BeatmapAttribute.Length] = ArtistStrings.TracklistLength.ToTitle(), + [BeatmapAttribute.RankedStatus] = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault, + [BeatmapAttribute.BPM] = BeatmapsetsStrings.ShowStatsBpm, + }.ToImmutableDictionary(); private readonly OsuSpriteText text; - static BeatmapAttributeText() - { - label_dictionary = new Dictionary - { - [BeatmapAttribute.CircleSize] = BeatmapsetsStrings.ShowStatsCs, - [BeatmapAttribute.Accuracy] = BeatmapsetsStrings.ShowStatsAccuracy, - [BeatmapAttribute.HPDrain] = BeatmapsetsStrings.ShowStatsDrain, - [BeatmapAttribute.ApproachRate] = BeatmapsetsStrings.ShowStatsAr, - [BeatmapAttribute.StarRating] = BeatmapsetsStrings.ShowStatsStars, - [BeatmapAttribute.Title] = EditorSetupStrings.Title, - [BeatmapAttribute.Artist] = EditorSetupStrings.Artist, - [BeatmapAttribute.DifficultyName] = EditorSetupStrings.DifficultyHeader, - [BeatmapAttribute.Creator] = EditorSetupStrings.Creator, - [BeatmapAttribute.Length] = ArtistStrings.TracklistLength.ToTitle(), - [BeatmapAttribute.RankedStatus] = BeatmapDiscussionsStrings.IndexFormBeatmapsetStatusDefault, - [BeatmapAttribute.BPM] = BeatmapsetsStrings.ShowStatsBpm, - }.ToImmutableDictionary(); - } - public BeatmapAttributeText() { AutoSizeAxes = Axes.Both; From 0f034606fd68b4106bd0deeaae75b962fb617489 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 16:49:51 +0900 Subject: [PATCH 2371/2686] Use `LocalisableDescription` from `BeatmapOnlineStatus` enum instead of locally defined --- .../Components/BeatmapAttributeText.cs | 38 +------------------ 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index 1d6661d26e..5cb78864f7 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -130,46 +130,10 @@ namespace osu.Game.Skinning.Components //update Length valueDictionary[BeatmapAttribute.Length] = TimeSpan.FromMilliseconds(workingBeatmap.BeatmapInfo.Length).ToFormattedDuration(); //update Status - valueDictionary[BeatmapAttribute.RankedStatus] = GetBetmapStatus(workingBeatmap.BeatmapInfo.Status); + valueDictionary[BeatmapAttribute.RankedStatus] = workingBeatmap.BeatmapInfo.Status.GetLocalisableDescription(); //update BPM valueDictionary[BeatmapAttribute.BPM] = workingBeatmap.BeatmapInfo.BPM.ToString("F2"); } - - public static LocalisableString GetBetmapStatus(BeatmapOnlineStatus status) - { - switch (status) - { - case BeatmapOnlineStatus.Approved: - return BeatmapsetsStrings.ShowStatusApproved; - - case BeatmapOnlineStatus.Graveyard: - return BeatmapsetsStrings.ShowStatusGraveyard; - - case BeatmapOnlineStatus.Loved: - return BeatmapsetsStrings.ShowStatusLoved; - - case BeatmapOnlineStatus.None: - return "None"; - - case BeatmapOnlineStatus.Pending: - return BeatmapsetsStrings.ShowStatusPending; - - case BeatmapOnlineStatus.Qualified: - return BeatmapsetsStrings.ShowStatusQualified; - - case BeatmapOnlineStatus.Ranked: - return BeatmapsetsStrings.ShowStatusRanked; - - case BeatmapOnlineStatus.LocallyModified: - return SongSelectStrings.LocallyModified; - - case BeatmapOnlineStatus.WIP: - return BeatmapsetsStrings.ShowStatusWip; - - default: - return @"null"; - } - } } public enum BeatmapAttribute From 0749a7bb0777691b35f438311ce1e7c3acf3a973 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 16:53:36 +0900 Subject: [PATCH 2372/2686] Simplify attribute assignment --- .../Components/BeatmapAttributeText.cs | 29 ++++--------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index 5cb78864f7..498ea1d268 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -104,35 +104,18 @@ namespace osu.Game.Skinning.Components public void UpdateBeatmapContent(WorkingBeatmap workingBeatmap) { - //update cs - double cs = workingBeatmap.BeatmapInfo.Difficulty.CircleSize; - valueDictionary[BeatmapAttribute.CircleSize] = cs.ToString("F2"); - //update HP - double hp = workingBeatmap.BeatmapInfo.Difficulty.DrainRate; - valueDictionary[BeatmapAttribute.HPDrain] = hp.ToString("F2"); - //update od - double od = workingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty; - valueDictionary[BeatmapAttribute.Accuracy] = od.ToString("F2"); - //update ar - double ar = workingBeatmap.BeatmapInfo.Difficulty.ApproachRate; - valueDictionary[BeatmapAttribute.ApproachRate] = ar.ToString("F2"); - //update sr - double sr = workingBeatmap.BeatmapInfo.StarRating; - valueDictionary[BeatmapAttribute.StarRating] = sr.ToString("F2"); - //update song title valueDictionary[BeatmapAttribute.Title] = workingBeatmap.BeatmapInfo.Metadata.Title; - //update artist valueDictionary[BeatmapAttribute.Artist] = workingBeatmap.BeatmapInfo.Metadata.Artist; - //update difficulty name valueDictionary[BeatmapAttribute.DifficultyName] = workingBeatmap.BeatmapInfo.DifficultyName; - //update mapper valueDictionary[BeatmapAttribute.Creator] = workingBeatmap.BeatmapInfo.Metadata.Author.Username; - //update Length valueDictionary[BeatmapAttribute.Length] = TimeSpan.FromMilliseconds(workingBeatmap.BeatmapInfo.Length).ToFormattedDuration(); - //update Status valueDictionary[BeatmapAttribute.RankedStatus] = workingBeatmap.BeatmapInfo.Status.GetLocalisableDescription(); - //update BPM - valueDictionary[BeatmapAttribute.BPM] = workingBeatmap.BeatmapInfo.BPM.ToString("F2"); + valueDictionary[BeatmapAttribute.BPM] = workingBeatmap.BeatmapInfo.BPM.ToString(@"F2"); + valueDictionary[BeatmapAttribute.CircleSize] = ((double)workingBeatmap.BeatmapInfo.Difficulty.CircleSize).ToString(@"F2"); + valueDictionary[BeatmapAttribute.HPDrain] = ((double)workingBeatmap.BeatmapInfo.Difficulty.DrainRate).ToString(@"F2"); + valueDictionary[BeatmapAttribute.Accuracy] = ((double)workingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty).ToString(@"F2"); + valueDictionary[BeatmapAttribute.ApproachRate] = ((double)workingBeatmap.BeatmapInfo.Difficulty.ApproachRate).ToString(@"F2"); + valueDictionary[BeatmapAttribute.StarRating] = workingBeatmap.BeatmapInfo.StarRating.ToString(@"F2"); } } From 774f70e380ab129f4472a73494e1397e556b0238 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 16:56:40 +0900 Subject: [PATCH 2373/2686] Simplify class structure --- .../Components/BeatmapAttributeText.cs | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index 498ea1d268..572b4ba818 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -60,49 +60,32 @@ namespace osu.Game.Skinning.Components public BeatmapAttributeText() { AutoSizeAxes = Axes.Both; + InternalChildren = new Drawable[] { text = new OsuSpriteText { - Text = "BeatInfoDrawable", Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Font = OsuFont.Default.With(size: 40) } }; - - foreach (var type in Enum.GetValues(typeof(BeatmapAttribute)).Cast()) - { - valueDictionary[type] = type.ToString(); - } } protected override void LoadComplete() { base.LoadComplete(); + Attribute.BindValueChanged(_ => updateLabel()); - Template.BindValueChanged(f => updateLabel(), true); + Template.BindValueChanged(_ => updateLabel()); beatmap.BindValueChanged(b => { - UpdateBeatmapContent(b.NewValue); + updateBeatmapContent(b.NewValue); updateLabel(); }, true); } - private void updateLabel() - { - string newText = Template.Value.Replace("{Label}", label_dictionary[Attribute.Value].ToString()) - .Replace("{Value}", valueDictionary[Attribute.Value].ToString()); - - foreach (var type in Enum.GetValues(typeof(BeatmapAttribute)).Cast()) - { - newText = newText.Replace("{" + type + "}", valueDictionary[type].ToString()); - } - - text.Text = newText; - } - - public void UpdateBeatmapContent(WorkingBeatmap workingBeatmap) + private void updateBeatmapContent(WorkingBeatmap workingBeatmap) { valueDictionary[BeatmapAttribute.Title] = workingBeatmap.BeatmapInfo.Metadata.Title; valueDictionary[BeatmapAttribute.Artist] = workingBeatmap.BeatmapInfo.Metadata.Artist; @@ -117,6 +100,19 @@ namespace osu.Game.Skinning.Components valueDictionary[BeatmapAttribute.ApproachRate] = ((double)workingBeatmap.BeatmapInfo.Difficulty.ApproachRate).ToString(@"F2"); valueDictionary[BeatmapAttribute.StarRating] = workingBeatmap.BeatmapInfo.StarRating.ToString(@"F2"); } + + private void updateLabel() + { + string newText = Template.Value.Replace("{Label}", label_dictionary[Attribute.Value].ToString()) + .Replace("{Value}", valueDictionary[Attribute.Value].ToString()); + + foreach (var type in Enum.GetValues(typeof(BeatmapAttribute)).Cast()) + { + newText = newText.Replace("{" + type + "}", valueDictionary[type].ToString()); + } + + text.Text = newText; + } } public enum BeatmapAttribute From a6bba1967ebfa392a27e2c77f4f0e4e68aac353f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 17:06:22 +0900 Subject: [PATCH 2374/2686] Update serialisation test to match new comopnent naming --- .../Archives/modified-default-20221102.osk | Bin 1534 -> 1599 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/osu.Game.Tests/Resources/Archives/modified-default-20221102.osk b/osu.Game.Tests/Resources/Archives/modified-default-20221102.osk index 3ec328db4e8212e2cb709865362b24f83951b93e..c1333acd13185826f4516eccf92f6d6d2e24cb8a 100644 GIT binary patch literal 1599 zcmWIWW@Zs#U|`^2$nGc)?YJIvbt{k;!UPgwU?|Sc%+t%v%e>pam(S5rp!Iic*Tsns z{)H?Gei;(7NFq&7dbjbWax?RJz7HqvVN%k%*!@oB{`ASkdDF844}3asA%o*q<;}x> zMuqE-a7=Q9Ftyj^XG=3j=%kV4kr1`we2WdC?W-Z$=X>o@7xxcT1BKAM-*l|!M zCuDkQtlz4W&+OxB5tz+^=dFGg6cF&q z`;2esrl5dR`g)-u7c?|a`JC}S@2Pt&1Z=74Gy|2P}=+8&6z!W&g?1KD=?$mLCK2CfYmEzD+8*dXMK!&cbbub;Q=25gBZ}! zzKNN69-%JI`MCx8d8v6N#bDRJo$ly=+d$;_`@bTA=MNTjOkU$*>u@S8bGBIEgC+}! z?_0MP`xqr3 z(fq@?w z{lWQp>A|TvsmUeact08(n|;VYr1pDwO6@zRTVGB$@@w6eJ2vA?p8g}}wdH0r)RuZW z3jY5clxwclY-ld2$p2l%@_CWpyEW|>&gHbMsfcbUZPr<-RWtud!}4r37GZ6hX_bns z9BV&t2+dVL8t{6Ot`@Ih&X(R=>Sk4~L57-aEb`NOkBMFn3vsjsGqZ`LW`W`=;U=f$H{l&EfbuG28E+4RM_}%t6^3{@u zE57zWF!8mRvq?zii}S0X?T2qIh-)v=xa2eK*_QhZ{;JU%qYiUQKXGl`l`I`mcc<2S zN7FXO3%4v*zLJZ&RCw&irj}W$X75dt>`yNG_HUYVURSrfgW=a2p&eV2uWfyv_)2L0 z1!LoaTaVi=T#1){KgqseU+AS{J8s>L2+M3MVbe%WJ>?i1Df=~E{fqu(p;`JeErI0` zix{k*t*=gh=Ca{Ed!9tay^|Yc9)4(g{7Et@?t_cG&;4Gt{^~6npYlJwI(r`&PmD|= z47dwUU}Ql+BZz_(qv*QO%Ot2C28PDlP+jm63SBFD$$-#00hnO0mlNn_peHYc8U4%{ Vi7mjJl?|kT1qeR@X>(Q(4*+f4o~Hl+ literal 1534 zcmWIWW@Zs#U|`^2NN-6B{k=AO?o1$WGgyRyp*TA;PcJhsQ}v7?Uz3A?!^L?i?+t<+ zla2&jio6+_nX1E<*3i4#IPE6y!yGZWliC~`|LOn#{Vzl`#=R|W?&X`O80LDVbQ(Nn znX#yx+1rz4%;f*Sr?uTAxyVI%L+HDUVhxY@BW5nr?WLKLEw~Gv4vZmjIpK z1H`;Q403*EURu6hR&jpb>Ss@b0s=mHpYaXd6clhuUoSMIBhX97>-_odz@Q5TMg~Tg zLN1&*>wnVcw2$w_kV}l(<$7MeIw$p+UUHm0eeSgW`DU+*XQI}d?VI+U#a$tj}*2ki&Obn>bd;h|Bkv}5?LpU=713%Dt z!TEXV!Kpc^$t7S1?wuH$eaJwf^*!r<=WE_87slTzdvNqxt--MwXLd<{RJs<_k*Cm#O61*4n}CKI$QjBky+}4dvo?E9ALgL{iCd#pKZ5a%i#m^JlemmzSzU* zn>F{6i?6z5Vu9M*ZOpwIWqwccDz*t;iaE+#Ikm*syV5-8LP%rPg6fEEm$eUxY&q?i zExc6g`}RX8+cqt23Cb|jk1YMX+$reB>uR>0mVcZD|1z*|e9!){Fs)Yq$l-;;t{+)_ zD=a=GtCuWJe#_;4FMsKl&*IxI>0MR3X!LFROBL6>XIi$rUD$G}r*YRNznnSYH{PDv z&xjiK)eZ7#FMwfR1`K#HVA%U6X6AW>x;W?O7Ubup=9LtKqu}lI*zDT|B5m)v|MII{ zUpK-2QNN?!ttHXNB#gax&A!Ba)Yj7_Ra54qPU4&W;d!#tkD6<1mc2-8c3j_gU-?VH zo5i<38z27}YAcg&a6dQU!$C=n*h&6t7>rH}I%G}a+@^eaHs{O(lcpZ(3Edcw9O}jV z!s>Uy^`DF@c1}|EnwNK7^7aFvM3sdmCt6;oJazi;hx^U5SBy_QraAH4v8r8WV*agk zcT1IP*qvJw#jB1ipVF46{C3S%C>i4mS7sdL-U)uL=KT!B_ z)h7=BUU#+~ArS^MotNz}*>(JyrqrY>aUbn3+u0UquI1j?-rhSYp?rP}qcQ94nrYsq zj^8HhvXm6gSzzb+cj5D`yOyU&{H&{B5%fxWrMmC=@%GT~OMWMQ`ELLD-^VkF+3Q$E z$}TWYvrzM#p?18aC Ghz9_U=60t5 From e69ed67335ab9824b238e4f0953be2d9c0b46ea9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 18:09:47 +0900 Subject: [PATCH 2375/2686] Add test of barline generation with negative start time control point --- .../TestSceneBarLineGeneration.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs index 095fddc33f..bd52af7615 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs @@ -83,5 +83,41 @@ namespace osu.Game.Rulesets.Taiko.Tests AddAssert("first barline ommited", () => barlines.All(b => b.StartTime != start_time)); AddAssert("second barline generated", () => barlines.Any(b => b.StartTime == start_time + (beat_length * time_signature_numerator))); } + + [Test] + public void TestNegativeStartTimeTimingPoint() + { + const double beat_length = 250; + + const int time_signature_numerator = 4; + + var beatmap = new Beatmap + { + HitObjects = + { + new Hit + { + Type = HitType.Centre, + StartTime = 1000 + } + }, + BeatmapInfo = + { + Difficulty = new BeatmapDifficulty { SliderTickRate = 4 }, + Ruleset = new TaikoRuleset().RulesetInfo + }, + }; + + beatmap.ControlPointInfo.Add(-100, new TimingControlPoint + { + BeatLength = beat_length, + TimeSignature = new TimeSignature(time_signature_numerator) + }); + + var barlines = new BarLineGenerator(beatmap).BarLines; + + AddAssert("bar line generated at t=900", () => barlines.Any(line => line.StartTime == 900)); + AddAssert("bar line generated at t=1900", () => barlines.Any(line => line.StartTime == 1900)); + } } } From f9d952220fcee1e1aadc588cbec85ce179461e55 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 18:12:03 +0900 Subject: [PATCH 2376/2686] Fix barlines being misaligned if generation start time is clamped --- osu.Game/Rulesets/Objects/BarLineGenerator.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/BarLineGenerator.cs b/osu.Game/Rulesets/Objects/BarLineGenerator.cs index 185088878c..5c76c43f20 100644 --- a/osu.Game/Rulesets/Objects/BarLineGenerator.cs +++ b/osu.Game/Rulesets/Objects/BarLineGenerator.cs @@ -47,13 +47,28 @@ namespace osu.Game.Rulesets.Objects // Don't generate barlines before the hit object or t=0 (whichever is earliest). Some beatmaps use very unrealistic values here (although none are ranked). // I'm not sure we ever want barlines to appear before the first hitobject, but let's keep some degree of compatibility for now. // Of note, this will still differ from stable if the first timing control point is t<0 and is not near the first hitobject. - double startTime = Math.Max(Math.Min(0, firstHitTime), currentTimingPoint.Time); + double generationStartTime = Math.Min(0, firstHitTime); // Stop on the next timing point, or if there is no next timing point stop slightly past the last object double endTime = i < timingPoints.Count - 1 ? timingPoints[i + 1].Time : lastHitTime + currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; double barLength = currentTimingPoint.BeatLength * currentTimingPoint.TimeSignature.Numerator; + double startTime; + + if (currentTimingPoint.Time > generationStartTime) + { + startTime = currentTimingPoint.Time; + } + else + { + // If the timing point starts before the minimum allowable time for bar lines, + // we still need to compute a start time for generation that is actually properly aligned with the timing point. + int barCount = (int)Math.Ceiling((generationStartTime - currentTimingPoint.Time) / barLength); + + startTime = currentTimingPoint.Time + barCount * barLength; + } + if (currentEffectPoint.OmitFirstBarLine) { startTime += barLength; From 5467097387b97f0dbf2ae9defb7234368977e5c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 23 Nov 2022 18:49:51 +0900 Subject: [PATCH 2377/2686] Fix adjacent day separators potentially being left behind after pending message resolution --- osu.Game/Overlays/Chat/DrawableChannel.cs | 36 ++++++++++++++--------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 3d2eafd973..65876fd7c5 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -141,27 +141,15 @@ namespace osu.Game.Overlays.Chat } var staleMessages = chatLines.Where(c => c.LifetimeEnd == double.MaxValue).ToArray(); + int count = staleMessages.Length - Channel.MAX_HISTORY; if (count > 0) { - void expireAndAdjustScroll(Drawable d) - { - scroll.OffsetScrollPosition(-d.DrawHeight); - d.Expire(); - } - for (int i = 0; i < count; i++) expireAndAdjustScroll(staleMessages[i]); - // remove all adjacent day separators after stale message removal - for (int i = 0; i < ChatLineFlow.Count - 1; i++) - { - if (!(ChatLineFlow[i] is DaySeparator)) break; - if (!(ChatLineFlow[i + 1] is DaySeparator)) break; - - expireAndAdjustScroll(ChatLineFlow[i]); - } + removeAdjacentDaySeparators(); } // due to the scroll adjusts from old messages removal above, a scroll-to-end must be enforced, @@ -199,9 +187,29 @@ namespace osu.Game.Overlays.Chat ChatLineFlow.Remove(ds, true); ChatLineFlow.Add(CreateDaySeparator(message.Timestamp)); + + removeAdjacentDaySeparators(); } } + private void removeAdjacentDaySeparators() + { + // remove all adjacent day separators after stale message removal + for (int i = 0; i < ChatLineFlow.Count - 1; i++) + { + if (!(ChatLineFlow[i] is DaySeparator)) break; + if (!(ChatLineFlow[i + 1] is DaySeparator)) break; + + expireAndAdjustScroll(ChatLineFlow[i]); + } + } + + private void expireAndAdjustScroll(Drawable d) + { + scroll.OffsetScrollPosition(-d.DrawHeight); + d.Expire(); + } + private void messageRemoved(Message removed) => Schedule(() => { chatLines.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); From 2204af04e485cbd2af81f51d8846684a36a17477 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 23 Nov 2022 16:12:13 +0300 Subject: [PATCH 2378/2686] Improve test scene to better show colour gradient --- .../TestSceneTrianglesV2Background.cs | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs index e8abc573cd..0c3a21d510 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs @@ -27,16 +27,24 @@ namespace osu.Game.Tests.Visual.Background { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(500), + Size = new Vector2(500, 100), Masking = true, CornerRadius = 40, - Child = triangles = new TrianglesV2 + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - ColourTop = Color4.Red, - ColourBottom = Color4.Orange + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Red + }, + triangles = new TrianglesV2 + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + ColourTop = Color4.White, + ColourBottom = Color4.Red + } } } }); From 06449b62f1517ab9f77e3a0c8050af8c0065ee5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Nov 2022 16:03:54 +0100 Subject: [PATCH 2379/2686] Add test coverage for crash scenario --- .../Visual/Editing/TestSceneTapTimingControl.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs index 10e1206b53..f2bfffda06 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs @@ -18,6 +18,7 @@ using osu.Game.Overlays; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Timing; using osuTK; +using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { @@ -125,6 +126,13 @@ namespace osu.Game.Tests.Visual.Editing AddUntilStep("wait for track stopped", () => !EditorClock.IsRunning); } + [Test] + public void TestNoCrashOnTapWhenNoGroupSelected() + { + AddStep("unset selected group", () => selectedGroup.Value = null); + AddStep("press T to tap", () => InputManager.Key(Key.T)); + } + protected override void Dispose(bool isDisposing) { Beatmap.Disabled = false; From cf5f5a4de310147523f2a41ff5621149758b07e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Nov 2022 17:19:58 +0100 Subject: [PATCH 2380/2686] Extend tap timing control test coverage in no point selected case --- .../Editing/TestSceneTapTimingControl.cs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs index f2bfffda06..6ed63515e9 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs @@ -127,10 +127,38 @@ namespace osu.Game.Tests.Visual.Editing } [Test] - public void TestNoCrashOnTapWhenNoGroupSelected() + public void TestNoCrashesWhenNoGroupSelected() { AddStep("unset selected group", () => selectedGroup.Value = null); AddStep("press T to tap", () => InputManager.Key(Key.T)); + + AddStep("click tap button", () => + { + control.ChildrenOfType() + .Last() + .TriggerClick(); + }); + + AddStep("click reset button", () => + { + control.ChildrenOfType() + .First() + .TriggerClick(); + }); + + AddStep("adjust offset", () => + { + var adjustOffsetButton = control.ChildrenOfType().First(); + InputManager.MoveMouseTo(adjustOffsetButton); + InputManager.Click(MouseButton.Left); + }); + + AddStep("adjust BPM", () => + { + var adjustBPMButton = control.ChildrenOfType().Last(); + InputManager.MoveMouseTo(adjustBPMButton); + InputManager.Click(MouseButton.Left); + }); } protected override void Dispose(bool isDisposing) From 30f9cc46a7618031088f98fc2d2444279f9e6dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 23 Nov 2022 17:22:40 +0100 Subject: [PATCH 2381/2686] Protect offset and bpm adjustments from null selection too --- osu.Game/Screens/Edit/Timing/TapTimingControl.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index daa3168746..3b26e335d9 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -201,6 +201,9 @@ namespace osu.Game.Screens.Edit.Timing private void adjustOffset(double adjust) { + if (selectedGroup.Value == null) + return; + bool wasAtStart = editorClock.CurrentTimeAccurate == selectedGroup.Value.Time; // VERY TEMPORARY @@ -222,7 +225,7 @@ namespace osu.Game.Screens.Edit.Timing private void adjustBpm(double adjust) { - var timing = selectedGroup.Value.ControlPoints.OfType().FirstOrDefault(); + var timing = selectedGroup.Value?.ControlPoints.OfType().FirstOrDefault(); if (timing == null) return; From 3acf15c7b8945e01081d86eeeeb2033bfcec9000 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Nov 2022 01:26:49 +0900 Subject: [PATCH 2382/2686] 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 8212707d44..06121fa9fa 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f81d9d27b4..b6dc691359 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index cd70f1c432..c7200b9620 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 4b44f31b5edd98f43e57ed81bb94f5c16c87b9a1 Mon Sep 17 00:00:00 2001 From: C0D3 M4513R <28912031+C0D3-M4513R@users.noreply.github.com> Date: Wed, 23 Nov 2022 21:02:43 +0100 Subject: [PATCH 2383/2686] Use LocaliseableStings in `BeatmapAttributeText` --- .../Components/BeatmapAttributeText.cs | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index 572b4ba818..ec84831fb4 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -93,25 +93,34 @@ namespace osu.Game.Skinning.Components valueDictionary[BeatmapAttribute.Creator] = workingBeatmap.BeatmapInfo.Metadata.Author.Username; valueDictionary[BeatmapAttribute.Length] = TimeSpan.FromMilliseconds(workingBeatmap.BeatmapInfo.Length).ToFormattedDuration(); valueDictionary[BeatmapAttribute.RankedStatus] = workingBeatmap.BeatmapInfo.Status.GetLocalisableDescription(); - valueDictionary[BeatmapAttribute.BPM] = workingBeatmap.BeatmapInfo.BPM.ToString(@"F2"); - valueDictionary[BeatmapAttribute.CircleSize] = ((double)workingBeatmap.BeatmapInfo.Difficulty.CircleSize).ToString(@"F2"); - valueDictionary[BeatmapAttribute.HPDrain] = ((double)workingBeatmap.BeatmapInfo.Difficulty.DrainRate).ToString(@"F2"); - valueDictionary[BeatmapAttribute.Accuracy] = ((double)workingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty).ToString(@"F2"); - valueDictionary[BeatmapAttribute.ApproachRate] = ((double)workingBeatmap.BeatmapInfo.Difficulty.ApproachRate).ToString(@"F2"); - valueDictionary[BeatmapAttribute.StarRating] = workingBeatmap.BeatmapInfo.StarRating.ToString(@"F2"); + valueDictionary[BeatmapAttribute.BPM] = workingBeatmap.BeatmapInfo.BPM.ToLocalisableString(@"F2"); + valueDictionary[BeatmapAttribute.CircleSize] = ((double)workingBeatmap.BeatmapInfo.Difficulty.CircleSize).ToLocalisableString(@"F2"); + valueDictionary[BeatmapAttribute.HPDrain] = ((double)workingBeatmap.BeatmapInfo.Difficulty.DrainRate).ToLocalisableString(@"F2"); + valueDictionary[BeatmapAttribute.Accuracy] = ((double)workingBeatmap.BeatmapInfo.Difficulty.OverallDifficulty).ToLocalisableString(@"F2"); + valueDictionary[BeatmapAttribute.ApproachRate] = ((double)workingBeatmap.BeatmapInfo.Difficulty.ApproachRate).ToLocalisableString(@"F2"); + valueDictionary[BeatmapAttribute.StarRating] = workingBeatmap.BeatmapInfo.StarRating.ToLocalisableString(@"F2"); } private void updateLabel() { - string newText = Template.Value.Replace("{Label}", label_dictionary[Attribute.Value].ToString()) - .Replace("{Value}", valueDictionary[Attribute.Value].ToString()); + string numberedTemplate = Template.Value + .Replace("{", "{{") + .Replace("}", "}}") + .Replace(@"{{Label}}", "{0}") + .Replace(@"{{Value}}", $"{{{1 + (int)Attribute.Value}}}"); + + object?[] args = valueDictionary.OrderBy(pair => pair.Key) + .Select(pair => pair.Value) + .Prepend(label_dictionary[Attribute.Value]) + .Cast() + .ToArray(); foreach (var type in Enum.GetValues(typeof(BeatmapAttribute)).Cast()) { - newText = newText.Replace("{" + type + "}", valueDictionary[type].ToString()); + numberedTemplate = numberedTemplate.Replace($"{{{{{type}}}}}", $"{{{1 + (int)type}}}"); } - text.Text = newText; + text.Text = LocalisableString.Format(numberedTemplate, args); } } From 37f725bfa242982350f40326db6399a7835a936c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Nov 2022 13:55:58 +0900 Subject: [PATCH 2384/2686] Reverse directionality of up/down traversal keys to match scroll --- .../Visual/Editing/TestSceneEditorSeeking.cs | 18 +++++++++--------- osu.Game/Screens/Edit/Editor.cs | 5 +++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs index 14679ae01d..8ef84fb094 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs @@ -124,17 +124,17 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("time is 0", () => EditorClock.CurrentTime == 0); // already at first control point, noop - pressAndCheckTime(Key.Down, 0); - - pressAndCheckTime(Key.Up, 2000); - - pressAndCheckTime(Key.Up, 20000); - // at last control point, noop - pressAndCheckTime(Key.Up, 20000); + pressAndCheckTime(Key.Up, 0); pressAndCheckTime(Key.Down, 2000); - pressAndCheckTime(Key.Down, 0); - pressAndCheckTime(Key.Down, 0); + + pressAndCheckTime(Key.Down, 20000); + // at last control point, noop + pressAndCheckTime(Key.Down, 20000); + + pressAndCheckTime(Key.Up, 2000); + pressAndCheckTime(Key.Up, 0); + pressAndCheckTime(Key.Up, 0); } private void pressAndCheckTime(Key key, double expectedTime) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 7c0e021ff9..e40910e5c6 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -499,11 +499,12 @@ namespace osu.Game.Screens.Edit seek(e, 1); return true; - case Key.Down: + // Of those, these two keys are reversed from stable because it feels more natural (and matches mouse wheel scroll directionality). + case Key.Up: seekControlPoint(-1); return true; - case Key.Up: + case Key.Down: seekControlPoint(1); return true; From a2438428a23639a9100f21e3723849325ae136c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Nov 2022 13:57:43 +0900 Subject: [PATCH 2385/2686] Move base call to end --- osu.Game/Rulesets/Mods/DifficultyBindable.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/DifficultyBindable.cs b/osu.Game/Rulesets/Mods/DifficultyBindable.cs index 2b3ba1dd13..cca72cf3ac 100644 --- a/osu.Game/Rulesets/Mods/DifficultyBindable.cs +++ b/osu.Game/Rulesets/Mods/DifficultyBindable.cs @@ -118,12 +118,12 @@ namespace osu.Game.Rulesets.Mods if (!(them is DifficultyBindable otherDifficultyBindable)) throw new InvalidOperationException($"Cannot bind to a non-{nameof(DifficultyBindable)}."); - base.BindTo(them); - ExtendedLimits.BindTarget = otherDifficultyBindable.ExtendedLimits; // the actual values need to be copied after the max value constraints. CurrentNumber.BindTarget = otherDifficultyBindable.CurrentNumber; + + base.BindTo(them); } public override void UnbindFrom(IUnbindable them) From 2e277ef40a3b51b8e935863f3ceea5bc4694597c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Nov 2022 15:18:49 +0900 Subject: [PATCH 2386/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 5f3fb858ee..647c7b179c 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 858cac1dac..5c4b5642b5 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 25217b872b..19f4248055 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + From 40f706155f56603f86f8c1bbfc194330d0a83f29 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Nov 2022 15:04:54 +0900 Subject: [PATCH 2387/2686] Update `RoundedButton` to have new triangles design --- .../UserInterface/TestSceneRoundedButton.cs | 2 +- osu.Game/Graphics/UserInterface/OsuButton.cs | 7 ++- .../Graphics/UserInterfaceV2/RoundedButton.cs | 61 +++++++++++++++++-- osu.Game/Overlays/Settings/SettingsButton.cs | 11 ---- 4 files changed, 63 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs index 2587960275..178a68b599 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.UserInterface }, new SettingsButton { - Text = "Test button", + Text = "Test settings button", Anchor = Anchor.Centre, Origin = Anchor.Centre, Enabled = { BindTarget = enabled }, diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index dae5de2d65..6f1312652b 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -37,7 +37,7 @@ namespace osu.Game.Graphics.UserInterface /// /// Sets a custom background colour to this button, replacing the provided default. /// - public Color4 BackgroundColour + public virtual Color4 BackgroundColour { get => backgroundColour ?? defaultBackgroundColour; set @@ -90,6 +90,7 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, + Depth = float.MaxValue, }, Hover = new Box { @@ -141,13 +142,15 @@ namespace osu.Game.Graphics.UserInterface return base.OnClick(e); } + protected virtual float HoverLayerFinalAlpha => 0.1f; + protected override bool OnHover(HoverEvent e) { if (Enabled.Value) { Hover.FadeTo(0.2f, 40, Easing.OutQuint) .Then() - .FadeTo(0.1f, 800, Easing.OutQuint); + .FadeTo(HoverLayerFinalAlpha, 800, Easing.OutQuint); } return base.OnHover(e); diff --git a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs index 4477633da1..3d970284ec 100644 --- a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs @@ -1,19 +1,28 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Events; using osu.Framework.Localisation; +using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; +using osuTK.Graphics; namespace osu.Game.Graphics.UserInterfaceV2 { public class RoundedButton : OsuButton, IFilterable { + private TrianglesV2? triangles; + + protected override float HoverLayerFinalAlpha => 0; + + private Color4 triangleGradientSecondColour = Color4.Transparent; + public override float Height { get => base.Height; @@ -26,19 +35,63 @@ namespace osu.Game.Graphics.UserInterfaceV2 } } + public override Color4 BackgroundColour + { + get => base.BackgroundColour; + set + { + base.BackgroundColour = value; + triangleGradientSecondColour = BackgroundColour.Lighten(0.2f); + updateColours(); + } + } + [BackgroundDependencyLoader(true)] - private void load(OsuColour colours) + private void load(OverlayColourProvider? overlayColourProvider, OsuColour colours) { // According to flyte, buttons are supposed to have explicit colours for now. // Not sure this is the correct direction, but we haven't decided on an `OverlayColourProvider` stand-in yet. // This is a better default. See `SettingsButton` for an override which uses `OverlayColourProvider`. - DefaultBackgroundColour = colours.Blue3; + DefaultBackgroundColour = overlayColourProvider?.Colour3 ?? colours.Blue3; + triangleGradientSecondColour = overlayColourProvider?.Colour1 ?? colours.Blue3.Lighten(0.2f); } protected override void LoadComplete() { base.LoadComplete(); + updateCornerRadius(); + + Add(triangles = new TrianglesV2 + { + Thickness = 0.02f, + SpawnRatio = 0.6f, + RelativeSizeAxes = Axes.Both, + Depth = float.MaxValue, + }); + + updateColours(); + } + + private void updateColours() + { + if (triangles == null) + return; + + triangles.ColourTop = triangleGradientSecondColour; + triangles.ColourBottom = BackgroundColour; + } + + protected override bool OnHover(HoverEvent e) + { + Background.FadeColour(triangleGradientSecondColour, 300, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + Background.FadeColour(BackgroundColour, 300, Easing.OutQuint); + base.OnHoverLost(e); } private void updateCornerRadius() => Content.CornerRadius = DrawHeight / 2; diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index 5f2a416f58..10aea92b22 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -1,16 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Collections.Generic; using System.Linq; -using JetBrains.Annotations; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; -using osu.Game.Graphics; using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Overlays.Settings @@ -23,12 +18,6 @@ namespace osu.Game.Overlays.Settings Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS, Right = SettingsPanel.CONTENT_MARGINS }; } - [BackgroundDependencyLoader(true)] - private void load([CanBeNull] OverlayColourProvider overlayColourProvider, OsuColour colours) - { - DefaultBackgroundColour = overlayColourProvider?.Highlight1 ?? colours.Blue3; - } - public LocalisableString TooltipText { get; set; } public override IEnumerable FilterTerms From 4fbca4037c45b67e192396903ffc8a448ff09ef9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Nov 2022 15:08:03 +0900 Subject: [PATCH 2388/2686] Update existing triangle buttons to use `RoundedButton` --- .../Graphics/UserInterface/TriangleButton.cs | 32 ++----------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/TriangleButton.cs b/osu.Game/Graphics/UserInterface/TriangleButton.cs index 60d1824e5a..891c8f779f 100644 --- a/osu.Game/Graphics/UserInterface/TriangleButton.cs +++ b/osu.Game/Graphics/UserInterface/TriangleButton.cs @@ -1,42 +1,14 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using System.Collections.Generic; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Localisation; -using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Graphics.UserInterface { /// /// A button with moving triangles in the background. /// - public class TriangleButton : OsuButton, IFilterable + public class TriangleButton : RoundedButton { - protected Triangles Triangles { get; private set; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Add(Triangles = new Triangles - { - RelativeSizeAxes = Axes.Both, - ColourDark = colours.BlueDarker, - ColourLight = colours.Blue, - }); - } - - public virtual IEnumerable FilterTerms => new[] { Text }; - - public bool MatchingFilter - { - set => this.FadeTo(value ? 1 : 0); - } - - public bool FilteringActive { get; set; } } } From bea2acc60ef93f5bed5896a83e8ccb8250d7aafc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Nov 2022 15:18:26 +0900 Subject: [PATCH 2389/2686] Remove local specifications of triangle colouring --- .../UserInterface/DangerousTriangleButton.cs | 2 -- .../Overlays/BeatmapSet/Buttons/HeaderButton.cs | 5 ----- .../Match/Components/CreateRoomButton.cs | 1 - .../Match/Components/PurpleTriangleButton.cs | 2 -- .../Match/MultiplayerMatchSettingsOverlay.cs | 2 -- .../Multiplayer/Match/MultiplayerReadyButton.cs | 7 ------- .../Multiplayer/Match/MultiplayerSpectateButton.cs | 14 ++------------ .../OnlinePlay/Playlists/PlaylistsReadyButton.cs | 2 -- .../Playlists/PlaylistsRoomSettingsOverlay.cs | 2 -- 9 files changed, 2 insertions(+), 35 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs b/osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs index 1414979531..3c78cbb634 100644 --- a/osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs +++ b/osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs @@ -13,8 +13,6 @@ namespace osu.Game.Graphics.UserInterface private void load(OsuColour colours) { BackgroundColour = colours.PinkDark; - Triangles.ColourDark = colours.PinkDarker; - Triangles.ColourLight = colours.Pink; } } } diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs index 25d11bd6d7..d6bf3464da 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -22,9 +20,6 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private void load() { BackgroundColour = Color4Extensions.FromHex(@"094c5f"); - Triangles.ColourLight = Color4Extensions.FromHex(@"0f7c9b"); - Triangles.ColourDark = Color4Extensions.FromHex(@"094c5f"); - Triangles.TriangleScale = 1.5f; } } } diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs index 3d0c181d9d..20e4b78eb4 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs @@ -16,7 +16,6 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components private void load() { SpriteText.Font = SpriteText.Font.With(size: 14); - Triangles.TriangleScale = 1.5f; } public bool OnPressed(KeyBindingPressEvent e) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs index 5c751f238f..c6df53c368 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs @@ -15,8 +15,6 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components private void load() { BackgroundColour = Color4Extensions.FromHex(@"593790"); - Triangles.ColourLight = Color4Extensions.FromHex(@"7247b6"); - Triangles.ColourDark = Color4Extensions.FromHex(@"593790"); } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index bbdfed0a00..17c361a420 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -475,8 +475,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private void load(OsuColour colours) { BackgroundColour = colours.Yellow; - Triangles.ColourLight = colours.YellowLight; - Triangles.ColourDark = colours.YellowDark; } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs index b4ff34cbc2..5f2ae82f55 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs @@ -12,7 +12,6 @@ using osu.Framework.Audio.Sample; using osu.Framework.Localisation; using osu.Framework.Threading; using osu.Game.Graphics; -using osu.Game.Graphics.Backgrounds; using osu.Game.Online.Multiplayer; using osu.Game.Screens.OnlinePlay.Components; @@ -20,8 +19,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public class MultiplayerReadyButton : ReadyButton { - public new Triangles Triangles => base.Triangles; - [Resolved] private MultiplayerClient multiplayerClient { get; set; } @@ -212,15 +209,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match void setYellow() { BackgroundColour = colours.YellowDark; - Triangles.ColourDark = colours.YellowDark; - Triangles.ColourLight = colours.Yellow; } void setGreen() { BackgroundColour = colours.Green; - Triangles.ColourDark = colours.Green; - Triangles.ColourLight = colours.GreenLight; } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs index b55a7d0731..51f11341cc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Graphics; -using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; using osuTK; @@ -24,11 +23,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private IBindable operationInProgress; - private readonly ButtonWithTrianglesExposed button; + private readonly TriangleButton button; public MultiplayerSpectateButton() { - InternalChild = button = new ButtonWithTrianglesExposed + InternalChild = button = new TriangleButton { RelativeSizeAxes = Axes.Both, Size = Vector2.One, @@ -67,15 +66,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match default: button.Text = "Spectate"; button.BackgroundColour = colours.BlueDark; - button.Triangles.ColourDark = colours.BlueDarker; - button.Triangles.ColourLight = colours.Blue; break; case MultiplayerUserState.Spectating: button.Text = "Stop spectating"; button.BackgroundColour = colours.Gray4; - button.Triangles.ColourDark = colours.Gray5; - button.Triangles.ColourLight = colours.Gray6; break; } @@ -83,10 +78,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match && Client.Room.State != MultiplayerRoomState.Closed && !operationInProgress.Value; } - - private class ButtonWithTrianglesExposed : TriangleButton - { - public new Triangles Triangles => base.Triangles; - } } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs index b8ab514721..79933e606e 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs @@ -38,8 +38,6 @@ namespace osu.Game.Screens.OnlinePlay.Playlists private void load(OsuColour colours) { BackgroundColour = colours.Green; - Triangles.ColourDark = colours.Green; - Triangles.ColourLight = colours.GreenLight; } private bool hasRemainingAttempts = true; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index cd52981528..3c57ea5a3b 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -425,8 +425,6 @@ namespace osu.Game.Screens.OnlinePlay.Playlists private void load(OsuColour colours) { BackgroundColour = colours.Yellow; - Triangles.ColourLight = colours.YellowLight; - Triangles.ColourDark = colours.YellowDark; } } From 53b03df93d60da4b8d0c395ff997ca265f51ba59 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Nov 2022 16:26:57 +0900 Subject: [PATCH 2390/2686] Combine `TriangleButton` and `RoundedButton` classes --- .../TestScenePlaylistsMatchSettingsOverlay.cs | 3 ++- .../Visual/UserInterface/TestSceneLoadingLayer.cs | 5 +++-- .../Visual/UserInterface/TestSceneOsuPopover.cs | 8 ++++---- .../TestSceneScreenBreadcrumbControl.cs | 3 ++- .../Screens/Setup/ActionableInfo.cs | 2 +- .../Screens/Setup/StablePathSelectScreen.cs | 4 ++-- .../Screens/Setup/TournamentSwitcher.cs | 3 ++- ...TriangleButton.cs => DangerousRoundedButton.cs} | 3 ++- osu.Game/Graphics/UserInterface/TriangleButton.cs | 14 -------------- .../Overlays/BeatmapSet/Buttons/HeaderButton.cs | 4 ++-- .../Overlays/Dashboard/CurrentlyPlayingDisplay.cs | 2 +- .../Settings/Sections/Input/KeyBindingRow.cs | 5 +++-- .../Sections/Maintenance/DirectorySelectScreen.cs | 5 ++--- osu.Game/Screens/Import/FileImportScreen.cs | 5 ++--- .../Components/MatchBeatmapDetailArea.cs | 4 ++-- .../Screens/OnlinePlay/Components/ReadyButton.cs | 4 ++-- .../OnlinePlay/Lounge/DrawableLoungeRoom.cs | 4 ++-- .../Match/Components/CreateRoomButton.cs | 2 +- ...pleTriangleButton.cs => PurpleRoundedButton.cs} | 6 ++---- .../Screens/OnlinePlay/Match/DrawableMatchRoom.cs | 2 +- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 2 +- .../Match/MultiplayerMatchSettingsOverlay.cs | 7 ++++--- .../Multiplayer/Match/MultiplayerSpectateButton.cs | 6 +++--- .../Multiplayer/MultiplayerMatchSubScreen.cs | 2 +- .../Playlists/PlaylistsRoomSettingsOverlay.cs | 9 +++++---- osu.Game/Screens/Play/SoloSpectator.cs | 6 +++--- .../Tests/Visual/OsuManualInputManagerTestScene.cs | 10 +++++----- 27 files changed, 60 insertions(+), 70 deletions(-) rename osu.Game/Graphics/UserInterface/{DangerousTriangleButton.cs => DangerousRoundedButton.cs} (80%) delete mode 100644 osu.Game/Graphics/UserInterface/TriangleButton.cs rename osu.Game/Screens/OnlinePlay/Match/Components/{PurpleTriangleButton.cs => PurpleRoundedButton.cs} (80%) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs index c71bdb3a06..811135435c 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay; using osu.Game.Screens.OnlinePlay.Playlists; @@ -148,7 +149,7 @@ namespace osu.Game.Tests.Visual.Playlists private class TestRoomSettings : PlaylistsRoomSettingsOverlay { - public TriangleButton ApplyButton => ((MatchSettings)Settings).ApplyButton; + public RoundedButton ApplyButton => ((MatchSettings)Settings).ApplyButton; public OsuTextBox NameField => ((MatchSettings)Settings).NameField; public OsuDropdown DurationField => ((MatchSettings)Settings).DurationField; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs index 2fc6405b88..9afb93236e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Utils; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osuTK; using osuTK.Graphics; @@ -49,8 +50,8 @@ namespace osu.Game.Tests.Visual.UserInterface Children = new Drawable[] { new OsuSpriteText { Text = "Sample content" }, - new TriangleButton { Text = "can't puush me", Width = 200, }, - new TriangleButton { Text = "puush me", Width = 200, Action = () => { } }, + new RoundedButton { Text = "can't puush me", Width = 200, }, + new RoundedButton { Text = "puush me", Width = 200, Action = () => { } }, } }, overlay = new TestLoadingLayer(true), diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuPopover.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuPopover.cs index 6cc89a6df8..e286578f56 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuPopover.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuPopover.cs @@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual.UserInterface Text = @"No OverlayColourProvider", Font = OsuFont.Default.With(size: 40) }, - new TriangleButtonWithPopover() + new RoundedButtonWithPopover() } }; @@ -50,15 +50,15 @@ namespace osu.Game.Tests.Visual.UserInterface Text = @"With OverlayColourProvider (orange)", Font = OsuFont.Default.With(size: 40) }, - new TriangleButtonWithPopover() + new RoundedButtonWithPopover() } } }; } - private class TriangleButtonWithPopover : TriangleButton, IHasPopover + private class RoundedButtonWithPopover : RoundedButton, IHasPopover { - public TriangleButtonWithPopover() + public RoundedButtonWithPopover() { Width = 100; Height = 30; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs index b3ee0af78b..7cfcc9de1f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs @@ -11,6 +11,7 @@ using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Screens; using osuTK; @@ -109,7 +110,7 @@ namespace osu.Game.Tests.Visual.UserInterface Origin = Anchor.TopCentre, Text = Title, }, - new TriangleButton + new RoundedButton { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, diff --git a/osu.Game.Tournament/Screens/Setup/ActionableInfo.cs b/osu.Game.Tournament/Screens/Setup/ActionableInfo.cs index a9ac21284e..1172c26ffa 100644 --- a/osu.Game.Tournament/Screens/Setup/ActionableInfo.cs +++ b/osu.Game.Tournament/Screens/Setup/ActionableInfo.cs @@ -61,7 +61,7 @@ namespace osu.Game.Tournament.Screens.Setup Spacing = new Vector2(10, 0), Children = new Drawable[] { - Button = new TriangleButton + Button = new RoundedButton { Size = new Vector2(100, 40), Action = () => Action?.Invoke() diff --git a/osu.Game.Tournament/Screens/Setup/StablePathSelectScreen.cs b/osu.Game.Tournament/Screens/Setup/StablePathSelectScreen.cs index fac488fcf5..32ac75178e 100644 --- a/osu.Game.Tournament/Screens/Setup/StablePathSelectScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/StablePathSelectScreen.cs @@ -93,7 +93,7 @@ namespace osu.Game.Tournament.Screens.Setup Spacing = new Vector2(20), Children = new Drawable[] { - new TriangleButton + new RoundedButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -101,7 +101,7 @@ namespace osu.Game.Tournament.Screens.Setup Text = "Select stable path", Action = ChangePath }, - new TriangleButton + new RoundedButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs b/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs index 447d6f44ce..1a1c90e96a 100644 --- a/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs +++ b/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Tournament.IO; namespace osu.Game.Tournament.Screens.Setup @@ -37,7 +38,7 @@ namespace osu.Game.Tournament.Screens.Setup { var drawable = base.CreateComponent(); - FlowContainer.Insert(-1, folderButton = new TriangleButton + FlowContainer.Insert(-1, folderButton = new RoundedButton { Text = "Open folder", Width = 100 diff --git a/osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs b/osu.Game/Graphics/UserInterface/DangerousRoundedButton.cs similarity index 80% rename from osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs rename to osu.Game/Graphics/UserInterface/DangerousRoundedButton.cs index 3c78cbb634..265ac01253 100644 --- a/osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs +++ b/osu.Game/Graphics/UserInterface/DangerousRoundedButton.cs @@ -4,10 +4,11 @@ #nullable disable using osu.Framework.Allocation; +using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Graphics.UserInterface { - public class DangerousTriangleButton : TriangleButton + public class DangerousRoundedButton : RoundedButton { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Graphics/UserInterface/TriangleButton.cs b/osu.Game/Graphics/UserInterface/TriangleButton.cs deleted file mode 100644 index 891c8f779f..0000000000 --- a/osu.Game/Graphics/UserInterface/TriangleButton.cs +++ /dev/null @@ -1,14 +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.Game.Graphics.UserInterfaceV2; - -namespace osu.Game.Graphics.UserInterface -{ - /// - /// A button with moving triangles in the background. - /// - public class TriangleButton : RoundedButton - { - } -} diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs index d6bf3464da..3b22ff594c 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs @@ -4,11 +4,11 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Overlays.BeatmapSet.Buttons { - public class HeaderButton : TriangleButton + public class HeaderButton : RoundedButton { public HeaderButton() { diff --git a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs index aae4932c22..571393f617 100644 --- a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs +++ b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs @@ -203,7 +203,7 @@ namespace osu.Game.Overlays.Dashboard Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, }, - new PurpleTriangleButton + new PurpleRoundedButton { RelativeSizeAxes = Axes.X, Text = "Spectate", diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 25ab8cfad2..386fee9d55 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -22,6 +22,7 @@ using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Input; using osu.Game.Input.Bindings; using osu.Game.Resources.Localisation.Web; @@ -446,7 +447,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input isDefault.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); } - private class CancelButton : TriangleButton + private class CancelButton : RoundedButton { public CancelButton() { @@ -455,7 +456,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - public class ClearButton : DangerousTriangleButton + public class ClearButton : DangerousRoundedButton { public ClearButton() { diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs index 1c9a758c6f..539600c7ca 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs @@ -13,7 +13,6 @@ using osuTK; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Localisation; -using osu.Game.Graphics.UserInterface; using osu.Framework.Screens; using osu.Game.Graphics.Containers; using osu.Game.Localisation; @@ -22,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { public abstract class DirectorySelectScreen : OsuScreen { - private TriangleButton selectionButton; + private RoundedButton selectionButton; private OsuDirectorySelector directorySelector; @@ -101,7 +100,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance }, new Drawable[] { - selectionButton = new TriangleButton + selectionButton = new RoundedButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/Import/FileImportScreen.cs b/osu.Game/Screens/Import/FileImportScreen.cs index e3d8de2dfd..e63fb95fc0 100644 --- a/osu.Game/Screens/Import/FileImportScreen.cs +++ b/osu.Game/Screens/Import/FileImportScreen.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osuTK; @@ -28,7 +27,7 @@ namespace osu.Game.Screens.Import private Container contentContainer; private TextFlowContainer currentFileText; - private TriangleButton importButton; + private RoundedButton importButton; private const float duration = 300; private const float button_height = 50; @@ -100,7 +99,7 @@ namespace osu.Game.Screens.Import } }, }, - importButton = new TriangleButton + importButton = new RoundedButton { Text = "Import", Anchor = Anchor.BottomCentre, diff --git a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs index 9a48769405..6d477be568 100644 --- a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs +++ b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs @@ -9,7 +9,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Select; @@ -54,7 +54,7 @@ namespace osu.Game.Screens.OnlinePlay.Components }, new Drawable[] { - new TriangleButton + new RoundedButton { Text = "Add new playlist entry", RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs index 0871fc9a72..ae0f8cb3e4 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs @@ -7,13 +7,13 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online; using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Components { - public abstract class ReadyButton : TriangleButton, IHasTooltip + public abstract class ReadyButton : RoundedButton, IHasTooltip { public new readonly BindableBool Enabled = new BindableBool(); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index 8a2aeb9e5e..c53324288d 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -197,7 +197,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge } private OsuPasswordTextBox passwordTextBox; - private TriangleButton joinButton; + private RoundedButton joinButton; private OsuSpriteText errorText; private Sample sampleJoinFail; @@ -226,7 +226,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge Width = 200, PlaceholderText = "password", }, - joinButton = new TriangleButton + joinButton = new RoundedButton { Width = 80, Text = "Join Room", diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs index 20e4b78eb4..4f42540146 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs @@ -10,7 +10,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public abstract class CreateRoomButton : PurpleTriangleButton, IKeyBindingHandler + public abstract class CreateRoomButton : PurpleRoundedButton, IKeyBindingHandler { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/PurpleRoundedButton.cs similarity index 80% rename from osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/PurpleRoundedButton.cs index c6df53c368..869806d21f 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/PurpleRoundedButton.cs @@ -1,15 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public class PurpleTriangleButton : TriangleButton + public class PurpleRoundedButton : RoundedButton { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs index 7c444b9bbd..7b0b0bdaa4 100644 --- a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.OnlinePlay.Match { if (allowEdit) { - ButtonsContainer.Add(editButton = new PurpleTriangleButton + ButtonsContainer.Add(editButton = new PurpleRoundedButton { RelativeSizeAxes = Axes.Y, Size = new Vector2(100, 1), diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 00c819e5e4..a4ef0297cf 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -517,7 +517,7 @@ namespace osu.Game.Screens.OnlinePlay.Match /// The room to change the settings of. protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room); - public class UserModSelectButton : PurpleTriangleButton, IKeyBindingHandler + public class UserModSelectButton : PurpleRoundedButton, IKeyBindingHandler { public bool OnPressed(KeyBindingPressEvent e) { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 17c361a420..6e0c81ab21 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -16,6 +16,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Overlays; @@ -64,7 +65,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match public OsuEnumDropdown QueueModeDropdown = null!; public OsuTextBox PasswordTextBox = null!; public OsuCheckbox AutoSkipCheckbox = null!; - public TriangleButton ApplyButton = null!; + public RoundedButton ApplyButton = null!; public OsuSpriteText ErrorText = null!; @@ -274,7 +275,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match RelativeSizeAxes = Axes.X, Height = DrawableRoomPlaylistItem.HEIGHT }, - new PurpleTriangleButton + new PurpleRoundedButton { RelativeSizeAxes = Axes.X, Height = 40, @@ -460,7 +461,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match }); } - public class CreateOrUpdateButton : TriangleButton + public class CreateOrUpdateButton : RoundedButton { [Resolved(typeof(Room), nameof(Room.RoomID))] private Bindable roomId { get; set; } = null!; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs index 51f11341cc..89b3e980e6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs @@ -7,7 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.Multiplayer; using osuTK; @@ -23,11 +23,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private IBindable operationInProgress; - private readonly TriangleButton button; + private readonly RoundedButton button; public MultiplayerSpectateButton() { - InternalChild = button = new TriangleButton + InternalChild = button = new RoundedButton { RelativeSizeAxes = Axes.Both, Size = Vector2.One, diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index db752f2b42..969b8e61d3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -430,7 +430,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer modSettingChangeTracker?.Dispose(); } - public class AddItemButton : PurpleTriangleButton + public class AddItemButton : PurpleRoundedButton { } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index 3c57ea5a3b..e4fcf0cbac 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -16,6 +16,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; @@ -58,7 +59,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists public OsuTextBox NameField = null!, MaxParticipantsField = null!, MaxAttemptsField = null!; public OsuDropdown DurationField = null!; public RoomAvailabilityPicker AvailabilityPicker = null!; - public TriangleButton ApplyButton = null!; + public RoundedButton ApplyButton = null!; public bool IsLoading => loadingLayer.State.Value == Visibility.Visible; @@ -68,7 +69,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists private DrawableRoomPlaylist playlist = null!; private OsuSpriteText playlistLength = null!; - private PurpleTriangleButton editPlaylistButton = null!; + private PurpleRoundedButton editPlaylistButton = null!; [Resolved] private IRoomManager? manager { get; set; } @@ -222,7 +223,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists }, new Drawable[] { - editPlaylistButton = new PurpleTriangleButton + editPlaylistButton = new PurpleRoundedButton { RelativeSizeAxes = Axes.X, Height = 40, @@ -414,7 +415,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists } } - public class CreateRoomButton : TriangleButton + public class CreateRoomButton : RoundedButton { public CreateRoomButton() { diff --git a/osu.Game/Screens/Play/SoloSpectator.cs b/osu.Game/Screens/Play/SoloSpectator.cs index 9ef05c3a05..2f1c86e639 100644 --- a/osu.Game/Screens/Play/SoloSpectator.cs +++ b/osu.Game/Screens/Play/SoloSpectator.cs @@ -18,7 +18,7 @@ using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Play private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); private Container beatmapPanelContainer; - private TriangleButton watchButton; + private RoundedButton watchButton; private SettingsCheckbox automaticDownload; /// @@ -147,7 +147,7 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - watchButton = new PurpleTriangleButton + watchButton = new PurpleRoundedButton { Text = "Start Watching", Width = 250, diff --git a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs index e56c546bac..3c569038b4 100644 --- a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs +++ b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs @@ -12,7 +12,7 @@ using osu.Framework.Testing; using osu.Framework.Testing.Input; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Input.Bindings; using osuTK; using osuTK.Graphics; @@ -27,8 +27,8 @@ namespace osu.Game.Tests.Visual protected readonly ManualInputManager InputManager; - private readonly TriangleButton buttonTest; - private readonly TriangleButton buttonLocal; + private readonly RoundedButton buttonTest; + private readonly RoundedButton buttonLocal; /// /// Whether to create a nested container to handle s that result from local (manual) test input. @@ -110,13 +110,13 @@ namespace osu.Game.Tests.Visual Children = new Drawable[] { - buttonLocal = new TriangleButton + buttonLocal = new RoundedButton { Text = "local", Size = new Vector2(50, 30), Action = returnUserInput }, - buttonTest = new TriangleButton + buttonTest = new RoundedButton { Text = "test", Size = new Vector2(50, 30), From 6ad432b311a457d90bebf0fe55304fde76c8d005 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Nov 2022 16:33:01 +0900 Subject: [PATCH 2391/2686] Use `RoundedButton` in more places --- osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs | 13 +++++++++---- .../Multiplayer/Match/MultiplayerCountdownButton.cs | 4 ++-- .../Match/MultiplayerMatchSettingsOverlay.cs | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs index 3d970284ec..4de4a14042 100644 --- a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -21,7 +22,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 protected override float HoverLayerFinalAlpha => 0; - private Color4 triangleGradientSecondColour = Color4.Transparent; + private Color4? triangleGradientSecondColour; public override float Height { @@ -53,7 +54,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 // Not sure this is the correct direction, but we haven't decided on an `OverlayColourProvider` stand-in yet. // This is a better default. See `SettingsButton` for an override which uses `OverlayColourProvider`. DefaultBackgroundColour = overlayColourProvider?.Colour3 ?? colours.Blue3; - triangleGradientSecondColour = overlayColourProvider?.Colour1 ?? colours.Blue3.Lighten(0.2f); + triangleGradientSecondColour ??= overlayColourProvider?.Colour1 ?? colours.Blue3.Lighten(0.2f); } protected override void LoadComplete() @@ -78,13 +79,17 @@ namespace osu.Game.Graphics.UserInterfaceV2 if (triangles == null) return; - triangles.ColourTop = triangleGradientSecondColour; + Debug.Assert(triangleGradientSecondColour != null); + + triangles.ColourTop = triangleGradientSecondColour.Value; triangles.ColourBottom = BackgroundColour; } protected override bool OnHover(HoverEvent e) { - Background.FadeColour(triangleGradientSecondColour, 300, Easing.OutQuint); + Debug.Assert(triangleGradientSecondColour != null); + + Background.FadeColour(triangleGradientSecondColour.Value, 300, Easing.OutQuint); return base.OnHover(e); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs index cd94b47d9e..c28e6d36e9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs @@ -109,7 +109,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match foreach (var duration in available_delays) { - flow.Add(new OsuButton + flow.Add(new RoundedButton { RelativeSizeAxes = Axes.X, Text = $"Start match in {duration.Humanize()}", @@ -124,7 +124,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match if (multiplayerClient.Room?.ActiveCountdowns.Any(c => c is MatchStartCountdown) == true && multiplayerClient.IsHost) { - flow.Add(new OsuButton + flow.Add(new RoundedButton { RelativeSizeAxes = Axes.X, Text = "Stop countdown", diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 6e0c81ab21..7c4b71b920 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -275,7 +275,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match RelativeSizeAxes = Axes.X, Height = DrawableRoomPlaylistItem.HEIGHT }, - new PurpleRoundedButton + new RoundedButton { RelativeSizeAxes = Axes.X, Height = 40, From 7b620392fe6430e8d8c948ef097839da219860ed Mon Sep 17 00:00:00 2001 From: Derrick Timmermans Date: Thu, 24 Nov 2022 13:13:45 +0100 Subject: [PATCH 2392/2686] Provide DrawableRulesetDependencies from HitObjectComposer --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 520fcb0290..d19ab2239e 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Edit } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => - dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + dependencies = new DrawableRulesetDependencies(Ruleset, base.CreateChildDependencies(parent)); [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) From f6e229c24dd1e730a88807b8edcb3b38997f68ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2022 01:15:11 +0900 Subject: [PATCH 2393/2686] "Fix" mod copy failure --- osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs | 4 ++-- osu.Game/Rulesets/Mods/ModMuted.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs index 68669d1a53..d7d24c99ee 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs @@ -45,8 +45,8 @@ namespace osu.Game.Rulesets.Osu.Tests.Mods InverseMuting = { Value = false }, })); - AddAssert("mute combo count = 0", () => muted.MuteComboCount.Value == 0); - AddAssert("inverse muting = false", () => muted.InverseMuting.Value == false); + AddAssert("mute combo count copied", () => muted.MuteComboCount.Value, () => Is.EqualTo(0)); + AddAssert("inverse muting copied", () => muted.InverseMuting.Value, () => Is.False); } } } diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 05ecd37000..27a777bff7 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -35,6 +35,9 @@ namespace osu.Game.Rulesets.Mods private readonly BindableNumber currentCombo = new BindableInt(); + [SettingSource("Start muted", "Increase volume as combo builds.")] + public BindableBool InverseMuting { get; } = new BindableBool(); + [SettingSource("Enable metronome", "Add a metronome beat to help you keep track of the rhythm.")] public BindableBool EnableMetronome { get; } = new BindableBool(true); @@ -45,9 +48,6 @@ namespace osu.Game.Rulesets.Mods MaxValue = 500, }; - [SettingSource("Start muted", "Increase volume as combo builds.")] - public BindableBool InverseMuting { get; } = new BindableBool(); - [SettingSource("Mute hit sounds", "Hit sounds are also muted alongside the track.")] public BindableBool AffectsHitSounds { get; } = new BindableBool(true); From ba0990d43e217fc4a7be954366549b4cdd2fe873 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2022 01:44:52 +0900 Subject: [PATCH 2394/2686] Update test assumptions --- .../Visual/UserInterface/TestSceneRoundedButton.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs index 178a68b599..6a8fe83176 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs @@ -9,7 +9,6 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; -using osu.Game.Graphics; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Overlays; using osu.Game.Overlays.Settings; @@ -56,8 +55,8 @@ namespace osu.Game.Tests.Visual.UserInterface public void TestBackgroundColour() { AddStep("set red scheme", () => CreateThemedContent(OverlayColourScheme.Red)); - AddAssert("rounded button has correct colour", () => Cell(0, 1).ChildrenOfType().First().BackgroundColour == new OsuColour().Blue3); - AddAssert("settings button has correct colour", () => Cell(0, 1).ChildrenOfType().First().BackgroundColour == new OverlayColourProvider(OverlayColourScheme.Red).Highlight1); + AddAssert("rounded button has correct colour", () => Cell(0, 1).ChildrenOfType().First().BackgroundColour == new OverlayColourProvider(OverlayColourScheme.Red).Colour3); + AddAssert("settings button has correct colour", () => Cell(0, 1).ChildrenOfType().First().BackgroundColour == new OverlayColourProvider(OverlayColourScheme.Red).Colour3); } } } From 65e5c9a3ae32c0786171d2a09d949e075569a5f7 Mon Sep 17 00:00:00 2001 From: Derrick Timmermans Date: Fri, 25 Nov 2022 08:27:22 +0100 Subject: [PATCH 2395/2686] Dispose DrawableRulesetDependencies in HitObjectComposer --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index d19ab2239e..d0164d0f2e 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Edit protected readonly Ruleset Ruleset; // Provides `Playfield` - private DependencyContainer dependencies; + private DrawableRulesetDependencies dependencies; [Resolved] protected EditorClock EditorClock { get; private set; } @@ -410,6 +410,13 @@ namespace osu.Game.Rulesets.Edit } #endregion + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + dependencies.Dispose(); + } } /// From 25410c9962ab4fb8d4e45314630987f3b0de0c76 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2022 19:47:55 +0900 Subject: [PATCH 2396/2686] Avoid changing ruleset when presenting a beatmap if it can be converted Closes #21415. --- osu.Game/OsuGame.cs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index a93c187e53..7eae27eabd 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -520,11 +520,29 @@ namespace osu.Game } else { - Logger.Log($"Completing {nameof(PresentBeatmap)} with beatmap {beatmap} ruleset {selection.Ruleset}"); - Ruleset.Value = selection.Ruleset; - Beatmap.Value = BeatmapManager.GetWorkingBeatmap(selection); + // Don't change the local ruleset if the user is on another ruleset and is showing converted beatmaps at song select. + // Eventually we probably want to check whether conversion is actually possible for the current ruleset. + bool requiresRulesetSwitch = !selection.Ruleset.Equals(Ruleset.Value) + && (selection.Ruleset.OnlineID > 0 || !LocalConfig.Get(OsuSetting.ShowConvertedBeatmaps)); + + if (requiresRulesetSwitch) + { + Ruleset.Value = selection.Ruleset; + Beatmap.Value = BeatmapManager.GetWorkingBeatmap(selection); + + Logger.Log($"Completing {nameof(PresentBeatmap)} with beatmap {beatmap} ruleset {selection.Ruleset}"); + } + else + { + Beatmap.Value = BeatmapManager.GetWorkingBeatmap(selection); + + Logger.Log($"Completing {nameof(PresentBeatmap)} with beatmap {beatmap} (maintaining ruleset)"); + } } - }, validScreens: new[] { typeof(SongSelect), typeof(IHandlePresentBeatmap) }); + }, validScreens: new[] + { + typeof(SongSelect), typeof(IHandlePresentBeatmap) + }); } /// From 2425878e676c10205f54d74388630ebba518b237 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2022 20:06:36 +0900 Subject: [PATCH 2397/2686] Add test coverage --- .../Navigation/TestScenePresentBeatmap.cs | 66 ++++++++++++++----- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs index 02b348b439..ce8c8d4af5 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs @@ -9,8 +9,10 @@ using NUnit.Framework; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Extensions; using osu.Game.Rulesets; +using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Menu; @@ -71,17 +73,51 @@ namespace osu.Game.Tests.Visual.Navigation } [Test] - public void TestFromSongSelectDifferentRuleset() + public void TestFromSongSelectDifferentRulesetWithConvertDisallowed() { - var firstImport = importBeatmap(1); - presentAndConfirm(firstImport); + AddStep("Set converts disallowed", () => Game.LocalConfig.SetValue(OsuSetting.ShowConvertedBeatmaps, false)); - var secondImport = importBeatmap(3, new ManiaRuleset().RulesetInfo); - confirmBeatmapInSongSelect(secondImport); - presentAndConfirm(secondImport); + var osuImport = importBeatmap(1); + presentAndConfirm(osuImport); - presentSecondDifficultyAndConfirm(firstImport, 1); - presentSecondDifficultyAndConfirm(secondImport, 3); + var maniaImport = importBeatmap(2, new ManiaRuleset().RulesetInfo); + confirmBeatmapInSongSelect(maniaImport); + presentAndConfirm(maniaImport); + + var catchImport = importBeatmap(3, new CatchRuleset().RulesetInfo); + confirmBeatmapInSongSelect(catchImport); + presentAndConfirm(catchImport); + + // Ruleset is always changed. + presentSecondDifficultyAndConfirm(maniaImport, 2); + presentSecondDifficultyAndConfirm(osuImport, 1); + presentSecondDifficultyAndConfirm(catchImport, 3); + } + + [Test] + public void TestFromSongSelectDifferentRulesetWithConvertAllowed() + { + AddStep("Set converts allowed", () => Game.LocalConfig.SetValue(OsuSetting.ShowConvertedBeatmaps, true)); + + var osuImport = importBeatmap(1); + presentAndConfirm(osuImport); + + var maniaImport = importBeatmap(2, new ManiaRuleset().RulesetInfo); + confirmBeatmapInSongSelect(maniaImport); + presentAndConfirm(maniaImport); + + var catchImport = importBeatmap(3, new CatchRuleset().RulesetInfo); + confirmBeatmapInSongSelect(catchImport); + presentAndConfirm(catchImport); + + // force ruleset to osu!mania + presentSecondDifficultyAndConfirm(maniaImport, 2); + + // ruleset is not changed as we can convert osu! beatmap. + presentSecondDifficultyAndConfirm(osuImport, 1, expectedRulesetOnlineID: 3); + + // ruleset is changed as we cannot convert. + presentSecondDifficultyAndConfirm(catchImport, 3); } private void returnToMenu() @@ -112,19 +148,19 @@ namespace osu.Game.Tests.Visual.Navigation imported = Game.BeatmapManager.Import(new BeatmapSetInfo { Hash = Guid.NewGuid().ToString(), - OnlineID = i, + OnlineID = i * 1024, Beatmaps = { new BeatmapInfo { - OnlineID = i * 1024, + OnlineID = i * 1024 + 1, Metadata = metadata, Difficulty = new BeatmapDifficulty(), Ruleset = ruleset ?? new OsuRuleset().RulesetInfo }, new BeatmapInfo { - OnlineID = i * 2048, + OnlineID = i * 1024 + 2, Metadata = metadata, Difficulty = new BeatmapDifficulty(), Ruleset = ruleset ?? new OsuRuleset().RulesetInfo @@ -156,14 +192,14 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("correct ruleset selected", () => Game.Ruleset.Value, () => Is.EqualTo(getImport().Beatmaps.First().Ruleset)); } - private void presentSecondDifficultyAndConfirm(Func getImport, int importedID) + private void presentSecondDifficultyAndConfirm(Func getImport, int importedID, int? expectedRulesetOnlineID = null) { - Predicate pred = b => b.OnlineID == importedID * 2048; + Predicate pred = b => b.OnlineID == importedID * 1024 + 2; AddStep("present difficulty", () => Game.PresentBeatmap(getImport(), pred)); AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect songSelect && songSelect.IsLoaded); - AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineID, () => Is.EqualTo(importedID * 2048)); - AddAssert("correct ruleset selected", () => Game.Ruleset.Value, () => Is.EqualTo(getImport().Beatmaps.First().Ruleset)); + AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineID, () => Is.EqualTo(importedID * 1024 + 2)); + AddAssert("correct ruleset selected", () => Game.Ruleset.Value.OnlineID, () => Is.EqualTo(expectedRulesetOnlineID ?? getImport().Beatmaps.First().Ruleset.OnlineID)); } } } From 4cb068ceb9f495cbd311c57aa33d50959eef1984 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2022 20:10:04 +0900 Subject: [PATCH 2398/2686] Change `AimCount` to not consider height --- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 5fc32ff704..02ab9a9367 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -172,7 +172,7 @@ namespace osu.Game.Graphics.Backgrounds // Limited by the maximum size of QuadVertexBuffer for safety. const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2); - AimCount = (int)Math.Min(max_triangles, DrawWidth * DrawHeight * 0.0005f * SpawnRatio); + AimCount = (int)Math.Min(max_triangles, DrawWidth * 0.02f * SpawnRatio); int currentCount = parts.Count; From b0f14d49633ecf9febd4fa90cb3e6ce08c5d8d36 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2022 20:14:21 +0900 Subject: [PATCH 2399/2686] Clamp `AimCount` to ensure at least one triangle is spawned --- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 02ab9a9367..77d30d50d6 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -172,7 +172,7 @@ namespace osu.Game.Graphics.Backgrounds // Limited by the maximum size of QuadVertexBuffer for safety. const int max_triangles = ushort.MaxValue / (IRenderer.VERTICES_PER_QUAD + 2); - AimCount = (int)Math.Min(max_triangles, DrawWidth * 0.02f * SpawnRatio); + AimCount = (int)Math.Clamp(DrawWidth * 0.02f * SpawnRatio, 1, max_triangles); int currentCount = parts.Count; From d0c46376837c1e7cda2f771428eadda7d63cc44b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2022 20:18:21 +0900 Subject: [PATCH 2400/2686] Lighten colour of multiplayer create game button --- .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 7c4b71b920..ea4df23c4a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -475,7 +475,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match [BackgroundDependencyLoader] private void load(OsuColour colours) { - BackgroundColour = colours.Yellow; + BackgroundColour = colours.YellowDark; } } From 76e9382e0be1812f50e9c5147717cf524bf0aca7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2022 20:18:35 +0900 Subject: [PATCH 2401/2686] Fix triangles showing on `ExpandableButton`s when in contracted state --- osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs | 10 +++++----- osu.Game/Rulesets/Edit/ExpandableButton.cs | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs index 4de4a14042..c40622190f 100644 --- a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs @@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { public class RoundedButton : OsuButton, IFilterable { - private TrianglesV2? triangles; + protected TrianglesV2? Triangles { get; private set; } protected override float HoverLayerFinalAlpha => 0; @@ -63,7 +63,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 updateCornerRadius(); - Add(triangles = new TrianglesV2 + Add(Triangles = new TrianglesV2 { Thickness = 0.02f, SpawnRatio = 0.6f, @@ -76,13 +76,13 @@ namespace osu.Game.Graphics.UserInterfaceV2 private void updateColours() { - if (triangles == null) + if (Triangles == null) return; Debug.Assert(triangleGradientSecondColour != null); - triangles.ColourTop = triangleGradientSecondColour.Value; - triangles.ColourBottom = BackgroundColour; + Triangles.ColourTop = triangleGradientSecondColour.Value; + Triangles.ColourBottom = BackgroundColour; } protected override bool OnHover(HoverEvent e) diff --git a/osu.Game/Rulesets/Edit/ExpandableButton.cs b/osu.Game/Rulesets/Edit/ExpandableButton.cs index a66600bd58..91bcc21c1b 100644 --- a/osu.Game/Rulesets/Edit/ExpandableButton.cs +++ b/osu.Game/Rulesets/Edit/ExpandableButton.cs @@ -86,6 +86,7 @@ namespace osu.Game.Rulesets.Edit SpriteText.Font = OsuFont.GetFont(weight: FontWeight.Bold); base.Height = actualHeight; Background.Show(); + Triangles?.Show(); } else { @@ -94,6 +95,7 @@ namespace osu.Game.Rulesets.Edit SpriteText.Font = OsuFont.GetFont(weight: FontWeight.Regular); base.Height = actualHeight / 2; Background.Hide(); + Triangles?.Hide(); } }, true); } From 5ada9efa60cbb984957d12869a2090441ca14d7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Nov 2022 22:10:20 +0900 Subject: [PATCH 2402/2686] Update outdated comment regarding colour choices --- osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs index c40622190f..fef9993932 100644 --- a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs @@ -50,9 +50,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 [BackgroundDependencyLoader(true)] private void load(OverlayColourProvider? overlayColourProvider, OsuColour colours) { - // According to flyte, buttons are supposed to have explicit colours for now. - // Not sure this is the correct direction, but we haven't decided on an `OverlayColourProvider` stand-in yet. - // This is a better default. See `SettingsButton` for an override which uses `OverlayColourProvider`. + // Many buttons have local colours, but this provides a sane default for all other cases. DefaultBackgroundColour = overlayColourProvider?.Colour3 ?? colours.Blue3; triangleGradientSecondColour ??= overlayColourProvider?.Colour1 ?? colours.Blue3.Lighten(0.2f); } From a2ea7a3f58f6177ed116bf297b9af92e017a0858 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Thu, 8 Sep 2022 02:20:48 +0800 Subject: [PATCH 2403/2686] show selected mod and use ILocalisedBindableString in np --- .../Online/TestSceneNowPlayingCommand.cs | 11 +++++ osu.Game/Online/Chat/NowPlayingCommand.cs | 48 +++++++++++++++---- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs index 2df9089a8a..6dbe9a71d9 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs @@ -11,6 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.Chat; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Users; namespace osu.Game.Tests.Visual.Online @@ -77,6 +78,16 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Check link not present", () => !postTarget.LastMessage.Contains("https://")); } + [Test] + public void TestModPresence() + { + AddStep("Add Hidden mod", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateMod() }); + + AddStep("Run command", () => Add(new NowPlayingCommand())); + + AddAssert("Check mod is present", () => postTarget.LastMessage.Contains("+Hidden")); + } + public class PostTarget : Component, IChannelPostTarget { public void PostMessage(string text, bool isAction = false, Channel target = null) diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index 6a25ceb919..ea44bd93d8 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -1,13 +1,15 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System.Collections.Generic; +using System.Text; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Online.API; +using osu.Game.Rulesets.Mods; using osu.Game.Users; namespace osu.Game.Online.Chat @@ -15,21 +17,27 @@ namespace osu.Game.Online.Chat public class NowPlayingCommand : Component { [Resolved] - private IChannelPostTarget channelManager { get; set; } + private IChannelPostTarget channelManager { get; set; } = null!; [Resolved] - private IAPIProvider api { get; set; } + private IAPIProvider api { get; set; } = null!; [Resolved] - private Bindable currentBeatmap { get; set; } + private Bindable currentBeatmap { get; set; } = null!; - private readonly Channel target; + [Resolved] + private Bindable> selectedMods { get; set; } = null!; + + [Resolved] + private LocalisationManager localisation { get; set; } = null!; + + private readonly Channel? target; /// /// Creates a new to post the currently-playing beatmap to a parenting . /// /// The target channel to post to. If null, the currently-selected channel will be posted to. - public NowPlayingCommand(Channel target = null) + public NowPlayingCommand(Channel? target = null) { this.target = target; } @@ -59,9 +67,31 @@ namespace osu.Game.Online.Chat break; } - string beatmapString = beatmapInfo.OnlineID > 0 ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfo}]" : beatmapInfo.ToString(); + string beatmapString() + { + string beatmapInfoString = localisation.GetLocalisedBindableString(beatmapInfo.GetDisplayTitleRomanisable()).Value; - channelManager.PostMessage($"is {verb} {beatmapString}", true, target); + return beatmapInfo.OnlineID > 0 ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfoString}]" : beatmapInfoString; + } + + string modString() + { + if (selectedMods.Value.Count == 0) + { + return string.Empty; + } + + StringBuilder modS = new StringBuilder(); + + foreach (var mod in selectedMods.Value) + { + modS.Append($"+{mod.Name} "); + } + + return modS.ToString(); + } + + channelManager.PostMessage($"is {verb} {beatmapString()} {modString()}", true, target); Expire(); } } From bbbc1d0428c2aad95e138e8411520b50974d1fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 25 Nov 2022 18:23:28 +0100 Subject: [PATCH 2404/2686] Darken colour of playlists create button To match d0c46376837c1e7cda2f771428eadda7d63cc44b. --- .../OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index e4fcf0cbac..2ee55da77b 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -425,7 +425,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [BackgroundDependencyLoader] private void load(OsuColour colours) { - BackgroundColour = colours.Yellow; + BackgroundColour = colours.YellowDark; } } From 92ed2ed4eff4516b292da3ebc58969589d64103a Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sat, 26 Nov 2022 12:19:08 +0100 Subject: [PATCH 2405/2686] Refactor star "DifficultyRangeFilterControl" into generic range slider class --- .../TestSceneDifficultyRangeFilterControl.cs | 28 --- .../UserInterface/TestSceneRangeSlider.cs | 60 +++++ .../Graphics/UserInterface/RangeSlider.cs | 210 ++++++++++++++++++ .../Select/DifficultyRangeFilterControl.cs | 152 ------------- osu.Game/Screens/Select/FilterControl.cs | 10 +- 5 files changed, 279 insertions(+), 181 deletions(-) delete mode 100644 osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs create mode 100644 osu.Game/Graphics/UserInterface/RangeSlider.cs delete mode 100644 osu.Game/Screens/Select/DifficultyRangeFilterControl.cs diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs deleted file mode 100644 index 7ae2c6e5e2..0000000000 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs +++ /dev/null @@ -1,28 +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 NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Screens.Select; -using osuTK; - -namespace osu.Game.Tests.Visual.SongSelect -{ - public class TestSceneDifficultyRangeFilterControl : OsuTestScene - { - [Test] - public void TestBasic() - { - AddStep("create control", () => - { - Child = new DifficultyRangeFilterControl - { - Width = 200, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(3), - }; - }); - } - } -} diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs new file mode 100644 index 0000000000..6a8a6304c8 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs @@ -0,0 +1,60 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneRangeSlider : OsuTestScene + { + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + + private readonly BindableNumber customStart = new BindableNumber + { + MinValue = 0, + MaxValue = 100, + Precision = 0.001f + }; + + private readonly BindableNumber customEnd = new BindableNumber(100) + { + MinValue = 0, + MaxValue = 100, + Precision = 0.1f + }; + + [Test] + public void TestBasic() + { + AddStep("create Control", () => Child = new RangeSlider + { + Width = 200, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(3), + LowerBound = customStart, + UpperBound = customEnd, + TooltipSuffix = "suffix", + NubWidth = Nub.HEIGHT * 2, + DefaultStringLowerBound = "Start", + DefaultStringUpperBound = "End" + }); + AddStep("Test Range", () => + { + customStart.Value = 50; + customEnd.Value = 75; + }); + AddStep("Test nub pushing", () => + { + customStart.Value = 90; + }); + } + } +} diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs new file mode 100644 index 0000000000..d654adf626 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs @@ -0,0 +1,210 @@ +// 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.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Graphics.UserInterface +{ + public class RangeSlider : CompositeDrawable + { + /// + /// The lower limiting value + /// + public Bindable LowerBound + { + set => lowerBound.Current = value; + } + + /// + /// The upper limiting value + /// + public Bindable UpperBound + { + set => upperBound.Current = value; + } + + /// + /// Text that describes this RangeSlider's functionality + /// + public string Label + { + set => label.Text = value; + } + + public float NubWidth + { + set => lowerBound.NubWidth = upperBound.NubWidth = value; + } + + /// + /// Minimum difference between the lower bound and higher bound + /// + public float MinRange + { + set => minRange = value; + } + + /// + /// lower bound display for when it is set to its default value + /// + public string DefaultStringLowerBound + { + set => lowerBound.DefaultString = value; + } + + /// + /// upper bound display for when it is set to its default value + /// + public string DefaultStringUpperBound + { + set => upperBound.DefaultString = value; + } + + public LocalisableString DefaultTooltipLowerBound + { + set => lowerBound.DefaultTooltip = value; + } + + public LocalisableString DefaultTooltipUpperBound + { + set => upperBound.DefaultTooltip = value; + } + + public string TooltipSuffix + { + set => upperBound.TooltipSuffix = lowerBound.TooltipSuffix = value; + } + + private float minRange = 0.1f; + + private readonly OsuSpriteText label; + + private readonly LowerBoundSlider lowerBound; + private readonly UpperBoundSlider upperBound; + + public RangeSlider() + { + const float vertical_offset = 13; + + InternalChildren = new Drawable[] + { + label = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 14), + }, + upperBound = new UpperBoundSlider + { + KeyboardStep = 0.1f, + RelativeSizeAxes = Axes.X, + Y = vertical_offset, + }, + lowerBound = new LowerBoundSlider + { + KeyboardStep = 0.1f, + RelativeSizeAxes = Axes.X, + Y = vertical_offset, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + lowerBound.Current.ValueChanged += min => upperBound.Current.Value = Math.Max(min.NewValue + minRange, upperBound.Current.Value); + upperBound.Current.ValueChanged += max => lowerBound.Current.Value = Math.Min(max.NewValue - minRange, lowerBound.Current.Value); + } + + private class LowerBoundSlider : BoundSlider + { + protected override void LoadComplete() + { + base.LoadComplete(); + + LeftBox.Height = 6; // hide any colour bleeding from overlap + + AccentColour = BackgroundColour; + BackgroundColour = Color4.Transparent; + } + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + base.ReceivePositionalInputAt(screenSpacePos) + && screenSpacePos.X <= Nub.ScreenSpaceDrawQuad.TopRight.X; + } + + private class UpperBoundSlider : BoundSlider + { + protected override void LoadComplete() + { + base.LoadComplete(); + + RightBox.Height = 6; // just to match the left bar height really + } + + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + base.ReceivePositionalInputAt(screenSpacePos) + && screenSpacePos.X >= Nub.ScreenSpaceDrawQuad.TopLeft.X; + } + + protected class BoundSlider : OsuSliderBar + { + public string? DefaultString; + public LocalisableString? DefaultTooltip; + public string? TooltipSuffix; + public float NubWidth { get; set; } = Nub.HEIGHT; + + public override LocalisableString TooltipText => + (Current.IsDefault ? DefaultTooltip : Current.Value.ToString($@"0.## {TooltipSuffix}")) ?? Current.Value.ToString($@"0.## {TooltipSuffix}"); + + protected override bool OnHover(HoverEvent e) + { + base.OnHover(e); + return true; // Make sure only one nub shows hover effect at once. + } + + protected override void LoadComplete() + { + base.LoadComplete(); + Nub.Width = NubWidth; + RangePadding = Nub.Width / 2; + + OsuSpriteText currentDisplay; + + Nub.Add(currentDisplay = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Y = -0.5f, + Colour = Color4.White, + Font = OsuFont.Torus.With(size: 10), + }); + + Current.BindValueChanged(current => + { + currentDisplay.Text = (current.NewValue != Current.Default ? current.NewValue.ToString("N1") : DefaultString) ?? current.NewValue.ToString("N1"); + }, true); + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider? colourProvider) + { + if (colourProvider == null) return; + + AccentColour = colourProvider.Background2; + Nub.AccentColour = colourProvider.Background2; + Nub.GlowingAccentColour = colourProvider.Background1; + Nub.GlowColour = colourProvider.Background2; + } + } + } +} diff --git a/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs b/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs deleted file mode 100644 index 45e7ff4caa..0000000000 --- a/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs +++ /dev/null @@ -1,152 +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 osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Select -{ - internal class DifficultyRangeFilterControl : CompositeDrawable - { - private Bindable lowerStars = null!; - private Bindable upperStars = null!; - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - const float vertical_offset = 13; - - InternalChildren = new Drawable[] - { - new OsuSpriteText - { - Text = "Difficulty range", - Font = OsuFont.GetFont(size: 14), - }, - new MaximumStarsSlider - { - Current = config.GetBindable(OsuSetting.DisplayStarsMaximum), - KeyboardStep = 0.1f, - RelativeSizeAxes = Axes.X, - Y = vertical_offset, - }, - new MinimumStarsSlider - { - Current = config.GetBindable(OsuSetting.DisplayStarsMinimum), - KeyboardStep = 0.1f, - RelativeSizeAxes = Axes.X, - Y = vertical_offset, - } - }; - - lowerStars = config.GetBindable(OsuSetting.DisplayStarsMinimum); - upperStars = config.GetBindable(OsuSetting.DisplayStarsMaximum); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - lowerStars.ValueChanged += min => upperStars.Value = Math.Max(min.NewValue + 0.1, upperStars.Value); - upperStars.ValueChanged += max => lowerStars.Value = Math.Min(max.NewValue - 0.1, lowerStars.Value); - } - - private class MinimumStarsSlider : StarsSlider - { - public MinimumStarsSlider() - : base("0") - { - } - - public override LocalisableString TooltipText => Current.Value.ToString(@"0.## stars"); - - protected override void LoadComplete() - { - base.LoadComplete(); - - LeftBox.Height = 6; // hide any colour bleeding from overlap - - AccentColour = BackgroundColour; - BackgroundColour = Color4.Transparent; - } - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => - base.ReceivePositionalInputAt(screenSpacePos) - && screenSpacePos.X <= Nub.ScreenSpaceDrawQuad.TopRight.X; - } - - private class MaximumStarsSlider : StarsSlider - { - public MaximumStarsSlider() - : base("∞") - { - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - RightBox.Height = 6; // just to match the left bar height really - } - - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => - base.ReceivePositionalInputAt(screenSpacePos) - && screenSpacePos.X >= Nub.ScreenSpaceDrawQuad.TopLeft.X; - } - - private class StarsSlider : OsuSliderBar - { - private readonly string defaultString; - - public override LocalisableString TooltipText => Current.IsDefault - ? UserInterfaceStrings.NoLimit - : Current.Value.ToString(@"0.## stars"); - - protected StarsSlider(string defaultString) - { - this.defaultString = defaultString; - } - - protected override bool OnHover(HoverEvent e) - { - base.OnHover(e); - return true; // Make sure only one nub shows hover effect at once. - } - - protected override void LoadComplete() - { - base.LoadComplete(); - Nub.Width = Nub.HEIGHT; - RangePadding = Nub.Width / 2; - - OsuSpriteText currentDisplay; - - Nub.Add(currentDisplay = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Y = -0.5f, - Colour = Color4.White, - Font = OsuFont.Torus.With(size: 10), - }); - - Current.BindValueChanged(current => - { - currentDisplay.Text = current.NewValue != Current.Default ? current.NewValue.ToString("N1") : defaultString; - }, true); - } - } - } -} diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index ae82285fba..91ba394416 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -16,6 +16,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osu.Game.Screens.Select.Filter; @@ -172,12 +173,19 @@ namespace osu.Game.Screens.Select Height = 40, Children = new Drawable[] { - new DifficultyRangeFilterControl + new RangeSlider { Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, + Label = "Difficulty range", + LowerBound = config.GetBindable(OsuSetting.DisplayStarsMinimum), + UpperBound = config.GetBindable(OsuSetting.DisplayStarsMaximum), RelativeSizeAxes = Axes.Both, Width = 0.48f, + DefaultStringLowerBound = "0", + DefaultStringUpperBound = "∞", + DefaultTooltipUpperBound = UserInterfaceStrings.NoLimit, + TooltipSuffix = "stars" }, collectionDropdown = new CollectionDropdown { From 1ebaf4963d2cc71c8de39f473cba4d0414f6b432 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sat, 26 Nov 2022 13:59:05 +0100 Subject: [PATCH 2406/2686] Improve tests slightly --- .../Visual/UserInterface/TestSceneRangeSlider.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs index 6a8a6304c8..189a6b61f5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs @@ -14,13 +14,13 @@ namespace osu.Game.Tests.Visual.UserInterface public class TestSceneRangeSlider : OsuTestScene { [Cached] - private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Red); private readonly BindableNumber customStart = new BindableNumber { MinValue = 0, MaxValue = 100, - Precision = 0.001f + Precision = 0.1f }; private readonly BindableNumber customEnd = new BindableNumber(100) @@ -44,7 +44,8 @@ namespace osu.Game.Tests.Visual.UserInterface TooltipSuffix = "suffix", NubWidth = Nub.HEIGHT * 2, DefaultStringLowerBound = "Start", - DefaultStringUpperBound = "End" + DefaultStringUpperBound = "End", + MinRange = 10 }); AddStep("Test Range", () => { From a1c559ae0597f71ba96c2c8cb872aef54cc34060 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 27 Nov 2022 00:00:12 +0900 Subject: [PATCH 2407/2686] 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 eab3c1fe11..b1d6231210 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index cd32ff2fd1..9d7ef7fb22 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 4426eba75a..ae0bc2d0c0 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 7bc8908ca9c026fed1d831eb6e58df7624a8d614 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 24 Nov 2022 14:32:20 +0900 Subject: [PATCH 2408/2686] Partial everything --- .../TestSceneOsuGame.cs | 2 +- .../TestSceneOsuPlayer.cs | 2 +- .../EmptyFreeformInputManager.cs | 2 +- .../EmptyFreeformRuleset.cs | 4 ++-- .../DrawableEmptyFreeformHitObject.cs | 2 +- .../UI/DrawableEmptyFreeformRuleset.cs | 2 +- .../UI/EmptyFreeformPlayfield.cs | 2 +- .../TestSceneOsuGame.cs | 2 +- .../TestSceneOsuPlayer.cs | 2 +- .../Drawables/DrawablePippidonHitObject.cs | 2 +- .../PippidonInputManager.cs | 2 +- .../PippidonRulesetIcon.cs | 2 +- .../UI/DrawablePippidonRuleset.cs | 2 +- .../UI/PippidonCursorContainer.cs | 2 +- .../UI/PippidonPlayfield.cs | 2 +- .../PippidonPlayfieldAdjustmentContainer.cs | 2 +- .../TestSceneOsuGame.cs | 2 +- .../TestSceneOsuPlayer.cs | 2 +- .../EmptyScrollingInputManager.cs | 2 +- .../DrawableEmptyScrollingHitObject.cs | 2 +- .../UI/DrawableEmptyScrollingRuleset.cs | 2 +- .../UI/EmptyScrollingPlayfield.cs | 2 +- .../TestSceneOsuGame.cs | 2 +- .../TestSceneOsuPlayer.cs | 2 +- .../Drawables/DrawablePippidonHitObject.cs | 2 +- .../PippidonInputManager.cs | 2 +- .../PippidonRulesetIcon.cs | 2 +- .../UI/DrawablePippidonRuleset.cs | 2 +- .../UI/PippidonCharacter.cs | 2 +- .../UI/PippidonPlayfield.cs | 6 +++--- osu.Desktop/DiscordRichPresence.cs | 2 +- osu.Desktop/OsuGameDesktop.cs | 2 +- .../Security/ElevatedPrivilegesChecker.cs | 4 ++-- osu.Desktop/Updater/SquirrelUpdateManager.cs | 2 +- osu.Desktop/Windows/GameplayWinKeyBlocker.cs | 2 +- .../CatchSkinnableTestScene.cs | 2 +- .../Editor/CatchEditorTestSceneContainer.cs | 4 ++-- .../CatchPlacementBlueprintTestScene.cs | 2 +- .../CatchSelectionBlueprintTestScene.cs | 4 ++-- ...TestSceneBananaShowerPlacementBlueprint.cs | 2 +- .../Editor/TestSceneCatchDistanceSnapGrid.cs | 2 +- .../Editor/TestSceneEditor.cs | 2 +- .../TestSceneFruitPlacementBlueprint.cs | 2 +- .../TestSceneJuiceStreamPlacementBlueprint.cs | 2 +- .../TestSceneJuiceStreamSelectionBlueprint.cs | 2 +- .../Mods/TestSceneCatchModFlashlight.cs | 2 +- .../Mods/TestSceneCatchModNoScope.cs | 2 +- .../Mods/TestSceneCatchModPerfect.cs | 2 +- .../Mods/TestSceneCatchModRelax.cs | 2 +- .../TestSceneAutoJuiceStream.cs | 2 +- .../TestSceneBananaShower.cs | 2 +- .../TestSceneCatchModHidden.cs | 2 +- .../TestSceneCatchPlayer.cs | 2 +- .../TestSceneCatchPlayerLegacySkin.cs | 2 +- .../TestSceneCatchReplay.cs | 2 +- .../TestSceneCatchSkinConfiguration.cs | 2 +- .../TestSceneCatchStacker.cs | 2 +- .../TestSceneCatchTouchInput.cs | 2 +- .../TestSceneCatcher.cs | 4 ++-- .../TestSceneCatcherArea.cs | 4 ++-- .../TestSceneComboCounter.cs | 2 +- .../TestSceneDrawableHitObjects.cs | 2 +- .../TestSceneDrawableHitObjectsHidden.cs | 2 +- .../TestSceneFruitObjects.cs | 4 ++-- .../TestSceneFruitRandomness.cs | 2 +- .../TestSceneFruitVisualChange.cs | 2 +- .../TestSceneHyperDash.cs | 2 +- .../TestSceneHyperDashColouring.cs | 2 +- .../TestSceneJuiceStream.cs | 2 +- .../TestSceneLegacyBeatmapSkin.cs | 4 ++-- osu.Game.Rulesets.Catch/CatchInputManager.cs | 2 +- .../BananaShowerPlacementBlueprint.cs | 2 +- .../BananaShowerSelectionBlueprint.cs | 2 +- .../Blueprints/CatchPlacementBlueprint.cs | 2 +- .../Blueprints/CatchSelectionBlueprint.cs | 2 +- .../Blueprints/Components/EditablePath.cs | 2 +- .../Blueprints/Components/FruitOutline.cs | 2 +- .../Components/NestedOutlineContainer.cs | 2 +- .../Components/PlacementEditablePath.cs | 2 +- .../Blueprints/Components/ScrollingPath.cs | 2 +- .../Components/SelectionEditablePath.cs | 2 +- .../Blueprints/Components/TimeSpanOutline.cs | 2 +- .../Edit/Blueprints/Components/VertexPiece.cs | 2 +- .../Blueprints/FruitPlacementBlueprint.cs | 2 +- .../Blueprints/FruitSelectionBlueprint.cs | 2 +- .../JuiceStreamPlacementBlueprint.cs | 2 +- .../JuiceStreamSelectionBlueprint.cs | 2 +- .../Edit/CatchBlueprintContainer.cs | 2 +- .../Edit/CatchDistanceSnapGrid.cs | 2 +- .../Edit/CatchEditorPlayfield.cs | 2 +- ...CatchEditorPlayfieldAdjustmentContainer.cs | 4 ++-- .../Edit/CatchHitObjectComposer.cs | 2 +- .../Edit/CatchSelectionHandler.cs | 2 +- .../Edit/DrawableCatchEditorRuleset.cs | 2 +- .../Mods/CatchModFlashlight.cs | 4 ++-- osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs | 4 ++-- .../Objects/Drawables/CaughtBanana.cs | 2 +- .../Objects/Drawables/CaughtDroplet.cs | 2 +- .../Objects/Drawables/CaughtFruit.cs | 2 +- .../Objects/Drawables/CaughtObject.cs | 2 +- .../Objects/Drawables/DrawableBanana.cs | 2 +- .../Objects/Drawables/DrawableBananaShower.cs | 2 +- .../Drawables/DrawableCatchHitObject.cs | 2 +- .../Objects/Drawables/DrawableDroplet.cs | 2 +- .../Objects/Drawables/DrawableFruit.cs | 2 +- .../Objects/Drawables/DrawableJuiceStream.cs | 2 +- .../DrawablePalpableCatchHitObject.cs | 2 +- .../Objects/Drawables/DrawableTinyDroplet.cs | 2 +- .../Scoring/CatchScoreProcessor.cs | 2 +- .../Skinning/Argon/ArgonBananaPiece.cs | 2 +- .../Skinning/Argon/ArgonCatcher.cs | 2 +- .../Skinning/Argon/ArgonDropletPiece.cs | 2 +- .../Skinning/Argon/ArgonFruitPiece.cs | 2 +- .../Skinning/Argon/ArgonHitExplosion.cs | 2 +- .../Skinning/Argon/ArgonJudgementPiece.cs | 6 +++--- .../Skinning/Default/BananaPiece.cs | 2 +- .../Skinning/Default/BananaPulpFormation.cs | 2 +- .../Skinning/Default/BorderPiece.cs | 2 +- .../Skinning/Default/CatchHitObjectPiece.cs | 2 +- .../Skinning/Default/DefaultCatcher.cs | 2 +- .../Skinning/Default/DefaultHitExplosion.cs | 2 +- .../Skinning/Default/DropletPiece.cs | 2 +- .../Skinning/Default/FruitPiece.cs | 2 +- .../Skinning/Default/FruitPulpFormation.cs | 2 +- .../Skinning/Default/HyperBorderPiece.cs | 2 +- .../Default/HyperDropletBorderPiece.cs | 2 +- .../Skinning/Default/Pulp.cs | 2 +- .../Skinning/Default/PulpFormation.cs | 2 +- .../Skinning/Legacy/LegacyBananaPiece.cs | 2 +- .../Legacy/LegacyCatchComboCounter.cs | 2 +- .../Legacy/LegacyCatchHitObjectPiece.cs | 2 +- .../Skinning/Legacy/LegacyCatcherNew.cs | 2 +- .../Skinning/Legacy/LegacyCatcherOld.cs | 2 +- .../Skinning/Legacy/LegacyDropletPiece.cs | 2 +- .../Skinning/Legacy/LegacyFruitPiece.cs | 2 +- .../Skinning/Legacy/LegacyHitExplosion.cs | 2 +- .../UI/CatchComboDisplay.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 +- .../UI/CatchPlayfieldAdjustmentContainer.cs | 4 ++-- .../UI/CatchReplayRecorder.cs | 2 +- .../UI/CatchTouchInputMapper.cs | 4 ++-- osu.Game.Rulesets.Catch/UI/Catcher.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 2 +- osu.Game.Rulesets.Catch/UI/CatcherTrail.cs | 2 +- .../UI/CatcherTrailDisplay.cs | 2 +- .../UI/DrawableCatchRuleset.cs | 2 +- .../UI/DroppedObjectContainer.cs | 2 +- osu.Game.Rulesets.Catch/UI/HitExplosion.cs | 2 +- .../UI/HitExplosionContainer.cs | 2 +- .../UI/SkinnableCatcher.cs | 2 +- .../ManiaPlacementBlueprintTestScene.cs | 2 +- .../ManiaSelectionBlueprintTestScene.cs | 2 +- .../Editor/TestSceneEditor.cs | 2 +- .../TestSceneHoldNotePlacementBlueprint.cs | 2 +- .../TestSceneHoldNoteSelectionBlueprint.cs | 2 +- .../Editor/TestSceneManiaBeatSnapGrid.cs | 4 ++-- .../Editor/TestSceneManiaComposeScreen.cs | 2 +- .../Editor/TestSceneManiaHitObjectComposer.cs | 4 ++-- .../Editor/TestSceneNotePlacementBlueprint.cs | 2 +- .../Editor/TestSceneNoteSelectionBlueprint.cs | 2 +- .../ManiaInputTestScene.cs | 6 +++--- .../Mods/TestSceneManiaModConstantSpeed.cs | 2 +- .../Mods/TestSceneManiaModFlashlight.cs | 2 +- .../Mods/TestSceneManiaModHoldOff.cs | 2 +- .../Mods/TestSceneManiaModInvert.cs | 2 +- .../Mods/TestSceneManiaModPerfect.cs | 2 +- .../Skinning/ColumnTestContainer.cs | 2 +- .../Skinning/ManiaHitObjectTestScene.cs | 2 +- .../Skinning/ManiaSkinnableTestScene.cs | 2 +- .../Skinning/TestSceneBarLine.cs | 2 +- .../Skinning/TestSceneColumnBackground.cs | 2 +- .../Skinning/TestSceneColumnHitObjectArea.cs | 2 +- .../Skinning/TestSceneDrawableJudgement.cs | 2 +- .../Skinning/TestSceneHitExplosion.cs | 2 +- .../Skinning/TestSceneHoldNote.cs | 2 +- .../Skinning/TestSceneNote.cs | 2 +- .../Skinning/TestScenePlayfield.cs | 2 +- .../Skinning/TestSceneStage.cs | 2 +- .../Skinning/TestSceneStageBackground.cs | 2 +- .../Skinning/TestSceneStageForeground.cs | 2 +- .../TestSceneAutoGeneration.cs | 2 +- .../TestSceneColumn.cs | 2 +- .../TestSceneDrawableManiaHitObject.cs | 2 +- .../TestSceneHoldNoteInput.cs | 4 ++-- .../TestSceneManiaHitObjectSamples.cs | 2 +- .../TestSceneManiaPlayer.cs | 2 +- .../TestSceneNotes.cs | 4 ++-- .../TestSceneOutOfOrderHits.cs | 4 ++-- .../TestScenePlayfieldCoveringContainer.cs | 2 +- .../TestSceneStage.cs | 2 +- .../TestSceneTimingBasedNoteColouring.cs | 2 +- .../Blueprints/Components/EditBodyPiece.cs | 2 +- .../Blueprints/Components/EditNotePiece.cs | 2 +- .../Blueprints/HoldNotePlacementBlueprint.cs | 2 +- .../Blueprints/HoldNoteSelectionBlueprint.cs | 2 +- .../Blueprints/ManiaPlacementBlueprint.cs | 2 +- .../Blueprints/ManiaSelectionBlueprint.cs | 2 +- .../Edit/Blueprints/NotePlacementBlueprint.cs | 2 +- .../Edit/Blueprints/NoteSelectionBlueprint.cs | 2 +- .../Edit/DrawableManiaEditorRuleset.cs | 2 +- .../Edit/ManiaBeatSnapGrid.cs | 4 ++-- .../Edit/ManiaBlueprintContainer.cs | 2 +- .../Edit/ManiaEditorPlayfield.cs | 2 +- .../Edit/ManiaHitObjectComposer.cs | 2 +- .../Edit/ManiaSelectionHandler.cs | 2 +- .../Edit/Setup/ManiaSetupSection.cs | 2 +- osu.Game.Rulesets.Mania/ManiaInputManager.cs | 2 +- .../ManiaSettingsSubsection.cs | 4 ++-- .../Mods/ManiaModFlashlight.cs | 4 ++-- .../Objects/Drawables/DrawableBarLine.cs | 2 +- .../Objects/Drawables/DrawableHoldNote.cs | 2 +- .../Objects/Drawables/DrawableHoldNoteHead.cs | 2 +- .../Objects/Drawables/DrawableHoldNoteTail.cs | 2 +- .../Objects/Drawables/DrawableHoldNoteTick.cs | 2 +- .../Drawables/DrawableManiaHitObject.cs | 4 ++-- .../Objects/Drawables/DrawableNote.cs | 2 +- .../Scoring/ManiaHealthProcessor.cs | 2 +- .../Scoring/ManiaScoreProcessor.cs | 2 +- .../Skinning/Argon/ArgonColumnBackground.cs | 2 +- .../Skinning/Argon/ArgonHitExplosion.cs | 2 +- .../Skinning/Argon/ArgonHitTarget.cs | 2 +- .../Skinning/Argon/ArgonHoldBodyPiece.cs | 2 +- .../Skinning/Argon/ArgonHoldNoteTailPiece.cs | 2 +- .../Skinning/Argon/ArgonJudgementPiece.cs | 6 +++--- .../Skinning/Argon/ArgonKeyArea.cs | 2 +- .../Skinning/Argon/ArgonNotePiece.cs | 2 +- .../Skinning/Argon/ArgonStageBackground.cs | 2 +- .../Skinning/Default/DefaultBodyPiece.cs | 4 ++-- .../Skinning/Default/DefaultNotePiece.cs | 2 +- .../Legacy/HitTargetInsetContainer.cs | 2 +- .../Skinning/Legacy/LegacyBodyPiece.cs | 2 +- .../Skinning/Legacy/LegacyColumnBackground.cs | 2 +- .../Skinning/Legacy/LegacyHitExplosion.cs | 2 +- .../Skinning/Legacy/LegacyHitTarget.cs | 2 +- .../Legacy/LegacyHoldNoteHeadPiece.cs | 2 +- .../Legacy/LegacyHoldNoteTailPiece.cs | 2 +- .../Skinning/Legacy/LegacyKeyArea.cs | 2 +- .../Legacy/LegacyManiaColumnElement.cs | 2 +- .../Legacy/LegacyManiaJudgementPiece.cs | 2 +- .../Skinning/Legacy/LegacyNotePiece.cs | 2 +- .../Skinning/Legacy/LegacyStageBackground.cs | 4 ++-- .../Skinning/Legacy/LegacyStageForeground.cs | 2 +- osu.Game.Rulesets.Mania/UI/Column.cs | 4 ++-- osu.Game.Rulesets.Mania/UI/ColumnFlow.cs | 2 +- .../UI/Components/ColumnHitObjectArea.cs | 2 +- .../UI/Components/DefaultColumnBackground.cs | 2 +- .../UI/Components/DefaultHitTarget.cs | 2 +- .../UI/Components/DefaultKeyArea.cs | 2 +- .../UI/Components/DefaultStageBackground.cs | 2 +- .../UI/Components/HitObjectArea.cs | 2 +- .../UI/DefaultHitExplosion.cs | 2 +- .../UI/DrawableManiaJudgement.cs | 4 ++-- .../UI/DrawableManiaRuleset.cs | 2 +- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 2 +- .../UI/ManiaPlayfieldAdjustmentContainer.cs | 2 +- .../UI/ManiaReplayRecorder.cs | 2 +- .../UI/PlayfieldCoveringWrapper.cs | 2 +- .../UI/PoolableHitExplosion.cs | 2 +- osu.Game.Rulesets.Mania/UI/Stage.cs | 2 +- .../TestSceneHitCirclePlacementBlueprint.cs | 2 +- .../TestSceneHitCircleSelectionBlueprint.cs | 4 ++-- .../Editor/TestSceneObjectBeatSnap.cs | 2 +- .../Editor/TestSceneObjectMerging.cs | 2 +- .../Editor/TestSceneObjectObjectSnap.cs | 2 +- .../Editor/TestSceneOsuComposerSelection.cs | 2 +- .../Editor/TestSceneOsuDistanceSnapGrid.cs | 4 ++-- .../Editor/TestSceneOsuEditor.cs | 2 +- .../Editor/TestSceneOsuEditorGrids.cs | 2 +- .../TestSceneOsuEditorSelectInvalidPath.cs | 2 +- .../TestScenePathControlPointVisualiser.cs | 2 +- .../TestSceneSliderControlPointPiece.cs | 6 +++--- .../Editor/TestSceneSliderLengthValidity.cs | 2 +- .../TestSceneSliderPlacementBlueprint.cs | 2 +- .../TestSceneSliderSelectionBlueprint.cs | 6 +++--- .../Editor/TestSceneSliderSnapping.cs | 2 +- .../Editor/TestSceneSliderSplitting.cs | 2 +- .../Editor/TestSceneSliderStreamConversion.cs | 2 +- .../Editor/TestSceneSliderVelocityAdjust.cs | 2 +- .../TestSceneSpinnerPlacementBlueprint.cs | 2 +- .../TestSceneSpinnerSelectionBlueprint.cs | 2 +- .../Editor/TestSliderScaling.cs | 2 +- .../LegacyMainCirclePieceTest.cs | 4 ++-- .../Mods/OsuModTestScene.cs | 2 +- .../Mods/TestSceneOsuModAlternate.cs | 2 +- .../Mods/TestSceneOsuModAutoplay.cs | 2 +- .../Mods/TestSceneOsuModDifficultyAdjust.cs | 2 +- .../Mods/TestSceneOsuModDoubleTime.cs | 2 +- .../Mods/TestSceneOsuModFlashlight.cs | 2 +- .../Mods/TestSceneOsuModFreezeFrame.cs | 2 +- .../Mods/TestSceneOsuModHidden.cs | 2 +- .../Mods/TestSceneOsuModMagnetised.cs | 2 +- .../Mods/TestSceneOsuModMuted.cs | 2 +- .../Mods/TestSceneOsuModNoScope.cs | 2 +- .../Mods/TestSceneOsuModPerfect.cs | 2 +- .../Mods/TestSceneOsuModRandom.cs | 2 +- .../Mods/TestSceneOsuModRepel.cs | 2 +- .../Mods/TestSceneOsuModSingleTap.cs | 2 +- .../Mods/TestSceneOsuModSpunOut.cs | 2 +- .../OsuSkinnableTestScene.cs | 2 +- .../TestPlayfieldBorder.cs | 2 +- .../TestSceneAccuracyHeatmap.cs | 6 +++--- .../TestSceneCursorParticles.cs | 2 +- .../TestSceneCursorTrail.cs | 6 +++--- .../TestSceneDrawableJudgement.cs | 4 ++-- .../TestSceneFollowPoints.cs | 4 ++-- .../TestSceneGameplayCursor.cs | 6 +++--- .../TestSceneHitCircle.cs | 6 +++--- .../TestSceneHitCircleApplication.cs | 2 +- .../TestSceneHitCircleArea.cs | 2 +- .../TestSceneHitCircleComboChange.cs | 2 +- .../TestSceneHitCircleHidden.cs | 2 +- .../TestSceneHitCircleKiai.cs | 2 +- .../TestSceneHitCircleLongCombo.cs | 2 +- .../TestSceneLegacyBeatmapSkin.cs | 2 +- .../TestSceneMissHitWindowJudgements.cs | 2 +- .../TestSceneNoSpinnerStacking.cs | 2 +- .../TestSceneObjectOrderedHitPolicy.cs | 4 ++-- .../TestSceneOsuHitObjectSamples.cs | 2 +- .../TestSceneOsuPlayer.cs | 2 +- .../TestSceneResumeOverlay.cs | 4 ++-- .../TestSceneShaking.cs | 2 +- .../TestSceneSkinFallbacks.cs | 4 ++-- .../TestSceneSlider.cs | 2 +- .../TestSceneSliderApplication.cs | 2 +- .../TestSceneSliderComboChange.cs | 2 +- .../TestSceneSliderFollowCircleInput.cs | 4 ++-- .../TestSceneSliderHidden.cs | 2 +- .../TestSceneSliderInput.cs | 4 ++-- .../TestSceneSliderSnaking.cs | 2 +- osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs | 6 +++--- .../TestSceneSpinner.cs | 4 ++-- .../TestSceneSpinnerApplication.cs | 2 +- .../TestSceneSpinnerHidden.cs | 2 +- .../TestSceneSpinnerRotation.cs | 4 ++-- .../TestSceneStartTimeOrderedHitPolicy.cs | 4 ++-- .../TestSceneTrianglesSpinnerRotation.cs | 4 ++-- .../Edit/Blueprints/BlueprintPiece.cs | 2 +- .../Components/HitCircleOverlapMarker.cs | 2 +- .../HitCircles/Components/HitCirclePiece.cs | 2 +- .../HitCircles/HitCirclePlacementBlueprint.cs | 2 +- .../HitCircles/HitCircleSelectionBlueprint.cs | 2 +- .../Edit/Blueprints/OsuSelectionBlueprint.cs | 2 +- .../PathControlPointConnectionPiece.cs | 2 +- .../Components/PathControlPointPiece.cs | 2 +- .../Components/PathControlPointVisualiser.cs | 2 +- .../Sliders/Components/SliderBodyPiece.cs | 2 +- .../Blueprints/Sliders/SliderCircleOverlay.cs | 2 +- .../Sliders/SliderPlacementBlueprint.cs | 2 +- .../Sliders/SliderSelectionBlueprint.cs | 2 +- .../Spinners/Components/SpinnerPiece.cs | 2 +- .../Spinners/SpinnerPlacementBlueprint.cs | 2 +- .../Spinners/SpinnerSelectionBlueprint.cs | 2 +- .../Edit/DrawableOsuEditorRuleset.cs | 4 ++-- .../Edit/OsuBlueprintContainer.cs | 2 +- .../Edit/OsuDistanceSnapGrid.cs | 2 +- .../Edit/OsuHitObjectComposer.cs | 2 +- .../Edit/OsuRectangularPositionSnapGrid.cs | 2 +- .../Edit/OsuSelectionHandler.cs | 2 +- .../Edit/Setup/OsuSetupSection.cs | 2 +- .../Mods/InputBlockingMod.cs | 4 ++-- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 6 +++--- .../Mods/OsuModFlashlight.cs | 4 ++-- .../Mods/OsuModStrictTracking.cs | 4 ++-- .../Drawables/Connections/FollowPoint.cs | 2 +- .../Connections/FollowPointConnection.cs | 2 +- .../Connections/FollowPointRenderer.cs | 2 +- .../Objects/Drawables/DrawableHitCircle.cs | 6 +++--- .../Objects/Drawables/DrawableOsuHitObject.cs | 2 +- .../Objects/Drawables/DrawableOsuJudgement.cs | 4 ++-- .../Objects/Drawables/DrawableSlider.cs | 4 ++-- .../Objects/Drawables/DrawableSliderBall.cs | 2 +- .../Objects/Drawables/DrawableSliderHead.cs | 2 +- .../Objects/Drawables/DrawableSliderRepeat.cs | 2 +- .../Objects/Drawables/DrawableSliderTail.cs | 2 +- .../Objects/Drawables/DrawableSliderTick.cs | 2 +- .../Objects/Drawables/DrawableSpinner.cs | 2 +- .../Drawables/DrawableSpinnerBonusTick.cs | 2 +- .../Objects/Drawables/DrawableSpinnerTick.cs | 2 +- .../Objects/Drawables/SkinnableLighting.cs | 2 +- osu.Game.Rulesets.Osu/OsuInputManager.cs | 4 ++-- .../Scoring/OsuScoreProcessor.cs | 2 +- .../Skinning/Argon/ArgonCursor.cs | 2 +- .../Skinning/Argon/ArgonCursorTrail.cs | 2 +- .../Skinning/Argon/ArgonFollowCircle.cs | 2 +- .../Skinning/Argon/ArgonFollowPoint.cs | 2 +- .../Skinning/Argon/ArgonJudgementPiece.cs | 4 ++-- .../Skinning/Argon/ArgonMainCirclePiece.cs | 4 ++-- .../Skinning/Argon/ArgonReverseArrow.cs | 2 +- .../Skinning/Argon/ArgonSliderBall.cs | 2 +- .../Skinning/Argon/ArgonSliderBody.cs | 4 ++-- .../Skinning/Argon/ArgonSliderScorePoint.cs | 2 +- .../Skinning/Argon/ArgonSpinner.cs | 2 +- .../Skinning/Argon/ArgonSpinnerDisc.cs | 2 +- .../Skinning/Argon/ArgonSpinnerProgressArc.cs | 2 +- .../Skinning/Argon/ArgonSpinnerRingArc.cs | 2 +- .../Skinning/Argon/ArgonSpinnerTicks.cs | 2 +- .../Skinning/Default/CirclePiece.cs | 2 +- .../Skinning/Default/DefaultApproachCircle.cs | 2 +- .../Skinning/Default/DefaultFollowCircle.cs | 2 +- .../Skinning/Default/DefaultSliderBall.cs | 2 +- .../Skinning/Default/DefaultSmokeSegment.cs | 2 +- .../Skinning/Default/DefaultSpinner.cs | 2 +- .../Skinning/Default/DefaultSpinnerDisc.cs | 2 +- .../Skinning/Default/DrawableSliderPath.cs | 2 +- .../Skinning/Default/ExplodePiece.cs | 2 +- .../Skinning/Default/FlashPiece.cs | 2 +- .../Skinning/Default/GlowPiece.cs | 2 +- .../Skinning/Default/KiaiFlash.cs | 2 +- .../Skinning/Default/MainCirclePiece.cs | 2 +- .../Skinning/Default/ManualSliderBody.cs | 2 +- .../Skinning/Default/NumberPiece.cs | 2 +- .../Skinning/Default/PlaySliderBody.cs | 2 +- .../Skinning/Default/ReverseArrowPiece.cs | 2 +- .../Skinning/Default/RingPiece.cs | 2 +- .../Default/SpinnerBackgroundLayer.cs | 2 +- .../Skinning/Default/SpinnerCentreLayer.cs | 2 +- .../Skinning/Default/SpinnerFill.cs | 2 +- .../Default/SpinnerRotationTracker.cs | 2 +- .../Skinning/Default/SpinnerSpmCalculator.cs | 2 +- .../Skinning/Default/SpinnerTicks.cs | 2 +- .../Skinning/Default/TrianglesPiece.cs | 2 +- .../Skinning/FollowCircle.cs | 2 +- .../Skinning/Legacy/LegacyApproachCircle.cs | 2 +- .../Skinning/Legacy/LegacyCursor.cs | 2 +- .../Skinning/Legacy/LegacyCursorParticles.cs | 4 ++-- .../Skinning/Legacy/LegacyCursorTrail.cs | 2 +- .../Skinning/Legacy/LegacyFollowCircle.cs | 2 +- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 2 +- .../Skinning/Legacy/LegacyNewStyleSpinner.cs | 2 +- .../Skinning/Legacy/LegacyOldStyleSpinner.cs | 2 +- .../Skinning/Legacy/LegacyReverseArrow.cs | 2 +- .../Skinning/Legacy/LegacySliderBall.cs | 2 +- .../Skinning/Legacy/LegacySliderBody.cs | 4 ++-- .../Legacy/LegacySliderHeadHitCircle.cs | 2 +- .../Skinning/Legacy/LegacySmokeSegment.cs | 2 +- .../Skinning/Legacy/LegacySpinner.cs | 2 +- .../Skinning/NonPlayfieldSprite.cs | 2 +- osu.Game.Rulesets.Osu/Skinning/SliderBody.cs | 4 ++-- .../Skinning/SmokeSegment.cs | 2 +- .../Skinning/SnakingSliderBody.cs | 2 +- .../Statistics/AccuracyHeatmap.cs | 4 ++-- .../UI/Cursor/CursorTrail.cs | 2 +- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs | 4 ++-- .../UI/Cursor/OsuCursorContainer.cs | 4 ++-- .../UI/Cursor/OsuCursorSprite.cs | 2 +- .../UI/DrawableOsuRuleset.cs | 2 +- osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs | 6 +++--- .../UI/OsuPlayfieldAdjustmentContainer.cs | 4 ++-- osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs | 2 +- osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs | 4 ++-- .../UI/OsuSettingsSubsection.cs | 2 +- osu.Game.Rulesets.Osu/UI/SmokeContainer.cs | 4 ++-- .../DrawableTaikoRulesetTestScene.cs | 2 +- .../DrawableTestHit.cs | 2 +- .../DrawableTestStrongHit.cs | 2 +- .../Editor/TestSceneEditor.cs | 2 +- .../Editor/TestSceneTaikoEditorSaving.cs | 2 +- .../Editor/TestSceneTaikoHitObjectComposer.cs | 4 ++-- .../HitObjectApplicationTestScene.cs | 2 +- .../Judgements/JudgementTest.cs | 4 ++-- .../Judgements/TestSceneDrumRollJudgements.cs | 2 +- .../Judgements/TestSceneHitJudgements.cs | 2 +- .../Judgements/TestSceneSwellJudgements.cs | 2 +- .../Mods/TaikoModTestScene.cs | 2 +- .../Mods/TestSceneTaikoModFlashlight.cs | 6 +++--- .../Mods/TestSceneTaikoModHidden.cs | 2 +- .../Mods/TestSceneTaikoModPerfect.cs | 6 +++--- .../Skinning/TaikoSkinnableTestScene.cs | 2 +- .../Skinning/TestSceneDrawableBarLine.cs | 2 +- .../Skinning/TestSceneDrawableDrumRoll.cs | 2 +- .../Skinning/TestSceneDrawableHit.cs | 2 +- .../Skinning/TestSceneDrawableSwell.cs | 2 +- .../Skinning/TestSceneDrawableTaikoMascot.cs | 2 +- .../Skinning/TestSceneHitExplosion.cs | 2 +- .../Skinning/TestSceneInputDrum.cs | 2 +- .../Skinning/TestSceneKiaiHitExplosion.cs | 2 +- .../Skinning/TestSceneTaikoPlayfield.cs | 2 +- .../Skinning/TestSceneTaikoScroller.cs | 2 +- .../TestSceneBarLineApplication.cs | 2 +- .../TestSceneBarLineGeneration.cs | 2 +- .../TestSceneDrumRollApplication.cs | 2 +- .../TestSceneDrumTouchInputArea.cs | 2 +- .../TestSceneFlyingHits.cs | 2 +- .../TestSceneHitApplication.cs | 2 +- .../TestSceneHits.cs | 2 +- .../TestSceneSampleOutput.cs | 2 +- .../TestSceneTaikoHitObjectSamples.cs | 2 +- .../TestSceneTaikoPlayer.cs | 2 +- .../TestSceneTaikoPlayerLegacySkin.cs | 2 +- .../TestSceneTaikoSuddenDeath.cs | 2 +- .../Blueprints/DrumRollPlacementBlueprint.cs | 2 +- .../Edit/Blueprints/HitPiece.cs | 2 +- .../Edit/Blueprints/HitPlacementBlueprint.cs | 2 +- .../Edit/Blueprints/LengthPiece.cs | 2 +- .../Blueprints/SwellPlacementBlueprint.cs | 2 +- .../Blueprints/TaikoSelectionBlueprint.cs | 2 +- .../Blueprints/TaikoSpanPlacementBlueprint.cs | 2 +- .../Edit/TaikoBlueprintContainer.cs | 2 +- .../Edit/TaikoHitObjectComposer.cs | 2 +- .../Edit/TaikoSelectionHandler.cs | 2 +- .../Mods/TaikoModFlashlight.cs | 4 ++-- .../Objects/Drawables/DrawableBarLine.cs | 2 +- .../Objects/Drawables/DrawableDrumRoll.cs | 4 ++-- .../Objects/Drawables/DrawableDrumRollTick.cs | 4 ++-- .../Objects/Drawables/DrawableFlyingHit.cs | 2 +- .../Objects/Drawables/DrawableHit.cs | 4 ++-- .../Drawables/DrawableStrongNestedHit.cs | 2 +- .../Objects/Drawables/DrawableSwell.cs | 2 +- .../Objects/Drawables/DrawableSwellTick.cs | 2 +- .../Drawables/DrawableTaikoHitObject.cs | 6 +++--- .../DrawableTaikoStrongableHitObject.cs | 2 +- .../Scoring/TaikoHealthProcessor.cs | 2 +- .../Scoring/TaikoScoreProcessor.cs | 2 +- .../Skinning/Argon/ArgonBarLine.cs | 2 +- .../Skinning/Argon/ArgonCentreCirclePiece.cs | 2 +- .../Skinning/Argon/ArgonCirclePiece.cs | 2 +- .../Argon/ArgonElongatedCirclePiece.cs | 2 +- .../Skinning/Argon/ArgonHitExplosion.cs | 2 +- .../Skinning/Argon/ArgonHitTarget.cs | 2 +- .../Skinning/Argon/ArgonInputDrum.cs | 4 ++-- .../Skinning/Argon/ArgonJudgementPiece.cs | 6 +++--- .../Argon/ArgonPlayfieldBackgroundLeft.cs | 2 +- .../Argon/ArgonPlayfieldBackgroundRight.cs | 2 +- .../Skinning/Argon/ArgonRimCirclePiece.cs | 2 +- .../Skinning/Argon/ArgonSwellCirclePiece.cs | 2 +- .../Skinning/Argon/ArgonTickPiece.cs | 2 +- .../Skinning/Argon/RingPiece.cs | 2 +- .../Skinning/Default/CentreHitCirclePiece.cs | 4 ++-- .../Skinning/Default/CirclePiece.cs | 2 +- .../Skinning/Default/DefaultBarLine.cs | 2 +- .../Skinning/Default/DefaultHitExplosion.cs | 2 +- .../Skinning/Default/DefaultInputDrum.cs | 4 ++-- .../Skinning/Default/DefaultJudgementPiece.cs | 2 +- .../Default/DefaultKiaiHitExplosion.cs | 2 +- .../Skinning/Default/ElongatedCirclePiece.cs | 2 +- .../Skinning/Default/RimHitCirclePiece.cs | 4 ++-- .../Skinning/Default/SwellSymbolPiece.cs | 4 ++-- .../Skinning/Default/TickPiece.cs | 2 +- .../Skinning/Legacy/LegacyBarLine.cs | 2 +- .../Skinning/Legacy/LegacyCirclePiece.cs | 2 +- .../Skinning/Legacy/LegacyDrumRoll.cs | 2 +- .../Skinning/Legacy/LegacyHit.cs | 2 +- .../Skinning/Legacy/LegacyHitExplosion.cs | 2 +- .../Skinning/Legacy/LegacyInputDrum.cs | 4 ++-- .../Skinning/Legacy/LegacyTaikoScroller.cs | 4 ++-- .../Skinning/Legacy/TaikoLegacyHitTarget.cs | 2 +- .../TaikoLegacyPlayfieldBackgroundRight.cs | 2 +- osu.Game.Rulesets.Taiko/TaikoInputManager.cs | 2 +- .../UI/BarLinePlayfield.cs | 2 +- .../UI/DrawableTaikoJudgement.cs | 2 +- .../UI/DrawableTaikoMascot.cs | 2 +- .../UI/DrawableTaikoRuleset.cs | 2 +- .../UI/DrumRollHitContainer.cs | 2 +- .../UI/DrumSamplePlayer.cs | 2 +- .../UI/DrumSampleTriggerSource.cs | 2 +- .../UI/DrumTouchInputArea.cs | 4 ++-- osu.Game.Rulesets.Taiko/UI/HitExplosion.cs | 2 +- .../UI/HitExplosionPool.cs | 2 +- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 2 +- .../UI/KiaiHitExplosion.cs | 2 +- .../UI/PlayfieldBackgroundLeft.cs | 2 +- .../UI/PlayfieldBackgroundRight.cs | 2 +- osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs | 2 +- .../UI/TaikoMascotAnimation.cs | 6 +++--- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 4 ++-- .../UI/TaikoPlayfieldAdjustmentContainer.cs | 2 +- .../UI/TaikoReplayRecorder.cs | 2 +- .../TestSceneBeatmapDifficultyCache.cs | 4 ++-- .../Beatmaps/TestSceneEditorBeatmap.cs | 2 +- .../Beatmaps/WorkingBeatmapManagerTest.cs | 2 +- .../Chat/TestSceneChannelManager.cs | 4 ++-- .../BackgroundBeatmapProcessorTests.cs | 4 ++-- osu.Game.Tests/Database/RealmTest.cs | 4 ++-- .../Database/TestRealmKeyBindingStore.cs | 4 ++-- ...tSceneHitObjectComposerDistanceSnapping.cs | 4 ++-- .../TestSceneHitObjectContainerEventBuffer.cs | 8 ++++---- .../TransactionalCommitComponentTest.cs | 4 ++-- .../TestSceneDrainingHealthProcessor.cs | 2 +- .../Gameplay/TestSceneDrawableHitObject.cs | 4 ++-- .../TestSceneHitObjectAccentColour.cs | 4 ++-- .../Gameplay/TestSceneHitObjectContainer.cs | 4 ++-- .../Gameplay/TestSceneHitObjectSamples.cs | 2 +- .../TestSceneMasterGameplayClockContainer.cs | 2 +- .../Gameplay/TestSceneProxyContainer.cs | 6 +++--- .../Gameplay/TestSceneScoreProcessor.cs | 2 +- .../Gameplay/TestSceneStoryboardSamples.cs | 4 ++-- osu.Game.Tests/ImportTest.cs | 4 ++-- .../Input/ConfineMouseTrackerTest.cs | 2 +- .../Mods/SettingsSourceAttributeTest.cs | 6 +++--- .../NonVisual/FirstAvailableHitWindowsTest.cs | 4 ++-- .../NonVisual/GameplayClockContainerTest.cs | 4 ++-- .../StatefulMultiplayerClientTest.cs | 2 +- .../NonVisual/OngoingOperationTrackerTest.cs | 4 ++-- .../Skinning/LegacySkinAnimationTest.cs | 2 +- .../Online/TestDummyAPIRequestHandling.cs | 2 +- .../Online/TestSceneBeatmapDownloading.cs | 2 +- ...eneOnlinePlayBeatmapAvailabilityTracker.cs | 2 +- .../OnlinePlay/TestSceneCatchUpSyncManager.cs | 2 +- .../Rulesets/Scoring/ScoreProcessorTest.cs | 4 ++-- .../TestSceneBrokenRulesetHandling.cs | 2 +- .../TestSceneDrawableRulesetDependencies.cs | 4 ++-- .../TestSceneRulesetSkinProvidingContainer.cs | 4 ++-- .../TestSceneBeatmapSkinLookupDisables.cs | 4 ++-- .../Skins/TestSceneBeatmapSkinResources.cs | 2 +- .../Skins/TestSceneSkinConfigurationLookup.cs | 4 ++-- .../Skins/TestSceneSkinProvidingContainer.cs | 4 ++-- .../Skins/TestSceneSkinResources.cs | 2 +- .../Testing/TestSceneRulesetDependencies.cs | 2 +- .../Visual/Audio/TestSceneAudioFilter.cs | 2 +- .../TestSceneBackgroundScreenDefault.cs | 8 ++++---- .../TestSceneSeasonalBackgroundLoader.cs | 2 +- .../TestSceneTrianglesBackground.cs | 2 +- .../Background/TestSceneUserDimBackgrounds.cs | 14 ++++++------- .../Background/TestSceneUserDimContainer.cs | 4 ++-- .../Visual/Beatmaps/TestSceneBeatmapCard.cs | 2 +- .../TestSceneBeatmapCardDifficultyList.cs | 2 +- .../TestSceneBeatmapCardDownloadButton.cs | 2 +- .../TestSceneBeatmapCardFavouriteButton.cs | 2 +- .../Beatmaps/TestSceneBeatmapCardThumbnail.cs | 2 +- .../TestSceneBeatmapSetOnlineStatusPill.cs | 2 +- .../TestSceneDifficultySpectrumDisplay.cs | 2 +- .../TestSceneManageCollectionsDialog.cs | 2 +- .../Colours/TestSceneStarDifficultyColours.cs | 2 +- .../Visual/Components/TestSceneIdleTracker.cs | 4 ++-- .../Components/TestScenePollingComponent.cs | 6 +++--- .../TestScenePreviewTrackManager.cs | 8 ++++---- .../Editing/TestSceneBeatDivisorControl.cs | 2 +- .../Editing/TestSceneBlueprintOrdering.cs | 2 +- .../Visual/Editing/TestSceneComposeScreen.cs | 2 +- .../Editing/TestSceneComposeSelectBox.cs | 2 +- .../Editing/TestSceneComposerSelection.cs | 2 +- .../Visual/Editing/TestSceneDesignSection.cs | 4 ++-- .../Editing/TestSceneDifficultyDelete.cs | 2 +- .../Editing/TestSceneDifficultySwitching.cs | 2 +- .../Editing/TestSceneDistanceSnapGrid.cs | 4 ++-- .../Editing/TestSceneEditorBeatmapCreation.cs | 2 +- .../Visual/Editing/TestSceneEditorBindings.cs | 2 +- .../Editing/TestSceneEditorChangeStates.cs | 2 +- .../Editing/TestSceneEditorClipboard.cs | 2 +- .../Visual/Editing/TestSceneEditorClock.cs | 2 +- .../TestSceneEditorComposeRadioButtons.cs | 2 +- .../Visual/Editing/TestSceneEditorMenuBar.cs | 2 +- .../Editing/TestSceneEditorNavigation.cs | 2 +- .../Editing/TestSceneEditorSamplePlayback.cs | 2 +- .../Visual/Editing/TestSceneEditorSaving.cs | 2 +- .../Editing/TestSceneEditorScreenModes.cs | 2 +- .../Editing/TestSceneEditorSeekSnapping.cs | 6 +++--- .../Visual/Editing/TestSceneEditorSeeking.cs | 2 +- .../Editing/TestSceneEditorSummaryTimeline.cs | 2 +- .../Editing/TestSceneEditorTestGameplay.cs | 2 +- .../Editing/TestSceneHitObjectComposer.cs | 4 ++-- ...ceneHitObjectDifficultyPointAdjustments.cs | 2 +- ...estSceneHitObjectSamplePointAdjustments.cs | 2 +- .../Editing/TestSceneLabelledTimeSignature.cs | 2 +- .../Editing/TestSceneMetadataSection.cs | 4 ++-- .../Editing/TestScenePlaybackControl.cs | 2 +- .../TestSceneRectangularPositionSnapGrid.cs | 4 ++-- .../TestSceneSelectionBlueprintDeselection.cs | 2 +- .../Visual/Editing/TestSceneSetupScreen.cs | 2 +- .../Visual/Editing/TestSceneTapButton.cs | 2 +- .../Editing/TestSceneTapTimingControl.cs | 2 +- .../TestSceneTimelineBlueprintContainer.cs | 2 +- .../TestSceneTimelineHitObjectBlueprint.cs | 2 +- .../Editing/TestSceneTimelineSelection.cs | 2 +- .../Editing/TestSceneTimelineTickDisplay.cs | 2 +- .../Visual/Editing/TestSceneTimelineZoom.cs | 2 +- .../Visual/Editing/TestSceneTimingScreen.cs | 2 +- .../Visual/Editing/TestSceneWaveform.cs | 4 ++-- .../TestSceneZoomableScrollContainer.cs | 2 +- .../Visual/Editing/TimelineTestScene.cs | 6 +++--- .../Visual/Gameplay/OsuPlayerTestScene.cs | 2 +- .../SkinnableHUDComponentTestScene.cs | 2 +- .../Gameplay/TestSceneAllRulesetPlayers.cs | 2 +- .../Visual/Gameplay/TestSceneAutoplay.cs | 2 +- .../Gameplay/TestSceneBeatmapOffsetControl.cs | 2 +- .../Gameplay/TestSceneBeatmapSkinFallbacks.cs | 2 +- .../Gameplay/TestSceneBezierConverter.cs | 2 +- .../Visual/Gameplay/TestSceneBreakTracker.cs | 4 ++-- .../TestSceneClicksPerSecondCalculator.cs | 2 +- .../Gameplay/TestSceneColourHitErrorMeter.cs | 2 +- .../TestSceneCompletionCancellation.cs | 4 ++-- .../TestSceneDrawableScrollingRuleset.cs | 14 ++++++------- .../TestSceneDrawableStoryboardSprite.cs | 2 +- .../Visual/Gameplay/TestSceneFailAnimation.cs | 4 ++-- .../Visual/Gameplay/TestSceneFailJudgement.cs | 4 ++-- .../Visual/Gameplay/TestSceneFailingLayer.cs | 4 ++-- .../TestSceneFrameStabilityContainer.cs | 4 ++-- .../Gameplay/TestSceneGameplayLeaderboard.cs | 4 ++-- .../Gameplay/TestSceneGameplayMenuOverlay.cs | 2 +- .../Gameplay/TestSceneGameplayRewinding.cs | 2 +- .../TestSceneGameplaySamplePlayback.cs | 2 +- .../TestSceneGameplaySampleTriggerSource.cs | 4 ++-- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +- .../Visual/Gameplay/TestSceneHitErrorMeter.cs | 6 +++--- .../Gameplay/TestSceneHoldForMenuButton.cs | 2 +- .../Visual/Gameplay/TestSceneKeyBindings.cs | 6 +++--- .../Visual/Gameplay/TestSceneKeyCounter.cs | 2 +- .../Visual/Gameplay/TestSceneLeadIn.cs | 4 ++-- .../Visual/Gameplay/TestSceneMedalOverlay.cs | 2 +- .../Visual/Gameplay/TestSceneModValidity.cs | 2 +- .../TestSceneNightcoreBeatContainer.cs | 2 +- .../Gameplay/TestSceneOverlayActivation.cs | 4 ++-- .../Gameplay/TestSceneParticleExplosion.cs | 2 +- .../Gameplay/TestSceneParticleSpewer.cs | 4 ++-- .../Visual/Gameplay/TestScenePause.cs | 4 ++-- .../Gameplay/TestScenePauseWhenInactive.cs | 2 +- .../TestScenePerformancePointsCounter.cs | 2 +- .../Visual/Gameplay/TestScenePlayerLoader.cs | 6 +++--- .../TestScenePlayerLocalScoreImport.cs | 2 +- .../TestScenePlayerReferenceLeaking.cs | 2 +- .../TestScenePlayerScoreSubmission.cs | 4 ++-- .../Gameplay/TestScenePoolingRuleset.cs | 10 +++++----- .../Visual/Gameplay/TestSceneReplay.cs | 4 ++-- .../Gameplay/TestSceneReplayDownloadButton.cs | 4 ++-- .../Visual/Gameplay/TestSceneReplayPlayer.cs | 2 +- .../Gameplay/TestSceneReplayRecorder.cs | 10 +++++----- .../Visual/Gameplay/TestSceneScoring.cs | 6 +++--- .../Gameplay/TestSceneScrollingHitObjects.cs | 10 +++++----- .../Visual/Gameplay/TestSceneSkinEditor.cs | 2 +- .../TestSceneSkinEditorComponentsList.cs | 2 +- .../TestSceneSkinEditorMultipleSkins.cs | 2 +- .../TestSceneSkinnableAccuracyCounter.cs | 2 +- .../TestSceneSkinnableComboCounter.cs | 2 +- .../Gameplay/TestSceneSkinnableDrawable.cs | 20 +++++++++---------- .../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +- .../TestSceneSkinnableHealthDisplay.cs | 2 +- .../TestSceneSkinnableScoreCounter.cs | 2 +- .../Gameplay/TestSceneSkinnableSound.cs | 4 ++-- .../Visual/Gameplay/TestSceneSkipOverlay.cs | 4 ++-- .../Visual/Gameplay/TestSceneSliderPath.cs | 2 +- .../TestSceneSoloGameplayLeaderboard.cs | 2 +- .../Visual/Gameplay/TestSceneSongProgress.cs | 2 +- .../Gameplay/TestSceneSongProgressGraph.cs | 4 ++-- .../Visual/Gameplay/TestSceneSpectator.cs | 4 ++-- .../Visual/Gameplay/TestSceneSpectatorHost.cs | 2 +- .../Gameplay/TestSceneSpectatorPlayback.cs | 10 +++++----- .../Visual/Gameplay/TestSceneStarCounter.cs | 2 +- .../Visual/Gameplay/TestSceneStoryboard.cs | 2 +- .../TestSceneStoryboardSamplePlayback.cs | 2 +- .../Gameplay/TestSceneStoryboardWithOutro.cs | 4 ++-- .../Visual/Gameplay/TestSceneUnknownMod.cs | 2 +- .../Gameplay/TestSceneUnstableRateCounter.cs | 4 ++-- osu.Game.Tests/Visual/Menus/IntroTestScene.cs | 2 +- .../Visual/Menus/TestSceneDisclaimer.cs | 2 +- .../Visual/Menus/TestSceneIntroCircles.cs | 2 +- .../Visual/Menus/TestSceneIntroTriangles.cs | 2 +- .../Visual/Menus/TestSceneIntroWelcome.cs | 2 +- .../Visual/Menus/TestSceneLoader.cs | 8 ++++---- .../Visual/Menus/TestSceneLoginPanel.cs | 2 +- .../Menus/TestSceneMusicActionHandling.cs | 2 +- .../Visual/Menus/TestSceneSideOverlays.cs | 2 +- .../Visual/Menus/TestSceneSongTicker.cs | 2 +- .../Visual/Menus/TestSceneToolbar.cs | 4 ++-- .../Visual/Menus/TestSceneToolbarClock.cs | 2 +- .../Menus/TestSceneToolbarUserButton.cs | 2 +- .../Visual/Mods/TestSceneModFailCondition.cs | 2 +- ...MultiplayerGameplayLeaderboardTestScene.cs | 2 +- .../Visual/Multiplayer/QueueModeTestScene.cs | 2 +- .../TestSceneAllPlayersQueueMode.cs | 2 +- .../TestSceneCreateMultiplayerMatchButton.cs | 2 +- .../TestSceneDrawableLoungeRoom.cs | 2 +- .../Multiplayer/TestSceneDrawableRoom.cs | 2 +- .../TestSceneDrawableRoomParticipantsList.cs | 2 +- .../TestSceneDrawableRoomPlaylist.cs | 4 ++-- .../TestSceneFreeModSelectOverlay.cs | 2 +- .../TestSceneGameplayChatDisplay.cs | 2 +- .../Multiplayer/TestSceneHostOnlyQueueMode.cs | 2 +- .../TestSceneLoungeRoomsContainer.cs | 2 +- .../TestSceneMatchBeatmapDetailArea.cs | 2 +- .../Multiplayer/TestSceneMatchLeaderboard.cs | 2 +- .../Multiplayer/TestSceneMatchStartControl.cs | 2 +- .../Multiplayer/TestSceneMultiHeader.cs | 4 ++-- .../TestSceneMultiSpectatorLeaderboard.cs | 2 +- .../TestSceneMultiSpectatorScreen.cs | 2 +- .../Multiplayer/TestSceneMultiplayer.cs | 2 +- ...TestSceneMultiplayerGameplayLeaderboard.cs | 4 ++-- ...ceneMultiplayerGameplayLeaderboardTeams.cs | 2 +- .../TestSceneMultiplayerLoungeSubScreen.cs | 2 +- .../TestSceneMultiplayerMatchFooter.cs | 2 +- .../TestSceneMultiplayerMatchSongSelect.cs | 4 ++-- .../TestSceneMultiplayerMatchSubScreen.cs | 4 ++-- .../TestSceneMultiplayerParticipantsList.cs | 2 +- .../Multiplayer/TestSceneMultiplayerPlayer.cs | 2 +- .../TestSceneMultiplayerPlaylist.cs | 2 +- .../TestSceneMultiplayerQueueList.cs | 2 +- .../TestSceneMultiplayerResults.cs | 2 +- .../TestSceneMultiplayerSpectateButton.cs | 2 +- ...TestSceneMultiplayerSpectatorPlayerGrid.cs | 4 ++-- .../TestSceneMultiplayerTeamResults.cs | 2 +- .../TestScenePlaylistsRoomSettingsPlaylist.cs | 4 ++-- .../TestScenePlaylistsSongSelect.cs | 4 ++-- .../Multiplayer/TestSceneRankRangePill.cs | 2 +- .../TestSceneStarRatingRangeDisplay.cs | 2 +- .../Visual/Multiplayer/TestSceneTeamVersus.cs | 2 +- .../TestSceneButtonSystemNavigation.cs | 2 +- .../TestSceneChangeAndUseGameplayBindings.cs | 2 +- .../Navigation/TestSceneEditDefaultSkin.cs | 2 +- .../Navigation/TestSceneFirstRunGame.cs | 4 ++-- .../TestSceneInterProcessCommunication.cs | 2 +- .../TestSceneMouseWheelVolumeAdjust.cs | 2 +- .../Visual/Navigation/TestSceneOsuGame.cs | 2 +- .../Navigation/TestScenePerformFromScreen.cs | 8 ++++---- .../Navigation/TestScenePresentBeatmap.cs | 2 +- .../Navigation/TestScenePresentScore.cs | 2 +- .../Navigation/TestSceneScreenNavigation.cs | 4 ++-- .../TestSceneSkinEditorNavigation.cs | 2 +- .../TestSceneStartupBeatmapDisplay.cs | 2 +- .../TestSceneStartupBeatmapSetDisplay.cs | 2 +- .../Navigation/TestSceneStartupImport.cs | 2 +- .../Navigation/TestSceneStartupRuleset.cs | 2 +- .../Navigation/TestSettingsMigration.cs | 2 +- .../Online/TestSceneAccountCreationOverlay.cs | 2 +- .../Online/TestSceneBeatmapAvailability.cs | 2 +- .../Online/TestSceneBeatmapDownloadButton.cs | 4 ++-- .../Online/TestSceneBeatmapListingOverlay.cs | 2 +- .../Online/TestSceneBeatmapRulesetSelector.cs | 2 +- .../Online/TestSceneBeatmapSetOverlay.cs | 4 ++-- .../TestSceneBeatmapSetOverlayDetails.cs | 4 ++-- .../TestSceneBeatmapSetOverlaySuccessRate.cs | 4 ++-- .../TestSceneBundledBeatmapDownloader.cs | 2 +- .../Online/TestSceneChangelogOverlay.cs | 4 ++-- .../TestSceneChangelogSupporterPromo.cs | 2 +- .../Visual/Online/TestSceneChannelList.cs | 2 +- .../Visual/Online/TestSceneChannelListing.cs | 2 +- .../Online/TestSceneChatLineTruncation.cs | 4 ++-- .../Visual/Online/TestSceneChatLink.cs | 4 ++-- .../Visual/Online/TestSceneChatOverlay.cs | 6 +++--- .../Visual/Online/TestSceneChatTextBox.cs | 2 +- .../Visual/Online/TestSceneCommentActions.cs | 2 +- .../Online/TestSceneCommentReportButton.cs | 2 +- .../Online/TestSceneCommentsContainer.cs | 2 +- .../Visual/Online/TestSceneCommentsHeader.cs | 2 +- .../TestSceneCurrentlyPlayingDisplay.cs | 4 ++-- .../Online/TestSceneDashboardOverlay.cs | 2 +- .../Visual/Online/TestSceneDrawableComment.cs | 2 +- .../Online/TestSceneExternalLinkButton.cs | 2 +- .../Visual/Online/TestSceneFavouriteButton.cs | 2 +- .../Visual/Online/TestSceneFriendDisplay.cs | 2 +- .../Online/TestSceneFullscreenOverlay.cs | 8 ++++---- .../Visual/Online/TestSceneGraph.cs | 2 +- .../Online/TestSceneHistoricalSection.cs | 2 +- .../Visual/Online/TestSceneHomeNewsPanel.cs | 2 +- .../Visual/Online/TestSceneKudosuHistory.cs | 2 +- .../Online/TestSceneLeaderboardModSelector.cs | 2 +- .../TestSceneLeaderboardScopeSelector.cs | 2 +- .../Visual/Online/TestSceneMessageNotifier.cs | 4 ++-- .../Visual/Online/TestSceneNewsCard.cs | 2 +- .../Visual/Online/TestSceneNewsHeader.cs | 4 ++-- .../Visual/Online/TestSceneNewsOverlay.cs | 2 +- .../Visual/Online/TestSceneNewsSidebar.cs | 4 ++-- .../Online/TestSceneNowPlayingCommand.cs | 4 ++-- .../TestSceneOfflineCommentsContainer.cs | 4 ++-- .../TestSceneOnlineBeatmapListingOverlay.cs | 2 +- .../TestSceneOnlineBeatmapSetOverlay.cs | 2 +- .../Online/TestSceneOnlineViewContainer.cs | 4 ++-- .../Online/TestScenePlayHistorySubsection.cs | 2 +- .../Online/TestSceneProfileRulesetSelector.cs | 2 +- .../Visual/Online/TestSceneRankGraph.cs | 2 +- .../Online/TestSceneRankingsCountryFilter.cs | 2 +- .../Visual/Online/TestSceneRankingsHeader.cs | 2 +- .../Visual/Online/TestSceneRankingsOverlay.cs | 4 ++-- .../TestSceneRankingsSpotlightSelector.cs | 2 +- .../Visual/Online/TestSceneRankingsTables.cs | 2 +- .../Visual/Online/TestSceneScoreboardTime.cs | 2 +- .../Visual/Online/TestSceneScoresContainer.cs | 4 ++-- .../Visual/Online/TestSceneShowMoreButton.cs | 2 +- .../Online/TestSceneSpotlightsLayout.cs | 2 +- .../Online/TestSceneStandAloneChatDisplay.cs | 4 ++-- .../Online/TestSceneTotalCommentsCounter.cs | 2 +- .../Online/TestSceneUserHistoryGraph.cs | 2 +- .../Visual/Online/TestSceneUserPanel.cs | 4 ++-- .../Online/TestSceneUserProfileHeader.cs | 2 +- .../Online/TestSceneUserProfileOverlay.cs | 4 ++-- .../TestSceneUserProfilePreviousUsernames.cs | 2 +- .../TestSceneUserProfileRecentSection.cs | 2 +- .../Online/TestSceneUserProfileScores.cs | 4 ++-- .../Visual/Online/TestSceneUserRanks.cs | 2 +- .../Visual/Online/TestSceneUserRequest.cs | 4 ++-- .../Visual/Online/TestSceneVotePill.cs | 4 ++-- .../Visual/Online/TestSceneWikiHeader.cs | 4 ++-- .../Visual/Online/TestSceneWikiMainPage.cs | 2 +- .../Online/TestSceneWikiMarkdownContainer.cs | 6 +++--- .../Visual/Online/TestSceneWikiOverlay.cs | 2 +- .../Visual/Online/TestSceneWikiSidebar.cs | 2 +- .../TestScenePlaylistsLoungeSubScreen.cs | 4 ++-- .../TestScenePlaylistsMatchSettingsOverlay.cs | 4 ++-- .../TestScenePlaylistsParticipantsList.cs | 2 +- .../TestScenePlaylistsResultsScreen.cs | 4 ++-- .../TestScenePlaylistsRoomCreation.cs | 4 ++-- .../Playlists/TestScenePlaylistsScreen.cs | 2 +- .../Visual/Ranking/TestSceneAccuracyCircle.cs | 2 +- .../TestSceneContractedPanelMiddleContent.cs | 4 ++-- .../TestSceneExpandedPanelMiddleContent.cs | 4 ++-- .../TestSceneExpandedPanelTopContent.cs | 2 +- ...estSceneHitEventTimingDistributionGraph.cs | 2 +- .../Visual/Ranking/TestSceneResultsScreen.cs | 10 +++++----- .../Visual/Ranking/TestSceneScorePanel.cs | 2 +- .../Visual/Ranking/TestSceneScorePanelList.cs | 2 +- .../Ranking/TestSceneSimpleStatisticTable.cs | 2 +- .../Ranking/TestSceneStatisticsPanel.cs | 2 +- .../Settings/TestSceneDirectorySelector.cs | 2 +- .../Visual/Settings/TestSceneFileSelector.cs | 2 +- .../Settings/TestSceneKeyBindingPanel.cs | 2 +- .../TestSceneLatencyCertifierScreen.cs | 2 +- .../Settings/TestSceneMigrationScreens.cs | 6 +++--- .../TestSceneRestoreDefaultValueButton.cs | 2 +- .../Visual/Settings/TestSceneSettingsItem.cs | 2 +- .../Settings/TestSceneSettingsNumberBox.cs | 2 +- .../Visual/Settings/TestSceneSettingsPanel.cs | 2 +- .../Settings/TestSceneSettingsSource.cs | 2 +- .../Settings/TestSceneTabletSettings.cs | 2 +- .../SongSelect/TestSceneAdvancedStats.cs | 4 ++-- .../SongSelect/TestSceneBeatmapCarousel.cs | 4 ++-- .../SongSelect/TestSceneBeatmapDetails.cs | 2 +- .../SongSelect/TestSceneBeatmapInfoWedge.cs | 4 ++-- .../SongSelect/TestSceneBeatmapLeaderboard.cs | 4 ++-- .../TestSceneBeatmapMetadataDisplay.cs | 4 ++-- .../TestSceneBeatmapOptionsOverlay.cs | 2 +- .../TestSceneBeatmapRecommendations.cs | 2 +- .../TestSceneDifficultyRangeFilterControl.cs | 2 +- .../SongSelect/TestSceneFilterControl.cs | 2 +- .../SongSelect/TestScenePlaySongSelect.cs | 4 ++-- .../SongSelect/TestSceneSongSelectFooter.cs | 2 +- .../SongSelect/TestSceneTopLocalRank.cs | 2 +- .../TestSceneUpdateBeatmapSetButton.cs | 2 +- .../TestSceneUserTopScoreContainer.cs | 2 +- .../Visual/TestMultiplayerComponents.cs | 4 ++-- .../Visual/TestSceneOsuScreenStack.cs | 14 ++++++------- .../UserInterface/TestSceneBackButton.cs | 2 +- .../TestSceneBeatSyncedContainer.cs | 6 +++--- ...stSceneBeatmapListingCardSizeTabControl.cs | 2 +- .../TestSceneBeatmapListingSearchControl.cs | 2 +- .../TestSceneBeatmapListingSortTabControl.cs | 2 +- .../TestSceneBeatmapSearchFilter.cs | 2 +- .../TestSceneBreadcrumbControl.cs | 4 ++-- .../TestSceneBreadcrumbControlHeader.cs | 6 +++--- .../UserInterface/TestSceneButtonSystem.cs | 2 +- .../UserInterface/TestSceneColourPicker.cs | 4 ++-- .../UserInterface/TestSceneCommentEditor.cs | 6 +++--- .../TestSceneCommentRepliesButton.cs | 4 ++-- .../UserInterface/TestSceneContextMenu.cs | 6 +++--- .../Visual/UserInterface/TestSceneCursors.cs | 8 ++++---- .../TestSceneDashboardBeatmapListing.cs | 2 +- .../TestSceneDeleteLocalScore.cs | 2 +- .../UserInterface/TestSceneDialogOverlay.cs | 6 +++--- .../TestSceneDifficultyMultiplierDisplay.cs | 2 +- .../UserInterface/TestSceneDrawableDate.cs | 4 ++-- .../UserInterface/TestSceneEditorSidebar.cs | 2 +- .../UserInterface/TestSceneExpandingBar.cs | 2 +- .../TestSceneExpandingContainer.cs | 4 ++-- .../UserInterface/TestSceneFPSCounter.cs | 2 +- .../TestSceneFirstRunScreenBehaviour.cs | 2 +- .../TestSceneFirstRunScreenBundledBeatmaps.cs | 2 +- ...TestSceneFirstRunScreenImportFromStable.cs | 2 +- .../TestSceneFirstRunScreenUIScale.cs | 2 +- .../TestSceneFirstRunSetupOverlay.cs | 2 +- .../TestSceneFooterButtonMods.cs | 4 ++-- .../TestSceneFriendsOnlineStatusControl.cs | 2 +- .../UserInterface/TestSceneHistoryTextBox.cs | 2 +- .../TestSceneHoldToConfirmOverlay.cs | 4 ++-- .../UserInterface/TestSceneIconButton.cs | 6 +++--- .../TestSceneLabelledColourPalette.cs | 2 +- .../TestSceneLabelledDrawable.cs | 6 +++--- .../TestSceneLabelledDropdown.cs | 2 +- .../TestSceneLabelledSliderBar.cs | 4 ++-- .../TestSceneLabelledSwitchButton.cs | 2 +- .../UserInterface/TestSceneLabelledTextBox.cs | 2 +- .../UserInterface/TestSceneLoadingLayer.cs | 4 ++-- .../UserInterface/TestSceneLoadingSpinner.cs | 2 +- .../UserInterface/TestSceneLogoAnimation.cs | 2 +- .../TestSceneLogoTrackingContainer.cs | 4 ++-- .../UserInterface/TestSceneModColumn.cs | 4 ++-- .../TestSceneModDifficultyAdjustSettings.cs | 2 +- .../UserInterface/TestSceneModDisplay.cs | 2 +- .../UserInterface/TestSceneModFlowDisplay.cs | 2 +- .../Visual/UserInterface/TestSceneModIcon.cs | 2 +- .../Visual/UserInterface/TestSceneModPanel.cs | 2 +- .../UserInterface/TestSceneModPresetColumn.cs | 2 +- .../UserInterface/TestSceneModPresetPanel.cs | 2 +- .../TestSceneModSelectOverlay.cs | 4 ++-- .../UserInterface/TestSceneModSettingsArea.cs | 2 +- .../UserInterface/TestSceneModSwitchSmall.cs | 2 +- .../UserInterface/TestSceneModSwitchTiny.cs | 2 +- .../TestSceneModsEffectDisplay.cs | 4 ++-- .../TestSceneNotificationOverlay.cs | 6 +++--- .../TestSceneNowPlayingOverlay.cs | 2 +- .../UserInterface/TestSceneOnScreenDisplay.cs | 8 ++++---- .../TestSceneOsuAnimatedButton.cs | 4 ++-- .../UserInterface/TestSceneOsuButton.cs | 2 +- .../UserInterface/TestSceneOsuDropdown.cs | 2 +- .../Visual/UserInterface/TestSceneOsuFont.cs | 2 +- .../TestSceneOsuHoverContainer.cs | 4 ++-- .../Visual/UserInterface/TestSceneOsuIcon.cs | 4 ++-- .../Visual/UserInterface/TestSceneOsuLogo.cs | 2 +- .../TestSceneOsuMarkdownContainer.cs | 2 +- .../Visual/UserInterface/TestSceneOsuMenu.cs | 2 +- .../UserInterface/TestSceneOsuPopover.cs | 6 +++--- .../UserInterface/TestSceneOsuTextBox.cs | 2 +- .../UserInterface/TestSceneOverlayHeader.cs | 16 +++++++-------- .../TestSceneOverlayHeaderBackground.cs | 2 +- .../TestSceneOverlayRulesetSelector.cs | 4 ++-- .../TestSceneOverlayScrollContainer.cs | 4 ++-- .../UserInterface/TestScenePageSelector.cs | 2 +- .../TestSceneParallaxContainer.cs | 2 +- .../UserInterface/TestScenePlaylistOverlay.cs | 2 +- .../UserInterface/TestScenePopupDialog.cs | 4 ++-- .../TestSceneProfileSubsectionHeader.cs | 2 +- .../TestSceneRankingsSortTabControl.cs | 2 +- .../UserInterface/TestSceneRoundedButton.cs | 2 +- .../TestSceneSafeAreaHandling.cs | 2 +- .../TestSceneScalingContainer.cs | 2 +- .../TestSceneScreenBreadcrumbControl.cs | 8 ++++---- .../TestSceneSectionsContainer.cs | 6 +++--- .../TestSceneSettingsCheckbox.cs | 4 ++-- .../TestSceneSettingsToolboxGroup.cs | 2 +- .../UserInterface/TestSceneShearedButtons.cs | 2 +- .../TestSceneShearedOverlayContainer.cs | 4 ++-- .../TestSceneShearedOverlayHeader.cs | 2 +- .../TestSceneShearedSearchTextBox.cs | 2 +- .../TestSceneSizePreservingSpriteText.cs | 2 +- .../TestSceneStarRatingDisplay.cs | 2 +- .../TestSceneStatefulMenuItem.cs | 2 +- .../UserInterface/TestSceneSwitchButton.cs | 2 +- .../UserInterface/TestSceneTabControl.cs | 2 +- .../UserInterface/TestSceneToggleMenuItem.cs | 2 +- .../TestSceneToolbarRulesetSelector.cs | 4 ++-- .../UserInterface/TestSceneTwoLayerButton.cs | 2 +- ...tSceneUpdateableBeatmapBackgroundSprite.cs | 4 ++-- .../TestSceneUpdateableBeatmapSetCover.cs | 6 +++--- ...tSceneUprightAspectMaintainingContainer.cs | 2 +- .../UserInterface/TestSceneUserListToolbar.cs | 2 +- .../UserInterface/TestSceneVolumeOverlay.cs | 2 +- .../UserInterface/TestSceneVolumePieces.cs | 2 +- .../UserInterface/TestSceneWaveContainer.cs | 2 +- .../UserInterface/ThemeComparisonTestScene.cs | 2 +- .../Components/TestSceneDateTextBox.cs | 2 +- .../TestSceneDrawableTournamentMatch.cs | 2 +- .../TestSceneDrawableTournamentTeam.cs | 2 +- .../Components/TestSceneMatchHeader.cs | 2 +- .../Components/TestSceneMatchScoreDisplay.cs | 2 +- .../Components/TestSceneRoundDisplay.cs | 2 +- .../Components/TestSceneSongBar.cs | 2 +- .../TestSceneTournamentBeatmapPanel.cs | 2 +- .../TestSceneTournamentMatchChatDisplay.cs | 2 +- .../TestSceneTournamentModDisplay.cs | 2 +- .../NonVisual/DataLoadTest.cs | 4 ++-- .../Screens/TestSceneDrawingsScreen.cs | 2 +- .../Screens/TestSceneGameplayScreen.cs | 2 +- .../Screens/TestSceneLadderEditorScreen.cs | 2 +- .../Screens/TestSceneLadderScreen.cs | 2 +- .../Screens/TestSceneMapPoolScreen.cs | 2 +- .../Screens/TestSceneRoundEditorScreen.cs | 2 +- .../Screens/TestSceneScheduleScreen.cs | 2 +- .../Screens/TestSceneSeedingEditorScreen.cs | 2 +- .../Screens/TestSceneSeedingScreen.cs | 2 +- .../Screens/TestSceneSetupScreen.cs | 2 +- .../Screens/TestSceneShowcaseScreen.cs | 2 +- .../TestSceneStablePathSelectScreen.cs | 4 ++-- .../Screens/TestSceneTeamEditorScreen.cs | 2 +- .../Screens/TestSceneTeamIntroScreen.cs | 2 +- .../Screens/TestSceneTeamWinScreen.cs | 2 +- .../TestSceneTournamentSceneManager.cs | 2 +- .../TournamentTestBrowser.cs | 2 +- .../TournamentTestScene.cs | 4 ++-- .../Components/ControlPanel.cs | 4 ++-- osu.Game.Tournament/Components/DateTextBox.cs | 2 +- .../Components/DrawableTeamFlag.cs | 2 +- .../Components/DrawableTeamHeader.cs | 2 +- .../Components/DrawableTeamTitle.cs | 2 +- .../Components/DrawableTeamTitleWithHeader.cs | 2 +- .../Components/DrawableTeamWithPlayers.cs | 2 +- .../DrawableTournamentHeaderLogo.cs | 4 ++-- .../DrawableTournamentHeaderText.cs | 4 ++-- .../Components/DrawableTournamentTeam.cs | 2 +- .../Components/IPCErrorDialog.cs | 2 +- .../Components/RoundDisplay.cs | 2 +- osu.Game.Tournament/Components/SongBar.cs | 4 ++-- .../Components/TournamentBeatmapPanel.cs | 2 +- .../Components/TournamentMatchChatDisplay.cs | 6 +++--- .../Components/TournamentModIcon.cs | 2 +- .../TournamentSpriteTextWithBackground.cs | 2 +- .../Components/TourneyVideo.cs | 2 +- osu.Game.Tournament/IPC/FileBasedIPC.cs | 2 +- osu.Game.Tournament/IPC/MatchIPCInfo.cs | 2 +- osu.Game.Tournament/SaveChangesOverlay.cs | 2 +- .../Screens/BeatmapInfoScreen.cs | 2 +- .../Screens/Drawings/Components/Group.cs | 2 +- .../Drawings/Components/GroupContainer.cs | 2 +- .../Screens/Drawings/Components/GroupTeam.cs | 2 +- .../Components/ScrollingTeamContainer.cs | 4 ++-- .../Components/VisualiserContainer.cs | 4 ++-- .../Screens/Drawings/DrawingsScreen.cs | 2 +- .../Screens/Editors/LadderEditorScreen.cs | 4 ++-- .../Screens/Editors/RoundEditorScreen.cs | 8 ++++---- .../Screens/Editors/SeedingEditorScreen.cs | 8 ++++---- .../Screens/Editors/TeamEditorScreen.cs | 8 ++++---- .../Screens/Editors/TournamentEditorScreen.cs | 2 +- .../Gameplay/Components/MatchHeader.cs | 2 +- .../Gameplay/Components/MatchRoundDisplay.cs | 2 +- .../Gameplay/Components/TeamDisplay.cs | 2 +- .../Screens/Gameplay/Components/TeamScore.cs | 6 +++--- .../Gameplay/Components/TeamScoreDisplay.cs | 2 +- .../Components/TournamentMatchScoreDisplay.cs | 4 ++-- .../Screens/Gameplay/GameplayScreen.cs | 4 ++-- .../Ladder/Components/DrawableMatchTeam.cs | 2 +- .../Components/DrawableTournamentMatch.cs | 2 +- .../Components/DrawableTournamentRound.cs | 2 +- .../Ladder/Components/LadderEditorSettings.cs | 4 ++-- .../Ladder/Components/ProgressionPath.cs | 2 +- .../Ladder/Components/SettingsTeamDropdown.cs | 2 +- .../Screens/Ladder/LadderDragContainer.cs | 2 +- .../Screens/Ladder/LadderScreen.cs | 2 +- .../Screens/MapPool/MapPoolScreen.cs | 2 +- .../Screens/Schedule/ScheduleScreen.cs | 8 ++++---- .../Screens/Setup/ActionableInfo.cs | 2 +- .../Screens/Setup/ResolutionSelector.cs | 2 +- .../Screens/Setup/SetupScreen.cs | 2 +- .../Screens/Setup/StablePathSelectScreen.cs | 2 +- .../Screens/Setup/TournamentSwitcher.cs | 2 +- .../Screens/Showcase/ShowcaseScreen.cs | 2 +- .../Screens/Showcase/TournamentLogo.cs | 2 +- .../Screens/TeamIntro/SeedingScreen.cs | 14 ++++++------- .../Screens/TeamIntro/TeamIntroScreen.cs | 2 +- .../Screens/TeamWin/TeamWinScreen.cs | 2 +- .../Screens/TournamentMatchScreen.cs | 2 +- .../Screens/TournamentScreen.cs | 2 +- osu.Game.Tournament/TournamentGame.cs | 2 +- osu.Game.Tournament/TournamentGameBase.cs | 4 ++-- osu.Game.Tournament/TournamentSceneManager.cs | 6 +++--- osu.Game.Tournament/TournamentSpriteText.cs | 2 +- osu.Game.Tournament/TourneyButton.cs | 2 +- osu.Game.Tournament/WarningBox.cs | 2 +- osu.Game/Audio/Effects/AudioFilter.cs | 2 +- osu.Game/Audio/PreviewTrack.cs | 2 +- osu.Game/Audio/PreviewTrackManager.cs | 4 ++-- osu.Game/BackgroundBeatmapProcessor.cs | 2 +- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 2 +- .../Beatmaps/BeatmapOnlineChangeIngest.cs | 2 +- osu.Game/Beatmaps/BeatmapStatisticIcon.cs | 2 +- osu.Game/Beatmaps/DifficultyRecommender.cs | 2 +- .../Drawables/BeatmapBackgroundSprite.cs | 2 +- .../Drawables/BeatmapDownloadButton.cs | 2 +- .../Drawables/BeatmapSetOnlineStatusPill.cs | 2 +- .../Drawables/BundledBeatmapDownloader.cs | 2 +- .../Beatmaps/Drawables/Cards/BeatmapCard.cs | 2 +- .../Drawables/Cards/BeatmapCardContent.cs | 2 +- .../Cards/BeatmapCardContentBackground.cs | 2 +- .../Cards/BeatmapCardDifficultyList.cs | 4 ++-- .../Cards/BeatmapCardDownloadProgressBar.cs | 2 +- .../Drawables/Cards/BeatmapCardExtra.cs | 2 +- .../Cards/BeatmapCardExtraInfoRow.cs | 2 +- .../Drawables/Cards/BeatmapCardNormal.cs | 2 +- .../Drawables/Cards/BeatmapCardThumbnail.cs | 2 +- .../Cards/Buttons/BeatmapCardIconButton.cs | 2 +- .../Drawables/Cards/Buttons/DownloadButton.cs | 2 +- .../Cards/Buttons/FavouriteButton.cs | 2 +- .../Cards/Buttons/GoToBeatmapButton.cs | 2 +- .../Drawables/Cards/Buttons/PlayButton.cs | 2 +- .../Cards/CollapsibleButtonContainer.cs | 2 +- .../Cards/ExpandedContentScrollContainer.cs | 4 ++-- .../Drawables/Cards/HoverHandlingContainer.cs | 2 +- osu.Game/Beatmaps/Drawables/Cards/IconPill.cs | 2 +- .../Statistics/BeatmapCardDateStatistic.cs | 2 +- .../Cards/Statistics/BeatmapCardStatistic.cs | 2 +- .../Cards/Statistics/FavouritesStatistic.cs | 2 +- .../Cards/Statistics/HypesStatistic.cs | 2 +- .../Cards/Statistics/NominationsStatistic.cs | 2 +- .../Cards/Statistics/PlayCountStatistic.cs | 2 +- .../Drawables/Cards/StoryboardIconPill.cs | 2 +- .../Beatmaps/Drawables/Cards/VideoIconPill.cs | 2 +- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 2 +- .../Drawables/DifficultyIconTooltip.cs | 2 +- .../Drawables/DifficultySpectrumDisplay.cs | 6 +++--- .../Beatmaps/Drawables/DownloadProgressBar.cs | 2 +- .../Drawables/OnlineBeatmapSetCover.cs | 2 +- .../Beatmaps/Drawables/StarRatingDisplay.cs | 2 +- .../UpdateableBeatmapBackgroundSprite.cs | 2 +- .../UpdateableOnlineBeatmapSetCover.cs | 2 +- osu.Game/Beatmaps/FramedBeatmapClock.cs | 2 +- osu.Game/Collections/CollectionDropdown.cs | 8 ++++---- .../Collections/DeleteCollectionDialog.cs | 2 +- .../Collections/DrawableCollectionList.cs | 6 +++--- .../Collections/DrawableCollectionListItem.cs | 8 ++++---- .../Collections/ManageCollectionsDialog.cs | 2 +- .../Configuration/SettingSourceAttribute.cs | 6 +++--- osu.Game/Database/BeatmapLookupCache.cs | 2 +- .../Database/ImportProgressNotification.cs | 2 +- osu.Game/Database/LegacyImportManager.cs | 2 +- osu.Game/Database/MemoryCachingComponent.cs | 2 +- osu.Game/Database/ModelDownloader.cs | 6 +++--- osu.Game/Database/OnlineLookupCache.cs | 2 +- .../Database/TooManyDownloadsNotification.cs | 2 +- osu.Game/Database/UserLookupCache.cs | 2 +- osu.Game/Graphics/Backgrounds/Background.cs | 2 +- .../Graphics/Backgrounds/BeatmapBackground.cs | 2 +- .../BeatmapBackgroundWithStoryboard.cs | 2 +- .../Backgrounds/SeasonalBackgroundLoader.cs | 4 ++-- .../Graphics/Backgrounds/SkinBackground.cs | 2 +- osu.Game/Graphics/Backgrounds/Triangles.cs | 2 +- .../Containers/BeatSyncedContainer.cs | 2 +- .../Containers/ConstrainedIconContainer.cs | 2 +- .../Containers/ExpandingButtonContainer.cs | 2 +- .../Graphics/Containers/ExpandingContainer.cs | 2 +- .../Containers/HoldToConfirmContainer.cs | 2 +- .../Graphics/Containers/LinkFlowContainer.cs | 2 +- .../Containers/LogoTrackingContainer.cs | 6 +++--- .../Markdown/OsuMarkdownContainer.cs | 2 +- .../Markdown/OsuMarkdownFencedCodeBlock.cs | 6 +++--- .../Containers/Markdown/OsuMarkdownHeading.cs | 4 ++-- .../Containers/Markdown/OsuMarkdownImage.cs | 2 +- .../Markdown/OsuMarkdownLinkText.cs | 4 ++-- .../Markdown/OsuMarkdownListItem.cs | 2 +- .../Markdown/OsuMarkdownOrderedListItem.cs | 2 +- .../Markdown/OsuMarkdownQuoteBlock.cs | 4 ++-- .../Markdown/OsuMarkdownSeparator.cs | 4 ++-- .../Containers/Markdown/OsuMarkdownTable.cs | 2 +- .../Markdown/OsuMarkdownTableCell.cs | 8 ++++---- .../Markdown/OsuMarkdownTextFlowContainer.cs | 4 ++-- .../Markdown/OsuMarkdownUnorderedListItem.cs | 2 +- .../Containers/OsuClickableContainer.cs | 2 +- .../Containers/OsuFocusedOverlayContainer.cs | 2 +- .../Graphics/Containers/OsuHoverContainer.cs | 2 +- .../OsuRearrangeableListContainer.cs | 2 +- .../Containers/OsuRearrangeableListItem.cs | 4 ++-- .../Graphics/Containers/OsuScrollContainer.cs | 6 +++--- .../Containers/OsuTextFlowContainer.cs | 2 +- .../Graphics/Containers/ParallaxContainer.cs | 2 +- .../ReverseChildIDFillFlowContainer.cs | 2 +- .../Graphics/Containers/ScalingContainer.cs | 8 ++++---- .../Graphics/Containers/SectionsContainer.cs | 2 +- .../SelectionCycleFillFlowContainer.cs | 2 +- .../Graphics/Containers/ShakeContainer.cs | 2 +- .../UprightAspectMaintainingContainer.cs | 2 +- .../Graphics/Containers/UserDimContainer.cs | 2 +- .../Containers/UserTrackingScrollContainer.cs | 4 ++-- osu.Game/Graphics/Containers/WaveContainer.cs | 4 ++-- .../Graphics/Cursor/GlobalCursorDisplay.cs | 2 +- .../Graphics/Cursor/MenuCursorContainer.cs | 6 +++--- .../Cursor/OsuContextMenuContainer.cs | 2 +- .../Graphics/Cursor/OsuTooltipContainer.cs | 4 ++-- osu.Game/Graphics/DateTooltip.cs | 2 +- osu.Game/Graphics/DrawableDate.cs | 2 +- osu.Game/Graphics/ErrorTextFlowContainer.cs | 2 +- osu.Game/Graphics/InputBlockingContainer.cs | 2 +- osu.Game/Graphics/ParticleExplosion.cs | 2 +- osu.Game/Graphics/ParticleSpewer.cs | 2 +- osu.Game/Graphics/ScreenshotManager.cs | 2 +- .../Graphics/Sprites/GlowingSpriteText.cs | 2 +- osu.Game/Graphics/Sprites/LogoAnimation.cs | 2 +- osu.Game/Graphics/Sprites/OsuSpriteText.cs | 2 +- .../Sprites/SizePreservingSpriteText.cs | 2 +- osu.Game/Graphics/UserInterface/BackButton.cs | 4 ++-- osu.Game/Graphics/UserInterface/Bar.cs | 2 +- osu.Game/Graphics/UserInterface/BarGraph.cs | 2 +- .../UserInterface/BasicSearchTextBox.cs | 2 +- .../UserInterface/BreadcrumbControl.cs | 4 ++-- .../CommaSeparatedScoreCounter.cs | 2 +- .../UserInterface/DangerousTriangleButton.cs | 2 +- .../Graphics/UserInterface/DialogButton.cs | 2 +- .../Graphics/UserInterface/DownloadButton.cs | 2 +- .../UserInterface/DrawableOsuMenuItem.cs | 4 ++-- .../UserInterface/DrawableStatefulMenuItem.cs | 4 ++-- .../UserInterface/ExpandableSlider.cs | 4 ++-- .../Graphics/UserInterface/ExpandingBar.cs | 2 +- .../UserInterface/ExternalLinkButton.cs | 2 +- osu.Game/Graphics/UserInterface/FPSCounter.cs | 2 +- .../UserInterface/FPSCounterTooltip.cs | 2 +- .../Graphics/UserInterface/FocusedTextBox.cs | 2 +- .../UserInterface/GradientLineTabControl.cs | 4 ++-- osu.Game/Graphics/UserInterface/GrayButton.cs | 2 +- .../Graphics/UserInterface/HistoryTextBox.cs | 2 +- .../UserInterface/HoverClickSounds.cs | 2 +- .../HoverSampleDebounceComponent.cs | 2 +- .../Graphics/UserInterface/HoverSounds.cs | 2 +- osu.Game/Graphics/UserInterface/IconButton.cs | 2 +- osu.Game/Graphics/UserInterface/LineGraph.cs | 2 +- .../Graphics/UserInterface/LoadingButton.cs | 2 +- .../Graphics/UserInterface/LoadingLayer.cs | 2 +- .../Graphics/UserInterface/LoadingSpinner.cs | 2 +- osu.Game/Graphics/UserInterface/Nub.cs | 2 +- .../UserInterface/OsuAnimatedButton.cs | 2 +- osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- .../Graphics/UserInterface/OsuCheckbox.cs | 2 +- .../Graphics/UserInterface/OsuContextMenu.cs | 2 +- .../UserInterface/OsuContextMenuSamples.cs | 2 +- .../Graphics/UserInterface/OsuDropdown.cs | 10 +++++----- .../Graphics/UserInterface/OsuEnumDropdown.cs | 2 +- osu.Game/Graphics/UserInterface/OsuMenu.cs | 2 +- .../Graphics/UserInterface/OsuNumberBox.cs | 2 +- .../UserInterface/OsuPasswordTextBox.cs | 6 +++--- .../Graphics/UserInterface/OsuSliderBar.cs | 2 +- .../Graphics/UserInterface/OsuTabControl.cs | 4 ++-- .../UserInterface/OsuTabControlCheckbox.cs | 2 +- .../Graphics/UserInterface/OsuTabDropdown.cs | 8 ++++---- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 6 +++--- .../PageSelector/PageEllipsis.cs | 2 +- .../PageSelector/PageSelector.cs | 2 +- .../PageSelector/PageSelectorButton.cs | 2 +- .../PageSelector/PageSelectorPageButton.cs | 2 +- .../PageSelectorPrevNextButton.cs | 2 +- .../Graphics/UserInterface/PageTabControl.cs | 4 ++-- .../UserInterface/PercentageCounter.cs | 2 +- .../Graphics/UserInterface/ProgressBar.cs | 2 +- .../Graphics/UserInterface/RollingCounter.cs | 2 +- .../Graphics/UserInterface/ScoreCounter.cs | 2 +- .../UserInterface/ScreenBreadcrumbControl.cs | 2 +- .../Graphics/UserInterface/SearchTextBox.cs | 2 +- .../UserInterface/SeekLimitedSearchTextBox.cs | 2 +- .../Graphics/UserInterface/ShearedButton.cs | 2 +- .../UserInterface/ShearedOverlayHeader.cs | 2 +- .../UserInterface/ShearedSearchTextBox.cs | 6 +++--- .../UserInterface/ShearedToggleButton.cs | 2 +- .../Graphics/UserInterface/ShowMoreButton.cs | 4 ++-- .../UserInterface/SlimEnumDropdown.cs | 4 ++-- .../Graphics/UserInterface/StarCounter.cs | 6 +++--- osu.Game/Graphics/UserInterface/TimeSlider.cs | 2 +- .../Graphics/UserInterface/TriangleButton.cs | 2 +- .../Graphics/UserInterface/TwoLayerButton.cs | 4 ++-- .../Graphics/UserInterfaceV2/ColourDisplay.cs | 4 ++-- .../Graphics/UserInterfaceV2/ColourPalette.cs | 4 ++-- .../UserInterfaceV2/LabelledColourPalette.cs | 2 +- .../UserInterfaceV2/LabelledComponent.cs | 2 +- .../UserInterfaceV2/LabelledDrawable.cs | 2 +- .../UserInterfaceV2/LabelledDropdown.cs | 2 +- .../UserInterfaceV2/LabelledEnumDropdown.cs | 2 +- .../UserInterfaceV2/LabelledNumberBox.cs | 2 +- .../UserInterfaceV2/LabelledSliderBar.cs | 2 +- .../UserInterfaceV2/LabelledSwitchButton.cs | 2 +- .../UserInterfaceV2/LabelledTextBox.cs | 2 +- .../UserInterfaceV2/OsuColourPicker.cs | 2 +- .../UserInterfaceV2/OsuDirectorySelector.cs | 2 +- .../OsuDirectorySelectorBreadcrumbDisplay.cs | 6 +++--- .../OsuDirectorySelectorDirectory.cs | 4 ++-- .../OsuDirectorySelectorHiddenToggle.cs | 2 +- .../OsuDirectorySelectorParentDirectory.cs | 2 +- .../UserInterfaceV2/OsuFileSelector.cs | 4 ++-- .../UserInterfaceV2/OsuHSVColourPicker.cs | 10 +++++----- .../UserInterfaceV2/OsuHexColourPicker.cs | 4 ++-- .../Graphics/UserInterfaceV2/OsuPopover.cs | 2 +- .../Graphics/UserInterfaceV2/RoundedButton.cs | 2 +- .../Graphics/UserInterfaceV2/SwitchButton.cs | 4 ++-- .../Bindings/DatabasedKeyBindingContainer.cs | 2 +- .../Input/Bindings/GlobalActionContainer.cs | 2 +- osu.Game/Input/ConfineMouseTracker.cs | 2 +- osu.Game/Input/GameIdleTracker.cs | 2 +- osu.Game/Input/IdleTracker.cs | 2 +- osu.Game/Input/OsuUserInputManager.cs | 2 +- osu.Game/Online/API/APIAccess.cs | 2 +- osu.Game/Online/API/DummyAPIAccess.cs | 2 +- osu.Game/Online/BeatmapDownloadTracker.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 2 +- osu.Game/Online/Chat/DrawableLinkCompiler.cs | 4 ++-- osu.Game/Online/Chat/ExternalLinkOpener.cs | 4 ++-- osu.Game/Online/Chat/MessageNotifier.cs | 8 ++++---- osu.Game/Online/Chat/NowPlayingCommand.cs | 2 +- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 10 +++++----- osu.Game/Online/DownloadTracker.cs | 2 +- osu.Game/Online/Leaderboards/DrawableRank.cs | 2 +- osu.Game/Online/Leaderboards/Leaderboard.cs | 2 +- .../Online/Leaderboards/LeaderboardScore.cs | 8 ++++---- .../Leaderboards/LeaderboardScoreTooltip.cs | 6 +++--- .../Online/Leaderboards/UpdateableRank.cs | 2 +- .../Leaderboards/UserTopScoreContainer.cs | 2 +- osu.Game/Online/Metadata/MetadataClient.cs | 2 +- .../Online/Metadata/OnlineMetadataClient.cs | 2 +- .../Online/Multiplayer/MultiplayerClient.cs | 2 +- .../Multiplayer/OnlineMultiplayerClient.cs | 2 +- .../Multiplayer/ServerShutdownNotification.cs | 2 +- osu.Game/Online/OnlineViewContainer.cs | 2 +- .../Placeholders/ClickablePlaceholder.cs | 2 +- .../Online/Placeholders/LoginPlaceholder.cs | 2 +- .../Online/Placeholders/MessagePlaceholder.cs | 2 +- osu.Game/Online/Placeholders/Placeholder.cs | 2 +- osu.Game/Online/PollingComponent.cs | 2 +- osu.Game/Online/Rooms/APICreatedRoom.cs | 2 +- .../OnlinePlayBeatmapAvailabilityTracker.cs | 2 +- osu.Game/Online/Rooms/Room.cs | 2 +- osu.Game/Online/ScoreDownloadTracker.cs | 2 +- .../Online/Spectator/OnlineSpectatorClient.cs | 2 +- osu.Game/Online/Spectator/SpectatorClient.cs | 2 +- .../Spectator/SpectatorScoreProcessor.cs | 2 +- osu.Game/OsuGame.cs | 2 +- .../AccountCreationBackground.cs | 2 +- .../AccountCreation/AccountCreationScreen.cs | 2 +- .../Overlays/AccountCreation/ScreenEntry.cs | 2 +- .../Overlays/AccountCreation/ScreenWarning.cs | 2 +- .../Overlays/AccountCreation/ScreenWelcome.cs | 2 +- osu.Game/Overlays/AccountCreationOverlay.cs | 2 +- .../BeatmapListingCardSizeTabControl.cs | 4 ++-- .../BeatmapListingFilterControl.cs | 2 +- .../BeatmapListing/BeatmapListingHeader.cs | 4 ++-- .../BeatmapListingSearchControl.cs | 6 +++--- .../BeatmapListingSortTabControl.cs | 8 ++++---- .../BeatmapListing/BeatmapSearchFilterRow.cs | 8 ++++---- .../BeatmapSearchGeneralFilterRow.cs | 6 +++--- ...BeatmapSearchMultipleSelectionFilterRow.cs | 6 +++--- .../BeatmapSearchRulesetFilterRow.cs | 6 +++--- .../BeatmapSearchScoreFilterRow.cs | 6 +++--- .../Overlays/BeatmapListing/FilterTabItem.cs | 2 +- osu.Game/Overlays/BeatmapListingOverlay.cs | 6 +++--- osu.Game/Overlays/BeatmapSet/AuthorInfo.cs | 4 ++-- osu.Game/Overlays/BeatmapSet/BasicStats.cs | 4 ++-- .../BeatmapSet/BeatmapAvailability.cs | 2 +- osu.Game/Overlays/BeatmapSet/BeatmapBadge.cs | 2 +- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 8 ++++---- .../BeatmapSet/BeatmapRulesetSelector.cs | 2 +- .../BeatmapSet/BeatmapRulesetTabItem.cs | 2 +- .../Overlays/BeatmapSet/BeatmapSetHeader.cs | 4 ++-- .../BeatmapSet/BeatmapSetHeaderContent.cs | 2 +- .../BeatmapSet/BeatmapSetLayoutSection.cs | 2 +- .../BeatmapSet/Buttons/FavouriteButton.cs | 2 +- .../BeatmapSet/Buttons/HeaderButton.cs | 2 +- .../Buttons/HeaderDownloadButton.cs | 2 +- .../Overlays/BeatmapSet/Buttons/PlayButton.cs | 2 +- .../BeatmapSet/Buttons/PreviewButton.cs | 2 +- osu.Game/Overlays/BeatmapSet/Details.cs | 4 ++-- .../BeatmapSet/ExplicitContentBeatmapBadge.cs | 2 +- .../BeatmapSet/FeaturedArtistBeatmapBadge.cs | 2 +- osu.Game/Overlays/BeatmapSet/Info.cs | 2 +- .../BeatmapSet/LeaderboardModSelector.cs | 4 ++-- .../BeatmapSet/LeaderboardScopeSelector.cs | 4 ++-- .../Overlays/BeatmapSet/MetadataSection.cs | 2 +- .../BeatmapSet/Scores/DrawableTopScore.cs | 4 ++-- .../BeatmapSet/Scores/NoScoresPlaceholder.cs | 2 +- .../Scores/NotSupporterPlaceholder.cs | 2 +- .../Overlays/BeatmapSet/Scores/ScoreTable.cs | 6 +++--- .../Scores/ScoreTableRowBackground.cs | 2 +- .../BeatmapSet/Scores/ScoreboardTime.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 2 +- .../Scores/TopScoreStatisticsSection.cs | 8 ++++---- .../BeatmapSet/Scores/TopScoreUserSection.cs | 2 +- .../BeatmapSet/SpotlightBeatmapBadge.cs | 2 +- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 4 ++-- osu.Game/Overlays/BeatmapSetOverlay.cs | 4 ++-- .../BreadcrumbControlOverlayHeader.cs | 6 +++--- osu.Game/Overlays/Changelog/ChangelogBuild.cs | 2 +- .../Overlays/Changelog/ChangelogContent.cs | 2 +- osu.Game/Overlays/Changelog/ChangelogEntry.cs | 2 +- .../Overlays/Changelog/ChangelogHeader.cs | 4 ++-- .../Overlays/Changelog/ChangelogListing.cs | 2 +- .../Changelog/ChangelogSingleBuild.cs | 6 +++--- .../Changelog/ChangelogSupporterPromo.cs | 6 +++--- .../Changelog/ChangelogUpdateStreamControl.cs | 2 +- .../Changelog/ChangelogUpdateStreamItem.cs | 2 +- osu.Game/Overlays/ChangelogOverlay.cs | 2 +- .../Overlays/Chat/ChannelList/ChannelList.cs | 4 ++-- .../Chat/ChannelList/ChannelListItem.cs | 2 +- .../ChannelList/ChannelListItemCloseButton.cs | 2 +- .../ChannelList/ChannelListItemMentionPill.cs | 2 +- .../Overlays/Chat/ChannelScrollContainer.cs | 2 +- osu.Game/Overlays/Chat/ChatLine.cs | 4 ++-- osu.Game/Overlays/Chat/ChatOverlayTopBar.cs | 2 +- osu.Game/Overlays/Chat/ChatTextBar.cs | 2 +- osu.Game/Overlays/Chat/ChatTextBox.cs | 2 +- osu.Game/Overlays/Chat/DaySeparator.cs | 2 +- osu.Game/Overlays/Chat/DrawableChannel.cs | 2 +- .../Overlays/Chat/Listing/ChannelListing.cs | 2 +- .../Chat/Listing/ChannelListingItem.cs | 2 +- osu.Game/Overlays/ChatOverlay.cs | 2 +- .../Comments/Buttons/ChevronButton.cs | 2 +- .../Comments/Buttons/CommentRepliesButton.cs | 2 +- .../Comments/Buttons/LoadRepliesButton.cs | 4 ++-- .../Comments/Buttons/ShowMoreRepliesButton.cs | 2 +- .../Comments/Buttons/ShowRepliesButton.cs | 2 +- .../Comments/CancellableCommentEditor.cs | 4 ++-- osu.Game/Overlays/Comments/CommentEditor.cs | 6 +++--- .../Comments/CommentMarkdownContainer.cs | 4 ++-- .../Overlays/Comments/CommentReportButton.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 4 ++-- osu.Game/Overlays/Comments/CommentsHeader.cs | 4 ++-- .../Comments/CommentsShowMoreButton.cs | 2 +- .../Comments/DeletedCommentsCounter.cs | 2 +- osu.Game/Overlays/Comments/DrawableComment.cs | 6 +++--- osu.Game/Overlays/Comments/HeaderButton.cs | 2 +- .../Overlays/Comments/ReportCommentPopover.cs | 2 +- .../Overlays/Comments/TotalCommentsCounter.cs | 2 +- osu.Game/Overlays/Comments/VotePill.cs | 2 +- .../Dashboard/CurrentlyPlayingDisplay.cs | 4 ++-- .../Dashboard/DashboardOverlayHeader.cs | 4 ++-- .../Dashboard/Friends/FriendDisplay.cs | 2 +- .../Friends/FriendOnlineStreamControl.cs | 2 +- .../Friends/FriendsOnlineStatusItem.cs | 2 +- .../Dashboard/Friends/UserListToolbar.cs | 2 +- .../Dashboard/Friends/UserSortTabControl.cs | 2 +- .../Dashboard/Home/DashboardBeatmapListing.cs | 2 +- .../Dashboard/Home/DashboardBeatmapPanel.cs | 2 +- .../Home/DashboardNewBeatmapPanel.cs | 2 +- .../Home/DashboardPopularBeatmapPanel.cs | 2 +- .../Dashboard/Home/DrawableBeatmapList.cs | 2 +- .../Dashboard/Home/DrawableNewBeatmapList.cs | 2 +- .../Home/DrawablePopularBeatmapList.cs | 2 +- osu.Game/Overlays/Dashboard/Home/HomePanel.cs | 2 +- .../Home/News/FeaturedNewsItemPanel.cs | 6 +++--- .../Dashboard/Home/News/NewsGroupItem.cs | 4 ++-- .../Dashboard/Home/News/NewsItemGroupPanel.cs | 2 +- .../Dashboard/Home/News/NewsTitleLink.cs | 2 +- .../Dashboard/Home/News/ShowMoreNewsPanel.cs | 2 +- osu.Game/Overlays/DashboardOverlay.cs | 2 +- osu.Game/Overlays/Dialog/ConfirmDialog.cs | 2 +- .../Dialog/DeleteConfirmationDialog.cs | 2 +- osu.Game/Overlays/Dialog/PopupDialog.cs | 2 +- osu.Game/Overlays/Dialog/PopupDialogButton.cs | 2 +- .../Dialog/PopupDialogCancelButton.cs | 2 +- .../Dialog/PopupDialogDangerousButton.cs | 4 ++-- .../Overlays/Dialog/PopupDialogOkButton.cs | 2 +- osu.Game/Overlays/DialogOverlay.cs | 2 +- .../FirstRunSetup/FirstRunSetupScreen.cs | 2 +- .../FirstRunSetup/ProgressRoundedButton.cs | 2 +- .../Overlays/FirstRunSetup/ScreenBeatmaps.cs | 2 +- .../Overlays/FirstRunSetup/ScreenBehaviour.cs | 2 +- .../FirstRunSetup/ScreenImportFromStable.cs | 8 ++++---- .../Overlays/FirstRunSetup/ScreenUIScale.cs | 12 +++++------ .../Overlays/FirstRunSetup/ScreenWelcome.cs | 6 +++--- osu.Game/Overlays/FirstRunSetupOverlay.cs | 2 +- osu.Game/Overlays/FullscreenOverlay.cs | 2 +- osu.Game/Overlays/HoldToConfirmOverlay.cs | 2 +- osu.Game/Overlays/Login/LoginForm.cs | 2 +- osu.Game/Overlays/Login/LoginPanel.cs | 2 +- osu.Game/Overlays/Login/UserDropdown.cs | 8 ++++---- osu.Game/Overlays/LoginOverlay.cs | 2 +- osu.Game/Overlays/MedalOverlay.cs | 6 +++--- .../Overlays/MedalSplash/DrawableMedal.cs | 2 +- osu.Game/Overlays/Mods/AddPresetButton.cs | 2 +- osu.Game/Overlays/Mods/AddPresetPopover.cs | 2 +- .../Overlays/Mods/DeleteModPresetDialog.cs | 2 +- .../Overlays/Mods/DeselectAllModsButton.cs | 2 +- .../Mods/DifficultyMultiplierDisplay.cs | 2 +- .../Mods/IncompatibilityDisplayingModPanel.cs | 2 +- .../Mods/IncompatibilityDisplayingTooltip.cs | 2 +- osu.Game/Overlays/Mods/ModButtonTooltip.cs | 2 +- osu.Game/Overlays/Mods/ModColumn.cs | 4 ++-- osu.Game/Overlays/Mods/ModPanel.cs | 2 +- osu.Game/Overlays/Mods/ModPresetColumn.cs | 2 +- osu.Game/Overlays/Mods/ModPresetPanel.cs | 2 +- osu.Game/Overlays/Mods/ModPresetTooltip.cs | 4 ++-- osu.Game/Overlays/Mods/ModSelectColumn.cs | 2 +- osu.Game/Overlays/Mods/ModSelectOverlay.cs | 10 +++++----- osu.Game/Overlays/Mods/ModSelectPanel.cs | 2 +- osu.Game/Overlays/Mods/ModSettingsArea.cs | 4 ++-- osu.Game/Overlays/Mods/ModsEffectDisplay.cs | 4 ++-- osu.Game/Overlays/Mods/SelectAllModsButton.cs | 2 +- .../Overlays/Mods/ShearedOverlayContainer.cs | 2 +- .../Overlays/Mods/UserModSelectOverlay.cs | 4 ++-- osu.Game/Overlays/Music/FilterControl.cs | 4 ++-- .../Overlays/Music/MusicKeyBindingHandler.cs | 4 ++-- .../Music/NowPlayingCollectionDropdown.cs | 6 +++--- osu.Game/Overlays/Music/Playlist.cs | 2 +- osu.Game/Overlays/Music/PlaylistItem.cs | 2 +- osu.Game/Overlays/Music/PlaylistOverlay.cs | 2 +- osu.Game/Overlays/MusicController.cs | 2 +- .../Overlays/News/Displays/ArticleListing.cs | 2 +- osu.Game/Overlays/News/NewsCard.cs | 4 ++-- osu.Game/Overlays/News/NewsHeader.cs | 4 ++-- osu.Game/Overlays/News/NewsPostBackground.cs | 2 +- .../Overlays/News/Sidebar/MonthSection.cs | 8 ++++---- osu.Game/Overlays/News/Sidebar/NewsSidebar.cs | 2 +- osu.Game/Overlays/News/Sidebar/YearsPanel.cs | 4 ++-- osu.Game/Overlays/NewsOverlay.cs | 2 +- osu.Game/Overlays/NotificationOverlay.cs | 2 +- .../Overlays/NotificationOverlayToastTray.cs | 2 +- .../Overlays/Notifications/Notification.cs | 8 ++++---- .../Notifications/NotificationSection.cs | 6 +++--- .../ProgressCompletionNotification.cs | 2 +- .../Notifications/ProgressNotification.cs | 4 ++-- .../Notifications/SimpleErrorNotification.cs | 2 +- .../Notifications/SimpleNotification.cs | 2 +- osu.Game/Overlays/NowPlayingOverlay.cs | 10 +++++----- osu.Game/Overlays/OSD/CopyUrlToast.cs | 2 +- osu.Game/Overlays/OSD/Toast.cs | 2 +- osu.Game/Overlays/OSD/TrackedSettingToast.cs | 4 ++-- osu.Game/Overlays/OnScreenDisplay.cs | 2 +- osu.Game/Overlays/OnlineOverlay.cs | 2 +- osu.Game/Overlays/OverlayHeader.cs | 2 +- osu.Game/Overlays/OverlayHeaderBackground.cs | 4 ++-- .../OverlayPanelDisplayStyleControl.cs | 4 ++-- osu.Game/Overlays/OverlayRulesetSelector.cs | 2 +- osu.Game/Overlays/OverlayRulesetTabItem.cs | 2 +- osu.Game/Overlays/OverlayScrollContainer.cs | 4 ++-- osu.Game/Overlays/OverlaySidebar.cs | 2 +- osu.Game/Overlays/OverlaySortTabControl.cs | 8 ++++---- osu.Game/Overlays/OverlayStreamControl.cs | 2 +- osu.Game/Overlays/OverlayStreamItem.cs | 2 +- osu.Game/Overlays/OverlayTabControl.cs | 4 ++-- osu.Game/Overlays/OverlayTitle.cs | 4 ++-- osu.Game/Overlays/OverlayView.cs | 2 +- .../Profile/Header/BottomHeaderContainer.cs | 2 +- .../Profile/Header/CentreHeaderContainer.cs | 2 +- .../Header/Components/DrawableBadge.cs | 2 +- .../Header/Components/ExpandDetailsButton.cs | 2 +- .../Header/Components/FollowersButton.cs | 2 +- .../Profile/Header/Components/LevelBadge.cs | 2 +- .../Header/Components/LevelProgressBar.cs | 2 +- .../Components/MappingSubscribersButton.cs | 2 +- .../Header/Components/MessageUserButton.cs | 2 +- .../Components/OverlinedInfoContainer.cs | 2 +- .../Components/OverlinedTotalPlayTime.cs | 2 +- .../Header/Components/PreviousUsernames.cs | 4 ++-- .../Header/Components/ProfileHeaderButton.cs | 2 +- .../ProfileHeaderStatisticsButton.cs | 2 +- .../Components/ProfileRulesetSelector.cs | 2 +- .../Components/ProfileRulesetTabItem.cs | 4 ++-- .../Profile/Header/Components/RankGraph.cs | 2 +- .../Header/Components/SupporterIcon.cs | 2 +- .../Profile/Header/DetailHeaderContainer.cs | 4 ++-- .../Profile/Header/MedalHeaderContainer.cs | 2 +- .../Profile/Header/TopHeaderContainer.cs | 4 ++-- osu.Game/Overlays/Profile/ProfileHeader.cs | 6 +++--- osu.Game/Overlays/Profile/ProfileSection.cs | 4 ++-- .../Overlays/Profile/Sections/AboutSection.cs | 2 +- .../Sections/BeatmapMetadataContainer.cs | 2 +- .../Beatmaps/PaginatedBeatmapContainer.cs | 2 +- .../Profile/Sections/BeatmapsSection.cs | 2 +- .../Overlays/Profile/Sections/CounterPill.cs | 2 +- .../Historical/ChartProfileSubsection.cs | 2 +- .../Historical/DrawableMostPlayedBeatmap.cs | 8 ++++---- .../PaginatedMostPlayedBeatmapContainer.cs | 2 +- .../Historical/PlayHistorySubsection.cs | 2 +- .../Sections/Historical/ProfileLineChart.cs | 6 +++--- .../Sections/Historical/ReplaysSubsection.cs | 2 +- .../Sections/Historical/UserHistoryGraph.cs | 2 +- .../Profile/Sections/HistoricalSection.cs | 2 +- .../Kudosu/DrawableKudosuHistoryItem.cs | 2 +- .../Profile/Sections/Kudosu/KudosuInfo.cs | 6 +++--- .../Kudosu/PaginatedKudosuHistoryContainer.cs | 2 +- .../Profile/Sections/KudosuSection.cs | 2 +- .../Profile/Sections/MedalsSection.cs | 2 +- .../Sections/PaginatedProfileSubsection.cs | 2 +- .../Profile/Sections/ProfileItemContainer.cs | 2 +- .../Profile/Sections/ProfileSubsection.cs | 2 +- .../Sections/ProfileSubsectionHeader.cs | 2 +- .../Sections/Ranks/DrawableProfileScore.cs | 4 ++-- .../Ranks/DrawableProfileWeightedScore.cs | 2 +- .../Sections/Ranks/PaginatedScoreContainer.cs | 2 +- .../Overlays/Profile/Sections/RanksSection.cs | 2 +- .../Sections/Recent/DrawableRecentActivity.cs | 2 +- .../Profile/Sections/Recent/MedalIcon.cs | 2 +- .../PaginatedRecentActivityContainer.cs | 2 +- .../Sections/Recent/RecentActivityIcon.cs | 2 +- .../Profile/Sections/RecentSection.cs | 2 +- osu.Game/Overlays/Profile/UserGraph.cs | 6 +++--- osu.Game/Overlays/Rankings/CountryFilter.cs | 2 +- osu.Game/Overlays/Rankings/CountryPill.cs | 4 ++-- .../Rankings/RankingsOverlayHeader.cs | 4 ++-- .../Rankings/RankingsSortTabControl.cs | 2 +- .../Overlays/Rankings/SpotlightSelector.cs | 8 ++++---- .../Overlays/Rankings/SpotlightsLayout.cs | 2 +- .../Rankings/Tables/CountriesTable.cs | 4 ++-- .../Rankings/Tables/PerformanceTable.cs | 2 +- .../Overlays/Rankings/Tables/RankingsTable.cs | 8 ++++---- .../Overlays/Rankings/Tables/ScoresTable.cs | 2 +- .../Rankings/Tables/TableRowBackground.cs | 2 +- .../Rankings/Tables/UserBasedTable.cs | 4 ++-- osu.Game/Overlays/RankingsOverlay.cs | 2 +- .../Overlays/RestoreDefaultValueButton.cs | 2 +- .../Settings/DangerousSettingsButton.cs | 2 +- osu.Game/Overlays/Settings/OutlinedTextBox.cs | 2 +- .../Settings/RulesetSettingsSubsection.cs | 2 +- .../Sections/Audio/AudioDevicesSettings.cs | 6 +++--- .../Settings/Sections/Audio/OffsetSettings.cs | 2 +- .../Settings/Sections/Audio/VolumeSettings.cs | 4 ++-- .../Settings/Sections/AudioSection.cs | 2 +- .../Settings/Sections/DebugSection.cs | 2 +- .../Sections/DebugSettings/GeneralSettings.cs | 2 +- .../Sections/DebugSettings/MemorySettings.cs | 2 +- .../Sections/Gameplay/AudioSettings.cs | 2 +- .../Sections/Gameplay/BackgroundSettings.cs | 2 +- .../Sections/Gameplay/BeatmapSettings.cs | 2 +- .../Sections/Gameplay/GeneralSettings.cs | 2 +- .../Settings/Sections/Gameplay/HUDSettings.cs | 2 +- .../Sections/Gameplay/InputSettings.cs | 2 +- .../Sections/Gameplay/ModsSettings.cs | 2 +- .../Settings/Sections/GameplaySection.cs | 2 +- .../Sections/General/LanguageSettings.cs | 2 +- .../Sections/General/UpdateSettings.cs | 2 +- .../Settings/Sections/GeneralSection.cs | 2 +- .../Sections/Graphics/LayoutSettings.cs | 14 ++++++------- .../Sections/Graphics/RendererSettings.cs | 2 +- .../Sections/Graphics/ScreenshotSettings.cs | 2 +- .../Sections/Graphics/VideoSettings.cs | 2 +- .../Settings/Sections/GraphicsSection.cs | 2 +- .../Sections/Input/BindingSettings.cs | 2 +- .../Input/GlobalKeyBindingsSection.cs | 14 ++++++------- .../Sections/Input/JoystickSettings.cs | 2 +- .../Sections/Input/KeyBindingPanel.cs | 2 +- .../Settings/Sections/Input/KeyBindingRow.cs | 8 ++++---- .../Sections/Input/KeyBindingsSubsection.cs | 4 ++-- .../Settings/Sections/Input/MouseSettings.cs | 6 +++--- .../Sections/Input/RotationPresetButtons.cs | 4 ++-- .../Sections/Input/RulesetBindingsSection.cs | 2 +- .../Sections/Input/TabletAreaSelection.cs | 2 +- .../Settings/Sections/Input/TabletSettings.cs | 2 +- .../Input/VariantBindingsSubsection.cs | 2 +- .../Settings/Sections/InputSection.cs | 4 ++-- .../Sections/Maintenance/BeatmapSettings.cs | 2 +- .../Maintenance/CollectionsSettings.cs | 2 +- .../Maintenance/DirectorySelectScreen.cs | 2 +- .../MassDeleteConfirmationDialog.cs | 2 +- .../MassVideoDeleteConfirmationDialog.cs | 2 +- .../Maintenance/MigrationRunScreen.cs | 2 +- .../Maintenance/MigrationSelectScreen.cs | 2 +- .../Sections/Maintenance/ModPresetSettings.cs | 2 +- .../Sections/Maintenance/ScoreSettings.cs | 2 +- .../Sections/Maintenance/SkinSettings.cs | 2 +- .../StableDirectoryLocationDialog.cs | 2 +- .../StableDirectorySelectScreen.cs | 2 +- .../Settings/Sections/MaintenanceSection.cs | 2 +- .../Online/AlertsAndPrivacySettings.cs | 2 +- .../Sections/Online/IntegrationSettings.cs | 2 +- .../Settings/Sections/Online/WebSettings.cs | 2 +- .../Settings/Sections/OnlineSection.cs | 2 +- .../Settings/Sections/RulesetSection.cs | 2 +- .../Overlays/Settings/Sections/SizeSlider.cs | 2 +- .../Overlays/Settings/Sections/SkinSection.cs | 10 +++++----- .../Sections/UserInterface/GeneralSettings.cs | 2 +- .../UserInterface/MainMenuSettings.cs | 2 +- .../UserInterface/SongSelectSettings.cs | 2 +- .../Settings/Sections/UserInterfaceSection.cs | 2 +- osu.Game/Overlays/Settings/SettingsButton.cs | 2 +- .../Overlays/Settings/SettingsCheckbox.cs | 2 +- .../Overlays/Settings/SettingsDropdown.cs | 4 ++-- .../Overlays/Settings/SettingsEnumDropdown.cs | 4 ++-- osu.Game/Overlays/Settings/SettingsFooter.cs | 4 ++-- osu.Game/Overlays/Settings/SettingsHeader.cs | 2 +- osu.Game/Overlays/Settings/SettingsItem.cs | 2 +- .../Overlays/Settings/SettingsNumberBox.cs | 6 +++--- osu.Game/Overlays/Settings/SettingsSection.cs | 2 +- osu.Game/Overlays/Settings/SettingsSidebar.cs | 2 +- osu.Game/Overlays/Settings/SettingsSlider.cs | 4 ++-- .../Overlays/Settings/SettingsSubsection.cs | 2 +- osu.Game/Overlays/Settings/SettingsTextBox.cs | 2 +- osu.Game/Overlays/Settings/SidebarButton.cs | 2 +- .../Overlays/Settings/SidebarIconButton.cs | 2 +- osu.Game/Overlays/SettingsOverlay.cs | 2 +- osu.Game/Overlays/SettingsPanel.cs | 6 +++--- osu.Game/Overlays/SettingsSubPanel.cs | 4 ++-- osu.Game/Overlays/SettingsToolboxGroup.cs | 2 +- osu.Game/Overlays/TabControlOverlayHeader.cs | 6 +++--- osu.Game/Overlays/TabbableOnlineOverlay.cs | 2 +- .../Overlays/Toolbar/AnalogClockDisplay.cs | 8 ++++---- osu.Game/Overlays/Toolbar/ClockDisplay.cs | 2 +- .../Overlays/Toolbar/DigitalClockDisplay.cs | 2 +- osu.Game/Overlays/Toolbar/Toolbar.cs | 4 ++-- .../Toolbar/ToolbarBeatmapListingButton.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 4 ++-- .../Toolbar/ToolbarChangelogButton.cs | 2 +- .../Overlays/Toolbar/ToolbarChatButton.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarClock.cs | 2 +- .../Overlays/Toolbar/ToolbarHomeButton.cs | 2 +- .../Overlays/Toolbar/ToolbarMusicButton.cs | 2 +- .../Overlays/Toolbar/ToolbarNewsButton.cs | 2 +- .../Toolbar/ToolbarNotificationButton.cs | 4 ++-- .../Toolbar/ToolbarOverlayToggleButton.cs | 2 +- .../Overlays/Toolbar/ToolbarRankingsButton.cs | 2 +- .../Toolbar/ToolbarRulesetSelector.cs | 2 +- .../Toolbar/ToolbarRulesetTabButton.cs | 4 ++-- .../Overlays/Toolbar/ToolbarSettingsButton.cs | 2 +- .../Overlays/Toolbar/ToolbarSocialButton.cs | 2 +- .../Overlays/Toolbar/ToolbarUserButton.cs | 2 +- .../Overlays/Toolbar/ToolbarWikiButton.cs | 2 +- osu.Game/Overlays/UserProfileOverlay.cs | 8 ++++---- osu.Game/Overlays/VersionManager.cs | 2 +- osu.Game/Overlays/Volume/MuteButton.cs | 2 +- .../Overlays/Volume/VolumeControlReceptor.cs | 2 +- osu.Game/Overlays/Volume/VolumeMeter.cs | 2 +- osu.Game/Overlays/VolumeOverlay.cs | 2 +- osu.Game/Overlays/WaveOverlayContainer.cs | 2 +- .../Wiki/Markdown/WikiMarkdownContainer.cs | 4 ++-- .../Wiki/Markdown/WikiMarkdownImage.cs | 2 +- .../Wiki/Markdown/WikiMarkdownImageBlock.cs | 8 ++++---- .../Wiki/Markdown/WikiNoticeContainer.cs | 4 ++-- osu.Game/Overlays/Wiki/WikiArticlePage.cs | 4 ++-- osu.Game/Overlays/Wiki/WikiHeader.cs | 4 ++-- osu.Game/Overlays/Wiki/WikiMainPage.cs | 2 +- osu.Game/Overlays/Wiki/WikiPanelContainer.cs | 6 +++--- osu.Game/Overlays/Wiki/WikiSidebar.cs | 2 +- osu.Game/Overlays/Wiki/WikiTableOfContents.cs | 4 ++-- osu.Game/Overlays/WikiOverlay.cs | 2 +- osu.Game/PerformFromMenuRunner.cs | 2 +- .../Performance/HighPerformanceSession.cs | 2 +- .../Edit/DistancedHitObjectComposer.cs | 4 ++-- .../Edit/DrawableEditorRulesetWrapper.cs | 2 +- osu.Game/Rulesets/Edit/EditorToolboxGroup.cs | 2 +- osu.Game/Rulesets/Edit/ExpandableButton.cs | 2 +- .../Edit/ExpandingToolboxContainer.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 4 ++-- .../Edit/HitObjectSelectionBlueprint.cs | 4 ++-- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 2 +- osu.Game/Rulesets/Edit/SelectionBlueprint.cs | 2 +- .../Judgements/DefaultJudgementPiece.cs | 2 +- .../Rulesets/Judgements/DrawableJudgement.cs | 2 +- .../Mods/DifficultyAdjustSettingsControl.cs | 4 ++-- osu.Game/Rulesets/Mods/MetronomeBeat.cs | 2 +- osu.Game/Rulesets/Mods/ModFlashlight.cs | 4 ++-- osu.Game/Rulesets/Mods/ModMuted.cs | 2 +- osu.Game/Rulesets/Mods/ModNightcore.cs | 4 ++-- osu.Game/Rulesets/Mods/ModNoScope.cs | 2 +- .../Objects/Drawables/DrawableHitObject.cs | 4 ++-- .../Pooling/PoolableDrawableWithLifetime.cs | 2 +- .../PooledDrawableWithLifetimeContainer.cs | 2 +- osu.Game/Rulesets/RulesetConfigCache.cs | 2 +- osu.Game/Rulesets/RulesetSelector.cs | 2 +- .../Scoring/AccumulatingHealthProcessor.cs | 2 +- .../Scoring/DrainingHealthProcessor.cs | 2 +- osu.Game/Rulesets/Scoring/HealthProcessor.cs | 2 +- .../Rulesets/Scoring/JudgementProcessor.cs | 2 +- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 +- osu.Game/Rulesets/UI/DrawableRuleset.cs | 4 ++-- .../Rulesets/UI/FrameStabilityContainer.cs | 2 +- .../Rulesets/UI/GameplayCursorContainer.cs | 2 +- .../UI/GameplaySampleTriggerSource.cs | 2 +- osu.Game/Rulesets/UI/HitObjectContainer.cs | 2 +- osu.Game/Rulesets/UI/JudgementContainer.cs | 2 +- osu.Game/Rulesets/UI/ModIcon.cs | 2 +- osu.Game/Rulesets/UI/ModSwitchSmall.cs | 2 +- osu.Game/Rulesets/UI/ModSwitchTiny.cs | 2 +- osu.Game/Rulesets/UI/Playfield.cs | 4 ++-- .../UI/PlayfieldAdjustmentContainer.cs | 2 +- osu.Game/Rulesets/UI/PlayfieldBorder.cs | 4 ++-- osu.Game/Rulesets/UI/ReplayRecorder.cs | 4 ++-- osu.Game/Rulesets/UI/RulesetInputManager.cs | 8 ++++---- .../UI/Scrolling/DrawableScrollingRuleset.cs | 2 +- .../Scrolling/ScrollingHitObjectContainer.cs | 2 +- .../UI/Scrolling/ScrollingPlayfield.cs | 2 +- ...UnprocessedPerformancePointsPlaceholder.cs | 2 +- osu.Game/Scoring/ScorePerformanceCache.cs | 2 +- osu.Game/Screens/BackgroundScreen.cs | 2 +- osu.Game/Screens/BackgroundScreenStack.cs | 2 +- .../Backgrounds/BackgroundScreenBeatmap.cs | 4 ++-- .../Backgrounds/BackgroundScreenBlack.cs | 2 +- .../Backgrounds/BackgroundScreenCustom.cs | 2 +- .../Backgrounds/BackgroundScreenDefault.cs | 2 +- osu.Game/Screens/Edit/BottomBar.cs | 2 +- .../Edit/Components/BottomBarContainer.cs | 2 +- .../Screens/Edit/Components/EditorSidebar.cs | 2 +- .../Edit/Components/EditorSidebarSection.cs | 4 ++-- .../Edit/Components/Menus/EditorMenuBar.cs | 14 ++++++------- .../Menus/EditorScreenSwitcherControl.cs | 4 ++-- .../Edit/Components/PlaybackControl.cs | 6 +++--- .../RadioButtons/EditorRadioButton.cs | 2 +- .../EditorRadioButtonCollection.cs | 2 +- .../TernaryButtons/DrawableTernaryButton.cs | 2 +- .../Edit/Components/TimeInfoContainer.cs | 2 +- .../Timelines/Summary/Parts/BookmarkPart.cs | 4 ++-- .../Timelines/Summary/Parts/BreakPart.cs | 4 ++-- .../Summary/Parts/ControlPointPart.cs | 2 +- .../Parts/ControlPointVisualisation.cs | 2 +- .../Summary/Parts/EffectPointVisualisation.cs | 2 +- .../Summary/Parts/GroupVisualisation.cs | 2 +- .../Timelines/Summary/Parts/MarkerPart.cs | 4 ++-- .../Timelines/Summary/Parts/TimelinePart.cs | 4 ++-- .../Timelines/Summary/SummaryTimeline.cs | 2 +- .../Timelines/Summary/TestGameplayButton.cs | 2 +- .../Visualisations/DurationVisualisation.cs | 2 +- .../Visualisations/PointVisualisation.cs | 2 +- .../Compose/Components/BeatDivisorControl.cs | 16 +++++++-------- .../Compose/Components/BlueprintContainer.cs | 2 +- .../Components/CircularDistanceSnapGrid.cs | 4 ++-- .../Components/ComposeBlueprintContainer.cs | 2 +- .../Compose/Components/DistanceSnapGrid.cs | 2 +- .../Edit/Compose/Components/DragBox.cs | 4 ++-- .../Components/EditorBlueprintContainer.cs | 2 +- .../Components/EditorSelectionHandler.cs | 2 +- .../HitObjectOrderedSelectionContainer.cs | 2 +- .../Components/RectangularPositionSnapGrid.cs | 2 +- .../Compose/Components/ScrollingDragBox.cs | 2 +- .../Edit/Compose/Components/SelectionBox.cs | 2 +- .../Compose/Components/SelectionBoxButton.cs | 2 +- .../Compose/Components/SelectionBoxControl.cs | 2 +- .../Components/SelectionBoxDragHandle.cs | 2 +- .../SelectionBoxDragHandleContainer.cs | 2 +- .../Components/SelectionBoxRotationHandle.cs | 2 +- .../Components/SelectionBoxScaleHandle.cs | 2 +- .../Compose/Components/SelectionHandler.cs | 2 +- .../Components/Timeline/CentreMarker.cs | 2 +- .../Timeline/DifficultyPointPiece.cs | 4 ++-- .../Timeline/HitObjectPointPiece.cs | 2 +- .../Components/Timeline/SamplePointPiece.cs | 4 ++-- .../Compose/Components/Timeline/Timeline.cs | 2 +- .../Components/Timeline/TimelineArea.cs | 2 +- .../Timeline/TimelineBlueprintContainer.cs | 6 +++--- .../Components/Timeline/TimelineButton.cs | 2 +- .../Timeline/TimelineControlPointDisplay.cs | 2 +- .../Timeline/TimelineControlPointGroup.cs | 2 +- .../Components/Timeline/TimelineDragBox.cs | 2 +- .../Timeline/TimelineHitObjectBlueprint.cs | 10 +++++----- .../Timeline/TimelineSelectionHandler.cs | 2 +- .../Timeline/TimelineTickDisplay.cs | 2 +- .../Components/Timeline/TimingPointPiece.cs | 2 +- .../Components/Timeline/TopPointPiece.cs | 2 +- .../Timeline/ZoomableScrollContainer.cs | 2 +- .../Screens/Edit/Compose/ComposeScreen.cs | 2 +- .../Screens/Edit/CreateNewDifficultyDialog.cs | 2 +- .../DeleteDifficultyConfirmationDialog.cs | 2 +- osu.Game/Screens/Edit/Design/DesignScreen.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 4 ++-- osu.Game/Screens/Edit/EditorBeatmap.cs | 2 +- osu.Game/Screens/Edit/EditorChangeHandler.cs | 2 +- osu.Game/Screens/Edit/EditorClock.cs | 2 +- osu.Game/Screens/Edit/EditorLoader.cs | 2 +- .../Edit/EditorRoundedScreenSettings.cs | 2 +- .../EditorRoundedScreenSettingsSection.cs | 2 +- osu.Game/Screens/Edit/EditorScreen.cs | 2 +- .../Screens/Edit/EditorScreenWithTimeline.cs | 2 +- .../Edit/EditorSkinProvidingContainer.cs | 2 +- osu.Game/Screens/Edit/EditorTable.cs | 6 +++--- .../Screens/Edit/GameplayTest/EditorPlayer.cs | 2 +- .../Edit/GameplayTest/EditorPlayerLoader.cs | 2 +- .../SaveBeforeGameplayTestDialog.cs | 2 +- osu.Game/Screens/Edit/PromptForSaveDialog.cs | 2 +- osu.Game/Screens/Edit/Setup/ColoursSection.cs | 2 +- osu.Game/Screens/Edit/Setup/DesignSection.cs | 2 +- .../Screens/Edit/Setup/DifficultySection.cs | 2 +- .../Screens/Edit/Setup/LabelledFileChooser.cs | 4 ++-- .../Edit/Setup/LabelledRomanisedTextBox.cs | 4 ++-- .../Edit/Setup/LabelledTextBoxWithPopover.cs | 4 ++-- .../Screens/Edit/Setup/MetadataSection.cs | 2 +- .../Screens/Edit/Setup/ResourcesSection.cs | 2 +- .../Screens/Edit/Setup/RulesetSetupSection.cs | 2 +- osu.Game/Screens/Edit/Setup/SetupScreen.cs | 4 ++-- .../Screens/Edit/Setup/SetupScreenHeader.cs | 8 ++++---- .../Edit/Setup/SetupScreenHeaderBackground.cs | 2 +- osu.Game/Screens/Edit/Setup/SetupSection.cs | 2 +- .../Edit/Timing/ControlPointSettings.cs | 2 +- .../Screens/Edit/Timing/ControlPointTable.cs | 4 ++-- osu.Game/Screens/Edit/Timing/EffectSection.cs | 2 +- osu.Game/Screens/Edit/Timing/GroupSection.cs | 2 +- .../IndeterminateSliderWithTextBoxInput.cs | 2 +- .../Edit/Timing/LabelledTimeSignature.cs | 4 ++-- .../Screens/Edit/Timing/MetronomeDisplay.cs | 2 +- .../Edit/Timing/RepeatingButtonBehaviour.cs | 2 +- osu.Game/Screens/Edit/Timing/RowAttribute.cs | 2 +- .../RowAttributes/AttributeProgressBar.cs | 2 +- .../Timing/RowAttributes/AttributeText.cs | 2 +- .../RowAttributes/DifficultyRowAttribute.cs | 2 +- .../RowAttributes/EffectRowAttribute.cs | 2 +- .../RowAttributes/SampleRowAttribute.cs | 2 +- .../RowAttributes/TimingRowAttribute.cs | 2 +- osu.Game/Screens/Edit/Timing/Section.cs | 2 +- .../Edit/Timing/SliderWithTextBoxInput.cs | 2 +- osu.Game/Screens/Edit/Timing/TapButton.cs | 4 ++-- .../Screens/Edit/Timing/TapTimingControl.cs | 4 ++-- .../Screens/Edit/Timing/TimingAdjustButton.cs | 4 ++-- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 4 ++-- osu.Game/Screens/Edit/Timing/TimingSection.cs | 4 ++-- .../Edit/Timing/WaveformComparisonDisplay.cs | 6 +++--- .../Edit/TransactionalCommitComponent.cs | 2 +- .../Edit/Verify/InterpretationSection.cs | 2 +- osu.Game/Screens/Edit/Verify/IssueList.cs | 2 +- osu.Game/Screens/Edit/Verify/IssueSettings.cs | 2 +- osu.Game/Screens/Edit/Verify/IssueTable.cs | 2 +- osu.Game/Screens/Edit/Verify/VerifyScreen.cs | 2 +- .../Screens/Edit/Verify/VisibilitySection.cs | 2 +- osu.Game/Screens/Import/FileImportScreen.cs | 2 +- osu.Game/Screens/Loader.cs | 4 ++-- osu.Game/Screens/Menu/ButtonArea.cs | 4 ++-- osu.Game/Screens/Menu/ButtonSystem.cs | 2 +- .../Menu/ConfirmDiscardChangesDialog.cs | 2 +- osu.Game/Screens/Menu/ConfirmExitDialog.cs | 2 +- osu.Game/Screens/Menu/Disclaimer.cs | 2 +- osu.Game/Screens/Menu/ExitConfirmOverlay.cs | 2 +- .../Screens/Menu/FlowContainerWithOrigin.cs | 2 +- osu.Game/Screens/Menu/IntroCircles.cs | 2 +- osu.Game/Screens/Menu/IntroScreen.cs | 2 +- osu.Game/Screens/Menu/IntroSequence.cs | 4 ++-- osu.Game/Screens/Menu/IntroTriangles.cs | 14 ++++++------- osu.Game/Screens/Menu/IntroWelcome.cs | 4 ++-- osu.Game/Screens/Menu/LogoVisualisation.cs | 2 +- osu.Game/Screens/Menu/MainMenu.cs | 2 +- osu.Game/Screens/Menu/MainMenuButton.cs | 2 +- .../Screens/Menu/MenuLogoVisualisation.cs | 2 +- osu.Game/Screens/Menu/MenuSideFlashes.cs | 2 +- osu.Game/Screens/Menu/OsuLogo.cs | 2 +- osu.Game/Screens/Menu/SongTicker.cs | 2 +- osu.Game/Screens/Menu/StorageErrorDialog.cs | 2 +- .../OnlinePlay/Components/BeatmapTitle.cs | 2 +- .../Components/DisableableTabControl.cs | 4 ++-- .../OnlinePlay/Components/DrawableGameType.cs | 4 ++-- .../Components/ListingPollingComponent.cs | 2 +- .../Components/MatchBeatmapDetailArea.cs | 2 +- .../Components/OnlinePlayBackgroundScreen.cs | 2 +- .../Components/OnlinePlayBackgroundSprite.cs | 2 +- .../OnlinePlay/Components/OverlinedHeader.cs | 2 +- .../Components/OverlinedPlaylistHeader.cs | 2 +- .../Components/ParticipantCountDisplay.cs | 2 +- .../Components/ParticipantsDisplay.cs | 2 +- .../OnlinePlay/Components/ParticipantsList.cs | 4 ++-- .../Components/PlaylistItemBackground.cs | 2 +- .../OnlinePlay/Components/ReadyButton.cs | 2 +- .../Components/RoomLocalUserInfo.cs | 2 +- .../OnlinePlay/Components/RoomManager.cs | 2 +- .../Components/RoomPollingComponent.cs | 2 +- .../Components/SelectionPollingComponent.cs | 2 +- .../Components/StarRatingRangeDisplay.cs | 2 +- .../Components/StatusColouredContainer.cs | 2 +- .../OnlinePlay/DrawableRoomPlaylist.cs | 2 +- .../OnlinePlay/DrawableRoomPlaylistItem.cs | 14 ++++++------- .../OnlinePlay/FooterButtonFreeMods.cs | 2 +- .../OnlinePlay/FreeModSelectOverlay.cs | 2 +- osu.Game/Screens/OnlinePlay/Header.cs | 4 ++-- .../Lounge/Components/DrawableRoom.cs | 8 ++++---- .../DrawableRoomParticipantsList.cs | 6 +++--- .../Lounge/Components/EndDateInfo.cs | 4 ++-- .../Lounge/Components/MatchTypePill.cs | 2 +- .../Lounge/Components/PillContainer.cs | 2 +- .../Lounge/Components/PlaylistCountPill.cs | 2 +- .../Lounge/Components/QueueModePill.cs | 2 +- .../Lounge/Components/RankRangePill.cs | 2 +- .../Components/RoomSpecialCategoryPill.cs | 2 +- .../Lounge/Components/RoomStatusPill.cs | 2 +- .../Lounge/Components/RoomsContainer.cs | 2 +- .../OnlinePlay/Lounge/DrawableLoungeRoom.cs | 4 ++-- .../Lounge/LoungeBackgroundScreen.cs | 2 +- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 2 +- .../Match/Components/CreateRoomButton.cs | 2 +- .../Match/Components/MatchChatDisplay.cs | 2 +- .../Match/Components/MatchLeaderboard.cs | 2 +- .../Match/Components/MatchLeaderboardScore.cs | 2 +- .../Match/Components/MatchTypePicker.cs | 4 ++-- .../Match/Components/PurpleTriangleButton.cs | 2 +- .../Components/RoomAvailabilityPicker.cs | 4 ++-- .../Match/Components/RoomSettingsOverlay.cs | 6 +++--- .../OnlinePlay/Match/DrawableMatchRoom.cs | 4 ++-- .../OnlinePlay/Match/RoomBackgroundScreen.cs | 2 +- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 4 ++-- .../CreateMultiplayerMatchButton.cs | 2 +- .../Multiplayer/GameplayChatDisplay.cs | 2 +- .../Multiplayer/GameplayMatchScoreDisplay.cs | 2 +- .../Multiplayer/Match/MatchStartControl.cs | 2 +- .../Match/MultiplayerCountdownButton.cs | 2 +- .../Match/MultiplayerMatchFooter.cs | 2 +- .../Match/MultiplayerMatchSettingsOverlay.cs | 6 +++--- .../Match/MultiplayerReadyButton.cs | 2 +- .../Match/MultiplayerSpectateButton.cs | 4 ++-- .../Match/Playlist/MultiplayerHistoryList.cs | 4 ++-- .../Match/Playlist/MultiplayerPlaylist.cs | 2 +- .../Playlist/MultiplayerPlaylistTabControl.cs | 4 ++-- .../Match/Playlist/MultiplayerQueueList.cs | 6 +++--- .../OnlinePlay/Multiplayer/Multiplayer.cs | 2 +- .../Multiplayer/MultiplayerLoungeSubScreen.cs | 4 ++-- .../Multiplayer/MultiplayerMatchSongSelect.cs | 2 +- .../Multiplayer/MultiplayerMatchSubScreen.cs | 4 ++-- .../Multiplayer/MultiplayerPlayer.cs | 2 +- .../Multiplayer/MultiplayerPlayerLoader.cs | 2 +- .../Multiplayer/MultiplayerResultsScreen.cs | 2 +- .../Multiplayer/MultiplayerRoomComposite.cs | 2 +- .../Multiplayer/MultiplayerRoomManager.cs | 2 +- .../Multiplayer/MultiplayerRoomSounds.cs | 2 +- .../MultiplayerTeamResultsScreen.cs | 2 +- .../Participants/ParticipantPanel.cs | 4 ++-- .../Participants/ParticipantsList.cs | 2 +- .../Participants/ParticipantsListHeader.cs | 2 +- .../Multiplayer/Participants/StateDisplay.cs | 2 +- .../Multiplayer/Participants/TeamDisplay.cs | 2 +- .../Spectate/MultiSpectatorLeaderboard.cs | 2 +- .../Spectate/MultiSpectatorPlayer.cs | 2 +- .../Spectate/MultiSpectatorPlayerLoader.cs | 2 +- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../Multiplayer/Spectate/PlayerArea.cs | 4 ++-- .../Multiplayer/Spectate/PlayerGrid_Cell.cs | 2 +- .../Multiplayer/Spectate/PlayerGrid_Facade.cs | 2 +- .../Spectate/SpectatorSyncManager.cs | 2 +- .../OnlinePlay/OngoingOperationTracker.cs | 2 +- .../Screens/OnlinePlay/OnlinePlayComposite.cs | 2 +- .../Screens/OnlinePlay/OnlinePlayScreen.cs | 4 ++-- .../OnlinePlay/OnlinePlaySongSelect.cs | 2 +- .../Screens/OnlinePlay/OnlinePlaySubScreen.cs | 2 +- .../OnlinePlay/OnlinePlaySubScreenStack.cs | 2 +- .../Playlists/CreatePlaylistsRoomButton.cs | 2 +- .../Screens/OnlinePlay/Playlists/Playlists.cs | 2 +- .../Playlists/PlaylistsLoungeSubScreen.cs | 2 +- .../OnlinePlay/Playlists/PlaylistsPlayer.cs | 2 +- .../Playlists/PlaylistsReadyButton.cs | 2 +- .../Playlists/PlaylistsResultsScreen.cs | 4 ++-- .../Playlists/PlaylistsRoomFooter.cs | 2 +- .../Playlists/PlaylistsRoomSettingsOverlay.cs | 8 ++++---- .../PlaylistsRoomSettingsPlaylist.cs | 2 +- .../Playlists/PlaylistsRoomSubScreen.cs | 2 +- .../Playlists/PlaylistsSongSelect.cs | 2 +- osu.Game/Screens/OsuScreen.cs | 2 +- osu.Game/Screens/OsuScreenStack.cs | 2 +- .../Screens/Play/BeatmapMetadataDisplay.cs | 6 +++--- osu.Game/Screens/Play/Break/BlurredIcon.cs | 2 +- osu.Game/Screens/Play/Break/BreakArrows.cs | 2 +- osu.Game/Screens/Play/Break/BreakInfo.cs | 2 +- osu.Game/Screens/Play/Break/BreakInfoLine.cs | 4 ++-- osu.Game/Screens/Play/Break/GlowIcon.cs | 2 +- .../Screens/Play/Break/LetterboxOverlay.cs | 2 +- .../Play/Break/RemainingTimeCounter.cs | 2 +- osu.Game/Screens/Play/BreakOverlay.cs | 2 +- osu.Game/Screens/Play/BreakTracker.cs | 2 +- osu.Game/Screens/Play/ComboEffects.cs | 2 +- osu.Game/Screens/Play/DimmableStoryboard.cs | 2 +- osu.Game/Screens/Play/EpilepsyWarning.cs | 2 +- osu.Game/Screens/Play/FailAnimation.cs | 2 +- osu.Game/Screens/Play/FailOverlay.cs | 2 +- .../Screens/Play/GameplayClockContainer.cs | 2 +- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 4 ++-- .../ClicksPerSecondCalculator.cs | 2 +- .../ClicksPerSecond/ClicksPerSecondCounter.cs | 4 ++-- osu.Game/Screens/Play/HUD/ComboCounter.cs | 2 +- .../Play/HUD/DefaultAccuracyCounter.cs | 2 +- .../Screens/Play/HUD/DefaultComboCounter.cs | 2 +- .../Screens/Play/HUD/DefaultHealthDisplay.cs | 2 +- .../Screens/Play/HUD/DefaultScoreCounter.cs | 2 +- .../Screens/Play/HUD/DefaultSongProgress.cs | 2 +- osu.Game/Screens/Play/HUD/FailingLayer.cs | 2 +- .../Play/HUD/GameplayAccuracyCounter.cs | 2 +- .../Screens/Play/HUD/GameplayLeaderboard.cs | 4 ++-- .../Play/HUD/GameplayLeaderboardScore.cs | 2 +- .../Screens/Play/HUD/GameplayScoreCounter.cs | 2 +- osu.Game/Screens/Play/HUD/HealthDisplay.cs | 2 +- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 4 ++-- .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 6 +++--- .../Play/HUD/HitErrorMeters/HitErrorMeter.cs | 2 +- .../Screens/Play/HUD/HoldForMenuButton.cs | 4 ++-- .../Screens/Play/HUD/LongestComboCounter.cs | 4 ++-- .../Screens/Play/HUD/MatchScoreDisplay.cs | 4 ++-- osu.Game/Screens/Play/HUD/ModDisplay.cs | 2 +- osu.Game/Screens/Play/HUD/ModFlowDisplay.cs | 2 +- .../HUD/MultiplayerGameplayLeaderboard.cs | 2 +- .../Play/HUD/PerformancePointsCounter.cs | 4 ++-- .../Screens/Play/HUD/PlayerSettingsOverlay.cs | 2 +- .../Play/HUD/SoloGameplayLeaderboard.cs | 2 +- osu.Game/Screens/Play/HUD/SongProgress.cs | 2 +- osu.Game/Screens/Play/HUD/SongProgressBar.cs | 2 +- .../Screens/Play/HUD/SongProgressGraph.cs | 2 +- osu.Game/Screens/Play/HUD/SongProgressInfo.cs | 2 +- .../Screens/Play/HUD/UnstableRateCounter.cs | 4 ++-- osu.Game/Screens/Play/HUDOverlay.cs | 4 ++-- osu.Game/Screens/Play/HotkeyExitOverlay.cs | 2 +- osu.Game/Screens/Play/HotkeyRetryOverlay.cs | 2 +- osu.Game/Screens/Play/KeyCounter.cs | 2 +- osu.Game/Screens/Play/KeyCounterAction.cs | 2 +- osu.Game/Screens/Play/KeyCounterDisplay.cs | 4 ++-- osu.Game/Screens/Play/KeyCounterKeyboard.cs | 2 +- osu.Game/Screens/Play/KeyCounterMouse.cs | 2 +- .../Play/MasterGameplayClockContainer.cs | 2 +- osu.Game/Screens/Play/PauseOverlay.cs | 2 +- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Play/PlayerLoader.cs | 6 +++--- .../Play/PlayerSettings/AudioSettings.cs | 2 +- .../PlayerSettings/BeatmapOffsetControl.cs | 6 +++--- .../Play/PlayerSettings/DiscussionSettings.cs | 2 +- .../Play/PlayerSettings/InputSettings.cs | 2 +- .../Play/PlayerSettings/PlaybackSettings.cs | 2 +- .../Play/PlayerSettings/PlayerCheckbox.cs | 4 ++-- .../PlayerSettings/PlayerSettingsGroup.cs | 2 +- .../Play/PlayerSettings/PlayerSliderBar.cs | 4 ++-- .../Play/PlayerSettings/VisualSettings.cs | 2 +- osu.Game/Screens/Play/ReplayPlayer.cs | 2 +- osu.Game/Screens/Play/ReplayPlayerLoader.cs | 2 +- osu.Game/Screens/Play/ResumeOverlay.cs | 2 +- osu.Game/Screens/Play/RoomSubmittingPlayer.cs | 2 +- .../Screens/Play/SaveFailedScoreButton.cs | 2 +- .../Screens/Play/ScreenSuspensionHandler.cs | 2 +- .../Play/ScreenWithBeatmapBackground.cs | 2 +- osu.Game/Screens/Play/SkipOverlay.cs | 8 ++++---- osu.Game/Screens/Play/SoloPlayer.cs | 2 +- osu.Game/Screens/Play/SoloSpectator.cs | 2 +- osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 2 +- osu.Game/Screens/Play/SpectatorPlayer.cs | 2 +- .../Screens/Play/SpectatorPlayerLoader.cs | 2 +- .../Screens/Play/SpectatorResultsScreen.cs | 2 +- osu.Game/Screens/Play/SquareGraph.cs | 4 ++-- osu.Game/Screens/Play/SubmittingPlayer.cs | 2 +- osu.Game/Screens/Ranking/AspectContainer.cs | 2 +- .../ContractedPanelMiddleContent.cs | 2 +- .../Contracted/ContractedPanelTopContent.cs | 2 +- .../Expanded/Accuracy/AccuracyCircle.cs | 2 +- .../Ranking/Expanded/Accuracy/RankBadge.cs | 2 +- .../Ranking/Expanded/Accuracy/RankNotch.cs | 2 +- .../Ranking/Expanded/Accuracy/RankText.cs | 2 +- .../Accuracy/SmoothCircularProgress.cs | 2 +- .../Expanded/ExpandedPanelMiddleContent.cs | 4 ++-- .../Expanded/ExpandedPanelTopContent.cs | 2 +- .../Expanded/Statistics/AccuracyStatistic.cs | 4 ++-- .../Expanded/Statistics/ComboStatistic.cs | 2 +- .../Expanded/Statistics/CounterStatistic.cs | 2 +- .../Expanded/Statistics/HitResultStatistic.cs | 2 +- .../Statistics/PerformanceStatistic.cs | 2 +- .../Expanded/Statistics/StatisticCounter.cs | 2 +- .../Expanded/Statistics/StatisticDisplay.cs | 2 +- .../Ranking/Expanded/TotalScoreCounter.cs | 2 +- .../Screens/Ranking/ReplayDownloadButton.cs | 2 +- osu.Game/Screens/Ranking/ResultsScreen.cs | 4 ++-- osu.Game/Screens/Ranking/RetryButton.cs | 2 +- osu.Game/Screens/Ranking/ScorePanel.cs | 2 +- osu.Game/Screens/Ranking/ScorePanelList.cs | 6 +++--- .../Ranking/ScorePanelTrackingContainer.cs | 2 +- osu.Game/Screens/Ranking/SoloResultsScreen.cs | 2 +- .../Ranking/Statistics/AverageHitError.cs | 2 +- .../HitEventTimingDistributionGraph.cs | 4 ++-- .../Statistics/PerformanceBreakdownChart.cs | 2 +- .../Ranking/Statistics/SimpleStatisticItem.cs | 4 ++-- .../Statistics/SimpleStatisticTable.cs | 4 ++-- .../Ranking/Statistics/StatisticContainer.cs | 2 +- .../Ranking/Statistics/StatisticsPanel.cs | 2 +- .../Ranking/Statistics/UnstableRate.cs | 2 +- osu.Game/Screens/ScreenWhiteBox.cs | 6 +++--- osu.Game/Screens/Select/BeatmapCarousel.cs | 4 ++-- .../Select/BeatmapClearScoresDialog.cs | 2 +- .../Screens/Select/BeatmapDeleteDialog.cs | 2 +- osu.Game/Screens/Select/BeatmapDetailArea.cs | 2 +- .../Select/BeatmapDetailAreaTabControl.cs | 2 +- osu.Game/Screens/Select/BeatmapDetails.cs | 4 ++-- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 6 +++--- .../Select/BeatmapInfoWedgeBackground.cs | 2 +- .../Screens/Select/Carousel/CarouselHeader.cs | 4 ++-- .../Carousel/DrawableCarouselBeatmap.cs | 2 +- .../Carousel/DrawableCarouselBeatmapSet.cs | 2 +- .../Select/Carousel/DrawableCarouselItem.cs | 2 +- .../Carousel/FilterableDifficultyIcon.cs | 2 +- .../Select/Carousel/GroupedDifficultyIcon.cs | 2 +- .../Select/Carousel/SetPanelBackground.cs | 2 +- .../Select/Carousel/SetPanelContent.cs | 2 +- .../Screens/Select/Carousel/TopLocalRank.cs | 2 +- .../Select/Carousel/UpdateBeatmapSetButton.cs | 2 +- .../Carousel/UpdateLocalConfirmationDialog.cs | 2 +- .../Screens/Select/Details/AdvancedStats.cs | 4 ++-- .../Screens/Select/Details/FailRetryGraph.cs | 2 +- .../Screens/Select/Details/UserRatings.cs | 2 +- .../Select/DifficultyRangeFilterControl.cs | 8 ++++---- osu.Game/Screens/Select/FilterControl.cs | 2 +- osu.Game/Screens/Select/Footer.cs | 2 +- osu.Game/Screens/Select/FooterButton.cs | 2 +- osu.Game/Screens/Select/FooterButtonMods.cs | 2 +- .../Screens/Select/FooterButtonOptions.cs | 2 +- osu.Game/Screens/Select/FooterButtonRandom.cs | 2 +- .../Select/Leaderboards/BeatmapLeaderboard.cs | 2 +- .../Screens/Select/LocalScoreDeleteDialog.cs | 2 +- .../Screens/Select/NoResultsPlaceholder.cs | 2 +- .../Select/Options/BeatmapOptionsButton.cs | 2 +- .../Select/Options/BeatmapOptionsOverlay.cs | 2 +- .../Screens/Select/PlayBeatmapDetailArea.cs | 2 +- osu.Game/Screens/Select/PlaySongSelect.cs | 2 +- osu.Game/Screens/Select/SkinDeleteDialog.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 8 ++++---- osu.Game/Screens/Select/WedgeBackground.cs | 2 +- osu.Game/Screens/Spectate/SpectatorScreen.cs | 2 +- osu.Game/Screens/StartupScreen.cs | 2 +- osu.Game/Screens/Utility/ButtonWithKeyBind.cs | 2 +- osu.Game/Screens/Utility/CircleGameplay.cs | 4 ++-- osu.Game/Screens/Utility/LatencyArea.cs | 2 +- .../Screens/Utility/LatencyCertifierScreen.cs | 2 +- .../LatencyCursorContainer.cs | 4 ++-- .../SampleComponents/LatencyMovableBox.cs | 2 +- .../LatencySampleComponent.cs | 2 +- osu.Game/Screens/Utility/ScrollingGameplay.cs | 4 ++-- .../Skinning/BeatmapSkinProvidingContainer.cs | 2 +- osu.Game/Skinning/Components/BigBlackBox.cs | 2 +- osu.Game/Skinning/Editor/SkinBlueprint.cs | 4 ++-- .../Skinning/Editor/SkinBlueprintContainer.cs | 2 +- .../Skinning/Editor/SkinComponentToolbox.cs | 6 +++--- osu.Game/Skinning/Editor/SkinEditor.cs | 4 ++-- osu.Game/Skinning/Editor/SkinEditorOverlay.cs | 2 +- .../Skinning/Editor/SkinEditorSceneLibrary.cs | 4 ++-- .../Skinning/Editor/SkinSelectionHandler.cs | 2 +- .../Skinning/Editor/SkinSettingsToolbox.cs | 2 +- osu.Game/Skinning/LegacyAccuracyCounter.cs | 2 +- osu.Game/Skinning/LegacyComboCounter.cs | 2 +- osu.Game/Skinning/LegacyHealthDisplay.cs | 16 +++++++-------- osu.Game/Skinning/LegacyJudgementPieceNew.cs | 2 +- osu.Game/Skinning/LegacyJudgementPieceOld.cs | 2 +- .../Skinning/LegacyKiaiFlashingDrawable.cs | 2 +- osu.Game/Skinning/LegacyRollingCounter.cs | 2 +- osu.Game/Skinning/LegacyScoreCounter.cs | 2 +- osu.Game/Skinning/LegacySkinExtensions.cs | 4 ++-- osu.Game/Skinning/LegacySongProgress.cs | 2 +- osu.Game/Skinning/LegacySpriteText.cs | 2 +- osu.Game/Skinning/PausableSkinnableSound.cs | 2 +- osu.Game/Skinning/PoolableSkinnableSample.cs | 2 +- .../Skinning/RulesetSkinProvidingContainer.cs | 2 +- osu.Game/Skinning/SkinProvidingContainer.cs | 2 +- osu.Game/Skinning/SkinReloadableDrawable.cs | 2 +- osu.Game/Skinning/SkinnableDrawable.cs | 2 +- osu.Game/Skinning/SkinnableSound.cs | 2 +- osu.Game/Skinning/SkinnableSprite.cs | 6 +++--- osu.Game/Skinning/SkinnableSpriteText.cs | 2 +- .../SkinnableTargetComponentsContainer.cs | 2 +- osu.Game/Skinning/SkinnableTargetContainer.cs | 2 +- .../Drawables/DrawableStoryboard.cs | 2 +- .../Drawables/DrawableStoryboardAnimation.cs | 2 +- .../Drawables/DrawableStoryboardLayer.cs | 4 ++-- .../Drawables/DrawableStoryboardSample.cs | 2 +- .../Drawables/DrawableStoryboardSprite.cs | 2 +- .../Drawables/DrawableStoryboardVideo.cs | 2 +- osu.Game/Storyboards/StoryboardVideoLayer.cs | 4 ++-- .../Tests/Beatmaps/HitObjectSampleTest.cs | 2 +- .../Beatmaps/LegacyBeatmapSkinColourTest.cs | 4 ++-- osu.Game/Tests/OsuTestBrowser.cs | 2 +- .../Visual/DependencyProvidingContainer.cs | 2 +- osu.Game/Tests/Visual/EditorClockTestScene.cs | 2 +- .../Tests/Visual/EditorSavingTestScene.cs | 2 +- osu.Game/Tests/Visual/EditorTestScene.cs | 6 +++--- .../Tests/Visual/LegacySkinPlayerTestScene.cs | 4 ++-- osu.Game/Tests/Visual/ModPerfectTestScene.cs | 4 ++-- osu.Game/Tests/Visual/ModTestScene.cs | 4 ++-- .../Multiplayer/MultiplayerTestScene.cs | 2 +- .../Multiplayer/TestMultiplayerClient.cs | 2 +- .../Multiplayer/TestMultiplayerRoomManager.cs | 2 +- .../Visual/OnlinePlay/OnlinePlayTestScene.cs | 2 +- .../Visual/OnlinePlay/TestRoomManager.cs | 2 +- osu.Game/Tests/Visual/OsuGameTestScene.cs | 8 ++++---- osu.Game/Tests/Visual/OsuGridTestScene.cs | 2 +- .../Visual/OsuManualInputManagerTestScene.cs | 2 +- osu.Game/Tests/Visual/OsuTestScene.cs | 4 ++-- .../Visual/PlacementBlueprintTestScene.cs | 2 +- osu.Game/Tests/Visual/PlayerTestScene.cs | 2 +- .../Visual/RateAdjustedBeatmapTestScene.cs | 2 +- osu.Game/Tests/Visual/ScreenTestScene.cs | 2 +- .../Tests/Visual/ScrollingTestContainer.cs | 2 +- .../Visual/SelectionBlueprintTestScene.cs | 2 +- osu.Game/Tests/Visual/SkinnableTestScene.cs | 4 ++-- .../Visual/Spectator/TestSpectatorClient.cs | 2 +- osu.Game/Tests/Visual/TestPlayer.cs | 2 +- osu.Game/Tests/Visual/TestReplayPlayer.cs | 2 +- osu.Game/Tests/Visual/TestUserLookupCache.cs | 2 +- osu.Game/Updater/NoActionUpdateManager.cs | 2 +- osu.Game/Updater/SimpleUpdateManager.cs | 2 +- osu.Game/Updater/UpdateManager.cs | 8 ++++---- osu.Game/Users/Drawables/ClickableAvatar.cs | 4 ++-- osu.Game/Users/Drawables/DrawableAvatar.cs | 2 +- osu.Game/Users/Drawables/DrawableFlag.cs | 2 +- osu.Game/Users/Drawables/UpdateableAvatar.cs | 2 +- osu.Game/Users/Drawables/UpdateableFlag.cs | 2 +- osu.Game/Users/ExtendedUserPanel.cs | 2 +- osu.Game/Users/UserBrickPanel.cs | 2 +- osu.Game/Users/UserCoverBackground.cs | 4 ++-- osu.Game/Users/UserGridPanel.cs | 2 +- osu.Game/Users/UserListPanel.cs | 2 +- osu.Game/Users/UserPanel.cs | 2 +- 2331 files changed, 3218 insertions(+), 3218 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs index 5973db908c..ca73074789 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs @@ -9,7 +9,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.EmptyFreeform.Tests { - public class TestSceneOsuGame : OsuTestScene + public partial class TestSceneOsuGame : OsuTestScene { [BackgroundDependencyLoader] private void load() diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuPlayer.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuPlayer.cs index 0f2ddf82a5..4b99fa7e09 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuPlayer.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuPlayer.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.EmptyFreeform.Tests { [TestFixture] - public class TestSceneOsuPlayer : PlayerTestScene + public partial class TestSceneOsuPlayer : PlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new EmptyFreeformRuleset(); } diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformInputManager.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformInputManager.cs index b292a28c0d..feac0f22f5 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformInputManager.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformInputManager.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.EmptyFreeform { - public class EmptyFreeformInputManager : RulesetInputManager + public partial class EmptyFreeformInputManager : RulesetInputManager { public EmptyFreeformInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs index 1e88f87f09..d7ef84541f 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/EmptyFreeformRuleset.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.EmptyFreeform { - public class EmptyFreeformRuleset : Ruleset + public partial class EmptyFreeformRuleset : Ruleset { public override string Description => "a very emptyfreeformruleset ruleset"; @@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.EmptyFreeform public override Drawable CreateIcon() => new Icon(ShortName[0]); - public class Icon : CompositeDrawable + public partial class Icon : CompositeDrawable { public Icon(char c) { diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/Drawables/DrawableEmptyFreeformHitObject.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/Drawables/DrawableEmptyFreeformHitObject.cs index 0f38e9fdf8..744e207b57 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/Drawables/DrawableEmptyFreeformHitObject.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/Objects/Drawables/DrawableEmptyFreeformHitObject.cs @@ -9,7 +9,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.EmptyFreeform.Objects.Drawables { - public class DrawableEmptyFreeformHitObject : DrawableHitObject + public partial class DrawableEmptyFreeformHitObject : DrawableHitObject { public DrawableEmptyFreeformHitObject(EmptyFreeformHitObject hitObject) : base(hitObject) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/UI/DrawableEmptyFreeformRuleset.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/UI/DrawableEmptyFreeformRuleset.cs index 290f35f516..608e8d3c07 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/UI/DrawableEmptyFreeformRuleset.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/UI/DrawableEmptyFreeformRuleset.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.EmptyFreeform.UI { [Cached] - public class DrawableEmptyFreeformRuleset : DrawableRuleset + public partial class DrawableEmptyFreeformRuleset : DrawableRuleset { public DrawableEmptyFreeformRuleset(EmptyFreeformRuleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/UI/EmptyFreeformPlayfield.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/UI/EmptyFreeformPlayfield.cs index 9df5935c45..532e88d55e 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/UI/EmptyFreeformPlayfield.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform/UI/EmptyFreeformPlayfield.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.EmptyFreeform.UI { [Cached] - public class EmptyFreeformPlayfield : Playfield + public partial class EmptyFreeformPlayfield : Playfield { [BackgroundDependencyLoader] private void load() diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs index b75a5ec187..c105e9c040 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs @@ -9,7 +9,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Pippidon.Tests { - public class TestSceneOsuGame : OsuTestScene + public partial class TestSceneOsuGame : OsuTestScene { [BackgroundDependencyLoader] private void load() diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuPlayer.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuPlayer.cs index f00528900c..793d3933d7 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuPlayer.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuPlayer.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Pippidon.Tests { [TestFixture] - public class TestSceneOsuPlayer : PlayerTestScene + public partial class TestSceneOsuPlayer : PlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new PippidonRuleset(); } diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs index 399d6adda2..29203f0a20 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Pippidon.Objects.Drawables { - public class DrawablePippidonHitObject : DrawableHitObject + public partial class DrawablePippidonHitObject : DrawableHitObject { private const double time_preempt = 600; private const double time_fadein = 400; diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonInputManager.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonInputManager.cs index aa7fa3188b..85b264bc67 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonInputManager.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonInputManager.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Pippidon { - public class PippidonInputManager : RulesetInputManager + public partial class PippidonInputManager : RulesetInputManager { public PippidonInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique) diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs index ff10233b50..1a672d10dd 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Rulesets.Pippidon { - public class PippidonRulesetIcon : Sprite + public partial class PippidonRulesetIcon : Sprite { private readonly Ruleset ruleset; diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/DrawablePippidonRuleset.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/DrawablePippidonRuleset.cs index d923963bef..982a80cb7a 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/DrawablePippidonRuleset.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/DrawablePippidonRuleset.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Pippidon.UI { [Cached] - public class DrawablePippidonRuleset : DrawableRuleset + public partial class DrawablePippidonRuleset : DrawableRuleset { public DrawablePippidonRuleset(PippidonRuleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonCursorContainer.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonCursorContainer.cs index 9de3f4ba14..20dd2e7c31 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonCursorContainer.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonCursorContainer.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Pippidon.UI { - public class PippidonCursorContainer : GameplayCursorContainer + public partial class PippidonCursorContainer : GameplayCursorContainer { private Sprite cursorSprite; private Texture cursorTexture; diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfield.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfield.cs index b5a97c5ea3..62e162ae4b 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfield.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfield.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Pippidon.UI { [Cached] - public class PippidonPlayfield : Playfield + public partial class PippidonPlayfield : Playfield { protected override GameplayCursorContainer CreateCursor() => new PippidonCursorContainer(); diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfieldAdjustmentContainer.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfieldAdjustmentContainer.cs index 9236683827..b46e795bbc 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfieldAdjustmentContainer.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfieldAdjustmentContainer.cs @@ -7,7 +7,7 @@ using osuTK; namespace osu.Game.Rulesets.Pippidon.UI { - public class PippidonPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer + public partial class PippidonPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer { public PippidonPlayfieldAdjustmentContainer() { diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs index ffe921b54c..a9a3c2eb5b 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs @@ -9,7 +9,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.EmptyScrolling.Tests { - public class TestSceneOsuGame : OsuTestScene + public partial class TestSceneOsuGame : OsuTestScene { [BackgroundDependencyLoader] private void load() diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuPlayer.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuPlayer.cs index 9460576196..2be3862833 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuPlayer.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuPlayer.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.EmptyScrolling.Tests { [TestFixture] - public class TestSceneOsuPlayer : PlayerTestScene + public partial class TestSceneOsuPlayer : PlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new EmptyScrollingRuleset(); } diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingInputManager.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingInputManager.cs index 632e04f301..a7b4ae61f0 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingInputManager.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/EmptyScrollingInputManager.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.EmptyScrolling { - public class EmptyScrollingInputManager : RulesetInputManager + public partial class EmptyScrollingInputManager : RulesetInputManager { public EmptyScrollingInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique) diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/Drawables/DrawableEmptyScrollingHitObject.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/Drawables/DrawableEmptyScrollingHitObject.cs index b5ff0cde7c..a3c3b89105 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/Drawables/DrawableEmptyScrollingHitObject.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/Objects/Drawables/DrawableEmptyScrollingHitObject.cs @@ -9,7 +9,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.EmptyScrolling.Objects.Drawables { - public class DrawableEmptyScrollingHitObject : DrawableHitObject + public partial class DrawableEmptyScrollingHitObject : DrawableHitObject { public DrawableEmptyScrollingHitObject(EmptyScrollingHitObject hitObject) : base(hitObject) diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/UI/DrawableEmptyScrollingRuleset.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/UI/DrawableEmptyScrollingRuleset.cs index 620a4abc51..99598fc113 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/UI/DrawableEmptyScrollingRuleset.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/UI/DrawableEmptyScrollingRuleset.cs @@ -18,7 +18,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.EmptyScrolling.UI { [Cached] - public class DrawableEmptyScrollingRuleset : DrawableScrollingRuleset + public partial class DrawableEmptyScrollingRuleset : DrawableScrollingRuleset { public DrawableEmptyScrollingRuleset(EmptyScrollingRuleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/UI/EmptyScrollingPlayfield.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/UI/EmptyScrollingPlayfield.cs index 56620e44b3..3770ba8172 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/UI/EmptyScrollingPlayfield.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling/UI/EmptyScrollingPlayfield.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.EmptyScrolling.UI { [Cached] - public class EmptyScrollingPlayfield : ScrollingPlayfield + public partial class EmptyScrollingPlayfield : ScrollingPlayfield { [BackgroundDependencyLoader] private void load() diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs index b75a5ec187..c105e9c040 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs @@ -9,7 +9,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Pippidon.Tests { - public class TestSceneOsuGame : OsuTestScene + public partial class TestSceneOsuGame : OsuTestScene { [BackgroundDependencyLoader] private void load() diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuPlayer.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuPlayer.cs index f00528900c..793d3933d7 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuPlayer.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuPlayer.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Pippidon.Tests { [TestFixture] - public class TestSceneOsuPlayer : PlayerTestScene + public partial class TestSceneOsuPlayer : PlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new PippidonRuleset(); } diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs index e458cacef9..554d03c79f 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/Objects/Drawables/DrawablePippidonHitObject.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Pippidon.Objects.Drawables { - public class DrawablePippidonHitObject : DrawableHitObject + public partial class DrawablePippidonHitObject : DrawableHitObject { private BindableNumber currentLane; diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonInputManager.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonInputManager.cs index c9e6e6faaa..a31c1bf832 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonInputManager.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonInputManager.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Pippidon { - public class PippidonInputManager : RulesetInputManager + public partial class PippidonInputManager : RulesetInputManager { public PippidonInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique) diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs index 6b87d93951..75005a3743 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/PippidonRulesetIcon.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Rulesets.Pippidon { - public class PippidonRulesetIcon : Sprite + public partial class PippidonRulesetIcon : Sprite { private readonly Ruleset ruleset; diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/DrawablePippidonRuleset.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/DrawablePippidonRuleset.cs index 9a73dd7790..1e7e09be67 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/DrawablePippidonRuleset.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/DrawablePippidonRuleset.cs @@ -18,7 +18,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Pippidon.UI { [Cached] - public class DrawablePippidonRuleset : DrawableScrollingRuleset + public partial class DrawablePippidonRuleset : DrawableScrollingRuleset { public DrawablePippidonRuleset(PippidonRuleset ruleset, IBeatmap beatmap, IReadOnlyList mods = null) : base(ruleset, beatmap, mods) diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/PippidonCharacter.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/PippidonCharacter.cs index 98dba622d0..33d349da62 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/PippidonCharacter.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/PippidonCharacter.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Pippidon.UI { - public class PippidonCharacter : BeatSyncedContainer, IKeyBindingHandler + public partial class PippidonCharacter : BeatSyncedContainer, IKeyBindingHandler { public readonly BindableInt LanePosition = new BindableInt { diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfield.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfield.cs index ab8c6bb2e9..a90326e935 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfield.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon/UI/PippidonPlayfield.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Pippidon.UI { [Cached] - public class PippidonPlayfield : ScrollingPlayfield + public partial class PippidonPlayfield : ScrollingPlayfield { public const float LANE_HEIGHT = 70; @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Pippidon.UI }); } - private class LaneContainer : BeatSyncedContainer + private partial class LaneContainer : BeatSyncedContainer { private OsuColour colours; private FillFlowContainer fill; @@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Pippidon.UI } } - private class Lane : CompositeDrawable + private partial class Lane : CompositeDrawable { public Lane() { diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 9cf68d88d9..2c4577f239 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -20,7 +20,7 @@ using LogLevel = osu.Framework.Logging.LogLevel; namespace osu.Desktop { - internal class DiscordRichPresence : Component + internal partial class DiscordRichPresence : Component { private const string client_id = "367827983903490050"; diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index 09f7292845..4c93c2286f 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -26,7 +26,7 @@ using SDL2; namespace osu.Desktop { - internal class OsuGameDesktop : OsuGame + internal partial class OsuGameDesktop : OsuGame { private OsuSchemeLinkIPCChannel? osuSchemeLinkIPCChannel; diff --git a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs index cc4337fb02..6665733656 100644 --- a/osu.Desktop/Security/ElevatedPrivilegesChecker.cs +++ b/osu.Desktop/Security/ElevatedPrivilegesChecker.cs @@ -16,7 +16,7 @@ namespace osu.Desktop.Security /// /// Checks if the game is running with elevated privileges (as admin in Windows, root in Unix) and displays a warning notification if so. /// - public class ElevatedPrivilegesChecker : Component + public partial class ElevatedPrivilegesChecker : Component { [Resolved] private INotificationOverlay notifications { get; set; } = null!; @@ -63,7 +63,7 @@ namespace osu.Desktop.Security return false; } - private class ElevatedPrivilegesNotification : SimpleNotification + private partial class ElevatedPrivilegesNotification : SimpleNotification { public override bool IsImportant => true; diff --git a/osu.Desktop/Updater/SquirrelUpdateManager.cs b/osu.Desktop/Updater/SquirrelUpdateManager.cs index 84bac9da7c..3d4db88471 100644 --- a/osu.Desktop/Updater/SquirrelUpdateManager.cs +++ b/osu.Desktop/Updater/SquirrelUpdateManager.cs @@ -17,7 +17,7 @@ using UpdateManager = osu.Game.Updater.UpdateManager; namespace osu.Desktop.Updater { [SupportedOSPlatform("windows")] - public class SquirrelUpdateManager : UpdateManager + public partial class SquirrelUpdateManager : UpdateManager { private Squirrel.UpdateManager? updateManager; private INotificationOverlay notificationOverlay = null!; diff --git a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs index 284d25306d..560f6fdd7f 100644 --- a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs +++ b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Play; namespace osu.Desktop.Windows { - public class GameplayWinKeyBlocker : Component + public partial class GameplayWinKeyBlocker : Component { private Bindable disableWinKey = null!; private IBindable localUserPlaying = null!; diff --git a/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs b/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs index be6622f06e..2af851a561 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchSkinnableTestScene.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests { - public abstract class CatchSkinnableTestScene : SkinnableTestScene + public abstract partial class CatchSkinnableTestScene : SkinnableTestScene { protected override Ruleset CreateRulesetForSkinProvider() => new CatchRuleset(); } diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/CatchEditorTestSceneContainer.cs b/osu.Game.Rulesets.Catch.Tests/Editor/CatchEditorTestSceneContainer.cs index 78f56b4937..39508359a4 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/CatchEditorTestSceneContainer.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/CatchEditorTestSceneContainer.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests.Editor { - public class CatchEditorTestSceneContainer : Container + public partial class CatchEditorTestSceneContainer : Container { [Cached(typeof(Playfield))] public readonly ScrollingPlayfield Playfield; @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor }; } - private class TestCatchPlayfield : CatchEditorPlayfield + private partial class TestCatchPlayfield : CatchEditorPlayfield { public TestCatchPlayfield() : base(new BeatmapDifficulty { CircleSize = 0 }) diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/CatchPlacementBlueprintTestScene.cs b/osu.Game.Rulesets.Catch.Tests/Editor/CatchPlacementBlueprintTestScene.cs index 9060fa5aa0..aae759d934 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/CatchPlacementBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/CatchPlacementBlueprintTestScene.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.Tests.Editor { - public abstract class CatchPlacementBlueprintTestScene : PlacementBlueprintTestScene + public abstract partial class CatchPlacementBlueprintTestScene : PlacementBlueprintTestScene { protected const double TIME_SNAP = 100; diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs index 60fb31d1e0..033dca587e 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/CatchSelectionBlueprintTestScene.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests.Editor { - public abstract class CatchSelectionBlueprintTestScene : SelectionBlueprintTestScene + public abstract partial class CatchSelectionBlueprintTestScene : SelectionBlueprintTestScene { protected ScrollingHitObjectContainer HitObjectContainer => contentContainer.Playfield.HitObjectContainer; @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor InputManager.MoveMouseTo(pos); }); - private class EditorBeatmapDependencyContainer : Container + private partial class EditorBeatmapDependencyContainer : Container { [Cached] private readonly EditorClock editorClock; diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs index d08acc90cd..2db4102513 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneBananaShowerPlacementBlueprint.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.Tests.Editor { - public class TestSceneBananaShowerPlacementBlueprint : CatchPlacementBlueprintTestScene + public partial class TestSceneBananaShowerPlacementBlueprint : CatchPlacementBlueprintTestScene { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableBananaShower((BananaShower)hitObject); diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneCatchDistanceSnapGrid.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneCatchDistanceSnapGrid.cs index 405bab971c..1e057cf3fb 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneCatchDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneCatchDistanceSnapGrid.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests.Editor { - public class TestSceneCatchDistanceSnapGrid : OsuManualInputManagerTestScene + public partial class TestSceneCatchDistanceSnapGrid : OsuManualInputManagerTestScene { private readonly ManualClock manualClock = new ManualClock(); diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneEditor.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneEditor.cs index 9ecfd5f5c5..5593f3d319 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneEditor.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneEditor.cs @@ -9,7 +9,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests.Editor { [TestFixture] - public class TestSceneEditor : EditorTestScene + public partial class TestSceneEditor : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new CatchRuleset(); } diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneFruitPlacementBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneFruitPlacementBlueprint.cs index 94574b564d..93b24d92fb 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneFruitPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneFruitPlacementBlueprint.cs @@ -17,7 +17,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.Tests.Editor { - public class TestSceneFruitPlacementBlueprint : CatchPlacementBlueprintTestScene + public partial class TestSceneFruitPlacementBlueprint : CatchPlacementBlueprintTestScene { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableFruit((Fruit)hitObject); diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs index 691ebc7efc..18d3d29bdc 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamPlacementBlueprint.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.Tests.Editor { - public class TestSceneJuiceStreamPlacementBlueprint : CatchPlacementBlueprintTestScene + public partial class TestSceneJuiceStreamPlacementBlueprint : CatchPlacementBlueprintTestScene { private const double velocity_factor = 0.5; diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs index 8635a88d79..f25b66c360 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.Tests.Editor { - public class TestSceneJuiceStreamSelectionBlueprint : CatchSelectionBlueprintTestScene + public partial class TestSceneJuiceStreamSelectionBlueprint : CatchSelectionBlueprintTestScene { private JuiceStream hitObject; diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModFlashlight.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModFlashlight.cs index 538fc7fac6..f89ed5ce8e 100644 --- a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModFlashlight.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests.Mods { - public class TestSceneCatchModFlashlight : ModTestScene + public partial class TestSceneCatchModFlashlight : ModTestScene { protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs index bbe543e73e..50b928d509 100644 --- a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs +++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModNoScope.cs @@ -14,7 +14,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests.Mods { - public class TestSceneCatchModNoScope : ModTestScene + public partial class TestSceneCatchModNoScope : ModTestScene { protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs index 3e06e78dba..71df523951 100644 --- a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs +++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests.Mods { - public class TestSceneCatchModPerfect : ModPerfectTestScene + public partial class TestSceneCatchModPerfect : ModPerfectTestScene { protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs index c01aff0aa0..8472b995e8 100644 --- a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs +++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests.Mods { - public class TestSceneCatchModRelax : ModTestScene + public partial class TestSceneCatchModRelax : ModTestScene { protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs index 202228c9e7..40dc7d2403 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneAutoJuiceStream : TestSceneCatchPlayer + public partial class TestSceneAutoJuiceStream : TestSceneCatchPlayer { protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs index 0ddc58eb25..402f8f548d 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Catch.Objects; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] - public class TestSceneBananaShower : TestSceneCatchPlayer + public partial class TestSceneBananaShower : TestSceneCatchPlayer { [Test] public void TestBananaShower() diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModHidden.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModHidden.cs index 7e1c39f6a8..05d3361dc3 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModHidden.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchModHidden.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneCatchModHidden : ModTestScene + public partial class TestSceneCatchModHidden : ModTestScene { [Test] public void TestJuiceStream() diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayer.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayer.cs index 16942f3f35..01cce88d9d 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayer.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayer.cs @@ -9,7 +9,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] - public class TestSceneCatchPlayer : PlayerTestScene + public partial class TestSceneCatchPlayer : PlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs index 2078e1453f..8f3f39be9b 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchPlayerLegacySkin.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] - public class TestSceneCatchPlayerLegacySkin : LegacySkinPlayerTestScene + public partial class TestSceneCatchPlayerLegacySkin : LegacySkinPlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new CatchRuleset(); diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchReplay.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchReplay.cs index 6e12dacf29..cbf900ebc0 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchReplay.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchReplay.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Catch.UI; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneCatchReplay : TestSceneCatchPlayer + public partial class TestSceneCatchReplay : TestSceneCatchPlayer { protected override bool Autoplay => true; diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs index a2d4e7fb1e..75ab4ad9d2 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchSkinConfiguration.cs @@ -23,7 +23,7 @@ using Direction = osu.Game.Rulesets.Catch.UI.Direction; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneCatchSkinConfiguration : OsuTestScene + public partial class TestSceneCatchSkinConfiguration : OsuTestScene { private Catcher catcher; diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs index 1405e0018d..c8979381fe 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchStacker.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Catch.UI; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] - public class TestSceneCatchStacker : TestSceneCatchPlayer + public partial class TestSceneCatchStacker : TestSceneCatchPlayer { protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs index cf6a8169c4..836adcc912 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatchTouchInput.cs @@ -15,7 +15,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] - public class TestSceneCatchTouchInput : OsuTestScene + public partial class TestSceneCatchTouchInput : OsuTestScene { [Test] public void TestBasic() diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs index 2dc99077d3..e8231b07ad 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] - public class TestSceneCatcher : OsuTestScene + public partial class TestSceneCatcher : OsuTestScene { [Resolved] private OsuConfigManager config { get; set; } @@ -324,7 +324,7 @@ namespace osu.Game.Rulesets.Catch.Tests } } - public class TestCatcher : Catcher + public partial class TestCatcher : Catcher { public IEnumerable CaughtObjects => this.ChildrenOfType(); diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs index 150c1f8406..99c2fc570d 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs @@ -23,7 +23,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] - public class TestSceneCatcherArea : CatchSkinnableTestScene + public partial class TestSceneCatcherArea : CatchSkinnableTestScene { private RulesetInfo catchRuleset; @@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Catch.Tests catchRuleset = rulesets.GetRuleset(2); } - private class TestCatcherArea : CatcherArea + private partial class TestCatcherArea : CatcherArea { public TestCatcherArea(IBeatmapDifficultyInfo beatmapDifficulty) { diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs index f3161f32be..391297a252 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneComboCounter.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneComboCounter : CatchSkinnableTestScene + public partial class TestSceneComboCounter : CatchSkinnableTestScene { private ScoreProcessor scoreProcessor = null!; diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs index 94c870a444..11d6419507 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneDrawableHitObjects : OsuTestScene + public partial class TestSceneDrawableHitObjects : OsuTestScene { private DrawableCatchRuleset drawableRuleset; private double playfieldTime => drawableRuleset.Playfield.Time.Current; diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs index 868f498e8c..007f309f3f 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjectsHidden.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Catch.Mods; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneDrawableHitObjectsHidden : TestSceneDrawableHitObjects + public partial class TestSceneDrawableHitObjectsHidden : TestSceneDrawableHitObjects { [SetUp] public void SetUp() => Schedule(() => diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs index 7d72633e34..223c4e57fc 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs @@ -15,7 +15,7 @@ using osu.Game.Rulesets.Catch.Objects.Drawables; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] - public class TestSceneFruitObjects : CatchSkinnableTestScene + public partial class TestSceneFruitObjects : CatchSkinnableTestScene { protected override void LoadComplete() { @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Catch.Tests private Drawable createDrawableTinyDroplet() => new TestDrawableCatchHitObjectSpecimen(new DrawableTinyDroplet(new TinyDroplet())); } - public class TestDrawableCatchHitObjectSpecimen : CompositeDrawable + public partial class TestDrawableCatchHitObjectSpecimen : CompositeDrawable { public readonly ManualClock ManualClock; diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs index c7d130b440..995daaceb1 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitRandomness.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneFruitRandomness : OsuTestScene + public partial class TestSceneFruitRandomness : OsuTestScene { private readonly DrawableFruit drawableFruit; private readonly DrawableBanana drawableBanana; diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs index f7abd8d519..4b2873e0a8 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitVisualChange.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Catch.Objects.Drawables; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneFruitVisualChange : TestSceneFruitObjects + public partial class TestSceneFruitVisualChange : TestSceneFruitObjects { private readonly Bindable indexInBeatmap = new Bindable(); private readonly Bindable hyperDash = new Bindable(); diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs index 4886942dc6..f8c43a221e 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests { [TestFixture] - public class TestSceneHyperDash : TestSceneCatchPlayer + public partial class TestSceneHyperDash : TestSceneCatchPlayer { protected override bool Autoplay => true; diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs index cf49b7fe12..b343174e6b 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs @@ -24,7 +24,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneHyperDashColouring : OsuTestScene + public partial class TestSceneHyperDashColouring : OsuTestScene { [Resolved] private SkinManager skins { get; set; } diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs index 81589459c4..c91f07891c 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneJuiceStream : TestSceneCatchPlayer + public partial class TestSceneJuiceStream : TestSceneCatchPlayer { [Test] public void TestJuiceStreamEndingCombo() diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs index 786353bb00..aa66fc8741 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneLegacyBeatmapSkin.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Tests { - public class TestSceneLegacyBeatmapSkin : LegacyBeatmapSkinColourTest + public partial class TestSceneLegacyBeatmapSkin : LegacyBeatmapSkinColourTest { [Resolved] private AudioManager audio { get; set; } @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Catch.Tests protected override ExposedPlayer CreateTestPlayer(bool userHasCustomColours) => new CatchExposedPlayer(userHasCustomColours); - private class CatchExposedPlayer : ExposedPlayer + private partial class CatchExposedPlayer : ExposedPlayer { public CatchExposedPlayer(bool userHasCustomColours) : base(userHasCustomColours) diff --git a/osu.Game.Rulesets.Catch/CatchInputManager.cs b/osu.Game.Rulesets.Catch/CatchInputManager.cs index 0f76953003..1ef9e55d2d 100644 --- a/osu.Game.Rulesets.Catch/CatchInputManager.cs +++ b/osu.Game.Rulesets.Catch/CatchInputManager.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Catch { [Cached] - public class CatchInputManager : RulesetInputManager + public partial class CatchInputManager : RulesetInputManager { public CatchInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique) diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs index 86fdf09a72..166fa44303 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerPlacementBlueprint.cs @@ -12,7 +12,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.Edit.Blueprints { - public class BananaShowerPlacementBlueprint : CatchPlacementBlueprint + public partial class BananaShowerPlacementBlueprint : CatchPlacementBlueprint { private readonly TimeSpanOutline outline; diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerSelectionBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerSelectionBlueprint.cs index 7e4aca180c..2c545e8f0e 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/BananaShowerSelectionBlueprint.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Catch.Objects; namespace osu.Game.Rulesets.Catch.Edit.Blueprints { - public class BananaShowerSelectionBlueprint : CatchSelectionBlueprint + public partial class BananaShowerSelectionBlueprint : CatchSelectionBlueprint { public BananaShowerSelectionBlueprint(BananaShower hitObject) : base(hitObject) diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchPlacementBlueprint.cs index 8a1ced7eea..94373147d2 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchPlacementBlueprint.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Edit.Blueprints { - public class CatchPlacementBlueprint : PlacementBlueprint + public partial class CatchPlacementBlueprint : PlacementBlueprint where THitObject : CatchHitObject, new() { protected new THitObject HitObject => (THitObject)base.HitObject; diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchSelectionBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchSelectionBlueprint.cs index e7c04cd132..87c33a9cb8 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/CatchSelectionBlueprint.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Edit.Blueprints { - public abstract class CatchSelectionBlueprint : HitObjectSelectionBlueprint + public abstract partial class CatchSelectionBlueprint : HitObjectSelectionBlueprint where THitObject : CatchHitObject { protected override bool AlwaysShowWhenSelected => true; diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs index 8473eda663..006ea6e9cf 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components { - public abstract class EditablePath : CompositeDrawable + public abstract partial class EditablePath : CompositeDrawable { public int PathId => path.InvalidationID; diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/FruitOutline.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/FruitOutline.cs index 86006a99fc..dc2b038e01 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/FruitOutline.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/FruitOutline.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components { - public class FruitOutline : CompositeDrawable + public partial class FruitOutline : CompositeDrawable { public FruitOutline() { diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs index a6f1732bc1..ac0c850bca 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/NestedOutlineContainer.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components { - public class NestedOutlineContainer : CompositeDrawable + public partial class NestedOutlineContainer : CompositeDrawable { private readonly List nestedHitObjects = new List(); diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/PlacementEditablePath.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/PlacementEditablePath.cs index 27df064be4..ba2f5ed0eb 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/PlacementEditablePath.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/PlacementEditablePath.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components { - public class PlacementEditablePath : EditablePath + public partial class PlacementEditablePath : EditablePath { /// /// The original position of the last added vertex. diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/ScrollingPath.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/ScrollingPath.cs index 3a62b07816..6deb5a174f 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/ScrollingPath.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/ScrollingPath.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components { - public class ScrollingPath : CompositeDrawable + public partial class ScrollingPath : CompositeDrawable { private readonly Path drawablePath; diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/SelectionEditablePath.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/SelectionEditablePath.cs index 4576e9f8ee..3a44f7ac8a 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/SelectionEditablePath.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/SelectionEditablePath.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components { - public class SelectionEditablePath : EditablePath, IHasContextMenu + public partial class SelectionEditablePath : EditablePath, IHasContextMenu { public MenuItem[] ContextMenuItems => getContextMenuItems().ToArray(); diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/TimeSpanOutline.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/TimeSpanOutline.cs index 2586a81ef5..a1d5d7ae3e 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/TimeSpanOutline.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/TimeSpanOutline.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components { - public class TimeSpanOutline : CompositeDrawable + public partial class TimeSpanOutline : CompositeDrawable { private const float border_width = 4; diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/VertexPiece.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/VertexPiece.cs index 236d27753a..49570d3735 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/VertexPiece.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/VertexPiece.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components { - public class VertexPiece : Circle + public partial class VertexPiece : Circle { [Resolved] private OsuColour osuColour { get; set; } diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitPlacementBlueprint.cs index 686840ae55..af75023e68 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitPlacementBlueprint.cs @@ -11,7 +11,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.Edit.Blueprints { - public class FruitPlacementBlueprint : CatchPlacementBlueprint + public partial class FruitPlacementBlueprint : CatchPlacementBlueprint { private readonly FruitOutline outline; diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitSelectionBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitSelectionBlueprint.cs index b5a25dbf62..319b1b5e20 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/FruitSelectionBlueprint.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Catch.Objects; namespace osu.Game.Rulesets.Catch.Edit.Blueprints { - public class FruitSelectionBlueprint : CatchSelectionBlueprint + public partial class FruitSelectionBlueprint : CatchSelectionBlueprint { private readonly FruitOutline outline; diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs index fcdd055b56..0e2ee334ff 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamPlacementBlueprint.cs @@ -14,7 +14,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.Edit.Blueprints { - public class JuiceStreamPlacementBlueprint : CatchPlacementBlueprint + public partial class JuiceStreamPlacementBlueprint : CatchPlacementBlueprint { private readonly ScrollingPath scrollingPath; diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamSelectionBlueprint.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamSelectionBlueprint.cs index fc2b5e08fe..99ec5e2b0c 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/JuiceStreamSelectionBlueprint.cs @@ -22,7 +22,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.Edit.Blueprints { - public class JuiceStreamSelectionBlueprint : CatchSelectionBlueprint + public partial class JuiceStreamSelectionBlueprint : CatchSelectionBlueprint { public override Quad SelectionQuad => HitObjectContainer.ToScreenSpace(getBoundingBox().Offset(new Vector2(0, HitObjectContainer.DrawHeight))); diff --git a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs index a0a11424d0..9408a9f95c 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Catch.Edit { - public class CatchBlueprintContainer : ComposeBlueprintContainer + public partial class CatchBlueprintContainer : ComposeBlueprintContainer { public CatchBlueprintContainer(CatchHitObjectComposer composer) : base(composer) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs b/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs index 718c76abfc..e5cdcf706c 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Catch.Edit /// The guide lines used in the osu!catch editor to compose patterns that can be caught with constant speed. /// Currently, only forward placement (an object is snapped based on the previous object, not the opposite) is supported. /// - public class CatchDistanceSnapGrid : CompositeDrawable + public partial class CatchDistanceSnapGrid : CompositeDrawable { public double StartTime { get; set; } diff --git a/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfield.cs b/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfield.cs index b9a875fe8a..bca89c6024 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfield.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfield.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Catch.UI; namespace osu.Game.Rulesets.Catch.Edit { - public class CatchEditorPlayfield : CatchPlayfield + public partial class CatchEditorPlayfield : CatchPlayfield { // TODO fixme: the size of the catcher is not changed when circle size is changed in setup screen. public CatchEditorPlayfield(IBeatmapDifficultyInfo difficulty) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfieldAdjustmentContainer.cs index 0a0f91c781..0271005dd1 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchEditorPlayfieldAdjustmentContainer.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Edit { - public class CatchEditorPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer + public partial class CatchEditorPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer { protected override Container Content => content; private readonly Container content; @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Edit }; } - private class ScalingContainer : Container + private partial class ScalingContainer : Container { public ScalingContainer() { diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 220bc49203..bbdffbf39c 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -28,7 +28,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Edit { - public class CatchHitObjectComposer : DistancedHitObjectComposer + public partial class CatchHitObjectComposer : DistancedHitObjectComposer { private const float distance_snap_radius = 50; diff --git a/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs b/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs index 5aac521d0b..d9d7047920 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs @@ -18,7 +18,7 @@ using Direction = osu.Framework.Graphics.Direction; namespace osu.Game.Rulesets.Catch.Edit { - public class CatchSelectionHandler : EditorSelectionHandler + public partial class CatchSelectionHandler : EditorSelectionHandler { protected ScrollingHitObjectContainer HitObjectContainer => (ScrollingHitObjectContainer)playfield.HitObjectContainer; diff --git a/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs b/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs index 67238f66d4..0a50ad1df4 100644 --- a/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs +++ b/osu.Game.Rulesets.Catch/Edit/DrawableCatchEditorRuleset.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Catch.Edit { - public class DrawableCatchEditorRuleset : DrawableCatchRuleset + public partial class DrawableCatchEditorRuleset : DrawableCatchRuleset { public readonly BindableDouble TimeRangeMultiplier = new BindableDouble(1); diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs index a9e9e8fbd5..40450c6729 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModFlashlight.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Mods { - public class CatchModFlashlight : ModFlashlight + public partial class CatchModFlashlight : ModFlashlight { public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1; @@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Mods base.ApplyToDrawableRuleset(drawableRuleset); } - private class CatchFlashlight : Flashlight + private partial class CatchFlashlight : Flashlight { private readonly CatchPlayfield playfield; diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs index 3f7560844c..83ad96d5b4 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Mods { - public class CatchModRelax : ModRelax, IApplicableToDrawableRuleset, IApplicableToPlayer + public partial class CatchModRelax : ModRelax, IApplicableToDrawableRuleset, IApplicableToPlayer { public override LocalisableString Description => @"Use the mouse to control the catcher."; @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Catch.Mods } } - private class MouseInputHelper : Drawable, IKeyBindingHandler, IRequireHighFrequencyMousePosition + private partial class MouseInputHelper : Drawable, IKeyBindingHandler, IRequireHighFrequencyMousePosition { private readonly CatcherArea catcherArea; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs index 31a27b6047..65d91bffe2 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtBanana.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables /// /// Represents a caught by the catcher. /// - public class CaughtBanana : CaughtObject + public partial class CaughtBanana : CaughtObject { public CaughtBanana() : base(CatchSkinComponents.Banana, _ => new BananaPiece()) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs index 6d5dd0ed25..ed8bf17747 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtDroplet.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables /// /// Represents a caught by the catcher. /// - public class CaughtDroplet : CaughtObject + public partial class CaughtDroplet : CaughtObject { public override bool StaysOnPlate => false; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs index 89757748ab..d296052220 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtFruit.cs @@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables /// /// Represents a caught by the catcher. /// - public class CaughtFruit : CaughtObject + public partial class CaughtFruit : CaughtObject { public CaughtFruit() : base(CatchSkinComponents.Fruit, _ => new FruitPiece()) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs index 8ac5eac227..436edf6367 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables /// Represents a caught by the catcher. /// [Cached(typeof(IHasCatchObjectState))] - public abstract class CaughtObject : SkinnableDrawable, IHasCatchObjectState + public abstract partial class CaughtObject : SkinnableDrawable, IHasCatchObjectState { public PalpableCatchHitObject HitObject { get; private set; } public Bindable AccentColour { get; } = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs index 80a4150d98..51addaebd5 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs @@ -11,7 +11,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableBanana : DrawablePalpableCatchHitObject + public partial class DrawableBanana : DrawablePalpableCatchHitObject { public DrawableBanana() : this(null) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs index f061f206ff..c5ae1b5526 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableBananaShower : DrawableCatchHitObject + public partial class DrawableBananaShower : DrawableCatchHitObject { private readonly Container bananaContainer; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs index 23264edf3d..c25bc7d076 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs @@ -15,7 +15,7 @@ using osu.Game.Utils; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public abstract class DrawableCatchHitObject : DrawableHitObject + public abstract partial class DrawableCatchHitObject : DrawableHitObject { public readonly Bindable OriginalXBindable = new Bindable(); public readonly Bindable XOffsetBindable = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs index a81d87480a..e8b0c4a9fb 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs @@ -11,7 +11,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableDroplet : DrawablePalpableCatchHitObject + public partial class DrawableDroplet : DrawablePalpableCatchHitObject { public DrawableDroplet() : this(null) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs index d7fd79929b..4347c77383 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs @@ -11,7 +11,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableFruit : DrawablePalpableCatchHitObject + public partial class DrawableFruit : DrawablePalpableCatchHitObject { public DrawableFruit() : this(null) diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs index 12a44c909e..1ad1664122 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableJuiceStream : DrawableCatchHitObject + public partial class DrawableJuiceStream : DrawableCatchHitObject { private readonly Container dropletContainer; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs index dd09b6c06d..8468cc0a6a 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Objects.Drawables { [Cached(typeof(IHasCatchObjectState))] - public abstract class DrawablePalpableCatchHitObject : DrawableCatchHitObject, IHasCatchObjectState + public abstract partial class DrawablePalpableCatchHitObject : DrawableCatchHitObject, IHasCatchObjectState { public new PalpableCatchHitObject HitObject => (PalpableCatchHitObject)base.HitObject; diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs index 8c48b62c7e..8e98efdbda 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs @@ -7,7 +7,7 @@ using JetBrains.Annotations; namespace osu.Game.Rulesets.Catch.Objects.Drawables { - public class DrawableTinyDroplet : DrawableDroplet + public partial class DrawableTinyDroplet : DrawableDroplet { protected override float ScaleFactor => base.ScaleFactor / 2; diff --git a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs index ba3d529212..b784fc4c19 100644 --- a/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs +++ b/osu.Game.Rulesets.Catch/Scoring/CatchScoreProcessor.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Catch.Scoring { - public class CatchScoreProcessor : ScoreProcessor + public partial class CatchScoreProcessor : ScoreProcessor { public CatchScoreProcessor() : base(new CatchRuleset()) diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs index 9a657c9216..8cdb490922 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonBananaPiece.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Argon { - internal class ArgonBananaPiece : ArgonFruitPiece + internal partial class ArgonBananaPiece : ArgonFruitPiece { private Container stabilisedPieceContainer = null!; diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs index 4db0df4a34..82374085c8 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonCatcher.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Argon { - public class ArgonCatcher : CompositeDrawable + public partial class ArgonCatcher : CompositeDrawable { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs index 267f8a06a3..38fe7916f5 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonDropletPiece.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Argon { - internal class ArgonDropletPiece : CatchHitObjectPiece + internal partial class ArgonDropletPiece : CatchHitObjectPiece { protected override Drawable HyperBorderPiece => hyperBorderPiece; diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs index 28538d48b3..4b5319e859 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonFruitPiece.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Argon { - internal class ArgonFruitPiece : CatchHitObjectPiece + internal partial class ArgonFruitPiece : CatchHitObjectPiece { protected override Drawable HyperBorderPiece => hyperBorderPiece; diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonHitExplosion.cs index 90dca49dfd..a3c0c8c108 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonHitExplosion.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Argon { - public class ArgonHitExplosion : CompositeDrawable, IHitExplosion + public partial class ArgonHitExplosion : CompositeDrawable, IHitExplosion { public override bool RemoveWhenNotAlive => true; diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs index 59e8b5a0b3..82d10e500d 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Argon { - public class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement { protected readonly HitResult Result; @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon public Drawable? GetAboveHitObjectsProxiedContent() => null; - private class RingExplosion : CompositeDrawable + private partial class RingExplosion : CompositeDrawable { private readonly float travel = 52; @@ -169,7 +169,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon this.FadeOutFromOne(1000, Easing.OutQuint); } - public class RingPiece : CircularContainer + public partial class RingPiece : CircularContainer { public RingPiece(float thickness = 9) { diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs index 359756f159..80ee9d5a0c 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPiece.cs @@ -5,7 +5,7 @@ using osu.Framework.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class BananaPiece : CatchHitObjectPiece + public partial class BananaPiece : CatchHitObjectPiece { protected override Drawable BorderPiece { get; } diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.cs b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.cs index ee1cc68f7d..26c8558e74 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/BananaPulpFormation.cs @@ -5,7 +5,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class BananaPulpFormation : PulpFormation + public partial class BananaPulpFormation : PulpFormation { public BananaPulpFormation() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs index 8d8ee49af7..f0bdcfa1ba 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/BorderPiece.cs @@ -9,7 +9,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class BorderPiece : Circle + public partial class BorderPiece : Circle { public BorderPiece() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs index e84e4d4ad2..7cc425966d 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/CatchHitObjectPiece.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public abstract class CatchHitObjectPiece : CompositeDrawable + public abstract partial class CatchHitObjectPiece : CompositeDrawable { public readonly Bindable AccentColour = new Bindable(); public readonly Bindable HyperDash = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.cs index e423f21b98..72208b763b 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultCatcher.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Catch.UI; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class DefaultCatcher : CompositeDrawable + public partial class DefaultCatcher : CompositeDrawable { public Bindable CurrentState { get; } = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs index 2650ba765b..3af178fe4d 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class DefaultHitExplosion : CompositeDrawable, IHitExplosion + public partial class DefaultHitExplosion : CompositeDrawable, IHitExplosion { private CircularContainer largeFaint = null!; private CircularContainer smallFaint = null!; diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs index 59e74bff74..f002457b61 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DropletPiece.cs @@ -7,7 +7,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class DropletPiece : CatchHitObjectPiece + public partial class DropletPiece : CatchHitObjectPiece { protected override Drawable HyperBorderPiece { get; } diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs index 3bd8032649..31e30d8073 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPiece.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Catch.Objects; namespace osu.Game.Rulesets.Catch.Skinning.Default { - internal class FruitPiece : CatchHitObjectPiece + internal partial class FruitPiece : CatchHitObjectPiece { /// /// Because we're adding a border around the fruit, we need to scale down some. diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.cs b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.cs index f097361d2a..c031e50e34 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/FruitPulpFormation.cs @@ -7,7 +7,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class FruitPulpFormation : PulpFormation + public partial class FruitPulpFormation : PulpFormation { public readonly Bindable VisualRepresentation = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs index c8895f32f4..c025c8e435 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/HyperBorderPiece.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.Catch.UI; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class HyperBorderPiece : BorderPiece + public partial class HyperBorderPiece : BorderPiece { public HyperBorderPiece() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.cs index 53a487b97f..1462bc3515 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/HyperDropletBorderPiece.cs @@ -3,7 +3,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class HyperDropletBorderPiece : HyperBorderPiece + public partial class HyperDropletBorderPiece : HyperBorderPiece { public HyperDropletBorderPiece() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/Pulp.cs b/osu.Game.Rulesets.Catch/Skinning/Default/Pulp.cs index 96c6233b41..4b4d6f3788 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/Pulp.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/Pulp.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class Pulp : Circle + public partial class Pulp : Circle { public readonly Bindable AccentColour = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.cs b/osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.cs index 8753aa4077..21502e6fa0 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/PulpFormation.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public abstract class PulpFormation : CompositeDrawable + public abstract partial class PulpFormation : CompositeDrawable { public readonly Bindable AccentColour = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyBananaPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyBananaPiece.cs index 310da8bf78..26832b7271 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyBananaPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyBananaPiece.cs @@ -5,7 +5,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Rulesets.Catch.Skinning.Legacy { - public class LegacyBananaPiece : LegacyCatchHitObjectPiece + public partial class LegacyBananaPiece : LegacyCatchHitObjectPiece { protected override void LoadComplete() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs index b4d29988d9..eba837a52d 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchComboCounter.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy /// /// A combo counter implementation that visually behaves almost similar to stable's osu!catch combo counter. /// - public class LegacyCatchComboCounter : CompositeDrawable, ICatchComboCounter + public partial class LegacyCatchComboCounter : CompositeDrawable, ICatchComboCounter { private readonly LegacyRollingCounter counter; diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchHitObjectPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchHitObjectPiece.cs index 1231ed6d5a..2184ecc363 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchHitObjectPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatchHitObjectPiece.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Legacy { - public abstract class LegacyCatchHitObjectPiece : PoolableDrawable + public abstract partial class LegacyCatchHitObjectPiece : PoolableDrawable { protected readonly Bindable IndexInBeatmap = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.cs index 667622e6f2..b36d7f11cb 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherNew.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Legacy { - public class LegacyCatcherNew : CompositeDrawable + public partial class LegacyCatcherNew : CompositeDrawable { [Resolved] private Bindable currentState { get; set; } = null!; diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.cs index 5f09d1e254..1e21d8eab1 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyCatcherOld.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Legacy { - public class LegacyCatcherOld : CompositeDrawable + public partial class LegacyCatcherOld : CompositeDrawable { public LegacyCatcherOld() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyDropletPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyDropletPiece.cs index 7007f1cc29..7ffd682698 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyDropletPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyDropletPiece.cs @@ -6,7 +6,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Legacy { - public class LegacyDropletPiece : LegacyCatchHitObjectPiece + public partial class LegacyDropletPiece : LegacyCatchHitObjectPiece { public LegacyDropletPiece() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs index f002bab219..85b60561dd 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyFruitPiece.cs @@ -5,7 +5,7 @@ using osu.Game.Rulesets.Catch.Objects; namespace osu.Game.Rulesets.Catch.Skinning.Legacy { - internal class LegacyFruitPiece : LegacyCatchHitObjectPiece + internal partial class LegacyFruitPiece : LegacyCatchHitObjectPiece { protected override void LoadComplete() { diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs index 393a1076af..47660503dc 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Legacy { - public class LegacyHitExplosion : CompositeDrawable, IHitExplosion + public partial class LegacyHitExplosion : CompositeDrawable, IHitExplosion { [Resolved] private Catcher catcher { get; set; } = null!; diff --git a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs index 03f0bc6a55..ffdc5299d0 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchComboDisplay.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.UI /// /// Represents a component that displays a skinned and handles combo judgement results for updating it accordingly. /// - public class CatchComboDisplay : SkinnableDrawable + public partial class CatchComboDisplay : SkinnableDrawable { private int currentCombo; diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index ce000b0fad..4df297565e 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.UI { - public class CatchPlayfield : ScrollingPlayfield + public partial class CatchPlayfield : ScrollingPlayfield { /// /// The width of the playfield. diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs index 82b85f54e4..c03179dc50 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfieldAdjustmentContainer.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.UI { - public class CatchPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer + public partial class CatchPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer { private const float playfield_size_adjust = 0.8f; @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Catch.UI /// /// A which scales its content relative to a target width. /// - private class ScalingContainer : Container + private partial class ScalingContainer : Container { protected override void Update() { diff --git a/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs b/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs index c118c14e3f..9ea150a2cf 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Catch.UI { - public class CatchReplayRecorder : ReplayRecorder + public partial class CatchReplayRecorder : ReplayRecorder { private readonly CatchPlayfield playfield; diff --git a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs index 12d695393f..d23913136d 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchTouchInputMapper.cs @@ -15,7 +15,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Catch.UI { - public class CatchTouchInputMapper : VisibilityContainer + public partial class CatchTouchInputMapper : VisibilityContainer { public override bool PropagatePositionalInputSubTree => true; public override bool PropagateNonPositionalInputSubTree => true; @@ -205,7 +205,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override void PopOut() => mainContent.FadeOut(300, Easing.OutQuint); - private class InputArea : CompositeDrawable, IKeyBindingHandler + private partial class InputArea : CompositeDrawable, IKeyBindingHandler { private readonly TouchCatchAction handledAction; diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 61fefcfd99..086b4ff285 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -26,7 +26,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.UI { [Cached] - public class Catcher : SkinReloadableDrawable + public partial class Catcher : SkinReloadableDrawable { /// /// The size of the catcher at 1x scale. diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 7a29ba9801..d0da05bc44 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Catch.UI /// It holds a as a child and translates input to the catcher movement. /// It also holds a combo display that is above the catcher, and judgment results are translated to the catcher and the combo display. /// - public class CatcherArea : Container, IKeyBindingHandler + public partial class CatcherArea : Container, IKeyBindingHandler { public Catcher Catcher { diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs index afaa037574..f486633e12 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrail.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Catch.UI /// A trail of the catcher. /// It also represents a hyper dash afterimage. /// - public class CatcherTrail : PoolableDrawableWithLifetime + public partial class CatcherTrail : PoolableDrawableWithLifetime { private readonly SkinnableCatcher body; diff --git a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs index d255937fed..e982be53d8 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherTrailDisplay.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.UI /// Represents a component responsible for displaying /// the appropriate catcher trails when requested to. /// - public class CatcherTrailDisplay : PooledDrawableWithLifetimeContainer + public partial class CatcherTrailDisplay : PooledDrawableWithLifetimeContainer { /// /// The most recent time a dash trail was added to this container. diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index e02b915508..0be271b236 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -21,7 +21,7 @@ using osu.Game.Scoring; namespace osu.Game.Rulesets.Catch.UI { - public class DrawableCatchRuleset : DrawableScrollingRuleset + public partial class DrawableCatchRuleset : DrawableScrollingRuleset { protected override ScrollVisualisationMethod VisualisationMethod => ScrollVisualisationMethod.Constant; diff --git a/osu.Game.Rulesets.Catch/UI/DroppedObjectContainer.cs b/osu.Game.Rulesets.Catch/UI/DroppedObjectContainer.cs index 1e4da479d2..cb2d8498cc 100644 --- a/osu.Game.Rulesets.Catch/UI/DroppedObjectContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/DroppedObjectContainer.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Catch.Objects.Drawables; namespace osu.Game.Rulesets.Catch.UI { - public class DroppedObjectContainer : Container + public partial class DroppedObjectContainer : Container { public DroppedObjectContainer() { diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs index 9b32893efe..c53957100a 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs @@ -8,7 +8,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch.UI { - public class HitExplosion : PoolableDrawableWithLifetime + public partial class HitExplosion : PoolableDrawableWithLifetime { private readonly SkinnableDrawable skinnableExplosion; diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs b/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs index 2004c971ad..e1dd665bf2 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Objects.Pooling; namespace osu.Game.Rulesets.Catch.UI { - public class HitExplosionContainer : PooledDrawableWithLifetimeContainer + public partial class HitExplosionContainer : PooledDrawableWithLifetimeContainer { protected override bool RemoveRewoundEntry => true; diff --git a/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs b/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs index fa6ccf6bd6..78a71f26a2 100644 --- a/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs +++ b/osu.Game.Rulesets.Catch/UI/SkinnableCatcher.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Catch.UI /// The visual representation of the . /// It includes the body part of the catcher and the catcher plate. /// - public class SkinnableCatcher : SkinnableDrawable + public partial class SkinnableCatcher : SkinnableDrawable { /// /// This is used by skin elements to determine which texture of the catcher is used. diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs index 0e4f612999..d2a44122aa 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaPlacementBlueprintTestScene.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Tests.Editor { - public abstract class ManiaPlacementBlueprintTestScene : PlacementBlueprintTestScene + public abstract partial class ManiaPlacementBlueprintTestScene : PlacementBlueprintTestScene { private readonly Column column; diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs index 4cadcf138b..2fda012f07 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/ManiaSelectionBlueprintTestScene.cs @@ -15,7 +15,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Editor { - public abstract class ManiaSelectionBlueprintTestScene : SelectionBlueprintTestScene + public abstract partial class ManiaSelectionBlueprintTestScene : SelectionBlueprintTestScene { protected override Container Content => blueprints ?? base.Content; diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneEditor.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneEditor.cs index 99850f33b8..0a21098d0d 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneEditor.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneEditor.cs @@ -14,7 +14,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Editor { [TestFixture] - public class TestSceneEditor : EditorTestScene + public partial class TestSceneEditor : EditorTestScene { private readonly Bindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNotePlacementBlueprint.cs index ddec1f3432..4b332c3faa 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNotePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNotePlacementBlueprint.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Mania.Tests.Editor { - public class TestSceneHoldNotePlacementBlueprint : ManiaPlacementBlueprintTestScene + public partial class TestSceneHoldNotePlacementBlueprint : ManiaPlacementBlueprintTestScene { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableHoldNote((HoldNote)hitObject); protected override PlacementBlueprint CreateBlueprint() => new HoldNotePlacementBlueprint(); diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteSelectionBlueprint.cs index b70d4e4fa6..a65f949cec 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneHoldNoteSelectionBlueprint.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Mania.Objects.Drawables; namespace osu.Game.Rulesets.Mania.Tests.Editor { - public class TestSceneHoldNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene + public partial class TestSceneHoldNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene { public TestSceneHoldNoteSelectionBlueprint() : base(4) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs index ef140995ec..653c75baac 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Tests.Editor { - public class TestSceneManiaBeatSnapGrid : EditorClockTestScene + public partial class TestSceneManiaBeatSnapGrid : EditorClockTestScene { [Cached(typeof(IScrollingInfo))] private ScrollingTestContainer.TestScrollingInfo scrollingInfo = new ScrollingTestContainer.TestScrollingInfo(); @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor public ManiaPlayfield Playfield { get; } } - public class TestHitObjectComposer : HitObjectComposer + public partial class TestHitObjectComposer : HitObjectComposer { public override Playfield Playfield { get; } public override IEnumerable HitObjects => Enumerable.Empty(); diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs index e082b90d3b..a1f4b234c4 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs @@ -22,7 +22,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Editor { - public class TestSceneManiaComposeScreen : EditorClockTestScene + public partial class TestSceneManiaComposeScreen : EditorClockTestScene { [Resolved] private SkinManager skins { get; set; } diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs index a3985be936..8e0b51dcf8 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaHitObjectComposer.cs @@ -27,7 +27,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Mania.Tests.Editor { - public class TestSceneManiaHitObjectComposer : EditorClockTestScene + public partial class TestSceneManiaHitObjectComposer : EditorClockTestScene { private TestComposer composer; @@ -193,7 +193,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor private void setScrollStep(ScrollingDirection direction) => AddStep($"set scroll direction = {direction}", () => ((Bindable)composer.Composer.ScrollingInfo.Direction).Value = direction); - private class TestComposer : CompositeDrawable + private partial class TestComposer : CompositeDrawable { [Cached(typeof(EditorBeatmap))] [Cached(typeof(IBeatSnapProvider))] diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNotePlacementBlueprint.cs index 28c002eef8..a446f13cbf 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNotePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNotePlacementBlueprint.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Mania.Tests.Editor { - public class TestSceneNotePlacementBlueprint : ManiaPlacementBlueprintTestScene + public partial class TestSceneNotePlacementBlueprint : ManiaPlacementBlueprintTestScene { [SetUp] public void Setup() => Schedule(() => diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNoteSelectionBlueprint.cs index f61d416e3b..86e87e7486 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneNoteSelectionBlueprint.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Mania.Objects.Drawables; namespace osu.Game.Rulesets.Mania.Tests.Editor { - public class TestSceneNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene + public partial class TestSceneNoteSelectionBlueprint : ManiaSelectionBlueprintTestScene { public TestSceneNoteSelectionBlueprint() : base(4) diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs b/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs index e456659ac4..c85583c1fd 100644 --- a/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/ManiaInputTestScene.cs @@ -12,7 +12,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests { - public abstract class ManiaInputTestScene : OsuTestScene + public abstract partial class ManiaInputTestScene : OsuTestScene { private readonly Container content; protected override Container Content => content ?? base.Content; @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Mania.Tests base.Content.Add(content = new LocalInputManager(keys)); } - private class LocalInputManager : ManiaInputManager + private partial class LocalInputManager : ManiaInputManager { public LocalInputManager(int variant) : base(new ManiaRuleset().RulesetInfo, variant) @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Mania.Tests protected override KeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) => new LocalKeyBindingContainer(ruleset, variant, unique); - private class LocalKeyBindingContainer : RulesetKeyBindingContainer + private partial class LocalKeyBindingContainer : RulesetKeyBindingContainer { public LocalKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique) diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs index 60363aaeef..dc4f660a45 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModConstantSpeed.cs @@ -13,7 +13,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Mods { - public class TestSceneManiaModConstantSpeed : ModTestScene + public partial class TestSceneManiaModConstantSpeed : ModTestScene { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFlashlight.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFlashlight.cs index 0e222fea89..001d53c887 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFlashlight.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModFlashlight.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Mods { - public class TestSceneManiaModFlashlight : ModTestScene + public partial class TestSceneManiaModFlashlight : ModTestScene { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs index d27a79c41d..3011a93755 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModHoldOff.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.Mania.Beatmaps; namespace osu.Game.Rulesets.Mania.Tests.Mods { - public class TestSceneManiaModHoldOff : ModTestScene + public partial class TestSceneManiaModHoldOff : ModTestScene { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModInvert.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModInvert.cs index f2cc254e38..2977241dc6 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModInvert.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModInvert.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Mods { - public class TestSceneManiaModInvert : ModTestScene + public partial class TestSceneManiaModInvert : ModTestScene { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs index 2e3b21aed7..97a6ee28f4 100644 --- a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs +++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs @@ -8,7 +8,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests.Mods { - public class TestSceneManiaModPerfect : ModPerfectTestScene + public partial class TestSceneManiaModPerfect : ModPerfectTestScene { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs index d3e90170b2..0c55cebf0d 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ColumnTestContainer.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning /// /// A container to be used in a to provide a resolvable dependency. /// - public class ColumnTestContainer : Container + public partial class ColumnTestContainer : Container { protected override Container Content => content; diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs index 75175c43d8..25e120edc5 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaHitObjectTestScene.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning /// /// A test scene for a mania hitobject. /// - public abstract class ManiaHitObjectTestScene : ManiaSkinnableTestScene + public abstract partial class ManiaHitObjectTestScene : ManiaSkinnableTestScene { [SetUp] public void SetUp() => Schedule(() => diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs index 2c5535a65f..30bd600d9d 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/ManiaSkinnableTestScene.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Skinning /// /// A test scene for skinnable mania components. /// - public abstract class ManiaSkinnableTestScene : SkinnableTestScene + public abstract partial class ManiaSkinnableTestScene : SkinnableTestScene { [Cached(Type = typeof(IScrollingInfo))] private readonly TestScrollingInfo scrollingInfo = new TestScrollingInfo(); diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs index 1bfe55b074..ab9f57ecc3 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneBarLine.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Tests.Skinning { - public class TestSceneBarLine : ManiaSkinnableTestScene + public partial class TestSceneBarLine : ManiaSkinnableTestScene { [Test] public void TestMinor() diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs index 3dece20308..3881aae22e 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnBackground.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Tests.Skinning { - public class TestSceneColumnBackground : ManiaSkinnableTestScene + public partial class TestSceneColumnBackground : ManiaSkinnableTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs index 1fb9d448a9..9cccc2dd86 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneColumnHitObjectArea.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Tests.Skinning { - public class TestSceneColumnHitObjectArea : ManiaSkinnableTestScene + public partial class TestSceneColumnHitObjectArea : ManiaSkinnableTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs index 8b12d37fe9..2a9727dbd4 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneDrawableJudgement.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mania.Tests.Skinning { - public class TestSceneDrawableJudgement : ManiaSkinnableTestScene + public partial class TestSceneDrawableJudgement : ManiaSkinnableTestScene { public TestSceneDrawableJudgement() { diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs index 744721f1a3..30dd83123d 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHitExplosion.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Tests.Skinning { [TestFixture] - public class TestSceneHitExplosion : ManiaSkinnableTestScene + public partial class TestSceneHitExplosion : ManiaSkinnableTestScene { private readonly List> hitExplosionPools = new List>(); diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHoldNote.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHoldNote.cs index 0947ddfeb0..0b9ca42af8 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHoldNote.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneHoldNote.cs @@ -15,7 +15,7 @@ using osu.Game.Rulesets.Mania.Objects.Drawables; namespace osu.Game.Rulesets.Mania.Tests.Skinning { - public class TestSceneHoldNote : ManiaHitObjectTestScene + public partial class TestSceneHoldNote : ManiaHitObjectTestScene { [Test] public void TestHoldNote() diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneNote.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneNote.cs index 85995e6994..d049d88ea8 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneNote.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneNote.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Mania.Objects.Drawables; namespace osu.Game.Rulesets.Mania.Tests.Skinning { - public class TestSceneNote : ManiaHitObjectTestScene + public partial class TestSceneNote : ManiaHitObjectTestScene { protected override DrawableManiaHitObject CreateHitObject() { diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs index 9817719c94..f85e303940 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestScenePlayfield.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Tests.Skinning { - public class TestScenePlayfield : ManiaSkinnableTestScene + public partial class TestScenePlayfield : ManiaSkinnableTestScene { private List stageDefinitions = new List(); diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs index 07aa0b845f..25e24929c9 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStage.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Tests.Skinning { - public class TestSceneStage : ManiaSkinnableTestScene + public partial class TestSceneStage : ManiaSkinnableTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs index 5c8e038eed..0557a201c8 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageBackground.cs @@ -10,7 +10,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Tests.Skinning { - public class TestSceneStageBackground : ManiaSkinnableTestScene + public partial class TestSceneStageBackground : ManiaSkinnableTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs index f9c17ee7f4..04d2eee83e 100644 --- a/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs +++ b/osu.Game.Rulesets.Mania.Tests/Skinning/TestSceneStageForeground.cs @@ -9,7 +9,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Tests.Skinning { - public class TestSceneStageForeground : ManiaSkinnableTestScene + public partial class TestSceneStageForeground : ManiaSkinnableTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs index 3abeb8a5f6..9fdd93bcc9 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneAutoGeneration.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Tests { [TestFixture] [HeadlessTest] - public class TestSceneAutoGeneration : OsuTestScene + public partial class TestSceneAutoGeneration : OsuTestScene { /// /// The number of frames which are generated at the start of a replay regardless of hitobject content. diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs index 83491b6fe9..b96fab9ec0 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneColumn.cs @@ -24,7 +24,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Tests { [TestFixture] - public class TestSceneColumn : ManiaInputTestScene + public partial class TestSceneColumn : ManiaInputTestScene { [Cached(typeof(IReadOnlyList))] private IReadOnlyList mods { get; set; } = Array.Empty(); diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs index d273f5cb35..51c2bac6d1 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableManiaHitObject.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Tests { - public class TestSceneDrawableManiaHitObject : OsuTestScene + public partial class TestSceneDrawableManiaHitObject : OsuTestScene { private readonly ManualClock clock = new ManualClock(); diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs index 0cba2076be..42e2099e3f 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Mania.Tests /// x : button press /// o : button release /// - public class TestSceneHoldNoteInput : RateAdjustedBeatmapTestScene + public partial class TestSceneHoldNoteInput : RateAdjustedBeatmapTestScene { private const double time_before_head = 250; private const double time_head = 1500; @@ -572,7 +572,7 @@ namespace osu.Game.Rulesets.Mania.Tests AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor?.HasCompleted.Value == true); } - private class ScoreAccessibleReplayPlayer : ReplayPlayer + private partial class ScoreAccessibleReplayPlayer : ReplayPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs index 00f0fcefd9..7021c081b7 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaHitObjectSamples.cs @@ -10,7 +10,7 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Rulesets.Mania.Tests { - public class TestSceneManiaHitObjectSamples : HitObjectSampleTest + public partial class TestSceneManiaHitObjectSamples : HitObjectSampleTest { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); protected override IResourceStore RulesetResources => new DllResourceStore(Assembly.GetAssembly(typeof(TestSceneManiaHitObjectSamples))); diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaPlayer.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaPlayer.cs index 9abedc22f9..98046320cb 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneManiaPlayer.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneManiaPlayer.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests { - public class TestSceneManiaPlayer : PlayerTestScene + public partial class TestSceneManiaPlayer : PlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); } diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs index df831d8c9f..31ff57395c 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneNotes.cs @@ -29,7 +29,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Tests { [TestFixture] - public class TestSceneNotes : OsuTestScene + public partial class TestSceneNotes : OsuTestScene { [Test] public void TestVariousNotes() @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Mania.Tests private bool verifyAnchors(DrawableHoldNote holdNote, Anchor expectedAnchor) => verifyAnchors((DrawableHitObject)holdNote, expectedAnchor) && holdNote.NestedHitObjects.All(n => verifyAnchors(n, expectedAnchor)); - private class NoteContainer : Container + private partial class NoteContainer : Container { private readonly Container content; protected override Container Content => content; diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs index 464dbecee5..e49b259615 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneOutOfOrderHits.cs @@ -24,7 +24,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Mania.Tests { - public class TestSceneOutOfOrderHits : RateAdjustedBeatmapTestScene + public partial class TestSceneOutOfOrderHits : RateAdjustedBeatmapTestScene { [Test] public void TestPreviousHitWindowDoesNotExtendPastNextObject() @@ -171,7 +171,7 @@ namespace osu.Game.Rulesets.Mania.Tests AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value); } - private class ScoreAccessibleReplayPlayer : ReplayPlayer + private partial class ScoreAccessibleReplayPlayer : ReplayPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; diff --git a/osu.Game.Rulesets.Mania.Tests/TestScenePlayfieldCoveringContainer.cs b/osu.Game.Rulesets.Mania.Tests/TestScenePlayfieldCoveringContainer.cs index 64e7eafb1b..f497c88bcc 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestScenePlayfieldCoveringContainer.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestScenePlayfieldCoveringContainer.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Tests { - public class TestScenePlayfieldCoveringContainer : OsuTestScene + public partial class TestScenePlayfieldCoveringContainer : OsuTestScene { private readonly ScrollingTestContainer scrollingContainer; private readonly PlayfieldCoveringWrapper cover; diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs index 6387dac957..86499a7c6e 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneStage.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Tests { [TestFixture] - public class TestSceneStage : ManiaInputTestScene + public partial class TestSceneStage : ManiaInputTestScene { private const int columns = 4; diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs index 9f2e3d2502..81557c198d 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs @@ -24,7 +24,7 @@ using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Tests { [TestFixture] - public class TestSceneTimingBasedNoteColouring : OsuTestScene + public partial class TestSceneTimingBasedNoteColouring : OsuTestScene { private Bindable configTimingBasedNoteColouring; diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs index 52995b73f4..be1cc9a7fe 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditBodyPiece.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Mania.Skinning.Default; namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components { - public class EditBodyPiece : DefaultBodyPiece + public partial class EditBodyPiece : DefaultBodyPiece { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs index 23475ef924..ef7ce9073c 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/Components/EditNotePiece.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Mania.Skinning.Default; namespace osu.Game.Rulesets.Mania.Edit.Blueprints.Components { - public class EditNotePiece : CompositeDrawable + public partial class EditNotePiece : CompositeDrawable { public EditNotePiece() { diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs index 7c720b30aa..21beee0769 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs @@ -16,7 +16,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public class HoldNotePlacementBlueprint : ManiaPlacementBlueprint + public partial class HoldNotePlacementBlueprint : ManiaPlacementBlueprint { private readonly EditBodyPiece bodyPiece; private readonly EditNotePiece headPiece; diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs index f76f170af0..8ec5213d5f 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNoteSelectionBlueprint.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public class HoldNoteSelectionBlueprint : ManiaSelectionBlueprint + public partial class HoldNoteSelectionBlueprint : ManiaSelectionBlueprint { [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs index 7c7c802111..5e0512b5dc 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs @@ -15,7 +15,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public abstract class ManiaPlacementBlueprint : PlacementBlueprint + public abstract partial class ManiaPlacementBlueprint : PlacementBlueprint where T : ManiaHitObject { protected new T HitObject => (T)base.HitObject; diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs index 5aa3b44f0d..cf4bca0030 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public abstract class ManiaSelectionBlueprint : HitObjectSelectionBlueprint + public abstract partial class ManiaSelectionBlueprint : HitObjectSelectionBlueprint where T : ManiaHitObject { [Resolved] diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/NotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NotePlacementBlueprint.cs index e3cb830b80..d77abca350 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/NotePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NotePlacementBlueprint.cs @@ -12,7 +12,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public class NotePlacementBlueprint : ManiaPlacementBlueprint + public partial class NotePlacementBlueprint : ManiaPlacementBlueprint { private readonly EditNotePiece piece; diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs index 929fdc29e0..a1392f09fa 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/NoteSelectionBlueprint.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Mania.Objects; namespace osu.Game.Rulesets.Mania.Edit.Blueprints { - public class NoteSelectionBlueprint : ManiaSelectionBlueprint + public partial class NoteSelectionBlueprint : ManiaSelectionBlueprint { public NoteSelectionBlueprint(Note note) : base(note) diff --git a/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditorRuleset.cs b/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditorRuleset.cs index a3a9591964..4a070e70b4 100644 --- a/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditorRuleset.cs +++ b/osu.Game.Rulesets.Mania/Edit/DrawableManiaEditorRuleset.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Mania.Edit { - public class DrawableManiaEditorRuleset : DrawableManiaRuleset + public partial class DrawableManiaEditorRuleset : DrawableManiaRuleset { public new IScrollingInfo ScrollingInfo => base.ScrollingInfo; diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaBeatSnapGrid.cs b/osu.Game.Rulesets.Mania/Edit/ManiaBeatSnapGrid.cs index b0019d8b6e..d1d5492b7a 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaBeatSnapGrid.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaBeatSnapGrid.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Edit /// /// A grid which displays coloured beat divisor lines in proximity to the selection or placement cursor. /// - public class ManiaBeatSnapGrid : Component + public partial class ManiaBeatSnapGrid : Component { private const double visible_range = 750; @@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.Mania.Edit } } - private class DrawableGridLine : DrawableHitObject + private partial class DrawableGridLine : DrawableHitObject { [Resolved] private IScrollingInfo scrollingInfo { get; set; } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs index f438d6497c..05d8ccc73f 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Mania.Edit { - public class ManiaBlueprintContainer : ComposeBlueprintContainer + public partial class ManiaBlueprintContainer : ComposeBlueprintContainer { public ManiaBlueprintContainer(HitObjectComposer composer) : base(composer) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaEditorPlayfield.cs b/osu.Game.Rulesets.Mania/Edit/ManiaEditorPlayfield.cs index 6683ab6bdc..0a697ca986 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaEditorPlayfield.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaEditorPlayfield.cs @@ -9,7 +9,7 @@ using System.Collections.Generic; namespace osu.Game.Rulesets.Mania.Edit { - public class ManiaEditorPlayfield : ManiaPlayfield + public partial class ManiaEditorPlayfield : ManiaPlayfield { public ManiaEditorPlayfield(List stages) : base(stages) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 3585fd4e8c..5e577a2964 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Edit { - public class ManiaHitObjectComposer : HitObjectComposer + public partial class ManiaHitObjectComposer : HitObjectComposer { private DrawableManiaEditorRuleset drawableRuleset; private ManiaBeatSnapGrid beatSnapGrid; diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index 7b9742a706..5e6ae9bb11 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Mania.Edit { - public class ManiaSelectionHandler : EditorSelectionHandler + public partial class ManiaSelectionHandler : EditorSelectionHandler { [Resolved] private HitObjectComposer composer { get; set; } diff --git a/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs b/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs index 81c41ab628..508733ad14 100644 --- a/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs +++ b/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Edit.Setup; namespace osu.Game.Rulesets.Mania.Edit.Setup { - public class ManiaSetupSection : RulesetSetupSection + public partial class ManiaSetupSection : RulesetSetupSection { private LabelledSwitchButton specialStyle; diff --git a/osu.Game.Rulesets.Mania/ManiaInputManager.cs b/osu.Game.Rulesets.Mania/ManiaInputManager.cs index e8e90d198a..9ad24d6256 100644 --- a/osu.Game.Rulesets.Mania/ManiaInputManager.cs +++ b/osu.Game.Rulesets.Mania/ManiaInputManager.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mania { [Cached] // Used for touch input, see ColumnTouchInputArea. - public class ManiaInputManager : RulesetInputManager + public partial class ManiaInputManager : RulesetInputManager { public ManiaInputManager(RulesetInfo ruleset, int variant) : base(ruleset, variant, SimultaneousBindingMode.Unique) diff --git a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs index e239068d1d..9ed555da51 100644 --- a/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs +++ b/osu.Game.Rulesets.Mania/ManiaSettingsSubsection.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania { - public class ManiaSettingsSubsection : RulesetSettingsSubsection + public partial class ManiaSettingsSubsection : RulesetSettingsSubsection { protected override LocalisableString Header => "osu!mania"; @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Mania }; } - private class ManiaScrollSlider : OsuSliderBar + private partial class ManiaScrollSlider : OsuSliderBar { public override LocalisableString TooltipText => $"{Current.Value}ms (speed {(int)Math.Round(DrawableManiaRuleset.MAX_TIME_RANGE / Current.Value)})"; } diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs index 947915cdf9..2539945c20 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Mods { - public class ManiaModFlashlight : ModFlashlight + public partial class ManiaModFlashlight : ModFlashlight { public override double ScoreMultiplier => 1; public override Type[] IncompatibleMods => new[] { typeof(ModHidden) }; @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Mania.Mods protected override Flashlight CreateFlashlight() => new ManiaFlashlight(this); - private class ManiaFlashlight : Flashlight + private partial class ManiaFlashlight : Flashlight { private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize); diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs index a607ed572d..8381b8b24b 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// Visualises a . Although this derives DrawableManiaHitObject, /// this does not handle input/sound like a normal hit object. /// - public class DrawableBarLine : DrawableManiaHitObject + public partial class DrawableBarLine : DrawableManiaHitObject { public DrawableBarLine(BarLine barLine) : base(barLine) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index 86d4ad0a36..759d2346e8 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// /// Visualises a hit object. /// - public class DrawableHoldNote : DrawableManiaHitObject, IKeyBindingHandler + public partial class DrawableHoldNote : DrawableManiaHitObject, IKeyBindingHandler { public override bool DisplayResult => false; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs index ac646ea427..1aa6ee2507 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// /// The head of a . /// - public class DrawableHoldNoteHead : DrawableNote + public partial class DrawableHoldNoteHead : DrawableNote { protected override ManiaSkinComponents Component => ManiaSkinComponents.HoldNoteHead; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs index 3084f71be2..bf477277c6 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// /// The tail of a . /// - public class DrawableHoldNoteTail : DrawableNote + public partial class DrawableHoldNoteTail : DrawableNote { /// /// Lenience of release hit windows. This is to make cases where the hold note release diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs index daec5ddbe7..ce6a83f79f 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTick.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// /// Visualises a hit object. /// - public class DrawableHoldNoteTick : DrawableManiaHitObject + public partial class DrawableHoldNoteTick : DrawableManiaHitObject { /// /// References the time at which the user started holding the hold note. diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 51f8ab1cf8..8498fd36de 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Objects.Drawables { - public abstract class DrawableManiaHitObject : DrawableHitObject + public abstract partial class DrawableManiaHitObject : DrawableHitObject { /// /// The which causes this to be hit. @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables public virtual void MissForcefully() => ApplyResult(r => r.Type = r.Judgement.MinResult); } - public abstract class DrawableManiaHitObject : DrawableManiaHitObject + public abstract partial class DrawableManiaHitObject : DrawableManiaHitObject where TObject : ManiaHitObject { public new TObject HitObject => (TObject)base.HitObject; diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index cf3149b065..0819e8401c 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables /// /// Visualises a hit object. /// - public class DrawableNote : DrawableManiaHitObject, IKeyBindingHandler + public partial class DrawableNote : DrawableManiaHitObject, IKeyBindingHandler { [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs index 3f0491e53f..5c6682ed73 100644 --- a/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mania.Scoring { - public class ManiaHealthProcessor : DrainingHealthProcessor + public partial class ManiaHealthProcessor : DrainingHealthProcessor { /// public ManiaHealthProcessor(double drainStartTime, double drainLenience = 0) diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs index dbf3d02955..f724972a29 100644 --- a/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs +++ b/osu.Game.Rulesets.Mania/Scoring/ManiaScoreProcessor.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mania.Scoring { - internal class ManiaScoreProcessor : ScoreProcessor + internal partial class ManiaScoreProcessor : ScoreProcessor { public ManiaScoreProcessor() : base(new ManiaRuleset()) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs index 598a765d3c..52e6079877 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonColumnBackground.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { - public class ArgonColumnBackground : CompositeDrawable, IKeyBindingHandler + public partial class ArgonColumnBackground : CompositeDrawable, IKeyBindingHandler { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs index af179d5580..e32de6f3f3 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitExplosion.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { - public class ArgonHitExplosion : CompositeDrawable, IHitExplosion + public partial class ArgonHitExplosion : CompositeDrawable, IHitExplosion { public override bool RemoveWhenNotAlive => true; diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs index 9e449623d5..4ffb4a435b 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHitTarget.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { - public class ArgonHitTarget : CompositeDrawable + public partial class ArgonHitTarget : CompositeDrawable { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs index 757190c4ae..1f52f5f15f 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldBodyPiece.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon /// /// Represents length-wise portion of a hold note. /// - public class ArgonHoldBodyPiece : CompositeDrawable, IHoldNoteBody + public partial class ArgonHoldBodyPiece : CompositeDrawable, IHoldNoteBody { protected readonly Bindable AccentColour = new Bindable(); protected readonly IBindable IsHitting = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs index 00cd37b6cf..a2166a6708 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonHoldNoteTailPiece.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { - internal class ArgonHoldNoteTailPiece : CompositeDrawable + internal partial class ArgonHoldNoteTailPiece : CompositeDrawable { private readonly IBindable direction = new Bindable(); private readonly IBindable accentColour = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs index e7dfec256d..2dbf475c7e 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { - public class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement { protected readonly HitResult Result; @@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon public Drawable? GetAboveHitObjectsProxiedContent() => null; - private class RingExplosion : CompositeDrawable + private partial class RingExplosion : CompositeDrawable { private readonly float travel = 52; @@ -169,7 +169,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon this.FadeOutFromOne(1000, Easing.OutQuint); } - public class RingPiece : CircularContainer + public partial class RingPiece : CircularContainer { public RingPiece(float thickness = 9) { diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs index 7670c9bdf2..95e24f8811 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonKeyArea.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { - public class ArgonKeyArea : CompositeDrawable, IKeyBindingHandler + public partial class ArgonKeyArea : CompositeDrawable, IKeyBindingHandler { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs index 454a6b012b..25b1965c18 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonNotePiece.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { - internal class ArgonNotePiece : CompositeDrawable + internal partial class ArgonNotePiece : CompositeDrawable { public const float NOTE_HEIGHT = 42; diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonStageBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonStageBackground.cs index 1881695b14..ec99177f98 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonStageBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonStageBackground.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Rulesets.Mania.Skinning.Argon { - public class ArgonStageBackground : CompositeDrawable + public partial class ArgonStageBackground : CompositeDrawable { public ArgonStageBackground() { diff --git a/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs index f0e214b190..9f5ee0846f 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultBodyPiece.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default /// /// Represents length-wise portion of a hold note. /// - public class DefaultBodyPiece : CompositeDrawable, IHoldNoteBody + public partial class DefaultBodyPiece : CompositeDrawable, IHoldNoteBody { protected readonly Bindable AccentColour = new Bindable(); protected readonly IBindable IsHitting = new Bindable(); @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default private void onAccentChanged(ValueChangedEvent accent) => Background.Colour = accent.NewValue.Opacity(0.7f); - private class ForegroundPiece : CompositeDrawable + private partial class ForegroundPiece : CompositeDrawable { public readonly Bindable AccentColour = new Bindable(); public readonly IBindable IsHitting = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs index 569740deee..e789335584 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Default/DefaultNotePiece.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Default /// /// Represents the static hit markers of notes. /// - internal class DefaultNotePiece : CompositeDrawable + internal partial class DefaultNotePiece : CompositeDrawable { public const float NOTE_HEIGHT = 12; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs index 3c89e2c04a..608cde7272 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/HitTargetInsetContainer.cs @@ -11,7 +11,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class HitTargetInsetContainer : Container + public partial class HitTargetInsetContainer : Container { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs index 52bca2aaa0..c928ebb3e0 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyBodyPiece.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyBodyPiece : LegacyManiaColumnElement + public partial class LegacyBodyPiece : LegacyManiaColumnElement { private DrawableHoldNote holdNote = null!; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs index 0ed96cf6f1..ab996519a7 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyColumnBackground.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyColumnBackground : LegacyManiaColumnElement, IKeyBindingHandler + public partial class LegacyColumnBackground : LegacyManiaColumnElement, IKeyBindingHandler { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.cs index 6b0e1e5d8a..6c56db613c 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitExplosion.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyHitExplosion : LegacyManiaColumnElement, IHitExplosion + public partial class LegacyHitExplosion : LegacyManiaColumnElement, IHitExplosion { public const double FADE_IN_DURATION = 80; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs index ed78cb6086..3a08a9d818 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHitTarget.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyHitTarget : CompositeDrawable + public partial class LegacyHitTarget : CompositeDrawable { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs index c3ed0111be..19c3d8e7f8 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteHeadPiece.cs @@ -6,7 +6,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyHoldNoteHeadPiece : LegacyNotePiece + public partial class LegacyHoldNoteHeadPiece : LegacyNotePiece { protected override Drawable? GetAnimation(ISkinSource skin) { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs index 13edc6e495..387c5b393a 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyHoldNoteTailPiece.cs @@ -8,7 +8,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyHoldNoteTailPiece : LegacyNotePiece + public partial class LegacyHoldNoteTailPiece : LegacyNotePiece { protected override void OnDirectionChanged(ValueChangedEvent direction) { diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs index e7dca3d946..48b92a8486 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyKeyArea.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyKeyArea : LegacyManiaColumnElement, IKeyBindingHandler + public partial class LegacyKeyArea : LegacyManiaColumnElement, IKeyBindingHandler { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs index 4ffef18781..7e3fb0438c 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaColumnElement.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy /// /// A which is placed somewhere within a . /// - public class LegacyManiaColumnElement : CompositeDrawable + public partial class LegacyManiaColumnElement : CompositeDrawable { [Resolved] protected Column Column { get; private set; } = null!; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs index 670a0aad6e..d21a8cd140 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyManiaJudgementPiece.cs @@ -13,7 +13,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyManiaJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class LegacyManiaJudgementPiece : CompositeDrawable, IAnimatableJudgement { private readonly HitResult result; private readonly Drawable animation; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs index 8c5a594b3b..4291ec3c13 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyNotePiece.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyNotePiece : LegacyManiaColumnElement + public partial class LegacyNotePiece : LegacyManiaColumnElement { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs index d039551cd7..758c8dd347 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageBackground.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyStageBackground : CompositeDrawable + public partial class LegacyStageBackground : CompositeDrawable { private Drawable leftSprite; private Drawable rightSprite; @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy rightSprite.Scale = new Vector2(1, DrawHeight / rightSprite.Height); } - private class ColumnBackground : CompositeDrawable + private partial class ColumnBackground : CompositeDrawable { private readonly int columnIndex; private readonly bool isLastColumn; diff --git a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs index 8e72e970ab..1a47fe5076 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Legacy/LegacyStageForeground.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.Skinning.Legacy { - public class LegacyStageForeground : CompositeDrawable + public partial class LegacyStageForeground : CompositeDrawable { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index de7424773b..6a31fb3fda 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -26,7 +26,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.UI { [Cached] - public class Column : ScrollingPlayfield, IKeyBindingHandler + public partial class Column : ScrollingPlayfield, IKeyBindingHandler { public const float COLUMN_WIDTH = 80; public const float SPECIAL_COLUMN_WIDTH = 70; @@ -185,7 +185,7 @@ namespace osu.Game.Rulesets.Mania.UI // This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border => DrawRectangle.Inflate(new Vector2(Stage.COLUMN_SPACING / 2, 0)).Contains(ToLocalSpace(screenSpacePos)); - public class ColumnTouchInputArea : Drawable + public partial class ColumnTouchInputArea : Drawable { private readonly Column column; diff --git a/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs b/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs index 9b3f6d7033..0bc0bf4caf 100644 --- a/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs +++ b/osu.Game.Rulesets.Mania/UI/ColumnFlow.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.UI /// Content can be added to individual columns via . /// /// The type of content in each column. - public class ColumnFlow : CompositeDrawable + public partial class ColumnFlow : CompositeDrawable where TContent : Drawable { /// diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs index e5a9ca1e85..c93be91a84 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs @@ -11,7 +11,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.UI.Components { - public class ColumnHitObjectArea : HitObjectArea + public partial class ColumnHitObjectArea : HitObjectArea { public readonly Container Explosions; diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs index 3680e7ea0a..fe34712c68 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultColumnBackground.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.UI.Components { - public class DefaultColumnBackground : CompositeDrawable, IKeyBindingHandler + public partial class DefaultColumnBackground : CompositeDrawable, IKeyBindingHandler { private readonly IBindable direction = new Bindable(); diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs index 97aa897782..bfc5fbc8f7 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultHitTarget.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.UI.Components { - public class DefaultHitTarget : CompositeDrawable + public partial class DefaultHitTarget : CompositeDrawable { private const float hit_target_bar_height = 2; diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs index 600c9feb73..77ab9f60c1 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultKeyArea.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.UI.Components { - public class DefaultKeyArea : CompositeDrawable, IKeyBindingHandler + public partial class DefaultKeyArea : CompositeDrawable, IKeyBindingHandler { private const float key_icon_size = 10; private const float key_icon_corner_radius = 3; diff --git a/osu.Game.Rulesets.Mania/UI/Components/DefaultStageBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/DefaultStageBackground.cs index 20d80580bf..ef34fc04ee 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/DefaultStageBackground.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/DefaultStageBackground.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.UI.Components { - public class DefaultStageBackground : CompositeDrawable + public partial class DefaultStageBackground : CompositeDrawable { public DefaultStageBackground() { diff --git a/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs index 7f4b8eacde..41b2dba173 100644 --- a/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs +++ b/osu.Game.Rulesets.Mania/UI/Components/HitObjectArea.cs @@ -14,7 +14,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.UI.Components { - public class HitObjectArea : SkinReloadableDrawable + public partial class HitObjectArea : SkinReloadableDrawable { protected readonly IBindable Direction = new Bindable(); public readonly HitObjectContainer HitObjectContainer; diff --git a/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs index 59716ee3e2..e0663e9878 100644 --- a/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/DefaultHitExplosion.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.UI { - public class DefaultHitExplosion : CompositeDrawable, IHitExplosion + public partial class DefaultHitExplosion : CompositeDrawable, IHitExplosion { private const float default_large_faint_size = 0.8f; diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs index 923fc6863c..896dfb2b23 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Mania.UI { - public class DrawableManiaJudgement : DrawableJudgement + public partial class DrawableManiaJudgement : DrawableJudgement { public DrawableManiaJudgement(JudgementResult result, DrawableHitObject judgedObject) : base(result, judgedObject) @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.UI protected override Drawable CreateDefaultJudgement(HitResult result) => new DefaultManiaJudgementPiece(result); - private class DefaultManiaJudgementPiece : DefaultJudgementPiece + private partial class DefaultManiaJudgementPiece : DefaultJudgementPiece { public DefaultManiaJudgementPiece(HitResult result) : base(result) diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index ea3b438ec8..af8758fb5e 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -30,7 +30,7 @@ using osu.Game.Scoring; namespace osu.Game.Rulesets.Mania.UI { - public class DrawableManiaRuleset : DrawableScrollingRuleset + public partial class DrawableManiaRuleset : DrawableScrollingRuleset { /// /// The minimum time range. This occurs at a of 40. diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 99b36bd366..01e9926ad7 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.UI { [Cached] - public class ManiaPlayfield : ScrollingPlayfield + public partial class ManiaPlayfield : ScrollingPlayfield { public IReadOnlyList Stages => stages; diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfieldAdjustmentContainer.cs index 8020fcb3cc..d4621ab8f3 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfieldAdjustmentContainer.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mania.UI { - public class ManiaPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer + public partial class ManiaPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer { public ManiaPlayfieldAdjustmentContainer() { diff --git a/osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs b/osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs index 87d6c25ac2..56ac38a737 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Mania.UI { - public class ManiaReplayRecorder : ReplayRecorder + public partial class ManiaReplayRecorder : ReplayRecorder { public ManiaReplayRecorder(Score score) : base(score) diff --git a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs index d397e7cc18..46cba01771 100644 --- a/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs +++ b/osu.Game.Rulesets.Mania/UI/PlayfieldCoveringWrapper.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mania.UI /// /// A that has its contents partially hidden by an adjustable "cover". This is intended to be used in a playfield. /// - public class PlayfieldCoveringWrapper : CompositeDrawable + public partial class PlayfieldCoveringWrapper : CompositeDrawable { /// /// The complete cover, including gradient and fill. diff --git a/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs b/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs index 8e5c8f9b75..4f6a84c60b 100644 --- a/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs +++ b/osu.Game.Rulesets.Mania/UI/PoolableHitExplosion.cs @@ -11,7 +11,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mania.UI { - public class PoolableHitExplosion : PoolableDrawable + public partial class PoolableHitExplosion : PoolableDrawable { public const double DURATION = 200; diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index 8aeaa9cf35..fc38a96a35 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mania.UI /// /// A collection of s. /// - public class Stage : ScrollingPlayfield + public partial class Stage : ScrollingPlayfield { [Cached] public readonly StageDefinition Definition; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneHitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneHitCirclePlacementBlueprint.cs index 4d84d3e79f..587bd2de44 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneHitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneHitCirclePlacementBlueprint.cs @@ -13,7 +13,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneHitCirclePlacementBlueprint : PlacementBlueprintTestScene + public partial class TestSceneHitCirclePlacementBlueprint : PlacementBlueprintTestScene { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableHitCircle((HitCircle)hitObject); protected override PlacementBlueprint CreateBlueprint() => new HitCirclePlacementBlueprint(); diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneHitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneHitCircleSelectionBlueprint.cs index fde62c7a53..9ffbd25a40 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneHitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneHitCircleSelectionBlueprint.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneHitCircleSelectionBlueprint : SelectionBlueprintTestScene + public partial class TestSceneHitCircleSelectionBlueprint : SelectionBlueprintTestScene { private HitCircle hitCircle; private DrawableHitCircle drawableObject; @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddAssert("blueprint positioned over hitobject", () => blueprint.CirclePiece.Position == hitCircle.StackedPosition); } - private class TestBlueprint : HitCircleSelectionBlueprint + private partial class TestBlueprint : HitCircleSelectionBlueprint { public new HitCirclePiece CirclePiece => base.CirclePiece; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectBeatSnap.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectBeatSnap.cs index a8829ef88c..56894242c8 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectBeatSnap.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectBeatSnap.cs @@ -14,7 +14,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { [TestFixture] - public class TestSceneObjectBeatSnap : TestSceneOsuEditor + public partial class TestSceneObjectBeatSnap : TestSceneOsuEditor { private OsuPlayfield playfield; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs index 5c5384e0b7..e7ac38c20e 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectMerging.cs @@ -14,7 +14,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneObjectMerging : TestSceneOsuEditor + public partial class TestSceneObjectMerging : TestSceneOsuEditor { private OsuSelectionHandler selectionHandler => Editor.ChildrenOfType().First(); diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectObjectSnap.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectObjectSnap.cs index 6e8c7ff2bd..3b8a5a90a5 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectObjectSnap.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectObjectSnap.cs @@ -17,7 +17,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { [TestFixture] - public class TestSceneObjectObjectSnap : TestSceneOsuEditor + public partial class TestSceneObjectObjectSnap : TestSceneOsuEditor { private OsuPlayfield playfield; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs index 800e6c0711..8641663ce8 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuComposerSelection.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { [TestFixture] - public class TestSceneOsuComposerSelection : TestSceneOsuEditor + public partial class TestSceneOsuComposerSelection : TestSceneOsuEditor { protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false); diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs index 1b67fc2ca9..7579e8077b 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuDistanceSnapGrid.cs @@ -27,7 +27,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneOsuDistanceSnapGrid : OsuManualInputManagerTestScene + public partial class TestSceneOsuDistanceSnapGrid : OsuManualInputManagerTestScene { private const float beat_length = 100; @@ -217,7 +217,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor return Precision.AlmostEquals(expectedDistance, Vector2.Distance(snappedPosition, grid_position)); }); - private class SnappingCursorContainer : CompositeDrawable + private partial class SnappingCursorContainer : CompositeDrawable { public Func GetSnapPosition; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditor.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditor.cs index 859290dbec..41a099e6e9 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditor.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditor.cs @@ -9,7 +9,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests.Editor { [TestFixture] - public class TestSceneOsuEditor : EditorTestScene + public partial class TestSceneOsuEditor : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); } diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs index f9cea5761b..59146bc05e 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorGrids.cs @@ -15,7 +15,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneOsuEditorGrids : EditorTestScene + public partial class TestSceneOsuEditorGrids : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorSelectInvalidPath.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorSelectInvalidPath.cs index 536739bd48..bb29504ec3 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorSelectInvalidPath.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneOsuEditorSelectInvalidPath.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneOsuEditorSelectInvalidPath : EditorTestScene + public partial class TestSceneOsuEditorSelectInvalidPath : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs index 6d93c3fcf9..d1a04e28e5 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestScenePathControlPointVisualiser : OsuManualInputManagerTestScene + public partial class TestScenePathControlPointVisualiser : OsuManualInputManagerTestScene { private Slider slider; private PathControlPointVisualiser visualiser; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs index a177079b8c..112aab884b 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneSliderControlPointPiece : SelectionBlueprintTestScene + public partial class TestSceneSliderControlPointPiece : SelectionBlueprintTestScene { private Slider slider; private DrawableSlider drawableObject; @@ -349,7 +349,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor private void assertControlPointPosition(int index, Vector2 position) => AddAssert($"control point {index} at {position}", () => Precision.AlmostEquals(position, slider.Path.ControlPoints[index].Position, 1)); - private class TestSliderBlueprint : SliderSelectionBlueprint + private partial class TestSliderBlueprint : SliderSelectionBlueprint { public new SliderBodyPiece BodyPiece => base.BodyPiece; public new TestSliderCircleOverlay HeadOverlay => (TestSliderCircleOverlay)base.HeadOverlay; @@ -364,7 +364,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor protected override SliderCircleOverlay CreateCircleOverlay(Slider slider, SliderPosition position) => new TestSliderCircleOverlay(slider, position); } - private class TestSliderCircleOverlay : SliderCircleOverlay + private partial class TestSliderCircleOverlay : SliderCircleOverlay { public new HitCirclePiece CirclePiece => base.CirclePiece; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderLengthValidity.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderLengthValidity.cs index 31b593e816..77e828e80a 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderLengthValidity.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderLengthValidity.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { [TestFixture] - public class TestSceneSliderLengthValidity : TestSceneOsuEditor + public partial class TestSceneSliderLengthValidity : TestSceneOsuEditor { private OsuPlayfield playfield; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderPlacementBlueprint.cs index 5c3c537541..7542e00a94 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderPlacementBlueprint.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneSliderPlacementBlueprint : PlacementBlueprintTestScene + public partial class TestSceneSliderPlacementBlueprint : PlacementBlueprintTestScene { [SetUp] public void Setup() => Schedule(() => diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs index f84204f01c..ad740b2977 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneSliderSelectionBlueprint : SelectionBlueprintTestScene + public partial class TestSceneSliderSelectionBlueprint : SelectionBlueprintTestScene { private Slider slider; private DrawableSlider drawableObject; @@ -194,7 +194,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor private void checkControlPointSelected(int index, bool selected) => AddAssert($"control point {index} {(selected ? "selected" : "not selected")}", () => blueprint.ControlPointVisualiser.Pieces[index].IsSelected.Value == selected); - private class TestSliderBlueprint : SliderSelectionBlueprint + private partial class TestSliderBlueprint : SliderSelectionBlueprint { public new SliderBodyPiece BodyPiece => base.BodyPiece; public new TestSliderCircleOverlay HeadOverlay => (TestSliderCircleOverlay)base.HeadOverlay; @@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor protected override SliderCircleOverlay CreateCircleOverlay(Slider slider, SliderPosition position) => new TestSliderCircleOverlay(slider, position); } - private class TestSliderCircleOverlay : SliderCircleOverlay + private partial class TestSliderCircleOverlay : SliderCircleOverlay { public new HitCirclePiece CirclePiece => base.CirclePiece; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs index e864afe056..e9d50d5118 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSnapping.cs @@ -26,7 +26,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneSliderSnapping : EditorTestScene + public partial class TestSceneSliderSnapping : EditorTestScene { private const double beat_length = 1000; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs index 015952c59a..b2ac462c8f 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSplitting.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneSliderSplitting : EditorTestScene + public partial class TestSceneSliderSplitting : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs index 0601dc6068..53465d43c9 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderStreamConversion.cs @@ -15,7 +15,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneSliderStreamConversion : TestSceneOsuEditor + public partial class TestSceneSliderStreamConversion : TestSceneOsuEditor { private BindableBeatDivisor beatDivisor => (BindableBeatDivisor)Editor.Dependencies.Get(typeof(BindableBeatDivisor)); diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs index ef9e332253..bb8c52bdfc 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderVelocityAdjust.cs @@ -22,7 +22,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneSliderVelocityAdjust : OsuGameTestScene + public partial class TestSceneSliderVelocityAdjust : OsuGameTestScene { private Screens.Edit.Editor editor => Game.ScreenStack.CurrentScreen as Screens.Edit.Editor; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSpinnerPlacementBlueprint.cs index 53ef675cb3..6378097800 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSpinnerPlacementBlueprint.cs @@ -13,7 +13,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneSpinnerPlacementBlueprint : PlacementBlueprintTestScene + public partial class TestSceneSpinnerPlacementBlueprint : PlacementBlueprintTestScene { protected override DrawableHitObject CreateHitObject(HitObject hitObject) => new DrawableSpinner((Spinner)hitObject); diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSpinnerSelectionBlueprint.cs index a1b946dd4c..c899f58c5a 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSpinnerSelectionBlueprint.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Editor { - public class TestSceneSpinnerSelectionBlueprint : SelectionBlueprintTestScene + public partial class TestSceneSpinnerSelectionBlueprint : SelectionBlueprintTestScene { public TestSceneSpinnerSelectionBlueprint() { diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs index efe195d872..64d23090d0 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSliderScaling.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests.Editor { [TestFixture] - public class TestSliderScaling : TestSceneOsuEditor + public partial class TestSliderScaling : TestSceneOsuEditor { private OsuPlayfield playfield; diff --git a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs index b6c8103e3c..baaa24959f 100644 --- a/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/LegacyMainCirclePieceTest.cs @@ -18,7 +18,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { [HeadlessTest] - public class LegacyMainCirclePieceTest : OsuTestScene + public partial class LegacyMainCirclePieceTest : OsuTestScene { [Resolved] private IRenderer renderer { get; set; } = null!; @@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Tests AddAssert("check overlay sprite", () => piece.OverlaySprite?.Texture?.AssetName == expectedOverlay); } - private class TestLegacyMainCirclePiece : LegacyMainCirclePiece + private partial class TestLegacyMainCirclePiece : LegacyMainCirclePiece { public new Sprite? CircleSprite => base.CircleSprite.ChildrenOfType().DistinctBy(s => s.Texture.AssetName).SingleOrDefault(); public new Sprite? OverlaySprite => base.OverlaySprite.ChildrenOfType().DistinctBy(s => s.Texture.AssetName).SingleOrDefault(); diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs b/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs index d3cb3bcf59..82d7ac6bba 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/OsuModTestScene.cs @@ -5,7 +5,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public abstract class OsuModTestScene : ModTestScene + public abstract partial class OsuModTestScene : ModTestScene { protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); } diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs index 521c10c10c..88c81c7a39 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAlternate.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModAlternate : OsuModTestScene + public partial class TestSceneOsuModAlternate : OsuModTestScene { [Test] public void TestInputAlternating() => CreateModTest(new ModTestData diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs index 3563995234..8fdab9f1f9 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModAutoplay.cs @@ -15,7 +15,7 @@ using osu.Game.Rulesets.Osu.UI; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModAutoplay : OsuModTestScene + public partial class TestSceneOsuModAutoplay : OsuModTestScene { [Test] public void TestSpmUnaffectedByRateAdjust() diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs index 88b6b9dd56..472c341bdd 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs @@ -15,7 +15,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModDifficultyAdjust : OsuModTestScene + public partial class TestSceneOsuModDifficultyAdjust : OsuModTestScene { [Test] public void TestNoAdjustment() => CreateModTest(new ModTestData diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs index 8df8afe147..f895b91151 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDoubleTime.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModDoubleTime : OsuModTestScene + public partial class TestSceneOsuModDoubleTime : OsuModTestScene { [TestCase(0.5)] [TestCase(1.01)] diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFlashlight.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFlashlight.cs index 704a548c61..a353914cd5 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFlashlight.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModFlashlight : OsuModTestScene + public partial class TestSceneOsuModFlashlight : OsuModTestScene { [TestCase(600)] [TestCase(120)] diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs index 7d7b2d9071..57d2b94188 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModFreezeFrame.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModFreezeFrame : OsuModTestScene + public partial class TestSceneOsuModFreezeFrame : OsuModTestScene { [Test] public void TestFreezeFrame() diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs index e692f8ecbc..3f84ac6935 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModHidden.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModHidden : OsuModTestScene + public partial class TestSceneOsuModHidden : OsuModTestScene { [Test] public void TestDefaultBeatmapTest() => CreateModTest(new ModTestData diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs index 9b49e60363..8a5a7706d1 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMagnetised.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModMagnetised : OsuModTestScene + public partial class TestSceneOsuModMagnetised : OsuModTestScene { [TestCase(0.1f)] [TestCase(0.5f)] diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs index d7d24c99ee..ac341d73b8 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModMuted.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModMuted : OsuModTestScene + public partial class TestSceneOsuModMuted : OsuModTestScene { /// /// Ensures that a final volume combo of 0 (i.e. "always muted" mode) constantly plays metronome and completely mutes track. diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs index da6fac3269..9dfa76fc8e 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModNoScope.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModNoScope : OsuModTestScene + public partial class TestSceneOsuModNoScope : OsuModTestScene { [Test] public void TestVisibleDuringBreak() diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs index 985baa8cf5..f0496efc19 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModPerfect : ModPerfectTestScene + public partial class TestSceneOsuModPerfect : ModPerfectTestScene { protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRandom.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRandom.cs index c24ba6d530..060a845137 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRandom.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRandom.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModRandom : OsuModTestScene + public partial class TestSceneOsuModRandom : OsuModTestScene { [TestCase(1)] [TestCase(7)] diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRepel.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRepel.cs index 6bd41e2fa5..8a3d645b05 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRepel.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModRepel.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModRepel : OsuModTestScene + public partial class TestSceneOsuModRepel : OsuModTestScene { [TestCase(0.1f)] [TestCase(0.5f)] diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSingleTap.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSingleTap.cs index 1aed84be10..402c680b46 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSingleTap.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSingleTap.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModSingleTap : OsuModTestScene + public partial class TestSceneOsuModSingleTap : OsuModTestScene { [Test] public void TestInputSingular() => CreateModTest(new ModTestData diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs index e121e6103d..de3ea5f148 100644 --- a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs +++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModSpunOut.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests.Mods { - public class TestSceneOsuModSpunOut : OsuModTestScene + public partial class TestSceneOsuModSpunOut : OsuModTestScene { protected override bool AllowFail => true; diff --git a/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs b/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs index 415e4ebedd..574618c528 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuSkinnableTestScene.cs @@ -9,7 +9,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { - public abstract class OsuSkinnableTestScene : SkinnableTestScene + public abstract partial class OsuSkinnableTestScene : SkinnableTestScene { private Container content; diff --git a/osu.Game.Rulesets.Osu.Tests/TestPlayfieldBorder.cs b/osu.Game.Rulesets.Osu.Tests/TestPlayfieldBorder.cs index 106a7f499f..5366a86bc0 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestPlayfieldBorder.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestPlayfieldBorder.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestPlayfieldBorder : OsuTestScene + public partial class TestPlayfieldBorder : OsuTestScene { public TestPlayfieldBorder() { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneAccuracyHeatmap.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneAccuracyHeatmap.cs index 805f4e6567..f99518997b 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneAccuracyHeatmap.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneAccuracyHeatmap.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneAccuracyHeatmap : OsuManualInputManagerTestScene + public partial class TestSceneAccuracyHeatmap : OsuManualInputManagerTestScene { private Box background; private Drawable object1; @@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Osu.Tests return true; } - private class TestAccuracyHeatmap : AccuracyHeatmap + private partial class TestAccuracyHeatmap : AccuracyHeatmap { public TestAccuracyHeatmap(ScoreInfo score) : base(score, new TestBeatmap(new OsuRuleset().RulesetInfo)) @@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Tests => base.AddPoint(start, end, hitPoint, radius); } - private class BorderCircle : CircularContainer + private partial class BorderCircle : CircularContainer { public BorderCircle() { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs index 7f0ecaca2b..f6e460284b 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorParticles.cs @@ -22,7 +22,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneCursorParticles : TestSceneOsuPlayer + public partial class TestSceneCursorParticles : TestSceneOsuPlayer { protected override bool Autoplay => autoplay; protected override bool HasCustomSteps => true; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs index 30f0891344..9582ee491b 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneCursorTrail.cs @@ -23,7 +23,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneCursorTrail : OsuTestScene + public partial class TestSceneCursorTrail : OsuTestScene { [Resolved] private IRenderer renderer { get; set; } @@ -83,7 +83,7 @@ namespace osu.Game.Rulesets.Osu.Tests }); [Cached(typeof(ISkinSource))] - private class LegacySkinContainer : Container, ISkinSource + private partial class LegacySkinContainer : Container, ISkinSource { private readonly IRenderer renderer; private readonly bool disjoint; @@ -131,7 +131,7 @@ namespace osu.Game.Rulesets.Osu.Tests } } - private class MovingCursorInputManager : ManualInputManager + private partial class MovingCursorInputManager : ManualInputManager { public MovingCursorInputManager() { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs index cfa1841fb7..ff71300733 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneDrawableJudgement.cs @@ -22,7 +22,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneDrawableJudgement : OsuSkinnableTestScene + public partial class TestSceneDrawableJudgement : OsuSkinnableTestScene { [Resolved] private OsuConfigManager config { get; set; } @@ -106,7 +106,7 @@ namespace osu.Game.Rulesets.Osu.Tests }); } - private class TestDrawableOsuJudgement : DrawableOsuJudgement + private partial class TestDrawableOsuJudgement : DrawableOsuJudgement { public new SkinnableSprite Lighting => base.Lighting; public new SkinnableDrawable JudgementBody => base.JudgementBody; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs index 1e625cd4e6..eefaa3cae3 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneFollowPoints : OsuTestScene + public partial class TestSceneFollowPoints : OsuTestScene { private Container hitObjectContainer; private FollowPointRenderer followPointRenderer; @@ -278,7 +278,7 @@ namespace osu.Game.Rulesets.Osu.Tests private FollowPointConnection getGroup(int index) => followPointRenderer.ChildrenOfType().Single(c => c.Entry == getEntry(index)); - private class TestHitObjectContainer : Container + private partial class TestHitObjectContainer : Container { protected override int Compare(Drawable x, Drawable y) { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs index 628082c2a9..907422858e 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs @@ -28,7 +28,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneGameplayCursor : OsuSkinnableTestScene + public partial class TestSceneGameplayCursor : OsuSkinnableTestScene { [Cached] private GameplayState gameplayState; @@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Osu.Tests } } - private class ClickingCursorContainer : OsuCursorContainer + private partial class ClickingCursorContainer : OsuCursorContainer { private bool pressed; @@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.Tests } } - private class MovingCursorInputManager : ManualInputManager + private partial class MovingCursorInputManager : ManualInputManager { public MovingCursorInputManager() { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs index be224b88ce..a418df605f 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneHitCircle : OsuSkinnableTestScene + public partial class TestSceneHitCircle : OsuSkinnableTestScene { private int depthIndex; @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Osu.Tests Depth = depthIndex++ }; - protected class TestDrawableHitCircle : DrawableHitCircle + protected partial class TestDrawableHitCircle : DrawableHitCircle { private readonly bool auto; private readonly double hitOffset; @@ -131,7 +131,7 @@ namespace osu.Game.Rulesets.Osu.Tests } } - protected class TestOsuPlayfield : OsuPlayfield + protected partial class TestOsuPlayfield : OsuPlayfield { public TestOsuPlayfield() { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleApplication.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleApplication.cs index 0bc65ac8e6..bcbff20016 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleApplication.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleApplication.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneHitCircleApplication : OsuTestScene + public partial class TestSceneHitCircleApplication : OsuTestScene { [Test] public void TestApplyNewCircle() diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs index 20aed514db..71174e3295 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleArea.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneHitCircleArea : OsuManualInputManagerTestScene + public partial class TestSceneHitCircleArea : OsuManualInputManagerTestScene { private HitCircle hitCircle; private DrawableHitCircle drawableHitCircle; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs index 85951a95a2..34c67e8b9c 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleComboChange.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneHitCircleComboChange : TestSceneHitCircle + public partial class TestSceneHitCircleComboChange : TestSceneHitCircle { private readonly Bindable comboIndex = new Bindable(); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleHidden.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleHidden.cs index a469f3dd99..b3498b9651 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleHidden.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleHidden.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneHitCircleHidden : TestSceneHitCircle + public partial class TestSceneHitCircleHidden : TestSceneHitCircle { [SetUp] public void SetUp() => Schedule(() => diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs index e694871408..2c9f1acd2c 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleKiai.cs @@ -10,7 +10,7 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneHitCircleKiai : TestSceneHitCircle + public partial class TestSceneHitCircleKiai : TestSceneHitCircle { [SetUp] public void SetUp() => Schedule(() => diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs index bcf2449e32..93f1123341 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircleLongCombo.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneHitCircleLongCombo : TestSceneOsuPlayer + public partial class TestSceneHitCircleLongCombo : TestSceneOsuPlayer { protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs index bb28b2b217..e70d45fb45 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneLegacyBeatmapSkin : LegacyBeatmapSkinColourTest + public partial class TestSceneLegacyBeatmapSkin : LegacyBeatmapSkinColourTest { [Resolved] private AudioManager audio { get; set; } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs index 0c6afe6c3d..0d3fd77568 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneMissHitWindowJudgements : ModTestScene + public partial class TestSceneMissHitWindowJudgements : ModTestScene { protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs index 9e524a1608..1f0e264cf7 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneNoSpinnerStacking.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneNoSpinnerStacking : TestSceneOsuPlayer + public partial class TestSceneNoSpinnerStacking : TestSceneOsuPlayer { protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) { diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs index ed1891b7d9..5d9316a21b 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneObjectOrderedHitPolicy.cs @@ -28,7 +28,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneObjectOrderedHitPolicy : RateAdjustedBeatmapTestScene + public partial class TestSceneObjectOrderedHitPolicy : RateAdjustedBeatmapTestScene { private const double early_miss_window = 1000; // time after -1000 to -500 is considered a miss private const double late_miss_window = 500; // time after +500 is considered a miss @@ -474,7 +474,7 @@ namespace osu.Game.Rulesets.Osu.Tests protected override DifficultyRange[] GetRanges() => ranges; } - private class ScoreAccessibleReplayPlayer : ReplayPlayer + private partial class ScoreAccessibleReplayPlayer : ReplayPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuHitObjectSamples.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuHitObjectSamples.cs index 3bc55278d9..4d0b2cc406 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuHitObjectSamples.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuHitObjectSamples.cs @@ -10,7 +10,7 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneOsuHitObjectSamples : HitObjectSampleTest + public partial class TestSceneOsuHitObjectSamples : HitObjectSampleTest { protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs index 6f378fc8b4..53c4e49807 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuPlayer.cs @@ -9,7 +9,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneOsuPlayer : PlayerTestScene + public partial class TestSceneOsuPlayer : PlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs index e0d33c0e09..b66974d4b1 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneResumeOverlay.cs @@ -12,7 +12,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneResumeOverlay : OsuManualInputManagerTestScene + public partial class TestSceneResumeOverlay : OsuManualInputManagerTestScene { public TestSceneResumeOverlay() { @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.Tests AddAssert("dismissed", () => resumeFired && resume.State.Value == Visibility.Hidden); } - private class ManualOsuInputManager : OsuInputManager + private partial class ManualOsuInputManager : OsuInputManager { public ManualOsuInputManager(RulesetInfo ruleset) : base(ruleset) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs index dd767bf5e0..bee7831625 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneShaking : TestSceneHitCircle + public partial class TestSceneShaking : TestSceneHitCircle { private readonly List scheduledTasks = new List(); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs index 878150e467..09b906cb10 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs @@ -29,7 +29,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneSkinFallbacks : TestSceneOsuPlayer + public partial class TestSceneSkinFallbacks : TestSceneOsuPlayer { private readonly TestSource testUserSkin; private readonly TestSource testBeatmapSkin; @@ -119,7 +119,7 @@ namespace osu.Game.Rulesets.Osu.Tests protected override ISkin GetSkin() => skin; } - public class SkinProvidingPlayer : TestPlayer + public partial class SkinProvidingPlayer : TestPlayer { private readonly TestSource userSkin; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs index a9ee276a9e..32d0cc8939 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSlider.cs @@ -26,7 +26,7 @@ using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneSlider : OsuSkinnableTestScene + public partial class TestSceneSlider : OsuSkinnableTestScene { private int depthIndex; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs index 728aa27da2..88b70a8836 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderApplication.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneSliderApplication : OsuTestScene + public partial class TestSceneSliderApplication : OsuTestScene { [Resolved] private SkinManager skinManager { get; set; } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs index b48789a709..dc8842a20a 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderComboChange.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneSliderComboChange : TestSceneSlider + public partial class TestSceneSliderComboChange : TestSceneSlider { private readonly Bindable comboIndex = new Bindable(); diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs index 7a6e19575e..0af0ff5604 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { [HeadlessTest] - public class TestSceneSliderFollowCircleInput : RateAdjustedBeatmapTestScene + public partial class TestSceneSliderFollowCircleInput : RateAdjustedBeatmapTestScene { private List? judgementResults; private ScoreAccessibleReplayPlayer? currentPlayer; @@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Tests AddUntilStep("Wait for completion", () => currentPlayer?.ScoreProcessor.HasCompleted.Value == true); } - private class ScoreAccessibleReplayPlayer : ReplayPlayer + private partial class ScoreAccessibleReplayPlayer : ReplayPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderHidden.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderHidden.cs index f70bdf8aa2..eb13995ad0 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderHidden.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderHidden.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneSliderHidden : TestSceneSlider + public partial class TestSceneSliderHidden : TestSceneSlider { [SetUp] public void SetUp() => Schedule(() => diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs index e3cf5e9b05..5f27cdc191 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneSliderInput : RateAdjustedBeatmapTestScene + public partial class TestSceneSliderInput : RateAdjustedBeatmapTestScene { private const double time_before_slider = 250; private const double time_slider_start = 1500; @@ -384,7 +384,7 @@ namespace osu.Game.Rulesets.Osu.Tests AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value); } - private class ScoreAccessibleReplayPlayer : ReplayPlayer + private partial class ScoreAccessibleReplayPlayer : ReplayPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs index 0118ed6513..630049f408 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSnaking.cs @@ -30,7 +30,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneSliderSnaking : TestSceneOsuPlayer + public partial class TestSceneSliderSnaking : TestSceneOsuPlayer { [Resolved] private AudioManager audioManager { get; set; } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs index 1cb64b71fc..d5d3cbb146 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSmoke.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneSmoke : OsuSkinnableTestScene + public partial class TestSceneSmoke : OsuSkinnableTestScene { [Test] public void TestSmoking() @@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Osu.Tests }); } - private class SmokingInputManager : ManualInputManager + private partial class SmokingInputManager : ManualInputManager { public double Duration { get; init; } @@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Tests } } - private class TestSmokeContainer : SmokeContainer + private partial class TestSmokeContainer : SmokeContainer { public double Duration { get; init; } diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs index 8dc8f82b86..74d0fb42a3 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneSpinner : OsuSkinnableTestScene + public partial class TestSceneSpinner : OsuSkinnableTestScene { private int depthIndex; @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.Osu.Tests return drawableSpinner; } - private class TestDrawableSpinner : DrawableSpinner + private partial class TestDrawableSpinner : DrawableSpinner { private readonly bool auto; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerApplication.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerApplication.cs index 14fa77245a..1ae17432be 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerApplication.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerApplication.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneSpinnerApplication : OsuTestScene + public partial class TestSceneSpinnerApplication : OsuTestScene { [Test] public void TestApplyNewSpinner() diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerHidden.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerHidden.cs index b7bc36722a..1aaba23e56 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerHidden.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerHidden.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Rulesets.Osu.Tests { [TestFixture] - public class TestSceneSpinnerHidden : TestSceneSpinner + public partial class TestSceneSpinnerHidden : TestSceneSpinner { [SetUp] public void SetUp() => Schedule(() => diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs index 13ea46eadf..116c974f32 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs @@ -26,7 +26,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneSpinnerRotation : TestSceneOsuPlayer + public partial class TestSceneSpinnerRotation : TestSceneOsuPlayer { private const double spinner_start_time = 100; private const double spinner_duration = 6000; @@ -221,7 +221,7 @@ namespace osu.Game.Rulesets.Osu.Tests } }; - private class ScoreExposedPlayer : TestPlayer + private partial class ScoreExposedPlayer : TestPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneStartTimeOrderedHitPolicy.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneStartTimeOrderedHitPolicy.cs index 96b26403e1..29e6fc4301 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneStartTimeOrderedHitPolicy.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneStartTimeOrderedHitPolicy.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneStartTimeOrderedHitPolicy : RateAdjustedBeatmapTestScene + public partial class TestSceneStartTimeOrderedHitPolicy : RateAdjustedBeatmapTestScene { private const double early_miss_window = 1000; // time after -1000 to -500 is considered a miss private const double late_miss_window = 500; // time after +500 is considered a miss @@ -434,7 +434,7 @@ namespace osu.Game.Rulesets.Osu.Tests protected override DifficultyRange[] GetRanges() => ranges; } - private class ScoreAccessibleReplayPlayer : ReplayPlayer + private partial class ScoreAccessibleReplayPlayer : ReplayPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneTrianglesSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneTrianglesSpinnerRotation.cs index 80e3af6cc0..1fef408088 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneTrianglesSpinnerRotation.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneTrianglesSpinnerRotation.cs @@ -28,7 +28,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneTrianglesSpinnerRotation : TestSceneOsuPlayer + public partial class TestSceneTrianglesSpinnerRotation : TestSceneOsuPlayer { private const double spinner_start_time = 100; private const double spinner_duration = 6000; @@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Osu.Tests } }; - private class ScoreExposedPlayer : TestPlayer + private partial class ScoreExposedPlayer : TestPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs index 55b7efc8af..41ab5a81b8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/BlueprintPiece.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints /// A piece of a selection or placement blueprint which visualises an . /// /// The type of which this visualises. - public abstract class BlueprintPiece : CompositeDrawable + public abstract partial class BlueprintPiece : CompositeDrawable where T : OsuHitObject { /// diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs index f16b6c138e..e5cc8595d1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCircleOverlapMarker.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components { - public class HitCircleOverlapMarker : BlueprintPiece + public partial class HitCircleOverlapMarker : BlueprintPiece { /// /// Hit objects are intentionally made to fade out at a constant slower rate than in gameplay. diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs index 984fbb83a8..1fed19da03 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/Components/HitCirclePiece.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components { - public class HitCirclePiece : BlueprintPiece + public partial class HitCirclePiece : BlueprintPiece { public HitCirclePiece() { diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs index ff4f61986f..26d18c7a17 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs @@ -11,7 +11,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { - public class HitCirclePlacementBlueprint : PlacementBlueprint + public partial class HitCirclePlacementBlueprint : PlacementBlueprint { public new HitCircle HitObject => (HitCircle)base.HitObject; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs index 73756d9326..1b3e7f3a8f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCircleSelectionBlueprint.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles { - public class HitCircleSelectionBlueprint : OsuSelectionBlueprint + public partial class HitCircleSelectionBlueprint : OsuSelectionBlueprint { protected new DrawableHitCircle DrawableObject => (DrawableHitCircle)base.DrawableObject; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs index 11527c9537..3e161089cd 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Edit; namespace osu.Game.Rulesets.Osu.Edit.Blueprints { - public abstract class OsuSelectionBlueprint : HitObjectSelectionBlueprint + public abstract partial class OsuSelectionBlueprint : HitObjectSelectionBlueprint where T : OsuHitObject { [Resolved] diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs index 0b9ccc5c37..28e0d650c4 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// /// A visualisation of the line between two s. /// - public class PathControlPointConnectionPiece : CompositeDrawable + public partial class PathControlPointConnectionPiece : CompositeDrawable { public readonly PathControlPoint ControlPoint; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index 5dec5d1cb0..d83f35d13f 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// /// A visualisation of a single in a . /// - public class PathControlPointPiece : BlueprintPiece, IHasTooltip + public partial class PathControlPointPiece : BlueprintPiece, IHasTooltip { public Action RequestSelection; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index c7e3516d62..3a175888d9 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -29,7 +29,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler, IHasContextMenu + public partial class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler, IHasContextMenu { public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; // allow context menu to appear outside of the playfield. diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs index da2a6ced67..ecd840dda6 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/SliderBodyPiece.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components { - public class SliderBodyPiece : BlueprintPiece + public partial class SliderBodyPiece : BlueprintPiece { private readonly ManualSliderBody body; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleOverlay.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleOverlay.cs index d48d43d532..3341a632c1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleOverlay.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleOverlay.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderCircleOverlay : CompositeDrawable + public partial class SliderCircleOverlay : CompositeDrawable { protected readonly HitCirclePiece CirclePiece; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index dd5335a743..f91d35e2e1 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderPlacementBlueprint : PlacementBlueprint + public partial class SliderPlacementBlueprint : PlacementBlueprint { public new Slider HitObject => (Slider)base.HitObject; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index 3718f0c6bc..a51c223785 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -29,7 +29,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { - public class SliderSelectionBlueprint : OsuSelectionBlueprint + public partial class SliderSelectionBlueprint : OsuSelectionBlueprint { protected new DrawableSlider DrawableObject => (DrawableSlider)base.DrawableObject; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs index b5a13a22ce..cc58acdc80 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/Components/SpinnerPiece.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components { - public class SpinnerPiece : BlueprintPiece + public partial class SpinnerPiece : BlueprintPiece { private readonly Circle circle; private readonly Circle ring; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index 97d53d8e95..e412c47c09 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -14,7 +14,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { - public class SpinnerPlacementBlueprint : PlacementBlueprint + public partial class SpinnerPlacementBlueprint : PlacementBlueprint { public new Spinner HitObject => (Spinner)base.HitObject; diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs index 5240c0bfeb..a80ec68c10 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerSelectionBlueprint.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners { - public class SpinnerSelectionBlueprint : OsuSelectionBlueprint + public partial class SpinnerSelectionBlueprint : OsuSelectionBlueprint { private readonly SpinnerPiece piece; diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs index a5f7707cb3..14e7b93f3a 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit { - public class DrawableOsuEditorRuleset : DrawableOsuRuleset + public partial class DrawableOsuEditorRuleset : DrawableOsuRuleset { public DrawableOsuEditorRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList mods) : base(ruleset, beatmap, mods) @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Edit public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer() => new OsuPlayfieldAdjustmentContainer { Size = Vector2.One }; - private class OsuEditorPlayfield : OsuPlayfield + private partial class OsuEditorPlayfield : OsuPlayfield { protected override GameplayCursorContainer CreateCursor() => null; diff --git a/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs index c0fb0ae7db..173a664902 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Osu.Edit { - public class OsuBlueprintContainer : ComposeBlueprintContainer + public partial class OsuBlueprintContainer : ComposeBlueprintContainer { public OsuBlueprintContainer(HitObjectComposer composer) : base(composer) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs index 23bf67ff29..848c994974 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Osu.Edit { - public class OsuDistanceSnapGrid : CircularDistanceSnapGrid + public partial class OsuDistanceSnapGrid : CircularDistanceSnapGrid { public OsuDistanceSnapGrid(OsuHitObject hitObject, [CanBeNull] OsuHitObject nextHitObject = null) : base(hitObject, hitObject.StackedEndPosition, hitObject.GetEndTime(), nextHitObject?.StartTime - 1) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 1460fae4d7..09ddc420a7 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -30,7 +30,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit { - public class OsuHitObjectComposer : DistancedHitObjectComposer + public partial class OsuHitObjectComposer : DistancedHitObjectComposer { public OsuHitObjectComposer(Ruleset ruleset) : base(ruleset) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuRectangularPositionSnapGrid.cs b/osu.Game.Rulesets.Osu/Edit/OsuRectangularPositionSnapGrid.cs index 35dad1a4fb..3234b03a3e 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuRectangularPositionSnapGrid.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuRectangularPositionSnapGrid.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Edit { - public class OsuRectangularPositionSnapGrid : RectangularPositionSnapGrid, IKeyBindingHandler + public partial class OsuRectangularPositionSnapGrid : RectangularPositionSnapGrid, IKeyBindingHandler { private static readonly int[] grid_sizes = { 4, 8, 16, 32 }; diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index eddc1390f0..6d5280e528 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -22,7 +22,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Osu.Edit { - public class OsuSelectionHandler : EditorSelectionHandler + public partial class OsuSelectionHandler : EditorSelectionHandler { [Resolved(CanBeNull = true)] private IDistanceSnapProvider? snapProvider { get; set; } diff --git a/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs b/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs index 2889832ff1..ac567559b8 100644 --- a/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs +++ b/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Edit.Setup; namespace osu.Game.Rulesets.Osu.Edit.Setup { - public class OsuSetupSection : RulesetSetupSection + public partial class OsuSetupSection : RulesetSetupSection { private LabelledSliderBar stackLeniency; diff --git a/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs b/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs index e4e8905722..7db4e2625b 100644 --- a/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs +++ b/osu.Game.Rulesets.Osu/Mods/InputBlockingMod.cs @@ -18,7 +18,7 @@ using osu.Game.Utils; namespace osu.Game.Rulesets.Osu.Mods { - public abstract class InputBlockingMod : Mod, IApplicableToDrawableRuleset, IUpdatableByPlayfield + public abstract partial class InputBlockingMod : Mod, IApplicableToDrawableRuleset, IUpdatableByPlayfield { public override double ScoreMultiplier => 1.0; public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModRelax), typeof(OsuModCinema) }; @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.Mods return false; } - private class InputInterceptor : Component, IKeyBindingHandler + private partial class InputInterceptor : Component, IKeyBindingHandler { private readonly InputBlockingMod mod; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 4c72667f15..2e2d320313 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModBlinds : Mod, IApplicableToDrawableRuleset, IApplicableToHealthProcessor + public partial class OsuModBlinds : Mod, IApplicableToDrawableRuleset, IApplicableToHealthProcessor { public override string Name => "Blinds"; public override LocalisableString Description => "Play with blinds on your screen."; @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Mods /// /// Element for the Blinds mod drawing 2 black boxes covering the whole screen which resize inside a restricted area with some leniency. /// - public class DrawableOsuBlinds : Container + public partial class DrawableOsuBlinds : Container { /// /// Black background boxes behind blind panel textures. @@ -204,7 +204,7 @@ namespace osu.Game.Rulesets.Osu.Mods /// public void AnimateClosedness(float value) => this.TransformTo(nameof(easing), value, 200, Easing.OutQuint); - public class ModBlindsPanel : Sprite + public partial class ModBlindsPanel : Sprite { [BackgroundDependencyLoader] private void load(TextureStore textures) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs index 1a86901d9c..efeac9a180 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModFlashlight : ModFlashlight, IApplicableToDrawableHitObject + public partial class OsuModFlashlight : ModFlashlight, IApplicableToDrawableHitObject { public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModBlinds)).ToArray(); @@ -53,7 +53,7 @@ namespace osu.Game.Rulesets.Osu.Mods s.Tracking.ValueChanged += flashlight.OnSliderTrackingChange; } - private class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition + private partial class OsuFlashlight : Flashlight, IRequireHighFrequencyMousePosition { private readonly double followDelay; diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs index af37f1e2e5..7e4ffc7408 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModStrictTracking.cs @@ -19,7 +19,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.Mods { - public class OsuModStrictTracking : Mod, IApplicableAfterBeatmapConversion, IApplicableToDrawableHitObject, IApplicableToDrawableRuleset + public partial class OsuModStrictTracking : Mod, IApplicableAfterBeatmapConversion, IApplicableToDrawableHitObject, IApplicableToDrawableRuleset { public override string Name => @"Strict Tracking"; public override string Acronym => @"ST"; @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Osu.Mods public override Judgement CreateJudgement() => new OsuJudgement(); } - private class StrictTrackingDrawableSliderTail : DrawableSliderTail + private partial class StrictTrackingDrawableSliderTail : DrawableSliderTail { public override bool DisplayResult => true; } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs index 8c95da9be1..d588127cb9 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPoint.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections /// /// A single follow point positioned between two adjacent s. /// - public class FollowPoint : PoolableDrawable, IAnimationTimeReference + public partial class FollowPoint : PoolableDrawable, IAnimationTimeReference { private const float width = 8; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs index 1a9d12e860..20c36b7804 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections /// /// Visualises the s between two s. /// - public class FollowPointConnection : PoolableDrawableWithLifetime + public partial class FollowPointConnection : PoolableDrawableWithLifetime { // Todo: These shouldn't be constants public const int SPACING = 32; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs index 306b034645..144eaffe82 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections /// /// Visualises connections between s. /// - public class FollowPointRenderer : PooledDrawableWithLifetimeContainer + public partial class FollowPointRenderer : PooledDrawableWithLifetimeContainer { public new IReadOnlyList Entries => lifetimeEntries; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs index 6201199cc3..3458069dd1 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableHitCircle : DrawableOsuHitObject, IHasApproachCircle + public partial class DrawableHitCircle : DrawableOsuHitObject, IHasApproachCircle { public OsuAction? HitAction => HitArea.HitAction; protected virtual OsuSkinComponents CirclePieceComponent => OsuSkinComponents.HitCircle; @@ -231,7 +231,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override JudgementResult CreateResult(Judgement judgement) => new OsuHitCircleJudgementResult(HitObject, judgement); - public class HitReceptor : CompositeDrawable, IKeyBindingHandler + public partial class HitReceptor : CompositeDrawable, IKeyBindingHandler { // IsHovered is used public override bool HandlePositionalInput => true; @@ -274,7 +274,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables } } - private class ProxyableSkinnableDrawable : SkinnableDrawable + private partial class ProxyableSkinnableDrawable : SkinnableDrawable { public override bool RemoveWhenNotAlive => false; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs index d9d0d28477..df0ba344d8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public abstract class DrawableOsuHitObject : DrawableHitObject + public abstract partial class DrawableOsuHitObject : DrawableHitObject { public readonly IBindable PositionBindable = new Bindable(); public readonly IBindable StackHeightBindable = new Bindable(); diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index b4abdde911..b4004ff572 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableOsuJudgement : DrawableJudgement + public partial class DrawableOsuJudgement : DrawableJudgement { protected SkinnableLighting Lighting { get; private set; } @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables protected override Drawable CreateDefaultJudgement(HitResult result) => new OsuJudgementPiece(result); - private class OsuJudgementPiece : DefaultJudgementPiece + private partial class OsuJudgementPiece : DefaultJudgementPiece { public OsuJudgementPiece(HitResult result) : base(result) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs index a4745b365b..4601af45d8 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSlider : DrawableOsuHitObject + public partial class DrawableSlider : DrawableOsuHitObject { public new Slider HitObject => (Slider)base.HitObject; @@ -327,7 +327,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => SliderBody?.ReceivePositionalInputAt(screenSpacePos) ?? base.ReceivePositionalInputAt(screenSpacePos); - private class DefaultSliderBody : PlaySliderBody + private partial class DefaultSliderBody : PlaySliderBody { } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs index 35d5c1f478..e1766adc20 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderBall.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderBall : CircularContainer, ISliderProgress, IRequireHighFrequencyMousePosition + public partial class DrawableSliderBall : CircularContainer, ISliderProgress, IRequireHighFrequencyMousePosition { public const float FOLLOW_AREA = 2.4f; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs index d1d749d7e2..b8a1efabe0 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderHead.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderHead : DrawableHitCircle + public partial class DrawableSliderHead : DrawableHitCircle { public new SliderHeadCircle HitObject => (SliderHeadCircle)base.HitObject; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs index 08602e168c..3446d41fb4 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderRepeat : DrawableOsuHitObject, ITrackSnaking + public partial class DrawableSliderRepeat : DrawableOsuHitObject, ITrackSnaking { public new SliderRepeat HitObject => (SliderRepeat)base.HitObject; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs index a59cd92d62..2c1b68e05a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTail.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking + public partial class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking { public new SliderTailCircle HitObject => (SliderTailCircle)base.HitObject; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs index 563c7e85aa..6d0ae93e62 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs @@ -14,7 +14,7 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSliderTick : DrawableOsuHitObject, IRequireTracking + public partial class DrawableSliderTick : DrawableOsuHitObject, IRequireTracking { public const double ANIM_DURATION = 150; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 83a9408570..eed5c3e2e3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -24,7 +24,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSpinner : DrawableOsuHitObject + public partial class DrawableSpinner : DrawableOsuHitObject { public new Spinner HitObject => (Spinner)base.HitObject; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerBonusTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerBonusTick.cs index 841f74b751..f1f4ec983e 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerBonusTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerBonusTick.cs @@ -5,7 +5,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSpinnerBonusTick : DrawableSpinnerTick + public partial class DrawableSpinnerBonusTick : DrawableSpinnerTick { public DrawableSpinnerBonusTick() : base(null) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs index 4975ca1248..b9ce07363c 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinnerTick.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class DrawableSpinnerTick : DrawableOsuHitObject + public partial class DrawableSpinnerTick : DrawableOsuHitObject { public override bool DisplayResult => false; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs index 4af4767a3e..68b61f9b2b 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/SkinnableLighting.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Objects.Drawables { - public class SkinnableLighting : SkinnableSprite + public partial class SkinnableLighting : SkinnableSprite { private DrawableHitObject targetObject; private JudgementResult targetResult; diff --git a/osu.Game.Rulesets.Osu/OsuInputManager.cs b/osu.Game.Rulesets.Osu/OsuInputManager.cs index 1e59e19246..7dede9e283 100644 --- a/osu.Game.Rulesets.Osu/OsuInputManager.cs +++ b/osu.Game.Rulesets.Osu/OsuInputManager.cs @@ -15,7 +15,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu { - public class OsuInputManager : RulesetInputManager + public partial class OsuInputManager : RulesetInputManager { public IEnumerable PressedActions => KeyBindingContainer.PressedActions; @@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Osu return base.HandleMouseTouchStateChange(e); } - private class OsuKeyBindingContainer : RulesetKeyBindingContainer + private partial class OsuKeyBindingContainer : RulesetKeyBindingContainer { private bool allowGameplayInputs = true; diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs index 34a1bd40e9..50d4eb6258 100644 --- a/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs +++ b/osu.Game.Rulesets.Osu/Scoring/OsuScoreProcessor.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Scoring { - public class OsuScoreProcessor : ScoreProcessor + public partial class OsuScoreProcessor : ScoreProcessor { public OsuScoreProcessor() : base(new OsuRuleset()) diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursor.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursor.cs index 446f3c83ae..4ca6abfdf7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursor.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursor.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonCursor : OsuCursorSprite + public partial class ArgonCursor : OsuCursorSprite { public ArgonCursor() { diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursorTrail.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursorTrail.cs index 9bb3122a3b..28991b4a62 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursorTrail.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonCursorTrail.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonCursorTrail : CursorTrail + public partial class ArgonCursorTrail : CursorTrail { protected override float IntervalMultiplier => 0.4f; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs index 83c5f6295a..95c75164aa 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowCircle.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonFollowCircle : FollowCircle + public partial class ArgonFollowCircle : FollowCircle { public ArgonFollowCircle() { diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowPoint.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowPoint.cs index 47dae3c30a..2f44264040 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowPoint.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonFollowPoint.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonFollowPoint : CompositeDrawable + public partial class ArgonFollowPoint : CompositeDrawable { public ArgonFollowPoint() { diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs index bb68c7298f..f5f410210b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement { protected readonly HitResult Result; @@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon public Drawable? GetAboveHitObjectsProxiedContent() => JudgementText.CreateProxy(); - private class RingExplosion : CompositeDrawable + private partial class RingExplosion : CompositeDrawable { private readonly float travel = 52; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs index 4ac71e4225..db458ec48a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonMainCirclePiece.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonMainCirclePiece : CompositeDrawable + public partial class ArgonMainCirclePiece : CompositeDrawable { public const float BORDER_THICKNESS = (OsuHitObject.OBJECT_RADIUS * 2) * (2f / 58); @@ -198,7 +198,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon drawableObject.ApplyCustomUpdateState -= updateStateTransforms; } - private class FlashPiece : Circle + private partial class FlashPiece : Circle { public FlashPiece() { diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs index 9d44db3614..f93e26b2ca 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonReverseArrow.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonReverseArrow : CompositeDrawable + public partial class ArgonReverseArrow : CompositeDrawable { private Bindable accentColour = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs index 3df9edd225..48b43f359d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBall.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonSliderBall : CircularContainer + public partial class ArgonSliderBall : CircularContainer { private readonly Box fill; private readonly SpriteIcon icon; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs index e1642d126d..c3d08116ac 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderBody.cs @@ -7,7 +7,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonSliderBody : PlaySliderBody + public partial class ArgonSliderBody : PlaySliderBody { protected override void LoadComplete() { @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon protected override Default.DrawableSliderPath CreateSliderPath() => new DrawableSliderPath(); - private class DrawableSliderPath : Default.DrawableSliderPath + private partial class DrawableSliderPath : Default.DrawableSliderPath { protected override Color4 ColourAt(float position) { diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs index 4c6b9a2f17..7479c2aced 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSliderScorePoint.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonSliderScorePoint : CircularContainer + public partial class ArgonSliderScorePoint : CircularContainer { private Bindable accentColour = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs index 95438e9588..d5a9cf46c5 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinner.cs @@ -15,7 +15,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonSpinner : CompositeDrawable + public partial class ArgonSpinner : CompositeDrawable { private DrawableSpinner drawableSpinner = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs index f99d4275bd..bdc93eb63f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerDisc.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonSpinnerDisc : CompositeDrawable + public partial class ArgonSpinnerDisc : CompositeDrawable { private const float initial_scale = 1f; private const float idle_alpha = 0.2f; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs index e998f55755..31cdc0dc0f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerProgressArc.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonSpinnerProgressArc : CompositeDrawable + public partial class ArgonSpinnerProgressArc : CompositeDrawable { private const float arc_fill = 0.15f; private const float arc_radius = 0.12f; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs index 57fb57a09e..702c5c2675 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerRingArc.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonSpinnerRingArc : CompositeDrawable + public partial class ArgonSpinnerRingArc : CompositeDrawable { private const float arc_fill = 0.31f; private const float arc_fill_complete = 0.50f; diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerTicks.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerTicks.cs index 0203432088..4f0e1256d4 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerTicks.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonSpinnerTicks.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public class ArgonSpinnerTicks : CompositeDrawable + public partial class ArgonSpinnerTicks : CompositeDrawable { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs index 4a679cda2c..f4761e0ea8 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/CirclePiece.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class CirclePiece : CompositeDrawable + public partial class CirclePiece : CompositeDrawable { [Resolved] private DrawableHitObject drawableObject { get; set; } = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs index 3a67ad526e..b65f46c414 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultApproachCircle.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class DefaultApproachCircle : SkinnableSprite + public partial class DefaultApproachCircle : SkinnableSprite { private readonly IBindable accentColour = new Bindable(); diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs index aaace89cd5..3c41d473f4 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultFollowCircle.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class DefaultFollowCircle : FollowCircle + public partial class DefaultFollowCircle : FollowCircle { public DefaultFollowCircle() { diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSliderBall.cs index 97bb4a3697..c911943bfb 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSliderBall.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSliderBall.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class DefaultSliderBall : CompositeDrawable + public partial class DefaultSliderBall : CompositeDrawable { private Box box = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmokeSegment.cs index 27a2dc3960..47c4bcc52c 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSmokeSegment.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class DefaultSmokeSegment : SmokeSegment + public partial class DefaultSmokeSegment : SmokeSegment { [BackgroundDependencyLoader] private void load(TextureStore textures) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinner.cs index a975030630..071fbe6add 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinner.cs @@ -15,7 +15,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class DefaultSpinner : CompositeDrawable + public partial class DefaultSpinner : CompositeDrawable { private DrawableSpinner drawableSpinner = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs index b58daf7174..75f3247448 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DefaultSpinnerDisc.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class DefaultSpinnerDisc : CompositeDrawable + public partial class DefaultSpinnerDisc : CompositeDrawable { private DrawableSpinner drawableSpinner = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs b/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs index 883524f334..6f41d33c3d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/DrawableSliderPath.cs @@ -6,7 +6,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public abstract class DrawableSliderPath : SmoothPath + public abstract partial class DrawableSliderPath : SmoothPath { public const float BORDER_PORTION = 0.128f; public const float GRADIENT_PORTION = 1 - BORDER_PORTION; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs index f8010a9971..91bf75617a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ExplodePiece.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class ExplodePiece : Container + public partial class ExplodePiece : Container { [Resolved] private DrawableHitObject drawableObject { get; set; } = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.cs index 06ee64d8b3..789137117e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/FlashPiece.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class FlashPiece : Container + public partial class FlashPiece : Container { public FlashPiece() { diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.cs index f5e01b802e..65cbdc3d2f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/GlowPiece.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class GlowPiece : Container + public partial class GlowPiece : Container { public GlowPiece() { diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/KiaiFlash.cs b/osu.Game.Rulesets.Osu/Skinning/Default/KiaiFlash.cs index 506f679836..11c2fd97e8 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/KiaiFlash.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/KiaiFlash.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class KiaiFlash : BeatSyncedContainer + public partial class KiaiFlash : BeatSyncedContainer { private const double fade_length = 80; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs index 6d56d21349..20fa4e5342 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class MainCirclePiece : CompositeDrawable + public partial class MainCirclePiece : CompositeDrawable { private readonly CirclePiece circle; private readonly RingPiece ring; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.cs index d73c94eb9b..d171f56f40 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ManualSliderBody.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default /// /// A with the ability to set the drawn vertices manually. /// - public class ManualSliderBody : SliderBody + public partial class ManualSliderBody : SliderBody { public new void SetVertices(IReadOnlyList vertices) { diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs index 60cfecfb5a..eb49b7b852 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/NumberPiece.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class NumberPiece : Container + public partial class NumberPiece : Container { private readonly SkinnableSpriteText number; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs index 96af59abe2..539777dd6b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public abstract class PlaySliderBody : SnakingSliderBody + public abstract partial class PlaySliderBody : SnakingSliderBody { protected IBindable ScaleBindable { get; private set; } = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs index 222e8d4348..3fe7872ff7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/ReverseArrowPiece.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class ReverseArrowPiece : BeatSyncedContainer + public partial class ReverseArrowPiece : BeatSyncedContainer { [Resolved] private DrawableHitObject drawableRepeat { get; set; } = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs index e813a7e274..46d48f62e7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/RingPiece.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class RingPiece : CircularContainer + public partial class RingPiece : CircularContainer { public RingPiece(float thickness = 9) { diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.cs index a1184a15cd..039c4825fa 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerBackgroundLayer.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class SpinnerBackgroundLayer : SpinnerFill + public partial class SpinnerBackgroundLayer : SpinnerFill { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.cs index 3dd5aed6ae..f5c90bafbf 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerCentreLayer.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class SpinnerCentreLayer : CompositeDrawable, IHasAccentColour + public partial class SpinnerCentreLayer : CompositeDrawable, IHasAccentColour { private DrawableSpinner spinner = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.cs index f574ae589e..93f93b8521 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerFill.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class SpinnerFill : CircularContainer, IHasAccentColour + public partial class SpinnerFill : CircularContainer, IHasAccentColour { public readonly Box Disc; diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs index 3a9f73404d..bf06f513b7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerRotationTracker.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class SpinnerRotationTracker : CircularContainer + public partial class SpinnerRotationTracker : CircularContainer { public override bool IsPresent => true; // handle input when hidden diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs index 9feaa0966a..0bd5fd4cac 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerSpmCalculator.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class SpinnerSpmCalculator : Component + public partial class SpinnerSpmCalculator : Component { private readonly Queue records = new Queue(); private const double spm_count_duration = 595; // not using hundreds to avoid frame rounding issues diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.cs index e518ae1da8..f5f8d456f3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SpinnerTicks.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class SpinnerTicks : Container, IHasAccentColour + public partial class SpinnerTicks : Container, IHasAccentColour { public SpinnerTicks() { diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs index fa23c60d57..f1143cf14d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/TrianglesPiece.cs @@ -5,7 +5,7 @@ using osu.Game.Graphics.Backgrounds; namespace osu.Game.Rulesets.Osu.Skinning.Default { - public class TrianglesPiece : Triangles + public partial class TrianglesPiece : Triangles { protected override bool CreateNewTriangles => false; protected override float SpawnRatio => 0.5f; diff --git a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs index 9eb8e66c83..355d3f9a2f 100644 --- a/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/FollowCircle.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Skinning { - public abstract class FollowCircle : CompositeDrawable + public abstract partial class FollowCircle : CompositeDrawable { [Resolved] protected DrawableHitObject? ParentObject { get; private set; } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs index 4dd4f9562a..e9342bbdbb 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyApproachCircle.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyApproachCircle : SkinnableSprite + public partial class LegacyApproachCircle : SkinnableSprite { private readonly IBindable accentColour = new Bindable(); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs index b2ffc171be..b0c01d2925 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursor.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyCursor : OsuCursorSprite + public partial class LegacyCursor : OsuCursorSprite { private readonly ISkin skin; private bool spin; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs index a28b480753..e022e5534d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorParticles.cs @@ -23,7 +23,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler + public partial class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler { public bool Active => breakSpewer.Active.Value || kiaiSpewer.Active.Value; @@ -140,7 +140,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy breakSpewer.Direction = SpewDirection.None; } - private class LegacyCursorParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition + private partial class LegacyCursorParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition { private const int particle_duration_min = 300; private const int particle_duration_max = 1000; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs index 9a59fd73b2..af71e2a5d9 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyCursorTrail : CursorTrail + public partial class LegacyCursorTrail : CursorTrail { private readonly ISkin skin; private const double disjoint_trail_time_separation = 1000 / 60.0; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs index 0d12fb01f5..f8dcb9e8a2 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyFollowCircle.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyFollowCircle : FollowCircle + public partial class LegacyFollowCircle : FollowCircle { public LegacyFollowCircle(Drawable animationContent) { diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index e155c1b816..6547b058c2 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyMainCirclePiece : CompositeDrawable + public partial class LegacyMainCirclePiece : CompositeDrawable { public override bool RemoveCompletedTransforms => false; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs index f950d3e43e..67a6d5e41a 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyNewStyleSpinner.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy /// Legacy skinned spinner with two main spinning layers, one fixed overlay and one final spinning overlay. /// No background layer. /// - public class LegacyNewStyleSpinner : LegacySpinner + public partial class LegacyNewStyleSpinner : LegacySpinner { private Sprite glow = null!; private Sprite discBottom = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs index e5efb668bc..c57487cf75 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy /// /// Legacy skinned spinner with one main spinning layer and a background layer. /// - public class LegacyOldStyleSpinner : LegacySpinner + public partial class LegacyOldStyleSpinner : LegacySpinner { private Sprite disc = null!; private Sprite metreSprite = null!; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs index 773cc7ae3c..fbe094ef81 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyReverseArrow.cs @@ -11,7 +11,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacyReverseArrow : CompositeDrawable + public partial class LegacyReverseArrow : CompositeDrawable { [Resolved(canBeNull: true)] private DrawableHitObject? drawableHitObject { get; set; } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs index 60d71ae843..2aa843581e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBall.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacySliderBall : CompositeDrawable + public partial class LegacySliderBall : CompositeDrawable { private readonly Drawable animationContent; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs index 29a0745193..b39092a467 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacySliderBody : PlaySliderBody + public partial class LegacySliderBody : PlaySliderBody { protected override DrawableSliderPath CreateSliderPath() => new LegacyDrawableSliderPath(); @@ -21,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return base.GetBodyAccentColour(skin, hitObjectAccentColour).Opacity(0.7f); } - private class LegacyDrawableSliderPath : DrawableSliderPath + private partial class LegacyDrawableSliderPath : DrawableSliderPath { private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs index 08b579697c..bc69e66fb3 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderHeadHitCircle.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Osu.Objects.Drawables; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacySliderHeadHitCircle : LegacyMainCirclePiece + public partial class LegacySliderHeadHitCircle : LegacyMainCirclePiece { [Resolved(canBeNull: true)] private DrawableHitObject? drawableHitObject { get; set; } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmokeSegment.cs index c9c7e86e86..0e93ef7ad5 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySmokeSegment.cs @@ -6,7 +6,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public class LegacySmokeSegment : SmokeSegment + public partial class LegacySmokeSegment : SmokeSegment { [BackgroundDependencyLoader] private void load(ISkinSource skin) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs index 66b195962b..d8f837ae5e 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { - public abstract class LegacySpinner : CompositeDrawable, IHasApproachCircle + public abstract partial class LegacySpinner : CompositeDrawable, IHasApproachCircle { public const float SPRITE_SCALE = 0.625f; diff --git a/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.cs b/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.cs index 2a13f07cdb..548a14f5eb 100644 --- a/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.cs +++ b/osu.Game.Rulesets.Osu/Skinning/NonPlayfieldSprite.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Skinning /// A sprite which is displayed within the playfield, but historically was not considered part of the playfield. /// Performs scale adjustment to undo the scale applied by (osu! ruleset specifically). /// - public class NonPlayfieldSprite : Sprite + public partial class NonPlayfieldSprite : Sprite { public override Texture? Texture { diff --git a/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs index 1411b27c09..283687adfd 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SliderBody.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning { - public abstract class SliderBody : CompositeDrawable + public abstract partial class SliderBody : CompositeDrawable { private DrawableSliderPath path; @@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.Skinning protected virtual DrawableSliderPath CreateSliderPath() => new DefaultDrawableSliderPath(); - private class DefaultDrawableSliderPath : DrawableSliderPath + private partial class DefaultDrawableSliderPath : DrawableSliderPath { private const float opacity_at_centre = 0.3f; private const float opacity_at_edge = 0.8f; diff --git a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs index 66d74ae13e..a824f202ec 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SmokeSegment.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning { - public abstract class SmokeSegment : Drawable, ITexturedShaderDrawable + public abstract partial class SmokeSegment : Drawable, ITexturedShaderDrawable { // fade anim values private const double initial_fade_out_duration = 4000; diff --git a/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs index 8ba9e75d19..f8ee465cd6 100644 --- a/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/SnakingSliderBody.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Skinning /// /// A which changes its curve depending on the snaking progress. /// - public abstract class SnakingSliderBody : SliderBody, ISliderProgress + public abstract partial class SnakingSliderBody : SliderBody, ISliderProgress { public readonly List CurrentCurve = new List(); diff --git a/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs b/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs index acf32da73f..0249b6d9b1 100644 --- a/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs +++ b/osu.Game.Rulesets.Osu/Statistics/AccuracyHeatmap.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Statistics { - public class AccuracyHeatmap : CompositeDrawable + public partial class AccuracyHeatmap : CompositeDrawable { /// /// Size of the inner circle containing the "hit" points, relative to the size of this . @@ -233,7 +233,7 @@ namespace osu.Game.Rulesets.Osu.Statistics bufferedGrid.ForceRedraw(); } - private class HitPoint : Circle + private partial class HitPoint : Circle { /// /// The base colour which will be lightened/darkened depending on the value of this . diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 1b2ef23674..9ecabd1d5e 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -24,7 +24,7 @@ using osuTK.Graphics.ES30; namespace osu.Game.Rulesets.Osu.UI.Cursor { - public class CursorTrail : Drawable, IRequireHighFrequencyMousePosition + public partial class CursorTrail : Drawable, IRequireHighFrequencyMousePosition { private const int max_sprites = 2048; diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs index 6d435f01b0..66c86ee09d 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursor.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.UI.Cursor { - public class OsuCursor : SkinReloadableDrawable + public partial class OsuCursor : SkinReloadableDrawable { private const float size = 28; @@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor public void Contract() => expandTarget.ScaleTo(released_scale, 400, Easing.OutQuad); - private class DefaultCursor : OsuCursorSprite + private partial class DefaultCursor : OsuCursorSprite { public DefaultCursor() { diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 26fe08972e..5d7648b073 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.UI.Cursor { - public class OsuCursorContainer : GameplayCursorContainer, IKeyBindingHandler + public partial class OsuCursorContainer : GameplayCursorContainer, IKeyBindingHandler { protected override Drawable CreateCursor() => new OsuCursor(); @@ -165,7 +165,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor ActiveCursor.ScaleTo(CursorScale.Value * 0.8f, 450, Easing.OutQuint); } - private class DefaultCursorTrail : CursorTrail + private partial class DefaultCursorTrail : CursorTrail { [BackgroundDependencyLoader] private void load(TextureStore textures) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorSprite.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorSprite.cs index 03ef79a262..aaf8949084 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorSprite.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorSprite.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Rulesets.Osu.UI.Cursor { - public abstract class OsuCursorSprite : CompositeDrawable + public abstract partial class OsuCursorSprite : CompositeDrawable { /// /// The an optional piece of the cursor to expand when in a clicked state. diff --git a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs index 5f430dc921..d1fa0d09cc 100644 --- a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.UI { - public class DrawableOsuRuleset : DrawableRuleset + public partial class DrawableOsuRuleset : DrawableRuleset { protected new OsuRulesetConfigManager Config => (OsuRulesetConfigManager)base.Config; diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs index e9a6c84c0b..122330d09b 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfield.cs @@ -29,7 +29,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.UI { [Cached] - public class OsuPlayfield : Playfield + public partial class OsuPlayfield : Playfield { private readonly PlayfieldBorder playfieldBorder; private readonly ProxyContainer approachCircles; @@ -181,12 +181,12 @@ namespace osu.Game.Rulesets.Osu.UI public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => HitObjectContainer.ReceivePositionalInputAt(screenSpacePos); - private class ProxyContainer : LifetimeManagementContainer + private partial class ProxyContainer : LifetimeManagementContainer { public void Add(Drawable proxy) => AddInternal(proxy); } - private class DrawableJudgementPool : DrawablePool + private partial class DrawableJudgementPool : DrawablePool { private readonly HitResult result; private readonly Action onLoaded; diff --git a/osu.Game.Rulesets.Osu/UI/OsuPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Osu/UI/OsuPlayfieldAdjustmentContainer.cs index 80f4eb3000..b45d552c7f 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuPlayfieldAdjustmentContainer.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.UI { - public class OsuPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer + public partial class OsuPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer { protected override Container Content => content; private readonly ScalingContainer content; @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Osu.UI /// /// A which scales its content relative to a target width. /// - private class ScalingContainer : Container + private partial class ScalingContainer : Container { internal bool PlayfieldShift { get; set; } diff --git a/osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs b/osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs index 5964a9b9b6..66a4f467a9 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Osu.UI { - public class OsuReplayRecorder : ReplayRecorder + public partial class OsuReplayRecorder : ReplayRecorder { public OsuReplayRecorder(Score score) : base(score) diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs index 412505331b..e951197643 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.UI { - public class OsuResumeOverlay : ResumeOverlay + public partial class OsuResumeOverlay : ResumeOverlay { private Container cursorScaleContainer; private OsuClickToResumeCursor clickToResumeCursor; @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.UI protected override bool OnHover(HoverEvent e) => true; - public class OsuClickToResumeCursor : OsuCursor, IKeyBindingHandler + public partial class OsuClickToResumeCursor : OsuCursor, IKeyBindingHandler { public override bool HandlePositionalInput => true; diff --git a/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs b/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs index eff4b30362..f711a0fc31 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuSettingsSubsection.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Osu.UI { - public class OsuSettingsSubsection : RulesetSettingsSubsection + public partial class OsuSettingsSubsection : RulesetSettingsSubsection { protected override LocalisableString Header => "osu!"; diff --git a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs index bf5618dc90..389440ba2d 100644 --- a/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/SmokeContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.UI /// /// Manages smoke trails generated from user input. /// - public class SmokeContainer : Container, IRequireHighFrequencyMousePosition, IKeyBindingHandler + public partial class SmokeContainer : Container, IRequireHighFrequencyMousePosition, IKeyBindingHandler { private SmokeSkinnableDrawable? currentSegmentSkinnable; @@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Osu.UI private void addPosition() => (currentSegmentSkinnable?.Drawable as SmokeSegment)?.AddPosition(lastMousePosition, Time.Current); - private class SmokeSkinnableDrawable : SkinnableDrawable + private partial class SmokeSkinnableDrawable : SkinnableDrawable { public override bool RemoveWhenNotAlive => true; diff --git a/osu.Game.Rulesets.Taiko.Tests/DrawableTaikoRulesetTestScene.cs b/osu.Game.Rulesets.Taiko.Tests/DrawableTaikoRulesetTestScene.cs index 01719bfea6..a222fe8275 100644 --- a/osu.Game.Rulesets.Taiko.Tests/DrawableTaikoRulesetTestScene.cs +++ b/osu.Game.Rulesets.Taiko.Tests/DrawableTaikoRulesetTestScene.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests { - public abstract class DrawableTaikoRulesetTestScene : OsuTestScene + public abstract partial class DrawableTaikoRulesetTestScene : OsuTestScene { protected const int DEFAULT_PLAYFIELD_CONTAINER_HEIGHT = 768; diff --git a/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs b/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs index 6a585b840d..157a96eec8 100644 --- a/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables; namespace osu.Game.Rulesets.Taiko.Tests { - public class DrawableTestHit : DrawableHit + public partial class DrawableTestHit : DrawableHit { public readonly HitResult Type; diff --git a/osu.Game.Rulesets.Taiko.Tests/DrawableTestStrongHit.cs b/osu.Game.Rulesets.Taiko.Tests/DrawableTestStrongHit.cs index 7355e1dbca..747c599721 100644 --- a/osu.Game.Rulesets.Taiko.Tests/DrawableTestStrongHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/DrawableTestStrongHit.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables; namespace osu.Game.Rulesets.Taiko.Tests { - public class DrawableTestStrongHit : DrawableTestHit + public partial class DrawableTestStrongHit : DrawableTestHit { private readonly bool hitBoth; diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditor.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditor.cs index 5915b9fdfa..3ee9171e7e 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditor.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneEditor.cs @@ -9,7 +9,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Editor { [TestFixture] - public class TestSceneEditor : EditorTestScene + public partial class TestSceneEditor : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new TaikoRuleset(); } diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs index 06c06f6e28..93b26624de 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoEditorSaving.cs @@ -10,7 +10,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Editor { - public class TestSceneTaikoEditorSaving : EditorSavingTestScene + public partial class TestSceneTaikoEditorSaving : EditorSavingTestScene { protected override Ruleset CreateRuleset() => new TaikoRuleset(); diff --git a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs index 8d17918a92..ed73730c4a 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Editor/TestSceneTaikoHitObjectComposer.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Editor { - public class TestSceneTaikoHitObjectComposer : EditorClockTestScene + public partial class TestSceneTaikoHitObjectComposer : EditorClockTestScene { [SetUp] public void Setup() => Schedule(() => @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Editor { } - private class TestComposer : CompositeDrawable + private partial class TestComposer : CompositeDrawable { [Cached(typeof(EditorBeatmap))] [Cached(typeof(IBeatSnapProvider))] diff --git a/osu.Game.Rulesets.Taiko.Tests/HitObjectApplicationTestScene.cs b/osu.Game.Rulesets.Taiko.Tests/HitObjectApplicationTestScene.cs index 09a6a2f16c..e8688f36bc 100644 --- a/osu.Game.Rulesets.Taiko.Tests/HitObjectApplicationTestScene.cs +++ b/osu.Game.Rulesets.Taiko.Tests/HitObjectApplicationTestScene.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests { - public abstract class HitObjectApplicationTestScene : OsuTestScene + public abstract partial class HitObjectApplicationTestScene : OsuTestScene { [Cached(typeof(IScrollingInfo))] private ScrollingTestContainer.TestScrollingInfo info = new ScrollingTestContainer.TestScrollingInfo diff --git a/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs b/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs index 7f2f27b2b8..eb2d96ec51 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Judgements/JudgementTest.cs @@ -19,7 +19,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Judgements { - public class JudgementTest : RateAdjustedBeatmapTestScene + public partial class JudgementTest : RateAdjustedBeatmapTestScene { private ScoreAccessibleReplayPlayer currentPlayer = null!; protected List JudgementResults { get; private set; } = null!; @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Judgements return beatmap; } - private class ScoreAccessibleReplayPlayer : ReplayPlayer + private partial class ScoreAccessibleReplayPlayer : ReplayPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; diff --git a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneDrumRollJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneDrumRollJudgements.cs index 2c28c3dad5..a9231b4783 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneDrumRollJudgements.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneDrumRollJudgements.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Taiko.Replays; namespace osu.Game.Rulesets.Taiko.Tests.Judgements { - public class TestSceneDrumRollJudgements : JudgementTest + public partial class TestSceneDrumRollJudgements : JudgementTest { [Test] public void TestHitAllDrumRoll() diff --git a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs index d2d5cdb6ac..3bf94eb62e 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneHitJudgements.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Taiko.Replays; namespace osu.Game.Rulesets.Taiko.Tests.Judgements { - public class TestSceneHitJudgements : JudgementTest + public partial class TestSceneHitJudgements : JudgementTest { [Test] public void TestHitCentreHit() diff --git a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneSwellJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneSwellJudgements.cs index 7bdfcf0b07..ccc829f09e 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneSwellJudgements.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Judgements/TestSceneSwellJudgements.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Taiko.Replays; namespace osu.Game.Rulesets.Taiko.Tests.Judgements { - public class TestSceneSwellJudgements : JudgementTest + public partial class TestSceneSwellJudgements : JudgementTest { [Test] public void TestHitAllSwell() diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TaikoModTestScene.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TaikoModTestScene.cs index 3090facf8c..7760c5a30b 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Mods/TaikoModTestScene.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TaikoModTestScene.cs @@ -5,7 +5,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Mods { - public abstract class TaikoModTestScene : ModTestScene + public abstract partial class TaikoModTestScene : ModTestScene { protected sealed override Ruleset CreatePlayerRuleset() => new TaikoRuleset(); } diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs index d55ce17e6c..05a408c621 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModFlashlight.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Tests.Mods { - public class TestSceneTaikoModFlashlight : TaikoModTestScene + public partial class TestSceneTaikoModFlashlight : TaikoModTestScene { [TestCase(1f)] [TestCase(0.5f)] @@ -38,11 +38,11 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods }); } - private class TestTaikoModFlashlight : TaikoModFlashlight + private partial class TestTaikoModFlashlight : TaikoModFlashlight { protected override Flashlight CreateFlashlight() => new TestTaikoFlashlight(this, Playfield); - public class TestTaikoFlashlight : TaikoFlashlight + public partial class TestTaikoFlashlight : TaikoFlashlight { public TestTaikoFlashlight(TaikoModFlashlight modFlashlight, TaikoPlayfield taikoPlayfield) : base(modFlashlight, taikoPlayfield) diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModHidden.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModHidden.cs index 7abbb9d186..edc53429b1 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModHidden.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModHidden.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Taiko.Mods; namespace osu.Game.Rulesets.Taiko.Tests.Mods { - public class TestSceneTaikoModHidden : TaikoModTestScene + public partial class TestSceneTaikoModHidden : TaikoModTestScene { [Test] public void TestDefaultBeatmapTest() => CreateModTest(new ModTestData diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs index 92503a9f03..aed08f33e0 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs @@ -10,7 +10,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Mods { - public class TestSceneTaikoModPerfect : ModPerfectTestScene + public partial class TestSceneTaikoModPerfect : ModPerfectTestScene { protected override Ruleset CreatePlayerRuleset() => new TestTaikoRuleset(); @@ -31,11 +31,11 @@ namespace osu.Game.Rulesets.Taiko.Tests.Mods [TestCase(true)] public void TestSwell(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Swell { StartTime = 1000, EndTime = 3000 }, false), shouldMiss); - private class TestTaikoRuleset : TaikoRuleset + private partial class TestTaikoRuleset : TaikoRuleset { public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new TestTaikoHealthProcessor(); - private class TestTaikoHealthProcessor : TaikoHealthProcessor + private partial class TestTaikoHealthProcessor : TaikoHealthProcessor { protected override void Reset(bool storeResults) { diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TaikoSkinnableTestScene.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TaikoSkinnableTestScene.cs index 82be26b422..38530282b7 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TaikoSkinnableTestScene.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TaikoSkinnableTestScene.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { - public abstract class TaikoSkinnableTestScene : SkinnableTestScene + public abstract partial class TaikoSkinnableTestScene : SkinnableTestScene { protected override Ruleset CreateRulesetForSkinProvider() => new TaikoRuleset(); } diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs index a4aa0e1fad..7fd90685e3 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs @@ -18,7 +18,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { [TestFixture] - public class TestSceneDrawableBarLine : TaikoSkinnableTestScene + public partial class TestSceneDrawableBarLine : TaikoSkinnableTestScene { [Cached(typeof(IScrollingInfo))] private ScrollingTestContainer.TestScrollingInfo info = new ScrollingTestContainer.TestScrollingInfo diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs index 25cb3f7886..3b2f4f2fb2 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableDrumRoll.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { [TestFixture] - public class TestSceneDrawableDrumRoll : TaikoSkinnableTestScene + public partial class TestSceneDrawableDrumRoll : TaikoSkinnableTestScene { [Cached(typeof(IScrollingInfo))] private ScrollingTestContainer.TestScrollingInfo info = new ScrollingTestContainer.TestScrollingInfo diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs index adfd27c5d6..9567eac80f 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableHit.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Gameplay; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { [TestFixture] - public class TestSceneDrawableHit : TaikoSkinnableTestScene + public partial class TestSceneDrawableHit : TaikoSkinnableTestScene { [Cached] private GameplayState gameplayState = TestGameplayState.Create(new TaikoRuleset()); diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs index b8c0f6f11e..c130b5f366 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableSwell.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { [TestFixture] - public class TestSceneDrawableSwell : TaikoSkinnableTestScene + public partial class TestSceneDrawableSwell : TaikoSkinnableTestScene { [Test] public void TestHits() diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs index 71ce4c08d0..e4e68c7207 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs @@ -25,7 +25,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { [TestFixture] - public class TestSceneDrawableTaikoMascot : TaikoSkinnableTestScene + public partial class TestSceneDrawableTaikoMascot : TaikoSkinnableTestScene { [Cached(typeof(IScrollingInfo))] private ScrollingTestContainer.TestScrollingInfo info = new ScrollingTestContainer.TestScrollingInfo diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs index 0ddc607336..924f903ce9 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs @@ -18,7 +18,7 @@ using osu.Game.Screens.Ranking; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { [TestFixture] - public class TestSceneHitExplosion : TaikoSkinnableTestScene + public partial class TestSceneHitExplosion : TaikoSkinnableTestScene { protected override double TimePerAction => 100; diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs index f342bfe78e..cb5d0d1f91 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { [TestFixture] - public class TestSceneInputDrum : TaikoSkinnableTestScene + public partial class TestSceneInputDrum : TaikoSkinnableTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs index e1a3c736fe..5f98f2f27a 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneKiaiHitExplosion.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Taiko.UI; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { [TestFixture] - public class TestSceneKiaiHitExplosion : TaikoSkinnableTestScene + public partial class TestSceneKiaiHitExplosion : TaikoSkinnableTestScene { [Test] public void TestKiaiHits() diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs index eff9f58751..eb2762cb2d 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs @@ -17,7 +17,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { - public class TestSceneTaikoPlayfield : TaikoSkinnableTestScene + public partial class TestSceneTaikoPlayfield : TaikoSkinnableTestScene { [Cached(typeof(IScrollingInfo))] private ScrollingTestContainer.TestScrollingInfo info = new ScrollingTestContainer.TestScrollingInfo diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs index a9304b01ad..826cf2acab 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoScroller.cs @@ -14,7 +14,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Tests.Skinning { - public class TestSceneTaikoScroller : TaikoSkinnableTestScene + public partial class TestSceneTaikoScroller : TaikoSkinnableTestScene { private readonly ManualClock clock = new ManualClock(); diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineApplication.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineApplication.cs index 867ee13bea..00292d5473 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineApplication.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineApplication.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables; namespace osu.Game.Rulesets.Taiko.Tests { - public class TestSceneBarLineApplication : HitObjectApplicationTestScene + public partial class TestSceneBarLineApplication : HitObjectApplicationTestScene { [Test] public void TestApplyNewBarLine() diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs index bd52af7615..7b8c8926f0 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneBarLineGeneration.cs @@ -12,7 +12,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests { - public class TestSceneBarLineGeneration : OsuTestScene + public partial class TestSceneBarLineGeneration : OsuTestScene { [Test] public void TestCloseBarLineGeneration() diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs index eceeaf5083..b01bd11149 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollApplication.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables; namespace osu.Game.Rulesets.Taiko.Tests { - public class TestSceneDrumRollApplication : HitObjectApplicationTestScene + public partial class TestSceneDrumRollApplication : HitObjectApplicationTestScene { [Test] public void TestApplyNewDrumRoll() diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs index 7210419c0e..6514b760bb 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumTouchInputArea.cs @@ -10,7 +10,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests { [TestFixture] - public class TestSceneDrumTouchInputArea : OsuTestScene + public partial class TestSceneDrumTouchInputArea : OsuTestScene { private DrumTouchInputArea drumTouchInputArea = null!; diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneFlyingHits.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneFlyingHits.cs index c787683620..e0ff617b59 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneFlyingHits.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneFlyingHits.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.Taiko.UI; namespace osu.Game.Rulesets.Taiko.Tests { [TestFixture] - public class TestSceneFlyingHits : DrawableTaikoRulesetTestScene + public partial class TestSceneFlyingHits : DrawableTaikoRulesetTestScene { [TestCase(HitType.Centre)] [TestCase(HitType.Rim)] diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneHitApplication.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneHitApplication.cs index b337519c85..301620edc9 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneHitApplication.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneHitApplication.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Taiko.Objects.Drawables; namespace osu.Game.Rulesets.Taiko.Tests { - public class TestSceneHitApplication : HitObjectApplicationTestScene + public partial class TestSceneHitApplication : HitObjectApplicationTestScene { [Test] public void TestApplyNewHit() diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs index 5350a81f55..91209e5ec5 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs @@ -23,7 +23,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Tests { [TestFixture] - public class TestSceneHits : DrawableTaikoRulesetTestScene + public partial class TestSceneHits : DrawableTaikoRulesetTestScene { private const double default_duration = 3000; private const float scroll_time = 1000; diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneSampleOutput.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneSampleOutput.cs index e6c28a532a..dcdda6014c 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneSampleOutput.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneSampleOutput.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Taiko.Tests /// Taiko has some interesting rules for legacy mappings. /// [HeadlessTest] - public class TestSceneSampleOutput : TestSceneTaikoPlayer + public partial class TestSceneSampleOutput : TestSceneTaikoPlayer { public override void SetUpSteps() { diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs index c674f87f80..1d1e82fb07 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoHitObjectSamples.cs @@ -8,7 +8,7 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Rulesets.Taiko.Tests { - public class TestSceneTaikoHitObjectSamples : HitObjectSampleTest + public partial class TestSceneTaikoHitObjectSamples : HitObjectSampleTest { protected override Ruleset CreatePlayerRuleset() => new TaikoRuleset(); diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayer.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayer.cs index 5e984b19f8..8c903f748c 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayer.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayer.cs @@ -7,7 +7,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests { - public class TestSceneTaikoPlayer : PlayerTestScene + public partial class TestSceneTaikoPlayer : PlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new TaikoRuleset(); } diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayerLegacySkin.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayerLegacySkin.cs index 13df24c988..39776229fa 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayerLegacySkin.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayerLegacySkin.cs @@ -6,7 +6,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests { - public class TestSceneTaikoPlayerLegacySkin : LegacySkinPlayerTestScene + public partial class TestSceneTaikoPlayerLegacySkin : LegacySkinPlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new TaikoRuleset(); diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs index 2169ac5581..08c06b08f2 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs @@ -13,7 +13,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Rulesets.Taiko.Tests { - public class TestSceneTaikoSuddenDeath : TestSceneTaikoPlayer + public partial class TestSceneTaikoSuddenDeath : TestSceneTaikoPlayer { protected override bool AllowFail => true; diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/DrumRollPlacementBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/DrumRollPlacementBlueprint.cs index dfbcd1cce3..4b4e2b5847 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/DrumRollPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/DrumRollPlacementBlueprint.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Edit.Blueprints { - public class DrumRollPlacementBlueprint : TaikoSpanPlacementBlueprint + public partial class DrumRollPlacementBlueprint : TaikoSpanPlacementBlueprint { public DrumRollPlacementBlueprint() : base(new DrumRoll()) diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPiece.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPiece.cs index 86f32ca17c..84bc547372 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPiece.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPiece.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Edit.Blueprints { - public class HitPiece : CompositeDrawable + public partial class HitPiece : CompositeDrawable { public HitPiece() { diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs index 863a2c9eac..0a1f5380b5 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/HitPlacementBlueprint.cs @@ -12,7 +12,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Taiko.Edit.Blueprints { - public class HitPlacementBlueprint : PlacementBlueprint + public partial class HitPlacementBlueprint : PlacementBlueprint { private readonly HitPiece piece; diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/LengthPiece.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/LengthPiece.cs index e201d58f7a..af02522a05 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/LengthPiece.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/LengthPiece.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Edit.Blueprints { - public class LengthPiece : CompositeDrawable + public partial class LengthPiece : CompositeDrawable { public LengthPiece() { diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/SwellPlacementBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/SwellPlacementBlueprint.cs index 1d08af47d3..2080293428 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/SwellPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/SwellPlacementBlueprint.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Taiko.Objects; namespace osu.Game.Rulesets.Taiko.Edit.Blueprints { - public class SwellPlacementBlueprint : TaikoSpanPlacementBlueprint + public partial class SwellPlacementBlueprint : TaikoSpanPlacementBlueprint { public SwellPlacementBlueprint() : base(new Swell()) diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSelectionBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSelectionBlueprint.cs index 4c67a37417..34695cbdd6 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSelectionBlueprint.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Edit.Blueprints { - public class TaikoSelectionBlueprint : HitObjectSelectionBlueprint + public partial class TaikoSelectionBlueprint : HitObjectSelectionBlueprint { public TaikoSelectionBlueprint(HitObject hitObject) : base(hitObject) diff --git a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs index 70364cabf1..fcf2573d64 100644 --- a/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Taiko/Edit/Blueprints/TaikoSpanPlacementBlueprint.cs @@ -16,7 +16,7 @@ using osuTK.Input; namespace osu.Game.Rulesets.Taiko.Edit.Blueprints { - public class TaikoSpanPlacementBlueprint : PlacementBlueprint + public partial class TaikoSpanPlacementBlueprint : PlacementBlueprint { private readonly HitPiece headPiece; private readonly HitPiece tailPiece; diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs index 6107c8009a..6be22f3af0 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Taiko.Edit { - public class TaikoBlueprintContainer : ComposeBlueprintContainer + public partial class TaikoBlueprintContainer : ComposeBlueprintContainer { public TaikoBlueprintContainer(HitObjectComposer composer) : base(composer) diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs index 161799c980..cff5731181 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs @@ -9,7 +9,7 @@ using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Taiko.Edit { - public class TaikoHitObjectComposer : HitObjectComposer + public partial class TaikoHitObjectComposer : HitObjectComposer { public TaikoHitObjectComposer(TaikoRuleset ruleset) : base(ruleset) diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs index 80e4e8f406..b727c0a61b 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoSelectionHandler.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Taiko.Edit { - public class TaikoSelectionHandler : EditorSelectionHandler + public partial class TaikoSelectionHandler : EditorSelectionHandler { private readonly Bindable selectionRimState = new Bindable(); private readonly Bindable selectionStrongState = new Bindable(); diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs index 46569c2495..733772e21f 100644 --- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs +++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Mods { - public class TaikoModFlashlight : ModFlashlight + public partial class TaikoModFlashlight : ModFlashlight { public override double ScoreMultiplier => UsesDefaultConfiguration ? 1.12 : 1; @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Mods base.ApplyToDrawableRuleset(drawableRuleset); } - public class TaikoFlashlight : Flashlight + public partial class TaikoFlashlight : Flashlight { private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.RequiredParentSizeToFit | Invalidation.DrawInfo); private readonly TaikoPlayfield taikoPlayfield; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs index 2405d5b73f..65a6fd4499 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// /// A line that scrolls alongside hit objects in the playfield and visualises control points. /// - public class DrawableBarLine : DrawableHitObject + public partial class DrawableBarLine : DrawableHitObject { public new BarLine HitObject => (BarLine)base.HitObject; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs index 0bb14c791e..005d2ab1ac 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public class DrawableDrumRoll : DrawableTaikoStrongableHitObject + public partial class DrawableDrumRoll : DrawableTaikoStrongableHitObject { /// /// Number of rolling hits required to reach the dark/final colour. @@ -173,7 +173,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables (MainPiece.Drawable as IHasAccentColour)?.FadeAccent(newColour, fadeDuration); } - public class StrongNestedHit : DrawableStrongNestedHit + public partial class StrongNestedHit : DrawableStrongNestedHit { public new DrawableDrumRoll ParentHitObject => (DrawableDrumRoll)base.ParentHitObject; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs index b01adc880a..45e25ee7dc 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs @@ -15,7 +15,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public class DrawableDrumRollTick : DrawableTaikoStrongableHitObject + public partial class DrawableDrumRollTick : DrawableTaikoStrongableHitObject { public BindableBool IsFirstTick = new BindableBool(); @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override DrawableStrongNestedHit CreateStrongNestedHit(DrumRollTick.StrongNestedHit hitObject) => new StrongNestedHit(hitObject); - public class StrongNestedHit : DrawableStrongNestedHit + public partial class StrongNestedHit : DrawableStrongNestedHit { public new DrawableDrumRollTick ParentHitObject => (DrawableDrumRollTick)base.ParentHitObject; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableFlyingHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableFlyingHit.cs index 5ce72028e0..0cd265ecab 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableFlyingHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableFlyingHit.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// /// A hit used specifically for drum rolls, where spawning flying hits is required. /// - public class DrawableFlyingHit : DrawableHit + public partial class DrawableFlyingHit : DrawableHit { public DrawableFlyingHit(DrawableDrumRollTick drumRollTick) : base(new IgnoreHit diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs index 59c9640beb..ff4edf35fa 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs @@ -19,7 +19,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public class DrawableHit : DrawableTaikoStrongableHitObject + public partial class DrawableHit : DrawableTaikoStrongableHitObject { /// /// A list of keys which can result in hits for this HitObject. @@ -220,7 +220,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables protected override DrawableStrongNestedHit CreateStrongNestedHit(Hit.StrongNestedHit hitObject) => new StrongNestedHit(hitObject); - public class StrongNestedHit : DrawableStrongNestedHit + public partial class StrongNestedHit : DrawableStrongNestedHit { public new DrawableHit ParentHitObject => (DrawableHit)base.ParentHitObject; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs index 01ee91a5c7..4ea30453d1 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableStrongNestedHit.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables /// /// Used as a nested hitobject to provide s for s. /// - public abstract class DrawableStrongNestedHit : DrawableTaikoHitObject + public abstract partial class DrawableStrongNestedHit : DrawableTaikoHitObject { public new DrawableTaikoHitObject ParentHitObject => (DrawableTaikoHitObject)base.ParentHitObject; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs index 753f85f23f..8441e3a749 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs @@ -21,7 +21,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public class DrawableSwell : DrawableTaikoHitObject + public partial class DrawableSwell : DrawableTaikoHitObject { private const float target_ring_thick_border = 1.4f; private const float target_ring_thin_border = 1f; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs index 5d44fce254..3a5c006962 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs @@ -11,7 +11,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public class DrawableSwellTick : DrawableTaikoHitObject + public partial class DrawableSwellTick : DrawableTaikoHitObject { public override bool DisplayResult => false; diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs index 400c2f40b1..6172b75d2c 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public abstract class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler + public abstract partial class DrawableTaikoHitObject : DrawableHitObject, IKeyBindingHandler { protected readonly Container Content; private readonly Container proxiedContent; @@ -105,13 +105,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables } } - private class ProxiedContentContainer : Container + private partial class ProxiedContentContainer : Container { public override bool RemoveWhenNotAlive => false; } } - public abstract class DrawableTaikoHitObject : DrawableTaikoHitObject + public abstract partial class DrawableTaikoHitObject : DrawableTaikoHitObject where TObject : TaikoHitObject { public override Vector2 OriginPosition => new Vector2(DrawHeight / 2); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs index 4b58cc60e6..4d7cdf3243 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoStrongableHitObject.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Objects.Drawables { - public abstract class DrawableTaikoStrongableHitObject : DrawableTaikoHitObject + public abstract partial class DrawableTaikoStrongableHitObject : DrawableTaikoHitObject where TObject : TaikoStrongableHitObject where TStrongNestedObject : StrongNestedHitObject { diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs index a663817aa8..7c70beb0a4 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring /// A for the taiko ruleset. /// Taiko fails if the player has not half-filled their health by the end of the map. /// - public class TaikoHealthProcessor : AccumulatingHealthProcessor + public partial class TaikoHealthProcessor : AccumulatingHealthProcessor { /// /// A value used for calculating . diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs index 3b0bb952dd..4b60ee3ccb 100644 --- a/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs +++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoScoreProcessor.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Taiko.Scoring { - internal class TaikoScoreProcessor : ScoreProcessor + internal partial class TaikoScoreProcessor : ScoreProcessor { public TaikoScoreProcessor() : base(new TaikoRuleset()) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonBarLine.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonBarLine.cs index 402e88b64d..32afb8e6ac 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonBarLine.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonBarLine : CompositeDrawable + public partial class ArgonBarLine : CompositeDrawable { private Container majorEdgeContainer = null!; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs index 551a5af078..dedb276d58 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCentreCirclePiece.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonCentreCirclePiece : ArgonCirclePiece + public partial class ArgonCentreCirclePiece : ArgonCirclePiece { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs index c22c0e9e79..d7e37899ce 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonCirclePiece.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public abstract class ArgonCirclePiece : BeatSyncedContainer + public abstract partial class ArgonCirclePiece : BeatSyncedContainer { public const float ICON_SIZE = 20 / 70f; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonElongatedCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonElongatedCirclePiece.cs index f86f181b2e..17386cc659 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonElongatedCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonElongatedCirclePiece.cs @@ -8,7 +8,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonElongatedCirclePiece : ArgonCirclePiece + public partial class ArgonElongatedCirclePiece : ArgonCirclePiece { public ArgonElongatedCirclePiece() { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitExplosion.cs index 05bb9bcb9a..a47fd7e62e 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitExplosion.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonHitExplosion : CompositeDrawable, IAnimatableHitExplosion + public partial class ArgonHitExplosion : CompositeDrawable, IAnimatableHitExplosion { private readonly TaikoSkinComponents component; private readonly Circle outer; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitTarget.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitTarget.cs index ec2eccd595..0ddcd6feb2 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitTarget.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonHitTarget.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonHitTarget : CompositeDrawable + public partial class ArgonHitTarget : CompositeDrawable { /// /// Thickness of all drawn line pieces. diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonInputDrum.cs index 528e75aabb..e7b0a5537a 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonInputDrum.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonInputDrum : AspectContainer + public partial class ArgonInputDrum : AspectContainer { private const float rim_size = 0.3f; @@ -91,7 +91,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon /// /// A half-drum. Contains one centre and one rim hit. /// - private class TaikoHalfDrum : CompositeDrawable, IKeyBindingHandler + private partial class TaikoHalfDrum : CompositeDrawable, IKeyBindingHandler { /// /// The key to be used for the rim of the half-drum. diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs index baaf9e41e2..6756001089 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement { protected readonly HitResult Result; @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon public Drawable? GetAboveHitObjectsProxiedContent() => null; - private class RingExplosion : CompositeDrawable + private partial class RingExplosion : CompositeDrawable { private readonly float travel = 58; @@ -174,7 +174,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon this.FadeOutFromOne(1000, Easing.OutQuint); } - public class RingPiece : CircularContainer + public partial class RingPiece : CircularContainer { public RingPiece(float thickness = 9) { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundLeft.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundLeft.cs index ebde83b607..07ac37b04c 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundLeft.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundLeft.cs @@ -8,7 +8,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonPlayfieldBackgroundLeft : CompositeDrawable + public partial class ArgonPlayfieldBackgroundLeft : CompositeDrawable { public ArgonPlayfieldBackgroundLeft() { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundRight.cs index bd0f3ab276..41a3e3bb33 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundRight.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonPlayfieldBackgroundRight.cs @@ -8,7 +8,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonPlayfieldBackgroundRight : CompositeDrawable + public partial class ArgonPlayfieldBackgroundRight : CompositeDrawable { public ArgonPlayfieldBackgroundRight() { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs index fd81221be3..b32326a90f 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonRimCirclePiece.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonRimCirclePiece : ArgonCirclePiece + public partial class ArgonRimCirclePiece : ArgonCirclePiece { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwellCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwellCirclePiece.cs index 82a6e34128..d93d8598f6 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwellCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonSwellCirclePiece.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonSwellCirclePiece : ArgonCirclePiece + public partial class ArgonSwellCirclePiece : ArgonCirclePiece { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonTickPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonTickPiece.cs index df63d4948e..5baa320201 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonTickPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonTickPiece.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class ArgonTickPiece : CompositeDrawable + public partial class ArgonTickPiece : CompositeDrawable { private readonly Bindable isFirstTick = new Bindable(); diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs index 534a1c71a3..719c1c36fa 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/RingPiece.cs @@ -8,7 +8,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public class RingPiece : CircularContainer + public partial class RingPiece : CircularContainer { private readonly float relativeBorderThickness; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs index 339ab35795..4ed5c3d0df 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CentreHitCirclePiece.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - public class CentreHitCirclePiece : CirclePiece + public partial class CentreHitCirclePiece : CirclePiece { public CentreHitCirclePiece() { @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default /// /// The symbol used for centre hit pieces. /// - public class CentreHitSymbolPiece : Container + public partial class CentreHitSymbolPiece : Container { public CentreHitSymbolPiece() { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs index 7ddc413d98..bde502bbed 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/CirclePiece.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default /// for a usage example. /// /// - public abstract class CirclePiece : BeatSyncedContainer, IHasAccentColour + public abstract partial class CirclePiece : BeatSyncedContainer, IHasAccentColour { public const float SYMBOL_SIZE = TaikoHitObject.DEFAULT_SIZE; public const float SYMBOL_BORDER = 8; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultBarLine.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultBarLine.cs index 973e685bc7..09965054e0 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultBarLine.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - public class DefaultBarLine : CompositeDrawable + public partial class DefaultBarLine : CompositeDrawable { /// /// The vertical offset of the triangles from the line tracker. diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs index 2e76396a4d..8a70c4bde8 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultHitExplosion.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - internal class DefaultHitExplosion : CircularContainer, IAnimatableHitExplosion + internal partial class DefaultHitExplosion : CircularContainer, IAnimatableHitExplosion { private readonly HitResult result; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs index 3d0578dbc0..6d19db999c 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultInputDrum.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - public class DefaultInputDrum : AspectContainer + public partial class DefaultInputDrum : AspectContainer { public DefaultInputDrum() { @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default /// /// A half-drum. Contains one centre and one rim hit. /// - private class TaikoHalfDrum : Container, IKeyBindingHandler + private partial class TaikoHalfDrum : Container, IKeyBindingHandler { /// /// The key to be used for the rim of the half-drum. diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs index c85a8db788..c78d7719d0 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultJudgementPiece.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - public class DefaultJudgementPiece : Rulesets.Judgements.DefaultJudgementPiece + public partial class DefaultJudgementPiece : Rulesets.Judgements.DefaultJudgementPiece { public DefaultJudgementPiece(HitResult result) : base(result) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultKiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultKiaiHitExplosion.cs index ae68d63d97..750fb505a0 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultKiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/DefaultKiaiHitExplosion.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - public class DefaultKiaiHitExplosion : CircularContainer + public partial class DefaultKiaiHitExplosion : CircularContainer { public override bool RemoveWhenNotAlive => true; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs index 210841bca0..11d82a3714 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/ElongatedCirclePiece.cs @@ -7,7 +7,7 @@ using osu.Game.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - public class ElongatedCirclePiece : CirclePiece + public partial class ElongatedCirclePiece : CirclePiece { public ElongatedCirclePiece() { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs index c6165495d8..0920d58a34 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/RimHitCirclePiece.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - public class RimHitCirclePiece : CirclePiece + public partial class RimHitCirclePiece : CirclePiece { public RimHitCirclePiece() { @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default /// /// The symbol used for rim hit pieces. /// - public class RimHitSymbolPiece : CircularContainer + public partial class RimHitSymbolPiece : CircularContainer { public RimHitSymbolPiece() { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs index 2f59cac3ff..d40b518aa3 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/SwellSymbolPiece.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - public class SwellCirclePiece : CirclePiece + public partial class SwellCirclePiece : CirclePiece { public SwellCirclePiece() { @@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default /// /// The symbol used for swell pieces. /// - public class SwellSymbolPiece : Container + public partial class SwellSymbolPiece : Container { public SwellSymbolPiece() { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs index a1eaef53ba..8bd8d5f4b4 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Default/TickPiece.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Default { - public class TickPiece : CompositeDrawable + public partial class TickPiece : CompositeDrawable { /// /// Any tick that is not the first for a drumroll is not filled, but is instead displayed diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs index 2b528ae8ce..01100bfd63 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyBarLine.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { - public class LegacyBarLine : Sprite + public partial class LegacyBarLine : Sprite { [BackgroundDependencyLoader] private void load(ISkinSource skin) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs index a5867ff51c..37eb95b86f 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyCirclePiece.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { - public class LegacyCirclePiece : CompositeDrawable, IHasAccentColour + public partial class LegacyCirclePiece : CompositeDrawable, IHasAccentColour { private Drawable backgroundLayer = null!; private Drawable? foregroundLayer; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs index 1249231d92..5543a31ec9 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyDrumRoll.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { - public class LegacyDrumRoll : CompositeDrawable, IHasAccentColour + public partial class LegacyDrumRoll : CompositeDrawable, IHasAccentColour { public override Quad ScreenSpaceDrawQuad { diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs index d93317f0e2..87c9d72d22 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHit.cs @@ -7,7 +7,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { - public class LegacyHit : LegacyCirclePiece + public partial class LegacyHit : LegacyCirclePiece { private readonly TaikoSkinComponents component; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs index ff1546381b..b9a432f3bd 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyHitExplosion.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Taiko.UI; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { - public class LegacyHitExplosion : CompositeDrawable, IAnimatableHitExplosion + public partial class LegacyHitExplosion : CompositeDrawable, IAnimatableHitExplosion { private readonly Drawable sprite; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs index 0abb365750..8ad419f8bd 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy /// /// A component of the playfield that captures input and displays input as a drum. /// - internal class LegacyInputDrum : Container + internal partial class LegacyInputDrum : Container { private Container content = null!; private LegacyHalfDrum left = null!; @@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy /// /// A half-drum. Contains one centre and one rim hit. /// - private class LegacyHalfDrum : Container, IKeyBindingHandler + private partial class LegacyHalfDrum : Container, IKeyBindingHandler { /// /// The key to be used for the rim of the half-drum. diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs index 4a2426bff5..2964473f89 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyTaikoScroller.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { - public class LegacyTaikoScroller : CompositeDrawable + public partial class LegacyTaikoScroller : CompositeDrawable { public Bindable LastResult = new Bindable(); @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy } } - private class ScrollerSprite : CompositeDrawable + private partial class ScrollerSprite : CompositeDrawable { private Sprite passingSprite = null!; private Sprite failingSprite = null!; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs index 21102f6eec..492782f0d1 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyHitTarget.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { - public class TaikoLegacyHitTarget : CompositeDrawable + public partial class TaikoLegacyHitTarget : CompositeDrawable { private Container content = null!; diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs index 3186f615a7..86175d3bca 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { - public class TaikoLegacyPlayfieldBackgroundRight : BeatSyncedContainer + public partial class TaikoLegacyPlayfieldBackgroundRight : BeatSyncedContainer { private Sprite kiai = null!; diff --git a/osu.Game.Rulesets.Taiko/TaikoInputManager.cs b/osu.Game.Rulesets.Taiko/TaikoInputManager.cs index d36fe5d496..ca06a0a77e 100644 --- a/osu.Game.Rulesets.Taiko/TaikoInputManager.cs +++ b/osu.Game.Rulesets.Taiko/TaikoInputManager.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko { [Cached] // Used for touch input, see DrumTouchInputArea. - public class TaikoInputManager : RulesetInputManager + public partial class TaikoInputManager : RulesetInputManager { public TaikoInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique) diff --git a/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs b/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs index cb878e8ea0..ebdf9ef191 100644 --- a/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/BarLinePlayfield.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Taiko.UI { - public class BarLinePlayfield : ScrollingPlayfield + public partial class BarLinePlayfield : ScrollingPlayfield { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs index 24d2fd7be7..f91fe586f2 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// /// Text that is shown as judgement when a hit object is hit or missed. /// - public class DrawableTaikoJudgement : DrawableJudgement + public partial class DrawableTaikoJudgement : DrawableJudgement { public DrawableTaikoJudgement() { diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs index c5cf09d449..0dfb796c74 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoMascot.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Rulesets.Taiko.UI { - public class DrawableTaikoMascot : BeatSyncedContainer + public partial class DrawableTaikoMascot : BeatSyncedContainer { public readonly Bindable State; public readonly Bindable LastResult; diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index c3d93a344d..32a83d87b8 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.UI { - public class DrawableTaikoRuleset : DrawableScrollingRuleset + public partial class DrawableTaikoRuleset : DrawableScrollingRuleset { public new BindableDouble TimeRange => base.TimeRange; diff --git a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs index ae37840825..87ee852171 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumRollHitContainer.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Rulesets.Taiko.UI { - internal class DrumRollHitContainer : ScrollingHitObjectContainer + internal partial class DrumRollHitContainer : ScrollingHitObjectContainer { // TODO: this usage is buggy. // Because `LifetimeStart` is set based on scrolling, lifetime is not same as the time when the object is created. diff --git a/osu.Game.Rulesets.Taiko/UI/DrumSamplePlayer.cs b/osu.Game.Rulesets.Taiko/UI/DrumSamplePlayer.cs index b65e2af3d8..6454fb5afa 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumSamplePlayer.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumSamplePlayer.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.UI { - internal class DrumSamplePlayer : CompositeDrawable, IKeyBindingHandler + internal partial class DrumSamplePlayer : CompositeDrawable, IKeyBindingHandler { private readonly DrumSampleTriggerSource leftRimSampleTriggerSource; private readonly DrumSampleTriggerSource leftCentreSampleTriggerSource; diff --git a/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs b/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs index 3279d128d3..4809791af8 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.UI { - public class DrumSampleTriggerSource : GameplaySampleTriggerSource + public partial class DrumSampleTriggerSource : GameplaySampleTriggerSource { public DrumSampleTriggerSource(HitObjectContainer hitObjectContainer) : base(hitObjectContainer) diff --git a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs index a7d9bd18c5..ab8c0a484e 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrumTouchInputArea.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// /// An overlay that captures and displays osu!taiko mouse and touch input. /// - public class DrumTouchInputArea : VisibilityContainer + public partial class DrumTouchInputArea : VisibilityContainer { // visibility state affects our child. we always want to handle input. public override bool PropagatePositionalInputSubTree => true; @@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Taiko.UI mainContent.FadeOut(300); } - private class QuarterCircle : CompositeDrawable, IKeyBindingHandler + private partial class QuarterCircle : CompositeDrawable, IKeyBindingHandler { private readonly Circle overlay; diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs index 8f2b702472..1a2652acf9 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// /// A circle explodes from the hit target to indicate a hitobject has been hit. /// - internal class HitExplosion : PoolableDrawable + internal partial class HitExplosion : PoolableDrawable { public override bool RemoveWhenNotAlive => true; public override bool RemoveCompletedTransforms => false; diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs index badf34554c..02a78b0f1c 100644 --- a/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs +++ b/osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// /// Pool for hit explosions of a specific type. /// - internal class HitExplosionPool : DrawablePool + internal partial class HitExplosionPool : DrawablePool { private readonly HitResult hitResult; diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 2f42a5aaf6..725857ed34 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// /// A component of the playfield that captures input and displays input as a drum. /// - internal class InputDrum : Container + internal partial class InputDrum : Container { public InputDrum() { diff --git a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs index 627e06e186..6c1e981a97 100644 --- a/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs +++ b/osu.Game.Rulesets.Taiko/UI/KiaiHitExplosion.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.UI { - public class KiaiHitExplosion : Container + public partial class KiaiHitExplosion : Container { public override bool RemoveWhenNotAlive => true; diff --git a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs index 2a8890a95d..f676d051eb 100644 --- a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs +++ b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundLeft.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.UI { - internal class PlayfieldBackgroundLeft : CompositeDrawable + internal partial class PlayfieldBackgroundLeft : CompositeDrawable { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs index 44bfdacf37..7b2dbc5f5a 100644 --- a/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs +++ b/osu.Game.Rulesets.Taiko/UI/PlayfieldBackgroundRight.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.UI { - public class PlayfieldBackgroundRight : CompositeDrawable + public partial class PlayfieldBackgroundRight : CompositeDrawable { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs b/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs index 6401c6d09f..a2f8dc83db 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoHitTarget.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Taiko.UI /// /// A component that is displayed at the hit position in the taiko playfield. /// - internal class TaikoHitTarget : Container + internal partial class TaikoHitTarget : Container { /// /// Thickness of all drawn line pieces. diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs index 0f214b8436..7b1e31112e 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoMascotAnimation.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.UI { - public sealed class TaikoMascotAnimation : BeatSyncedContainer + public sealed partial class TaikoMascotAnimation : BeatSyncedContainer { private readonly TextureAnimation textureAnimation; @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Taiko.UI } } - private class ManualMascotTextureAnimation : TextureAnimation + private partial class ManualMascotTextureAnimation : TextureAnimation { private readonly TaikoMascotAnimationState state; @@ -103,7 +103,7 @@ namespace osu.Game.Rulesets.Taiko.UI } } - private class ClearMascotTextureAnimation : TextureAnimation + private partial class ClearMascotTextureAnimation : TextureAnimation { private const float clear_animation_speed = 1000 / 10f; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 45a3b80931..6ce0be5868 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -28,7 +28,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.UI { - public class TaikoPlayfield : ScrollingPlayfield + public partial class TaikoPlayfield : ScrollingPlayfield { /// /// Default height of a when inside a . @@ -342,7 +342,7 @@ namespace osu.Game.Rulesets.Taiko.UI kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type)); } - private class ProxyContainer : LifetimeManagementContainer + private partial class ProxyContainer : LifetimeManagementContainer { public void Add(Drawable proxy) => AddInternal(proxy); diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs index 9cf530e903..79c5c36e08 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfieldAdjustmentContainer.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Taiko.UI { - public class TaikoPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer + public partial class TaikoPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer { private const float default_relative_height = TaikoPlayfield.DEFAULT_HEIGHT / 768; private const float default_aspect = 16f / 9f; diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs b/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs index e6391d1386..57ff3b59d5 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.UI { - public class TaikoReplayRecorder : ReplayRecorder + public partial class TaikoReplayRecorder : ReplayRecorder { public TaikoReplayRecorder(Score score) : base(score) diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index 6eb103316f..ab40092b3f 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -22,7 +22,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Beatmaps { [HeadlessTest] - public class TestSceneBeatmapDifficultyCache : OsuTestScene + public partial class TestSceneBeatmapDifficultyCache : OsuTestScene { public const double BASE_STARS = 5.55; @@ -162,7 +162,7 @@ namespace osu.Game.Tests.Beatmaps Assert.AreEqual(expectedBracket, actualBracket); } - private class TestBeatmapDifficultyCache : BeatmapDifficultyCache + private partial class TestBeatmapDifficultyCache : BeatmapDifficultyCache { public Func ComputeDifficulty { get; set; } diff --git a/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs b/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs index 81d0e6f3ef..bb24560a44 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneEditorBeatmap.cs @@ -18,7 +18,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Beatmaps { [HeadlessTest] - public class TestSceneEditorBeatmap : EditorClockTestScene + public partial class TestSceneEditorBeatmap : EditorClockTestScene { /// /// Tests that the addition event is correctly invoked after a hitobject is added. diff --git a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs index 4ef466efbf..89b8c8927d 100644 --- a/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs +++ b/osu.Game.Tests/Beatmaps/WorkingBeatmapManagerTest.cs @@ -19,7 +19,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Beatmaps { [HeadlessTest] - public class WorkingBeatmapManagerTest : OsuTestScene + public partial class WorkingBeatmapManagerTest : OsuTestScene { private BeatmapManager beatmaps = null!; diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index c9a78cbf59..cdd192cfe1 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -18,7 +18,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Chat { [HeadlessTest] - public class TestSceneChannelManager : OsuTestScene + public partial class TestSceneChannelManager : OsuTestScene { private ChannelManager channelManager; private int currentMessageId; @@ -183,7 +183,7 @@ namespace osu.Game.Tests.Chat LastMessageId = 0, }; - private class ChannelManagerContainer : CompositeDrawable + private partial class ChannelManagerContainer : CompositeDrawable { [Cached] public ChannelManager ChannelManager { get; } diff --git a/osu.Game.Tests/Database/BackgroundBeatmapProcessorTests.cs b/osu.Game.Tests/Database/BackgroundBeatmapProcessorTests.cs index 4012e3f851..ddb60606ec 100644 --- a/osu.Game.Tests/Database/BackgroundBeatmapProcessorTests.cs +++ b/osu.Game.Tests/Database/BackgroundBeatmapProcessorTests.cs @@ -15,7 +15,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Database { [HeadlessTest] - public class BackgroundBeatmapProcessorTests : OsuTestScene, ILocalUserPlayInfo + public partial class BackgroundBeatmapProcessorTests : OsuTestScene, ILocalUserPlayInfo { public IBindable IsPlaying => isPlaying; @@ -124,7 +124,7 @@ namespace osu.Game.Tests.Database }); } - public class TestBackgroundBeatmapProcessor : BackgroundBeatmapProcessor + public partial class TestBackgroundBeatmapProcessor : BackgroundBeatmapProcessor { protected override int TimeToSleepDuringGameplay => 10; } diff --git a/osu.Game.Tests/Database/RealmTest.cs b/osu.Game.Tests/Database/RealmTest.cs index 1b1878942b..d2779e3038 100644 --- a/osu.Game.Tests/Database/RealmTest.cs +++ b/osu.Game.Tests/Database/RealmTest.cs @@ -18,7 +18,7 @@ using osu.Game.Rulesets; namespace osu.Game.Tests.Database { [TestFixture] - public abstract class RealmTest + public abstract partial class RealmTest { protected void RunTestWithRealm([InstantHandle] Action testAction, [CallerMemberName] string caller = "") { @@ -107,7 +107,7 @@ namespace osu.Game.Tests.Database protected static RulesetInfo CreateRuleset() => new RulesetInfo("osu", "osu!", string.Empty, 0) { Available = true }; - private class RealmTestGame : Framework.Game + private partial class RealmTestGame : Framework.Game { public RealmTestGame([InstantHandle] Func work) { diff --git a/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs b/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs index 362b37124d..f4467867db 100644 --- a/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs +++ b/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs @@ -20,7 +20,7 @@ using Realms; namespace osu.Game.Tests.Database { [TestFixture] - public class TestRealmKeyBindingStore + public partial class TestRealmKeyBindingStore { private NativeStorage storage; @@ -123,7 +123,7 @@ namespace osu.Game.Tests.Database storage.DeleteDirectory(string.Empty); } - public class TestKeyBindingContainer : KeyBindingContainer + public partial class TestKeyBindingContainer : KeyBindingContainer { public override IEnumerable DefaultKeyBindings => new[] diff --git a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs index 495a221159..f556f6e2fe 100644 --- a/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs +++ b/osu.Game.Tests/Editing/TestSceneHitObjectComposerDistanceSnapping.cs @@ -20,7 +20,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Editing { [HeadlessTest] - public class TestSceneHitObjectComposerDistanceSnapping : EditorClockTestScene + public partial class TestSceneHitObjectComposerDistanceSnapping : EditorClockTestScene { private TestHitObjectComposer composer = null!; @@ -251,7 +251,7 @@ namespace osu.Game.Tests.Editing private void assertSnappedDistance(float distance, float expectedDistance, HitObject? referenceObject = null) => AddAssert($"distance = {distance} -> distance = {expectedDistance} (snapped)", () => composer.FindSnappedDistance(referenceObject ?? new HitObject(), distance), () => Is.EqualTo(expectedDistance).Within(Precision.FLOAT_EPSILON)); - private class TestHitObjectComposer : OsuHitObjectComposer + private partial class TestHitObjectComposer : OsuHitObjectComposer { public new EditorBeatmap EditorBeatmap => base.EditorBeatmap; diff --git a/osu.Game.Tests/Editing/TestSceneHitObjectContainerEventBuffer.cs b/osu.Game.Tests/Editing/TestSceneHitObjectContainerEventBuffer.cs index c3e171684c..745c636166 100644 --- a/osu.Game.Tests/Editing/TestSceneHitObjectContainerEventBuffer.cs +++ b/osu.Game.Tests/Editing/TestSceneHitObjectContainerEventBuffer.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Editing { [HeadlessTest] - public class TestSceneHitObjectContainerEventBuffer : OsuTestScene + public partial class TestSceneHitObjectContainerEventBuffer : OsuTestScene { private readonly TestHitObject testObj = new TestHitObject(); @@ -139,7 +139,7 @@ namespace osu.Game.Tests.Editing => AddAssert($"began = {began}, finished = {finished}, transferred = {transferred}", () => (beganUsage == testObj) == began && (finishedUsage == testObj) == finished && (transferredUsage == testObj) == transferred); - private class TestPlayfield : Playfield + private partial class TestPlayfield : Playfield { public TestPlayfield() { @@ -165,11 +165,11 @@ namespace osu.Game.Tests.Editing public override string ToString() => "TestHitObject"; } - private class TestDrawableHitObject : DrawableHitObject + private partial class TestDrawableHitObject : DrawableHitObject { } - private class TestDrawable : Drawable + private partial class TestDrawable : Drawable { public new void Schedule(Action action) => base.Schedule(action); } diff --git a/osu.Game.Tests/Editing/TransactionalCommitComponentTest.cs b/osu.Game.Tests/Editing/TransactionalCommitComponentTest.cs index 3d7286c396..7280631e32 100644 --- a/osu.Game.Tests/Editing/TransactionalCommitComponentTest.cs +++ b/osu.Game.Tests/Editing/TransactionalCommitComponentTest.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Edit; namespace osu.Game.Tests.Editing { [TestFixture] - public class TransactionalCommitComponentTest + public partial class TransactionalCommitComponentTest { private TestHandler handler; @@ -89,7 +89,7 @@ namespace osu.Game.Tests.Editing Assert.That(() => handler.EndChange(), Throws.TypeOf()); } - private class TestHandler : TransactionalCommitComponent + private partial class TestHandler : TransactionalCommitComponent { public int StateUpdateCount { get; private set; } diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs index c4e8bbfccf..fd0bff101f 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs @@ -21,7 +21,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Gameplay { [HeadlessTest] - public class TestSceneDrainingHealthProcessor : OsuTestScene + public partial class TestSceneDrainingHealthProcessor : OsuTestScene { private HealthProcessor processor; private ManualClock clock; diff --git a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs index 91e33b759c..62863524fe 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Gameplay { [HeadlessTest] - public class TestSceneDrawableHitObject : OsuTestScene + public partial class TestSceneDrawableHitObject : OsuTestScene { [Test] public void TestEntryLifetime() @@ -137,7 +137,7 @@ namespace osu.Game.Tests.Gameplay AddAssert("DHO state is correct", () => dho.State.Value == ArmedState.Miss); } - private class TestDrawableHitObject : DrawableHitObject + private partial class TestDrawableHitObject : DrawableHitObject { public const double INITIAL_LIFETIME_OFFSET = 100; public const double LIFETIME_ON_APPLY = 222; diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs index 255d6400c8..f38c2c9416 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -25,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Gameplay { [HeadlessTest] - public class TestSceneHitObjectAccentColour : OsuTestScene + public partial class TestSceneHitObjectAccentColour : OsuTestScene { [Resolved] private OsuConfigManager config { get; set; } @@ -84,7 +84,7 @@ namespace osu.Game.Tests.Gameplay AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green); } - private class TestDrawableHitObject : DrawableHitObject + private partial class TestDrawableHitObject : DrawableHitObject { public TestDrawableHitObject() : base(new TestHitObjectWithCombo()) diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectContainer.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectContainer.cs index 79e64ba2a2..8322833187 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectContainer.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectContainer.cs @@ -14,7 +14,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Gameplay { [HeadlessTest] - public class TestSceneHitObjectContainer : OsuTestScene + public partial class TestSceneHitObjectContainer : OsuTestScene { private HitObjectContainer container; @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Gameplay AddAssert("second object index is 0", () => container.IndexOf(secondObject) == 1); } - private class TestDrawableHitObject : DrawableHitObject + private partial class TestDrawableHitObject : DrawableHitObject { public TestDrawableHitObject([NotNull] HitObject hitObject) : base(hitObject) diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs index e25d08f98c..769ca1f9a9 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs @@ -13,7 +13,7 @@ using static osu.Game.Skinning.SkinConfiguration; namespace osu.Game.Tests.Gameplay { - public class TestSceneHitObjectSamples : HitObjectSampleTest + public partial class TestSceneHitObjectSamples : HitObjectSampleTest { protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); protected override IResourceStore RulesetResources => TestResources.GetStore(); diff --git a/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs b/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs index abd734b96c..3c6ec28da2 100644 --- a/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs +++ b/osu.Game.Tests/Gameplay/TestSceneMasterGameplayClockContainer.cs @@ -17,7 +17,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Gameplay { [HeadlessTest] - public class TestSceneMasterGameplayClockContainer : OsuTestScene + public partial class TestSceneMasterGameplayClockContainer : OsuTestScene { private OsuConfigManager localConfig; diff --git a/osu.Game.Tests/Gameplay/TestSceneProxyContainer.cs b/osu.Game.Tests/Gameplay/TestSceneProxyContainer.cs index 1893e43f43..be69b77e8b 100644 --- a/osu.Game.Tests/Gameplay/TestSceneProxyContainer.cs +++ b/osu.Game.Tests/Gameplay/TestSceneProxyContainer.cs @@ -17,7 +17,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Gameplay { [HeadlessTest] - public class TestSceneProxyContainer : OsuTestScene + public partial class TestSceneProxyContainer : OsuTestScene { private HitObjectContainer hitObjectContainer; private ProxyContainer proxyContainer; @@ -62,14 +62,14 @@ namespace osu.Game.Tests.Gameplay proxyContainer.AddProxy(drawableHitObject); } - private class ProxyContainer : LifetimeManagementContainer + private partial class ProxyContainer : LifetimeManagementContainer { public IReadOnlyList AliveChildren => AliveInternalChildren; public void AddProxy(Drawable d) => AddInternal(d.CreateProxy()); } - private class TestDrawableHitObject : DrawableHitObject + private partial class TestDrawableHitObject : DrawableHitObject { protected override double InitialLifetimeOffset => 100; diff --git a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs index d5219f6391..3ce7aa72d9 100644 --- a/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs +++ b/osu.Game.Tests/Gameplay/TestSceneScoreProcessor.cs @@ -22,7 +22,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Gameplay { [HeadlessTest] - public class TestSceneScoreProcessor : OsuTestScene + public partial class TestSceneScoreProcessor : OsuTestScene { [Test] public void TestNoScoreIncreaseFromMiss() diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index 577933eae3..2cad7d33c2 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -33,7 +33,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Gameplay { [HeadlessTest] - public class TestSceneStoryboardSamples : OsuTestScene, IStorageResourceProvider + public partial class TestSceneStoryboardSamples : OsuTestScene, IStorageResourceProvider { [Resolved] private OsuConfigManager config { get; set; } @@ -199,7 +199,7 @@ namespace osu.Game.Tests.Gameplay protected internal override ISkin GetSkin() => new TestSkin("test-sample", resources); } - private class TestDrawableStoryboardSample : DrawableStoryboardSample + private partial class TestDrawableStoryboardSample : DrawableStoryboardSample { public TestDrawableStoryboardSample(StoryboardSampleInfo sampleInfo) : base(sampleInfo) diff --git a/osu.Game.Tests/ImportTest.cs b/osu.Game.Tests/ImportTest.cs index 23ca31ee42..9e2c9cd7e0 100644 --- a/osu.Game.Tests/ImportTest.cs +++ b/osu.Game.Tests/ImportTest.cs @@ -15,7 +15,7 @@ using osu.Game.Tests.Resources; namespace osu.Game.Tests { - public abstract class ImportTest + public abstract partial class ImportTest { protected virtual TestOsuGameBase LoadOsuIntoHost(GameHost host, bool withBeatmap = false) { @@ -45,7 +45,7 @@ namespace osu.Game.Tests Assert.IsTrue(task.Wait(timeout), failureMessage); } - public class TestOsuGameBase : OsuGameBase + public partial class TestOsuGameBase : OsuGameBase { public RealmAccess Realm => Dependencies.Get(); diff --git a/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs b/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs index a91d4553de..3c296b2ff5 100644 --- a/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs +++ b/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs @@ -15,7 +15,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Input { [HeadlessTest] - public class ConfineMouseTrackerTest : OsuGameTestScene + public partial class ConfineMouseTrackerTest : OsuGameTestScene { [Resolved] private FrameworkConfigManager frameworkConfigManager { get; set; } diff --git a/osu.Game.Tests/Mods/SettingsSourceAttributeTest.cs b/osu.Game.Tests/Mods/SettingsSourceAttributeTest.cs index dd105787fa..bf59862787 100644 --- a/osu.Game.Tests/Mods/SettingsSourceAttributeTest.cs +++ b/osu.Game.Tests/Mods/SettingsSourceAttributeTest.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Tests.Mods { [TestFixture] - public class SettingsSourceAttributeTest + public partial class SettingsSourceAttributeTest { [Test] public void TestOrdering() @@ -60,11 +60,11 @@ namespace osu.Game.Tests.Mods public BindableInt UnorderedSetting { get; set; } = new BindableInt(); } - private class CustomSettingsControl : SettingsItem + private partial class CustomSettingsControl : SettingsItem { protected override Drawable CreateControl() => new CustomControl(); - private class CustomControl : Drawable, IHasCurrentValue + private partial class CustomControl : Drawable, IHasCurrentValue { public Bindable Current { get; set; } = new Bindable(); } diff --git a/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs b/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs index 14da07bc2d..9a32b8e894 100644 --- a/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs +++ b/osu.Game.Tests/NonVisual/FirstAvailableHitWindowsTest.cs @@ -18,7 +18,7 @@ using osu.Game.Scoring; namespace osu.Game.Tests.NonVisual { - public class FirstAvailableHitWindowsTest + public partial class FirstAvailableHitWindowsTest { private TestDrawableRuleset testDrawableRuleset; @@ -76,7 +76,7 @@ namespace osu.Game.Tests.NonVisual } [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] - private class TestDrawableRuleset : DrawableRuleset + private partial class TestDrawableRuleset : DrawableRuleset { public List HitObjects; public override IEnumerable Objects => HitObjects; diff --git a/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs b/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs index 363c7a459e..d67a3cb824 100644 --- a/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs +++ b/osu.Game.Tests/NonVisual/GameplayClockContainerTest.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Tests.NonVisual { [TestFixture] - public class GameplayClockContainerTest + public partial class GameplayClockContainerTest { [TestCase(0)] [TestCase(1)] @@ -22,7 +22,7 @@ namespace osu.Game.Tests.NonVisual Assert.That(gameplayClock.GetTrueGameplayRate(), Is.EqualTo(2)); } - private class TestGameplayClockContainer : GameplayClockContainer + private partial class TestGameplayClockContainer : GameplayClockContainer { public TestGameplayClockContainer(IFrameBasedClock underlyingClock) : base(underlyingClock) diff --git a/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs b/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs index d1c5e2d8b3..ae6a76f6cd 100644 --- a/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs +++ b/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Visual.Multiplayer; namespace osu.Game.Tests.NonVisual.Multiplayer { [HeadlessTest] - public class StatefulMultiplayerClientTest : MultiplayerTestScene + public partial class StatefulMultiplayerClientTest : MultiplayerTestScene { [Test] public void TestUserAddedOnJoin() diff --git a/osu.Game.Tests/NonVisual/OngoingOperationTrackerTest.cs b/osu.Game.Tests/NonVisual/OngoingOperationTrackerTest.cs index 03ca3a0a1a..0bcae05f44 100644 --- a/osu.Game.Tests/NonVisual/OngoingOperationTrackerTest.cs +++ b/osu.Game.Tests/NonVisual/OngoingOperationTrackerTest.cs @@ -17,7 +17,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.NonVisual { [HeadlessTest] - public class OngoingOperationTrackerTest : OsuTestScene + public partial class OngoingOperationTrackerTest : OsuTestScene { private OngoingOperationTracker tracker; private IBindable operationInProgress; @@ -94,7 +94,7 @@ namespace osu.Game.Tests.NonVisual AddAssert("operation ended", () => !screen.OngoingOperationTracker.InProgress.Value); } - private class TestScreenWithTracker : OsuScreen + private partial class TestScreenWithTracker : OsuScreen { public OngoingOperationTracker OngoingOperationTracker { get; private set; } diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs index 5c247bace9..197e9404ff 100644 --- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs @@ -22,7 +22,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.NonVisual.Skinning { [HeadlessTest] - public class LegacySkinAnimationTest : OsuTestScene + public partial class LegacySkinAnimationTest : OsuTestScene { private const string animation_name = "animation"; private const int frame_count = 6; diff --git a/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs b/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs index 61fdae0ca1..f41c3ad6af 100644 --- a/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs +++ b/osu.Game.Tests/Online/TestDummyAPIRequestHandling.cs @@ -14,7 +14,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Online { [HeadlessTest] - public class TestDummyAPIRequestHandling : OsuTestScene + public partial class TestDummyAPIRequestHandling : OsuTestScene { [Test] public void TestGenericRequestHandling() diff --git a/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs b/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs index 641c1ad523..c959132332 100644 --- a/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs +++ b/osu.Game.Tests/Online/TestSceneBeatmapDownloading.cs @@ -15,7 +15,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Online { [HeadlessTest] - public class TestSceneBeatmapDownloading : OsuTestScene + public partial class TestSceneBeatmapDownloading : OsuTestScene { private BeatmapModelDownloader beatmaps; private ProgressNotification recentNotification; diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs index e7590df3e0..e1d8e08c5e 100644 --- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs @@ -34,7 +34,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Online { [HeadlessTest] - public class TestSceneOnlinePlayBeatmapAvailabilityTracker : OsuTestScene + public partial class TestSceneOnlinePlayBeatmapAvailabilityTracker : OsuTestScene { private RulesetStore rulesets; private TestBeatmapManager beatmaps; diff --git a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs index 6015c92663..1d568a9dc2 100644 --- a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs +++ b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.OnlinePlay { [HeadlessTest] - public class TestSceneCatchUpSyncManager : OsuTestScene + public partial class TestSceneCatchUpSyncManager : OsuTestScene { private GameplayClockContainer master; private SpectatorSyncManager syncManager; diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs index 7a45d1e7cf..e9e94aa897 100644 --- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs +++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs @@ -22,7 +22,7 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Rulesets.Scoring { - public class ScoreProcessorTest + public partial class ScoreProcessorTest { private ScoreProcessor scoreProcessor; private IBeatmap beatmap; @@ -394,7 +394,7 @@ namespace osu.Game.Tests.Rulesets.Scoring } } - private class TestScoreProcessor : ScoreProcessor + private partial class TestScoreProcessor : ScoreProcessor { protected override double DefaultAccuracyPortion => 0.5; protected override double DefaultComboPortion => 0.5; diff --git a/osu.Game.Tests/Rulesets/TestSceneBrokenRulesetHandling.cs b/osu.Game.Tests/Rulesets/TestSceneBrokenRulesetHandling.cs index ecc4b3ec63..c3a6b7c474 100644 --- a/osu.Game.Tests/Rulesets/TestSceneBrokenRulesetHandling.cs +++ b/osu.Game.Tests/Rulesets/TestSceneBrokenRulesetHandling.cs @@ -18,7 +18,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Rulesets { [HeadlessTest] - public class TestSceneBrokenRulesetHandling : OsuTestScene + public partial class TestSceneBrokenRulesetHandling : OsuTestScene { [Resolved] private OsuGameBase gameBase { get; set; } = null!; diff --git a/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs b/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs index 29534348dc..3fba21050e 100644 --- a/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs +++ b/osu.Game.Tests/Rulesets/TestSceneDrawableRulesetDependencies.cs @@ -29,7 +29,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Rulesets { [HeadlessTest] - public class TestSceneDrawableRulesetDependencies : OsuTestScene + public partial class TestSceneDrawableRulesetDependencies : OsuTestScene { [Test] public void TestDisposalDoesNotDisposeParentStores() @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Rulesets AddAssert("parent shader manager not disposed", () => !shaderManager.IsDisposed); } - private class DrawableWithDependencies : CompositeDrawable + private partial class DrawableWithDependencies : CompositeDrawable { public TestTextureStore ParentTextureStore { get; private set; } public TestSampleStore ParentSampleStore { get; private set; } diff --git a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs index a29fc9f1fb..11f3fe660d 100644 --- a/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs +++ b/osu.Game.Tests/Rulesets/TestSceneRulesetSkinProvidingContainer.cs @@ -21,7 +21,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Rulesets { [HeadlessTest] - public class TestSceneRulesetSkinProvidingContainer : OsuTestScene + public partial class TestSceneRulesetSkinProvidingContainer : OsuTestScene { private SkinRequester requester; @@ -64,7 +64,7 @@ namespace osu.Game.Tests.Rulesets }); } - private class SkinRequester : Drawable, ISkin + private partial class SkinRequester : Drawable, ISkin { private ISkinSource skin; diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs index a31c624f78..0bbf4406fb 100644 --- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs +++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinLookupDisables.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Skins { [TestFixture] [HeadlessTest] - public class TestSceneBeatmapSkinLookupDisables : OsuTestScene + public partial class TestSceneBeatmapSkinLookupDisables : OsuTestScene { private UserSkinSource userSource; private BeatmapSkinSource beatmapSource; @@ -88,7 +88,7 @@ namespace osu.Game.Tests.Skins } } - public class SkinRequester : Drawable, ISkin + public partial class SkinRequester : Drawable, ISkin { private ISkinSource skin; diff --git a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs index e82a5b57d9..5256bcb3af 100644 --- a/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneBeatmapSkinResources.cs @@ -17,7 +17,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Skins { [HeadlessTest] - public class TestSceneBeatmapSkinResources : OsuTestScene + public partial class TestSceneBeatmapSkinResources : OsuTestScene { [Resolved] private BeatmapManager beatmaps { get; set; } diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index 8c6f137dc0..816834989c 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Skins { [TestFixture] [HeadlessTest] - public class TestSceneSkinConfigurationLookup : OsuTestScene + public partial class TestSceneSkinConfigurationLookup : OsuTestScene { private UserSkinSource userSource; private BeatmapSkinSource beatmapSource; @@ -211,7 +211,7 @@ namespace osu.Game.Tests.Skins } } - public class SkinRequester : Drawable, ISkin + public partial class SkinRequester : Drawable, ISkin { private ISkinSource skin; diff --git a/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs b/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs index ad71296a11..df314b56a9 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinProvidingContainer.cs @@ -20,7 +20,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Skins { [HeadlessTest] - public class TestSceneSkinProvidingContainer : OsuTestScene + public partial class TestSceneSkinProvidingContainer : OsuTestScene { [Resolved] private IRenderer renderer { get; set; } @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Skins }); } - private class TestSkinProvidingContainer : SkinProvidingContainer + private partial class TestSkinProvidingContainer : SkinProvidingContainer { private readonly IEnumerable sources; diff --git a/osu.Game.Tests/Skins/TestSceneSkinResources.cs b/osu.Game.Tests/Skins/TestSceneSkinResources.cs index 22d6d08355..748668b6ca 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinResources.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinResources.cs @@ -26,7 +26,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Skins { [HeadlessTest] - public class TestSceneSkinResources : OsuTestScene + public partial class TestSceneSkinResources : OsuTestScene { [Resolved] private SkinManager skins { get; set; } = null!; diff --git a/osu.Game.Tests/Testing/TestSceneRulesetDependencies.cs b/osu.Game.Tests/Testing/TestSceneRulesetDependencies.cs index 79b44c109a..f1533a32b9 100644 --- a/osu.Game.Tests/Testing/TestSceneRulesetDependencies.cs +++ b/osu.Game.Tests/Testing/TestSceneRulesetDependencies.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Testing /// provided ruleset below are cached at the base implementation. /// [HeadlessTest] - public class TestSceneRulesetDependencies : OsuTestScene + public partial class TestSceneRulesetDependencies : OsuTestScene { protected override Ruleset CreateRuleset() => new TestRuleset(); diff --git a/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs b/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs index 15903b2074..cc72731493 100644 --- a/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs +++ b/osu.Game.Tests/Visual/Audio/TestSceneAudioFilter.cs @@ -19,7 +19,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Tests.Visual.Audio { - public class TestSceneAudioFilter : OsuTestScene + public partial class TestSceneAudioFilter : OsuTestScene { private OsuSpriteText lowPassText; private AudioFilter lowPassFilter; diff --git a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs b/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs index d9dfa1d876..fbdaad1cd8 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneBackgroundScreenDefault.cs @@ -32,7 +32,7 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual.Background { [TestFixture] - public class TestSceneBackgroundScreenDefault : OsuTestScene + public partial class TestSceneBackgroundScreenDefault : OsuTestScene { private BackgroundScreenStack stack; private TestBackgroundScreenDefault screen; @@ -252,7 +252,7 @@ namespace osu.Game.Tests.Visual.Background private WorkingBeatmap createTestWorkingBeatmapWithUniqueBackground() => new UniqueBackgroundTestWorkingBeatmap(renderer, Audio); private WorkingBeatmap createTestWorkingBeatmapWithStoryboard() => new TestWorkingBeatmapWithStoryboard(Audio); - private class TestBackgroundScreenDefault : BackgroundScreenDefault + private partial class TestBackgroundScreenDefault : BackgroundScreenDefault { private bool? lastLoadTriggerCausedChange; @@ -289,7 +289,7 @@ namespace osu.Game.Tests.Visual.Background protected override Texture GetBackground() => renderer.CreateTexture(1, 1); } - private class TestWorkingBeatmapWithStoryboard : TestWorkingBeatmap + private partial class TestWorkingBeatmapWithStoryboard : TestWorkingBeatmap { public TestWorkingBeatmapWithStoryboard(AudioManager audioManager) : base(new Beatmap(), createStoryboard(), audioManager) @@ -315,7 +315,7 @@ namespace osu.Game.Tests.Visual.Background public Drawable CreateDrawable() => new DrawableTestStoryboardElement(); } - private class DrawableTestStoryboardElement : OsuSpriteText + private partial class DrawableTestStoryboardElement : OsuSpriteText { public override bool RemoveWhenNotAlive => false; diff --git a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs index c9920cd01f..54a722cee0 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs @@ -20,7 +20,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tests.Visual.Background { - public class TestSceneSeasonalBackgroundLoader : ScreenTestScene + public partial class TestSceneSeasonalBackgroundLoader : ScreenTestScene { [Resolved] private OsuConfigManager config { get; set; } diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs index 81a3249efb..d3cdf928e8 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesBackground.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Shapes; namespace osu.Game.Tests.Visual.Background { - public class TestSceneTrianglesBackground : OsuTestScene + public partial class TestSceneTrianglesBackground : OsuTestScene { private readonly Triangles triangles; diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs index 917434ae22..5df5337a96 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs @@ -37,7 +37,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Background { [TestFixture] - public class TestSceneUserDimBackgrounds : ScreenTestScene + public partial class TestSceneUserDimBackgrounds : ScreenTestScene { private DummySongSelect songSelect; private TestPlayerLoader playerLoader; @@ -299,7 +299,7 @@ namespace osu.Game.Tests.Visual.Background rulesets?.Dispose(); } - private class DummySongSelect : PlaySongSelect + private partial class DummySongSelect : PlaySongSelect { private FadeAccessibleBackground background; @@ -346,7 +346,7 @@ namespace osu.Game.Tests.Visual.Background public bool IsBackgroundCurrent() => background?.IsCurrentScreen() == true; } - private class FadeAccessibleResults : ResultsScreen + private partial class FadeAccessibleResults : ResultsScreen { public FadeAccessibleResults(ScoreInfo score) : base(score, true) @@ -358,7 +358,7 @@ namespace osu.Game.Tests.Visual.Background public Vector2 ExpectedBackgroundBlur => new Vector2(BACKGROUND_BLUR); } - private class LoadBlockingTestPlayer : TestPlayer + private partial class LoadBlockingTestPlayer : TestPlayer { protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value); @@ -400,7 +400,7 @@ namespace osu.Game.Tests.Visual.Background } } - private class TestPlayerLoader : PlayerLoader + private partial class TestPlayerLoader : PlayerLoader { private FadeAccessibleBackground background; @@ -419,7 +419,7 @@ namespace osu.Game.Tests.Visual.Background protected override BackgroundScreen CreateBackground() => background = new FadeAccessibleBackground(Beatmap.Value); } - private class FadeAccessibleBackground : BackgroundScreenBeatmap + private partial class FadeAccessibleBackground : BackgroundScreenBeatmap { protected override DimmableBackground CreateFadeContainer() => dimmable = new TestDimmableBackground { RelativeSizeAxes = Axes.Both }; @@ -439,7 +439,7 @@ namespace osu.Game.Tests.Visual.Background } } - private class TestDimmableBackground : BackgroundScreenBeatmap.DimmableBackground + private partial class TestDimmableBackground : BackgroundScreenBeatmap.DimmableBackground { public Color4 CurrentColour => Content.Colour; public float CurrentAlpha => Content.Alpha; diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs index 7cad6f504b..ff35f5e8a9 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Background { - public class TestSceneUserDimContainer : OsuTestScene + public partial class TestSceneUserDimContainer : OsuTestScene { private TestUserDimContainer userDimContainer; @@ -104,7 +104,7 @@ namespace osu.Game.Tests.Visual.Background AddAssert("no dim", () => userDimContainer.DimEqual(0)); } - private class TestUserDimContainer : UserDimContainer + private partial class TestUserDimContainer : UserDimContainer { public bool DimEqual(float expectedDimLevel) => Content.Colour == OsuColour.Gray(1f - expectedDimLevel); diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs index f95e3b9990..d4018be7fc 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCard.cs @@ -26,7 +26,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Beatmaps { - public class TestSceneBeatmapCard : OsuManualInputManagerTestScene + public partial class TestSceneBeatmapCard : OsuManualInputManagerTestScene { /// /// All cards on this scene use a common online ID to ensure that map download, preview tracks, etc. can be tested manually with online sources. diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDifficultyList.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDifficultyList.cs index b609b06921..9f3e36ad76 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDifficultyList.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDifficultyList.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Beatmaps { - public class TestSceneBeatmapCardDifficultyList : OsuTestScene + public partial class TestSceneBeatmapCardDifficultyList : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs index 82e18e45bb..ed80def57d 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardDownloadButton.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Beatmaps { - public class TestSceneBeatmapCardDownloadButton : OsuTestScene + public partial class TestSceneBeatmapCardDownloadButton : OsuTestScene { private DownloadButton downloadButton; diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs index 9540d9e4f7..c33033624a 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardFavouriteButton.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Beatmaps { - public class TestSceneBeatmapCardFavouriteButton : OsuManualInputManagerTestScene + public partial class TestSceneBeatmapCardFavouriteButton : OsuManualInputManagerTestScene { private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs index 5afda0ad0c..f44fe2b90c 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapCardThumbnail.cs @@ -17,7 +17,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Beatmaps { - public class TestSceneBeatmapCardThumbnail : OsuManualInputManagerTestScene + public partial class TestSceneBeatmapCardThumbnail : OsuManualInputManagerTestScene { private PlayButton playButton => this.ChildrenOfType().Single(); diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapSetOnlineStatusPill.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapSetOnlineStatusPill.cs index ada521f7f6..8a11d60875 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapSetOnlineStatusPill.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneBeatmapSetOnlineStatusPill.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Beatmaps { - public class TestSceneBeatmapSetOnlineStatusPill : ThemeComparisonTestScene + public partial class TestSceneBeatmapSetOnlineStatusPill : ThemeComparisonTestScene { protected override Drawable CreateContent() => new FillFlowContainer { diff --git a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultySpectrumDisplay.cs b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultySpectrumDisplay.cs index 94b2d10fcf..11fa6ed92d 100644 --- a/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultySpectrumDisplay.cs +++ b/osu.Game.Tests/Visual/Beatmaps/TestSceneDifficultySpectrumDisplay.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Beatmaps { - public class TestSceneDifficultySpectrumDisplay : OsuTestScene + public partial class TestSceneDifficultySpectrumDisplay : OsuTestScene { private DifficultySpectrumDisplay display; diff --git a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs index 77e781bfe4..1e9982f8d4 100644 --- a/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs +++ b/osu.Game.Tests/Visual/Collections/TestSceneManageCollectionsDialog.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Collections { - public class TestSceneManageCollectionsDialog : OsuManualInputManagerTestScene + public partial class TestSceneManageCollectionsDialog : OsuManualInputManagerTestScene { protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game.Tests/Visual/Colours/TestSceneStarDifficultyColours.cs b/osu.Game.Tests/Visual/Colours/TestSceneStarDifficultyColours.cs index 13d7a33600..55a2efa89d 100644 --- a/osu.Game.Tests/Visual/Colours/TestSceneStarDifficultyColours.cs +++ b/osu.Game.Tests/Visual/Colours/TestSceneStarDifficultyColours.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Colours { - public class TestSceneStarDifficultyColours : OsuTestScene + public partial class TestSceneStarDifficultyColours : OsuTestScene { [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs b/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs index 9dd75b6e5e..aad30ff450 100644 --- a/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs +++ b/osu.Game.Tests/Visual/Components/TestSceneIdleTracker.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Components { [TestFixture] - public class TestSceneIdleTracker : OsuManualInputManagerTestScene + public partial class TestSceneIdleTracker : OsuManualInputManagerTestScene { private IdleTrackingBox box1; private IdleTrackingBox box2; @@ -154,7 +154,7 @@ namespace osu.Game.Tests.Visual.Components AddUntilStep("wait for all idle", () => box1.IsIdle && box2.IsIdle && box3.IsIdle && box4.IsIdle); } - private class IdleTrackingBox : CompositeDrawable + private partial class IdleTrackingBox : CompositeDrawable { private readonly IdleTracker idleTracker; diff --git a/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs b/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs index 3c89267610..4bab8d0ccc 100644 --- a/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs +++ b/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Components { [HeadlessTest] - public class TestScenePollingComponent : OsuTestScene + public partial class TestScenePollingComponent : OsuTestScene { private Container pollBox; private TestPoller poller; @@ -132,7 +132,7 @@ namespace osu.Game.Tests.Visual.Components protected override double TimePerAction => 500; - public class TestPoller : PollingComponent + public partial class TestPoller : PollingComponent { public event Action OnPoll; @@ -143,7 +143,7 @@ namespace osu.Game.Tests.Visual.Components } } - public class TestSlowPoller : TestPoller + public partial class TestSlowPoller : TestPoller { protected override Task Poll() => Task.Delay((int)(TimeBetweenPolls.Value / 2f / Clock.Rate)).ContinueWith(_ => base.Poll()); } diff --git a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs index 94a71ed50c..b334616125 100644 --- a/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs +++ b/osu.Game.Tests/Visual/Components/TestScenePreviewTrackManager.cs @@ -13,7 +13,7 @@ using osu.Game.Beatmaps; namespace osu.Game.Tests.Visual.Components { - public class TestScenePreviewTrackManager : OsuTestScene, IPreviewTrackOwner + public partial class TestScenePreviewTrackManager : OsuTestScene, IPreviewTrackOwner { private readonly IAdjustableAudioComponent gameTrackAudio = new AudioAdjustments(); @@ -201,7 +201,7 @@ namespace osu.Game.Tests.Visual.Components return track; } - private class TestTrackOwner : CompositeDrawable, IPreviewTrackOwner + private partial class TestTrackOwner : CompositeDrawable, IPreviewTrackOwner { private readonly PreviewTrack track; private readonly bool registerAsOwner; @@ -227,7 +227,7 @@ namespace osu.Game.Tests.Visual.Components } } - public class TestPreviewTrackManager : PreviewTrackManager + public partial class TestPreviewTrackManager : PreviewTrackManager { public bool AllowUpdate = true; @@ -248,7 +248,7 @@ namespace osu.Game.Tests.Visual.Components return base.UpdateSubTree(); } - public class TestPreviewTrack : TrackManagerPreviewTrack + public partial class TestPreviewTrack : TrackManagerPreviewTrack { private readonly ITrackStore trackManager; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs index f2d27b9117..56b16301be 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneBeatDivisorControl.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneBeatDivisorControl : OsuManualInputManagerTestScene + public partial class TestSceneBeatDivisorControl : OsuManualInputManagerTestScene { private BeatDivisorControl beatDivisorControl; private BindableBeatDivisor bindableBeatDivisor; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneBlueprintOrdering.cs b/osu.Game.Tests/Visual/Editing/TestSceneBlueprintOrdering.cs index 796a3cf9fc..7728adecae 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneBlueprintOrdering.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneBlueprintOrdering.cs @@ -24,7 +24,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneBlueprintOrdering : EditorTestScene + public partial class TestSceneBlueprintOrdering : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs index 0df44b9ac4..035092ecb7 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs @@ -21,7 +21,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneComposeScreen : EditorClockTestScene + public partial class TestSceneComposeScreen : EditorClockTestScene { private EditorBeatmap editorBeatmap = null!; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposeSelectBox.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposeSelectBox.cs index 52e44efb30..7a0b3d0c1a 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneComposeSelectBox.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneComposeSelectBox.cs @@ -15,7 +15,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneComposeSelectBox : OsuManualInputManagerTestScene + public partial class TestSceneComposeSelectBox : OsuManualInputManagerTestScene { private Container selectionArea; private SelectionBox selectionBox; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs index 31fc107892..ffb8a67c68 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneComposerSelection.cs @@ -26,7 +26,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneComposerSelection : EditorTestScene + public partial class TestSceneComposerSelection : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs b/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs index 1ecbc24d90..9a66e1676d 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneDesignSection : OsuManualInputManagerTestScene + public partial class TestSceneDesignSection : OsuManualInputManagerTestScene { private TestDesignSection designSection; private EditorBeatmap editorBeatmap { get; set; } @@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual.Editing AddAssert($"beatmap value is {expectedFinalValue}", () => editorBeatmap.BeatmapInfo.CountdownOffset == expectedFinalValue); } - private class TestDesignSection : DesignSection + private partial class TestDesignSection : DesignSection { public new LabelledSwitchButton EnableCountdown => base.EnableCountdown; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs index 4366b1c0bb..280e6de97e 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultyDelete.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneDifficultyDelete : EditorTestScene + public partial class TestSceneDifficultyDelete : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); protected override bool IsolateSavingFromDatabase => false; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs index 1f88fa8f35..69070b0b64 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs @@ -20,7 +20,7 @@ using osu.Game.Tests.Beatmaps.IO; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneDifficultySwitching : EditorTestScene + public partial class TestSceneDifficultySwitching : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs b/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs index 01a49c7dea..21b925a257 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDistanceSnapGrid.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneDistanceSnapGrid : EditorClockTestScene + public partial class TestSceneDistanceSnapGrid : EditorClockTestScene { private const double beat_length = 100; private const int beat_snap_distance = 10; @@ -108,7 +108,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("check correct interval count", () => Assert.That((end_time / grid.DistanceBetweenTicks) * multiplier, Is.EqualTo(grid.MaxIntervals))); } - private class TestDistanceSnapGrid : DistanceSnapGrid + private partial class TestDistanceSnapGrid : DistanceSnapGrid { public new float DistanceBetweenTicks => base.DistanceBetweenTicks; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index 80a5b4832b..a40c7814e1 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -31,7 +31,7 @@ using SharpCompress.Archives.Zip; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneEditorBeatmapCreation : EditorTestScene + public partial class TestSceneEditorBeatmapCreation : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBindings.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBindings.cs index 5771d64775..61723aab7e 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBindings.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBindings.cs @@ -11,7 +11,7 @@ namespace osu.Game.Tests.Visual.Editing /// /// Test editor hotkeys at a high level to ensure they all work well together. /// - public class TestSceneEditorBindings : EditorTestScene + public partial class TestSceneEditorBindings : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorChangeStates.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorChangeStates.cs index 109a49310a..278b6e9626 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorChangeStates.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorChangeStates.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneEditorChangeStates : EditorTestScene + public partial class TestSceneEditorChangeStates : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs index 0a5a1febe4..d26bb6bb8a 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorClipboard.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneEditorClipboard : EditorTestScene + public partial class TestSceneEditorClipboard : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs index 319f8ab9dc..82d2542190 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneEditorClock : EditorClockTestScene + public partial class TestSceneEditorClock : EditorClockTestScene { [Cached] private EditorBeatmap editorBeatmap = new EditorBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo)); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorComposeRadioButtons.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorComposeRadioButtons.cs index 6a69347651..e11d2e9dbf 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorComposeRadioButtons.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorComposeRadioButtons.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Edit.Components.RadioButtons; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneEditorComposeRadioButtons : OsuTestScene + public partial class TestSceneEditorComposeRadioButtons : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorMenuBar.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorMenuBar.cs index 913155aafb..699b99c57f 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorMenuBar.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorMenuBar.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.Edit.Components.Menus; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneEditorMenuBar : OsuTestScene + public partial class TestSceneEditorMenuBar : OsuTestScene { [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Aquamarine); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs index 327d581e37..5914290d40 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorNavigation.cs @@ -17,7 +17,7 @@ using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneEditorNavigation : OsuGameTestScene + public partial class TestSceneEditorNavigation : OsuGameTestScene { [Test] public void TestEditorGameplayTestAlwaysUsesOriginalRuleset() diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSamplePlayback.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSamplePlayback.cs index 43a3cb1342..8b941d7597 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSamplePlayback.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSamplePlayback.cs @@ -13,7 +13,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneEditorSamplePlayback : EditorTestScene + public partial class TestSceneEditorSamplePlayback : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs index d7e9cc1bc0..70118e0b67 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneEditorSaving : EditorSavingTestScene + public partial class TestSceneEditorSaving : EditorSavingTestScene { [Test] public void TestCantExitWithoutSaving() diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorScreenModes.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorScreenModes.cs index 962260e1bd..a9d054881b 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorScreenModes.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorScreenModes.cs @@ -12,7 +12,7 @@ using osu.Game.Screens.Edit; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneEditorScreenModes : EditorTestScene + public partial class TestSceneEditorScreenModes : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs index aa4bccd728..9df5df6b39 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeekSnapping.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneEditorSeekSnapping : EditorClockTestScene + public partial class TestSceneEditorSeekSnapping : EditorClockTestScene { public TestSceneEditorSeekSnapping() { @@ -315,7 +315,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("Reset", () => EditorClock.Seek(0)); } - private class TimingPointVisualiser : CompositeDrawable + private partial class TimingPointVisualiser : CompositeDrawable { private readonly double length; @@ -386,7 +386,7 @@ namespace osu.Game.Tests.Visual.Editing tracker.X = (float)(Time.Current / length); } - private class TimingPointTimeline : CompositeDrawable + private partial class TimingPointTimeline : CompositeDrawable { public TimingPointTimeline(TimingControlPoint timingPoint, double endTime, double fullDuration) { diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs index 924396ce03..817e0f17f7 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs @@ -12,7 +12,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneEditorSeeking : EditorTestScene + public partial class TestSceneEditorSeeking : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs index 3657878075..ccd2feef9c 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSummaryTimeline.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneEditorSummaryTimeline : EditorClockTestScene + public partial class TestSceneEditorSummaryTimeline : EditorClockTestScene { [Cached(typeof(EditorBeatmap))] private readonly EditorBeatmap editorBeatmap; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs index ee6c322ee3..2250868a39 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorTestGameplay.cs @@ -27,7 +27,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneEditorTestGameplay : EditorTestScene + public partial class TestSceneEditorTestGameplay : EditorTestScene { protected override bool IsolateSavingFromDatabase => false; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs index 1c87eb49c9..7ab0188114 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectComposer.cs @@ -29,7 +29,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneHitObjectComposer : EditorClockTestScene + public partial class TestSceneHitObjectComposer : EditorClockTestScene { private OsuHitObjectComposer hitObjectComposer; private EditorBeatmapContainer editorBeatmapContainer; @@ -168,7 +168,7 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("distance spacing increased by 0.5", () => editorBeatmap.BeatmapInfo.DistanceSpacing == originalSpacing + 0.5); } - public class EditorBeatmapContainer : Container + public partial class EditorBeatmapContainer : Container { private readonly IWorkingBeatmap working; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectDifficultyPointAdjustments.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectDifficultyPointAdjustments.cs index a429c6f58b..ab82678eb9 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectDifficultyPointAdjustments.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectDifficultyPointAdjustments.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneHitObjectDifficultyPointAdjustments : EditorTestScene + public partial class TestSceneHitObjectDifficultyPointAdjustments : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSamplePointAdjustments.cs b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSamplePointAdjustments.cs index 6313842dfd..e8dcc6f19b 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSamplePointAdjustments.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneHitObjectSamplePointAdjustments.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneHitObjectSamplePointAdjustments : EditorTestScene + public partial class TestSceneHitObjectSamplePointAdjustments : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneLabelledTimeSignature.cs b/osu.Game.Tests/Visual/Editing/TestSceneLabelledTimeSignature.cs index 328e41ebea..e91596b872 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneLabelledTimeSignature.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneLabelledTimeSignature.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Edit.Timing; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneLabelledTimeSignature : OsuManualInputManagerTestScene + public partial class TestSceneLabelledTimeSignature : OsuManualInputManagerTestScene { private LabelledTimeSignature timeSignature; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs b/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs index d87bbd8a10..a9f8e19e30 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneMetadataSection.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Edit.Setup; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneMetadataSection : OsuTestScene + public partial class TestSceneMetadataSection : OsuTestScene { [Cached] private EditorBeatmap editorBeatmap = new EditorBeatmap(new Beatmap @@ -141,7 +141,7 @@ namespace osu.Game.Tests.Visual.Editing AddAssert($"romanised title is {(editable ? "" : "not ")}editable", () => metadataSection.RomanisedTitleTextBox.ReadOnly == !editable); } - private class TestMetadataSection : MetadataSection + private partial class TestMetadataSection : MetadataSection { public new LabelledTextBox ArtistTextBox => base.ArtistTextBox; public new LabelledTextBox RomanisedArtistTextBox => base.RomanisedArtistTextBox; diff --git a/osu.Game.Tests/Visual/Editing/TestScenePlaybackControl.cs b/osu.Game.Tests/Visual/Editing/TestScenePlaybackControl.cs index 674476d644..6fa52d5bbc 100644 --- a/osu.Game.Tests/Visual/Editing/TestScenePlaybackControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestScenePlaybackControl.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestScenePlaybackControl : EditorClockTestScene + public partial class TestScenePlaybackControl : EditorClockTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tests/Visual/Editing/TestSceneRectangularPositionSnapGrid.cs b/osu.Game.Tests/Visual/Editing/TestSceneRectangularPositionSnapGrid.cs index 7ad12c37bc..e73a45e154 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneRectangularPositionSnapGrid.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneRectangularPositionSnapGrid.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneRectangularPositionSnapGrid : OsuManualInputManagerTestScene + public partial class TestSceneRectangularPositionSnapGrid : OsuManualInputManagerTestScene { private Container content; protected override Container Content => content; @@ -64,7 +64,7 @@ namespace osu.Game.Tests.Visual.Editing })); } - private class SnappingCursorContainer : CompositeDrawable + private partial class SnappingCursorContainer : CompositeDrawable { public Func GetSnapPosition; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs b/osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs index 5c933468be..24f50d36a2 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneSelectionBlueprintDeselection.cs @@ -12,7 +12,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneSelectionBlueprintDeselection : EditorTestScene + public partial class TestSceneSelectionBlueprintDeselection : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs index ddb458d570..c0e681b8b4 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs @@ -20,7 +20,7 @@ using osu.Game.Screens.Edit.Setup; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneSetupScreen : EditorClockTestScene + public partial class TestSceneSetupScreen : EditorClockTestScene { [Cached(typeof(EditorBeatmap))] [Cached(typeof(IBeatSnapProvider))] diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapButton.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapButton.cs index f36524290a..8562fb746a 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTapButton.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapButton.cs @@ -13,7 +13,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneTapButton : OsuManualInputManagerTestScene + public partial class TestSceneTapButton : OsuManualInputManagerTestScene { private TapButton tapButton; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs index 6ed63515e9..f38df89e82 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTapTimingControl.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneTapTimingControl : EditorClockTestScene + public partial class TestSceneTapTimingControl : EditorClockTestScene { private EditorBeatmap editorBeatmap => editorBeatmapContainer?.EditorBeatmap; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineBlueprintContainer.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineBlueprintContainer.cs index c098b683a6..b63296a48d 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineBlueprintContainer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineBlueprintContainer.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Edit.Compose.Components.Timeline; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneTimelineBlueprintContainer : TimelineTestScene + public partial class TestSceneTimelineBlueprintContainer : TimelineTestScene { public override Drawable CreateTestComponent() => new TimelineBlueprintContainer(Composer); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineHitObjectBlueprint.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineHitObjectBlueprint.cs index 603dbf4c67..709d796e97 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineHitObjectBlueprint.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineHitObjectBlueprint.cs @@ -18,7 +18,7 @@ using static osu.Game.Screens.Edit.Compose.Components.Timeline.TimelineHitObject namespace osu.Game.Tests.Visual.Editing { - public class TestSceneTimelineHitObjectBlueprint : TimelineTestScene + public partial class TestSceneTimelineHitObjectBlueprint : TimelineTestScene { public override Drawable CreateTestComponent() => new TimelineBlueprintContainer(Composer); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs index 54ad4e25e4..50eeb9a54b 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineSelection.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneTimelineSelection : EditorTestScene + public partial class TestSceneTimelineSelection : EditorTestScene { protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineTickDisplay.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineTickDisplay.cs index b02f0b09b4..41fb3ed8b9 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineTickDisplay.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineTickDisplay.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneTimelineTickDisplay : TimelineTestScene + public partial class TestSceneTimelineTickDisplay : TimelineTestScene { public override Drawable CreateTestComponent() => Empty(); // tick display is implicitly inside the timeline. diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs index 11ac102814..19f4678c15 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimelineZoom.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneTimelineZoom : TimelineTestScene + public partial class TestSceneTimelineZoom : TimelineTestScene { public override Drawable CreateTestComponent() => Empty(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs index e7805bf393..86a977fd3f 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneTimingScreen : EditorClockTestScene + public partial class TestSceneTimingScreen : EditorClockTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneWaveform.cs b/osu.Game.Tests/Visual/Editing/TestSceneWaveform.cs index 82b0d70cff..4c2b77bb1d 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneWaveform.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneWaveform.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Editing { [TestFixture] - public class TestSceneWaveform : OsuTestScene + public partial class TestSceneWaveform : OsuTestScene { private IWorkingBeatmap waveformBeatmap; @@ -104,7 +104,7 @@ namespace osu.Game.Tests.Visual.Editing AddUntilStep("wait for load", () => graph.Loaded.IsSet); } - public class TestWaveformGraph : WaveformGraph + public partial class TestWaveformGraph : WaveformGraph { public readonly ManualResetEventSlim Loaded = new ManualResetEventSlim(); diff --git a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs index 89c5b9b23b..6bc2922253 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneZoomableScrollContainer : OsuManualInputManagerTestScene + public partial class TestSceneZoomableScrollContainer : OsuManualInputManagerTestScene { private ZoomableScrollContainer scrollContainer; private Drawable innerBox; diff --git a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs index c2b1ba3aba..cb45ad5a07 100644 --- a/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs +++ b/osu.Game.Tests/Visual/Editing/TimelineTestScene.cs @@ -23,7 +23,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Editing { - public abstract class TimelineTestScene : EditorClockTestScene + public abstract partial class TimelineTestScene : EditorClockTestScene { protected TimelineArea TimelineArea { get; private set; } @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual.Editing public abstract Drawable CreateTestComponent(); - private class AudioVisualiser : CompositeDrawable + private partial class AudioVisualiser : CompositeDrawable { private readonly Drawable marker; @@ -126,7 +126,7 @@ namespace osu.Game.Tests.Visual.Editing } } - private class StartStopButton : OsuButton + private partial class StartStopButton : OsuButton { [Resolved] private EditorClock editorClock { get; set; } diff --git a/osu.Game.Tests/Visual/Gameplay/OsuPlayerTestScene.cs b/osu.Game.Tests/Visual/Gameplay/OsuPlayerTestScene.cs index f173170da5..7ff059ff77 100644 --- a/osu.Game.Tests/Visual/Gameplay/OsuPlayerTestScene.cs +++ b/osu.Game.Tests/Visual/Gameplay/OsuPlayerTestScene.cs @@ -11,7 +11,7 @@ namespace osu.Game.Tests.Visual.Gameplay /// /// A with an arbitrary ruleset value to test with. /// - public abstract class OsuPlayerTestScene : PlayerTestScene + public abstract partial class OsuPlayerTestScene : PlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); } diff --git a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs index ea4aa98f86..545b3c2cf4 100644 --- a/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs +++ b/osu.Game.Tests/Visual/Gameplay/SkinnableHUDComponentTestScene.cs @@ -9,7 +9,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { - public abstract class SkinnableHUDComponentTestScene : SkinnableTestScene + public abstract partial class SkinnableHUDComponentTestScene : SkinnableTestScene { protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs index a8d7148bd2..e86302bbd1 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Gameplay /// A base class which runs test for all available rulesets. /// Steps to be run for each ruleset should be added via . /// - public abstract class TestSceneAllRulesetPlayers : RateAdjustedBeatmapTestScene + public abstract partial class TestSceneAllRulesetPlayers : RateAdjustedBeatmapTestScene { protected Player Player { get; private set; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs index f2fe55d719..5442b3bfef 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs @@ -19,7 +19,7 @@ using osu.Game.Users.Drawables; namespace osu.Game.Tests.Visual.Gameplay { [Description("Player instantiated with an autoplay mod.")] - public class TestSceneAutoplay : TestSceneAllRulesetPlayers + public partial class TestSceneAutoplay : TestSceneAllRulesetPlayers { protected new TestReplayPlayer Player => (TestReplayPlayer)base.Player; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs index cfd282c404..6eae795630 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapOffsetControl.cs @@ -14,7 +14,7 @@ using osu.Game.Tests.Visual.Ranking; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneBeatmapOffsetControl : OsuTestScene + public partial class TestSceneBeatmapOffsetControl : OsuTestScene { private BeatmapOffsetControl offsetControl; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 8ad97eb33c..5cd8c00935 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -26,7 +26,7 @@ using osu.Game.Storyboards; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneBeatmapSkinFallbacks : OsuPlayerTestScene + public partial class TestSceneBeatmapSkinFallbacks : OsuPlayerTestScene { private ISkin currentBeatmapSkin; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs index 28a9d17882..a40eab5948 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBezierConverter.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneBezierConverter : OsuTestScene + public partial class TestSceneBezierConverter : OsuTestScene { private readonly SmoothPath drawablePath; private readonly SmoothPath controlPointDrawablePath; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBreakTracker.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBreakTracker.cs index e31b325d54..c010b2c809 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBreakTracker.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBreakTracker.cs @@ -14,7 +14,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneBreakTracker : OsuTestScene + public partial class TestSceneBreakTracker : OsuTestScene { private readonly BreakOverlay breakOverlay; @@ -161,7 +161,7 @@ namespace osu.Game.Tests.Visual.Gameplay }); } - private class TestBreakTracker : BreakTracker + private partial class TestBreakTracker : BreakTracker { public readonly FramedClock FramedManualClock; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs index 2dad5e2c32..6b8e0e1088 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneClicksPerSecondCalculator.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneClicksPerSecondCalculator : OsuTestScene + public partial class TestSceneClicksPerSecondCalculator : OsuTestScene { private ClicksPerSecondCalculator calculator = null!; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs index a953db4f19..0784aac298 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneColourHitErrorMeter.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneColourHitErrorMeter : OsuTestScene + public partial class TestSceneColourHitErrorMeter : OsuTestScene { private DependencyProvidingContainer dependencyContainer = null!; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs index 13ceb05aff..434d853992 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneCompletionCancellation.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneCompletionCancellation : OsuPlayerTestScene + public partial class TestSceneCompletionCancellation : OsuPlayerTestScene { [Resolved] private AudioManager audio { get; set; } @@ -122,7 +122,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override TestPlayer CreatePlayer(Ruleset ruleset) => new FakeRankingPushPlayer(); - public class FakeRankingPushPlayer : TestPlayer + public partial class FakeRankingPushPlayer : TestPlayer { public bool ResultsCreated { get; private set; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs index 334d8f1452..287b7d43b4 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs @@ -33,7 +33,7 @@ using JetBrains.Annotations; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneDrawableScrollingRuleset : OsuTestScene + public partial class TestSceneDrawableScrollingRuleset : OsuTestScene { /// /// The amount of time visible by the "view window" of the playfield. @@ -305,7 +305,7 @@ namespace osu.Game.Tests.Visual.Gameplay public override string ShortName { get; } = string.Empty; } - private class TestDrawableScrollingRuleset : DrawableScrollingRuleset + private partial class TestDrawableScrollingRuleset : DrawableScrollingRuleset { public bool RelativeScaleBeatLengthsOverride { get; set; } @@ -342,7 +342,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override Playfield CreatePlayfield() => new TestPlayfield(); } - private class TestPlayfield : ScrollingPlayfield + private partial class TestPlayfield : ScrollingPlayfield { public TestPlayfield() { @@ -427,7 +427,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class DrawableTestHitObject : DrawableHitObject + private partial class DrawableTestHitObject : DrawableHitObject { public DrawableTestHitObject([CanBeNull] TestHitObject hitObject) : base(hitObject) @@ -457,7 +457,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override void Update() => LifetimeEnd = HitObject.EndTime; } - private class DrawableTestPooledHitObject : DrawableTestHitObject + private partial class DrawableTestPooledHitObject : DrawableTestHitObject { public DrawableTestPooledHitObject() : base(null) @@ -467,7 +467,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class DrawableTestParentHitObject : DrawableTestHitObject + private partial class DrawableTestParentHitObject : DrawableTestHitObject { private readonly Container container; @@ -491,7 +491,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override void ClearNestedHitObjects() => container.Clear(false); } - private class DrawableTestPooledParentHitObject : DrawableTestParentHitObject + private partial class DrawableTestPooledParentHitObject : DrawableTestParentHitObject { public DrawableTestPooledParentHitObject() : base(null) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs index 3fc456c411..ec4bb1a86b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableStoryboardSprite.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneDrawableStoryboardSprite : SkinnableTestScene + public partial class TestSceneDrawableStoryboardSprite : SkinnableTestScene { protected override Ruleset CreateRulesetForSkinProvider() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs index ce01bf2fb5..6cb1101173 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneFailAnimation : TestSceneAllRulesetPlayers + public partial class TestSceneFailAnimation : TestSceneAllRulesetPlayers { protected override Player CreatePlayer(Ruleset ruleset) { @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("frequency only ever decreased", () => !((FailPlayer)Player).FrequencyIncreased); } - private class FailPlayer : TestPlayer + private partial class FailPlayer : TestPlayer { public new FailOverlay FailOverlay => base.FailOverlay; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs index 5e87eff717..e779c6c1cb 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneFailJudgement : TestSceneAllRulesetPlayers + public partial class TestSceneFailJudgement : TestSceneAllRulesetPlayers { protected override Player CreatePlayer(Ruleset ruleset) { @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Visual.Gameplay }); } - private class FailPlayer : TestPlayer + private partial class FailPlayer : TestPlayer { public new HealthProcessor HealthProcessor => base.HealthProcessor; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailingLayer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailingLayer.cs index 90e36ecae2..235ada2d63 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailingLayer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailingLayer.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneFailingLayer : OsuTestScene + public partial class TestSceneFailingLayer : OsuTestScene { private FailingLayer layer; @@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("layer fade is visible", () => layer.IsPresent); } - private class HealthProcessorContainer : Container + private partial class HealthProcessorContainer : Container { [Cached(typeof(HealthProcessor))] private readonly HealthProcessor healthProcessor; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFrameStabilityContainer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFrameStabilityContainer.cs index ef74024b4b..534348bed3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneFrameStabilityContainer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFrameStabilityContainer.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneFrameStabilityContainer : OsuTestScene + public partial class TestSceneFrameStabilityContainer : OsuTestScene { private readonly ManualClock manualClock; @@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void checkRate(double rate) => AddAssert($"clock rate is {rate}", () => consumer.Clock.Rate, () => Is.EqualTo(rate)); - public class ClockConsumingChild : CompositeDrawable + public partial class ClockConsumingChild : CompositeDrawable { private readonly OsuSpriteText text; private readonly OsuSpriteText text2; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 30d2cc6423..d4000c07e7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneGameplayLeaderboard : OsuTestScene + public partial class TestSceneGameplayLeaderboard : OsuTestScene { private TestGameplayLeaderboard leaderboard; @@ -169,7 +169,7 @@ namespace osu.Game.Tests.Visual.Gameplay leaderboardScore.TotalScore.BindTo(score); } - private class TestGameplayLeaderboard : GameplayLeaderboard + private partial class TestGameplayLeaderboard : GameplayLeaderboard { public float Spacing => Flow.Spacing.Y; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs index f3a6302da0..aa5e5985c3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayMenuOverlay.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { [Description("player pause/fail screens")] - public class TestSceneGameplayMenuOverlay : OsuManualInputManagerTestScene + public partial class TestSceneGameplayMenuOverlay : OsuManualInputManagerTestScene { private FailOverlay failOverlay; private PauseOverlay pauseOverlay; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs index bd55ed8bd6..1dffeed01b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneGameplayRewinding : OsuPlayerTestScene + public partial class TestSceneGameplayRewinding : OsuPlayerTestScene { [Resolved] private AudioManager audioManager { get; set; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySamplePlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySamplePlayback.cs index 1fe2dfd4df..3d35860fef 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySamplePlayback.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySamplePlayback.cs @@ -14,7 +14,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneGameplaySamplePlayback : PlayerTestScene + public partial class TestSceneGameplaySamplePlayback : PlayerTestScene { [Test] public void TestAllSamplesStopDuringSeek() diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index b6da562bd0..e184d50d7c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneGameplaySampleTriggerSource : PlayerTestScene + public partial class TestSceneGameplaySampleTriggerSource : PlayerTestScene { private TestGameplaySampleTriggerSource sampleTriggerSource; protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); @@ -124,7 +124,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddRepeatStep("trigger sample", () => sampleTriggerSource.Play(), 10); } - public class TestGameplaySampleTriggerSource : GameplaySampleTriggerSource + public partial class TestGameplaySampleTriggerSource : GameplaySampleTriggerSource { public TestGameplaySampleTriggerSource(HitObjectContainer hitObjectContainer) : base(hitObjectContainer) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 75510fa822..94f9b4262d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -24,7 +24,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneHUDOverlay : OsuManualInputManagerTestScene + public partial class TestSceneHUDOverlay : OsuManualInputManagerTestScene { private OsuConfigManager localConfig = null!; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index b90b9b437d..e2ff2780e0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -31,7 +31,7 @@ using osu.Game.Screens.Play.HUD.HitErrorMeters; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneHitErrorMeter : OsuTestScene + public partial class TestSceneHitErrorMeter : OsuTestScene { [Cached(typeof(ScoreProcessor))] private TestScoreProcessor scoreProcessor = new TestScoreProcessor(); @@ -263,7 +263,7 @@ namespace osu.Game.Tests.Visual.Gameplay } [SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")] - private class TestDrawableRuleset : DrawableRuleset + private partial class TestDrawableRuleset : DrawableRuleset { public HitWindows HitWindows; @@ -305,7 +305,7 @@ namespace osu.Game.Tests.Visual.Gameplay public override void CancelResume() => throw new NotImplementedException(); } - private class TestScoreProcessor : ScoreProcessor + private partial class TestScoreProcessor : ScoreProcessor { public TestScoreProcessor() : base(new OsuRuleset()) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHoldForMenuButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHoldForMenuButton.cs index 50fd1b2a51..3c225d60e0 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHoldForMenuButton.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHoldForMenuButton.cs @@ -15,7 +15,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { [Description("'Hold to Quit' UI element")] - public class TestSceneHoldForMenuButton : OsuManualInputManagerTestScene + public partial class TestSceneHoldForMenuButton : OsuManualInputManagerTestScene { private bool exitAction; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyBindings.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyBindings.cs index c690203f82..53c07304cf 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyBindings.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyBindings.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { [HeadlessTest] - public class TestSceneKeyBindings : OsuManualInputManagerTestScene + public partial class TestSceneKeyBindings : OsuManualInputManagerTestScene { private readonly ActionReceiver receiver; @@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.Gameplay Down, } - private class TestKeyBindingContainer : DatabasedKeyBindingContainer + private partial class TestKeyBindingContainer : DatabasedKeyBindingContainer { public TestKeyBindingContainer() : base(new TestRuleset().RulesetInfo, 0) @@ -79,7 +79,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class ActionReceiver : CompositeDrawable, IKeyBindingHandler + private partial class ActionReceiver : CompositeDrawable, IKeyBindingHandler { public bool ReceivedAction; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs index bfda6f50cb..890ac21b40 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs @@ -13,7 +13,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneKeyCounter : OsuManualInputManagerTestScene + public partial class TestSceneKeyCounter : OsuManualInputManagerTestScene { public TestSceneKeyCounter() { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs index c18a78fe3c..dadf3ca65f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneLeadIn : RateAdjustedBeatmapTestScene + public partial class TestSceneLeadIn : RateAdjustedBeatmapTestScene { private LeadInPlayer player = null!; @@ -106,7 +106,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("player loaded", () => player.IsLoaded && player.Alpha == 1); } - private class LeadInPlayer : TestPlayer + private partial class LeadInPlayer : TestPlayer { public LeadInPlayer() : base(false, false) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneMedalOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneMedalOverlay.cs index 3fd36d509d..626406e4d2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneMedalOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneMedalOverlay.cs @@ -10,7 +10,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneMedalOverlay : OsuTestScene + public partial class TestSceneMedalOverlay : OsuTestScene { public TestSceneMedalOverlay() { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs index 0c6b656ab6..b26f48d028 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneModValidity.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Tests.Visual.Gameplay { [HeadlessTest] - public class TestSceneModValidity : TestSceneAllRulesetPlayers + public partial class TestSceneModValidity : TestSceneAllRulesetPlayers { protected override void AddCheckSteps() { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneNightcoreBeatContainer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneNightcoreBeatContainer.cs index 966138c0b3..84334ba0a9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneNightcoreBeatContainer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneNightcoreBeatContainer.cs @@ -13,7 +13,7 @@ using osu.Game.Tests.Visual.UserInterface; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneNightcoreBeatContainer : TestSceneBeatSyncedContainer + public partial class TestSceneNightcoreBeatContainer : TestSceneBeatSyncedContainer { protected override void LoadComplete() { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs index 789e7e770f..269d104fa3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneOverlayActivation : OsuPlayerTestScene + public partial class TestSceneOverlayActivation : OsuPlayerTestScene { protected new OverlayTestPlayer Player => base.Player as OverlayTestPlayer; @@ -64,7 +64,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override TestPlayer CreatePlayer(Ruleset ruleset) => new OverlayTestPlayer(); - protected class OverlayTestPlayer : TestPlayer + protected partial class OverlayTestPlayer : TestPlayer { public new OverlayActivation OverlayActivationMode => base.OverlayActivationMode.Value; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleExplosion.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleExplosion.cs index bddf051871..2d48ac81e2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleExplosion.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleExplosion.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneParticleExplosion : OsuTestScene + public partial class TestSceneParticleExplosion : OsuTestScene { private ParticleExplosion explosion; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs index 66441c8bad..c73d57dc2b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneParticleSpewer.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneParticleSpewer : OsuTestScene + public partial class TestSceneParticleSpewer : OsuTestScene { private TestParticleSpewer spewer; @@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay Size = new Vector2(0.5f), }; - private class TestParticleSpewer : ParticleSpewer + private partial class TestParticleSpewer : ParticleSpewer { public const int MAX_DURATION = 1500; private const int rate = 250; diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index d0371acce7..7880a849a2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestScenePause : OsuPlayerTestScene + public partial class TestScenePause : OsuPlayerTestScene { protected new PausePlayer Player => (PausePlayer)base.Player; @@ -396,7 +396,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override TestPlayer CreatePlayer(Ruleset ruleset) => new PausePlayer(); - protected class PausePlayer : TestPlayer + protected partial class PausePlayer : TestPlayer { public double LastPauseTime { get; private set; } public double LastResumeTime { get; private set; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePauseWhenInactive.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePauseWhenInactive.cs index e1c755b90c..b770f72f19 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePauseWhenInactive.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePauseWhenInactive.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { [HeadlessTest] // we alter unsafe properties on the game host to test inactive window state. - public class TestScenePauseWhenInactive : OsuPlayerTestScene + public partial class TestScenePauseWhenInactive : OsuPlayerTestScene { [Resolved] private GameHost host { get; set; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs index a86e707400..9622caabf5 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePerformancePointsCounter.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestScenePerformancePointsCounter : OsuTestScene + public partial class TestScenePerformancePointsCounter : OsuTestScene { private DependencyProvidingContainer dependencyContainer; diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs index 6b24ac7384..2ea27c2fef 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs @@ -32,7 +32,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestScenePlayerLoader : ScreenTestScene + public partial class TestScenePlayerLoader : ScreenTestScene { private TestPlayerLoader loader; private TestPlayer player; @@ -451,7 +451,7 @@ namespace osu.Game.Tests.Visual.Gameplay private EpilepsyWarning getWarning() => loader.ChildrenOfType().SingleOrDefault(); - private class TestPlayerLoader : PlayerLoader + private partial class TestPlayerLoader : PlayerLoader { public new VisualSettings VisualSettings => base.VisualSettings; @@ -482,7 +482,7 @@ namespace osu.Game.Tests.Visual.Gameplay public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; } - protected class SlowLoadPlayer : TestPlayer + protected partial class SlowLoadPlayer : TestPlayer { public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim(false); diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs index 38a091dd85..80c4e4bce9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs @@ -27,7 +27,7 @@ using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Gameplay { - public class TestScenePlayerLocalScoreImport : PlayerTestScene + public partial class TestScenePlayerLocalScoreImport : PlayerTestScene { private BeatmapManager beatmaps = null!; private RulesetStore rulesets = null!; diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs index ec0eea62d9..b1209e3a4f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs @@ -12,7 +12,7 @@ using osu.Game.Storyboards; namespace osu.Game.Tests.Visual.Gameplay { - public class TestScenePlayerReferenceLeaking : TestSceneAllRulesetPlayers + public partial class TestScenePlayerReferenceLeaking : TestSceneAllRulesetPlayers { private readonly WeakList workingWeakReferences = new WeakList(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs index d1bdfb1dfa..2fbdfbc198 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerScoreSubmission.cs @@ -26,7 +26,7 @@ using osu.Game.Tests.Beatmaps; namespace osu.Game.Tests.Visual.Gameplay { - public class TestScenePlayerScoreSubmission : PlayerTestScene + public partial class TestScenePlayerScoreSubmission : PlayerTestScene { protected override bool AllowFail => allowFail; @@ -345,7 +345,7 @@ namespace osu.Game.Tests.Visual.Gameplay }); } - protected class FakeImportingPlayer : TestPlayer + protected partial class FakeImportingPlayer : TestPlayer { public bool ScoreImportStarted { get; set; } public SemaphoreSlim AllowImportCompletion { get; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs index 618ffbcb0e..55ee6c9fc9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePoolingRuleset.cs @@ -31,7 +31,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Gameplay { - public class TestScenePoolingRuleset : OsuTestScene + public partial class TestScenePoolingRuleset : OsuTestScene { private const double time_between_objects = 1000; @@ -194,7 +194,7 @@ namespace osu.Game.Tests.Visual.Gameplay public override string ShortName { get; } = string.Empty; } - private class TestDrawablePoolingRuleset : DrawableRuleset + private partial class TestDrawablePoolingRuleset : DrawableRuleset { public int PoolSize; @@ -210,7 +210,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override Playfield CreatePlayfield() => new TestPlayfield(PoolSize); } - private class TestPlayfield : Playfield + private partial class TestPlayfield : Playfield { private readonly int poolSize; @@ -283,7 +283,7 @@ namespace osu.Game.Tests.Visual.Gameplay public double Duration { get; set; } } - private class DrawableTestHitObject : DrawableHitObject + private partial class DrawableTestHitObject : DrawableHitObject { public DrawableTestHitObject() : base(null) @@ -335,7 +335,7 @@ namespace osu.Game.Tests.Visual.Gameplay { } - private class DrawableTestKilledHitObject : DrawableHitObject + private partial class DrawableTestKilledHitObject : DrawableHitObject { public DrawableTestKilledHitObject() : base(null) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs index faa6a429c5..c476aae202 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual.Gameplay { [Description("Player instantiated with a replay.")] - public class TestSceneReplay : TestSceneAllRulesetPlayers + public partial class TestSceneReplay : TestSceneAllRulesetPlayers { protected override Player CreatePlayer(Ruleset ruleset) { @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("cannot fail", () => !((ScoreAccessibleReplayPlayer)Player).AllowFail); } - private class ScoreAccessibleReplayPlayer : ReplayPlayer + private partial class ScoreAccessibleReplayPlayer : ReplayPlayer { public new ScoreProcessor ScoreProcessor => base.ScoreProcessor; public new HUDOverlay HUDOverlay => base.HUDOverlay; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs index cd227630c1..c473278fdc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs @@ -24,7 +24,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneReplayDownloadButton : OsuManualInputManagerTestScene + public partial class TestSceneReplayDownloadButton : OsuManualInputManagerTestScene { private const long online_score_id = 2553163309; @@ -219,7 +219,7 @@ namespace osu.Game.Tests.Visual.Gameplay } }; - private class TestReplayDownloadButton : ReplayDownloadButton + private partial class TestReplayDownloadButton : ReplayDownloadButton { public void SetDownloadState(DownloadState state) => State.Value = state; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs index 6319b91a38..e0a6a60ff2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs @@ -10,7 +10,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneReplayPlayer : RateAdjustedBeatmapTestScene + public partial class TestSceneReplayPlayer : RateAdjustedBeatmapTestScene { protected TestReplayPlayer Player; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs index b3401c916b..65b409a6f7 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs @@ -31,7 +31,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneReplayRecorder : OsuManualInputManagerTestScene + public partial class TestSceneReplayRecorder : OsuManualInputManagerTestScene { private TestRulesetInputManager playbackManager; private TestRulesetInputManager recordingManager; @@ -218,7 +218,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - public class TestInputConsumer : CompositeDrawable, IKeyBindingHandler + public partial class TestInputConsumer : CompositeDrawable, IKeyBindingHandler { public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent.ReceivePositionalInputAt(screenSpacePos); @@ -261,7 +261,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - public class TestRulesetInputManager : RulesetInputManager + public partial class TestRulesetInputManager : RulesetInputManager { public TestRulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique) @@ -271,7 +271,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override KeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) => new TestKeyBindingContainer(); - internal class TestKeyBindingContainer : KeyBindingContainer + internal partial class TestKeyBindingContainer : KeyBindingContainer { public override IEnumerable DefaultKeyBindings => new[] { @@ -299,7 +299,7 @@ namespace osu.Game.Tests.Visual.Gameplay Down, } - internal class TestReplayRecorder : ReplayRecorder + internal partial class TestReplayRecorder : ReplayRecorder { public TestReplayRecorder(Score target) : base(target) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs index f8b5085a70..8fff07e6d8 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoring.cs @@ -28,7 +28,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneScoring : OsuTestScene + public partial class TestSceneScoring : OsuTestScene { private GraphContainer graphs = null!; private SettingsSlider sliderMaxCombo = null!; @@ -279,7 +279,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - public class GraphContainer : Container, IHasCustomTooltip> + public partial class GraphContainer : Container, IHasCustomTooltip> { public readonly BindableList MissLocations = new BindableList(); public readonly BindableList NonPerfectLocations = new BindableList(); @@ -439,7 +439,7 @@ namespace osu.Game.Tests.Visual.Gameplay public IEnumerable TooltipContent => Content.OfType(); - public class GraphTooltip : CompositeDrawable, ITooltip> + public partial class GraphTooltip : CompositeDrawable, ITooltip> { private readonly GraphContainer graphContainer; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs index 6d036f8e9b..317d01553a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs @@ -29,7 +29,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneScrollingHitObjects : OsuTestScene + public partial class TestSceneScrollingHitObjects : OsuTestScene { [Cached(typeof(IReadOnlyList))] private IReadOnlyList mods { get; set; } = Array.Empty(); @@ -252,7 +252,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void setScrollAlgorithm(ScrollVisualisationMethod algorithm) => scrollContainers.ForEach(c => c.ScrollAlgorithm = algorithm); - private class TestPlayfield : ScrollingPlayfield + private partial class TestPlayfield : ScrollingPlayfield { public new ScrollingDirection Direction => base.Direction.Value; @@ -279,7 +279,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override ScrollingHitObjectContainer CreateScrollingHitObjectContainer() => new TestScrollingHitObjectContainer(); } - private class TestDrawableControlPoint : DrawableHitObject + private partial class TestDrawableControlPoint : DrawableHitObject { public TestDrawableControlPoint(ScrollingDirection direction, double time) : base(new HitObject { StartTime = time, HitWindows = HitWindows.Empty }) @@ -320,7 +320,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class TestDrawableHitObject : DrawableHitObject + private partial class TestDrawableHitObject : DrawableHitObject { public TestDrawableHitObject(TestHitObject hitObject) : base(hitObject) @@ -336,7 +336,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class TestScrollingHitObjectContainer : ScrollingHitObjectContainer + private partial class TestScrollingHitObjectContainer : ScrollingHitObjectContainer { protected override RectangleF GetConservativeBoundingBox(HitObjectLifetimeEntry entry) { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs index 578718b7c9..48dbda9da6 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditor.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinEditor : PlayerTestScene + public partial class TestSceneSkinEditor : PlayerTestScene { private SkinEditor? skinEditor; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs index f88b4be3d8..05a550a24d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorComponentsList.cs @@ -13,7 +13,7 @@ using osu.Game.Skinning.Editor; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinEditorComponentsList : SkinnableTestScene + public partial class TestSceneSkinEditorComponentsList : SkinnableTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs index 6c02ddab14..ad3911f50b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinEditorMultipleSkins : SkinnableTestScene + public partial class TestSceneSkinEditorMultipleSkins : SkinnableTestScene { [Cached] private readonly ScoreProcessor scoreProcessor = new ScoreProcessor(new OsuRuleset()); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs index 1288f2a9f1..6f079778c5 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableAccuracyCounter.cs @@ -14,7 +14,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinnableAccuracyCounter : SkinnableHUDComponentTestScene + public partial class TestSceneSkinnableAccuracyCounter : SkinnableHUDComponentTestScene { [Cached] private ScoreProcessor scoreProcessor = new ScoreProcessor(new OsuRuleset()); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs index ef56f456ea..93fa953ef4 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableComboCounter.cs @@ -14,7 +14,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinnableComboCounter : SkinnableHUDComponentTestScene + public partial class TestSceneSkinnableComboCounter : SkinnableHUDComponentTestScene { [Cached] private ScoreProcessor scoreProcessor = new ScoreProcessor(new OsuRuleset()); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs index 97974d2368..c02cec8c75 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableDrawable.cs @@ -24,7 +24,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinnableDrawable : OsuTestScene + public partial class TestSceneSkinnableDrawable : OsuTestScene { [Test] public void TestConfineScaleDown() @@ -160,7 +160,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("consumer using base source", () => consumer.Drawable is BaseSourceBox); } - private class SwitchableSkinProvidingContainer : SkinProvidingContainer + private partial class SwitchableSkinProvidingContainer : SkinProvidingContainer { private bool allow = true; @@ -178,7 +178,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class ExposedSkinnableDrawable : SkinnableDrawable + private partial class ExposedSkinnableDrawable : SkinnableDrawable { public new Drawable Drawable => base.Drawable; @@ -188,7 +188,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class DefaultBox : DrawWidthBox + private partial class DefaultBox : DrawWidthBox { public DefaultBox() { @@ -196,7 +196,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class DrawWidthBox : Container + private partial class DrawWidthBox : Container { private readonly OsuSpriteText text; @@ -224,7 +224,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class NamedBox : Container + private partial class NamedBox : Container { public NamedBox(string name) { @@ -246,7 +246,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class SkinConsumer : SkinnableDrawable + private partial class SkinConsumer : SkinnableDrawable { public new Drawable Drawable => base.Drawable; public int SkinChangedCount { get; private set; } @@ -263,7 +263,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class BaseSourceBox : NamedBox + private partial class BaseSourceBox : NamedBox { public BaseSourceBox() : base("Base Source") @@ -271,7 +271,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - private class SecondarySourceBox : NamedBox + private partial class SecondarySourceBox : NamedBox { public SecondarySourceBox() : base("Secondary Source") @@ -316,7 +316,7 @@ namespace osu.Game.Tests.Visual.Gameplay } [Cached(typeof(ISkinSource))] - private class SkinSourceContainer : Container, ISkinSource + private partial class SkinSourceContainer : Container, ISkinSource { public Drawable GetDrawableComponent(ISkinComponentLookup componentLookupName) => new BaseSourceBox(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs index 485c76ac5c..1f2329af4a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinnableHUDOverlay : SkinnableTestScene + public partial class TestSceneSkinnableHUDOverlay : SkinnableTestScene { private HUDOverlay hudOverlay; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs index 2d6ad28b90..7f6c9d7804 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHealthDisplay.cs @@ -16,7 +16,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinnableHealthDisplay : SkinnableHUDComponentTestScene + public partial class TestSceneSkinnableHealthDisplay : SkinnableHUDComponentTestScene { [Cached(typeof(HealthProcessor))] private HealthProcessor healthProcessor = new DrainingHealthProcessor(0); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs index 1b3538cc21..c95e8ee5b2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableScoreCounter.cs @@ -13,7 +13,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinnableScoreCounter : SkinnableHUDComponentTestScene + public partial class TestSceneSkinnableScoreCounter : SkinnableHUDComponentTestScene { [Cached] private ScoreProcessor scoreProcessor = new ScoreProcessor(new OsuRuleset()); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs index 8122d8defb..5c69062e67 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableSound.cs @@ -20,7 +20,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSkinnableSound : OsuTestScene + public partial class TestSceneSkinnableSound : OsuTestScene { private TestSkinSourceContainer skinSource; private PausableSkinnableSound skinnableSound; @@ -131,7 +131,7 @@ namespace osu.Game.Tests.Visual.Gameplay } [Cached(typeof(ISkinSource))] - private class TestSkinSourceContainer : Container, ISkinSource, ISamplePlaybackDisabler + private partial class TestSkinSourceContainer : Container, ISkinSource, ISamplePlaybackDisabler { [Resolved] private ISkinSource source { get; set; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs index 1bba62a5cf..8b1a8307ca 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkipOverlay.cs @@ -15,7 +15,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneSkipOverlay : OsuManualInputManagerTestScene + public partial class TestSceneSkipOverlay : OsuManualInputManagerTestScene { private TestSkipOverlay skip; private int requestCount; @@ -162,7 +162,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert($"request count is {expected}", () => requestCount, () => Is.EqualTo(expected)); } - private class TestSkipOverlay : SkipOverlay + private partial class TestSkipOverlay : SkipOverlay { public TestSkipOverlay(double startTime) : base(startTime) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSliderPath.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSliderPath.cs index 7044ddad37..dfa9fdf03b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSliderPath.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSliderPath.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSliderPath : OsuTestScene + public partial class TestSceneSliderPath : OsuTestScene { private readonly SmoothPath drawablePath; private SliderPath path; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs index 881870921c..8ae6a2a5fc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSoloGameplayLeaderboard.cs @@ -19,7 +19,7 @@ using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSoloGameplayLeaderboard : OsuTestScene + public partial class TestSceneSoloGameplayLeaderboard : OsuTestScene { [Cached] private readonly ScoreProcessor scoreProcessor = new ScoreProcessor(new OsuRuleset()); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs index 6127aa304c..2e579cc522 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs @@ -17,7 +17,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneSongProgress : SkinnableHUDComponentTestScene + public partial class TestSceneSongProgress : SkinnableHUDComponentTestScene { private GameplayClockContainer gameplayClockContainer = null!; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgressGraph.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgressGraph.cs index 2fa3c0c7ec..5a61502978 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgressGraph.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgressGraph.cs @@ -14,7 +14,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneSongProgressGraph : OsuTestScene + public partial class TestSceneSongProgressGraph : OsuTestScene { private TestSongProgressGraph graph; @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Gameplay graph.Objects = objects; } - private class TestSongProgressGraph : SongProgressGraph + private partial class TestSongProgressGraph : SongProgressGraph { public int CreationCount { get; private set; } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index 929af7f84d..8f1eb98c79 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -28,7 +28,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSpectator : ScreenTestScene + public partial class TestSceneSpectator : ScreenTestScene { private readonly APIUser streamingUser = new APIUser { Id = MultiplayerTestScene.PLAYER_1_ID, Username = "Test user" }; @@ -388,7 +388,7 @@ namespace osu.Game.Tests.Visual.Gameplay /// /// Used for the sole purpose of adding as a resolvable dependency. /// - private class DependenciesScreen : OsuScreen + private partial class DependenciesScreen : OsuScreen { [Cached(typeof(SpectatorClient))] public readonly TestSpectatorClient SpectatorClient = new TestSpectatorClient(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs index 083be3539d..1c09c29748 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorHost.cs @@ -15,7 +15,7 @@ using osu.Game.Tests.Visual.Spectator; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSpectatorHost : PlayerTestScene + public partial class TestSceneSpectatorHost : PlayerTestScene { protected override Ruleset CreatePlayerRuleset() => new ManiaRuleset(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs index 9c41c70a0e..1ad1da0994 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs @@ -35,7 +35,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneSpectatorPlayback : OsuManualInputManagerTestScene + public partial class TestSceneSpectatorPlayback : OsuManualInputManagerTestScene { private TestRulesetInputManager playbackManager; private TestRulesetInputManager recordingManager; @@ -257,7 +257,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - public class TestInputConsumer : CompositeDrawable, IKeyBindingHandler + public partial class TestInputConsumer : CompositeDrawable, IKeyBindingHandler { public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parent.ReceivePositionalInputAt(screenSpacePos); @@ -300,7 +300,7 @@ namespace osu.Game.Tests.Visual.Gameplay } } - public class TestRulesetInputManager : RulesetInputManager + public partial class TestRulesetInputManager : RulesetInputManager { public TestRulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique) @@ -310,7 +310,7 @@ namespace osu.Game.Tests.Visual.Gameplay protected override KeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) => new TestKeyBindingContainer(); - internal class TestKeyBindingContainer : KeyBindingContainer + internal partial class TestKeyBindingContainer : KeyBindingContainer { public override IEnumerable DefaultKeyBindings => new[] { @@ -360,7 +360,7 @@ namespace osu.Game.Tests.Visual.Gameplay Down, } - internal class TestReplayRecorder : ReplayRecorder + internal partial class TestReplayRecorder : ReplayRecorder { public List SentFrames = new List(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs index 708a5e94de..699c8ea20a 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStarCounter.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneStarCounter : OsuTestScene + public partial class TestSceneStarCounter : OsuTestScene { private readonly StarCounter starCounter; private readonly OsuSpriteText starsLabel; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs index eaf22ba9cc..dbce62cbef 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboard.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneStoryboard : OsuTestScene + public partial class TestSceneStoryboard : OsuTestScene { private Container storyboardContainer = null!; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs index f0e184d727..a9d4508f70 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardSamplePlayback.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneStoryboardSamplePlayback : PlayerTestScene + public partial class TestSceneStoryboardSamplePlayback : PlayerTestScene { private Storyboard storyboard; diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs index a26a7e97be..0d88fb01a8 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneStoryboardWithOutro.cs @@ -26,7 +26,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneStoryboardWithOutro : PlayerTestScene + public partial class TestSceneStoryboardWithOutro : PlayerTestScene { protected override bool HasCustomSteps => true; @@ -198,7 +198,7 @@ namespace osu.Game.Tests.Visual.Gameplay return storyboard; } - protected class OutroPlayer : TestPlayer + protected partial class OutroPlayer : TestPlayer { public void ExitViaPause() => PerformExit(true); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneUnknownMod.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneUnknownMod.cs index a31347589b..cb5631e599 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneUnknownMod.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneUnknownMod.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Osu; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneUnknownMod : ModTestScene + public partial class TestSceneUnknownMod : ModTestScene { protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs index 60b8691bfb..2f572b46c9 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneUnstableRateCounter.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Gameplay { - public class TestSceneUnstableRateCounter : OsuTestScene + public partial class TestSceneUnstableRateCounter : OsuTestScene { [Cached(typeof(ScoreProcessor))] private TestScoreProcessor scoreProcessor = new TestScoreProcessor(); @@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.Gameplay }); } - private class TestScoreProcessor : ScoreProcessor + private partial class TestScoreProcessor : ScoreProcessor { public TestScoreProcessor() : base(new OsuRuleset()) diff --git a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs index e0f0df0554..b09dbc1a91 100644 --- a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs +++ b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Menus { [TestFixture] - public abstract class IntroTestScene : OsuTestScene + public abstract partial class IntroTestScene : OsuTestScene { [Cached] private OsuLogo logo; diff --git a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs index 57f16bbcce..45e5a7c270 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Menu; namespace osu.Game.Tests.Visual.Menus { - public class TestSceneDisclaimer : ScreenTestScene + public partial class TestSceneDisclaimer : ScreenTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs b/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs index 85a3a51ddb..0c024248ea 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneIntroCircles.cs @@ -9,7 +9,7 @@ using osu.Game.Screens.Menu; namespace osu.Game.Tests.Visual.Menus { [TestFixture] - public class TestSceneIntroCircles : IntroTestScene + public partial class TestSceneIntroCircles : IntroTestScene { protected override bool IntroReliesOnTrack => false; protected override IntroScreen CreateScreen() => new IntroCircles(); diff --git a/osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs b/osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs index 7ab04a22e5..23373892d1 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneIntroTriangles.cs @@ -9,7 +9,7 @@ using osu.Game.Screens.Menu; namespace osu.Game.Tests.Visual.Menus { [TestFixture] - public class TestSceneIntroTriangles : IntroTestScene + public partial class TestSceneIntroTriangles : IntroTestScene { protected override bool IntroReliesOnTrack => true; protected override IntroScreen CreateScreen() => new IntroTriangles(); diff --git a/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs b/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs index ae63022823..2ccf184525 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneIntroWelcome.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Menu; namespace osu.Game.Tests.Visual.Menus { [TestFixture] - public class TestSceneIntroWelcome : IntroTestScene + public partial class TestSceneIntroWelcome : IntroTestScene { protected override bool IntroReliesOnTrack => false; protected override IntroScreen CreateScreen() => new IntroWelcome(); diff --git a/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs b/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs index 1f2eb57b79..aac9614ddb 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneLoader.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Menus { [TestFixture] - public class TestSceneLoader : ScreenTestScene + public partial class TestSceneLoader : ScreenTestScene { private TestLoader loader; @@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.Menus AddUntilStep("not current", () => !loader.IsCurrentScreen()); } - private class TestLoader : Loader + private partial class TestLoader : Loader { public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim(); @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Menus protected override OsuScreen CreateLoadableScreen() => screen = new TestScreen(); protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler(AllowLoad); - private class TestShaderPrecompiler : ShaderPrecompiler + private partial class TestShaderPrecompiler : ShaderPrecompiler { private readonly ManualResetEventSlim allowLoad; @@ -92,7 +92,7 @@ namespace osu.Game.Tests.Visual.Menus protected override bool AllLoaded => allowLoad.IsSet; } - private class TestScreen : OsuScreen + private partial class TestScreen : OsuScreen { public TestScreen() { diff --git a/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs b/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs index dbe7b9cc74..738220f5ce 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneLoginPanel.cs @@ -16,7 +16,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Menus { [TestFixture] - public class TestSceneLoginPanel : OsuManualInputManagerTestScene + public partial class TestSceneLoginPanel : OsuManualInputManagerTestScene { private LoginPanel loginPanel; private int hideCount; diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs index 720e32a242..f17433244b 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs @@ -16,7 +16,7 @@ using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Menus { - public class TestSceneMusicActionHandling : OsuGameTestScene + public partial class TestSceneMusicActionHandling : OsuGameTestScene { private GlobalActionContainer globalActionContainer => Game.ChildrenOfType().First(); diff --git a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs index 7a2b4d5ca5..e5e092b382 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Menus { - public class TestSceneSideOverlays : OsuGameTestScene + public partial class TestSceneSideOverlays : OsuGameTestScene { [SetUpSteps] public override void SetUpSteps() diff --git a/osu.Game.Tests/Visual/Menus/TestSceneSongTicker.cs b/osu.Game.Tests/Visual/Menus/TestSceneSongTicker.cs index ba73361566..c54c66df7e 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneSongTicker.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneSongTicker.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Menu; namespace osu.Game.Tests.Visual.Menus { - public class TestSceneSongTicker : OsuTestScene + public partial class TestSceneSongTicker : OsuTestScene { public TestSceneSongTicker() { diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs index 4473f315b9..0bc42b06dd 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbar.cs @@ -26,7 +26,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Menus { [TestFixture] - public class TestSceneToolbar : OsuManualInputManagerTestScene + public partial class TestSceneToolbar : OsuManualInputManagerTestScene { private TestToolbar toolbar; @@ -201,7 +201,7 @@ namespace osu.Game.Tests.Visual.Menus AddAssert("volume not changed", () => Audio.Volume.Value == 0.5); } - public class TestToolbar : Toolbar + public partial class TestToolbar : Toolbar { public new Bindable OverlayActivationMode => base.OverlayActivationMode as Bindable; } diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbarClock.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbarClock.cs index d96f80df40..f38ad5af15 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneToolbarClock.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbarClock.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Menus { [TestFixture] - public class TestSceneToolbarClock : OsuManualInputManagerTestScene + public partial class TestSceneToolbarClock : OsuManualInputManagerTestScene { private Bindable clockDisplayMode; diff --git a/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs b/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs index 2901501b30..2bdfc8959d 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneToolbarUserButton.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Menus { [TestFixture] - public class TestSceneToolbarUserButton : OsuManualInputManagerTestScene + public partial class TestSceneToolbarUserButton : OsuManualInputManagerTestScene { public TestSceneToolbarUserButton() { diff --git a/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs b/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs index 23c1eda7f7..49256c7a01 100644 --- a/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs +++ b/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs @@ -14,7 +14,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Tests.Visual.Mods { - public class TestSceneModFailCondition : ModTestScene + public partial class TestSceneModFailCondition : ModTestScene { private bool restartRequested; diff --git a/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs index 631f2e707a..fa7d2c04f4 100644 --- a/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs @@ -26,7 +26,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Multiplayer { - public abstract class MultiplayerGameplayLeaderboardTestScene : OsuTestScene + public abstract partial class MultiplayerGameplayLeaderboardTestScene : OsuTestScene { protected const int TOTAL_USERS = 16; diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs index ca4d926866..0e9863a9f5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs @@ -24,7 +24,7 @@ using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Multiplayer { - public abstract class QueueModeTestScene : ScreenTestScene + public abstract partial class QueueModeTestScene : ScreenTestScene { protected abstract QueueMode Mode { get; } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs index 5947cabf7f..7b1abd104f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneAllPlayersQueueMode : QueueModeTestScene + public partial class TestSceneAllPlayersQueueMode : QueueModeTestScene { protected override QueueMode Mode => QueueMode.AllPlayers; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneCreateMultiplayerMatchButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneCreateMultiplayerMatchButton.cs index 317e410f37..11b0f8b91c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneCreateMultiplayerMatchButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneCreateMultiplayerMatchButton.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.OnlinePlay.Multiplayer; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneCreateMultiplayerMatchButton : MultiplayerTestScene + public partial class TestSceneCreateMultiplayerMatchButton : MultiplayerTestScene { private CreateMultiplayerMatchButton button; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs index be1f21a7b2..4de911b6b6 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneDrawableLoungeRoom : OsuManualInputManagerTestScene + public partial class TestSceneDrawableLoungeRoom : OsuManualInputManagerTestScene { private readonly Room room = new Room { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 23ef440a4d..4ffccdbf0e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneDrawableRoom : OsuTestScene + public partial class TestSceneDrawableRoom : OsuTestScene { [Cached] protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs index b26481387d..98abc93994 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomParticipantsList.cs @@ -15,7 +15,7 @@ using osu.Game.Users.Drawables; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneDrawableRoomParticipantsList : OnlinePlayTestScene + public partial class TestSceneDrawableRoomParticipantsList : OnlinePlayTestScene { private DrawableRoomParticipantsList list; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 73d1222156..312135402f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -33,7 +33,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneDrawableRoomPlaylist : MultiplayerTestScene + public partial class TestSceneDrawableRoomPlaylist : MultiplayerTestScene { private TestPlaylist playlist; @@ -390,7 +390,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded)); } - private class TestPlaylist : DrawableRoomPlaylist + private partial class TestPlaylist : DrawableRoomPlaylist { public new IReadOnlyDictionary> ItemMap => base.ItemMap; } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs index 457af3e4af..45f671618e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneFreeModSelectOverlay.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneFreeModSelectOverlay : MultiplayerTestScene + public partial class TestSceneFreeModSelectOverlay : MultiplayerTestScene { private FreeModSelectOverlay freeModSelectOverlay; private readonly Bindable>> availableMods = new Bindable>>(); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs index a08791ecff..979cb4424e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneGameplayChatDisplay : OsuManualInputManagerTestScene + public partial class TestSceneGameplayChatDisplay : OsuManualInputManagerTestScene { private GameplayChatDisplay chatDisplay; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs index 800b523a9d..145c655c0a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs @@ -17,7 +17,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneHostOnlyQueueMode : QueueModeTestScene + public partial class TestSceneHostOnlyQueueMode : QueueModeTestScene { protected override QueueMode Mode => QueueMode.HostOnly; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index 3d6d4f0a90..d99d764449 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneLoungeRoomsContainer : OnlinePlayTestScene + public partial class TestSceneLoungeRoomsContainer : OnlinePlayTestScene { protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs index b113352117..63a0ada3dc 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMatchBeatmapDetailArea : OnlinePlayTestScene + public partial class TestSceneMatchBeatmapDetailArea : OnlinePlayTestScene { public override void SetUpSteps() { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs index d2468ae005..defb3006cc 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs @@ -15,7 +15,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMatchLeaderboard : OnlinePlayTestScene + public partial class TestSceneMatchLeaderboard : OnlinePlayTestScene { public override void SetUpSteps() { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs index 12e7394c93..3efc7fbd30 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs @@ -28,7 +28,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMatchStartControl : OsuManualInputManagerTestScene + public partial class TestSceneMatchStartControl : OsuManualInputManagerTestScene { private readonly Mock multiplayerClient = new Mock(); private readonly Mock availabilityTracker = new Mock(); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs index 70c6271d24..3d85a47ca9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs @@ -12,7 +12,7 @@ using osu.Game.Screens.OnlinePlay; namespace osu.Game.Tests.Visual.Multiplayer { [TestFixture] - public class TestSceneMultiHeader : OsuTestScene + public partial class TestSceneMultiHeader : OsuTestScene { public TestSceneMultiHeader() { @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("push multi screen", () => screenStack.CurrentScreen.Push(new TestOnlinePlaySubScreen(++index))); } - private class TestOnlinePlaySubScreen : OsuScreen, IOnlinePlaySubScreen + private partial class TestOnlinePlaySubScreen : OsuScreen, IOnlinePlaySubScreen { private readonly int index; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs index 4fda4c1c50..049c02ffde 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiSpectatorLeaderboard : MultiplayerTestScene + public partial class TestSceneMultiSpectatorLeaderboard : MultiplayerTestScene { private Dictionary clocks; private MultiSpectatorLeaderboard leaderboard; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 13fde4fd72..c2036984c1 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -30,7 +30,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiSpectatorScreen : MultiplayerTestScene + public partial class TestSceneMultiSpectatorScreen : MultiplayerTestScene { [Resolved] private OsuGameBase game { get; set; } = null!; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 6098a3e794..5033347b15 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -46,7 +46,7 @@ using ReadyButton = osu.Game.Screens.OnlinePlay.Components.ReadyButton; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayer : ScreenTestScene + public partial class TestSceneMultiplayer : ScreenTestScene { private BeatmapManager beatmaps = null!; private BeatmapSetInfo importedSet = null!; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs index 95fd449dd3..a612167d57 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerGameplayLeaderboard : MultiplayerGameplayLeaderboardTestScene + public partial class TestSceneMultiplayerGameplayLeaderboard : MultiplayerGameplayLeaderboardTestScene { protected override MultiplayerRoomUser CreateUser(int userId) { @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Multiplayer }); } - private class TestLeaderboard : MultiplayerGameplayLeaderboard + private partial class TestLeaderboard : MultiplayerGameplayLeaderboard { public Dictionary> UserMods => UserScores.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ScoreProcessor.Mods); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs index 93ccf3977b..48f74cf308 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -12,7 +12,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerGameplayLeaderboardTeams : MultiplayerGameplayLeaderboardTestScene + public partial class TestSceneMultiplayerGameplayLeaderboardTeams : MultiplayerGameplayLeaderboardTestScene { private int team; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs index 1a3fefa603..cf25e06799 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerLoungeSubScreen : OnlinePlayTestScene + public partial class TestSceneMultiplayerLoungeSubScreen : OnlinePlayTestScene { protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs index 83e7ef6a81..d636373fbd 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchFooter.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.OnlinePlay.Multiplayer.Match; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerMatchFooter : MultiplayerTestScene + public partial class TestSceneMultiplayerMatchFooter : MultiplayerTestScene { public override void SetUpSteps() { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs index b87321c047..c0b6a0beab 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs @@ -31,7 +31,7 @@ using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerMatchSongSelect : MultiplayerTestScene + public partial class TestSceneMultiplayerMatchSongSelect : MultiplayerTestScene { private BeatmapManager manager; private RulesetStore rulesets; @@ -112,7 +112,7 @@ namespace osu.Game.Tests.Visual.Multiplayer .All(b => b.Mod.GetType() != type)); } - private class TestMultiplayerMatchSongSelect : MultiplayerMatchSongSelect + private partial class TestMultiplayerMatchSongSelect : MultiplayerMatchSongSelect { public new Bindable> Mods => base.Mods; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs index 9fc42dc68b..8816787ceb 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs @@ -39,7 +39,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerMatchSubScreen : MultiplayerTestScene + public partial class TestSceneMultiplayerMatchSubScreen : MultiplayerTestScene { private MultiplayerMatchSubScreen screen; @@ -286,7 +286,7 @@ namespace osu.Game.Tests.Visual.Multiplayer }); } - private class TestMultiplayerMatchSubScreen : MultiplayerMatchSubScreen + private partial class TestMultiplayerMatchSubScreen : MultiplayerMatchSubScreen { [Resolved(canBeNull: true)] [CanBeNull] diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index edd1491865..2da29ccc95 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -23,7 +23,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerParticipantsList : MultiplayerTestScene + public partial class TestSceneMultiplayerParticipantsList : MultiplayerTestScene { [SetUpSteps] public void SetupSteps() diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs index f6a6b3c667..45c5c67fff 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs @@ -14,7 +14,7 @@ using osu.Game.Screens.OnlinePlay.Multiplayer; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerPlayer : MultiplayerTestScene + public partial class TestSceneMultiplayerPlayer : MultiplayerTestScene { private MultiplayerPlayer player; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs index 8dbad4e330..d7578b4114 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerPlaylist : MultiplayerTestScene + public partial class TestSceneMultiplayerPlaylist : MultiplayerTestScene { private MultiplayerPlaylist list; private BeatmapManager beatmaps; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs index 63677ce378..bb37f1a5a7 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs @@ -25,7 +25,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerQueueList : MultiplayerTestScene + public partial class TestSceneMultiplayerQueueList : MultiplayerTestScene { private MultiplayerQueueList playlist; private BeatmapManager beatmaps; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs index a638702ceb..f030466fff 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs @@ -11,7 +11,7 @@ using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerResults : ScreenTestScene + public partial class TestSceneMultiplayerResults : ScreenTestScene { [Test] public void TestDisplayResults() diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs index 9b4cb722f3..816ba4ca32 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs @@ -26,7 +26,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerSpectateButton : MultiplayerTestScene + public partial class TestSceneMultiplayerSpectateButton : MultiplayerTestScene { private MultiplayerSpectateButton spectateButton; private MatchStartControl startControl; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectatorPlayerGrid.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectatorPlayerGrid.cs index 089b4a020d..8fd05dcaa9 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectatorPlayerGrid.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectatorPlayerGrid.cs @@ -14,7 +14,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerSpectatorPlayerGrid : OsuManualInputManagerTestScene + public partial class TestSceneMultiplayerSpectatorPlayerGrid : OsuManualInputManagerTestScene { private PlayerGrid grid; @@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual.Multiplayer bool checkAction() => Precision.AlmostEquals(grid.MaximisedFacade.DrawSize, grid.Content.ElementAt(index).DrawSize, 10) == shouldBeMaximised; } - private class GridContent : Box + private partial class GridContent : Box { public GridContent() { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs index 56260941a8..68fd39a066 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneMultiplayerTeamResults : ScreenTestScene + public partial class TestSceneMultiplayerTeamResults : ScreenTestScene { [Test] public void TestScaling() diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs index bbccdb0d17..91e9ce5ea2 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsRoomSettingsPlaylist.cs @@ -25,7 +25,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestScenePlaylistsRoomSettingsPlaylist : OnlinePlayTestScene + public partial class TestScenePlaylistsRoomSettingsPlaylist : OnlinePlayTestScene { private TestPlaylist playlist; @@ -159,7 +159,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded)); } - private class TestPlaylist : PlaylistsRoomSettingsPlaylist + private partial class TestPlaylist : PlaylistsRoomSettingsPlaylist { public new IReadOnlyDictionary> ItemMap => base.ItemMap; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs index 2eddf1a17e..b0b753fc22 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs @@ -24,7 +24,7 @@ using osu.Game.Tests.Visual.OnlinePlay; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestScenePlaylistsSongSelect : OnlinePlayTestScene + public partial class TestScenePlaylistsSongSelect : OnlinePlayTestScene { private BeatmapManager manager; @@ -154,7 +154,7 @@ namespace osu.Game.Tests.Visual.Multiplayer }); } - private class TestPlaylistsSongSelect : PlaylistsSongSelect + private partial class TestPlaylistsSongSelect : PlaylistsSongSelect { public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs index cb80fb56df..aaf1a850af 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.OnlinePlay.Lounge.Components; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneRankRangePill : OsuTestScene + public partial class TestSceneRankRangePill : OsuTestScene { private readonly Mock multiplayerClient = new Mock(); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs index 5bccabcf2f..e46ae978d7 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneStarRatingRangeDisplay.cs @@ -12,7 +12,7 @@ using osu.Game.Tests.Visual.OnlinePlay; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneStarRatingRangeDisplay : OnlinePlayTestScene + public partial class TestSceneStarRatingRangeDisplay : OnlinePlayTestScene { public override void SetUpSteps() { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs index ef2a431b8f..32e90153d8 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs @@ -27,7 +27,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneTeamVersus : ScreenTestScene + public partial class TestSceneTeamVersus : ScreenTestScene { private BeatmapManager beatmaps; private BeatmapSetInfo importedSet; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs index bff30b83f9..64ea6003bc 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneButtonSystemNavigation.cs @@ -12,7 +12,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation { - public class TestSceneButtonSystemNavigation : OsuGameTestScene + public partial class TestSceneButtonSystemNavigation : OsuGameTestScene { private ButtonSystem buttons => ((MainMenu)Game.ScreenStack.CurrentScreen).ChildrenOfType().Single(); diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs index c3d7bde68f..d937b9e6d7 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation { - public class TestSceneChangeAndUseGameplayBindings : OsuGameTestScene + public partial class TestSceneChangeAndUseGameplayBindings : OsuGameTestScene { [Test] public void TestGameplayKeyBindings() diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs index 010ed23c9b..7d39d48378 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneEditDefaultSkin.cs @@ -13,7 +13,7 @@ using osu.Game.Skinning.Editor; namespace osu.Game.Tests.Visual.Navigation { - public class TestSceneEditDefaultSkin : OsuGameTestScene + public partial class TestSceneEditDefaultSkin : OsuGameTestScene { private SkinManager skinManager => Game.Dependencies.Get(); private SkinEditorOverlay skinEditor => Game.Dependencies.Get(); diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunGame.cs index fe26d59812..7f7a81d787 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunGame.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays.Notifications; namespace osu.Game.Tests.Visual.Navigation { [System.ComponentModel.Description("game with first-run setup overlay")] - public class TestSceneFirstRunGame : OsuGameTestScene + public partial class TestSceneFirstRunGame : OsuGameTestScene { public override void SetUpSteps() { @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Navigation protected override TestOsuGame CreateTestGame() => new FirstRunGame(LocalStorage, API); - private class FirstRunGame : TestOsuGame + private partial class FirstRunGame : TestOsuGame { public FirstRunGame(Storage storage, IAPIProvider api, string[] args = null) : base(storage, api, args) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs b/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs index 1c2b1fe37d..346f1d9f90 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneInterProcessCommunication.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Navigation { [TestFixture] [Ignore("This test cannot be run headless, as it requires the game host running the nested game to have IPC bound.")] - public class TestSceneInterProcessCommunication : OsuGameTestScene + public partial class TestSceneInterProcessCommunication : OsuGameTestScene { private HeadlessGameHost ipcSenderHost = null!; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs b/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs index 2592936ab6..a89f5fb647 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneMouseWheelVolumeAdjust.cs @@ -12,7 +12,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation { - public class TestSceneMouseWheelVolumeAdjust : OsuGameTestScene + public partial class TestSceneMouseWheelVolumeAdjust : OsuGameTestScene { public override void SetUpSteps() { diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index 6070b1456f..de303fe074 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -30,7 +30,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation { [TestFixture] - public class TestSceneOsuGame : OsuGameTestScene + public partial class TestSceneOsuGame : OsuGameTestScene { private IReadOnlyList requiredGameDependencies => new[] { diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs index ce0543875b..1c8fa775b9 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs @@ -22,7 +22,7 @@ using static osu.Game.Tests.Visual.Navigation.TestSceneScreenNavigation; namespace osu.Game.Tests.Visual.Navigation { - public class TestScenePerformFromScreen : OsuGameTestScene + public partial class TestScenePerformFromScreen : OsuGameTestScene { private bool actionPerformed; @@ -237,7 +237,7 @@ namespace osu.Game.Tests.Visual.Navigation AddUntilStep("beatmap updated", () => Game.Beatmap.Value.BeatmapSetInfo.OnlineID == 241526); } - public class DialogBlockingScreen : OsuScreen + public partial class DialogBlockingScreen : OsuScreen { [Resolved] private IDialogOverlay dialogOverlay { get; set; } @@ -260,7 +260,7 @@ namespace osu.Game.Tests.Visual.Navigation } } - public class TestScreenWithNestedStack : OsuScreen, IHasSubScreenStack + public partial class TestScreenWithNestedStack : OsuScreen, IHasSubScreenStack { public DialogBlockingScreen Blocker { get; private set; } @@ -285,7 +285,7 @@ namespace osu.Game.Tests.Visual.Navigation } } - public class TestLoadBlockingScreen : OsuScreen + public partial class TestLoadBlockingScreen : OsuScreen { public readonly ManualResetEventSlim LoadEvent = new ManualResetEventSlim(); diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs index 02b348b439..8a09e7ac6f 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs @@ -18,7 +18,7 @@ using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.Navigation { - public class TestScenePresentBeatmap : OsuGameTestScene + public partial class TestScenePresentBeatmap : OsuGameTestScene { [Test] public void TestFromMainMenu() diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs index 003cec0d07..4bcd6b100a 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentScore.cs @@ -24,7 +24,7 @@ using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.Navigation { - public class TestScenePresentScore : OsuGameTestScene + public partial class TestScenePresentScore : OsuGameTestScene { private BeatmapSetInfo beatmap; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index e500efede3..d8fda5b21f 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -38,7 +38,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation { - public class TestSceneScreenNavigation : OsuGameTestScene + public partial class TestSceneScreenNavigation : OsuGameTestScene { private const float click_padding = 25; @@ -694,7 +694,7 @@ namespace osu.Game.Tests.Visual.Navigation ConfirmAtMainMenu(); } - public class TestPlaySongSelect : PlaySongSelect + public partial class TestPlaySongSelect : PlaySongSelect { public ModSelectOverlay ModSelectOverlay => ModSelect; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 2f0f2f68a5..e0b61794e4 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -24,7 +24,7 @@ using static osu.Game.Tests.Visual.Navigation.TestSceneScreenNavigation; namespace osu.Game.Tests.Visual.Navigation { - public class TestSceneSkinEditorNavigation : OsuGameTestScene + public partial class TestSceneSkinEditorNavigation : OsuGameTestScene { private TestPlaySongSelect songSelect; private SkinEditor skinEditor => Game.ChildrenOfType().FirstOrDefault(); diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs b/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs index bd3dcb8597..0c165bc40e 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.BeatmapSet; namespace osu.Game.Tests.Visual.Navigation { - public class TestSceneStartupBeatmapDisplay : OsuGameTestScene + public partial class TestSceneStartupBeatmapDisplay : OsuGameTestScene { private const int requested_beatmap_id = 75; private const int requested_beatmap_set_id = 1; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapSetDisplay.cs b/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapSetDisplay.cs index 1072508e33..f885c2f44c 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapSetDisplay.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapSetDisplay.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Navigation { - public class TestSceneStartupBeatmapSetDisplay : OsuGameTestScene + public partial class TestSceneStartupBeatmapSetDisplay : OsuGameTestScene { private const int requested_beatmap_set_id = 1; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneStartupImport.cs b/osu.Game.Tests/Visual/Navigation/TestSceneStartupImport.cs index 552eb82419..e795166d3e 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneStartupImport.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneStartupImport.cs @@ -9,7 +9,7 @@ using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Navigation { - public class TestSceneStartupImport : OsuGameTestScene + public partial class TestSceneStartupImport : OsuGameTestScene { private string? importFilename; diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneStartupRuleset.cs b/osu.Game.Tests/Visual/Navigation/TestSceneStartupRuleset.cs index 1aadff7a20..621dabe869 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneStartupRuleset.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneStartupRuleset.cs @@ -10,7 +10,7 @@ using osu.Game.Configuration; namespace osu.Game.Tests.Visual.Navigation { [TestFixture] - public class TestSceneStartupRuleset : OsuGameTestScene + public partial class TestSceneStartupRuleset : OsuGameTestScene { protected override TestOsuGame CreateTestGame() { diff --git a/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs b/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs index 2879536034..c32aa7f5f9 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs @@ -9,7 +9,7 @@ using osu.Game.Configuration; namespace osu.Game.Tests.Visual.Navigation { - public class TestSettingsMigration : OsuGameTestScene + public partial class TestSettingsMigration : OsuGameTestScene { public override void RecycleLocalStorage(bool isDisposing) { diff --git a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs index b9d800e6fd..0f920643f0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs @@ -18,7 +18,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { - public class TestSceneAccountCreationOverlay : OsuTestScene + public partial class TestSceneAccountCreationOverlay : OsuTestScene { private readonly Container userPanelArea; private readonly AccountCreationOverlay accountCreation; diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs index c78a36d2bd..36f8d2d9bd 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapAvailability.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays.BeatmapSet; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneBeatmapAvailability : OsuTestScene + public partial class TestSceneBeatmapAvailability : OsuTestScene { private readonly BeatmapAvailability container; diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs index ba600332bb..40e34a52b6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapDownloadButton.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { - public class TestSceneBeatmapDownloadButton : OsuTestScene + public partial class TestSceneBeatmapDownloadButton : OsuTestScene { private TestDownloadButton downloadButton; @@ -139,7 +139,7 @@ namespace osu.Game.Tests.Visual.Online return apiBeatmapSet; } - private class TestDownloadButton : BeatmapDownloadButton + private partial class TestDownloadButton : BeatmapDownloadButton { public new bool DownloadEnabled => base.DownloadEnabled; diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs index 1e0a09d37a..c64343b47b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs @@ -25,7 +25,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { - public class TestSceneBeatmapListingOverlay : OsuManualInputManagerTestScene + public partial class TestSceneBeatmapListingOverlay : OsuManualInputManagerTestScene { private readonly List setsForResponse = new List(); diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs index b73028be5b..36c3576da6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays.BeatmapSet; namespace osu.Game.Tests.Visual.Online { - public class TestSceneBeatmapRulesetSelector : OsuTestScene + public partial class TestSceneBeatmapRulesetSelector : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index bb4823fb1d..3335f69dbb 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -24,7 +24,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { - public class TestSceneBeatmapSetOverlay : OsuTestScene + public partial class TestSceneBeatmapSetOverlay : OsuTestScene { private readonly TestBeatmapSetOverlay overlay; @@ -283,7 +283,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.HeaderContent.DownloadButtonsVisible == shown); } - private class TestBeatmapSetOverlay : BeatmapSetOverlay + private partial class TestBeatmapSetOverlay : BeatmapSetOverlay { public new BeatmapSetHeader Header => base.Header; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs index 31cebc2f0b..69c9faa9d3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.Select.Details; namespace osu.Game.Tests.Visual.Online { - public class TestSceneBeatmapSetOverlayDetails : OsuTestScene + public partial class TestSceneBeatmapSetOverlayDetails : OsuTestScene { private RatingsExposingDetails details; @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual.Online }; } - private class RatingsExposingDetails : Details + private partial class RatingsExposingDetails : Details { public new UserRatings Ratings => base.Ratings; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs index 26e1e49ca3..59c96ec719 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Online { - public class TestSceneBeatmapSetOverlaySuccessRate : OsuTestScene + public partial class TestSceneBeatmapSetOverlaySuccessRate : OsuTestScene { private GraphExposingSuccessRate successRate; @@ -104,7 +104,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("graph max values correct", () => successRate.ChildrenOfType().All(graph => graph.MaxValue == 0)); } - private class GraphExposingSuccessRate : SuccessRate + private partial class GraphExposingSuccessRate : SuccessRate { public new FailRetryGraph Graph => base.Graph; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneBundledBeatmapDownloader.cs b/osu.Game.Tests/Visual/Online/TestSceneBundledBeatmapDownloader.cs index 08c6914f83..0f2786f9ef 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBundledBeatmapDownloader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBundledBeatmapDownloader.cs @@ -9,7 +9,7 @@ using osu.Game.Beatmaps.Drawables; namespace osu.Game.Tests.Visual.Online { [Ignore("Only for visual testing")] - public class TestSceneBundledBeatmapDownloader : OsuTestScene + public partial class TestSceneBundledBeatmapDownloader : OsuTestScene { private BundledBeatmapDownloader downloader; diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs index c5ac3dd442..8d61c5df9f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs @@ -18,7 +18,7 @@ using osu.Game.Overlays.Changelog; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneChangelogOverlay : OsuTestScene + public partial class TestSceneChangelogOverlay : OsuTestScene { private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; @@ -201,7 +201,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("show build", () => changelog.ShowBuild(requestedBuild)); } - private class TestChangelogOverlay : ChangelogOverlay + private partial class TestChangelogOverlay : ChangelogOverlay { public new List Streams => base.Streams; diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogSupporterPromo.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogSupporterPromo.cs index 018d40d1bc..96996db940 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChangelogSupporterPromo.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogSupporterPromo.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Changelog; namespace osu.Game.Tests.Visual.Online { - public class TestSceneChangelogSupporterPromo : OsuTestScene + public partial class TestSceneChangelogSupporterPromo : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs index 8e17c490b1..a0cca5f53d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelList.cs @@ -20,7 +20,7 @@ using osu.Game.Overlays.Chat.Listing; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneChannelList : OsuTestScene + public partial class TestSceneChannelList : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelListing.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelListing.cs index 214c05e64d..2d2d7fc0ff 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChannelListing.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChannelListing.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneChannelListing : OsuTestScene + public partial class TestSceneChannelListing : OsuTestScene { [Cached] private readonly OverlayColourProvider overlayColours = new OverlayColourProvider(OverlayColourScheme.Pink); diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs index 79dc17cfa6..32d95ec8dc 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLineTruncation.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.Chat; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneChatLineTruncation : OsuTestScene + public partial class TestSceneChatLineTruncation : OsuTestScene { private readonly TestChatLineContainer textContainer; @@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual.Online } } - private class TestChatLineContainer : FillFlowContainer + private partial class TestChatLineContainer : FillFlowContainer { protected override int Compare(Drawable x, Drawable y) { diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs index de44986001..aa33866fa4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneChatLink : OsuTestScene + public partial class TestSceneChatLink : OsuTestScene { private readonly TestChatLineContainer textContainer; private Color4 linkColour; @@ -207,7 +207,7 @@ namespace osu.Game.Tests.Visual.Online } } - private class TestChatLineContainer : FillFlowContainer + private partial class TestChatLineContainer : FillFlowContainer { protected override int Compare(Drawable x, Drawable y) { diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 0b75a2aa05..8cc4eabcd7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -34,7 +34,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneChatOverlay : OsuManualInputManagerTestScene + public partial class TestSceneChatOverlay : OsuManualInputManagerTestScene { private TestChatOverlay chatOverlay; private ChannelManager channelManager; @@ -621,7 +621,7 @@ namespace osu.Game.Tests.Visual.Online }; } - private class TestChatOverlay : ChatOverlay + private partial class TestChatOverlay : ChatOverlay { public bool SlowLoading { get; set; } @@ -635,7 +635,7 @@ namespace osu.Game.Tests.Visual.Online } } - private class SlowLoadingDrawableChannel : DrawableChannel + private partial class SlowLoadingDrawableChannel : DrawableChannel { public readonly ManualResetEventSlim LoadEvent = new ManualResetEventSlim(); diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatTextBox.cs b/osu.Game.Tests/Visual/Online/TestSceneChatTextBox.cs index 5d28d553a0..1e80acd56b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatTextBox.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatTextBox.cs @@ -18,7 +18,7 @@ using osu.Game.Overlays.Chat; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneChatTextBox : OsuTestScene + public partial class TestSceneChatTextBox : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index b4ffcd42b5..7981e212d4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -25,7 +25,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Online { - public class TestSceneCommentActions : OsuManualInputManagerTestScene + public partial class TestSceneCommentActions : OsuManualInputManagerTestScene { private Container content = null!; protected override Container Content => content; diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs index fb56a41507..d2e73b8673 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentReportButton.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { - public class TestSceneCommentReportButton : ThemeComparisonTestScene + public partial class TestSceneCommentReportButton : ThemeComparisonTestScene { [SetUpSteps] public void SetUpSteps() diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index a94b9e61c0..291ccd634d 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -20,7 +20,7 @@ using osu.Game.Overlays.Comments; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneCommentsContainer : OsuTestScene + public partial class TestSceneCommentsContainer : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs index 95b718041e..43d80ee0ac 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Comments; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneCommentsHeader : OsuTestScene + public partial class TestSceneCommentsHeader : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs index 62f8f72929..4f825e1191 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCurrentlyPlayingDisplay.cs @@ -20,7 +20,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { - public class TestSceneCurrentlyPlayingDisplay : OsuTestScene + public partial class TestSceneCurrentlyPlayingDisplay : OsuTestScene { private readonly APIUser streamingUser = new APIUser { Id = 2, Username = "Test user" }; @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("Panel no longer present", () => !currentlyPlaying.ChildrenOfType().Any()); } - internal class TestUserLookupCache : UserLookupCache + internal partial class TestUserLookupCache : UserLookupCache { private static readonly string[] usernames = { diff --git a/osu.Game.Tests/Visual/Online/TestSceneDashboardOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneDashboardOverlay.cs index 074fea0604..504be45b44 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDashboardOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDashboardOverlay.cs @@ -8,7 +8,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { - public class TestSceneDashboardOverlay : OsuTestScene + public partial class TestSceneDashboardOverlay : OsuTestScene { protected override bool UseOnlineAPI => true; diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs index cab0ffa3ba..ac80463d3a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.Comments; namespace osu.Game.Tests.Visual.Online { - public class TestSceneDrawableComment : OsuTestScene + public partial class TestSceneDrawableComment : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/Online/TestSceneExternalLinkButton.cs b/osu.Game.Tests/Visual/Online/TestSceneExternalLinkButton.cs index 4185d56833..90ec3160d8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneExternalLinkButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneExternalLinkButton.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { - public class TestSceneExternalLinkButton : OsuTestScene + public partial class TestSceneExternalLinkButton : OsuTestScene { public TestSceneExternalLinkButton() { diff --git a/osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs b/osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs index 3206640f9a..3954fd5cff 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneFavouriteButton.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { - public class TestSceneFavouriteButton : OsuTestScene + public partial class TestSceneFavouriteButton : OsuTestScene { private FavouriteButton favourite; diff --git a/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs index 5454c87dff..7925b252b6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs @@ -16,7 +16,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { - public class TestSceneFriendDisplay : OsuTestScene + public partial class TestSceneFriendDisplay : OsuTestScene { protected override bool UseOnlineAPI => true; diff --git a/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs index b7e918207f..16d31c916e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneFullscreenOverlay : OsuTestScene + public partial class TestSceneFullscreenOverlay : OsuTestScene { private FullscreenOverlay overlay; @@ -40,7 +40,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("fire count 3", () => fireCount == 3); } - private class TestFullscreenOverlay : FullscreenOverlay + private partial class TestFullscreenOverlay : FullscreenOverlay { public TestFullscreenOverlay() : base(OverlayColourScheme.Pink) @@ -57,11 +57,11 @@ namespace osu.Game.Tests.Visual.Online protected override OverlayHeader CreateHeader() => new TestHeader(); - internal class TestHeader : OverlayHeader + internal partial class TestHeader : OverlayHeader { protected override OverlayTitle CreateTitle() => new TestTitle(); - internal class TestTitle : OverlayTitle + internal partial class TestTitle : OverlayTitle { } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneGraph.cs index 8b0536651d..357ed7548c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneGraph.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneGraph.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneGraph : OsuTestScene + public partial class TestSceneGraph : OsuTestScene { public TestSceneGraph() { diff --git a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs index afc20dedff..d884c0cf14 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs @@ -16,7 +16,7 @@ using osu.Game.Overlays.Profile.Sections; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneHistoricalSection : OsuTestScene + public partial class TestSceneHistoricalSection : OsuTestScene { protected override bool UseOnlineAPI => true; diff --git a/osu.Game.Tests/Visual/Online/TestSceneHomeNewsPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneHomeNewsPanel.cs index 181b086b00..a58845ca7e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneHomeNewsPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneHomeNewsPanel.cs @@ -15,7 +15,7 @@ using System.Collections.Generic; namespace osu.Game.Tests.Visual.Online { - public class TestSceneHomeNewsPanel : OsuTestScene + public partial class TestSceneHomeNewsPanel : OsuTestScene { [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs index 7f0a00c474..e753632474 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneKudosuHistory.cs @@ -16,7 +16,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Tests.Visual.Online { - public class TestSceneKudosuHistory : OsuTestScene + public partial class TestSceneKudosuHistory : OsuTestScene { private readonly Box background; diff --git a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs index 5579ecedbd..0a6bab468a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardModSelector.cs @@ -20,7 +20,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Tests.Visual.Online { - public class TestSceneLeaderboardModSelector : OsuTestScene + public partial class TestSceneLeaderboardModSelector : OsuTestScene { public TestSceneLeaderboardModSelector() { diff --git a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs index 8c38027df3..0231775189 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { - public class TestSceneLeaderboardScopeSelector : OsuTestScene + public partial class TestSceneLeaderboardScopeSelector : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 57514cdf37..ba2b160fd1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -23,7 +23,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { - public class TestSceneMessageNotifier : OsuManualInputManagerTestScene + public partial class TestSceneMessageNotifier : OsuManualInputManagerTestScene { private APIUser friend; private Channel publicChannel; @@ -228,7 +228,7 @@ namespace osu.Game.Tests.Visual.Online InputManager.Click(MouseButton.Left); } - private class TestContainer : Container + private partial class TestContainer : Container { [Cached] public ChannelManager ChannelManager { get; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneNewsCard.cs b/osu.Game.Tests/Visual/Online/TestSceneNewsCard.cs index 8d73165d99..001e6d925e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNewsCard.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNewsCard.cs @@ -14,7 +14,7 @@ using System; namespace osu.Game.Tests.Visual.Online { - public class TestSceneNewsCard : OsuTestScene + public partial class TestSceneNewsCard : OsuTestScene { [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/Online/TestSceneNewsHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneNewsHeader.cs index cad045623b..2413c32d61 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNewsHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNewsHeader.cs @@ -11,7 +11,7 @@ using osu.Framework.Allocation; namespace osu.Game.Tests.Visual.Online { - public class TestSceneNewsHeader : OsuTestScene + public partial class TestSceneNewsHeader : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("1 tab total", () => header.TabCount == 1); } - private class TestHeader : NewsHeader + private partial class TestHeader : NewsHeader { public int TabCount => TabControl.Items.Count; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs index 3e5dd91b2c..0e272c9cc8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNewsOverlay.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { - public class TestSceneNewsOverlay : OsuTestScene + public partial class TestSceneNewsOverlay : OsuTestScene { private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; diff --git a/osu.Game.Tests/Visual/Online/TestSceneNewsSidebar.cs b/osu.Game.Tests/Visual/Online/TestSceneNewsSidebar.cs index 266e98db15..ce5fc888aa 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNewsSidebar.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNewsSidebar.cs @@ -16,7 +16,7 @@ using static osu.Game.Overlays.News.Sidebar.YearsPanel; namespace osu.Game.Tests.Visual.Online { - public class TestSceneNewsSidebar : OsuTestScene + public partial class TestSceneNewsSidebar : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); @@ -211,7 +211,7 @@ namespace osu.Game.Tests.Visual.Online } }; - private class TestNewsSidebar : NewsSidebar + private partial class TestNewsSidebar : NewsSidebar { public Action YearChanged; diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs index 2df9089a8a..c017227243 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs @@ -16,7 +16,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { [HeadlessTest] - public class TestSceneNowPlayingCommand : OsuTestScene + public partial class TestSceneNowPlayingCommand : OsuTestScene { [Cached(typeof(IChannelPostTarget))] private PostTarget postTarget { get; set; } @@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Check link not present", () => !postTarget.LastMessage.Contains("https://")); } - public class PostTarget : Component, IChannelPostTarget + public partial class PostTarget : Component, IChannelPostTarget { public void PostMessage(string text, bool isAction = false, Channel target = null) { diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs index 07ccfcec88..4016fa7b68 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -19,7 +19,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { - public class TestSceneOfflineCommentsContainer : OsuTestScene + public partial class TestSceneOfflineCommentsContainer : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); @@ -184,7 +184,7 @@ namespace osu.Game.Tests.Visual.Online PinnedComments = new List(), }; - private class TestCommentsContainer : CommentsContainer + private partial class TestCommentsContainer : CommentsContainer { public new void AppendComments([NotNull] CommentBundle bundle) => base.AppendComments(bundle); diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineBeatmapListingOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineBeatmapListingOverlay.cs index 388c0a9d60..ecfa76f395 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineBeatmapListingOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineBeatmapListingOverlay.cs @@ -9,7 +9,7 @@ using NUnit.Framework; namespace osu.Game.Tests.Visual.Online { [Description("uses online API")] - public class TestSceneOnlineBeatmapListingOverlay : OsuTestScene + public partial class TestSceneOnlineBeatmapListingOverlay : OsuTestScene { protected override bool UseOnlineAPI => true; diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineBeatmapSetOverlay.cs index 0d9c47db7b..01b0b39661 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineBeatmapSetOverlay.cs @@ -8,7 +8,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { - public class TestSceneOnlineBeatmapSetOverlay : OsuTestScene + public partial class TestSceneOnlineBeatmapSetOverlay : OsuTestScene { private readonly BeatmapSetOverlay overlay; diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index b4bac5ee7e..6c8430e955 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneOnlineViewContainer : OsuTestScene + public partial class TestSceneOnlineViewContainer : OsuTestScene { private readonly TestOnlineViewContainer onlineView; @@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("loading animation is visible", () => onlineView.LoadingSpinner.IsPresent); } - private class TestOnlineViewContainer : OnlineViewContainer + private partial class TestOnlineViewContainer : OnlineViewContainer { public new LoadingSpinner LoadingSpinner => base.LoadingSpinner; diff --git a/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs b/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs index 118da682a7..15e411b9d8 100644 --- a/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs +++ b/osu.Game.Tests/Visual/Online/TestScenePlayHistorySubsection.cs @@ -17,7 +17,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tests.Visual.Online { - public class TestScenePlayHistorySubsection : OsuTestScene + public partial class TestScenePlayHistorySubsection : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Red); diff --git a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs index 3068ba0185..e81b7a2ac8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs @@ -16,7 +16,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tests.Visual.Online { - public class TestSceneProfileRulesetSelector : OsuTestScene + public partial class TestSceneProfileRulesetSelector : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs index d05f1f02f7..55817e38a6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneRankGraph : OsuTestScene + public partial class TestSceneRankGraph : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsCountryFilter.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsCountryFilter.cs index 6a39db4870..dfefcd735e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsCountryFilter.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsCountryFilter.cs @@ -16,7 +16,7 @@ using osu.Framework.Allocation; namespace osu.Game.Tests.Visual.Online { - public class TestSceneRankingsCountryFilter : OsuTestScene + public partial class TestSceneRankingsCountryFilter : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs index c776cfe377..5aef91bef1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs @@ -12,7 +12,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { - public class TestSceneRankingsHeader : OsuTestScene + public partial class TestSceneRankingsHeader : OsuTestScene { [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs index 5476049882..d1c1164768 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs @@ -15,7 +15,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { - public class TestSceneRankingsOverlay : OsuTestScene + public partial class TestSceneRankingsOverlay : OsuTestScene { protected override bool UseOnlineAPI => true; @@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.Online }; } - private class TestRankingsOverlay : RankingsOverlay + private partial class TestRankingsOverlay : RankingsOverlay { public new Bindable Country => base.Country; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs index 5aafcf3f6b..119d79e2a9 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.Rankings; namespace osu.Game.Tests.Visual.Online { - public class TestSceneRankingsSpotlightSelector : OsuTestScene + public partial class TestSceneRankingsSpotlightSelector : OsuTestScene { protected override bool UseOnlineAPI => true; diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs index 81b76d19ac..cd5e1cef08 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs @@ -16,7 +16,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { - public class TestSceneRankingsTables : OsuTestScene + public partial class TestSceneRankingsTables : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoreboardTime.cs b/osu.Game.Tests/Visual/Online/TestSceneScoreboardTime.cs index 8f03f240f7..ab85cd4a15 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneScoreboardTime.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneScoreboardTime.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays.BeatmapSet.Scores; namespace osu.Game.Tests.Visual.Online { - public class TestSceneScoreboardTime : OsuTestScene + public partial class TestSceneScoreboardTime : OsuTestScene { private StopwatchClock stopwatch; diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs index a0f76c4e14..2bfbf76c10 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs @@ -26,7 +26,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.Online { - public class TestSceneScoresContainer : OsuTestScene + public partial class TestSceneScoresContainer : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); @@ -313,7 +313,7 @@ namespace osu.Game.Tests.Visual.Online Position = 1337, }; - private class TestScoresContainer : ScoresContainer + private partial class TestScoresContainer : ScoresContainer { public new APIScoresCollection Scores { diff --git a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs index 32262c18a8..905a085386 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { - public class TestSceneShowMoreButton : OsuTestScene + public partial class TestSceneShowMoreButton : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs b/osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs index d7feade128..4cbcaaac85 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets.Taiko; namespace osu.Game.Tests.Visual.Online { - public class TestSceneSpotlightsLayout : OsuTestScene + public partial class TestSceneSpotlightsLayout : OsuTestScene { protected override bool UseOnlineAPI => true; diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index 34ecad7dc1..7d2ac90939 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Online { - public class TestSceneStandAloneChatDisplay : OsuManualInputManagerTestScene + public partial class TestSceneStandAloneChatDisplay : OsuManualInputManagerTestScene { private readonly APIUser admin = new APIUser { @@ -401,7 +401,7 @@ namespace osu.Game.Tests.Visual.Online private void checkNotScrolledToBottom() => AddUntilStep("not scrolled to bottom", () => !chatDisplay.ScrolledToBottom); - private class TestStandAloneChatDisplay : StandAloneChatDisplay + private partial class TestStandAloneChatDisplay : StandAloneChatDisplay { public TestStandAloneChatDisplay(bool textBox = false) : base(textBox) diff --git a/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs b/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs index d4355d2f11..8af87dd597 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { - public class TestSceneTotalCommentsCounter : OsuTestScene + public partial class TestSceneTotalCommentsCounter : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs index 42a8462604..d93bf059dd 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserHistoryGraph.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Profile.Sections.Historical; namespace osu.Game.Tests.Visual.Online { - public class TestSceneUserHistoryGraph : OsuTestScene + public partial class TestSceneUserHistoryGraph : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index 2a70fd7df3..4c1df850b2 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneUserPanel : OsuTestScene + public partial class TestSceneUserPanel : OsuTestScene { private readonly Bindable activity = new Bindable(); private readonly Bindable status = new Bindable(); @@ -132,7 +132,7 @@ namespace osu.Game.Tests.Visual.Online private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.InSoloGame(null, rulesetStore.GetRuleset(rulesetId)); - private class TestUserListPanel : UserListPanel + private partial class TestUserListPanel : UserListPanel { public TestUserListPanel(APIUser user) : base(user) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs index 1abe06ed76..75743d788a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs @@ -15,7 +15,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { - public class TestSceneUserProfileHeader : OsuTestScene + public partial class TestSceneUserProfileHeader : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 7064a08151..02d01b4a46 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -14,7 +14,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneUserProfileOverlay : OsuTestScene + public partial class TestSceneUserProfileOverlay : OsuTestScene { protected override bool UseOnlineAPI => true; @@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Show without reload", profile.Show); } - private class TestUserProfileOverlay : UserProfileOverlay + private partial class TestUserProfileOverlay : UserProfileOverlay { public new ProfileHeader Header => base.Header; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs index 4260fff02d..fcefb31716 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfilePreviousUsernames.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Profile.Header.Components; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneUserProfilePreviousUsernames : OsuTestScene + public partial class TestSceneUserProfilePreviousUsernames : OsuTestScene { private PreviousUsernames container; diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs index 7875a9dfbc..f8432118d4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs @@ -20,7 +20,7 @@ using osu.Game.Overlays.Profile.Sections.Recent; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneUserProfileRecentSection : OsuTestScene + public partial class TestSceneUserProfileRecentSection : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs index 4bbb72c862..6f0ef10911 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Online { - public class TestSceneUserProfileScores : OsuTestScene + public partial class TestSceneUserProfileScores : OsuTestScene { public TestSceneUserProfileScores() { @@ -138,7 +138,7 @@ namespace osu.Game.Tests.Visual.Online }); } - private class ColourProvidedContainer : Container + private partial class ColourProvidedContainer : Container { [Cached] private readonly OverlayColourProvider colourProvider; diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs index d517aaa105..ef3a677efc 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs @@ -17,7 +17,7 @@ using osu.Game.Overlays.Profile.Sections; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneUserRanks : OsuTestScene + public partial class TestSceneUserRanks : OsuTestScene { protected override bool UseOnlineAPI => true; diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs b/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs index 32d427ba6d..1ffb438355 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs @@ -20,7 +20,7 @@ using osu.Game.Rulesets.Taiko; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneUserRequest : OsuTestScene + public partial class TestSceneUserRequest : OsuTestScene { [Resolved] private IAPIProvider api { get; set; } @@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.Online api.Queue(request); } - private class UserTestContainer : FillFlowContainer + private partial class UserTestContainer : FillFlowContainer { public readonly Bindable User = new Bindable(); diff --git a/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs b/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs index fdc15af73d..ce1a9ac6a7 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs @@ -15,7 +15,7 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneVotePill : OsuTestScene + public partial class TestSceneVotePill : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); @@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Online }; } - private class TestPill : VotePill + private partial class TestPill : VotePill { public new Box Background => base.Background; diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs index 99e301f3ba..4e71c5977e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiHeader.cs @@ -16,7 +16,7 @@ using osu.Game.Overlays.Wiki; namespace osu.Game.Tests.Visual.Online { - public class TestSceneWikiHeader : OsuTestScene + public partial class TestSceneWikiHeader : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Orange); @@ -97,7 +97,7 @@ namespace osu.Game.Tests.Visual.Online }; } - private class TestHeader : WikiHeader + private partial class TestHeader : WikiHeader { public IReadOnlyList TabControlItems => TabControl.Items; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs index 03b94aded7..8876f0fd3b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMainPage.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Wiki; namespace osu.Game.Tests.Visual.Online { - public class TestSceneWikiMainPage : OsuTestScene + public partial class TestSceneWikiMainPage : OsuTestScene { [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Orange); diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 863b352618..b486f800c6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -21,7 +21,7 @@ using osu.Game.Overlays.Wiki.Markdown; namespace osu.Game.Tests.Visual.Online { - public class TestSceneWikiMarkdownContainer : OsuTestScene + public partial class TestSceneWikiMarkdownContainer : OsuTestScene { private TestMarkdownContainer markdownContainer; @@ -199,7 +199,7 @@ Line after image"; }); } - private class TestMarkdownContainer : WikiMarkdownContainer + private partial class TestMarkdownContainer : WikiMarkdownContainer { public LinkInline Link; @@ -208,7 +208,7 @@ Line after image"; UrlAdded = link => Link = link, }; - private class TestMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer + private partial class TestMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer { public Action UrlAdded; diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs index 27cd74bb1f..620fd710e3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Online { - public class TestSceneWikiOverlay : OsuTestScene + public partial class TestSceneWikiOverlay : OsuTestScene { private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs index 33e3ee7023..89944b3a8a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays.Wiki; namespace osu.Game.Tests.Visual.Online { - public class TestSceneWikiSidebar : OsuTestScene + public partial class TestSceneWikiSidebar : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Orange); diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs index 8ca37a241b..0c536cb1d4 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs @@ -17,7 +17,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Playlists { - public class TestScenePlaylistsLoungeSubScreen : OnlinePlayTestScene + public partial class TestScenePlaylistsLoungeSubScreen : OnlinePlayTestScene { protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager; @@ -95,7 +95,7 @@ namespace osu.Game.Tests.Visual.Playlists loungeScreen.ChildrenOfType().First().ScreenSpaceDrawQuad .Contains(room.ScreenSpaceDrawQuad.Centre); - private class TestLoungeSubScreen : PlaylistsLoungeSubScreen + private partial class TestLoungeSubScreen : PlaylistsLoungeSubScreen { public new Bindable SelectedRoom => base.SelectedRoom; } diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs index c71bdb3a06..901c541026 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs @@ -17,7 +17,7 @@ using osu.Game.Tests.Visual.OnlinePlay; namespace osu.Game.Tests.Visual.Playlists { - public class TestScenePlaylistsMatchSettingsOverlay : OnlinePlayTestScene + public partial class TestScenePlaylistsMatchSettingsOverlay : OnlinePlayTestScene { protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager; @@ -146,7 +146,7 @@ namespace osu.Game.Tests.Visual.Playlists AddUntilStep("error not displayed", () => !settings.ErrorText.IsPresent); } - private class TestRoomSettings : PlaylistsRoomSettingsOverlay + private partial class TestRoomSettings : PlaylistsRoomSettingsOverlay { public TriangleButton ApplyButton => ((MatchSettings)Settings).ApplyButton; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs index 9a0dda056a..c4a1200cb1 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsParticipantsList.cs @@ -13,7 +13,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.Playlists { - public class TestScenePlaylistsParticipantsList : OnlinePlayTestScene + public partial class TestScenePlaylistsParticipantsList : OnlinePlayTestScene { public override void SetUpSteps() { diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index 26fa740159..cb422d8c06 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -28,7 +28,7 @@ using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Playlists { - public class TestScenePlaylistsResultsScreen : ScreenTestScene + public partial class TestScenePlaylistsResultsScreen : ScreenTestScene { private const int scores_per_result = 10; private const int real_user_position = 200; @@ -365,7 +365,7 @@ namespace osu.Game.Tests.Visual.Playlists }; } - private class TestResultsScreen : PlaylistsResultsScreen + private partial class TestResultsScreen : PlaylistsResultsScreen { public new LoadingSpinner LeftSpinner => base.LeftSpinner; public new LoadingSpinner CentreSpinner => base.CentreSpinner; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs index b304b34275..bdae91de59 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs @@ -33,7 +33,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Playlists { - public class TestScenePlaylistsRoomCreation : OnlinePlayTestScene + public partial class TestScenePlaylistsRoomCreation : OnlinePlayTestScene { private BeatmapManager manager; @@ -219,7 +219,7 @@ namespace osu.Game.Tests.Visual.Playlists importedBeatmap = manager.Import(beatmap.BeatmapInfo.BeatmapSet)?.Value.Detach(); }); - private class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen + private partial class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen { public new Bindable SelectedItem => base.SelectedItem; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs index af3d2d9d9a..71e284ecfe 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsScreen.cs @@ -8,7 +8,7 @@ using NUnit.Framework; namespace osu.Game.Tests.Visual.Playlists { [TestFixture] - public class TestScenePlaylistsScreen : ScreenTestScene + public partial class TestScenePlaylistsScreen : ScreenTestScene { protected override bool UseOnlineAPI => true; diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs index 3e2043cea5..0145a1dfef 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneAccuracyCircle.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Ranking { - public class TestSceneAccuracyCircle : OsuTestScene + public partial class TestSceneAccuracyCircle : OsuTestScene { [TestCase(0.2, ScoreRank.D)] [TestCase(0.5, ScoreRank.D)] diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneContractedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneContractedPanelMiddleContent.cs index 83242fe363..e92e74598d 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneContractedPanelMiddleContent.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneContractedPanelMiddleContent.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Ranking { - public class TestSceneContractedPanelMiddleContent : OsuTestScene + public partial class TestSceneContractedPanelMiddleContent : OsuTestScene { [Test] public void TestShowPanel() @@ -45,7 +45,7 @@ namespace osu.Game.Tests.Visual.Ranking Child = new ContractedPanelMiddleContentContainer(workingBeatmap, score); } - private class ContractedPanelMiddleContentContainer : Container + private partial class ContractedPanelMiddleContentContainer : Container { [Cached] private Bindable workingBeatmap { get; set; } diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs index 62e9adcf25..bd7a11b4bb 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelMiddleContent.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Ranking { - public class TestSceneExpandedPanelMiddleContent : OsuTestScene + public partial class TestSceneExpandedPanelMiddleContent : OsuTestScene { [Resolved] private RulesetStore rulesetStore { get; set; } @@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual.Ranking private bool containsAny(string text, params string[] stringsToMatch) => stringsToMatch.Any(text.Contains); - private class ExpandedPanelMiddleContentContainer : Container + private partial class ExpandedPanelMiddleContentContainer : Container { public ExpandedPanelMiddleContentContainer(ScoreInfo score) { diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelTopContent.cs b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelTopContent.cs index 94f6fa8839..be7be6d4f1 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelTopContent.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneExpandedPanelTopContent.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Ranking { - public class TestSceneExpandedPanelTopContent : OsuTestScene + public partial class TestSceneExpandedPanelTopContent : OsuTestScene { public TestSceneExpandedPanelTopContent() { diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs index e014d79402..a40cb41e2c 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Ranking { - public class TestSceneHitEventTimingDistributionGraph : OsuTestScene + public partial class TestSceneHitEventTimingDistributionGraph : OsuTestScene { private HitEventTimingDistributionGraph graph = null!; private readonly BindableFloat width = new BindableFloat(600); diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs index 89d6206fd7..42068ff117 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs @@ -35,7 +35,7 @@ using Realms; namespace osu.Game.Tests.Visual.Ranking { [TestFixture] - public class TestSceneResultsScreen : OsuManualInputManagerTestScene + public partial class TestSceneResultsScreen : OsuManualInputManagerTestScene { [Resolved] private BeatmapManager beatmaps { get; set; } @@ -309,7 +309,7 @@ namespace osu.Game.Tests.Visual.Ranking private UnrankedSoloResultsScreen createUnrankedSoloResultsScreen() => new UnrankedSoloResultsScreen(TestResources.CreateTestScoreInfo()); - private class TestResultsContainer : Container + private partial class TestResultsContainer : Container { [Cached(typeof(Player))] private readonly Player player = new TestPlayer(); @@ -328,7 +328,7 @@ namespace osu.Game.Tests.Visual.Ranking } } - private class TestResultsScreen : ResultsScreen + private partial class TestResultsScreen : ResultsScreen { public HotkeyRetryOverlay RetryOverlay; @@ -362,7 +362,7 @@ namespace osu.Game.Tests.Visual.Ranking } } - private class DelayedFetchResultsScreen : TestResultsScreen + private partial class DelayedFetchResultsScreen : TestResultsScreen { private readonly Task fetchWaitTask; @@ -398,7 +398,7 @@ namespace osu.Game.Tests.Visual.Ranking } } - private class UnrankedSoloResultsScreen : SoloResultsScreen + private partial class UnrankedSoloResultsScreen : SoloResultsScreen { public HotkeyRetryOverlay RetryOverlay; diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs index 77fcd04fbd..b87e5adfb1 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanel.cs @@ -12,7 +12,7 @@ using osu.Game.Tests.Resources; namespace osu.Game.Tests.Visual.Ranking { - public class TestSceneScorePanel : OsuTestScene + public partial class TestSceneScorePanel : OsuTestScene { private ScorePanel panel; diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs index 871224f3e4..f08a6c9eca 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Ranking { - public class TestSceneScorePanelList : OsuManualInputManagerTestScene + public partial class TestSceneScorePanelList : OsuManualInputManagerTestScene { private ScorePanelList list; diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneSimpleStatisticTable.cs b/osu.Game.Tests/Visual/Ranking/TestSceneSimpleStatisticTable.cs index 57a3907b6e..81d146614a 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneSimpleStatisticTable.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneSimpleStatisticTable.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.Ranking.Statistics; namespace osu.Game.Tests.Visual.Ranking { - public class TestSceneSimpleStatisticTable : OsuTestScene + public partial class TestSceneSimpleStatisticTable : OsuTestScene { private Container container; diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs b/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs index 8214c52edc..fcd5f97fcc 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Ranking { - public class TestSceneStatisticsPanel : OsuTestScene + public partial class TestSceneStatisticsPanel : OsuTestScene { [Test] public void TestScoreWithTimeStatistics() diff --git a/osu.Game.Tests/Visual/Settings/TestSceneDirectorySelector.cs b/osu.Game.Tests/Visual/Settings/TestSceneDirectorySelector.cs index 16110e5595..ce6973aacf 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneDirectorySelector.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneDirectorySelector.cs @@ -9,7 +9,7 @@ using osu.Game.Tests.Visual.UserInterface; namespace osu.Game.Tests.Visual.Settings { - public class TestSceneDirectorySelector : ThemeComparisonTestScene + public partial class TestSceneDirectorySelector : ThemeComparisonTestScene { protected override Drawable CreateContent() => new OsuDirectorySelector { diff --git a/osu.Game.Tests/Visual/Settings/TestSceneFileSelector.cs b/osu.Game.Tests/Visual/Settings/TestSceneFileSelector.cs index 97bf0d212a..f61e3ca557 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneFileSelector.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneFileSelector.cs @@ -13,7 +13,7 @@ using osu.Game.Tests.Visual.UserInterface; namespace osu.Game.Tests.Visual.Settings { - public class TestSceneFileSelector : ThemeComparisonTestScene + public partial class TestSceneFileSelector : ThemeComparisonTestScene { [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index bd54591b9b..da48086717 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -17,7 +17,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Settings { [TestFixture] - public class TestSceneKeyBindingPanel : OsuManualInputManagerTestScene + public partial class TestSceneKeyBindingPanel : OsuManualInputManagerTestScene { private readonly KeyBindingPanel panel; diff --git a/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs index caffc54d47..84c153c15b 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneLatencyCertifierScreen.cs @@ -10,7 +10,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Settings { - public class TestSceneLatencyCertifierScreen : ScreenTestScene + public partial class TestSceneLatencyCertifierScreen : ScreenTestScene { private LatencyCertifierScreen latencyCertifier = null!; diff --git a/osu.Game.Tests/Visual/Settings/TestSceneMigrationScreens.cs b/osu.Game.Tests/Visual/Settings/TestSceneMigrationScreens.cs index e32757c6f6..91320fdb1c 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneMigrationScreens.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneMigrationScreens.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays.Settings.Sections.Maintenance; namespace osu.Game.Tests.Visual.Settings { - public class TestSceneMigrationScreens : ScreenTestScene + public partial class TestSceneMigrationScreens : ScreenTestScene { [Cached(typeof(INotificationOverlay))] private readonly NotificationOverlay notifications; @@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.Settings AddStep("Push screen", () => Stack.Push(new TestMigrationSelectScreen(false))); } - private class TestMigrationSelectScreen : MigrationSelectScreen + private partial class TestMigrationSelectScreen : MigrationSelectScreen { private readonly bool deleteSuccess; @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Settings protected override void BeginMigration(DirectoryInfo target) => this.Push(new TestMigrationRunScreen(deleteSuccess)); - private class TestMigrationRunScreen : MigrationRunScreen + private partial class TestMigrationRunScreen : MigrationRunScreen { private readonly bool success; diff --git a/osu.Game.Tests/Visual/Settings/TestSceneRestoreDefaultValueButton.cs b/osu.Game.Tests/Visual/Settings/TestSceneRestoreDefaultValueButton.cs index 289969af3e..6e52881f5e 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneRestoreDefaultValueButton.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneRestoreDefaultValueButton.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Settings { - public class TestSceneRestoreDefaultValueButton : OsuTestScene + public partial class TestSceneRestoreDefaultValueButton : OsuTestScene { [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs index 6ff53663ba..384508f375 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs @@ -17,7 +17,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Settings { [TestFixture] - public class TestSceneSettingsItem : OsuTestScene + public partial class TestSceneSettingsItem : OsuTestScene { [Test] public void TestRestoreDefaultValueButtonVisibility() diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsNumberBox.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsNumberBox.cs index 53e1f0e0bf..fc261611db 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsNumberBox.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsNumberBox.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Tests.Visual.Settings { - public class TestSceneSettingsNumberBox : OsuTestScene + public partial class TestSceneSettingsNumberBox : OsuTestScene { private SettingsNumberBox numberBox; private OsuTextBox textBox; diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs index ad60c98e05..4e295ba665 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Settings { [TestFixture] - public class TestSceneSettingsPanel : OsuManualInputManagerTestScene + public partial class TestSceneSettingsPanel : OsuManualInputManagerTestScene { private SettingsPanel settings; private DialogOverlay dialogOverlay; diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs index 3cf6f7febf..30811bab32 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsSource.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Settings { [TestFixture] - public class TestSceneSettingsSource : OsuTestScene + public partial class TestSceneSettingsSource : OsuTestScene { public TestSceneSettingsSource() { diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index 5e75bd7bc1..5ca08e0bba 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Tests.Visual.Settings { [TestFixture] - public class TestSceneTabletSettings : OsuTestScene + public partial class TestSceneTabletSettings : OsuTestScene { private TestTabletHandler tabletHandler; private TabletSettings settings; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs index 1042341337..8650119dd4 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.SongSelect { [System.ComponentModel.Description("Advanced beatmap statistics display")] - public class TestSceneAdvancedStats : OsuTestScene + public partial class TestSceneAdvancedStats : OsuTestScene { private TestAdvancedStats advancedStats; @@ -164,7 +164,7 @@ namespace osu.Game.Tests.Visual.SongSelect private bool barIsBlue(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == colours.BlueDark; private bool barIsRed(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == colours.Red; - private class TestAdvancedStats : AdvancedStats + private partial class TestAdvancedStats : AdvancedStats { public new StatisticRow FirstValue => base.FirstValue; public new StatisticRow HpDrain => base.HpDrain; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index d4d9f89c6a..2d1c5ef120 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -26,7 +26,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] - public class TestSceneBeatmapCarousel : OsuManualInputManagerTestScene + public partial class TestSceneBeatmapCarousel : OsuManualInputManagerTestScene { private TestBeatmapCarousel carousel; private RulesetStore rulesets; @@ -1112,7 +1112,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddAssert("Selection is visible", selectedBeatmapVisible); } - private class TestBeatmapCarousel : BeatmapCarousel + private partial class TestBeatmapCarousel : BeatmapCarousel { public bool PendingFilterTask => PendingFilter != null; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs index e33cfe280e..20cc1e544e 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs @@ -14,7 +14,7 @@ using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.SongSelect { [System.ComponentModel.Description("PlaySongSelect beatmap details")] - public class TestSceneBeatmapDetails : OsuTestScene + public partial class TestSceneBeatmapDetails : OsuTestScene { private BeatmapDetails details; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs index a144111fd3..a470ed47d4 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs @@ -30,7 +30,7 @@ using osuTK; namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] - public class TestSceneBeatmapInfoWedge : OsuTestScene + public partial class TestSceneBeatmapInfoWedge : OsuTestScene { private RulesetStore rulesets; private TestBeatmapInfoWedge infoWedge; @@ -267,7 +267,7 @@ namespace osu.Game.Tests.Visual.SongSelect }; } - private class TestBeatmapInfoWedge : BeatmapInfoWedge + private partial class TestBeatmapInfoWedge : BeatmapInfoWedge { public new Container DisplayedContent => base.DisplayedContent; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 1839821bb5..ef0ad6c25c 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Tests.Visual.SongSelect { - public class TestSceneBeatmapLeaderboard : OsuTestScene + public partial class TestSceneBeatmapLeaderboard : OsuTestScene { private readonly FailableLeaderboard leaderboard; @@ -381,7 +381,7 @@ namespace osu.Game.Tests.Visual.SongSelect }; } - private class FailableLeaderboard : BeatmapLeaderboard + private partial class FailableLeaderboard : BeatmapLeaderboard { public new void SetErrorState(LeaderboardState state) => base.SetErrorState(state); public new void SetScores(IEnumerable? scores, ScoreInfo? userScore = null) => base.SetScores(scores, userScore); diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs index c42b51c1a6..c2537cff79 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Tests.Visual.SongSelect { - public class TestSceneBeatmapMetadataDisplay : OsuTestScene + public partial class TestSceneBeatmapMetadataDisplay : OsuTestScene { private BeatmapMetadataDisplay display; @@ -119,7 +119,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("finish loading", () => display.Loading = false); } - private class TestBeatmapDifficultyCache : BeatmapDifficultyCache + private partial class TestBeatmapDifficultyCache : BeatmapDifficultyCache { private TaskCompletionSource calculationBlocker; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs index 5ad82f1ffd..46a26d2e98 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapOptionsOverlay.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Select.Options; namespace osu.Game.Tests.Visual.SongSelect { [Description("bottom beatmap details")] - public class TestSceneBeatmapOptionsOverlay : OsuTestScene + public partial class TestSceneBeatmapOptionsOverlay : OsuTestScene { public TestSceneBeatmapOptionsOverlay() { diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 504ded5406..a368e901f5 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -23,7 +23,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.SongSelect { - public class TestSceneBeatmapRecommendations : OsuGameTestScene + public partial class TestSceneBeatmapRecommendations : OsuGameTestScene { [Resolved] private IRulesetStore rulesetStore { get; set; } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs index 7ae2c6e5e2..275e6ca753 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneDifficultyRangeFilterControl.cs @@ -8,7 +8,7 @@ using osuTK; namespace osu.Game.Tests.Visual.SongSelect { - public class TestSceneDifficultyRangeFilterControl : OsuTestScene + public partial class TestSceneDifficultyRangeFilterControl : OsuTestScene { [Test] public void TestBasic() diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs index dadcd43db5..64e2447cca 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneFilterControl.cs @@ -24,7 +24,7 @@ using Realms; namespace osu.Game.Tests.Visual.SongSelect { - public class TestSceneFilterControl : OsuManualInputManagerTestScene + public partial class TestSceneFilterControl : OsuManualInputManagerTestScene { protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index b6b9e8926b..01c5ad8358 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -42,7 +42,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] - public class TestScenePlaySongSelect : ScreenTestScene + public partial class TestScenePlaySongSelect : ScreenTestScene { private BeatmapManager manager = null!; private RulesetStore rulesets = null!; @@ -1141,7 +1141,7 @@ namespace osu.Game.Tests.Visual.SongSelect rulesets.Dispose(); } - private class TestSongSelect : PlaySongSelect + private partial class TestSongSelect : PlaySongSelect { public Action? StartRequested; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs index 0a88abface..646dedc2be 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneSongSelectFooter.cs @@ -13,7 +13,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.SongSelect { - public class TestSceneSongSelectFooter : OsuManualInputManagerTestScene + public partial class TestSceneSongSelectFooter : OsuManualInputManagerTestScene { private FooterButtonRandom randomButton; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs index cced9b8b89..cf0de14541 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Tests.Visual.SongSelect { - public class TestSceneTopLocalRank : OsuTestScene + public partial class TestSceneTopLocalRank : OsuTestScene { private RulesetStore rulesets = null!; private BeatmapManager beatmapManager = null!; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs index 96cfbe4dd1..e47b7e25a8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs @@ -22,7 +22,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.SongSelect { [TestFixture] - public class TestSceneUpdateBeatmapSetButton : OsuManualInputManagerTestScene + public partial class TestSceneUpdateBeatmapSetButton : OsuManualInputManagerTestScene { private BeatmapCarousel carousel = null!; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs index 39fd9fda2b..0476198e41 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs @@ -19,7 +19,7 @@ using osu.Game.Users; namespace osu.Game.Tests.Visual.SongSelect { - public class TestSceneUserTopScoreContainer : OsuTestScene + public partial class TestSceneUserTopScoreContainer : OsuTestScene { [Cached(typeof(IDialogOverlay))] private readonly DialogOverlay dialogOverlay; diff --git a/osu.Game.Tests/Visual/TestMultiplayerComponents.cs b/osu.Game.Tests/Visual/TestMultiplayerComponents.cs index 0458f41358..1814fb70c8 100644 --- a/osu.Game.Tests/Visual/TestMultiplayerComponents.cs +++ b/osu.Game.Tests/Visual/TestMultiplayerComponents.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual /// ///

///
- public class TestMultiplayerComponents : OsuScreen + public partial class TestMultiplayerComponents : OsuScreen { public Screens.OnlinePlay.Multiplayer.Multiplayer MultiplayerScreen => multiplayerScreen; @@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual return true; } - private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer + private partial class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer { public new TestMultiplayerRoomManager RoomManager { get; private set; } public TestRoomRequestsHandler RequestsHandler { get; private set; } diff --git a/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs b/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs index 7588546f42..7f01a67903 100644 --- a/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs +++ b/osu.Game.Tests/Visual/TestSceneOsuScreenStack.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual { [TestFixture] - public class TestSceneOsuScreenStack : OsuTestScene + public partial class TestSceneOsuScreenStack : OsuTestScene { private TestOsuScreenStack stack; @@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual AddAssert("allows adjustments 11", () => musicController.AllowTrackAdjustments); } - public class TestScreen : ScreenWithBeatmapBackground + public partial class TestScreen : ScreenWithBeatmapBackground { private readonly string screenText; @@ -112,7 +112,7 @@ namespace osu.Game.Tests.Visual } } - private class NoParallaxTestScreen : TestScreen + private partial class NoParallaxTestScreen : TestScreen { public NoParallaxTestScreen(string screenText) : base(screenText) @@ -122,22 +122,22 @@ namespace osu.Game.Tests.Visual public override float BackgroundParallaxAmount => 0.0f; } - private class TestOsuScreenStack : OsuScreenStack + private partial class TestOsuScreenStack : OsuScreenStack { public new float ParallaxAmount => base.ParallaxAmount; } - private class AllowScreen : OsuScreen + private partial class AllowScreen : OsuScreen { public override bool? AllowTrackAdjustments => true; } - public class DisallowScreen : OsuScreen + public partial class DisallowScreen : OsuScreen { public override bool? AllowTrackAdjustments => false; } - private class InheritScreen : OsuScreen + private partial class InheritScreen : OsuScreen { } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs index 9b84cf2a9e..837de60053 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBackButton.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneBackButton : OsuTestScene + public partial class TestSceneBackButton : OsuTestScene { public TestSceneBackButton() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs index 368babc9b5..5d97714ab5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs @@ -26,7 +26,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneBeatSyncedContainer : OsuTestScene + public partial class TestSceneBeatSyncedContainer : OsuTestScene { private TestBeatSyncedContainer beatContainer; @@ -171,7 +171,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("effect has kiai", () => actualEffectPoint != null && ((EffectControlPoint)actualEffectPoint).KiaiMode); } - private class TestBeatSyncedContainer : BeatSyncedContainer + private partial class TestBeatSyncedContainer : BeatSyncedContainer { private const int flash_layer_height = 150; @@ -321,7 +321,7 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class InfoString : FillFlowContainer + private partial class InfoString : FillFlowContainer { private const int text_size = 20; private const int margin = 7; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingCardSizeTabControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingCardSizeTabControl.cs index bc846d8bcb..f93c9a3d5d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingCardSizeTabControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingCardSizeTabControl.cs @@ -16,7 +16,7 @@ using osu.Game.Overlays.BeatmapListing; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneBeatmapListingCardSizeTabControl : OsuTestScene + public partial class TestSceneBeatmapListingCardSizeTabControl : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs index e8454e8d0f..0aae182db4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneBeatmapListingSearchControl : OsuTestScene + public partial class TestSceneBeatmapListingSearchControl : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSortTabControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSortTabControl.cs index 0ef13385ec..316035275f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSortTabControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSortTabControl.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneBeatmapListingSortTabControl : OsuTestScene + public partial class TestSceneBeatmapListingSortTabControl : OsuTestScene { private readonly BeatmapListingSortTabControl control; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapSearchFilter.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapSearchFilter.cs index ff1dce1a4e..7f7ba6966b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapSearchFilter.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapSearchFilter.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneBeatmapSearchFilter : OsuTestScene + public partial class TestSceneBeatmapSearchFilter : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs index a387148c2c..eeb2d1e70f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs @@ -14,7 +14,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneBreadcrumbControl : OsuTestScene + public partial class TestSceneBreadcrumbControl : OsuTestScene { private readonly TestBreadcrumbControl breadcrumbs; @@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.UserInterface Circles, } - private class TestBreadcrumbControl : BreadcrumbControl + private partial class TestBreadcrumbControl : BreadcrumbControl { public BreadcrumbTabItem GetDrawable(BreadcrumbTab tab) => (BreadcrumbTabItem)TabContainer.First(t => t.Value == tab); } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControlHeader.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControlHeader.cs index 8e2502dad1..cc203b3043 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControlHeader.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControlHeader.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneBreadcrumbControlHeader : OsuTestScene + public partial class TestSceneBreadcrumbControlHeader : OsuTestScene { private static readonly string[] items = { "first", "second", "third", "fourth", "fifth" }; @@ -48,7 +48,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep($"Remove {item} item", () => header.RemoveItem(item)); } - private class TestHeader : BreadcrumbControlOverlayHeader + private partial class TestHeader : BreadcrumbControlOverlayHeader { public TestHeader() { @@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual.UserInterface protected override OverlayTitle CreateTitle() => new TestTitle(); } - private class TestTitle : OverlayTitle + private partial class TestTitle : OverlayTitle { public TestTitle() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs index cbd4c69180..ac811aeb65 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonSystem.cs @@ -17,7 +17,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneButtonSystem : OsuManualInputManagerTestScene + public partial class TestSceneButtonSystem : OsuManualInputManagerTestScene { private OsuLogo logo; private ButtonSystem buttons; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs index eba0e8cfed..d2acf89dc8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneColourPicker : OsuTestScene + public partial class TestSceneColourPicker : OsuTestScene { private readonly Bindable colour = new Bindable(Colour4.Aquamarine); @@ -79,7 +79,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("set red", () => colour.Value = Colour4.Red); } - private class ColourProvidingContainer : Container + private partial class ColourProvidingContainer : Container { [Cached] private OverlayColourProvider provider { get; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs index fd4ec2f3dc..99e1702870 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs @@ -15,7 +15,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneCommentEditor : OsuManualInputManagerTestScene + public partial class TestSceneCommentEditor : OsuManualInputManagerTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); @@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("cancel action fired", () => cancellableCommentEditor.Cancelled); } - private class TestCommentEditor : CommentEditor + private partial class TestCommentEditor : CommentEditor { public new Bindable Current => base.Current; public new FillFlowContainer ButtonsContainer => base.ButtonsContainer; @@ -126,7 +126,7 @@ namespace osu.Game.Tests.Visual.UserInterface protected override string TextBoxPlaceholder => @"This text box is empty"; } - private class TestCancellableCommentEditor : CancellableCommentEditor + private partial class TestCancellableCommentEditor : CancellableCommentEditor { public new FillFlowContainer ButtonsContainer => base.ButtonsContainer; protected override string FooterText => @"Wow, another one. Sicc"; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentRepliesButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentRepliesButton.cs index 115833b034..1bfa389a25 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentRepliesButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentRepliesButton.cs @@ -16,7 +16,7 @@ using osu.Framework.Testing; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneCommentRepliesButton : OsuTestScene + public partial class TestSceneCommentRepliesButton : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("Icon facing downwards", () => button.Icon.Scale.Y == 1); } - private class TestButton : CommentRepliesButton + private partial class TestButton : CommentRepliesButton { public SpriteIcon Icon => this.ChildrenOfType().First(); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneContextMenu.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneContextMenu.cs index bd77c4725c..3491b7dbc1 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneContextMenu.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneContextMenu.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneContextMenu : OsuTestScene + public partial class TestSceneContextMenu : OsuTestScene { private const int start_time = 0; private const int duration = 1000; @@ -113,12 +113,12 @@ namespace osu.Game.Tests.Visual.UserInterface }; } - private class MyContextMenuContainer : Container, IHasContextMenu + private partial class MyContextMenuContainer : Container, IHasContextMenu { public MenuItem[] ContextMenuItems => makeMenu(); } - private class AnotherContextMenuContainer : Container, IHasContextMenu + private partial class AnotherContextMenuContainer : Container, IHasContextMenu { public MenuItem[] ContextMenuItems { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs index 75c47f0b1b..01d4eb83f3 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneCursors : OsuManualInputManagerTestScene + public partial class TestSceneCursors : OsuManualInputManagerTestScene { private readonly GlobalCursorDisplay globalCursorDisplay; private readonly CustomCursorBox[] cursorBoxes = new CustomCursorBox[6]; @@ -239,7 +239,7 @@ namespace osu.Game.Tests.Visual.UserInterface private bool checkAtMouse(CursorContainer cursorContainer) => Precision.AlmostEquals(InputManager.CurrentState.Mouse.Position, cursorContainer.ToScreenSpace(cursorContainer.ActiveCursor.DrawPosition)); - private class CustomCursorBox : Container, IProvideCursor + private partial class CustomCursorBox : Container, IProvideCursor { public bool SmoothTransition; @@ -290,11 +290,11 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class TestCursorContainer : CursorContainer + private partial class TestCursorContainer : CursorContainer { protected override Drawable CreateCursor() => new TestCursor(); - private class TestCursor : CircularContainer + private partial class TestCursor : CircularContainer { public TestCursor() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs index 2b6a93143f..6092f35050 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDashboardBeatmapListing.cs @@ -17,7 +17,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneDashboardBeatmapListing : OsuTestScene + public partial class TestSceneDashboardBeatmapListing : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index c1a9768cf0..7635c61867 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -32,7 +32,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneDeleteLocalScore : OsuManualInputManagerTestScene + public partial class TestSceneDeleteLocalScore : OsuManualInputManagerTestScene { private readonly ContextMenuContainer contextMenuContainer; private readonly BeatmapLeaderboard leaderboard; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs index a8e6142bab..81b692004b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDialogOverlay.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneDialogOverlay : OsuTestScene + public partial class TestSceneDialogOverlay : OsuTestScene { private DialogOverlay overlay; @@ -114,7 +114,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("dialog displayed", () => overlay.CurrentDialog == dialog); } - public class SlowLoadingDialogOverlay : DialogOverlay + public partial class SlowLoadingDialogOverlay : DialogOverlay { public ManualResetEventSlim LoadEvent = new ManualResetEventSlim(); @@ -166,7 +166,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("dialog is not part of hierarchy", () => testDialog.Parent == null); } - private class TestPopupDialog : PopupDialog + private partial class TestPopupDialog : PopupDialog { } } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDifficultyMultiplierDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDifficultyMultiplierDisplay.cs index 984276b27e..890c7295b4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDifficultyMultiplierDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDifficultyMultiplierDisplay.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Mods; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneDifficultyMultiplierDisplay : OsuTestScene + public partial class TestSceneDifficultyMultiplierDisplay : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDrawableDate.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDrawableDate.cs index 59e85ae085..108ad8b7c1 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDrawableDate.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDrawableDate.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneDrawableDate : OsuTestScene + public partial class TestSceneDrawableDate : OsuTestScene { public TestSceneDrawableDate() { @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.UserInterface }; } - private class PokeyDrawableDate : CompositeDrawable + private partial class PokeyDrawableDate : CompositeDrawable { public PokeyDrawableDate(DateTimeOffset date) { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneEditorSidebar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneEditorSidebar.cs index ee07acef52..72dacb7558 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneEditorSidebar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneEditorSidebar.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneEditorSidebar : OsuTestScene + public partial class TestSceneEditorSidebar : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingBar.cs index 2d97513206..9d850c0fc5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingBar.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneExpandingBar : OsuTestScene + public partial class TestSceneExpandingBar : OsuTestScene { public TestSceneExpandingBar() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs index 704185b117..3f4f86e424 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneExpandingContainer.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneExpandingContainer : OsuManualInputManagerTestScene + public partial class TestSceneExpandingContainer : OsuManualInputManagerTestScene { private TestExpandingContainer container; private SettingsToolboxGroup toolboxGroup; @@ -149,7 +149,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("container still expanded", () => container.Expanded.Value); } - private class TestExpandingContainer : ExpandingContainer + private partial class TestExpandingContainer : ExpandingContainer { public TestExpandingContainer() : base(120, 250) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFPSCounter.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFPSCounter.cs index d78707045b..a91e6e3350 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFPSCounter.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFPSCounter.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneFPSCounter : OsuTestScene + public partial class TestSceneFPSCounter : OsuTestScene { [SetUpSteps] public void SetUpSteps() diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenBehaviour.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenBehaviour.cs index 8fa4f7ec0e..ec8ef0ad50 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenBehaviour.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenBehaviour.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays.FirstRunSetup; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneFirstRunScreenBehaviour : OsuManualInputManagerTestScene + public partial class TestSceneFirstRunScreenBehaviour : OsuManualInputManagerTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenBundledBeatmaps.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenBundledBeatmaps.cs index 6cc4ac709b..e9460e45d3 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenBundledBeatmaps.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenBundledBeatmaps.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays.FirstRunSetup; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneFirstRunScreenBundledBeatmaps : OsuManualInputManagerTestScene + public partial class TestSceneFirstRunScreenBundledBeatmaps : OsuManualInputManagerTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenImportFromStable.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenImportFromStable.cs index 3c3d5933e4..e6fc889a70 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenImportFromStable.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenImportFromStable.cs @@ -17,7 +17,7 @@ using osu.Game.Overlays.FirstRunSetup; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneFirstRunScreenImportFromStable : OsuManualInputManagerTestScene + public partial class TestSceneFirstRunScreenImportFromStable : OsuManualInputManagerTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenUIScale.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenUIScale.cs index 98ad77fbae..8ba94cf9ae 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenUIScale.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenUIScale.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays.FirstRunSetup; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneFirstRunScreenUIScale : OsuManualInputManagerTestScene + public partial class TestSceneFirstRunScreenUIScale : OsuManualInputManagerTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index 16d564f0ee..77ed97e3ed 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -25,7 +25,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneFirstRunSetupOverlay : OsuManualInputManagerTestScene + public partial class TestSceneFirstRunSetupOverlay : OsuManualInputManagerTestScene { private FirstRunSetupOverlay overlay; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs index a4b5faae26..24b4060a42 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs @@ -14,7 +14,7 @@ using osu.Game.Screens.Select; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneFooterButtonMods : OsuTestScene + public partial class TestSceneFooterButtonMods : OsuTestScene { private readonly TestFooterButtonMods footerButtonMods; @@ -81,7 +81,7 @@ namespace osu.Game.Tests.Visual.UserInterface return expectedValue == footerButtonMods.MultiplierText.Current.Value; } - private class TestFooterButtonMods : FooterButtonMods + private partial class TestFooterButtonMods : FooterButtonMods { public new OsuSpriteText MultiplierText => base.MultiplierText; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs index ad5e498c8b..c75c2a7877 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays.Dashboard.Friends; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneFriendsOnlineStatusControl : OsuTestScene + public partial class TestSceneFriendsOnlineStatusControl : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs index 8ed5dd43cc..ed59572cab 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHistoryTextBox.cs @@ -11,7 +11,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneHistoryTextBox : OsuManualInputManagerTestScene + public partial class TestSceneHistoryTextBox : OsuManualInputManagerTestScene { private const string temp = "Temp message"; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneHoldToConfirmOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneHoldToConfirmOverlay.cs index 235dbc1fcb..801bef62c8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneHoldToConfirmOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneHoldToConfirmOverlay.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Menu; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneHoldToConfirmOverlay : OsuTestScene + public partial class TestSceneHoldToConfirmOverlay : OsuTestScene { protected override double TimePerAction => 100; // required for the early exit test, since hold-to-confirm delay is 200ms @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait until fired again", () => overlay.Fired); } - private class TestHoldToConfirmOverlay : ExitConfirmOverlay + private partial class TestHoldToConfirmOverlay : ExitConfirmOverlay { public void Begin() => BeginConfirm(); } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs index 35d250c7ac..454fa7cd05 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneIconButton.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneIconButton : OsuTestScene + public partial class TestSceneIconButton : OsuTestScene { public TestSceneIconButton() { @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.UserInterface }; } - private class ColouredIconButton : IconButton + private partial class ColouredIconButton : IconButton { public ColouredIconButton() { @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class NamedIconButton : Container + private partial class NamedIconButton : Container { public NamedIconButton(string name, IconButton button) { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs index d7a69616f3..91a60009dc 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneLabelledColourPalette : OsuManualInputManagerTestScene + public partial class TestSceneLabelledColourPalette : OsuManualInputManagerTestScene { private LabelledColourPalette component; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs index 7ce0fceff9..0dffc9da51 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDrawable.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneLabelledDrawable : OsuTestScene + public partial class TestSceneLabelledDrawable : OsuTestScene { [TestCase(false)] [TestCase(true)] @@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert($"description {(hasDescription ? "visible" : "hidden")}", () => component.ChildrenOfType().ElementAt(1).IsPresent == hasDescription); } - private class PaddedLabelledDrawable : LabelledDrawable + private partial class PaddedLabelledDrawable : LabelledDrawable { public PaddedLabelledDrawable() : base(true) @@ -104,7 +104,7 @@ namespace osu.Game.Tests.Visual.UserInterface }; } - private class NonPaddedLabelledDrawable : LabelledDrawable + private partial class NonPaddedLabelledDrawable : LabelledDrawable { public NonPaddedLabelledDrawable() : base(false) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs index cd14d6bde3..a2cfae3c7f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneLabelledDropdown : OsuTestScene + public partial class TestSceneLabelledDropdown : OsuTestScene { [Test] public void TestLabelledDropdown() diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs index 5548375af2..6181891e13 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSliderBar.cs @@ -17,7 +17,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneLabelledSliderBar : OsuTestScene + public partial class TestSceneLabelledSliderBar : OsuTestScene { [Test] public void TestBasic() => createSliderBar(); @@ -101,7 +101,7 @@ namespace osu.Game.Tests.Visual.UserInterface }); } - private class OverlayColourContainer : Container + private partial class OverlayColourContainer : Container { [Cached] private OverlayColourProvider colourProvider; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs index 03434ff0a1..c4af47bd0f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledSwitchButton.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneLabelledSwitchButton : OsuTestScene + public partial class TestSceneLabelledSwitchButton : OsuTestScene { [TestCase(false)] [TestCase(true)] diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs index 3f93e60773..8046554819 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledTextBox.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneLabelledTextBox : OsuTestScene + public partial class TestSceneLabelledTextBox : OsuTestScene { [TestCase(false)] [TestCase(true)] diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs index 2fc6405b88..cc5304a961 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneLoadingLayer : OsuTestScene + public partial class TestSceneLoadingLayer : OsuTestScene { private TestLoadingLayer overlay; @@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("hide", () => overlay.Hide()); } - private class TestLoadingLayer : LoadingLayer + private partial class TestLoadingLayer : LoadingLayer { public new Box BackgroundDimLayer => base.BackgroundDimLayer; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingSpinner.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingSpinner.cs index 8c9b9186b1..40e786592a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingSpinner.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingSpinner.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneLoadingSpinner : OsuGridTestScene + public partial class TestSceneLoadingSpinner : OsuGridTestScene { public TestSceneLoadingSpinner() : base(2, 2) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLogoAnimation.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLogoAnimation.cs index b565cb359b..f9d92aabc6 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLogoAnimation.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLogoAnimation.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneLogoAnimation : OsuTestScene + public partial class TestSceneLogoAnimation : OsuTestScene { [BackgroundDependencyLoader] private void load(LargeTextureStore textures) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs index d069e742dd..5926f07a11 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneLogoTrackingContainer : OsuTestScene + public partial class TestSceneLogoTrackingContainer : OsuTestScene { private OsuLogo logo; private TestLogoTrackingContainer trackingContainer; @@ -277,7 +277,7 @@ namespace osu.Game.Tests.Visual.UserInterface Schedule(moveLogoFacade); } - private class TestLogoTrackingContainer : LogoTrackingContainer + private partial class TestLogoTrackingContainer : LogoTrackingContainer { /// /// Check that the logo is tracking the position of the facade, with an acceptable precision lenience. diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs index 72cddc0ad2..a11000214c 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModColumn.cs @@ -22,7 +22,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneModColumn : OsuManualInputManagerTestScene + public partial class TestSceneModColumn : OsuManualInputManagerTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); @@ -294,7 +294,7 @@ namespace osu.Game.Tests.Visual.UserInterface modState.Filtered.Value = filter?.Invoke(modState.Mod) == false; } - private class TestModColumn : ModColumn + private partial class TestModColumn : ModColumn { public new bool SelectionAnimationRunning => base.SelectionAnimationRunning; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs index 181f46a996..0d02a72d87 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneModDifficultyAdjustSettings : OsuManualInputManagerTestScene + public partial class TestSceneModDifficultyAdjustSettings : OsuManualInputManagerTestScene { private OsuModDifficultyAdjust modDifficultyAdjust; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs index c65d1f8c5e..bd5a0d8645 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneModDisplay : OsuTestScene + public partial class TestSceneModDisplay : OsuTestScene { [Test] public void TestMode([Values] ExpansionMode mode) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModFlowDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModFlowDisplay.cs index c45ea3a40c..f0efabe2f7 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModFlowDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModFlowDisplay.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneModFlowDisplay : OsuTestScene + public partial class TestSceneModFlowDisplay : OsuTestScene { private ModFlowDisplay modFlow; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModIcon.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModIcon.cs index ce9aa682d1..897d5fd9f5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModIcon.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModIcon.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneModIcon : OsuTestScene + public partial class TestSceneModIcon : OsuTestScene { [Test] public void TestShowAllMods() diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPanel.cs index 9c0b36073b..64bdc167c2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPanel.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPanel.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneModPanel : OsuManualInputManagerTestScene + public partial class TestSceneModPanel : OsuManualInputManagerTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index 901f234db6..1090764788 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -25,7 +25,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneModPresetColumn : OsuManualInputManagerTestScene + public partial class TestSceneModPresetColumn : OsuManualInputManagerTestScene { protected override bool UseFreshStoragePerRun => true; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs index bcd5579f03..35e352534b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetPanel.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneModPresetPanel : OsuTestScene + public partial class TestSceneModPresetPanel : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 0292ce5905..eff320a575 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -28,7 +28,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneModSelectOverlay : OsuManualInputManagerTestScene + public partial class TestSceneModSelectOverlay : OsuManualInputManagerTestScene { protected override bool UseFreshStoragePerRun => true; @@ -584,7 +584,7 @@ namespace osu.Game.Tests.Visual.UserInterface private ModPanel getPanelForMod(Type modType) => modSelectOverlay.ChildrenOfType().Single(panel => panel.Mod.GetType() == modType); - private class TestModSelectOverlay : UserModSelectOverlay + private partial class TestModSelectOverlay : UserModSelectOverlay { protected override bool ShowPresets => true; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettingsArea.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettingsArea.cs index a9c3872643..dac1f94c28 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettingsArea.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettingsArea.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneModSettingsArea : OsuTestScene + public partial class TestSceneModSettingsArea : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchSmall.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchSmall.cs index ff9cc09806..07312379b3 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchSmall.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchSmall.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneModSwitchSmall : OsuTestScene + public partial class TestSceneModSwitchSmall : OsuTestScene { [Test] public void TestOsu() => createSwitchTestFor(new OsuRuleset()); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchTiny.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchTiny.cs index ddb5845df8..34dd139428 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchTiny.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSwitchTiny.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneModSwitchTiny : OsuTestScene + public partial class TestSceneModSwitchTiny : OsuTestScene { [Test] public void TestOsu() => createSwitchTestFor(new OsuRuleset()); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs index 42eceb3242..a1c8bef1de 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModsEffectDisplay.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneModsEffectDisplay : OsuTestScene + public partial class TestSceneModsEffectDisplay : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); @@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("colours are correct", () => testDisplay.Container.Colour == colourProvider.Background5 && background.Colour == colours.ForModType(ModType.DifficultyIncrease)); } - private class TestDisplay : ModsEffectDisplay + private partial class TestDisplay : ModsEffectDisplay { public Container Container => Content; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs index 7ed08d8dff..3cd5daf7a1 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneNotificationOverlay : OsuManualInputManagerTestScene + public partial class TestSceneNotificationOverlay : OsuManualInputManagerTestScene { private NotificationOverlay notificationOverlay = null!; @@ -617,12 +617,12 @@ namespace osu.Game.Tests.Visual.UserInterface notificationOverlay.Post(new SimpleNotification { Text = @"Spam incoming!!" }); } - private class BackgroundNotification : SimpleNotification + private partial class BackgroundNotification : SimpleNotification { public override bool IsImportant => false; } - private class BackgroundProgressNotification : ProgressNotification + private partial class BackgroundProgressNotification : ProgressNotification { public override bool IsImportant => false; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs index f7f35b8361..d07b90025f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Osu; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneNowPlayingOverlay : OsuTestScene + public partial class TestSceneNowPlayingOverlay : OsuTestScene { [Cached] private MusicController musicController = new MusicController(); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOnScreenDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOnScreenDisplay.cs index 2d8d7a5de3..f2123061e5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOnScreenDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOnScreenDisplay.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays.OSD; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneOnScreenDisplay : OsuTestScene + public partial class TestSceneOnScreenDisplay : OsuTestScene { [BackgroundDependencyLoader] private void load() @@ -95,7 +95,7 @@ namespace osu.Game.Tests.Visual.UserInterface Setting4 } - private class EmptyToast : Toast + private partial class EmptyToast : Toast { public EmptyToast() : base("", "", "") @@ -103,7 +103,7 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class LengthyToast : Toast + private partial class LengthyToast : Toast { public LengthyToast() : base("Toast with a very very very long text", "A very very very very very very long text also", "A very very very very very long shortcut") @@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class TestOnScreenDisplay : OnScreenDisplay + private partial class TestOnScreenDisplay : OnScreenDisplay { protected override void DisplayTemporarily(Drawable toDisplay) => toDisplay.FadeIn().ResizeHeightTo(110); } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs index bab2121d70..eba3885a2b 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuAnimatedButton.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOsuAnimatedButton : OsuTestScene + public partial class TestSceneOsuAnimatedButton : OsuTestScene { [Test] public void TestRelativeSized() @@ -104,7 +104,7 @@ namespace osu.Game.Tests.Visual.UserInterface }); } - public class BaseContainer : OsuAnimatedButton + public partial class BaseContainer : OsuAnimatedButton { public BaseContainer(string text) { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs index d4c2bfd422..41e5d47093 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOsuButton : OsuTestScene + public partial class TestSceneOsuButton : OsuTestScene { [Test] public void TestToggleEnabled() diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuDropdown.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuDropdown.cs index 2cda95bda4..770b9dece1 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuDropdown.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuDropdown.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOsuDropdown : ThemeComparisonTestScene + public partial class TestSceneOsuDropdown : ThemeComparisonTestScene { protected override Drawable CreateContent() => new OsuEnumDropdown diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuFont.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuFont.cs index f534fc0fac..7b3f97a16e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuFont.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuFont.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOsuFont : OsuTestScene + public partial class TestSceneOsuFont : OsuTestScene { private OsuSpriteText spriteText; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuHoverContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuHoverContainer.cs index d4b15c06c5..ab5a70f448 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuHoverContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuHoverContainer.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneOsuHoverContainer : OsuManualInputManagerTestScene + public partial class TestSceneOsuHoverContainer : OsuManualInputManagerTestScene { private OsuHoverTestContainer hoverContainer; private Box colourContainer; @@ -181,7 +181,7 @@ namespace osu.Game.Tests.Visual.UserInterface private void doMoveOut() => InputManager.MoveMouseTo(new Vector2(InputManager.ScreenSpaceDrawQuad.TopLeft.X, InputManager.ScreenSpaceDrawQuad.TopLeft.Y)); - private sealed class OsuHoverTestContainer : OsuHoverContainer + private sealed partial class OsuHoverTestContainer : OsuHoverContainer { public static readonly Color4 HOVER_COLOUR = Color4.Red; public static readonly Color4 IDLE_COLOUR = Color4.Green; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs index 1e1c3b3282..a1254678b7 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuIcon.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneOsuIcon : OsuTestScene + public partial class TestSceneOsuIcon : OsuTestScene { public TestSceneOsuIcon() { @@ -60,7 +60,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("change icons", () => flow.Children.ForEach(i => i.SpriteIcon.Icon = new IconUsage((char)(i.SpriteIcon.Icon.Icon + 1)))); } - private class Icon : Container, IHasTooltip + private partial class Icon : Container, IHasTooltip { public LocalisableString TooltipText { get; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuLogo.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuLogo.cs index e23a960a7e..24a27f71e8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuLogo.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuLogo.cs @@ -9,7 +9,7 @@ using osu.Game.Screens.Menu; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOsuLogo : OsuTestScene + public partial class TestSceneOsuLogo : OsuTestScene { [Test] public void TestBasic() diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuMarkdownContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuMarkdownContainer.cs index cdccb817b9..1e2485c6e2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuMarkdownContainer.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOsuMarkdownContainer : OsuTestScene + public partial class TestSceneOsuMarkdownContainer : OsuTestScene { private OsuMarkdownContainer markdownContainer; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuMenu.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuMenu.cs index 5349a1b8a0..addaab5d35 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuMenu.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuMenu.cs @@ -12,7 +12,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOsuMenu : OsuManualInputManagerTestScene + public partial class TestSceneOsuMenu : OsuManualInputManagerTestScene { private OsuMenu menu; private bool actionPerformed; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuPopover.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuPopover.cs index 6cc89a6df8..ca26c26b0a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuPopover.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuPopover.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOsuPopover : OsuGridTestScene + public partial class TestSceneOsuPopover : OsuGridTestScene { public TestSceneOsuPopover() : base(1, 2) @@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.UserInterface }; } - private class TriangleButtonWithPopover : TriangleButton, IHasPopover + private partial class TriangleButtonWithPopover : TriangleButton, IHasPopover { public TriangleButtonWithPopover() { @@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.UserInterface }; } - private class ColourProvidingContainer : Container + private partial class ColourProvidingContainer : Container { [Cached] private OverlayColourProvider provider { get; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuTextBox.cs index cc510f007b..929537e675 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuTextBox.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOsuTextBox : ThemeComparisonTestScene + public partial class TestSceneOsuTextBox : ThemeComparisonTestScene { private IEnumerable numberBoxes => this.ChildrenOfType(); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs index a5493559d6..8f10065d17 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOverlayHeader : OsuTestScene + public partial class TestSceneOverlayHeader : OsuTestScene { private readonly FillFlowContainer flow; @@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.UserInterface }); } - private class ColourProvidedContainer : Container + private partial class ColourProvidedContainer : Container { [Cached] private readonly OverlayColourProvider colourProvider; @@ -85,7 +85,7 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class TestNoBackgroundHeader : OverlayHeader + private partial class TestNoBackgroundHeader : OverlayHeader { protected override OverlayTitle CreateTitle() => new TestTitle(); @@ -95,14 +95,14 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class TestNoControlHeader : OverlayHeader + private partial class TestNoControlHeader : OverlayHeader { protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/changelog"); protected override OverlayTitle CreateTitle() => new TestTitle(); } - private class TestStringTabControlHeader : TabControlOverlayHeader + private partial class TestStringTabControlHeader : TabControlOverlayHeader { protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/news"); @@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class TestEnumTabControlHeader : TabControlOverlayHeader + private partial class TestEnumTabControlHeader : TabControlOverlayHeader { public TestEnumTabControlHeader() { @@ -136,7 +136,7 @@ namespace osu.Game.Tests.Visual.UserInterface Tabs } - private class TestBreadcrumbControlHeader : BreadcrumbControlOverlayHeader + private partial class TestBreadcrumbControlHeader : BreadcrumbControlOverlayHeader { protected override OverlayTitle CreateTitle() => new TestTitle(); @@ -150,7 +150,7 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class TestTitle : OverlayTitle + private partial class TestTitle : OverlayTitle { public TestTitle() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeaderBackground.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeaderBackground.cs index 11507e561f..7a445427f5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeaderBackground.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeaderBackground.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOverlayHeaderBackground : OsuTestScene + public partial class TestSceneOverlayHeaderBackground : OsuTestScene { public TestSceneOverlayHeaderBackground() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs index 5a1ce9e791..432e448038 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs @@ -18,7 +18,7 @@ using osu.Framework.Allocation; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOverlayRulesetSelector : OsuTestScene + public partial class TestSceneOverlayRulesetSelector : OsuTestScene { private readonly OverlayRulesetSelector selector; private readonly Bindable ruleset = new Bindable(); @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.UserInterface }); } - private class ColourProvidedContainer : Container + private partial class ColourProvidedContainer : Container { [Cached] private readonly OverlayColourProvider colourProvider; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs index 7b3e82ff6d..926bc01aea 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayScrollContainer.cs @@ -15,7 +15,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneOverlayScrollContainer : OsuManualInputManagerTestScene + public partial class TestSceneOverlayScrollContainer : OsuManualInputManagerTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); @@ -100,7 +100,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("invocation count is 1", () => invocationCount == 1); } - private class TestScrollContainer : OverlayScrollContainer + private partial class TestScrollContainer : OverlayScrollContainer { public new ScrollToTopButton Button => base.Button; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePageSelector.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePageSelector.cs index 1907a56735..b9e3592389 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePageSelector.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePageSelector.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { - public class TestScenePageSelector : OsuTestScene + public partial class TestScenePageSelector : OsuTestScene { [Cached] private OverlayColourProvider provider { get; } = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneParallaxContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneParallaxContainer.cs index 6ab69f32ef..92d4981d4a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneParallaxContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneParallaxContainer.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Backgrounds; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneParallaxContainer : OsuTestScene + public partial class TestSceneParallaxContainer : OsuTestScene { public TestSceneParallaxContainer() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index d87bcfa5dd..c723988d6a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestScenePlaylistOverlay : OsuManualInputManagerTestScene + public partial class TestScenePlaylistOverlay : OsuManualInputManagerTestScene { protected override bool UseFreshStoragePerRun => true; diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs index 218677fd03..9537ab63be 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePopupDialog.cs @@ -13,7 +13,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestScenePopupDialog : OsuManualInputManagerTestScene + public partial class TestScenePopupDialog : OsuManualInputManagerTestScene { private TestPopupDialog dialog; @@ -52,7 +52,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("release button", () => InputManager.ReleaseButton(MouseButton.Left)); } - private class TestPopupDialog : PopupDialog + private partial class TestPopupDialog : PopupDialog { public PopupDialogDangerousButton DangerousButton { get; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.cs index 9738ff33c3..b4b45da133 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneProfileSubsectionHeader.cs @@ -13,7 +13,7 @@ using osu.Framework.Allocation; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneProfileSubsectionHeader : OsuTestScene + public partial class TestSceneProfileSubsectionHeader : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRankingsSortTabControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRankingsSortTabControl.cs index a95ae190dd..f364a48616 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneRankingsSortTabControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRankingsSortTabControl.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays.Rankings; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneRankingsSortTabControl : OsuTestScene + public partial class TestSceneRankingsSortTabControl : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs index 2587960275..1dc9845916 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRoundedButton.cs @@ -16,7 +16,7 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneRoundedButton : ThemeComparisonTestScene + public partial class TestSceneRoundedButton : ThemeComparisonTestScene { private readonly BindableBool enabled = new BindableBool(true); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSafeAreaHandling.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSafeAreaHandling.cs index 90365ec939..453cdd1357 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSafeAreaHandling.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSafeAreaHandling.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneSafeAreaHandling : OsuGameTestScene + public partial class TestSceneSafeAreaHandling : OsuGameTestScene { private SafeAreaDefiningContainer safeAreaContainer; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScalingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScalingContainer.cs index 67c47492b0..26fa26a0b8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneScalingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScalingContainer.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneScalingContainer : OsuTestScene + public partial class TestSceneScalingContainer : OsuTestScene { private OsuConfigManager osuConfigManager { get; set; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs index b3ee0af78b..e0ae23e1c8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneScreenBreadcrumbControl : OsuTestScene + public partial class TestSceneScreenBreadcrumbControl : OsuTestScene { private readonly ScreenBreadcrumbControl breadcrumbs; private readonly OsuScreenStack screenStack; @@ -79,7 +79,7 @@ namespace osu.Game.Tests.Visual.UserInterface private void pushNext() => AddStep(@"push next screen", () => ((TestScreen)screenStack.CurrentScreen).PushNext()); private void waitForCurrent() => AddUntilStep("current screen", () => screenStack.CurrentScreen.IsCurrentScreen()); - private abstract class TestScreen : OsuScreen + private abstract partial class TestScreen : OsuScreen { protected abstract string NextTitle { get; } protected abstract TestScreen CreateNextScreen(); @@ -122,14 +122,14 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class TestScreenOne : TestScreen + private partial class TestScreenOne : TestScreen { public override string Title => @"Screen One"; protected override string NextTitle => @"Two"; protected override TestScreen CreateNextScreen() => new TestScreenTwo(); } - private class TestScreenTwo : TestScreen + private partial class TestScreenTwo : TestScreen { public override string Title => @"Screen Two"; protected override string NextTitle => @"One"; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSectionsContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSectionsContainer.cs index f71d797363..05fffc903d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSectionsContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSectionsContainer.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneSectionsContainer : OsuManualInputManagerTestScene + public partial class TestSceneSectionsContainer : OsuManualInputManagerTestScene { private SectionsContainer container; private float custom; @@ -196,7 +196,7 @@ namespace osu.Game.Tests.Visual.UserInterface InputManager.ScrollVerticalBy(direction); } - private class TestSection : TestBox + private partial class TestSection : TestBox { public bool Selected { @@ -210,7 +210,7 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class TestBox : Container + private partial class TestBox : Container { private readonly Box background; private readonly OsuSpriteText text; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsCheckbox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsCheckbox.cs index 466c83b1ac..a0fe5fce32 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsCheckbox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsCheckbox.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneSettingsCheckbox : OsuTestScene + public partial class TestSceneSettingsCheckbox : OsuTestScene { [TestCase] public void TestCheckbox() @@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.UserInterface }); } - private class OverlayColourContainer : Container + private partial class OverlayColourContainer : Container { [Cached] private OverlayColourProvider colourProvider; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs index 9fb0905a4f..71b98ed9af 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsToolboxGroup.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneSettingsToolboxGroup : OsuManualInputManagerTestScene + public partial class TestSceneSettingsToolboxGroup : OsuManualInputManagerTestScene { private SettingsToolboxGroup group; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs index 6c485aff34..118d32ee70 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedButtons.cs @@ -17,7 +17,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneShearedButtons : OsuManualInputManagerTestScene + public partial class TestSceneShearedButtons : OsuManualInputManagerTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayContainer.cs index c0fb315e03..fb06760568 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayContainer.cs @@ -22,7 +22,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneShearedOverlayContainer : OsuManualInputManagerTestScene + public partial class TestSceneShearedOverlayContainer : OsuManualInputManagerTestScene { private TestShearedOverlayContainer overlay; @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("overlay dismissed", () => overlay.State.Value == Visibility.Hidden); } - public class TestShearedOverlayContainer : ShearedOverlayContainer + public partial class TestShearedOverlayContainer : ShearedOverlayContainer { public TestShearedOverlayContainer() : base(OverlayColourScheme.Green) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayHeader.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayHeader.cs index 09292ee92b..aeea0681eb 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayHeader.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedOverlayHeader.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneShearedOverlayHeader : OsuTestScene + public partial class TestSceneShearedOverlayHeader : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSearchTextBox.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSearchTextBox.cs index 78e06f7e32..0072864335 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSearchTextBox.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneShearedSearchTextBox.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneShearedSearchTextBox : OsuTestScene + public partial class TestSceneShearedSearchTextBox : OsuTestScene { [Test] public void TestAllColourSchemes() diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingSpriteText.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingSpriteText.cs index c4568d9aeb..7339ea7b23 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingSpriteText.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSizePreservingSpriteText.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneSizePreservingSpriteText : OsuGridTestScene + public partial class TestSceneSizePreservingSpriteText : OsuGridTestScene { private readonly List parentContainers = new List(); private readonly List childContainers = new List(); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs index 72929a4555..6988bac2ee 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneStarRatingDisplay : OsuTestScene + public partial class TestSceneStarRatingDisplay : OsuTestScene { [TestCase(StarRatingDisplaySize.Regular)] [TestCase(StarRatingDisplaySize.Small)] diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs index 11acb31fef..88187f1808 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStatefulMenuItem.cs @@ -13,7 +13,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneStatefulMenuItem : OsuManualInputManagerTestScene + public partial class TestSceneStatefulMenuItem : OsuManualInputManagerTestScene { [Test] public void TestTernaryRadioMenuItem() diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs index 4d90a11405..f3ab5dbff8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSwitchButton.cs @@ -11,7 +11,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneSwitchButton : OsuManualInputManagerTestScene + public partial class TestSceneSwitchButton : OsuManualInputManagerTestScene { private SwitchButton switchButton; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneTabControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneTabControl.cs index b868abcc45..24c4ed79b1 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneTabControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneTabControl.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { [Description("SongSelect filter control")] - public class TestSceneTabControl : OsuTestScene + public partial class TestSceneTabControl : OsuTestScene { public TestSceneTabControl() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs index 92cfeef369..41a6f35624 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneToggleMenuItem.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneToggleMenuItem : OsuTestScene + public partial class TestSceneToggleMenuItem : OsuTestScene { public TestSceneToggleMenuItem() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs index de67b85c7d..651c5376b5 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneToolbarRulesetSelector : OsuTestScene + public partial class TestSceneToolbarRulesetSelector : OsuTestScene { [Resolved] private RulesetStore rulesets { get; set; } @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("mode line has moved", () => selector.ModeButtonLine.DrawPosition.X > 0); } - private class TestSelector : ToolbarRulesetSelector + private partial class TestSelector : ToolbarRulesetSelector { public new Drawable ModeButtonLine => base.ModeButtonLine; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs index a11efb69bd..20b0ab5801 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneTwoLayerButton.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneTwoLayerButton : OsuTestScene + public partial class TestSceneTwoLayerButton : OsuTestScene { public TestSceneTwoLayerButton() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs index 32f47d77e1..48fe517f8a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapBackgroundSprite.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneUpdateableBeatmapBackgroundSprite : OsuTestScene + public partial class TestSceneUpdateableBeatmapBackgroundSprite : OsuTestScene { protected override bool UseOnlineAPI => true; @@ -138,7 +138,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("all unloaded", () => !loadedBackgrounds.Any()); } - private class TestUpdateableBeatmapBackgroundSprite : UpdateableBeatmapBackgroundSprite + private partial class TestUpdateableBeatmapBackgroundSprite : UpdateableBeatmapBackgroundSprite { protected override double UnloadDelay => 2000; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs index 8176871481..a1a546d4a7 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUpdateableBeatmapSetCover.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneUpdateableBeatmapSetCover : OsuTestScene + public partial class TestSceneUpdateableBeatmapSetCover : OsuTestScene { [Test] public void TestLocal([Values] BeatmapSetCoverType coverType) @@ -139,7 +139,7 @@ namespace osu.Game.Tests.Visual.UserInterface Covers = new BeatmapSetOnlineCovers { Cover = coverUrl } }; - private class TestUpdateableOnlineBeatmapSetCover : UpdateableOnlineBeatmapSetCover + private partial class TestUpdateableOnlineBeatmapSetCover : UpdateableOnlineBeatmapSetCover { private readonly int loadDelay; @@ -163,7 +163,7 @@ namespace osu.Game.Tests.Visual.UserInterface } } - private class TestOnlineBeatmapSetCover : OnlineBeatmapSetCover + private partial class TestOnlineBeatmapSetCover : OnlineBeatmapSetCover { private readonly int loadDelay; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs index 67c26829df..15570b7927 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUprightAspectMaintainingContainer.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneUprightAspectMaintainingContainer : OsuGridTestScene + public partial class TestSceneUprightAspectMaintainingContainer : OsuGridTestScene { private const int rows = 3; private const int columns = 4; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs index 5e2e2ccff6..8737f7312e 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneUserListToolbar : OsuTestScene + public partial class TestSceneUserListToolbar : OsuTestScene { [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneVolumeOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneVolumeOverlay.cs index b5b4542eac..52543c68ce 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneVolumeOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneVolumeOverlay.cs @@ -9,7 +9,7 @@ using osu.Game.Overlays.Volume; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneVolumeOverlay : OsuTestScene + public partial class TestSceneVolumeOverlay : OsuTestScene { private VolumeOverlay volume; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneVolumePieces.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneVolumePieces.cs index 9ce71a5347..7cedef96e3 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneVolumePieces.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneVolumePieces.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneVolumePieces : OsuTestScene + public partial class TestSceneVolumePieces : OsuTestScene { protected override void LoadComplete() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs index 6a4934cf47..7851571b36 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneWaveContainer.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.UserInterface { [TestFixture] - public class TestSceneWaveContainer : OsuTestScene + public partial class TestSceneWaveContainer : OsuTestScene { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs b/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs index 8fb0fd84a1..05ffd1fbef 100644 --- a/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs +++ b/osu.Game.Tests/Visual/UserInterface/ThemeComparisonTestScene.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Tests.Visual.UserInterface { - public abstract class ThemeComparisonTestScene : OsuGridTestScene + public abstract partial class ThemeComparisonTestScene : OsuGridTestScene { protected ThemeComparisonTestScene() : base(1, 2) diff --git a/osu.Game.Tournament.Tests/Components/TestSceneDateTextBox.cs b/osu.Game.Tournament.Tests/Components/TestSceneDateTextBox.cs index 0e6e8f54bd..f547acd635 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneDateTextBox.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneDateTextBox.cs @@ -11,7 +11,7 @@ using osuTK.Input; namespace osu.Game.Tournament.Tests.Components { - public class TestSceneDateTextBox : OsuManualInputManagerTestScene + public partial class TestSceneDateTextBox : OsuManualInputManagerTestScene { private DateTextBox textBox; diff --git a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentMatch.cs b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentMatch.cs index 66093b80a1..cb923a1f9a 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentMatch.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentMatch.cs @@ -10,7 +10,7 @@ using osu.Game.Tournament.Screens.Ladder.Components; namespace osu.Game.Tournament.Tests.Components { - public class TestSceneDrawableTournamentMatch : TournamentTestScene + public partial class TestSceneDrawableTournamentMatch : TournamentTestScene { public TestSceneDrawableTournamentMatch() { diff --git a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs index 4ea7e8008a..dd7c613c6c 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneDrawableTournamentTeam.cs @@ -14,7 +14,7 @@ using osu.Game.Tournament.Screens.Ladder.Components; namespace osu.Game.Tournament.Tests.Components { - public class TestSceneDrawableTournamentTeam : OsuGridTestScene + public partial class TestSceneDrawableTournamentTeam : OsuGridTestScene { public TestSceneDrawableTournamentTeam() : base(4, 3) diff --git a/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs b/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs index 55d58fef6e..2347c84ba8 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Tournament.Tests.Components { - public class TestSceneMatchHeader : TournamentTestScene + public partial class TestSceneMatchHeader : TournamentTestScene { public TestSceneMatchHeader() { diff --git a/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs index 53301c34d4..9b1fc17591 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs @@ -11,7 +11,7 @@ using osu.Game.Tournament.Screens.Gameplay.Components; namespace osu.Game.Tournament.Tests.Components { - public class TestSceneMatchScoreDisplay : TournamentTestScene + public partial class TestSceneMatchScoreDisplay : TournamentTestScene { [Cached(Type = typeof(MatchIPCInfo))] private MatchIPCInfo matchInfo = new MatchIPCInfo(); diff --git a/osu.Game.Tournament.Tests/Components/TestSceneRoundDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneRoundDisplay.cs index 514a797068..cb22e7e7c7 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneRoundDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneRoundDisplay.cs @@ -9,7 +9,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Tests.Components { - public class TestSceneRoundDisplay : TournamentTestScene + public partial class TestSceneRoundDisplay : TournamentTestScene { public TestSceneRoundDisplay() { diff --git a/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs b/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs index 992baa48a3..f793c33878 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneSongBar.cs @@ -14,7 +14,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Tests.Components { [TestFixture] - public class TestSceneSongBar : OsuTestScene + public partial class TestSceneSongBar : OsuTestScene { [Cached] private readonly LadderInfo ladder = new LadderInfo(); diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs index adfe048ce4..057566d426 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentBeatmapPanel.cs @@ -14,7 +14,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Tests.Components { - public class TestSceneTournamentBeatmapPanel : TournamentTestScene + public partial class TestSceneTournamentBeatmapPanel : TournamentTestScene { /// /// Warning: the below API instance is actually the online API, rather than the dummy API provided by the test. diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs index eb8b0dfbe6..d9ae8df651 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentMatchChatDisplay.cs @@ -15,7 +15,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Tests.Components { - public class TestSceneTournamentMatchChatDisplay : OsuTestScene + public partial class TestSceneTournamentMatchChatDisplay : OsuTestScene { private readonly Channel testChannel = new Channel(); private readonly Channel testChannel2 = new Channel(); diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs index 263617ddf7..cea4306ff8 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Tournament.Tests.Components { - public class TestSceneTournamentModDisplay : TournamentTestScene + public partial class TestSceneTournamentModDisplay : TournamentTestScene { [Resolved] private IAPIProvider api { get; set; } diff --git a/osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs b/osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs index df77b31191..256a984a7c 100644 --- a/osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs +++ b/osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs @@ -17,7 +17,7 @@ using osu.Game.Tests; namespace osu.Game.Tournament.Tests.NonVisual { - public class DataLoadTest : TournamentHostTest + public partial class DataLoadTest : TournamentHostTest { [Test] public void TestRulesetGetsValidOnlineID() @@ -78,7 +78,7 @@ namespace osu.Game.Tournament.Tests.NonVisual } } - public class TestTournament : TournamentGameBase + public partial class TestTournament : TournamentGameBase { private readonly bool resetRuleset; private readonly Action runOnLoadComplete; diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneDrawingsScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneDrawingsScreen.cs index e0c6aaf834..10ed850002 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneDrawingsScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneDrawingsScreen.cs @@ -12,7 +12,7 @@ using osu.Game.Tournament.Screens.Drawings; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneDrawingsScreen : TournamentTestScene + public partial class TestSceneDrawingsScreen : TournamentTestScene { [BackgroundDependencyLoader] private void load(Storage storage) diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs index 4fc15c365f..f127a930a6 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs @@ -15,7 +15,7 @@ using osu.Game.Tournament.Screens.Gameplay.Components; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneGameplayScreen : TournamentTestScene + public partial class TestSceneGameplayScreen : TournamentTestScene { [Cached] private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay { Width = 0.5f }; diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneLadderEditorScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneLadderEditorScreen.cs index 7aade4fb82..5c4e1b2a5a 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneLadderEditorScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneLadderEditorScreen.cs @@ -10,7 +10,7 @@ using osu.Game.Tournament.Screens.Editors; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneLadderEditorScreen : TournamentTestScene + public partial class TestSceneLadderEditorScreen : TournamentTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneLadderScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneLadderScreen.cs index 1f817a1b22..20f729bb8d 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneLadderScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneLadderScreen.cs @@ -10,7 +10,7 @@ using osu.Game.Tournament.Screens.Ladder; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneLadderScreen : TournamentTestScene + public partial class TestSceneLadderScreen : TournamentTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneMapPoolScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneMapPoolScreen.cs index e0f91cc359..5695cb5574 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneMapPoolScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneMapPoolScreen.cs @@ -14,7 +14,7 @@ using osu.Game.Tournament.Screens.MapPool; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneMapPoolScreen : TournamentTestScene + public partial class TestSceneMapPoolScreen : TournamentTestScene { private MapPoolScreen screen; diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneRoundEditorScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneRoundEditorScreen.cs index 656663ece7..ebeb69012d 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneRoundEditorScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneRoundEditorScreen.cs @@ -7,7 +7,7 @@ using osu.Game.Tournament.Screens.Editors; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneRoundEditorScreen : TournamentTestScene + public partial class TestSceneRoundEditorScreen : TournamentTestScene { public TestSceneRoundEditorScreen() { diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneScheduleScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneScheduleScreen.cs index 6061314796..fd0de3d63a 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneScheduleScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneScheduleScreen.cs @@ -12,7 +12,7 @@ using osu.Game.Tournament.Screens.Schedule; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneScheduleScreen : TournamentTestScene + public partial class TestSceneScheduleScreen : TournamentTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneSeedingEditorScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneSeedingEditorScreen.cs index 94321e708f..cfb533149d 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneSeedingEditorScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneSeedingEditorScreen.cs @@ -9,7 +9,7 @@ using osu.Game.Tournament.Screens.Editors; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneSeedingEditorScreen : TournamentTestScene + public partial class TestSceneSeedingEditorScreen : TournamentTestScene { [Cached] private readonly LadderInfo ladder = new LadderInfo(); diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs index 2581ed4b7e..c9620bc0b9 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs @@ -14,7 +14,7 @@ using osu.Game.Tournament.Screens.TeamIntro; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneSeedingScreen : TournamentTestScene + public partial class TestSceneSeedingScreen : TournamentTestScene { [Cached] private readonly LadderInfo ladder = new LadderInfo diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneSetupScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneSetupScreen.cs index 9070590b15..84c8b9a141 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneSetupScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneSetupScreen.cs @@ -8,7 +8,7 @@ using osu.Game.Tournament.Screens.Setup; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneSetupScreen : TournamentTestScene + public partial class TestSceneSetupScreen : TournamentTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneShowcaseScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneShowcaseScreen.cs index 44e7c48887..6287679c27 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneShowcaseScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneShowcaseScreen.cs @@ -8,7 +8,7 @@ using osu.Game.Tournament.Screens.Showcase; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneShowcaseScreen : TournamentTestScene + public partial class TestSceneShowcaseScreen : TournamentTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneStablePathSelectScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneStablePathSelectScreen.cs index 27e5c59600..dbd9cb2817 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneStablePathSelectScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneStablePathSelectScreen.cs @@ -7,14 +7,14 @@ using osu.Game.Tournament.Screens.Setup; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneStablePathSelectScreen : TournamentTestScene + public partial class TestSceneStablePathSelectScreen : TournamentTestScene { public TestSceneStablePathSelectScreen() { AddStep("Add screen", () => Add(new StablePathSelectTestScreen())); } - private class StablePathSelectTestScreen : StablePathSelectScreen + private partial class StablePathSelectTestScreen : StablePathSelectScreen { protected override void ChangePath() { diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamEditorScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamEditorScreen.cs index b38430ece5..63c08800ad 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneTeamEditorScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamEditorScreen.cs @@ -7,7 +7,7 @@ using osu.Game.Tournament.Screens.Editors; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneTeamEditorScreen : TournamentTestScene + public partial class TestSceneTeamEditorScreen : TournamentTestScene { public TestSceneTeamEditorScreen() { diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs index fccc09c14e..5c26bc203c 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamIntroScreen.cs @@ -11,7 +11,7 @@ using osu.Game.Tournament.Screens.TeamIntro; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneTeamIntroScreen : TournamentTestScene + public partial class TestSceneTeamIntroScreen : TournamentTestScene { [Cached] private readonly LadderInfo ladder = new LadderInfo(); diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs index 3b48c2eee5..43e16873c6 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs @@ -10,7 +10,7 @@ using osu.Game.Tournament.Screens.TeamWin; namespace osu.Game.Tournament.Tests.Screens { - public class TestSceneTeamWinScreen : TournamentTestScene + public partial class TestSceneTeamWinScreen : TournamentTestScene { [Test] public void TestBasic() diff --git a/osu.Game.Tournament.Tests/TestSceneTournamentSceneManager.cs b/osu.Game.Tournament.Tests/TestSceneTournamentSceneManager.cs index e961a3c670..859d0591c3 100644 --- a/osu.Game.Tournament.Tests/TestSceneTournamentSceneManager.cs +++ b/osu.Game.Tournament.Tests/TestSceneTournamentSceneManager.cs @@ -7,7 +7,7 @@ using osu.Framework.Allocation; namespace osu.Game.Tournament.Tests { - public class TestSceneTournamentSceneManager : TournamentTestScene + public partial class TestSceneTournamentSceneManager : TournamentTestScene { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tournament.Tests/TournamentTestBrowser.cs b/osu.Game.Tournament.Tests/TournamentTestBrowser.cs index 1adbe07709..1a9122c117 100644 --- a/osu.Game.Tournament.Tests/TournamentTestBrowser.cs +++ b/osu.Game.Tournament.Tests/TournamentTestBrowser.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.Backgrounds; namespace osu.Game.Tournament.Tests { - public class TournamentTestBrowser : TournamentGameBase + public partial class TournamentTestBrowser : TournamentGameBase { protected override void LoadComplete() { diff --git a/osu.Game.Tournament.Tests/TournamentTestScene.cs b/osu.Game.Tournament.Tests/TournamentTestScene.cs index b440034f34..cab78422a2 100644 --- a/osu.Game.Tournament.Tests/TournamentTestScene.cs +++ b/osu.Game.Tournament.Tests/TournamentTestScene.cs @@ -18,7 +18,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Tests { - public abstract class TournamentTestScene : OsuTestScene + public abstract partial class TournamentTestScene : OsuTestScene { private TournamentMatch match; @@ -165,7 +165,7 @@ namespace osu.Game.Tournament.Tests protected override ITestSceneTestRunner CreateRunner() => new TournamentTestSceneTestRunner(); - public class TournamentTestSceneTestRunner : TournamentGameBase, ITestSceneTestRunner + public partial class TournamentTestSceneTestRunner : TournamentGameBase, ITestSceneTestRunner { private TestSceneTestRunner.TestRunner runner; diff --git a/osu.Game.Tournament/Components/ControlPanel.cs b/osu.Game.Tournament/Components/ControlPanel.cs index f43d494d5a..c3e66e80eb 100644 --- a/osu.Game.Tournament/Components/ControlPanel.cs +++ b/osu.Game.Tournament/Components/ControlPanel.cs @@ -16,7 +16,7 @@ namespace osu.Game.Tournament.Components /// An element anchored to the right-hand area of a screen that provides streamer level controls. /// Should be off-screen. /// - public class ControlPanel : Container + public partial class ControlPanel : Container { private readonly FillFlowContainer buttons; @@ -57,7 +57,7 @@ namespace osu.Game.Tournament.Components }; } - public class Spacer : CompositeDrawable + public partial class Spacer : CompositeDrawable { public Spacer(float height = 20) { diff --git a/osu.Game.Tournament/Components/DateTextBox.cs b/osu.Game.Tournament/Components/DateTextBox.cs index 76d12a6b03..192d8c9fd1 100644 --- a/osu.Game.Tournament/Components/DateTextBox.cs +++ b/osu.Game.Tournament/Components/DateTextBox.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Tournament.Components { - public class DateTextBox : SettingsTextBox + public partial class DateTextBox : SettingsTextBox { public new Bindable Current { diff --git a/osu.Game.Tournament/Components/DrawableTeamFlag.cs b/osu.Game.Tournament/Components/DrawableTeamFlag.cs index 348fd8cd76..317d685ee7 100644 --- a/osu.Game.Tournament/Components/DrawableTeamFlag.cs +++ b/osu.Game.Tournament/Components/DrawableTeamFlag.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Tournament.Components { - public class DrawableTeamFlag : Container + public partial class DrawableTeamFlag : Container { private readonly TournamentTeam team; diff --git a/osu.Game.Tournament/Components/DrawableTeamHeader.cs b/osu.Game.Tournament/Components/DrawableTeamHeader.cs index ceaf8d5e6e..1648e7373b 100644 --- a/osu.Game.Tournament/Components/DrawableTeamHeader.cs +++ b/osu.Game.Tournament/Components/DrawableTeamHeader.cs @@ -8,7 +8,7 @@ using osuTK; namespace osu.Game.Tournament.Components { - public class DrawableTeamHeader : TournamentSpriteTextWithBackground + public partial class DrawableTeamHeader : TournamentSpriteTextWithBackground { public DrawableTeamHeader(TeamColour colour) { diff --git a/osu.Game.Tournament/Components/DrawableTeamTitle.cs b/osu.Game.Tournament/Components/DrawableTeamTitle.cs index e64e08a921..68cc46be19 100644 --- a/osu.Game.Tournament/Components/DrawableTeamTitle.cs +++ b/osu.Game.Tournament/Components/DrawableTeamTitle.cs @@ -10,7 +10,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Components { - public class DrawableTeamTitle : TournamentSpriteTextWithBackground + public partial class DrawableTeamTitle : TournamentSpriteTextWithBackground { private readonly TournamentTeam team; diff --git a/osu.Game.Tournament/Components/DrawableTeamTitleWithHeader.cs b/osu.Game.Tournament/Components/DrawableTeamTitleWithHeader.cs index dbc9fa7f16..27113b0d21 100644 --- a/osu.Game.Tournament/Components/DrawableTeamTitleWithHeader.cs +++ b/osu.Game.Tournament/Components/DrawableTeamTitleWithHeader.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Tournament.Components { - public class DrawableTeamTitleWithHeader : CompositeDrawable + public partial class DrawableTeamTitleWithHeader : CompositeDrawable { public DrawableTeamTitleWithHeader(TournamentTeam team, TeamColour colour) { diff --git a/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs b/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs index 0bb35d534c..9606670ad8 100644 --- a/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs +++ b/osu.Game.Tournament/Components/DrawableTeamWithPlayers.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Components { - public class DrawableTeamWithPlayers : CompositeDrawable + public partial class DrawableTeamWithPlayers : CompositeDrawable { public DrawableTeamWithPlayers(TournamentTeam team, TeamColour colour) { diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs index 9f5b825e30..c83fceb01d 100644 --- a/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs +++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Tournament.Components { - public class DrawableTournamentHeaderLogo : CompositeDrawable + public partial class DrawableTournamentHeaderLogo : CompositeDrawable { public DrawableTournamentHeaderLogo() { @@ -21,7 +21,7 @@ namespace osu.Game.Tournament.Components RelativeSizeAxes = Axes.X; } - private class LogoSprite : Sprite + private partial class LogoSprite : Sprite { [BackgroundDependencyLoader] private void load(TextureStore textures) diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs index 67eeee7de4..7a1f448cb4 100644 --- a/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs +++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Tournament.Components { - public class DrawableTournamentHeaderText : CompositeDrawable + public partial class DrawableTournamentHeaderText : CompositeDrawable { public DrawableTournamentHeaderText(bool center = true) { @@ -25,7 +25,7 @@ namespace osu.Game.Tournament.Components RelativeSizeAxes = Axes.X; } - private class TextSprite : Sprite + private partial class TextSprite : Sprite { [BackgroundDependencyLoader] private void load(TextureStore textures) diff --git a/osu.Game.Tournament/Components/DrawableTournamentTeam.cs b/osu.Game.Tournament/Components/DrawableTournamentTeam.cs index eb1dde21e7..0036f5f115 100644 --- a/osu.Game.Tournament/Components/DrawableTournamentTeam.cs +++ b/osu.Game.Tournament/Components/DrawableTournamentTeam.cs @@ -12,7 +12,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Components { - public abstract class DrawableTournamentTeam : CompositeDrawable + public abstract partial class DrawableTournamentTeam : CompositeDrawable { public readonly TournamentTeam Team; diff --git a/osu.Game.Tournament/Components/IPCErrorDialog.cs b/osu.Game.Tournament/Components/IPCErrorDialog.cs index a32e01fb48..995bbffffc 100644 --- a/osu.Game.Tournament/Components/IPCErrorDialog.cs +++ b/osu.Game.Tournament/Components/IPCErrorDialog.cs @@ -8,7 +8,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Tournament.Components { - public class IPCErrorDialog : PopupDialog + public partial class IPCErrorDialog : PopupDialog { public IPCErrorDialog(string headerText, string bodyText) { diff --git a/osu.Game.Tournament/Components/RoundDisplay.cs b/osu.Game.Tournament/Components/RoundDisplay.cs index 98ef09aa58..6018cc6ffb 100644 --- a/osu.Game.Tournament/Components/RoundDisplay.cs +++ b/osu.Game.Tournament/Components/RoundDisplay.cs @@ -10,7 +10,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Components { - public class RoundDisplay : CompositeDrawable + public partial class RoundDisplay : CompositeDrawable { public RoundDisplay(TournamentMatch match) { diff --git a/osu.Game.Tournament/Components/SongBar.cs b/osu.Game.Tournament/Components/SongBar.cs index a9056166be..aeceece160 100644 --- a/osu.Game.Tournament/Components/SongBar.cs +++ b/osu.Game.Tournament/Components/SongBar.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Components { - public class SongBar : CompositeDrawable + public partial class SongBar : CompositeDrawable { private TournamentBeatmap beatmap; @@ -242,7 +242,7 @@ namespace osu.Game.Tournament.Components }; } - public class DiffPiece : TextFlowContainer + public partial class DiffPiece : TextFlowContainer { public DiffPiece(params (string heading, string content)[] tuples) { diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs index 462743cc3d..52769321a9 100644 --- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs +++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Components { - public class TournamentBeatmapPanel : CompositeDrawable + public partial class TournamentBeatmapPanel : CompositeDrawable { public readonly TournamentBeatmap Beatmap; diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs index ca2b400e8b..8a0dd6e336 100644 --- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs @@ -15,7 +15,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Components { - public class TournamentMatchChatDisplay : StandAloneChatDisplay + public partial class TournamentMatchChatDisplay : StandAloneChatDisplay { private readonly Bindable chatChannel = new Bindable(); @@ -75,7 +75,7 @@ namespace osu.Game.Tournament.Components protected override StandAloneDrawableChannel CreateDrawableChannel(Channel channel) => new MatchChannel(channel); - public class MatchChannel : StandAloneDrawableChannel + public partial class MatchChannel : StandAloneDrawableChannel { public MatchChannel(Channel channel) : base(channel) @@ -84,7 +84,7 @@ namespace osu.Game.Tournament.Components } } - protected class MatchMessage : StandAloneMessage + protected partial class MatchMessage : StandAloneMessage { public MatchMessage(Message message) : base(message) diff --git a/osu.Game.Tournament/Components/TournamentModIcon.cs b/osu.Game.Tournament/Components/TournamentModIcon.cs index 6697a993c3..76b6151519 100644 --- a/osu.Game.Tournament/Components/TournamentModIcon.cs +++ b/osu.Game.Tournament/Components/TournamentModIcon.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tournament.Components /// /// Mod icon displayed in tournament usages, allowing user overridden graphics. /// - public class TournamentModIcon : CompositeDrawable + public partial class TournamentModIcon : CompositeDrawable { private readonly string modAcronym; diff --git a/osu.Game.Tournament/Components/TournamentSpriteTextWithBackground.cs b/osu.Game.Tournament/Components/TournamentSpriteTextWithBackground.cs index b088670caa..3a16662463 100644 --- a/osu.Game.Tournament/Components/TournamentSpriteTextWithBackground.cs +++ b/osu.Game.Tournament/Components/TournamentSpriteTextWithBackground.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics; namespace osu.Game.Tournament.Components { - public class TournamentSpriteTextWithBackground : CompositeDrawable + public partial class TournamentSpriteTextWithBackground : CompositeDrawable { public readonly TournamentSpriteText Text; diff --git a/osu.Game.Tournament/Components/TourneyVideo.cs b/osu.Game.Tournament/Components/TourneyVideo.cs index 2e79998e66..b9ce84b735 100644 --- a/osu.Game.Tournament/Components/TourneyVideo.cs +++ b/osu.Game.Tournament/Components/TourneyVideo.cs @@ -15,7 +15,7 @@ using osu.Game.Tournament.IO; namespace osu.Game.Tournament.Components { - public class TourneyVideo : CompositeDrawable + public partial class TourneyVideo : CompositeDrawable { private readonly string filename; private readonly bool drawFallbackGradient; diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs index ad564c58c3..f940571ffe 100644 --- a/osu.Game.Tournament/IPC/FileBasedIPC.cs +++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs @@ -22,7 +22,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.IPC { - public class FileBasedIPC : MatchIPCInfo + public partial class FileBasedIPC : MatchIPCInfo { public Storage IPCStorage { get; private set; } diff --git a/osu.Game.Tournament/IPC/MatchIPCInfo.cs b/osu.Game.Tournament/IPC/MatchIPCInfo.cs index f438923803..3bf790d58e 100644 --- a/osu.Game.Tournament/IPC/MatchIPCInfo.cs +++ b/osu.Game.Tournament/IPC/MatchIPCInfo.cs @@ -10,7 +10,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.IPC { - public class MatchIPCInfo : Component + public partial class MatchIPCInfo : Component { public Bindable Beatmap { get; } = new Bindable(); public Bindable Mods { get; } = new Bindable(); diff --git a/osu.Game.Tournament/SaveChangesOverlay.cs b/osu.Game.Tournament/SaveChangesOverlay.cs index b5e08fc005..a81f11cbe1 100644 --- a/osu.Game.Tournament/SaveChangesOverlay.cs +++ b/osu.Game.Tournament/SaveChangesOverlay.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tournament { - internal class SaveChangesOverlay : CompositeDrawable + internal partial class SaveChangesOverlay : CompositeDrawable { [Resolved] private TournamentGame tournamentGame { get; set; } = null!; diff --git a/osu.Game.Tournament/Screens/BeatmapInfoScreen.cs b/osu.Game.Tournament/Screens/BeatmapInfoScreen.cs index 763f576afe..6f7234b8c3 100644 --- a/osu.Game.Tournament/Screens/BeatmapInfoScreen.cs +++ b/osu.Game.Tournament/Screens/BeatmapInfoScreen.cs @@ -13,7 +13,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens { - public abstract class BeatmapInfoScreen : TournamentMatchScreen + public abstract partial class BeatmapInfoScreen : TournamentMatchScreen { protected readonly SongBar SongBar; diff --git a/osu.Game.Tournament/Screens/Drawings/Components/Group.cs b/osu.Game.Tournament/Screens/Drawings/Components/Group.cs index 0b1a5328ab..b397f807f0 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/Group.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/Group.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens.Drawings.Components { - public class Group : Container + public partial class Group : Container { public readonly string GroupName; diff --git a/osu.Game.Tournament/Screens/Drawings/Components/GroupContainer.cs b/osu.Game.Tournament/Screens/Drawings/Components/GroupContainer.cs index 62b3c4e8ff..37e15b7e45 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/GroupContainer.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/GroupContainer.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Drawings.Components { - public class GroupContainer : Container + public partial class GroupContainer : Container { private readonly List groups = new List(); diff --git a/osu.Game.Tournament/Screens/Drawings/Components/GroupTeam.cs b/osu.Game.Tournament/Screens/Drawings/Components/GroupTeam.cs index 80bdad8b7b..167a576424 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/GroupTeam.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/GroupTeam.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Drawings.Components { - public class GroupTeam : DrawableTournamentTeam + public partial class GroupTeam : DrawableTournamentTeam { private readonly FillFlowContainer innerContainer; diff --git a/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs b/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs index 8092c24ccb..c2b15dd3e9 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/ScrollingTeamContainer.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens.Drawings.Components { - public class ScrollingTeamContainer : Container + public partial class ScrollingTeamContainer : Container { public event Action OnScrollStarted; public event Action OnSelected; @@ -309,7 +309,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components Scrolling } - public class ScrollingTeam : DrawableTournamentTeam + public partial class ScrollingTeam : DrawableTournamentTeam { public const float WIDTH = 58; public const float HEIGHT = 44; diff --git a/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs b/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs index 663162d1ca..676eec14cd 100644 --- a/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs +++ b/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs @@ -14,7 +14,7 @@ using osu.Framework.Utils; namespace osu.Game.Tournament.Screens.Drawings.Components { - public class VisualiserContainer : Container + public partial class VisualiserContainer : Container { /// /// Number of lines in the visualiser. @@ -61,7 +61,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components allLines.Remove(allLines.First()); } - private class VisualiserLine : Container + private partial class VisualiserLine : Container { /// /// Time offset. diff --git a/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs b/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs index 5ac25f97b5..23d0edf26e 100644 --- a/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs +++ b/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs @@ -24,7 +24,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens.Drawings { - public class DrawingsScreen : TournamentScreen + public partial class DrawingsScreen : TournamentScreen { private const string results_filename = "drawings_results.txt"; diff --git a/osu.Game.Tournament/Screens/Editors/LadderEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/LadderEditorScreen.cs index 4261828df2..4ee3108034 100644 --- a/osu.Game.Tournament/Screens/Editors/LadderEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/LadderEditorScreen.cs @@ -23,7 +23,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens.Editors { [Cached] - public class LadderEditorScreen : LadderScreen, IHasContextMenu + public partial class LadderEditorScreen : LadderScreen, IHasContextMenu { [Cached] private LadderEditorInfo editorInfo = new LadderEditorInfo(); @@ -86,7 +86,7 @@ namespace osu.Game.Tournament.Screens.Editors MatchesContainer.FirstOrDefault(p => p.Match == match)?.Remove(); } - private class JoinVisualiser : CompositeDrawable + private partial class JoinVisualiser : CompositeDrawable { private readonly Container matchesContainer; public readonly TournamentMatch Source; diff --git a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs index 0bd5ddb257..75131c282d 100644 --- a/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/RoundEditorScreen.cs @@ -20,11 +20,11 @@ using osuTK; namespace osu.Game.Tournament.Screens.Editors { - public class RoundEditorScreen : TournamentEditorScreen + public partial class RoundEditorScreen : TournamentEditorScreen { protected override BindableList Storage => LadderInfo.Rounds; - public class RoundRow : CompositeDrawable, IModelBacked + public partial class RoundRow : CompositeDrawable, IModelBacked { public TournamentRound Model { get; } @@ -113,7 +113,7 @@ namespace osu.Game.Tournament.Screens.Editors AutoSizeAxes = Axes.Y; } - public class RoundBeatmapEditor : CompositeDrawable + public partial class RoundBeatmapEditor : CompositeDrawable { private readonly TournamentRound round; private readonly FillFlowContainer flow; @@ -141,7 +141,7 @@ namespace osu.Game.Tournament.Screens.Editors flow.Add(new RoundBeatmapRow(round, user)); } - public class RoundBeatmapRow : CompositeDrawable + public partial class RoundBeatmapRow : CompositeDrawable { public RoundBeatmap Model { get; } diff --git a/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs index 348661e2a3..a4358b4396 100644 --- a/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Editors { - public class SeedingEditorScreen : TournamentEditorScreen + public partial class SeedingEditorScreen : TournamentEditorScreen { private readonly TournamentTeam team; @@ -32,7 +32,7 @@ namespace osu.Game.Tournament.Screens.Editors this.team = team; } - public class SeedingResultRow : CompositeDrawable, IModelBacked + public partial class SeedingResultRow : CompositeDrawable, IModelBacked { public SeedingResult Model { get; } @@ -106,7 +106,7 @@ namespace osu.Game.Tournament.Screens.Editors AutoSizeAxes = Axes.Y; } - public class SeedingBeatmapEditor : CompositeDrawable + public partial class SeedingBeatmapEditor : CompositeDrawable { private readonly SeedingResult round; private readonly FillFlowContainer flow; @@ -134,7 +134,7 @@ namespace osu.Game.Tournament.Screens.Editors flow.Add(new SeedingBeatmapRow(round, user)); } - public class SeedingBeatmapRow : CompositeDrawable + public partial class SeedingBeatmapRow : CompositeDrawable { private readonly SeedingResult result; public SeedingBeatmap Model { get; } diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs index da27c09e01..988f0a02f0 100644 --- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs @@ -23,7 +23,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Editors { - public class TeamEditorScreen : TournamentEditorScreen + public partial class TeamEditorScreen : TournamentEditorScreen { protected override BindableList Storage => LadderInfo.Teams; @@ -60,7 +60,7 @@ namespace osu.Game.Tournament.Screens.Editors Storage.Add(c); } - public class TeamRow : CompositeDrawable, IModelBacked + public partial class TeamRow : CompositeDrawable, IModelBacked { public TournamentTeam Model { get; } @@ -181,7 +181,7 @@ namespace osu.Game.Tournament.Screens.Editors drawableContainer.Child = new DrawableTeamFlag(Model); } - public class PlayerEditor : CompositeDrawable + public partial class PlayerEditor : CompositeDrawable { private readonly TournamentTeam team; private readonly FillFlowContainer flow; @@ -209,7 +209,7 @@ namespace osu.Game.Tournament.Screens.Editors flow.Add(new PlayerRow(team, player)); } - public class PlayerRow : CompositeDrawable + public partial class PlayerRow : CompositeDrawable { private readonly TournamentUser user; diff --git a/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs index 8c55026c67..8f0d1de0cb 100644 --- a/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs +++ b/osu.Game.Tournament/Screens/Editors/TournamentEditorScreen.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Editors { - public abstract class TournamentEditorScreen : TournamentScreen + public abstract partial class TournamentEditorScreen : TournamentScreen where TDrawable : Drawable, IModelBacked where TModel : class, new() { diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs index 91a75bf86f..8f7484980d 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Gameplay.Components { - public class MatchHeader : Container + public partial class MatchHeader : Container { private TeamScoreDisplay teamDisplay1; private TeamScoreDisplay teamDisplay2; diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs index 78206c6d47..d2b61220f0 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs @@ -10,7 +10,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens.Gameplay.Components { - public class MatchRoundDisplay : TournamentSpriteTextWithBackground + public partial class MatchRoundDisplay : TournamentSpriteTextWithBackground { private readonly Bindable currentMatch = new Bindable(); diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/TeamDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/TeamDisplay.cs index 1eceddd871..60d1678326 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/TeamDisplay.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/TeamDisplay.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Gameplay.Components { - public class TeamDisplay : DrawableTournamentTeam + public partial class TeamDisplay : DrawableTournamentTeam { private readonly TeamScore score; diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScore.cs b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScore.cs index 3fa06c16b4..8b3786fa1f 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScore.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScore.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens.Gameplay.Components { - public class TeamScore : CompositeDrawable + public partial class TeamScore : CompositeDrawable { private readonly Bindable currentTeamScore = new Bindable(); private readonly StarCounter counter; @@ -41,7 +41,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components private void scoreChanged(ValueChangedEvent score) => counter.Current = score.NewValue ?? 0; - public class TeamScoreStarCounter : StarCounter + public partial class TeamScoreStarCounter : StarCounter { public TeamScoreStarCounter(int count) : base(count) @@ -50,7 +50,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components public override Star CreateStar() => new LightSquare(); - public class LightSquare : Star + public partial class LightSquare : Star { private readonly Box box; diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs index 0fa5884603..57fe1c7312 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs @@ -13,7 +13,7 @@ using osuTK.Input; namespace osu.Game.Tournament.Screens.Gameplay.Components { - public class TeamScoreDisplay : CompositeDrawable + public partial class TeamScoreDisplay : CompositeDrawable { private readonly TeamColour teamColour; diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/TournamentMatchScoreDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/TournamentMatchScoreDisplay.cs index 7454d22aa2..bd1f3a2dd0 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/TournamentMatchScoreDisplay.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/TournamentMatchScoreDisplay.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Gameplay.Components { // TODO: Update to derive from osu-side class? - public class TournamentMatchScoreDisplay : CompositeDrawable + public partial class TournamentMatchScoreDisplay : CompositeDrawable { private const float bar_height = 18; @@ -128,7 +128,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components score2Text.X = Math.Max(5 + score2Text.DrawWidth / 2, score2Bar.DrawWidth); } - private class MatchScoreCounter : CommaSeparatedScoreCounter + private partial class MatchScoreCounter : CommaSeparatedScoreCounter { private OsuSpriteText displayedSpriteText; diff --git a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs index 8a23ee65da..f2a2e97bcc 100644 --- a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs +++ b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens.Gameplay { - public class GameplayScreen : BeatmapInfoScreen + public partial class GameplayScreen : BeatmapInfoScreen { private readonly BindableBool warmup = new BindableBool(); @@ -232,7 +232,7 @@ namespace osu.Game.Tournament.Screens.Gameplay } } - private class ChromaArea : CompositeDrawable + private partial class ChromaArea : CompositeDrawable { [Resolved] private LadderInfo ladder { get; set; } diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs index c005e11efe..2b66df1a31 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs @@ -24,7 +24,7 @@ using osuTK.Input; namespace osu.Game.Tournament.Screens.Ladder.Components { - public class DrawableMatchTeam : DrawableTournamentTeam, IHasContextMenu + public partial class DrawableMatchTeam : DrawableTournamentTeam, IHasContextMenu { private readonly TournamentMatch match; private readonly bool losers; diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentMatch.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentMatch.cs index ed8b789387..33e383482f 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentMatch.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentMatch.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Tournament.Screens.Ladder.Components { - public class DrawableTournamentMatch : CompositeDrawable + public partial class DrawableTournamentMatch : CompositeDrawable { public readonly TournamentMatch Match; private readonly bool editor; diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs index 466b9ed482..4b2a29247b 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs @@ -12,7 +12,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens.Ladder.Components { - public class DrawableTournamentRound : CompositeDrawable + public partial class DrawableTournamentRound : CompositeDrawable { [UsedImplicitly] private readonly Bindable name; diff --git a/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs b/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs index 1fdf616e34..603a7830c7 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs @@ -18,7 +18,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens.Ladder.Components { - public class LadderEditorSettings : PlayerSettingsGroup + public partial class LadderEditorSettings : PlayerSettingsGroup { private const int padding = 10; @@ -89,7 +89,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components { } - private class SettingsRoundDropdown : SettingsDropdown + private partial class SettingsRoundDropdown : SettingsDropdown { public SettingsRoundDropdown(BindableList rounds) { diff --git a/osu.Game.Tournament/Screens/Ladder/Components/ProgressionPath.cs b/osu.Game.Tournament/Screens/Ladder/Components/ProgressionPath.cs index c5f8c3bb51..c79dbc26be 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/ProgressionPath.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/ProgressionPath.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Ladder.Components { - public class ProgressionPath : Path + public partial class ProgressionPath : Path { public DrawableTournamentMatch Source { get; } public DrawableTournamentMatch Destination { get; } diff --git a/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs b/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs index 74424783c6..c90cdb7775 100644 --- a/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs +++ b/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs @@ -13,7 +13,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens.Ladder.Components { - public class SettingsTeamDropdown : SettingsDropdown + public partial class SettingsTeamDropdown : SettingsDropdown { public SettingsTeamDropdown(BindableList teams) { diff --git a/osu.Game.Tournament/Screens/Ladder/LadderDragContainer.cs b/osu.Game.Tournament/Screens/Ladder/LadderDragContainer.cs index 6fae44de35..10d58612f4 100644 --- a/osu.Game.Tournament/Screens/Ladder/LadderDragContainer.cs +++ b/osu.Game.Tournament/Screens/Ladder/LadderDragContainer.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Ladder { - public class LadderDragContainer : Container + public partial class LadderDragContainer : Container { protected override bool OnDragStart(DragStartEvent e) => true; diff --git a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs index 7ad7e76a1f..595f08ed36 100644 --- a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs +++ b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens.Ladder { - public class LadderScreen : TournamentScreen + public partial class LadderScreen : TournamentScreen { protected Container MatchesContainer; private Container paths; diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs index decd723814..f0e34d78c3 100644 --- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs +++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs @@ -22,7 +22,7 @@ using osuTK.Input; namespace osu.Game.Tournament.Screens.MapPool { - public class MapPoolScreen : TournamentMatchScreen + public partial class MapPoolScreen : TournamentMatchScreen { private readonly FillFlowContainer> mapFlows; diff --git a/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs b/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs index 0827cbae69..8d5547c749 100644 --- a/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs +++ b/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens.Schedule { - public class ScheduleScreen : TournamentScreen + public partial class ScheduleScreen : TournamentScreen { private readonly Bindable currentMatch = new Bindable(); private Container mainContainer; @@ -209,7 +209,7 @@ namespace osu.Game.Tournament.Screens.Schedule } } - public class ScheduleMatch : DrawableTournamentMatch + public partial class ScheduleMatch : DrawableTournamentMatch { public ScheduleMatch(TournamentMatch match, bool showTimestamp = true) : base(match) @@ -249,7 +249,7 @@ namespace osu.Game.Tournament.Screens.Schedule } } - public class ScheduleMatchDate : DrawableDate + public partial class ScheduleMatchDate : DrawableDate { public ScheduleMatchDate(DateTimeOffset date, float textSize = OsuFont.DEFAULT_FONT_SIZE, bool italic = true) : base(date, textSize, italic) @@ -261,7 +261,7 @@ namespace osu.Game.Tournament.Screens.Schedule : $"Starting {base.Format()}"; } - public class ScheduleContainer : Container + public partial class ScheduleContainer : Container { protected override Container Content => content; diff --git a/osu.Game.Tournament/Screens/Setup/ActionableInfo.cs b/osu.Game.Tournament/Screens/Setup/ActionableInfo.cs index a9ac21284e..639cca23b1 100644 --- a/osu.Game.Tournament/Screens/Setup/ActionableInfo.cs +++ b/osu.Game.Tournament/Screens/Setup/ActionableInfo.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens.Setup { - internal class ActionableInfo : LabelledDrawable + internal partial class ActionableInfo : LabelledDrawable { protected OsuButton Button; diff --git a/osu.Game.Tournament/Screens/Setup/ResolutionSelector.cs b/osu.Game.Tournament/Screens/Setup/ResolutionSelector.cs index a387341d66..e6ab6f143a 100644 --- a/osu.Game.Tournament/Screens/Setup/ResolutionSelector.cs +++ b/osu.Game.Tournament/Screens/Setup/ResolutionSelector.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Tournament.Screens.Setup { - internal class ResolutionSelector : ActionableInfo + internal partial class ResolutionSelector : ActionableInfo { private const int minimum_window_height = 480; private const int maximum_window_height = 2160; diff --git a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs index ff781dec80..b86513eb49 100644 --- a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Setup { - public class SetupScreen : TournamentScreen + public partial class SetupScreen : TournamentScreen { private FillFlowContainer fillFlow; diff --git a/osu.Game.Tournament/Screens/Setup/StablePathSelectScreen.cs b/osu.Game.Tournament/Screens/Setup/StablePathSelectScreen.cs index fac488fcf5..49f60156b6 100644 --- a/osu.Game.Tournament/Screens/Setup/StablePathSelectScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/StablePathSelectScreen.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.Setup { - public class StablePathSelectScreen : TournamentScreen + public partial class StablePathSelectScreen : TournamentScreen { [Resolved(canBeNull: true)] private TournamentSceneManager sceneManager { get; set; } diff --git a/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs b/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs index 447d6f44ce..ff98d044f8 100644 --- a/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs +++ b/osu.Game.Tournament/Screens/Setup/TournamentSwitcher.cs @@ -10,7 +10,7 @@ using osu.Game.Tournament.IO; namespace osu.Game.Tournament.Screens.Setup { - internal class TournamentSwitcher : ActionableInfo + internal partial class TournamentSwitcher : ActionableInfo { private OsuDropdown dropdown; private OsuButton folderButton; diff --git a/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs b/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs index a7a175ceba..35d63f4fcf 100644 --- a/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs +++ b/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament.Screens.Showcase { - public class ShowcaseScreen : BeatmapInfoScreen + public partial class ShowcaseScreen : BeatmapInfoScreen { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs b/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs index 07a632ec72..d04059118f 100644 --- a/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs +++ b/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Tournament.Screens.Showcase { - public class TournamentLogo : CompositeDrawable + public partial class TournamentLogo : CompositeDrawable { public TournamentLogo() { diff --git a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs index ba75b6a2ed..b07a0a65dd 100644 --- a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs +++ b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.TeamIntro { - public class SeedingScreen : TournamentMatchScreen + public partial class SeedingScreen : TournamentMatchScreen { private Container mainContainer; @@ -116,7 +116,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro }; }); - private class RightInfo : CompositeDrawable + private partial class RightInfo : CompositeDrawable { public RightInfo(TournamentTeam team) { @@ -148,7 +148,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro } } - private class BeatmapScoreRow : CompositeDrawable + private partial class BeatmapScoreRow : CompositeDrawable { public BeatmapScoreRow(SeedingBeatmap beatmap) { @@ -190,7 +190,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro } } - private class ModRow : CompositeDrawable + private partial class ModRow : CompositeDrawable { private readonly string mods; private readonly int seeding; @@ -254,7 +254,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro } } - private class LeftInfo : CompositeDrawable + private partial class LeftInfo : CompositeDrawable { public LeftInfo(TournamentTeam team) { @@ -286,7 +286,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro fill.Add(new RowDisplay(p.Username, p.Rank?.ToString("\\##,0") ?? "-")); } - internal class RowDisplay : CompositeDrawable + internal partial class RowDisplay : CompositeDrawable { public RowDisplay(string left, string right) { @@ -313,7 +313,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro } } - private class TeamDisplay : DrawableTournamentTeam + private partial class TeamDisplay : DrawableTournamentTeam { public TeamDisplay(TournamentTeam team) : base(team) diff --git a/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs index 08c9a7a897..950a63808c 100644 --- a/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs +++ b/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.TeamIntro { - public class TeamIntroScreen : TournamentMatchScreen + public partial class TeamIntroScreen : TournamentMatchScreen { private Container mainContainer; diff --git a/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs b/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs index ac54ff58f5..9206de1dc2 100644 --- a/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs +++ b/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Tournament.Screens.TeamWin { - public class TeamWinScreen : TournamentMatchScreen + public partial class TeamWinScreen : TournamentMatchScreen { private Container mainContainer; diff --git a/osu.Game.Tournament/Screens/TournamentMatchScreen.cs b/osu.Game.Tournament/Screens/TournamentMatchScreen.cs index 585cdd09c1..58444d0c1b 100644 --- a/osu.Game.Tournament/Screens/TournamentMatchScreen.cs +++ b/osu.Game.Tournament/Screens/TournamentMatchScreen.cs @@ -8,7 +8,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens { - public abstract class TournamentMatchScreen : TournamentScreen + public abstract partial class TournamentMatchScreen : TournamentScreen { protected readonly Bindable CurrentMatch = new Bindable(); private WarningBox noMatchWarning; diff --git a/osu.Game.Tournament/Screens/TournamentScreen.cs b/osu.Game.Tournament/Screens/TournamentScreen.cs index b4641fa45d..02903a637c 100644 --- a/osu.Game.Tournament/Screens/TournamentScreen.cs +++ b/osu.Game.Tournament/Screens/TournamentScreen.cs @@ -10,7 +10,7 @@ using osu.Game.Tournament.Models; namespace osu.Game.Tournament.Screens { - public abstract class TournamentScreen : CompositeDrawable + public abstract partial class TournamentScreen : CompositeDrawable { public const double FADE_DELAY = 200; diff --git a/osu.Game.Tournament/TournamentGame.cs b/osu.Game.Tournament/TournamentGame.cs index 7d67bfa759..beef1e197d 100644 --- a/osu.Game.Tournament/TournamentGame.cs +++ b/osu.Game.Tournament/TournamentGame.cs @@ -23,7 +23,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament { [Cached] - public class TournamentGame : TournamentGameBase + public partial class TournamentGame : TournamentGameBase { public static ColourInfo GetTeamColour(TeamColour teamColour) => teamColour == TeamColour.Red ? COLOUR_RED : COLOUR_BLUE; diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 98ba3ca60f..08f21cb556 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -27,7 +27,7 @@ using osuTK.Input; namespace osu.Game.Tournament { [Cached(typeof(TournamentGameBase))] - public class TournamentGameBase : OsuGameBase + public partial class TournamentGameBase : OsuGameBase { public const string BRACKET_FILENAME = @"bracket.json"; private LadderInfo ladder; @@ -335,7 +335,7 @@ namespace osu.Game.Tournament protected override UserInputManager CreateUserInputManager() => new TournamentInputManager(); - private class TournamentInputManager : UserInputManager + private partial class TournamentInputManager : UserInputManager { protected override MouseButtonEventManager CreateButtonEventManagerFor(MouseButton button) { diff --git a/osu.Game.Tournament/TournamentSceneManager.cs b/osu.Game.Tournament/TournamentSceneManager.cs index a12dbb4740..abfe69b97b 100644 --- a/osu.Game.Tournament/TournamentSceneManager.cs +++ b/osu.Game.Tournament/TournamentSceneManager.cs @@ -33,7 +33,7 @@ using osuTK.Input; namespace osu.Game.Tournament { [Cached] - public class TournamentSceneManager : CompositeDrawable + public partial class TournamentSceneManager : CompositeDrawable { private Container screens; private TourneyVideo video; @@ -224,7 +224,7 @@ namespace osu.Game.Tournament s.IsSelected = screenType == s.Type; } - private class Separator : CompositeDrawable + private partial class Separator : CompositeDrawable { public Separator() { @@ -233,7 +233,7 @@ namespace osu.Game.Tournament } } - private class ScreenButton : TourneyButton + private partial class ScreenButton : TourneyButton { public readonly Type Type; diff --git a/osu.Game.Tournament/TournamentSpriteText.cs b/osu.Game.Tournament/TournamentSpriteText.cs index 166a8dfaf0..7ecb31ff15 100644 --- a/osu.Game.Tournament/TournamentSpriteText.cs +++ b/osu.Game.Tournament/TournamentSpriteText.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Tournament { - public class TournamentSpriteText : OsuSpriteText + public partial class TournamentSpriteText : OsuSpriteText { public TournamentSpriteText() { diff --git a/osu.Game.Tournament/TourneyButton.cs b/osu.Game.Tournament/TourneyButton.cs index f1b14df783..558bd476c3 100644 --- a/osu.Game.Tournament/TourneyButton.cs +++ b/osu.Game.Tournament/TourneyButton.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Tournament { - public class TourneyButton : OsuButton + public partial class TourneyButton : OsuButton { public new Box Background => base.Background; diff --git a/osu.Game.Tournament/WarningBox.cs b/osu.Game.Tournament/WarningBox.cs index 123e78113a..4a196446f6 100644 --- a/osu.Game.Tournament/WarningBox.cs +++ b/osu.Game.Tournament/WarningBox.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Tournament { - internal class WarningBox : Container + internal partial class WarningBox : Container { public WarningBox(string text) { diff --git a/osu.Game/Audio/Effects/AudioFilter.cs b/osu.Game/Audio/Effects/AudioFilter.cs index 9446967173..682ca4ca7b 100644 --- a/osu.Game/Audio/Effects/AudioFilter.cs +++ b/osu.Game/Audio/Effects/AudioFilter.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; namespace osu.Game.Audio.Effects { - public class AudioFilter : Component, ITransformableFilter + public partial class AudioFilter : Component, ITransformableFilter { /// /// The maximum cutoff frequency that can be used with a low-pass filter. diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index 2409ca6eb6..ea226ab650 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -10,7 +10,7 @@ using osu.Framework.Threading; namespace osu.Game.Audio { [LongRunningLoad] - public abstract class PreviewTrack : Component + public abstract partial class PreviewTrack : Component { /// /// Invoked when this has stopped playing. diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index b8662b6a4b..1d710e6395 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -12,7 +12,7 @@ using osu.Game.Beatmaps; namespace osu.Game.Audio { - public class PreviewTrackManager : Component + public partial class PreviewTrackManager : Component { private readonly IAdjustableAudioComponent mainTrackAdjustments; @@ -85,7 +85,7 @@ namespace osu.Game.Audio protected virtual TrackManagerPreviewTrack CreatePreviewTrack(IBeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TrackManagerPreviewTrack(beatmapSetInfo, trackStore); - public class TrackManagerPreviewTrack : PreviewTrack + public partial class TrackManagerPreviewTrack : PreviewTrack { [Resolved] public IPreviewTrackOwner? Owner { get; private set; } diff --git a/osu.Game/BackgroundBeatmapProcessor.cs b/osu.Game/BackgroundBeatmapProcessor.cs index ea5904a8d3..b8c89d8822 100644 --- a/osu.Game/BackgroundBeatmapProcessor.cs +++ b/osu.Game/BackgroundBeatmapProcessor.cs @@ -20,7 +20,7 @@ using osu.Game.Screens.Play; namespace osu.Game { - public class BackgroundBeatmapProcessor : Component + public partial class BackgroundBeatmapProcessor : Component { [Resolved] private RulesetStore rulesetStore { get; set; } = null!; diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index bf7b980e75..871faf5906 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -26,7 +26,7 @@ namespace osu.Game.Beatmaps /// A component which performs and acts as a central cache for difficulty calculations of beatmap/ruleset/mod combinations. /// Currently not persisted between game sessions. /// - public class BeatmapDifficultyCache : MemoryCachingComponent + public partial class BeatmapDifficultyCache : MemoryCachingComponent { // Too many simultaneous updates can lead to stutters. One thread seems to work fine for song select display purposes. private readonly ThreadedTaskScheduler updateScheduler = new ThreadedTaskScheduler(1, nameof(BeatmapDifficultyCache)); diff --git a/osu.Game/Beatmaps/BeatmapOnlineChangeIngest.cs b/osu.Game/Beatmaps/BeatmapOnlineChangeIngest.cs index 5d0765641b..98aefd75d3 100644 --- a/osu.Game/Beatmaps/BeatmapOnlineChangeIngest.cs +++ b/osu.Game/Beatmaps/BeatmapOnlineChangeIngest.cs @@ -11,7 +11,7 @@ namespace osu.Game.Beatmaps /// /// Ingests any changes that happen externally to the client, reprocessing as required. /// - public class BeatmapOnlineChangeIngest : Component + public partial class BeatmapOnlineChangeIngest : Component { private readonly BeatmapUpdater beatmapUpdater; private readonly RealmAccess realm; diff --git a/osu.Game/Beatmaps/BeatmapStatisticIcon.cs b/osu.Game/Beatmaps/BeatmapStatisticIcon.cs index 8002910b52..ca07e5f365 100644 --- a/osu.Game/Beatmaps/BeatmapStatisticIcon.cs +++ b/osu.Game/Beatmaps/BeatmapStatisticIcon.cs @@ -13,7 +13,7 @@ namespace osu.Game.Beatmaps /// /// A default implementation of an icon used to represent beatmap statistics. /// - public class BeatmapStatisticIcon : Sprite + public partial class BeatmapStatisticIcon : Sprite { private readonly BeatmapStatisticsIconType iconType; diff --git a/osu.Game/Beatmaps/DifficultyRecommender.cs b/osu.Game/Beatmaps/DifficultyRecommender.cs index ed2d6cd3a8..7a23b32c84 100644 --- a/osu.Game/Beatmaps/DifficultyRecommender.cs +++ b/osu.Game/Beatmaps/DifficultyRecommender.cs @@ -19,7 +19,7 @@ namespace osu.Game.Beatmaps /// A class which will recommend the most suitable difficulty for the local user from a beatmap set. /// This requires the user to be logged in, as it sources from the user's online profile. /// - public class DifficultyRecommender : Component + public partial class DifficultyRecommender : Component { [Resolved] private IAPIProvider api { get; set; } diff --git a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs index 4ba16839f5..d31a7ae2fe 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Beatmaps.Drawables { - public class BeatmapBackgroundSprite : Sprite + public partial class BeatmapBackgroundSprite : Sprite { private readonly IWorkingBeatmap working; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs b/osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs index 4dd3a56244..cf27023a9c 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapDownloadButton.cs @@ -18,7 +18,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Beatmaps.Drawables { - public class BeatmapDownloadButton : CompositeDrawable + public partial class BeatmapDownloadButton : CompositeDrawable { protected bool DownloadEnabled => button.Enabled.Value; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs index 23d90ab76e..c353b9e904 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapSetOnlineStatusPill.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables { - public class BeatmapSetOnlineStatusPill : CircularContainer, IHasTooltip + public partial class BeatmapSetOnlineStatusPill : CircularContainer, IHasTooltip { private BeatmapOnlineStatus status; diff --git a/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs b/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs index 053ac8fc17..21ab1b78ea 100644 --- a/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs +++ b/osu.Game/Beatmaps/Drawables/BundledBeatmapDownloader.cs @@ -21,7 +21,7 @@ using osu.Game.Utils; namespace osu.Game.Beatmaps.Drawables { - public class BundledBeatmapDownloader : CompositeDrawable + public partial class BundledBeatmapDownloader : CompositeDrawable { private readonly bool shouldPostNotifications; diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs index b9e0a4e6cb..00f9a6b3d5 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCard.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Beatmaps.Drawables.Cards { - public abstract class BeatmapCard : OsuClickableContainer + public abstract partial class BeatmapCard : OsuClickableContainer { public const float TRANSITION_DURATION = 400; public const float CORNER_RADIUS = 10; diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContent.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContent.cs index bfec391b1d..d4cbe6ddd0 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContent.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContent.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Beatmaps.Drawables.Cards { - public class BeatmapCardContent : CompositeDrawable + public partial class BeatmapCardContent : CompositeDrawable { public Drawable MainContent { diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContentBackground.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContentBackground.cs index 64a28c5394..deb56bb281 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContentBackground.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardContentBackground.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays; namespace osu.Game.Beatmaps.Drawables.Cards { - public class BeatmapCardContentBackground : CompositeDrawable + public partial class BeatmapCardContentBackground : CompositeDrawable { public BindableBool Dimmed { get; } = new BindableBool(); diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDifficultyList.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDifficultyList.cs index 9489116530..84445dc14c 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDifficultyList.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDifficultyList.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Beatmaps.Drawables.Cards { - public class BeatmapCardDifficultyList : CompositeDrawable + public partial class BeatmapCardDifficultyList : CompositeDrawable { public BeatmapCardDifficultyList(IBeatmapSetInfo beatmapSetInfo) { @@ -53,7 +53,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards } } - private class BeatmapCardDifficultyRow : CompositeDrawable + private partial class BeatmapCardDifficultyRow : CompositeDrawable { private readonly IBeatmapInfo beatmapInfo; diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDownloadProgressBar.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDownloadProgressBar.cs index d55622d7aa..3737715a7d 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDownloadProgressBar.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardDownloadProgressBar.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Beatmaps.Drawables.Cards { - public class BeatmapCardDownloadProgressBar : CompositeDrawable + public partial class BeatmapCardDownloadProgressBar : CompositeDrawable { public IBindable State => state; private readonly Bindable state = new Bindable(); diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs index 646c990564..5c6f0c4ee1 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs @@ -17,7 +17,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Beatmaps.Drawables.Cards { - public class BeatmapCardExtra : BeatmapCard + public partial class BeatmapCardExtra : BeatmapCard { protected override Drawable IdleContent => idleBottomContent; protected override Drawable DownloadInProgressContent => downloadProgressBar; diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtraInfoRow.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtraInfoRow.cs index 7ba677e5dc..3a1b8f7e86 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtraInfoRow.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtraInfoRow.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Beatmaps.Drawables.Cards { - public class BeatmapCardExtraInfoRow : CompositeDrawable + public partial class BeatmapCardExtraInfoRow : CompositeDrawable { [Resolved(CanBeNull = true)] private BeatmapCardContent? content { get; set; } diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs index addc88700c..720d892495 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardNormal.cs @@ -18,7 +18,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Beatmaps.Drawables.Cards { - public class BeatmapCardNormal : BeatmapCard + public partial class BeatmapCardNormal : BeatmapCard { protected override Drawable IdleContent => idleBottomContent; protected override Drawable DownloadInProgressContent => downloadProgressBar; diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardThumbnail.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardThumbnail.cs index 55d3f0b969..781133aac7 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardThumbnail.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardThumbnail.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables.Cards { - public class BeatmapCardThumbnail : Container + public partial class BeatmapCardThumbnail : Container { public BindableBool Dimmed { get; } = new BindableBool(); diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs index af1a8eb06a..ee45d56b6e 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/BeatmapCardIconButton.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { - public abstract class BeatmapCardIconButton : OsuClickableContainer + public abstract partial class BeatmapCardIconButton : OsuClickableContainer { private Colour4 idleColour; diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs index 1b15b2498c..7f23b46150 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/DownloadButton.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { - public class DownloadButton : BeatmapCardIconButton + public partial class DownloadButton : BeatmapCardIconButton { public Bindable State { get; } = new Bindable(); diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs index bc0fcb92bb..f698185863 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/FavouriteButton.cs @@ -15,7 +15,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { - public class FavouriteButton : BeatmapCardIconButton, IHasCurrentValue + public partial class FavouriteButton : BeatmapCardIconButton, IHasCurrentValue { private readonly BindableWithCurrent current; diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/GoToBeatmapButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/GoToBeatmapButton.cs index 127c5bd903..3df94bf233 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/GoToBeatmapButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/GoToBeatmapButton.cs @@ -10,7 +10,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { - public class GoToBeatmapButton : BeatmapCardIconButton + public partial class GoToBeatmapButton : BeatmapCardIconButton { public IBindable State => state; private readonly Bindable state = new Bindable(); diff --git a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs index c5436182a4..f808fd21b7 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Buttons/PlayButton.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Beatmaps.Drawables.Cards.Buttons { - public class PlayButton : OsuHoverContainer + public partial class PlayButton : OsuHoverContainer { public IBindable Progress => progress; private readonly BindableDouble progress = new BindableDouble(); diff --git a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs index 9b200d62aa..fe2ee8c7cc 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/CollapsibleButtonContainer.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Beatmaps.Drawables.Cards { - public class CollapsibleButtonContainer : Container + public partial class CollapsibleButtonContainer : Container { public Bindable ShowDetails = new Bindable(); public Bindable FavouriteState = new Bindable(); diff --git a/osu.Game/Beatmaps/Drawables/Cards/ExpandedContentScrollContainer.cs b/osu.Game/Beatmaps/Drawables/Cards/ExpandedContentScrollContainer.cs index c0ed6ac1a9..9a2a37a09a 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/ExpandedContentScrollContainer.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/ExpandedContentScrollContainer.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Beatmaps.Drawables.Cards { - public class ExpandedContentScrollContainer : OsuScrollContainer + public partial class ExpandedContentScrollContainer : OsuScrollContainer { public const float HEIGHT = 200; @@ -61,7 +61,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards protected override bool OnClick(ClickEvent e) => true; - private class ExpandedContentScrollbar : OsuScrollbar + private partial class ExpandedContentScrollbar : OsuScrollbar { public ExpandedContentScrollbar(Direction scrollDir) : base(scrollDir) diff --git a/osu.Game/Beatmaps/Drawables/Cards/HoverHandlingContainer.cs b/osu.Game/Beatmaps/Drawables/Cards/HoverHandlingContainer.cs index 7d70f3c4cd..91cd498b81 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/HoverHandlingContainer.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/HoverHandlingContainer.cs @@ -7,7 +7,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Beatmaps.Drawables.Cards { - public class HoverHandlingContainer : Container + public partial class HoverHandlingContainer : Container { public Func? Hovered { get; set; } public Action? Unhovered { get; set; } diff --git a/osu.Game/Beatmaps/Drawables/Cards/IconPill.cs b/osu.Game/Beatmaps/Drawables/Cards/IconPill.cs index aad71610a5..3cabbba98d 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/IconPill.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/IconPill.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables.Cards { - public abstract class IconPill : CircularContainer, IHasTooltip + public abstract partial class IconPill : CircularContainer, IHasTooltip { public Vector2 IconSize { diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs index f6fc3070aa..2948e89e60 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardDateStatistic.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics; namespace osu.Game.Beatmaps.Drawables.Cards.Statistics { - public class BeatmapCardDateStatistic : BeatmapCardStatistic + public partial class BeatmapCardDateStatistic : BeatmapCardStatistic { private readonly DateTimeOffset dateTime; diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs index 89a4687500..10de2b9128 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/BeatmapCardStatistic.cs @@ -19,7 +19,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Statistics /// /// A single statistic shown on a beatmap card. /// - public abstract class BeatmapCardStatistic : CompositeDrawable, IHasTooltip, IHasCustomTooltip + public abstract partial class BeatmapCardStatistic : CompositeDrawable, IHasTooltip, IHasCustomTooltip { protected IconUsage Icon { diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs index cef1f630ed..439e6acd22 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/FavouritesStatistic.cs @@ -15,7 +15,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Statistics /// /// Shows the number of favourites that a beatmap set has received. /// - public class FavouritesStatistic : BeatmapCardStatistic, IHasCurrentValue + public partial class FavouritesStatistic : BeatmapCardStatistic, IHasCurrentValue { private readonly BindableWithCurrent current; diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/HypesStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/HypesStatistic.cs index 26b90ba0c0..840763b58e 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/HypesStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/HypesStatistic.cs @@ -10,7 +10,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Statistics /// /// Shows the number of current hypes that a map has received, as well as the number of hypes required for nomination. /// - public class HypesStatistic : BeatmapCardStatistic + public partial class HypesStatistic : BeatmapCardStatistic { private HypesStatistic(BeatmapSetHypeStatus hypeStatus) { diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/NominationsStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/NominationsStatistic.cs index 4f3605c138..083f1a353b 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/NominationsStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/NominationsStatistic.cs @@ -10,7 +10,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Statistics /// /// Shows the number of current nominations that a map has received, as well as the number of nominations required for qualification. /// - public class NominationsStatistic : BeatmapCardStatistic + public partial class NominationsStatistic : BeatmapCardStatistic { private NominationsStatistic(BeatmapSetNominationStatus nominationStatus) { diff --git a/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs b/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs index f66d51de5d..45ab6ddb40 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/Statistics/PlayCountStatistic.cs @@ -13,7 +13,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Statistics /// /// Shows the number of times the given beatmap set has been played. /// - public class PlayCountStatistic : BeatmapCardStatistic + public partial class PlayCountStatistic : BeatmapCardStatistic { public PlayCountStatistic(IBeatmapSetOnlineInfo onlineInfo) { diff --git a/osu.Game/Beatmaps/Drawables/Cards/StoryboardIconPill.cs b/osu.Game/Beatmaps/Drawables/Cards/StoryboardIconPill.cs index dcb2c3c760..6de16da2b1 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/StoryboardIconPill.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/StoryboardIconPill.cs @@ -9,7 +9,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Beatmaps.Drawables.Cards { - public class StoryboardIconPill : IconPill + public partial class StoryboardIconPill : IconPill { public StoryboardIconPill() : base(FontAwesome.Solid.Image) diff --git a/osu.Game/Beatmaps/Drawables/Cards/VideoIconPill.cs b/osu.Game/Beatmaps/Drawables/Cards/VideoIconPill.cs index 9ca1e5c4c4..63b5e95b12 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/VideoIconPill.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/VideoIconPill.cs @@ -9,7 +9,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Beatmaps.Drawables.Cards { - public class VideoIconPill : IconPill + public partial class VideoIconPill : IconPill { public VideoIconPill() : base(FontAwesome.Solid.Film) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 679e9c3665..1665ec52fa 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables { - public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip, IHasCurrentValue + public partial class DifficultyIcon : CompositeDrawable, IHasCustomTooltip, IHasCurrentValue { /// /// Size of this difficulty icon. diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 4732de6e79..3fa24bcc3e 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Beatmaps.Drawables { - internal class DifficultyIconTooltip : VisibilityContainer, ITooltip + internal partial class DifficultyIconTooltip : VisibilityContainer, ITooltip { private OsuSpriteText difficultyName; private StarRatingDisplay starRating; diff --git a/osu.Game/Beatmaps/Drawables/DifficultySpectrumDisplay.cs b/osu.Game/Beatmaps/Drawables/DifficultySpectrumDisplay.cs index 22ca0a9037..efce0f80f1 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultySpectrumDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultySpectrumDisplay.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Beatmaps.Drawables { - public class DifficultySpectrumDisplay : CompositeDrawable + public partial class DifficultySpectrumDisplay : CompositeDrawable { private Vector2 dotSize = new Vector2(4, 8); @@ -83,7 +83,7 @@ namespace osu.Game.Beatmaps.Drawables } } - private class RulesetDifficultyGroup : FillFlowContainer + private partial class RulesetDifficultyGroup : FillFlowContainer { private readonly int rulesetId; private readonly IEnumerable beatmapInfos; @@ -143,7 +143,7 @@ namespace osu.Game.Beatmaps.Drawables } } - private class DifficultyDot : CircularContainer + private partial class DifficultyDot : CircularContainer { private readonly double starDifficulty; diff --git a/osu.Game/Beatmaps/Drawables/DownloadProgressBar.cs b/osu.Game/Beatmaps/Drawables/DownloadProgressBar.cs index 50bd7ad48e..9877b628db 100644 --- a/osu.Game/Beatmaps/Drawables/DownloadProgressBar.cs +++ b/osu.Game/Beatmaps/Drawables/DownloadProgressBar.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables { - public class DownloadProgressBar : CompositeDrawable + public partial class DownloadProgressBar : CompositeDrawable { private readonly ProgressBar progressBar; private readonly BeatmapDownloadTracker downloadTracker; diff --git a/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs index 063990c89c..e4ffc1d553 100644 --- a/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs +++ b/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Beatmaps.Drawables { [LongRunningLoad] - public class OnlineBeatmapSetCover : Sprite + public partial class OnlineBeatmapSetCover : Sprite { private readonly IBeatmapSetOnlineInfo set; private readonly BeatmapSetCoverType type; diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index 9585f1bdb5..36fff1dc3c 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -23,7 +23,7 @@ namespace osu.Game.Beatmaps.Drawables /// /// A pill that displays the star rating of a beatmap. /// - public class StarRatingDisplay : CompositeDrawable, IHasCurrentValue + public partial class StarRatingDisplay : CompositeDrawable, IHasCurrentValue { private readonly bool animated; private readonly Box background; diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs index f37771a74d..2cd9785048 100644 --- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs @@ -14,7 +14,7 @@ namespace osu.Game.Beatmaps.Drawables /// /// Display a beatmap background from a local source, but fallback to online source if not available. /// - public class UpdateableBeatmapBackgroundSprite : ModelBackedDrawable + public partial class UpdateableBeatmapBackgroundSprite : ModelBackedDrawable { public readonly Bindable Beatmap = new Bindable(); diff --git a/osu.Game/Beatmaps/Drawables/UpdateableOnlineBeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/UpdateableOnlineBeatmapSetCover.cs index 236bb63e24..93b0dd5c15 100644 --- a/osu.Game/Beatmaps/Drawables/UpdateableOnlineBeatmapSetCover.cs +++ b/osu.Game/Beatmaps/Drawables/UpdateableOnlineBeatmapSetCover.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics; namespace osu.Game.Beatmaps.Drawables { - public class UpdateableOnlineBeatmapSetCover : ModelBackedDrawable + public partial class UpdateableOnlineBeatmapSetCover : ModelBackedDrawable { private readonly BeatmapSetCoverType coverType; diff --git a/osu.Game/Beatmaps/FramedBeatmapClock.cs b/osu.Game/Beatmaps/FramedBeatmapClock.cs index c7050cc50f..080b0ce7ec 100644 --- a/osu.Game/Beatmaps/FramedBeatmapClock.cs +++ b/osu.Game/Beatmaps/FramedBeatmapClock.cs @@ -24,7 +24,7 @@ namespace osu.Game.Beatmaps /// - Exposes track length. /// - Allows changing the source to a new track (for cases like editor track updating). /// - public class FramedBeatmapClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock + public partial class FramedBeatmapClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock { private readonly bool applyOffsets; diff --git a/osu.Game/Collections/CollectionDropdown.cs b/osu.Game/Collections/CollectionDropdown.cs index f203d49900..19fa3a3d66 100644 --- a/osu.Game/Collections/CollectionDropdown.cs +++ b/osu.Game/Collections/CollectionDropdown.cs @@ -24,7 +24,7 @@ namespace osu.Game.Collections /// /// A dropdown to select the collection to be used to filter results. /// - public class CollectionDropdown : OsuDropdown + public partial class CollectionDropdown : OsuDropdown { /// /// Whether to show the "manage collections..." menu item in the dropdown. @@ -140,7 +140,7 @@ namespace osu.Game.Collections protected virtual CollectionDropdownMenu CreateCollectionMenu() => new CollectionDropdownMenu(); - public class CollectionDropdownHeader : OsuDropdownHeader + public partial class CollectionDropdownHeader : OsuDropdownHeader { public CollectionDropdownHeader() { @@ -150,7 +150,7 @@ namespace osu.Game.Collections } } - protected class CollectionDropdownMenu : OsuDropdownMenu + protected partial class CollectionDropdownMenu : OsuDropdownMenu { public CollectionDropdownMenu() { @@ -164,7 +164,7 @@ namespace osu.Game.Collections }; } - protected class CollectionDropdownDrawableMenuItem : OsuDropdownMenu.DrawableOsuDropdownMenuItem + protected partial class CollectionDropdownDrawableMenuItem : OsuDropdownMenu.DrawableOsuDropdownMenuItem { private IconButton addOrRemoveButton = null!; diff --git a/osu.Game/Collections/DeleteCollectionDialog.cs b/osu.Game/Collections/DeleteCollectionDialog.cs index bf187265c1..4b23f661f9 100644 --- a/osu.Game/Collections/DeleteCollectionDialog.cs +++ b/osu.Game/Collections/DeleteCollectionDialog.cs @@ -8,7 +8,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Collections { - public class DeleteCollectionDialog : DeleteConfirmationDialog + public partial class DeleteCollectionDialog : DeleteConfirmationDialog { public DeleteCollectionDialog(Live collection, Action deleteAction) { diff --git a/osu.Game/Collections/DrawableCollectionList.cs b/osu.Game/Collections/DrawableCollectionList.cs index 0f4362fff3..0fdf196c4a 100644 --- a/osu.Game/Collections/DrawableCollectionList.cs +++ b/osu.Game/Collections/DrawableCollectionList.cs @@ -18,7 +18,7 @@ namespace osu.Game.Collections /// /// Visualises a list of s. /// - public class DrawableCollectionList : OsuRearrangeableListContainer> + public partial class DrawableCollectionList : OsuRearrangeableListContainer> { protected override ScrollContainer CreateScrollContainer() => scroll = new Scroll(); @@ -68,7 +68,7 @@ namespace osu.Game.Collections /// /// Use to transfer the placeholder into the main list. /// - private class Scroll : OsuScrollContainer + private partial class Scroll : OsuScrollContainer { /// /// The currently-displayed placeholder item. @@ -132,7 +132,7 @@ namespace osu.Game.Collections /// /// The flow of . Disables layout easing unless a drag is in progress. /// - private class Flow : FillFlowContainer>> + private partial class Flow : FillFlowContainer>> { public readonly IBindable DragActive = new Bindable(); diff --git a/osu.Game/Collections/DrawableCollectionListItem.cs b/osu.Game/Collections/DrawableCollectionListItem.cs index d1e40f6262..23156b1ad5 100644 --- a/osu.Game/Collections/DrawableCollectionListItem.cs +++ b/osu.Game/Collections/DrawableCollectionListItem.cs @@ -23,7 +23,7 @@ namespace osu.Game.Collections /// /// Visualises a inside a . /// - public class DrawableCollectionListItem : OsuRearrangeableListItem> + public partial class DrawableCollectionListItem : OsuRearrangeableListItem> { private const float item_height = 35; private const float button_width = item_height * 0.75f; @@ -44,7 +44,7 @@ namespace osu.Game.Collections /// /// The main content of the . /// - private class ItemContent : CircularContainer + private partial class ItemContent : CircularContainer { private readonly Live collection; @@ -113,7 +113,7 @@ namespace osu.Game.Collections } } - private class ItemTextBox : OsuTextBox + private partial class ItemTextBox : OsuTextBox { protected override float LeftRightPadding => item_height / 2; @@ -125,7 +125,7 @@ namespace osu.Game.Collections } } - public class DeleteButton : CompositeDrawable + public partial class DeleteButton : CompositeDrawable { public Func IsTextBoxHovered = null!; diff --git a/osu.Game/Collections/ManageCollectionsDialog.cs b/osu.Game/Collections/ManageCollectionsDialog.cs index 13737dbd78..36142cf26f 100644 --- a/osu.Game/Collections/ManageCollectionsDialog.cs +++ b/osu.Game/Collections/ManageCollectionsDialog.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Collections { - public class ManageCollectionsDialog : OsuFocusedOverlayContainer + public partial class ManageCollectionsDialog : OsuFocusedOverlayContainer { private const double enter_duration = 500; private const double exit_duration = 200; diff --git a/osu.Game/Configuration/SettingSourceAttribute.cs b/osu.Game/Configuration/SettingSourceAttribute.cs index 630b65ae82..043bba3134 100644 --- a/osu.Game/Configuration/SettingSourceAttribute.cs +++ b/osu.Game/Configuration/SettingSourceAttribute.cs @@ -107,7 +107,7 @@ namespace osu.Game.Configuration } } - public static class SettingSourceExtensions + public static partial class SettingSourceExtensions { public static IEnumerable CreateSettingsControls(this object obj) { @@ -267,12 +267,12 @@ namespace osu.Game.Configuration .OrderBy(attr => attr.Item1) .ToArray(); - private class ModSettingsEnumDropdown : SettingsEnumDropdown + private partial class ModSettingsEnumDropdown : SettingsEnumDropdown where T : struct, Enum { protected override OsuDropdown CreateDropdown() => new ModDropdownControl(); - private class ModDropdownControl : DropdownControl + private partial class ModDropdownControl : DropdownControl { // Set menu's max height low enough to workaround nested scroll issues (see https://github.com/ppy/osu-framework/issues/4536). protected override DropdownMenu CreateMenu() => base.CreateMenu().With(m => m.MaxHeight = 100); diff --git a/osu.Game/Database/BeatmapLookupCache.cs b/osu.Game/Database/BeatmapLookupCache.cs index 53cb7d72fc..d9bf0138dc 100644 --- a/osu.Game/Database/BeatmapLookupCache.cs +++ b/osu.Game/Database/BeatmapLookupCache.cs @@ -13,7 +13,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Database { - public class BeatmapLookupCache : OnlineLookupCache + public partial class BeatmapLookupCache : OnlineLookupCache { /// /// Perform an API lookup on the specified beatmap, populating a model. diff --git a/osu.Game/Database/ImportProgressNotification.cs b/osu.Game/Database/ImportProgressNotification.cs index aaee3e117f..762918f376 100644 --- a/osu.Game/Database/ImportProgressNotification.cs +++ b/osu.Game/Database/ImportProgressNotification.cs @@ -5,7 +5,7 @@ using osu.Game.Overlays.Notifications; namespace osu.Game.Database { - public class ImportProgressNotification : ProgressNotification + public partial class ImportProgressNotification : ProgressNotification { public ImportProgressNotification() { diff --git a/osu.Game/Database/LegacyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs index 78ebd8750e..901b953bf2 100644 --- a/osu.Game/Database/LegacyImportManager.cs +++ b/osu.Game/Database/LegacyImportManager.cs @@ -22,7 +22,7 @@ namespace osu.Game.Database /// /// Handles migration of legacy user data from osu-stable. /// - public class LegacyImportManager : Component + public partial class LegacyImportManager : Component { [Resolved] private SkinManager skins { get; set; } = null!; diff --git a/osu.Game/Database/MemoryCachingComponent.cs b/osu.Game/Database/MemoryCachingComponent.cs index 571a9ccc7c..5d1a381f09 100644 --- a/osu.Game/Database/MemoryCachingComponent.cs +++ b/osu.Game/Database/MemoryCachingComponent.cs @@ -18,7 +18,7 @@ namespace osu.Game.Database /// A component which performs lookups (or calculations) and caches the results. /// Currently not persisted between game sessions. /// - public abstract class MemoryCachingComponent : Component + public abstract partial class MemoryCachingComponent : Component { private readonly ConcurrentDictionary cache = new ConcurrentDictionary(); diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index 6cba8fe819..3e2d034937 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays.Notifications; namespace osu.Game.Database { - public abstract class ModelDownloader : IModelDownloader + public abstract partial class ModelDownloader : IModelDownloader where TModel : class, IHasGuidPrimaryKey, ISoftDelete, IEquatable, T where T : class { @@ -124,7 +124,7 @@ namespace osu.Game.Database private bool canDownload(T model) => GetExistingDownload(model) == null && api != null; - private class DownloadNotification : ProgressNotification + private partial class DownloadNotification : ProgressNotification { public override bool IsImportant => false; @@ -134,7 +134,7 @@ namespace osu.Game.Database Text = CompletionText }; - private class SilencedProgressCompletionNotification : ProgressCompletionNotification + private partial class SilencedProgressCompletionNotification : ProgressCompletionNotification { public override bool IsImportant => false; } diff --git a/osu.Game/Database/OnlineLookupCache.cs b/osu.Game/Database/OnlineLookupCache.cs index 317c37bbfb..d9b37e2f29 100644 --- a/osu.Game/Database/OnlineLookupCache.cs +++ b/osu.Game/Database/OnlineLookupCache.cs @@ -15,7 +15,7 @@ using osu.Game.Online.API; namespace osu.Game.Database { - public abstract class OnlineLookupCache : MemoryCachingComponent + public abstract partial class OnlineLookupCache : MemoryCachingComponent where TLookup : IEquatable where TValue : class, IHasOnlineID where TRequest : APIRequest diff --git a/osu.Game/Database/TooManyDownloadsNotification.cs b/osu.Game/Database/TooManyDownloadsNotification.cs index 14012e1d34..92e9a73026 100644 --- a/osu.Game/Database/TooManyDownloadsNotification.cs +++ b/osu.Game/Database/TooManyDownloadsNotification.cs @@ -9,7 +9,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Database { - public class TooManyDownloadsNotification : SimpleNotification + public partial class TooManyDownloadsNotification : SimpleNotification { public TooManyDownloadsNotification() { diff --git a/osu.Game/Database/UserLookupCache.cs b/osu.Game/Database/UserLookupCache.cs index 87f08d36ae..b1609fbf7b 100644 --- a/osu.Game/Database/UserLookupCache.cs +++ b/osu.Game/Database/UserLookupCache.cs @@ -13,7 +13,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Database { - public class UserLookupCache : OnlineLookupCache + public partial class UserLookupCache : OnlineLookupCache { /// /// Perform an API lookup on the specified user, populating a model. diff --git a/osu.Game/Graphics/Backgrounds/Background.cs b/osu.Game/Graphics/Backgrounds/Background.cs index 0899c0706d..bc2ad81fef 100644 --- a/osu.Game/Graphics/Backgrounds/Background.cs +++ b/osu.Game/Graphics/Backgrounds/Background.cs @@ -18,7 +18,7 @@ namespace osu.Game.Graphics.Backgrounds /// /// A background which offers blurring via a on demand. /// - public class Background : CompositeDrawable, IEquatable + public partial class Background : CompositeDrawable, IEquatable { public readonly Sprite Sprite; diff --git a/osu.Game/Graphics/Backgrounds/BeatmapBackground.cs b/osu.Game/Graphics/Backgrounds/BeatmapBackground.cs index 543bfe2bac..b79eb4927f 100644 --- a/osu.Game/Graphics/Backgrounds/BeatmapBackground.cs +++ b/osu.Game/Graphics/Backgrounds/BeatmapBackground.cs @@ -9,7 +9,7 @@ using osu.Game.Beatmaps; namespace osu.Game.Graphics.Backgrounds { - public class BeatmapBackground : Background + public partial class BeatmapBackground : Background { public readonly WorkingBeatmap Beatmap; diff --git a/osu.Game/Graphics/Backgrounds/BeatmapBackgroundWithStoryboard.cs b/osu.Game/Graphics/Backgrounds/BeatmapBackgroundWithStoryboard.cs index 0dcfa4e9aa..9c0d109ce4 100644 --- a/osu.Game/Graphics/Backgrounds/BeatmapBackgroundWithStoryboard.cs +++ b/osu.Game/Graphics/Backgrounds/BeatmapBackgroundWithStoryboard.cs @@ -14,7 +14,7 @@ using osu.Game.Storyboards.Drawables; namespace osu.Game.Graphics.Backgrounds { - public class BeatmapBackgroundWithStoryboard : BeatmapBackground + public partial class BeatmapBackgroundWithStoryboard : BeatmapBackground { private readonly InterpolatingFramedClock storyboardClock; diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index 9d873762bf..6f6febb646 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -17,7 +17,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Graphics.Backgrounds { - public class SeasonalBackgroundLoader : Component + public partial class SeasonalBackgroundLoader : Component { /// /// Fired when background should be changed due to receiving backgrounds from API @@ -97,7 +97,7 @@ namespace osu.Game.Graphics.Backgrounds } [LongRunningLoad] - public class SeasonalBackground : Background + public partial class SeasonalBackground : Background { private readonly string url; private const string fallback_texture_name = @"Backgrounds/bg1"; diff --git a/osu.Game/Graphics/Backgrounds/SkinBackground.cs b/osu.Game/Graphics/Backgrounds/SkinBackground.cs index e4bf3b94c5..e30bb961a0 100644 --- a/osu.Game/Graphics/Backgrounds/SkinBackground.cs +++ b/osu.Game/Graphics/Backgrounds/SkinBackground.cs @@ -8,7 +8,7 @@ using osu.Game.Skinning; namespace osu.Game.Graphics.Backgrounds { - internal class SkinBackground : Background + internal partial class SkinBackground : Background { private readonly Skin skin; diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 09d137011c..94397f7ffb 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -21,7 +21,7 @@ using osu.Framework.Bindables; namespace osu.Game.Graphics.Backgrounds { - public class Triangles : Drawable + public partial class Triangles : Drawable { private const float triangle_size = 100; private const float base_velocity = 50; diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 00fea601c6..724005a0cc 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Graphics.Containers /// /// This container will also trigger beat events when the beat matching clock is paused at 's BPM. /// - public class BeatSyncedContainer : Container + public partial class BeatSyncedContainer : Container { private int lastBeat; diff --git a/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs b/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs index f34a856707..55160e14af 100644 --- a/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs +++ b/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs @@ -14,7 +14,7 @@ namespace osu.Game.Graphics.Containers /// /// Display an icon that is forced to scale to the size of this container. /// - public class ConstrainedIconContainer : CompositeDrawable + public partial class ConstrainedIconContainer : CompositeDrawable { public Drawable Icon { diff --git a/osu.Game/Graphics/Containers/ExpandingButtonContainer.cs b/osu.Game/Graphics/Containers/ExpandingButtonContainer.cs index f66afb27c4..a06af61125 100644 --- a/osu.Game/Graphics/Containers/ExpandingButtonContainer.cs +++ b/osu.Game/Graphics/Containers/ExpandingButtonContainer.cs @@ -11,7 +11,7 @@ namespace osu.Game.Graphics.Containers /// /// Mostly used for buttons with explanatory labels, in which the label would display after a "long hover". /// - public class ExpandingButtonContainer : ExpandingContainer + public partial class ExpandingButtonContainer : ExpandingContainer { protected ExpandingButtonContainer(float contractedWidth, float expandedWidth) : base(contractedWidth, expandedWidth) diff --git a/osu.Game/Graphics/Containers/ExpandingContainer.cs b/osu.Game/Graphics/Containers/ExpandingContainer.cs index debc068220..60b9e6a167 100644 --- a/osu.Game/Graphics/Containers/ExpandingContainer.cs +++ b/osu.Game/Graphics/Containers/ExpandingContainer.cs @@ -14,7 +14,7 @@ namespace osu.Game.Graphics.Containers /// /// Represents a with the ability to expand/contract on hover. /// - public class ExpandingContainer : Container, IExpandingContainer + public partial class ExpandingContainer : Container, IExpandingContainer { private readonly float contractedWidth; private readonly float expandedWidth; diff --git a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs index 7d38478b81..cbe327bac7 100644 --- a/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs +++ b/osu.Game/Graphics/Containers/HoldToConfirmContainer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Graphics.Containers /// The is exposed as a transforming bindable which smoothly tracks the progress of a hold operation. /// It can be used for animating and displaying progress directly. /// - public abstract class HoldToConfirmContainer : Container + public abstract partial class HoldToConfirmContainer : Container { public const double DANGEROUS_HOLD_ACTIVATION_DELAY = 500; diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index bf96695fd3..2d27ce906b 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -18,7 +18,7 @@ using osu.Game.Users; namespace osu.Game.Graphics.Containers { - public class LinkFlowContainer : OsuTextFlowContainer + public partial class LinkFlowContainer : OsuTextFlowContainer { public LinkFlowContainer(Action defaultCreationParameters = null) : base(defaultCreationParameters) diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index bf8d70a200..735b8b4e7d 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.Containers /// /// A container that handles tracking of an through different layout scenarios. /// - public class LogoTrackingContainer : Container + public partial class LogoTrackingContainer : Container { public Facade LogoFacade => facade; @@ -131,7 +131,7 @@ namespace osu.Game.Graphics.Containers base.Dispose(isDisposing); } - private class InternalFacade : Facade + private partial class InternalFacade : Facade { public new void SetSize(Vector2 size) { @@ -142,7 +142,7 @@ namespace osu.Game.Graphics.Containers /// /// A dummy object used to denote another object's location. /// - public abstract class Facade : Drawable + public abstract partial class Facade : Drawable { public override Vector2 Size { diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs index 3855ed6d4e..e884b5db69 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs @@ -19,7 +19,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownContainer : MarkdownContainer + public partial class OsuMarkdownContainer : MarkdownContainer { /// /// Allows this markdown container to parse and link footnotes. diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownFencedCodeBlock.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownFencedCodeBlock.cs index fc7401046f..b5bbe3e2cc 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownFencedCodeBlock.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownFencedCodeBlock.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownFencedCodeBlock : MarkdownFencedCodeBlock + public partial class OsuMarkdownFencedCodeBlock : MarkdownFencedCodeBlock { // TODO : change to monospace font for this component public OsuMarkdownFencedCodeBlock(FencedCodeBlock fencedCodeBlock) @@ -24,7 +24,7 @@ namespace osu.Game.Graphics.Containers.Markdown public override MarkdownTextFlowContainer CreateTextFlow() => new CodeBlockTextFlowContainer(); - private class CodeBlockBackground : Box + private partial class CodeBlockBackground : Box { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -34,7 +34,7 @@ namespace osu.Game.Graphics.Containers.Markdown } } - private class CodeBlockTextFlowContainer : OsuMarkdownTextFlowContainer + private partial class CodeBlockTextFlowContainer : OsuMarkdownTextFlowContainer { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownHeading.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownHeading.cs index 0c70952222..800a0e1fc3 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownHeading.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownHeading.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownHeading : MarkdownHeading + public partial class OsuMarkdownHeading : MarkdownHeading { private readonly int level; @@ -66,7 +66,7 @@ namespace osu.Game.Graphics.Containers.Markdown } } - private class HeadingTextFlowContainer : OsuMarkdownTextFlowContainer + private partial class HeadingTextFlowContainer : OsuMarkdownTextFlowContainer { public float FontSize; public FontWeight FontWeight; diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs index 9ad501fdff..8ccac158eb 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownImage.cs @@ -10,7 +10,7 @@ using osu.Framework.Localisation; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownImage : MarkdownImage, IHasTooltip + public partial class OsuMarkdownImage : MarkdownImage, IHasTooltip { public LocalisableString TooltipText { get; } diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownLinkText.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownLinkText.cs index 3a16eb0a0f..0049feca02 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownLinkText.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownLinkText.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownLinkText : MarkdownLinkText + public partial class OsuMarkdownLinkText : MarkdownLinkText { [Resolved(canBeNull: true)] private ILinkHandler linkHandler { get; set; } @@ -54,7 +54,7 @@ namespace osu.Game.Graphics.Containers.Markdown protected override void OnLinkPressed() => linkHandler?.HandleLink(Url); - private class OsuMarkdownLinkCompiler : DrawableLinkCompiler + private partial class OsuMarkdownLinkCompiler : DrawableLinkCompiler { public OsuMarkdownLinkCompiler(IEnumerable parts) : base(parts) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownListItem.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownListItem.cs index 153c4f9f93..2d38e44d32 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownListItem.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownListItem.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Graphics.Containers.Markdown { - public abstract class OsuMarkdownListItem : CompositeDrawable + public abstract partial class OsuMarkdownListItem : CompositeDrawable { [Resolved] private IMarkdownTextComponent parentTextComponent { get; set; } diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownOrderedListItem.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownOrderedListItem.cs index 116a8e2872..6eac9378ae 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownOrderedListItem.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownOrderedListItem.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownOrderedListItem : OsuMarkdownListItem + public partial class OsuMarkdownOrderedListItem : OsuMarkdownListItem { private const float left_padding = 30; diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownQuoteBlock.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownQuoteBlock.cs index 3ef67df7a9..447085a48c 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownQuoteBlock.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownQuoteBlock.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownQuoteBlock : MarkdownQuoteBlock + public partial class OsuMarkdownQuoteBlock : MarkdownQuoteBlock { public OsuMarkdownQuoteBlock(QuoteBlock quoteBlock) : base(quoteBlock) @@ -30,7 +30,7 @@ namespace osu.Game.Graphics.Containers.Markdown }); } - private class QuoteBackground : Box + private partial class QuoteBackground : Box { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownSeparator.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownSeparator.cs index abbc10a7e2..343a1d1015 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownSeparator.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownSeparator.cs @@ -11,11 +11,11 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownSeparator : MarkdownSeparator + public partial class OsuMarkdownSeparator : MarkdownSeparator { protected override Drawable CreateSeparator() => new Separator(); - private class Separator : Box + private partial class Separator : Box { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTable.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTable.cs index ee851045f9..c9c1098e05 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTable.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTable.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers.Markdown; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownTable : MarkdownTable + public partial class OsuMarkdownTable : MarkdownTable { public OsuMarkdownTable(Table table) : base(table) diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTableCell.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTableCell.cs index 3863beb133..dbf15a2546 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTableCell.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTableCell.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownTableCell : MarkdownTableCell + public partial class OsuMarkdownTableCell : MarkdownTableCell { private readonly bool isHeading; @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.Containers.Markdown return new TableBodyBorder(); } - private class TableHeadBorder : Box + private partial class TableHeadBorder : Box { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -58,7 +58,7 @@ namespace osu.Game.Graphics.Containers.Markdown } } - private class TableBodyBorder : Box + private partial class TableBodyBorder : Box { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -69,7 +69,7 @@ namespace osu.Game.Graphics.Containers.Markdown } } - private class TableCellTextFlowContainer : OsuMarkdownTextFlowContainer + private partial class TableCellTextFlowContainer : OsuMarkdownTextFlowContainer { public FontWeight Weight { get; set; } diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs index 9d7b47281f..7de63fe09c 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownTextFlowContainer : MarkdownTextFlowContainer + public partial class OsuMarkdownTextFlowContainer : MarkdownTextFlowContainer { protected override void AddLinkText(string text, LinkInline linkInline) => AddDrawable(new OsuMarkdownLinkText(text, linkInline)); @@ -64,7 +64,7 @@ namespace osu.Game.Graphics.Containers.Markdown AddDrawable(new DrawableFlag(countryCode) { Size = new Vector2(20, 15) }); } - private class OsuMarkdownInlineCode : Container + private partial class OsuMarkdownInlineCode : Container { [Resolved] private IMarkdownTextComponent parentTextComponent { get; set; } diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownUnorderedListItem.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownUnorderedListItem.cs index f8e8571557..64e98511c2 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownUnorderedListItem.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownUnorderedListItem.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.Containers.Markdown { - public class OsuMarkdownUnorderedListItem : OsuMarkdownListItem + public partial class OsuMarkdownUnorderedListItem : OsuMarkdownListItem { private const float left_padding = 20; diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index 03a1cfcc13..4729ddf1a8 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.Containers { - public class OsuClickableContainer : ClickableContainer, IHasTooltip + public partial class OsuClickableContainer : ClickableContainer, IHasTooltip { private readonly HoverSampleSet sampleSet; diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index e8a0c0cd25..740c170f8f 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -18,7 +18,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.Containers { [Cached(typeof(IPreviewTrackOwner))] - public abstract class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler + public abstract partial class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler { private Sample samplePopIn; private Sample samplePopOut; diff --git a/osu.Game/Graphics/Containers/OsuHoverContainer.cs b/osu.Game/Graphics/Containers/OsuHoverContainer.cs index 93205e0d03..b4b80f7574 100644 --- a/osu.Game/Graphics/Containers/OsuHoverContainer.cs +++ b/osu.Game/Graphics/Containers/OsuHoverContainer.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.Containers { - public class OsuHoverContainer : OsuClickableContainer + public partial class OsuHoverContainer : OsuClickableContainer { protected const float FADE_DURATION = 500; diff --git a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs index b604ae73eb..fcc48d80ea 100644 --- a/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs +++ b/osu.Game/Graphics/Containers/OsuRearrangeableListContainer.cs @@ -14,7 +14,7 @@ using osu.Framework.Utils; namespace osu.Game.Graphics.Containers { - public abstract class OsuRearrangeableListContainer : RearrangeableListContainer + public abstract partial class OsuRearrangeableListContainer : RearrangeableListContainer { /// /// Whether any item is currently being dragged. Used to hide other items' drag handles. diff --git a/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs b/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs index e6183ea837..39a3edb82c 100644 --- a/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs +++ b/osu.Game/Graphics/Containers/OsuRearrangeableListItem.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.Containers { - public abstract class OsuRearrangeableListItem : RearrangeableListItem + public abstract partial class OsuRearrangeableListItem : RearrangeableListItem { public const float FADE_DURATION = 100; @@ -129,7 +129,7 @@ namespace osu.Game.Graphics.Containers protected abstract Drawable CreateContent(); - public class PlaylistItemHandle : SpriteIcon + public partial class PlaylistItemHandle : SpriteIcon { public bool HandlingDrag { get; private set; } private bool isHovering; diff --git a/osu.Game/Graphics/Containers/OsuScrollContainer.cs b/osu.Game/Graphics/Containers/OsuScrollContainer.cs index 7e5d5e53d3..e39fd45a16 100644 --- a/osu.Game/Graphics/Containers/OsuScrollContainer.cs +++ b/osu.Game/Graphics/Containers/OsuScrollContainer.cs @@ -14,7 +14,7 @@ using osuTK.Input; namespace osu.Game.Graphics.Containers { - public class OsuScrollContainer : OsuScrollContainer + public partial class OsuScrollContainer : OsuScrollContainer { public OsuScrollContainer() { @@ -26,7 +26,7 @@ namespace osu.Game.Graphics.Containers } } - public class OsuScrollContainer : ScrollContainer where T : Drawable + public partial class OsuScrollContainer : ScrollContainer where T : Drawable { public const float SCROLL_BAR_HEIGHT = 10; public const float SCROLL_BAR_PADDING = 3; @@ -131,7 +131,7 @@ namespace osu.Game.Graphics.Containers protected override ScrollbarContainer CreateScrollbar(Direction direction) => new OsuScrollbar(direction); - protected class OsuScrollbar : ScrollbarContainer + protected partial class OsuScrollbar : ScrollbarContainer { private Color4 hoverColour; private Color4 defaultColour; diff --git a/osu.Game/Graphics/Containers/OsuTextFlowContainer.cs b/osu.Game/Graphics/Containers/OsuTextFlowContainer.cs index 5cdccee01d..d3bbc2e80b 100644 --- a/osu.Game/Graphics/Containers/OsuTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/OsuTextFlowContainer.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.Containers { - public class OsuTextFlowContainer : TextFlowContainer + public partial class OsuTextFlowContainer : TextFlowContainer { public OsuTextFlowContainer(Action defaultCreationParameters = null) : base(defaultCreationParameters) diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs index f70abc16dd..3893413f61 100644 --- a/osu.Game/Graphics/Containers/ParallaxContainer.cs +++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs @@ -15,7 +15,7 @@ using osu.Framework.Utils; namespace osu.Game.Graphics.Containers { - public class ParallaxContainer : Container, IRequireHighFrequencyMousePosition + public partial class ParallaxContainer : Container, IRequireHighFrequencyMousePosition { public const float DEFAULT_PARALLAX_AMOUNT = 0.02f; diff --git a/osu.Game/Graphics/Containers/ReverseChildIDFillFlowContainer.cs b/osu.Game/Graphics/Containers/ReverseChildIDFillFlowContainer.cs index db265d6d64..e37d23fe97 100644 --- a/osu.Game/Graphics/Containers/ReverseChildIDFillFlowContainer.cs +++ b/osu.Game/Graphics/Containers/ReverseChildIDFillFlowContainer.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Graphics.Containers { - public class ReverseChildIDFillFlowContainer : FillFlowContainer where T : Drawable + public partial class ReverseChildIDFillFlowContainer : FillFlowContainer where T : Drawable { protected override int Compare(Drawable x, Drawable y) => CompareReverseChildID(x, y); } diff --git a/osu.Game/Graphics/Containers/ScalingContainer.cs b/osu.Game/Graphics/Containers/ScalingContainer.cs index 11e57d4be3..fb5c3e3b60 100644 --- a/osu.Game/Graphics/Containers/ScalingContainer.cs +++ b/osu.Game/Graphics/Containers/ScalingContainer.cs @@ -21,7 +21,7 @@ namespace osu.Game.Graphics.Containers /// /// Handles user-defined scaling, allowing application at multiple levels defined by . /// - public class ScalingContainer : Container + public partial class ScalingContainer : Container { internal const float TRANSITION_DURATION = 500; @@ -82,7 +82,7 @@ namespace osu.Game.Graphics.Containers }; } - public class ScalingDrawSizePreservingFillContainer : DrawSizePreservingFillContainer + public partial class ScalingDrawSizePreservingFillContainer : DrawSizePreservingFillContainer { private readonly bool applyUIScale; private Bindable uiScale; @@ -211,7 +211,7 @@ namespace osu.Game.Graphics.Containers .OnComplete(_ => { sizableContainer.Masking = requiresMasking; }); } - private class ScalingBackgroundScreen : BackgroundScreenDefault + private partial class ScalingBackgroundScreen : BackgroundScreenDefault { protected override bool AllowStoryboardBackground => false; @@ -221,7 +221,7 @@ namespace osu.Game.Graphics.Containers } } - private class SizeableAlwaysInputContainer : Container + private partial class SizeableAlwaysInputContainer : Container { [Resolved] private GameHost host { get; set; } diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 97e9ff88b5..123589c552 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -20,7 +20,7 @@ namespace osu.Game.Graphics.Containers /// A container that can scroll to each section inside it. /// [Cached] - public class SectionsContainer : Container + public partial class SectionsContainer : Container where T : Drawable { public Bindable SelectedSection { get; } = new Bindable(); diff --git a/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs b/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs index 2667b8b8e0..62544c6111 100644 --- a/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs +++ b/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs @@ -16,7 +16,7 @@ namespace osu.Game.Graphics.Containers /// A FillFlowContainer that provides functionality to cycle selection between children /// The selection wraps around when overflowing past the first or last child. /// - public class SelectionCycleFillFlowContainer : FillFlowContainer where T : Drawable, IStateful + public partial class SelectionCycleFillFlowContainer : FillFlowContainer where T : Drawable, IStateful { public T Selected => (selectedIndex >= 0 && selectedIndex < Count) ? this[selectedIndex.Value] : null; diff --git a/osu.Game/Graphics/Containers/ShakeContainer.cs b/osu.Game/Graphics/Containers/ShakeContainer.cs index 7b6fc22cc0..9a1ddac40d 100644 --- a/osu.Game/Graphics/Containers/ShakeContainer.cs +++ b/osu.Game/Graphics/Containers/ShakeContainer.cs @@ -11,7 +11,7 @@ namespace osu.Game.Graphics.Containers /// /// A container that adds the ability to shake its contents. /// - public class ShakeContainer : Container + public partial class ShakeContainer : Container { /// /// The length of a single shake. diff --git a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs index 300b5bd4b4..38ab6deb97 100644 --- a/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs +++ b/osu.Game/Graphics/Containers/UprightAspectMaintainingContainer.cs @@ -12,7 +12,7 @@ namespace osu.Game.Graphics.Containers /// /// A container that reverts any rotation (and optionally scale) applied by its direct parent. /// - public class UprightAspectMaintainingContainer : Container + public partial class UprightAspectMaintainingContainer : Container { /// /// Controls how much this container scales compared to its parent (default is 1.0f). diff --git a/osu.Game/Graphics/Containers/UserDimContainer.cs b/osu.Game/Graphics/Containers/UserDimContainer.cs index 0b20159190..25830c9d54 100644 --- a/osu.Game/Graphics/Containers/UserDimContainer.cs +++ b/osu.Game/Graphics/Containers/UserDimContainer.cs @@ -14,7 +14,7 @@ namespace osu.Game.Graphics.Containers /// /// A container that applies user-configured visual settings to its contents. /// - public abstract class UserDimContainer : Container + public abstract partial class UserDimContainer : Container { /// /// Amount of lightening to apply to current dim level during break times. diff --git a/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs b/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs index 2bb9d7261d..715677aec1 100644 --- a/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs +++ b/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; namespace osu.Game.Graphics.Containers { - public class UserTrackingScrollContainer : UserTrackingScrollContainer + public partial class UserTrackingScrollContainer : UserTrackingScrollContainer { public UserTrackingScrollContainer() { @@ -19,7 +19,7 @@ namespace osu.Game.Graphics.Containers } } - public class UserTrackingScrollContainer : OsuScrollContainer + public partial class UserTrackingScrollContainer : OsuScrollContainer where T : Drawable { /// diff --git a/osu.Game/Graphics/Containers/WaveContainer.cs b/osu.Game/Graphics/Containers/WaveContainer.cs index ba85ef0aab..952ef3f182 100644 --- a/osu.Game/Graphics/Containers/WaveContainer.cs +++ b/osu.Game/Graphics/Containers/WaveContainer.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.Containers { - public class WaveContainer : VisibilityContainer + public partial class WaveContainer : VisibilityContainer { public const float APPEAR_DURATION = 800; public const float DISAPPEAR_DURATION = 500; @@ -131,7 +131,7 @@ namespace osu.Game.Graphics.Containers wavesContainer.Height = Math.Max(0, DrawHeight - (contentContainer.DrawHeight - contentContainer.Y * DrawHeight)); } - private class Wave : VisibilityContainer + private partial class Wave : VisibilityContainer { public float FinalPosition; diff --git a/osu.Game/Graphics/Cursor/GlobalCursorDisplay.cs b/osu.Game/Graphics/Cursor/GlobalCursorDisplay.cs index f5429723be..85a2d68e55 100644 --- a/osu.Game/Graphics/Cursor/GlobalCursorDisplay.cs +++ b/osu.Game/Graphics/Cursor/GlobalCursorDisplay.cs @@ -16,7 +16,7 @@ namespace osu.Game.Graphics.Cursor /// A container which provides the main . /// Also handles cases where a more localised cursor is provided by another component (via ). /// - public class GlobalCursorDisplay : Container, IProvideCursor + public partial class GlobalCursorDisplay : Container, IProvideCursor { /// /// Control whether any cursor should be displayed. diff --git a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs index adc0f81daf..b63e73e679 100644 --- a/osu.Game/Graphics/Cursor/MenuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/MenuCursorContainer.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Graphics.Cursor { - public class MenuCursorContainer : CursorContainer + public partial class MenuCursorContainer : CursorContainer { private readonly IBindable screenshotCursorVisibility = new Bindable(true); public override bool IsPresent => screenshotCursorVisibility.Value && base.IsPresent; @@ -241,7 +241,7 @@ namespace osu.Game.Graphics.Cursor channel.Play(); } - public class Cursor : Container + public partial class Cursor : Container { private Container cursorContainer = null!; private Bindable cursorScale = null!; @@ -284,7 +284,7 @@ namespace osu.Game.Graphics.Cursor } } - private class MouseInputDetector : Component + private partial class MouseInputDetector : Component { /// /// Whether the last input applied to the game is sourced from mouse. diff --git a/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs b/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs index fbaefe24b0..27700e71d9 100644 --- a/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs +++ b/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.Cursor { - public class OsuContextMenuContainer : ContextMenuContainer + public partial class OsuContextMenuContainer : ContextMenuContainer { [Cached] private OsuContextMenuSamples samples = new OsuContextMenuSamples(); diff --git a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs index 8bf4dfcd24..dc75d626b9 100644 --- a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs +++ b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs @@ -16,7 +16,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.Cursor { - public class OsuTooltipContainer : TooltipContainer + public partial class OsuTooltipContainer : TooltipContainer { protected override ITooltip CreateTooltip() => new OsuTooltip(); @@ -27,7 +27,7 @@ namespace osu.Game.Graphics.Cursor protected override double AppearDelay => (1 - CurrentTooltip.Alpha) * base.AppearDelay; // reduce appear delay if the tooltip is already partly visible. - public class OsuTooltip : Tooltip + public partial class OsuTooltip : Tooltip { private readonly Box background; private readonly OsuSpriteText text; diff --git a/osu.Game/Graphics/DateTooltip.cs b/osu.Game/Graphics/DateTooltip.cs index 77bf78b213..d9bb2b610a 100644 --- a/osu.Game/Graphics/DateTooltip.cs +++ b/osu.Game/Graphics/DateTooltip.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Graphics { - public class DateTooltip : VisibilityContainer, ITooltip + public partial class DateTooltip : VisibilityContainer, ITooltip { private readonly OsuSpriteText dateText, timeText; private readonly Box background; diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs index 0008d0fcaa..553b27acb1 100644 --- a/osu.Game/Graphics/DrawableDate.cs +++ b/osu.Game/Graphics/DrawableDate.cs @@ -12,7 +12,7 @@ using osu.Game.Utils; namespace osu.Game.Graphics { - public class DrawableDate : OsuSpriteText, IHasCustomTooltip + public partial class DrawableDate : OsuSpriteText, IHasCustomTooltip { private DateTimeOffset date; diff --git a/osu.Game/Graphics/ErrorTextFlowContainer.cs b/osu.Game/Graphics/ErrorTextFlowContainer.cs index 0d47245e8c..65a90534e5 100644 --- a/osu.Game/Graphics/ErrorTextFlowContainer.cs +++ b/osu.Game/Graphics/ErrorTextFlowContainer.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics { - public class ErrorTextFlowContainer : OsuTextFlowContainer + public partial class ErrorTextFlowContainer : OsuTextFlowContainer { private readonly List errorTextParts = new List(); diff --git a/osu.Game/Graphics/InputBlockingContainer.cs b/osu.Game/Graphics/InputBlockingContainer.cs index 66caa57c1a..f652dc8850 100644 --- a/osu.Game/Graphics/InputBlockingContainer.cs +++ b/osu.Game/Graphics/InputBlockingContainer.cs @@ -9,7 +9,7 @@ namespace osu.Game.Graphics /// /// A simple container which blocks input events from travelling through it. /// - public class InputBlockingContainer : Container + public partial class InputBlockingContainer : Container { protected override bool OnHover(HoverEvent e) => true; diff --git a/osu.Game/Graphics/ParticleExplosion.cs b/osu.Game/Graphics/ParticleExplosion.cs index a902c8426f..56e1568441 100644 --- a/osu.Game/Graphics/ParticleExplosion.cs +++ b/osu.Game/Graphics/ParticleExplosion.cs @@ -18,7 +18,7 @@ namespace osu.Game.Graphics /// /// An explosion of textured particles based on how osu-stable randomises the explosion pattern. /// - public class ParticleExplosion : Sprite + public partial class ParticleExplosion : Sprite { private readonly int particleCount; private readonly double duration; diff --git a/osu.Game/Graphics/ParticleSpewer.cs b/osu.Game/Graphics/ParticleSpewer.cs index 41a7d82e74..8519cf0c59 100644 --- a/osu.Game/Graphics/ParticleSpewer.cs +++ b/osu.Game/Graphics/ParticleSpewer.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Graphics { - public abstract class ParticleSpewer : Sprite + public abstract partial class ParticleSpewer : Sprite { private readonly FallingParticle[] particles; private int currentIndex; diff --git a/osu.Game/Graphics/ScreenshotManager.cs b/osu.Game/Graphics/ScreenshotManager.cs index 2cc9e63c87..29e9b0276c 100644 --- a/osu.Game/Graphics/ScreenshotManager.cs +++ b/osu.Game/Graphics/ScreenshotManager.cs @@ -25,7 +25,7 @@ using SixLabors.ImageSharp.Formats.Jpeg; namespace osu.Game.Graphics { - public class ScreenshotManager : Component, IKeyBindingHandler, IHandleGlobalKeyboardInput + public partial class ScreenshotManager : Component, IKeyBindingHandler, IHandleGlobalKeyboardInput { private readonly BindableBool cursorVisibility = new BindableBool(true); diff --git a/osu.Game/Graphics/Sprites/GlowingSpriteText.cs b/osu.Game/Graphics/Sprites/GlowingSpriteText.cs index dca6b7158b..ae594ddfe2 100644 --- a/osu.Game/Graphics/Sprites/GlowingSpriteText.cs +++ b/osu.Game/Graphics/Sprites/GlowingSpriteText.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Graphics.Sprites { - public class GlowingSpriteText : Container, IHasText + public partial class GlowingSpriteText : Container, IHasText { private readonly OsuSpriteText spriteText, blurredText; diff --git a/osu.Game/Graphics/Sprites/LogoAnimation.cs b/osu.Game/Graphics/Sprites/LogoAnimation.cs index 097de4dfcb..e177cc604b 100644 --- a/osu.Game/Graphics/Sprites/LogoAnimation.cs +++ b/osu.Game/Graphics/Sprites/LogoAnimation.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.Sprites { - public class LogoAnimation : Sprite + public partial class LogoAnimation : Sprite { [BackgroundDependencyLoader] private void load(ShaderManager shaders) diff --git a/osu.Game/Graphics/Sprites/OsuSpriteText.cs b/osu.Game/Graphics/Sprites/OsuSpriteText.cs index a46ed27b9b..e149e0abfb 100644 --- a/osu.Game/Graphics/Sprites/OsuSpriteText.cs +++ b/osu.Game/Graphics/Sprites/OsuSpriteText.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.Sprites { - public class OsuSpriteText : SpriteText + public partial class OsuSpriteText : SpriteText { public OsuSpriteText() { diff --git a/osu.Game/Graphics/Sprites/SizePreservingSpriteText.cs b/osu.Game/Graphics/Sprites/SizePreservingSpriteText.cs index baffe106ed..458dac2b91 100644 --- a/osu.Game/Graphics/Sprites/SizePreservingSpriteText.cs +++ b/osu.Game/Graphics/Sprites/SizePreservingSpriteText.cs @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.Sprites /// /// A wrapped version of which will expand in size based on text content, but never shrink back down. /// - public class SizePreservingSpriteText : CompositeDrawable + public partial class SizePreservingSpriteText : CompositeDrawable { private readonly OsuSpriteText text = new OsuSpriteText(); diff --git a/osu.Game/Graphics/UserInterface/BackButton.cs b/osu.Game/Graphics/UserInterface/BackButton.cs index d2ed71dfc6..cd9a357ea4 100644 --- a/osu.Game/Graphics/UserInterface/BackButton.cs +++ b/osu.Game/Graphics/UserInterface/BackButton.cs @@ -13,7 +13,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Graphics.UserInterface { - public class BackButton : VisibilityContainer + public partial class BackButton : VisibilityContainer { public Action Action; @@ -60,7 +60,7 @@ namespace osu.Game.Graphics.UserInterface button.FadeOut(400, Easing.OutQuint); } - public class Receptor : Drawable, IKeyBindingHandler + public partial class Receptor : Drawable, IKeyBindingHandler { public Action OnBackPressed; diff --git a/osu.Game/Graphics/UserInterface/Bar.cs b/osu.Game/Graphics/UserInterface/Bar.cs index e9a20761b3..53217e2120 100644 --- a/osu.Game/Graphics/UserInterface/Bar.cs +++ b/osu.Game/Graphics/UserInterface/Bar.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Shapes; namespace osu.Game.Graphics.UserInterface { - public class Bar : Container, IHasAccentColour + public partial class Bar : Container, IHasAccentColour { private readonly Box background; private readonly Box bar; diff --git a/osu.Game/Graphics/UserInterface/BarGraph.cs b/osu.Game/Graphics/UserInterface/BarGraph.cs index 3f356c0225..c394e58d87 100644 --- a/osu.Game/Graphics/UserInterface/BarGraph.cs +++ b/osu.Game/Graphics/UserInterface/BarGraph.cs @@ -17,7 +17,7 @@ using System; namespace osu.Game.Graphics.UserInterface { - public class BarGraph : Drawable + public partial class BarGraph : Drawable { private const int resize_duration = 250; private const Easing easing = Easing.InOutCubic; diff --git a/osu.Game/Graphics/UserInterface/BasicSearchTextBox.cs b/osu.Game/Graphics/UserInterface/BasicSearchTextBox.cs index e0efa1d81c..c4e03133dc 100644 --- a/osu.Game/Graphics/UserInterface/BasicSearchTextBox.cs +++ b/osu.Game/Graphics/UserInterface/BasicSearchTextBox.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class BasicSearchTextBox : SearchTextBox + public partial class BasicSearchTextBox : SearchTextBox { public BasicSearchTextBox() { diff --git a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs index b6ae4d6dc5..67b63e120b 100644 --- a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs +++ b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs @@ -14,7 +14,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public class BreadcrumbControl : OsuTabControl + public partial class BreadcrumbControl : OsuTabControl { private const float padding = 10; @@ -44,7 +44,7 @@ namespace osu.Game.Graphics.UserInterface }; } - public class BreadcrumbTabItem : OsuTabItem, IStateful + public partial class BreadcrumbTabItem : OsuTabItem, IStateful { protected virtual float ChevronSize => 10; diff --git a/osu.Game/Graphics/UserInterface/CommaSeparatedScoreCounter.cs b/osu.Game/Graphics/UserInterface/CommaSeparatedScoreCounter.cs index bec78c68d3..ba76a17fc6 100644 --- a/osu.Game/Graphics/UserInterface/CommaSeparatedScoreCounter.cs +++ b/osu.Game/Graphics/UserInterface/CommaSeparatedScoreCounter.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public abstract class CommaSeparatedScoreCounter : RollingCounter + public abstract partial class CommaSeparatedScoreCounter : RollingCounter { protected override double RollingDuration => 1000; protected override Easing RollingEasing => Easing.Out; diff --git a/osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs b/osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs index 1414979531..c2c01a0ddb 100644 --- a/osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs +++ b/osu.Game/Graphics/UserInterface/DangerousTriangleButton.cs @@ -7,7 +7,7 @@ using osu.Framework.Allocation; namespace osu.Game.Graphics.UserInterface { - public class DangerousTriangleButton : TriangleButton + public partial class DangerousTriangleButton : TriangleButton { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Graphics/UserInterface/DialogButton.cs b/osu.Game/Graphics/UserInterface/DialogButton.cs index 52ad5c6b80..670778b07b 100644 --- a/osu.Game/Graphics/UserInterface/DialogButton.cs +++ b/osu.Game/Graphics/UserInterface/DialogButton.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { - public class DialogButton : OsuClickableContainer, IStateful + public partial class DialogButton : OsuClickableContainer, IStateful { private const float idle_width = 0.8f; private const float hover_width = 0.9f; diff --git a/osu.Game/Graphics/UserInterface/DownloadButton.cs b/osu.Game/Graphics/UserInterface/DownloadButton.cs index dfbe6bd44d..73783e718c 100644 --- a/osu.Game/Graphics/UserInterface/DownloadButton.cs +++ b/osu.Game/Graphics/UserInterface/DownloadButton.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class DownloadButton : GrayButton + public partial class DownloadButton : GrayButton { [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs index 6c8eeed391..ad02e3b2ab 100644 --- a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { - public class DrawableOsuMenuItem : Menu.DrawableMenuItem + public partial class DrawableOsuMenuItem : Menu.DrawableMenuItem { public const int MARGIN_HORIZONTAL = 17; public const int MARGIN_VERTICAL = 4; @@ -95,7 +95,7 @@ namespace osu.Game.Graphics.UserInterface protected sealed override Drawable CreateContent() => text = CreateTextContainer(); protected virtual TextContainer CreateTextContainer() => new TextContainer(); - protected class TextContainer : Container, IHasText + protected partial class TextContainer : Container, IHasText { public LocalisableString Text { diff --git a/osu.Game/Graphics/UserInterface/DrawableStatefulMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableStatefulMenuItem.cs index 5a7cf0d73e..ec3a5744f8 100644 --- a/osu.Game/Graphics/UserInterface/DrawableStatefulMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/DrawableStatefulMenuItem.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class DrawableStatefulMenuItem : DrawableOsuMenuItem + public partial class DrawableStatefulMenuItem : DrawableOsuMenuItem { protected new StatefulMenuItem Item => (StatefulMenuItem)base.Item; @@ -21,7 +21,7 @@ namespace osu.Game.Graphics.UserInterface protected override TextContainer CreateTextContainer() => new ToggleTextContainer(Item); - private class ToggleTextContainer : TextContainer + private partial class ToggleTextContainer : TextContainer { private readonly StatefulMenuItem menuItem; private readonly Bindable state; diff --git a/osu.Game/Graphics/UserInterface/ExpandableSlider.cs b/osu.Game/Graphics/UserInterface/ExpandableSlider.cs index 92b0059157..9669fe89a5 100644 --- a/osu.Game/Graphics/UserInterface/ExpandableSlider.cs +++ b/osu.Game/Graphics/UserInterface/ExpandableSlider.cs @@ -19,7 +19,7 @@ namespace osu.Game.Graphics.UserInterface /// /// An implementation for the UI slider bar control. /// - public class ExpandableSlider : CompositeDrawable, IExpandable, IHasCurrentValue + public partial class ExpandableSlider : CompositeDrawable, IExpandable, IHasCurrentValue where T : struct, IEquatable, IComparable, IConvertible where TSlider : OsuSliderBar, new() { @@ -130,7 +130,7 @@ namespace osu.Game.Graphics.UserInterface /// /// An implementation for the UI slider bar control. /// - public class ExpandableSlider : ExpandableSlider> + public partial class ExpandableSlider : ExpandableSlider> where T : struct, IEquatable, IComparable, IConvertible { } diff --git a/osu.Game/Graphics/UserInterface/ExpandingBar.cs b/osu.Game/Graphics/UserInterface/ExpandingBar.cs index b2ffb4da7d..6d7c41ee7c 100644 --- a/osu.Game/Graphics/UserInterface/ExpandingBar.cs +++ b/osu.Game/Graphics/UserInterface/ExpandingBar.cs @@ -13,7 +13,7 @@ namespace osu.Game.Graphics.UserInterface /// A rounded bar which can be expanded or collapsed. /// Generally used for tabs or breadcrumbs. /// - public class ExpandingBar : Circle + public partial class ExpandingBar : Circle { private bool expanded = true; diff --git a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs index e51dbeed14..efbbaaca85 100644 --- a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs +++ b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { - public class ExternalLinkButton : CompositeDrawable, IHasTooltip, IHasContextMenu + public partial class ExternalLinkButton : CompositeDrawable, IHasTooltip, IHasContextMenu { public string? Link { get; set; } diff --git a/osu.Game/Graphics/UserInterface/FPSCounter.cs b/osu.Game/Graphics/UserInterface/FPSCounter.cs index e9fb6a046a..9dbeba6449 100644 --- a/osu.Game/Graphics/UserInterface/FPSCounter.cs +++ b/osu.Game/Graphics/UserInterface/FPSCounter.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class FPSCounter : VisibilityContainer, IHasCustomTooltip + public partial class FPSCounter : VisibilityContainer, IHasCustomTooltip { private OsuSpriteText counterUpdateFrameTime = null!; private OsuSpriteText counterDrawFPS = null!; diff --git a/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs b/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs index bf53bff9b4..17e7be1d8b 100644 --- a/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs +++ b/osu.Game/Graphics/UserInterface/FPSCounterTooltip.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class FPSCounterTooltip : CompositeDrawable, ITooltip + public partial class FPSCounterTooltip : CompositeDrawable, ITooltip { private OsuTextFlowContainer textFlow = null!; diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index 0c18fd36fc..338f32f321 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A textbox which holds focus eagerly. /// - public class FocusedTextBox : OsuTextBox, IKeyBindingHandler + public partial class FocusedTextBox : OsuTextBox, IKeyBindingHandler { private bool focus; diff --git a/osu.Game/Graphics/UserInterface/GradientLineTabControl.cs b/osu.Game/Graphics/UserInterface/GradientLineTabControl.cs index e16f1ee897..7e29053035 100644 --- a/osu.Game/Graphics/UserInterface/GradientLineTabControl.cs +++ b/osu.Game/Graphics/UserInterface/GradientLineTabControl.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics.Colour; namespace osu.Game.Graphics.UserInterface { - public abstract class GradientLineTabControl : PageTabControl + public abstract partial class GradientLineTabControl : PageTabControl { protected Color4 LineColour { @@ -46,7 +46,7 @@ namespace osu.Game.Graphics.UserInterface Spacing = new Vector2(20, 0), }; - private class GradientLine : GridContainer + private partial class GradientLine : GridContainer { public GradientLine() { diff --git a/osu.Game/Graphics/UserInterface/GrayButton.cs b/osu.Game/Graphics/UserInterface/GrayButton.cs index d95032bce6..3df234e97d 100644 --- a/osu.Game/Graphics/UserInterface/GrayButton.cs +++ b/osu.Game/Graphics/UserInterface/GrayButton.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class GrayButton : OsuAnimatedButton + public partial class GrayButton : OsuAnimatedButton { protected SpriteIcon Icon { get; private set; } protected Box Background { get; private set; } diff --git a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs index 0958e1832e..d74a4f2cdb 100644 --- a/osu.Game/Graphics/UserInterface/HistoryTextBox.cs +++ b/osu.Game/Graphics/UserInterface/HistoryTextBox.cs @@ -13,7 +13,7 @@ namespace osu.Game.Graphics.UserInterface /// The history of committed text can be navigated using up/down arrows. /// This resembles the operation of command-line terminals. /// - public class HistoryTextBox : FocusedTextBox + public partial class HistoryTextBox : FocusedTextBox { private readonly LimitedCapacityQueue messageHistory; diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 99cec7411c..ed1838abd0 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -19,7 +19,7 @@ namespace osu.Game.Graphics.UserInterface /// Adds hover and click sounds to a drawable. /// Does not draw anything. /// - public class HoverClickSounds : HoverSounds + public partial class HoverClickSounds : HoverSounds { public Bindable Enabled = new Bindable(true); diff --git a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs index 20715309a2..53f1c06a67 100644 --- a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs +++ b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs @@ -14,7 +14,7 @@ namespace osu.Game.Graphics.UserInterface /// /// Handles debouncing hover sounds at a global level to ensure the effects are not overwhelming. /// - public abstract class HoverSampleDebounceComponent : CompositeDrawable + public abstract partial class HoverSampleDebounceComponent : CompositeDrawable { private Bindable lastPlaybackTime; diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index dd03e83ab1..012594b404 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -16,7 +16,7 @@ namespace osu.Game.Graphics.UserInterface /// Adds hover sounds to a drawable. /// Does not draw anything. /// - public class HoverSounds : HoverSampleDebounceComponent + public partial class HoverSounds : HoverSampleDebounceComponent { private Sample sampleHover; diff --git a/osu.Game/Graphics/UserInterface/IconButton.cs b/osu.Game/Graphics/UserInterface/IconButton.cs index e0b5999c4d..47f06715b5 100644 --- a/osu.Game/Graphics/UserInterface/IconButton.cs +++ b/osu.Game/Graphics/UserInterface/IconButton.cs @@ -11,7 +11,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Graphics.UserInterface { - public class IconButton : OsuAnimatedButton + public partial class IconButton : OsuAnimatedButton { public const float DEFAULT_BUTTON_SIZE = 30; diff --git a/osu.Game/Graphics/UserInterface/LineGraph.cs b/osu.Game/Graphics/UserInterface/LineGraph.cs index fe634390a2..18c022818f 100644 --- a/osu.Game/Graphics/UserInterface/LineGraph.cs +++ b/osu.Game/Graphics/UserInterface/LineGraph.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { - public class LineGraph : Container + public partial class LineGraph : Container { /// /// Manually set the max value, otherwise will be used. diff --git a/osu.Game/Graphics/UserInterface/LoadingButton.cs b/osu.Game/Graphics/UserInterface/LoadingButton.cs index 44067bac8b..8a841ffc94 100644 --- a/osu.Game/Graphics/UserInterface/LoadingButton.cs +++ b/osu.Game/Graphics/UserInterface/LoadingButton.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public abstract class LoadingButton : OsuHoverContainer + public abstract partial class LoadingButton : OsuHoverContainer { private bool isLoading; diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs index 9f6177c226..9059b61a33 100644 --- a/osu.Game/Graphics/UserInterface/LoadingLayer.cs +++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs @@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface /// Also optionally dims target elements. /// Useful for disabling all elements in a form and showing we are waiting on a response, for instance. /// - public class LoadingLayer : LoadingSpinner + public partial class LoadingLayer : LoadingSpinner { private readonly bool blockInput; diff --git a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs index 864dd0a65e..0ea44dfe49 100644 --- a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs +++ b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A loading spinner. /// - public class LoadingSpinner : VisibilityContainer + public partial class LoadingSpinner : VisibilityContainer { private readonly SpriteIcon spinner; diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index db3a41e303..4f56872f42 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -19,7 +19,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.UserInterface { - public class Nub : Container, IHasCurrentValue, IHasAccentColour + public partial class Nub : Container, IHasCurrentValue, IHasAccentColour { public const float HEIGHT = 15; diff --git a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs index f720678a93..5ef590d253 100644 --- a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs @@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface /// /// Highlight on hover, bounce on click. /// - public class OsuAnimatedButton : OsuClickableContainer + public partial class OsuAnimatedButton : OsuClickableContainer { /// /// The colour that should be flashed when the is clicked. diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index dae5de2d65..1de15bc13c 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -20,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A button with added default sound effects. /// - public class OsuButton : Button + public partial class OsuButton : Button { public LocalisableString Text { diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs index 8772c1e2d9..160105af1a 100644 --- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs @@ -15,7 +15,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Graphics.UserInterface { - public class OsuCheckbox : Checkbox + public partial class OsuCheckbox : Checkbox { /// /// Whether to play sounds when the state changes as a result of user interaction. diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs index cc5ce8f46d..1b5f7cc4b5 100644 --- a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterface { - public class OsuContextMenu : OsuMenu + public partial class OsuContextMenu : OsuMenu { private const int fade_duration = 250; diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenuSamples.cs b/osu.Game/Graphics/UserInterface/OsuContextMenuSamples.cs index c329974e28..6d7543c472 100644 --- a/osu.Game/Graphics/UserInterface/OsuContextMenuSamples.cs +++ b/osu.Game/Graphics/UserInterface/OsuContextMenuSamples.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics; namespace osu.Game.Graphics.UserInterface { - public class OsuContextMenuSamples : Component + public partial class OsuContextMenuSamples : Component { private Sample sampleClick; private Sample sampleOpen; diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index ce2a690e92..3230bb0569 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { - public class OsuDropdown : Dropdown + public partial class OsuDropdown : Dropdown { private const float corner_radius = 5; @@ -32,7 +32,7 @@ namespace osu.Game.Graphics.UserInterface #region OsuDropdownMenu - protected class OsuDropdownMenu : DropdownMenu, IKeyBindingHandler + protected partial class OsuDropdownMenu : DropdownMenu, IKeyBindingHandler { public override bool HandleNonPositionalInput => State == MenuState.Open; @@ -135,7 +135,7 @@ namespace osu.Game.Graphics.UserInterface #region DrawableOsuDropdownMenuItem - public class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem + public partial class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem { // IsHovered is used public override bool HandlePositionalInput => true; @@ -203,7 +203,7 @@ namespace osu.Game.Graphics.UserInterface protected override Drawable CreateContent() => new Content(); - protected new class Content : CompositeDrawable, IHasText + protected new partial class Content : CompositeDrawable, IHasText { public LocalisableString Text { @@ -297,7 +297,7 @@ namespace osu.Game.Graphics.UserInterface #endregion - public class OsuDropdownHeader : DropdownHeader + public partial class OsuDropdownHeader : DropdownHeader { protected readonly SpriteText Text; diff --git a/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs b/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs index 3d4a8cf359..9ef58f4c49 100644 --- a/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuEnumDropdown.cs @@ -7,7 +7,7 @@ using System; namespace osu.Game.Graphics.UserInterface { - public class OsuEnumDropdown : OsuDropdown + public partial class OsuEnumDropdown : OsuDropdown where T : struct, Enum { public OsuEnumDropdown() diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index a11bffd05d..73d57af793 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class OsuMenu : Menu + public partial class OsuMenu : Menu { private Sample sampleOpen; private Sample sampleClose; diff --git a/osu.Game/Graphics/UserInterface/OsuNumberBox.cs b/osu.Game/Graphics/UserInterface/OsuNumberBox.cs index 93d47792c8..f6a3abdaae 100644 --- a/osu.Game/Graphics/UserInterface/OsuNumberBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuNumberBox.cs @@ -7,7 +7,7 @@ using osu.Framework.Extensions; namespace osu.Game.Graphics.UserInterface { - public class OsuNumberBox : OsuTextBox + public partial class OsuNumberBox : OsuTextBox { protected override bool AllowIme => false; diff --git a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs index 305b1b6687..63c98d7838 100644 --- a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs @@ -19,7 +19,7 @@ using osu.Framework.Platform; namespace osu.Game.Graphics.UserInterface { - public class OsuPasswordTextBox : OsuTextBox, ISuppressKeyEventLogging + public partial class OsuPasswordTextBox : OsuTextBox, ISuppressKeyEventLogging { protected override Drawable GetDrawableCharacter(char c) => new FallingDownContainer { @@ -73,7 +73,7 @@ namespace osu.Game.Graphics.UserInterface private void updateCapsWarning(bool visible) => warning.FadeTo(visible ? 1 : 0, 250, Easing.OutQuint); - public class PasswordMaskChar : Container + public partial class PasswordMaskChar : Container { private readonly CircularContainer circle; @@ -110,7 +110,7 @@ namespace osu.Game.Graphics.UserInterface } } - private class CapsWarning : SpriteIcon, IHasTooltip + private partial class CapsWarning : SpriteIcon, IHasTooltip { public LocalisableString TooltipText => "caps lock is active"; diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 4d3f4be8f6..6d6a591673 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -25,7 +25,7 @@ using osu.Game.Utils; namespace osu.Game.Graphics.UserInterface { - public class OsuSliderBar : SliderBar, IHasTooltip, IHasAccentColour + public partial class OsuSliderBar : SliderBar, IHasTooltip, IHasAccentColour where T : struct, IEquatable, IComparable, IConvertible { /// diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index 3cfe401bb9..05309760e7 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -22,7 +22,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public class OsuTabControl : TabControl + public partial class OsuTabControl : TabControl { private Color4 accentColour; @@ -98,7 +98,7 @@ namespace osu.Game.Graphics.UserInterface strip.Width = Interpolation.ValueAt(Math.Clamp(Clock.ElapsedFrameTime, 0, 1000), strip.Width, StripWidth, 0, 500, Easing.OutQuint); } - public class OsuTabItem : TabItem, IHasAccentColour + public partial class OsuTabItem : TabItem, IHasAccentColour { protected readonly SpriteText Text; protected readonly Box Bar; diff --git a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs index 6e6296c24b..fa58ae27f2 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs @@ -22,7 +22,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A Checkbox styled to be placed in line with an /// - public class OsuTabControlCheckbox : Checkbox + public partial class OsuTabControlCheckbox : Checkbox { private readonly Box box; private readonly SpriteText text; diff --git a/osu.Game/Graphics/UserInterface/OsuTabDropdown.cs b/osu.Game/Graphics/UserInterface/OsuTabDropdown.cs index d9d9a21401..01d072b6d7 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabDropdown.cs @@ -13,7 +13,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Graphics.UserInterface { - public class OsuTabDropdown : OsuDropdown, IHasAccentColour + public partial class OsuTabDropdown : OsuDropdown, IHasAccentColour { private Color4 accentColour; @@ -60,7 +60,7 @@ namespace osu.Game.Graphics.UserInterface tabDropdownHeader.AccentColour = accentColour; } - private class OsuTabDropdownMenu : OsuDropdownMenu + private partial class OsuTabDropdownMenu : OsuDropdownMenu { public OsuTabDropdownMenu() { @@ -73,7 +73,7 @@ namespace osu.Game.Graphics.UserInterface protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableOsuTabDropdownMenuItem(item); - private class DrawableOsuTabDropdownMenuItem : DrawableOsuDropdownMenuItem + private partial class DrawableOsuTabDropdownMenuItem : DrawableOsuDropdownMenuItem { public DrawableOsuTabDropdownMenuItem(MenuItem item) : base(item) @@ -83,7 +83,7 @@ namespace osu.Game.Graphics.UserInterface } } - protected class OsuTabDropdownHeader : OsuDropdownHeader, IHasAccentColour + protected partial class OsuTabDropdownHeader : OsuDropdownHeader, IHasAccentColour { private Color4 accentColour; diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 18977638f3..1114c29afd 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class OsuTextBox : BasicTextBox + public partial class OsuTextBox : BasicTextBox { /// /// Whether to allow playing a different samples based on the type of character. @@ -302,7 +302,7 @@ namespace osu.Game.Graphics.UserInterface sampleLastPlaybackTime = Time.Current; }); - private class OsuCaret : Caret + private partial class OsuCaret : Caret { private const float caret_move_time = 60; @@ -349,7 +349,7 @@ namespace osu.Game.Graphics.UserInterface } } - private class CaretBeatSyncedContainer : BeatSyncedContainer + private partial class CaretBeatSyncedContainer : BeatSyncedContainer { private bool hasSelection; diff --git a/osu.Game/Graphics/UserInterface/PageSelector/PageEllipsis.cs b/osu.Game/Graphics/UserInterface/PageSelector/PageEllipsis.cs index b750abcd2b..068e477d79 100644 --- a/osu.Game/Graphics/UserInterface/PageSelector/PageEllipsis.cs +++ b/osu.Game/Graphics/UserInterface/PageSelector/PageEllipsis.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.UserInterface.PageSelector { - internal class PageEllipsis : CompositeDrawable + internal partial class PageEllipsis : CompositeDrawable { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) diff --git a/osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs b/osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs index 7c5d38b91b..63f35d5f89 100644 --- a/osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs +++ b/osu.Game/Graphics/UserInterface/PageSelector/PageSelector.cs @@ -11,7 +11,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Graphics.UserInterface.PageSelector { - public class PageSelector : CompositeDrawable + public partial class PageSelector : CompositeDrawable { public readonly BindableInt CurrentPage = new BindableInt { MinValue = 0, }; diff --git a/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorButton.cs b/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorButton.cs index adeae4fc8d..9388f045d3 100644 --- a/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorButton.cs +++ b/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorButton.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.UserInterface.PageSelector { - public abstract class PageSelectorButton : OsuClickableContainer + public abstract partial class PageSelectorButton : OsuClickableContainer { protected const int DURATION = 200; diff --git a/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPageButton.cs b/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPageButton.cs index 7696087195..3e5d1fac6d 100644 --- a/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPageButton.cs +++ b/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPageButton.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface.PageSelector { - public class PageSelectorPageButton : PageSelectorButton + public partial class PageSelectorPageButton : PageSelectorButton { private readonly BindableBool selected = new BindableBool(); diff --git a/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPrevNextButton.cs b/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPrevNextButton.cs index a96cc892d4..e5e0dab2f0 100644 --- a/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPrevNextButton.cs +++ b/osu.Game/Graphics/UserInterface/PageSelector/PageSelectorPrevNextButton.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface.PageSelector { - public class PageSelectorPrevNextButton : PageSelectorButton + public partial class PageSelectorPrevNextButton : PageSelectorButton { private readonly bool rightAligned; private readonly LocalisableString text; diff --git a/osu.Game/Graphics/UserInterface/PageTabControl.cs b/osu.Game/Graphics/UserInterface/PageTabControl.cs index 13654fac85..2fe8acfbd5 100644 --- a/osu.Game/Graphics/UserInterface/PageTabControl.cs +++ b/osu.Game/Graphics/UserInterface/PageTabControl.cs @@ -18,7 +18,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public class PageTabControl : OsuTabControl + public partial class PageTabControl : OsuTabControl { protected override TabItem CreateTabItem(T value) => new PageTabItem(value); @@ -33,7 +33,7 @@ namespace osu.Game.Graphics.UserInterface AccentColour = colours.Yellow; } - public class PageTabItem : TabItem, IHasAccentColour + public partial class PageTabItem : TabItem, IHasAccentColour { private const float transition_duration = 100; diff --git a/osu.Game/Graphics/UserInterface/PercentageCounter.cs b/osu.Game/Graphics/UserInterface/PercentageCounter.cs index e5b0f0cbee..de93d9b2b4 100644 --- a/osu.Game/Graphics/UserInterface/PercentageCounter.cs +++ b/osu.Game/Graphics/UserInterface/PercentageCounter.cs @@ -14,7 +14,7 @@ namespace osu.Game.Graphics.UserInterface /// /// Used as an accuracy counter. Represented visually as a percentage. /// - public class PercentageCounter : RollingCounter + public partial class PercentageCounter : RollingCounter { protected override double RollingDuration => 750; diff --git a/osu.Game/Graphics/UserInterface/ProgressBar.cs b/osu.Game/Graphics/UserInterface/ProgressBar.cs index 774704223b..8f383c76db 100644 --- a/osu.Game/Graphics/UserInterface/ProgressBar.cs +++ b/osu.Game/Graphics/UserInterface/ProgressBar.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { - public class ProgressBar : SliderBar + public partial class ProgressBar : SliderBar { public Action OnSeek; diff --git a/osu.Game/Graphics/UserInterface/RollingCounter.cs b/osu.Game/Graphics/UserInterface/RollingCounter.cs index 2f8c8414e2..b80c0e3b58 100644 --- a/osu.Game/Graphics/UserInterface/RollingCounter.cs +++ b/osu.Game/Graphics/UserInterface/RollingCounter.cs @@ -16,7 +16,7 @@ using osu.Framework.Localisation; namespace osu.Game.Graphics.UserInterface { - public abstract class RollingCounter : Container, IHasCurrentValue + public abstract partial class RollingCounter : Container, IHasCurrentValue where T : struct, IEquatable { private readonly BindableWithCurrent current = new BindableWithCurrent(); diff --git a/osu.Game/Graphics/UserInterface/ScoreCounter.cs b/osu.Game/Graphics/UserInterface/ScoreCounter.cs index 2efe27c842..255b2149f0 100644 --- a/osu.Game/Graphics/UserInterface/ScoreCounter.cs +++ b/osu.Game/Graphics/UserInterface/ScoreCounter.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public abstract class ScoreCounter : RollingCounter + public abstract partial class ScoreCounter : RollingCounter { protected override double RollingDuration => 1000; protected override Easing RollingEasing => Easing.Out; diff --git a/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs index edd705ca00..65dce422d6 100644 --- a/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs +++ b/osu.Game/Graphics/UserInterface/ScreenBreadcrumbControl.cs @@ -13,7 +13,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A which follows the active screen (and allows navigation) in a stack. /// - public class ScreenBreadcrumbControl : BreadcrumbControl + public partial class ScreenBreadcrumbControl : BreadcrumbControl { public ScreenBreadcrumbControl(ScreenStack stack) { diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs index 2c2597f149..2d09a239bb 100644 --- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs +++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs @@ -10,7 +10,7 @@ using osuTK.Input; namespace osu.Game.Graphics.UserInterface { - public class SearchTextBox : FocusedTextBox + public partial class SearchTextBox : FocusedTextBox { protected virtual bool AllowCommit => false; diff --git a/osu.Game/Graphics/UserInterface/SeekLimitedSearchTextBox.cs b/osu.Game/Graphics/UserInterface/SeekLimitedSearchTextBox.cs index f64f455f6b..a85cd36808 100644 --- a/osu.Game/Graphics/UserInterface/SeekLimitedSearchTextBox.cs +++ b/osu.Game/Graphics/UserInterface/SeekLimitedSearchTextBox.cs @@ -8,7 +8,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A which does not handle left/right arrow keys for seeking. /// - public class SeekLimitedSearchTextBox : BasicSearchTextBox + public partial class SeekLimitedSearchTextBox : BasicSearchTextBox { public override bool HandleLeftRightArrows => false; } diff --git a/osu.Game/Graphics/UserInterface/ShearedButton.cs b/osu.Game/Graphics/UserInterface/ShearedButton.cs index e406e273e6..f1afacb2f4 100644 --- a/osu.Game/Graphics/UserInterface/ShearedButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedButton.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class ShearedButton : OsuClickableContainer + public partial class ShearedButton : OsuClickableContainer { public LocalisableString Text { diff --git a/osu.Game/Graphics/UserInterface/ShearedOverlayHeader.cs b/osu.Game/Graphics/UserInterface/ShearedOverlayHeader.cs index deb2374e88..99eb439f75 100644 --- a/osu.Game/Graphics/UserInterface/ShearedOverlayHeader.cs +++ b/osu.Game/Graphics/UserInterface/ShearedOverlayHeader.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class ShearedOverlayHeader : CompositeDrawable + public partial class ShearedOverlayHeader : CompositeDrawable { public const float HEIGHT = main_area_height + 2 * corner_radius; diff --git a/osu.Game/Graphics/UserInterface/ShearedSearchTextBox.cs b/osu.Game/Graphics/UserInterface/ShearedSearchTextBox.cs index d7e027b3f9..7bd083f9d5 100644 --- a/osu.Game/Graphics/UserInterface/ShearedSearchTextBox.cs +++ b/osu.Game/Graphics/UserInterface/ShearedSearchTextBox.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterface { - public class ShearedSearchTextBox : CompositeDrawable, IHasCurrentValue + public partial class ShearedSearchTextBox : CompositeDrawable, IHasCurrentValue { private const float corner_radius = 7; @@ -95,7 +95,7 @@ namespace osu.Game.Graphics.UserInterface public override bool HandleNonPositionalInput => textBox.HandleNonPositionalInput; - private class InnerSearchTextBox : SearchTextBox + private partial class InnerSearchTextBox : SearchTextBox { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -112,7 +112,7 @@ namespace osu.Game.Graphics.UserInterface protected override SpriteText CreatePlaceholder() => new SearchPlaceholder(); - internal class SearchPlaceholder : SpriteText + internal partial class SearchPlaceholder : SpriteText { public override void Show() { diff --git a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs index 9ef09d799e..d5e0abe9d8 100644 --- a/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs +++ b/osu.Game/Graphics/UserInterface/ShearedToggleButton.cs @@ -8,7 +8,7 @@ using osu.Framework.Bindables; namespace osu.Game.Graphics.UserInterface { - public class ShearedToggleButton : ShearedButton + public partial class ShearedToggleButton : ShearedButton { private Sample? sampleClick; private Sample? sampleOff; diff --git a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs index ed64a31412..3afb7e701f 100644 --- a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs +++ b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs @@ -19,7 +19,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Graphics.UserInterface { - public class ShowMoreButton : LoadingButton + public partial class ShowMoreButton : LoadingButton { private const int duration = 200; @@ -115,7 +115,7 @@ namespace osu.Game.Graphics.UserInterface rightIcon.SetHoveredState(false); } - public class ChevronIcon : SpriteIcon + public partial class ChevronIcon : SpriteIcon { [Resolved] private OverlayColourProvider colourProvider { get; set; } diff --git a/osu.Game/Graphics/UserInterface/SlimEnumDropdown.cs b/osu.Game/Graphics/UserInterface/SlimEnumDropdown.cs index 534fcf76e5..e3f5bc65e6 100644 --- a/osu.Game/Graphics/UserInterface/SlimEnumDropdown.cs +++ b/osu.Game/Graphics/UserInterface/SlimEnumDropdown.cs @@ -9,12 +9,12 @@ using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterface { - public class SlimEnumDropdown : OsuEnumDropdown + public partial class SlimEnumDropdown : OsuEnumDropdown where T : struct, Enum { protected override DropdownHeader CreateHeader() => new SlimDropdownHeader(); - private class SlimDropdownHeader : OsuDropdownHeader + private partial class SlimDropdownHeader : OsuDropdownHeader { public SlimDropdownHeader() { diff --git a/osu.Game/Graphics/UserInterface/StarCounter.cs b/osu.Game/Graphics/UserInterface/StarCounter.cs index d9274bf2cb..d7d088d798 100644 --- a/osu.Game/Graphics/UserInterface/StarCounter.cs +++ b/osu.Game/Graphics/UserInterface/StarCounter.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public class StarCounter : Container + public partial class StarCounter : Container { private readonly FillFlowContainer stars; @@ -120,7 +120,7 @@ namespace osu.Game.Graphics.UserInterface } } - public class DefaultStar : Star + public partial class DefaultStar : Star { private const double scaling_duration = 1000; @@ -156,7 +156,7 @@ namespace osu.Game.Graphics.UserInterface } } - public abstract class Star : CompositeDrawable + public abstract partial class Star : CompositeDrawable { public abstract void DisplayAt(float scale); } diff --git a/osu.Game/Graphics/UserInterface/TimeSlider.cs b/osu.Game/Graphics/UserInterface/TimeSlider.cs index d45c6614aa..46f0821033 100644 --- a/osu.Game/Graphics/UserInterface/TimeSlider.cs +++ b/osu.Game/Graphics/UserInterface/TimeSlider.cs @@ -10,7 +10,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A slider bar which displays a millisecond time value. /// - public class TimeSlider : OsuSliderBar + public partial class TimeSlider : OsuSliderBar { public override LocalisableString TooltipText => $"{Current.Value:N0} ms"; } diff --git a/osu.Game/Graphics/UserInterface/TriangleButton.cs b/osu.Game/Graphics/UserInterface/TriangleButton.cs index 60d1824e5a..3038813b89 100644 --- a/osu.Game/Graphics/UserInterface/TriangleButton.cs +++ b/osu.Game/Graphics/UserInterface/TriangleButton.cs @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A button with moving triangles in the background. /// - public class TriangleButton : OsuButton, IFilterable + public partial class TriangleButton : OsuButton, IFilterable { protected Triangles Triangles { get; private set; } diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs index 1b8848f3d5..aa542b8f49 100644 --- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs +++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs @@ -22,7 +22,7 @@ using osu.Game.Screens.Select; namespace osu.Game.Graphics.UserInterface { - public class TwoLayerButton : OsuClickableContainer + public partial class TwoLayerButton : OsuClickableContainer { private readonly BouncingIcon bouncingIcon; @@ -207,7 +207,7 @@ namespace osu.Game.Graphics.UserInterface return base.OnClick(e); } - private class BouncingIcon : BeatSyncedContainer + private partial class BouncingIcon : BeatSyncedContainer { private const double beat_in_time = 60; diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs index 93852f19c4..9ddbf84c39 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourDisplay.cs @@ -24,7 +24,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 /// /// A component which displays a colour along with related description text. /// - public class ColourDisplay : CompositeDrawable, IHasCurrentValue + public partial class ColourDisplay : CompositeDrawable, IHasCurrentValue { /// /// Invoked when the user has requested the colour corresponding to this @@ -86,7 +86,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 }; } - private class ColourCircle : OsuClickableContainer, IHasPopover, IHasContextMenu + private partial class ColourCircle : OsuClickableContainer, IHasPopover, IHasContextMenu { public Bindable Current { get; } = new Bindable(); diff --git a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs index f61d6db8b1..f554887510 100644 --- a/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/ColourPalette.cs @@ -23,7 +23,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 /// /// A component which displays a collection of colours in individual s. /// - public class ColourPalette : CompositeDrawable + public partial class ColourPalette : CompositeDrawable { public BindableList Colours { get; } = new BindableList(); @@ -119,7 +119,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 } } - internal class AddColourButton : CompositeDrawable + internal partial class AddColourButton : CompositeDrawable { public Action Action { diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs index b144f8f696..721d8990ba 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledColourPalette.cs @@ -9,7 +9,7 @@ using osu.Framework.Localisation; namespace osu.Game.Graphics.UserInterfaceV2 { - public class LabelledColourPalette : LabelledDrawable + public partial class LabelledColourPalette : LabelledDrawable { public LabelledColourPalette() : base(true) diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs index 977ef5d7bc..8fd9a62ad7 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledComponent.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterfaceV2 { - public abstract class LabelledComponent : LabelledDrawable, IHasCurrentValue + public abstract partial class LabelledComponent : LabelledDrawable, IHasCurrentValue where TDrawable : Drawable, IHasCurrentValue { protected LabelledComponent(bool padded) diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs index 8c98a3e0a7..9b7087ce6d 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 { - public abstract class LabelledDrawable : CompositeDrawable + public abstract partial class LabelledDrawable : CompositeDrawable where T : Drawable { private float? fixedLabelWidth; diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs index bfb009658d..0e2ea362da 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterfaceV2 { - public class LabelledDropdown : LabelledComponent, TItem> + public partial class LabelledDropdown : LabelledComponent, TItem> { public LabelledDropdown() : base(true) diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs index 594f132154..3ca460be90 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterfaceV2 { - public class LabelledEnumDropdown : LabelledDropdown + public partial class LabelledEnumDropdown : LabelledDropdown where TEnum : struct, Enum { protected override OsuDropdown CreateDropdown() => new OsuEnumDropdown(); diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledNumberBox.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledNumberBox.cs index cb032698ef..2643db0547 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledNumberBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledNumberBox.cs @@ -7,7 +7,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterfaceV2 { - public class LabelledNumberBox : LabelledTextBox + public partial class LabelledNumberBox : LabelledTextBox { protected override OsuTextBox CreateTextBox() => new OsuNumberBox(); } diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledSliderBar.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledSliderBar.cs index 50b6834f01..00f4ef1a30 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledSliderBar.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledSliderBar.cs @@ -9,7 +9,7 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Graphics.UserInterfaceV2 { - public class LabelledSliderBar : LabelledComponent, TNumber> + public partial class LabelledSliderBar : LabelledComponent, TNumber> where TNumber : struct, IEquatable, IComparable, IConvertible { public LabelledSliderBar() diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs index 99a1a98d5b..3c27829de3 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledSwitchButton.cs @@ -5,7 +5,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { - public class LabelledSwitchButton : LabelledComponent + public partial class LabelledSwitchButton : LabelledComponent { public LabelledSwitchButton() : base(true) diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs index 97bc845766..454be02d0b 100644 --- a/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledTextBox.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterfaceV2 { - public class LabelledTextBox : LabelledComponent + public partial class LabelledTextBox : LabelledComponent { public event TextBox.OnCommitHandler OnCommit; diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuColourPicker.cs b/osu.Game/Graphics/UserInterfaceV2/OsuColourPicker.cs index f4ae2f0fd7..fed17eaf20 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuColourPicker.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuColourPicker.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterfaceV2 { - public class OsuColourPicker : ColourPicker + public partial class OsuColourPicker : ColourPicker { public OsuColourPicker() { diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelector.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelector.cs index 0e348108aa..21f926ba42 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelector.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelector.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Graphics.UserInterfaceV2 { - public class OsuDirectorySelector : DirectorySelector + public partial class OsuDirectorySelector : DirectorySelector { public const float ITEM_HEIGHT = 20; diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorBreadcrumbDisplay.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorBreadcrumbDisplay.cs index 08a569269e..0917b9db97 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorBreadcrumbDisplay.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorBreadcrumbDisplay.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 { - internal class OsuDirectorySelectorBreadcrumbDisplay : DirectorySelectorBreadcrumbDisplay + internal partial class OsuDirectorySelectorBreadcrumbDisplay : DirectorySelectorBreadcrumbDisplay { protected override Drawable CreateCaption() => new OsuSpriteText { @@ -30,7 +30,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 Padding = new MarginPadding(15); } - private class OsuBreadcrumbDisplayComputer : OsuBreadcrumbDisplayDirectory + private partial class OsuBreadcrumbDisplayComputer : OsuBreadcrumbDisplayDirectory { protected override IconUsage? Icon => null; @@ -40,7 +40,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 } } - private class OsuBreadcrumbDisplayDirectory : OsuDirectorySelectorDirectory + private partial class OsuBreadcrumbDisplayDirectory : OsuDirectorySelectorDirectory { public OsuBreadcrumbDisplayDirectory(DirectoryInfo directory, string displayName = null) : base(directory, displayName) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorDirectory.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorDirectory.cs index 1896d7ee4d..932017b03e 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorDirectory.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorDirectory.cs @@ -16,7 +16,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.UserInterfaceV2 { - internal class OsuDirectorySelectorDirectory : DirectorySelectorDirectory + internal partial class OsuDirectorySelectorDirectory : DirectorySelectorDirectory { public OsuDirectorySelectorDirectory(DirectoryInfo directory, string displayName = null) : base(directory, displayName) @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 ? FontAwesome.Solid.Database : FontAwesome.Regular.Folder; - internal class Background : CompositeDrawable + internal partial class Background : CompositeDrawable { [BackgroundDependencyLoader(true)] private void load(OverlayColourProvider overlayColourProvider, OsuColour colours) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs index 7aaf12ca34..7665ed507f 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorHiddenToggle.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.UserInterfaceV2 { - internal class OsuDirectorySelectorHiddenToggle : OsuCheckbox + internal partial class OsuDirectorySelectorHiddenToggle : OsuCheckbox { public OsuDirectorySelectorHiddenToggle() { diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorParentDirectory.cs b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorParentDirectory.cs index 7d2b28e803..beaeb86243 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorParentDirectory.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelectorParentDirectory.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Graphics.UserInterfaceV2 { - internal class OsuDirectorySelectorParentDirectory : OsuDirectorySelectorDirectory + internal partial class OsuDirectorySelectorParentDirectory : OsuDirectorySelectorDirectory { protected override IconUsage? Icon => FontAwesome.Solid.Folder; diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs b/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs index 70af68d595..37e15c6127 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs @@ -16,7 +16,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterfaceV2 { - public class OsuFileSelector : FileSelector + public partial class OsuFileSelector : FileSelector { public OsuFileSelector(string initialPath = null, string[] validFileExtensions = null) : base(initialPath, validFileExtensions) @@ -43,7 +43,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 protected override void NotifySelectionError() => this.FlashColour(Colour4.Red, 300); - protected class OsuDirectoryListingFile : DirectoryListingFile + protected partial class OsuDirectoryListingFile : DirectoryListingFile { public OsuDirectoryListingFile(FileInfo file) : base(file) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs b/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs index 1a8fa435cb..ff51f3aa92 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 { - public class OsuHSVColourPicker : HSVColourPicker + public partial class OsuHSVColourPicker : HSVColourPicker { private const float spacing = 10; private const float corner_radius = 10; @@ -42,7 +42,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 Colour = Colour4.Black.Opacity(0.3f) }; - private class OsuHueSelector : HueSelector + private partial class OsuHueSelector : HueSelector { public OsuHueSelector() { @@ -52,7 +52,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 protected override Drawable CreateSliderNub() => new SliderNub(this); - private class SliderNub : CompositeDrawable + private partial class SliderNub : CompositeDrawable { private readonly Bindable hue; private readonly Box fill; @@ -85,7 +85,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 } } - private class OsuSaturationValueSelector : SaturationValueSelector + private partial class OsuSaturationValueSelector : SaturationValueSelector { public OsuSaturationValueSelector() { @@ -95,7 +95,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 protected override Marker CreateMarker() => new OsuMarker(); - private class OsuMarker : Marker + private partial class OsuMarker : Marker { private readonly Box previewBox; diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuHexColourPicker.cs b/osu.Game/Graphics/UserInterfaceV2/OsuHexColourPicker.cs index 12313791f0..9aa650d88d 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuHexColourPicker.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuHexColourPicker.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays; namespace osu.Game.Graphics.UserInterfaceV2 { - public class OsuHexColourPicker : HexColourPicker + public partial class OsuHexColourPicker : HexColourPicker { public OsuHexColourPicker() { @@ -31,7 +31,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 protected override TextBox CreateHexCodeTextBox() => new OsuTextBox(); protected override ColourPreview CreateColourPreview() => new OsuColourPreview(); - private class OsuColourPreview : ColourPreview + private partial class OsuColourPreview : ColourPreview { private readonly Box preview; diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs index e468e14f45..e66e48373c 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 { - public class OsuPopover : Popover, IKeyBindingHandler + public partial class OsuPopover : Popover, IKeyBindingHandler { private const float fade_duration = 250; private const double scale_duration = 500; diff --git a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs index 4477633da1..8bdfa01e9c 100644 --- a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterfaceV2 { - public class RoundedButton : OsuButton, IFilterable + public partial class RoundedButton : OsuButton, IFilterable { public override float Height { diff --git a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs index b5c1c0a854..cf569a73ca 100644 --- a/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/SwitchButton.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.UserInterfaceV2 { - public class SwitchButton : Checkbox + public partial class SwitchButton : Checkbox { private const float border_thickness = 4.5f; private const float padding = 1.25f; @@ -128,7 +128,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 circularContainer.TransformBorderTo((Current.Value ? enabledColour : disabledColour).Lighten(IsHovered ? 0.3f : 0)); } - private class CircularBorderContainer : CircularContainer + private partial class CircularBorderContainer : CircularContainer { public void TransformBorderTo(ColourInfo colour) => this.TransformTo(nameof(BorderColour), colour, 250, Easing.OutQuint); diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs index 4f079ab435..fab0be6cf0 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs @@ -18,7 +18,7 @@ namespace osu.Game.Input.Bindings /// A KeyBindingInputManager with a database backing for custom overrides. /// /// The type of the custom action. - public class DatabasedKeyBindingContainer : KeyBindingContainer + public partial class DatabasedKeyBindingContainer : KeyBindingContainer where T : struct { private readonly RulesetInfo ruleset; diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index ebdc446ec8..07cef50dec 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Input.Bindings { - public class GlobalActionContainer : DatabasedKeyBindingContainer, IHandleGlobalKeyboardInput + public partial class GlobalActionContainer : DatabasedKeyBindingContainer, IHandleGlobalKeyboardInput { private readonly Drawable? handler; diff --git a/osu.Game/Input/ConfineMouseTracker.cs b/osu.Game/Input/ConfineMouseTracker.cs index 7e8ace5693..de8660dbce 100644 --- a/osu.Game/Input/ConfineMouseTracker.cs +++ b/osu.Game/Input/ConfineMouseTracker.cs @@ -18,7 +18,7 @@ namespace osu.Game.Input /// If is true, we should also confine the mouse cursor if it has been /// requested with . /// - public class ConfineMouseTracker : Component + public partial class ConfineMouseTracker : Component { private Bindable frameworkConfineMode; private Bindable frameworkWindowMode; diff --git a/osu.Game/Input/GameIdleTracker.cs b/osu.Game/Input/GameIdleTracker.cs index d82cc25851..560ec1bc1e 100644 --- a/osu.Game/Input/GameIdleTracker.cs +++ b/osu.Game/Input/GameIdleTracker.cs @@ -7,7 +7,7 @@ using osu.Framework.Input; namespace osu.Game.Input { - public class GameIdleTracker : IdleTracker + public partial class GameIdleTracker : IdleTracker { private InputManager inputManager; diff --git a/osu.Game/Input/IdleTracker.cs b/osu.Game/Input/IdleTracker.cs index 45036b3e41..54157c9e3d 100644 --- a/osu.Game/Input/IdleTracker.cs +++ b/osu.Game/Input/IdleTracker.cs @@ -17,7 +17,7 @@ namespace osu.Game.Input /// /// Track whether the end-user is in an idle state, based on their last interaction with the game. /// - public class IdleTracker : Component, IKeyBindingHandler, IKeyBindingHandler, IHandleGlobalKeyboardInput + public partial class IdleTracker : Component, IKeyBindingHandler, IKeyBindingHandler, IHandleGlobalKeyboardInput { private readonly double timeToIdle; diff --git a/osu.Game/Input/OsuUserInputManager.cs b/osu.Game/Input/OsuUserInputManager.cs index 7a9002a004..ab43497156 100644 --- a/osu.Game/Input/OsuUserInputManager.cs +++ b/osu.Game/Input/OsuUserInputManager.cs @@ -8,7 +8,7 @@ using osuTK.Input; namespace osu.Game.Input { - public class OsuUserInputManager : UserInputManager + public partial class OsuUserInputManager : UserInputManager { internal OsuUserInputManager() { diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 65f78e1fd7..f2b9b6e968 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -26,7 +26,7 @@ using osu.Game.Users; namespace osu.Game.Online.API { - public class APIAccess : Component, IAPIProvider + public partial class APIAccess : Component, IAPIProvider { private readonly OsuConfigManager config; diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 609efd8ab6..abe2755654 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -15,7 +15,7 @@ using osu.Game.Users; namespace osu.Game.Online.API { - public class DummyAPIAccess : Component, IAPIProvider + public partial class DummyAPIAccess : Component, IAPIProvider { public const int DUMMY_USER_ID = 1001; diff --git a/osu.Game/Online/BeatmapDownloadTracker.cs b/osu.Game/Online/BeatmapDownloadTracker.cs index 19708cc07d..144c4445a3 100644 --- a/osu.Game/Online/BeatmapDownloadTracker.cs +++ b/osu.Game/Online/BeatmapDownloadTracker.cs @@ -10,7 +10,7 @@ using osu.Game.Online.API; namespace osu.Game.Online { - public class BeatmapDownloadTracker : DownloadTracker + public partial class BeatmapDownloadTracker : DownloadTracker { [Resolved(CanBeNull = true)] protected BeatmapModelDownloader? Downloader { get; private set; } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 25a53360f0..eaef940d5f 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -24,7 +24,7 @@ namespace osu.Game.Online.Chat /// /// Manages everything channel related /// - public class ChannelManager : CompositeComponent, IChannelPostTarget + public partial class ChannelManager : CompositeComponent, IChannelPostTarget { /// /// The channels the player joins on startup diff --git a/osu.Game/Online/Chat/DrawableLinkCompiler.cs b/osu.Game/Online/Chat/DrawableLinkCompiler.cs index 44e66c1a69..ee53c00668 100644 --- a/osu.Game/Online/Chat/DrawableLinkCompiler.cs +++ b/osu.Game/Online/Chat/DrawableLinkCompiler.cs @@ -20,7 +20,7 @@ namespace osu.Game.Online.Chat /// /// An invisible drawable that brings multiple pieces together to form a consumable clickable link. /// - public class DrawableLinkCompiler : OsuHoverContainer + public partial class DrawableLinkCompiler : OsuHoverContainer { /// /// Each word part of a chat link (split for word-wrap support). @@ -52,7 +52,7 @@ namespace osu.Game.Online.Chat protected override IEnumerable EffectTargets => Parts; - private class LinkHoverSounds : HoverClickSounds + private partial class LinkHoverSounds : HoverClickSounds { private readonly List parts; diff --git a/osu.Game/Online/Chat/ExternalLinkOpener.cs b/osu.Game/Online/Chat/ExternalLinkOpener.cs index 587159179f..201212c648 100644 --- a/osu.Game/Online/Chat/ExternalLinkOpener.cs +++ b/osu.Game/Online/Chat/ExternalLinkOpener.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Online.Chat { - public class ExternalLinkOpener : Component + public partial class ExternalLinkOpener : Component { [Resolved] private GameHost host { get; set; } = null!; @@ -37,7 +37,7 @@ namespace osu.Game.Online.Chat host.OpenUrlExternally(url); } - public class ExternalLinkDialog : PopupDialog + public partial class ExternalLinkDialog : PopupDialog { public ExternalLinkDialog(string url, Action openExternalLinkAction, Action copyExternalLinkAction) { diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 22c2b4690e..4872d93467 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -23,7 +23,7 @@ namespace osu.Game.Online.Chat /// /// Component that handles creating and posting notifications for incoming messages. /// - public class MessageNotifier : Component + public partial class MessageNotifier : Component { [Resolved] private INotificationOverlay notifications { get; set; } @@ -138,7 +138,7 @@ namespace osu.Game.Online.Chat return Regex.IsMatch(message, $@"(^|\W)({fullName}|{underscoreName})($|\W)", RegexOptions.IgnoreCase); } - public class PrivateMessageNotification : HighlightMessageNotification + public partial class PrivateMessageNotification : HighlightMessageNotification { public PrivateMessageNotification(Message message, Channel channel) : base(message, channel) @@ -148,7 +148,7 @@ namespace osu.Game.Online.Chat } } - public class MentionNotification : HighlightMessageNotification + public partial class MentionNotification : HighlightMessageNotification { public MentionNotification(Message message, Channel channel) : base(message, channel) @@ -158,7 +158,7 @@ namespace osu.Game.Online.Chat } } - public abstract class HighlightMessageNotification : SimpleNotification + public abstract partial class HighlightMessageNotification : SimpleNotification { protected HighlightMessageNotification(Message message, Channel channel) { diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index 6a25ceb919..76f1de5f29 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -12,7 +12,7 @@ using osu.Game.Users; namespace osu.Game.Online.Chat { - public class NowPlayingCommand : Component + public partial class NowPlayingCommand : Component { [Resolved] private IChannelPostTarget channelManager { get; set; } diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index de68dd231f..9c89333ee7 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -23,7 +23,7 @@ namespace osu.Game.Online.Chat /// /// Display a chat channel in an insolated region. /// - public class StandAloneChatDisplay : CompositeDrawable + public partial class StandAloneChatDisplay : CompositeDrawable { public readonly Bindable Channel = new Bindable(); @@ -120,7 +120,7 @@ namespace osu.Game.Online.Chat AddInternal(drawableChannel); } - public class ChatTextBox : HistoryTextBox + public partial class ChatTextBox : HistoryTextBox { protected override bool OnKeyDown(KeyDownEvent e) { @@ -156,7 +156,7 @@ namespace osu.Game.Online.Chat public Action FocusLost; } - public class StandAloneDrawableChannel : DrawableChannel + public partial class StandAloneDrawableChannel : DrawableChannel { public Func CreateChatLineAction; @@ -170,7 +170,7 @@ namespace osu.Game.Online.Chat protected override DaySeparator CreateDaySeparator(DateTimeOffset time) => new StandAloneDaySeparator(time); } - protected class StandAloneDaySeparator : DaySeparator + protected partial class StandAloneDaySeparator : DaySeparator { protected override float TextSize => 14; protected override float LineHeight => 1; @@ -190,7 +190,7 @@ namespace osu.Game.Online.Chat } } - protected class StandAloneMessage : ChatLine + protected partial class StandAloneMessage : ChatLine { protected override float TextSize => 15; protected override float Spacing => 5; diff --git a/osu.Game/Online/DownloadTracker.cs b/osu.Game/Online/DownloadTracker.cs index 85af9abb33..27a765ca20 100644 --- a/osu.Game/Online/DownloadTracker.cs +++ b/osu.Game/Online/DownloadTracker.cs @@ -6,7 +6,7 @@ using osu.Framework.Graphics; namespace osu.Game.Online { - public abstract class DownloadTracker : Component + public abstract partial class DownloadTracker : Component where T : class { public readonly T TrackedItem; diff --git a/osu.Game/Online/Leaderboards/DrawableRank.cs b/osu.Game/Online/Leaderboards/DrawableRank.cs index 35bdc4e31f..5a65c15444 100644 --- a/osu.Game/Online/Leaderboards/DrawableRank.cs +++ b/osu.Game/Online/Leaderboards/DrawableRank.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Online.Leaderboards { - public class DrawableRank : CompositeDrawable + public partial class DrawableRank : CompositeDrawable { private readonly ScoreRank rank; diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 69b4e5b209..93aa0b95a7 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -31,7 +31,7 @@ namespace osu.Game.Online.Leaderboards /// /// The scope of the leaderboard (ie. global or local). /// The score model class. - public abstract class Leaderboard : CompositeDrawable + public abstract partial class Leaderboard : CompositeDrawable { /// /// The currently displayed scores. diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index a7b6bd044d..e20b28ee0c 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -37,7 +37,7 @@ using osu.Game.Utils; namespace osu.Game.Online.Leaderboards { - public class LeaderboardScore : OsuClickableContainer, IHasContextMenu, IHasCustomTooltip + public partial class LeaderboardScore : OsuClickableContainer, IHasContextMenu, IHasCustomTooltip { public const float HEIGHT = 60; @@ -310,7 +310,7 @@ namespace osu.Game.Online.Leaderboards base.OnHoverLost(e); } - private class ScoreComponentLabel : Container, IHasTooltip + private partial class ScoreComponentLabel : Container, IHasTooltip { private const float icon_size = 20; private readonly FillFlowContainer content; @@ -372,7 +372,7 @@ namespace osu.Game.Online.Leaderboards } } - private class RankLabel : Container, IHasTooltip + private partial class RankLabel : Container, IHasTooltip { public RankLabel(int? rank) { @@ -391,7 +391,7 @@ namespace osu.Game.Online.Leaderboards public LocalisableString TooltipText { get; } } - private class DateLabel : DrawableDate + private partial class DateLabel : DrawableDate { public DateLabel(DateTimeOffset date) : base(date) diff --git a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs index f51f57c031..170f266307 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs @@ -20,7 +20,7 @@ using osu.Game.Configuration; namespace osu.Game.Online.Leaderboards { - public class LeaderboardScoreTooltip : VisibilityContainer, ITooltip + public partial class LeaderboardScoreTooltip : VisibilityContainer, ITooltip { private OsuSpriteText timestampLabel = null!; private FillFlowContainer topScoreStatistics = null!; @@ -147,7 +147,7 @@ namespace osu.Game.Online.Leaderboards public void Move(Vector2 pos) => Position = pos; - private class HitResultCell : CompositeDrawable + private partial class HitResultCell : CompositeDrawable { private readonly LocalisableString displayName; private readonly HitResult result; @@ -189,7 +189,7 @@ namespace osu.Game.Online.Leaderboards } } - private class ModCell : CompositeDrawable + private partial class ModCell : CompositeDrawable { private readonly Mod mod; diff --git a/osu.Game/Online/Leaderboards/UpdateableRank.cs b/osu.Game/Online/Leaderboards/UpdateableRank.cs index e640fe8494..46cfe8ec65 100644 --- a/osu.Game/Online/Leaderboards/UpdateableRank.cs +++ b/osu.Game/Online/Leaderboards/UpdateableRank.cs @@ -9,7 +9,7 @@ using osu.Game.Scoring; namespace osu.Game.Online.Leaderboards { - public class UpdateableRank : ModelBackedDrawable + public partial class UpdateableRank : ModelBackedDrawable { public ScoreRank? Rank { diff --git a/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs b/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs index 391e8804f0..af59da2fb8 100644 --- a/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs +++ b/osu.Game/Online/Leaderboards/UserTopScoreContainer.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Online.Leaderboards { - public class UserTopScoreContainer : VisibilityContainer + public partial class UserTopScoreContainer : VisibilityContainer { private const int duration = 500; diff --git a/osu.Game/Online/Metadata/MetadataClient.cs b/osu.Game/Online/Metadata/MetadataClient.cs index 60867da2d7..d4e7540fe7 100644 --- a/osu.Game/Online/Metadata/MetadataClient.cs +++ b/osu.Game/Online/Metadata/MetadataClient.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; namespace osu.Game.Online.Metadata { - public abstract class MetadataClient : Component, IMetadataClient, IMetadataServer + public abstract partial class MetadataClient : Component, IMetadataClient, IMetadataServer { public abstract Task BeatmapSetsUpdated(BeatmapUpdates updates); diff --git a/osu.Game/Online/Metadata/OnlineMetadataClient.cs b/osu.Game/Online/Metadata/OnlineMetadataClient.cs index 06d24a82f3..ba7ccb24f7 100644 --- a/osu.Game/Online/Metadata/OnlineMetadataClient.cs +++ b/osu.Game/Online/Metadata/OnlineMetadataClient.cs @@ -13,7 +13,7 @@ using osu.Game.Online.API; namespace osu.Game.Online.Metadata { - public class OnlineMetadataClient : MetadataClient + public partial class OnlineMetadataClient : MetadataClient { private readonly string endpoint; diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index b39781ebc2..bd87f2d43e 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -26,7 +26,7 @@ using osu.Game.Utils; namespace osu.Game.Online.Multiplayer { - public abstract class MultiplayerClient : Component, IMultiplayerClient, IMultiplayerRoomServer + public abstract partial class MultiplayerClient : Component, IMultiplayerClient, IMultiplayerRoomServer { public Action? PostNotification { protected get; set; } diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 190d150502..386a3d5262 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -18,7 +18,7 @@ namespace osu.Game.Online.Multiplayer /// /// A with online connectivity. /// - public class OnlineMultiplayerClient : MultiplayerClient + public partial class OnlineMultiplayerClient : MultiplayerClient { private readonly string endpoint; diff --git a/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs b/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs index c114741be8..1de18e44a7 100644 --- a/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs +++ b/osu.Game/Online/Multiplayer/ServerShutdownNotification.cs @@ -10,7 +10,7 @@ using osu.Game.Utils; namespace osu.Game.Online.Multiplayer { - public class ServerShutdownNotification : SimpleNotification + public partial class ServerShutdownNotification : SimpleNotification { private readonly DateTimeOffset endDate; private ScheduledDelegate? updateDelegate; diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 7af1ac9d5d..46f64fbb61 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Online /// A for displaying online content which require a local user to be logged in. /// Shows its children only when the local user is logged in and supports displaying a placeholder if not. /// - public class OnlineViewContainer : Container + public partial class OnlineViewContainer : Container { protected LoadingSpinner LoadingSpinner { get; private set; } diff --git a/osu.Game/Online/Placeholders/ClickablePlaceholder.cs b/osu.Game/Online/Placeholders/ClickablePlaceholder.cs index 7f9e16399e..9bef1d4b7a 100644 --- a/osu.Game/Online/Placeholders/ClickablePlaceholder.cs +++ b/osu.Game/Online/Placeholders/ClickablePlaceholder.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Online.Placeholders { - public class ClickablePlaceholder : Placeholder + public partial class ClickablePlaceholder : Placeholder { public Action Action; diff --git a/osu.Game/Online/Placeholders/LoginPlaceholder.cs b/osu.Game/Online/Placeholders/LoginPlaceholder.cs index 6a4065208e..de7ac6e936 100644 --- a/osu.Game/Online/Placeholders/LoginPlaceholder.cs +++ b/osu.Game/Online/Placeholders/LoginPlaceholder.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays; namespace osu.Game.Online.Placeholders { - public sealed class LoginPlaceholder : ClickablePlaceholder + public sealed partial class LoginPlaceholder : ClickablePlaceholder { [Resolved(CanBeNull = true)] private LoginOverlay login { get; set; } diff --git a/osu.Game/Online/Placeholders/MessagePlaceholder.cs b/osu.Game/Online/Placeholders/MessagePlaceholder.cs index 451a4cba85..07a111a10f 100644 --- a/osu.Game/Online/Placeholders/MessagePlaceholder.cs +++ b/osu.Game/Online/Placeholders/MessagePlaceholder.cs @@ -9,7 +9,7 @@ using osu.Framework.Localisation; namespace osu.Game.Online.Placeholders { - public class MessagePlaceholder : Placeholder + public partial class MessagePlaceholder : Placeholder { private readonly LocalisableString message; diff --git a/osu.Game/Online/Placeholders/Placeholder.cs b/osu.Game/Online/Placeholders/Placeholder.cs index 3a05ce1365..37669fb899 100644 --- a/osu.Game/Online/Placeholders/Placeholder.cs +++ b/osu.Game/Online/Placeholders/Placeholder.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Online.Placeholders { - public abstract class Placeholder : OsuTextFlowContainer, IEquatable + public abstract partial class Placeholder : OsuTextFlowContainer, IEquatable { protected const float TEXT_SIZE = 22; diff --git a/osu.Game/Online/PollingComponent.cs b/osu.Game/Online/PollingComponent.cs index fcea650e2d..a44308c726 100644 --- a/osu.Game/Online/PollingComponent.cs +++ b/osu.Game/Online/PollingComponent.cs @@ -16,7 +16,7 @@ namespace osu.Game.Online /// /// A component which requires a constant polling process. /// - public abstract class PollingComponent : CompositeComponent + public abstract partial class PollingComponent : CompositeComponent { private double? lastTimePolled; diff --git a/osu.Game/Online/Rooms/APICreatedRoom.cs b/osu.Game/Online/Rooms/APICreatedRoom.cs index ca1179efeb..254a338a60 100644 --- a/osu.Game/Online/Rooms/APICreatedRoom.cs +++ b/osu.Game/Online/Rooms/APICreatedRoom.cs @@ -7,7 +7,7 @@ using Newtonsoft.Json; namespace osu.Game.Online.Rooms { - public class APICreatedRoom : Room + public partial class APICreatedRoom : Room { [JsonProperty("error")] public string Error { get; set; } diff --git a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs index 7f8f9703e4..1d496cc636 100644 --- a/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game/Online/Rooms/OnlinePlayBeatmapAvailabilityTracker.cs @@ -27,7 +27,7 @@ namespace osu.Game.Online.Rooms /// This differs from a regular download tracking composite as this accounts for the /// databased beatmap set's checksum, to disallow from playing with an altered version of the beatmap. /// - public class OnlinePlayBeatmapAvailabilityTracker : CompositeComponent + public partial class OnlinePlayBeatmapAvailabilityTracker : CompositeComponent { public readonly IBindable SelectedItem = new Bindable(); diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index adfd4c226a..bdd7d6ce1c 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -16,7 +16,7 @@ using osu.Game.Online.Rooms.RoomStatuses; namespace osu.Game.Online.Rooms { [JsonObject(MemberSerialization.OptIn)] - public class Room + public partial class Room { [Cached] [JsonProperty("id")] diff --git a/osu.Game/Online/ScoreDownloadTracker.cs b/osu.Game/Online/ScoreDownloadTracker.cs index 680bb16264..4ddcb40368 100644 --- a/osu.Game/Online/ScoreDownloadTracker.cs +++ b/osu.Game/Online/ScoreDownloadTracker.cs @@ -11,7 +11,7 @@ using osu.Game.Scoring; namespace osu.Game.Online { - public class ScoreDownloadTracker : DownloadTracker + public partial class ScoreDownloadTracker : DownloadTracker { [Resolved(CanBeNull = true)] protected ScoreModelDownloader? Downloader { get; private set; } diff --git a/osu.Game/Online/Spectator/OnlineSpectatorClient.cs b/osu.Game/Online/Spectator/OnlineSpectatorClient.cs index 48d5c0bea9..d69bd81b57 100644 --- a/osu.Game/Online/Spectator/OnlineSpectatorClient.cs +++ b/osu.Game/Online/Spectator/OnlineSpectatorClient.cs @@ -12,7 +12,7 @@ using osu.Game.Online.Multiplayer; namespace osu.Game.Online.Spectator { - public class OnlineSpectatorClient : SpectatorClient + public partial class OnlineSpectatorClient : SpectatorClient { private readonly string endpoint; diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index 592bae80ba..b0ee0bc37b 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -21,7 +21,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Online.Spectator { - public abstract class SpectatorClient : Component, ISpectatorClient + public abstract partial class SpectatorClient : Component, ISpectatorClient { /// /// The maximum milliseconds between frame bundle sends. diff --git a/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs b/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs index 573c504add..c97871c3aa 100644 --- a/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs +++ b/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs @@ -21,7 +21,7 @@ namespace osu.Game.Online.Spectator /// A wrapper over a for spectated users. /// This should be used when a local "playable" beatmap is unavailable or expensive to generate for the spectated user. /// - public class SpectatorScoreProcessor : Component + public partial class SpectatorScoreProcessor : Component { /// /// The current total score. diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index a93c187e53..544b8ad837 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -71,7 +71,7 @@ namespace osu.Game /// for initial components that are generally retrieved via DI. /// [Cached(typeof(OsuGame))] - public class OsuGame : OsuGameBase, IKeyBindingHandler, ILocalUserPlayInfo, IPerformFromScreenRunner, IOverlayManager, ILinkHandler + public partial class OsuGame : OsuGameBase, IKeyBindingHandler, ILocalUserPlayInfo, IPerformFromScreenRunner, IOverlayManager, ILinkHandler { /// /// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications). diff --git a/osu.Game/Overlays/AccountCreation/AccountCreationBackground.cs b/osu.Game/Overlays/AccountCreation/AccountCreationBackground.cs index 2b372c18eb..0042b9f8f6 100644 --- a/osu.Game/Overlays/AccountCreation/AccountCreationBackground.cs +++ b/osu.Game/Overlays/AccountCreation/AccountCreationBackground.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Overlays.AccountCreation { - public class AccountCreationBackground : Sprite + public partial class AccountCreationBackground : Sprite { public AccountCreationBackground() { diff --git a/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs b/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs index 299a41f45b..a7dd53f511 100644 --- a/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs +++ b/osu.Game/Overlays/AccountCreation/AccountCreationScreen.cs @@ -8,7 +8,7 @@ using osu.Framework.Screens; namespace osu.Game.Overlays.AccountCreation { - public abstract class AccountCreationScreen : Screen + public abstract partial class AccountCreationScreen : Screen { public override void OnEntering(ScreenTransitionEvent e) { diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs index 2120f351a2..ea1ee2c9a9 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs @@ -25,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.AccountCreation { - public class ScreenEntry : AccountCreationScreen + public partial class ScreenEntry : AccountCreationScreen { private ErrorTextFlowContainer usernameDescription; private ErrorTextFlowContainer emailAddressDescription; diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index f8070788c2..a833a871f9 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.AccountCreation { - public class ScreenWarning : AccountCreationScreen + public partial class ScreenWarning : AccountCreationScreen { private OsuTextFlowContainer multiAccountExplanationText; private LinkFlowContainer furtherAssistance; diff --git a/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs b/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs index 1936ad533a..4becb225f8 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWelcome.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Overlays.AccountCreation { - public class ScreenWelcome : AccountCreationScreen + public partial class ScreenWelcome : AccountCreationScreen { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs index c51ed07c38..6f79316670 100644 --- a/osu.Game/Overlays/AccountCreationOverlay.cs +++ b/osu.Game/Overlays/AccountCreationOverlay.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public class AccountCreationOverlay : OsuFocusedOverlayContainer + public partial class AccountCreationOverlay : OsuFocusedOverlayContainer { private const float transition_time = 400; diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingCardSizeTabControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingCardSizeTabControl.cs index 13da9d335c..feb0c27ee7 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingCardSizeTabControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingCardSizeTabControl.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapListingCardSizeTabControl : OsuTabControl + public partial class BeatmapListingCardSizeTabControl : OsuTabControl { public BeatmapListingCardSizeTabControl() { @@ -35,7 +35,7 @@ namespace osu.Game.Overlays.BeatmapListing protected override TabItem CreateTabItem(BeatmapCardSize value) => new TabItem(value); - private class TabItem : TabItem + private partial class TabItem : TabItem { private Box background; private SpriteIcon icon; diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs index ff9a46ed4f..c5c252fb5d 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingFilterControl.cs @@ -26,7 +26,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapListingFilterControl : CompositeDrawable + public partial class BeatmapListingFilterControl : CompositeDrawable { /// /// Fired when a search finishes. diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs index ccab810612..76b6dec65b 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingHeader.cs @@ -8,11 +8,11 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapListingHeader : OverlayHeader + public partial class BeatmapListingHeader : OverlayHeader { protected override OverlayTitle CreateTitle() => new BeatmapListingTitle(); - private class BeatmapListingTitle : OverlayTitle + private partial class BeatmapListingTitle : OverlayTitle { public BeatmapListingTitle() { diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index 86cf3b5588..f28ec9c295 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -24,7 +24,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapListingSearchControl : CompositeDrawable + public partial class BeatmapListingSearchControl : CompositeDrawable { /// /// Any time the text box receives key events (even while masked). @@ -165,7 +165,7 @@ namespace osu.Game.Overlays.BeatmapListing public void TakeFocus() => textBox.TakeFocus(); - private class BeatmapSearchTextBox : BasicSearchTextBox + private partial class BeatmapSearchTextBox : BasicSearchTextBox { /// /// Any time the text box receives key events (even while masked). @@ -198,7 +198,7 @@ namespace osu.Game.Overlays.BeatmapListing } } - private class TopSearchBeatmapSetCover : UpdateableOnlineBeatmapSetCover + private partial class TopSearchBeatmapSetCover : UpdateableOnlineBeatmapSetCover { protected override bool TransformImmediately => true; } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs index bc1f30dcaf..34e0408db6 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSortTabControl.cs @@ -13,7 +13,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapListingSortTabControl : OverlaySortTabControl + public partial class BeatmapListingSortTabControl : OverlaySortTabControl { public readonly Bindable SortDirection = new Bindable(Overlays.SortDirection.Descending); @@ -72,7 +72,7 @@ namespace osu.Game.Overlays.BeatmapListing SortDirection = { BindTarget = SortDirection }, }; - private class BeatmapSortTabControl : SortTabControl + private partial class BeatmapSortTabControl : SortTabControl { protected override bool AddEnumEntriesAutomatically => false; @@ -84,7 +84,7 @@ namespace osu.Game.Overlays.BeatmapListing }; } - private class BeatmapSortTabItem : SortTabItem + private partial class BeatmapSortTabItem : SortTabItem { public readonly Bindable SortDirection = new Bindable(); @@ -100,7 +100,7 @@ namespace osu.Game.Overlays.BeatmapListing }; } - private class BeatmapTabButton : TabButton + private partial class BeatmapTabButton : TabButton { public readonly Bindable SortDirection = new Bindable(); diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs index 8ae39aeaca..3ab0e47a6c 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs @@ -18,7 +18,7 @@ using osu.Framework.Localisation; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapSearchFilterRow : CompositeDrawable, IHasCurrentValue + public partial class BeatmapSearchFilterRow : CompositeDrawable, IHasCurrentValue { private readonly BindableWithCurrent current = new BindableWithCurrent(); @@ -69,7 +69,7 @@ namespace osu.Game.Overlays.BeatmapListing [NotNull] protected virtual Drawable CreateFilter() => new BeatmapSearchFilter(); - protected class BeatmapSearchFilter : TabControl + protected partial class BeatmapSearchFilter : TabControl { public BeatmapSearchFilter() { @@ -98,7 +98,7 @@ namespace osu.Game.Overlays.BeatmapListing protected override TabItem CreateTabItem(T value) => new FilterTabItem(value); - private class FilterDropdown : OsuTabDropdown + private partial class FilterDropdown : OsuTabDropdown { protected override DropdownHeader CreateHeader() => new FilterHeader { @@ -106,7 +106,7 @@ namespace osu.Game.Overlays.BeatmapListing Origin = Anchor.TopRight }; - private class FilterHeader : OsuTabDropdownHeader + private partial class FilterHeader : OsuTabDropdownHeader { public FilterHeader() { diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs index c01aa9a1c4..10ec66e396 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapSearchGeneralFilterRow : BeatmapSearchMultipleSelectionFilterRow + public partial class BeatmapSearchGeneralFilterRow : BeatmapSearchMultipleSelectionFilterRow { public BeatmapSearchGeneralFilterRow() : base(BeatmapsStrings.ListingSearchFiltersGeneral) @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.BeatmapListing protected override MultipleSelectionFilter CreateMultipleSelectionFilter() => new GeneralFilter(); - private class GeneralFilter : MultipleSelectionFilter + private partial class GeneralFilter : MultipleSelectionFilter { protected override MultipleSelectionFilterTabItem CreateTabItem(SearchGeneral value) { @@ -30,7 +30,7 @@ namespace osu.Game.Overlays.BeatmapListing } } - private class FeaturedArtistsTabItem : MultipleSelectionFilterTabItem + private partial class FeaturedArtistsTabItem : MultipleSelectionFilterTabItem { public FeaturedArtistsTabItem() : base(SearchGeneral.FeaturedArtists) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index cca75e9548..79a794a9ad 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapSearchMultipleSelectionFilterRow : BeatmapSearchFilterRow> + public partial class BeatmapSearchMultipleSelectionFilterRow : BeatmapSearchFilterRow> { public new readonly BindableList Current = new BindableList(); @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapListing [NotNull] protected virtual MultipleSelectionFilter CreateMultipleSelectionFilter() => new MultipleSelectionFilter(); - protected class MultipleSelectionFilter : FillFlowContainer + protected partial class MultipleSelectionFilter : FillFlowContainer { public readonly BindableList Current = new BindableList(); @@ -85,7 +85,7 @@ namespace osu.Game.Overlays.BeatmapListing } } - protected class MultipleSelectionFilterTabItem : FilterTabItem + protected partial class MultipleSelectionFilterTabItem : FilterTabItem { public MultipleSelectionFilterTabItem(T value) : base(value) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs index 526c14511e..fa37810f37 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapSearchRulesetFilterRow : BeatmapSearchFilterRow + public partial class BeatmapSearchRulesetFilterRow : BeatmapSearchFilterRow { public BeatmapSearchRulesetFilterRow() : base(BeatmapsStrings.ListingSearchFiltersMode) @@ -20,7 +20,7 @@ namespace osu.Game.Overlays.BeatmapListing protected override Drawable CreateFilter() => new RulesetFilter(); - private class RulesetFilter : BeatmapSearchFilter + private partial class RulesetFilter : BeatmapSearchFilter { [BackgroundDependencyLoader] private void load(RulesetStore rulesets) @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.BeatmapListing } } - private class RulesetFilterTabItemAny : FilterTabItem + private partial class RulesetFilterTabItemAny : FilterTabItem { protected override LocalisableString LabelFor(RulesetInfo info) => BeatmapsStrings.ModeAny; diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs index 09b44be6c9..031833a107 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs @@ -12,7 +12,7 @@ using osu.Game.Scoring; namespace osu.Game.Overlays.BeatmapListing { - public class BeatmapSearchScoreFilterRow : BeatmapSearchMultipleSelectionFilterRow + public partial class BeatmapSearchScoreFilterRow : BeatmapSearchMultipleSelectionFilterRow { public BeatmapSearchScoreFilterRow() : base(BeatmapsStrings.ListingSearchFiltersRank) @@ -21,14 +21,14 @@ namespace osu.Game.Overlays.BeatmapListing protected override MultipleSelectionFilter CreateMultipleSelectionFilter() => new RankFilter(); - private class RankFilter : MultipleSelectionFilter + private partial class RankFilter : MultipleSelectionFilter { protected override MultipleSelectionFilterTabItem CreateTabItem(ScoreRank value) => new RankItem(value); protected override IEnumerable GetValues() => base.GetValues().Where(r => r > ScoreRank.F).Reverse(); } - private class RankItem : MultipleSelectionFilterTabItem + private partial class RankItem : MultipleSelectionFilterTabItem { public RankItem(ScoreRank value) : base(value) diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index cc131ffc27..7b95ae8ea8 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapListing { - public class FilterTabItem : TabItem + public partial class FilterTabItem : TabItem { [Resolved] private OverlayColourProvider colourProvider { get; set; } diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 2d9583b864..d6d4f1a67b 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -31,7 +31,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public class BeatmapListingOverlay : OnlineOverlay + public partial class BeatmapListingOverlay : OnlineOverlay { [Resolved] private PreviewTrackManager previewTrackManager { get; set; } @@ -248,7 +248,7 @@ namespace osu.Game.Overlays base.Dispose(isDisposing); } - public class NotFoundDrawable : CompositeDrawable + public partial class NotFoundDrawable : CompositeDrawable { public NotFoundDrawable() { @@ -292,7 +292,7 @@ namespace osu.Game.Overlays // TODO: localisation requires Text/LinkFlowContainer support for localising strings with links inside // (https://github.com/ppy/osu-framework/issues/4530) - public class SupporterRequiredDrawable : CompositeDrawable + public partial class SupporterRequiredDrawable : CompositeDrawable { private LinkFlowContainer supporterRequiredText; diff --git a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs index 2341997626..1d01495188 100644 --- a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs +++ b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs @@ -21,7 +21,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.BeatmapSet { - public class AuthorInfo : Container + public partial class AuthorInfo : Container { private const float height = 50; @@ -105,7 +105,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - private class Field : FillFlowContainer + private partial class Field : FillFlowContainer { public Field(string first, string second, FontUsage secondFont) { diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index a8bbb9fe1c..4a9a3d8089 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Overlays.BeatmapSet { - public class BasicStats : Container + public partial class BasicStats : Container { private readonly Statistic length, bpm, circleCount, sliderCount; @@ -117,7 +117,7 @@ namespace osu.Game.Overlays.BeatmapSet updateDisplay(); } - private class Statistic : Container, IHasTooltip + private partial class Statistic : Container, IHasTooltip { private readonly OsuSpriteText value; diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs b/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs index d893ef80d8..d18e1c93c9 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapAvailability.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet { - public class BeatmapAvailability : Container + public partial class BeatmapAvailability : Container { private APIBeatmapSet beatmapSet; diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapBadge.cs b/osu.Game/Overlays/BeatmapSet/BeatmapBadge.cs index 52fed99431..feb27aaa60 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapBadge.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapBadge.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.BeatmapSet { - public abstract class BeatmapBadge : CompositeDrawable + public abstract partial class BeatmapBadge : CompositeDrawable { /// /// The text displayed on the badge's label. diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index b27d9b3f1e..84d12f2611 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Overlays.BeatmapSet { - public class BeatmapPicker : Container + public partial class BeatmapPicker : Container { private const float tile_icon_padding = 7; private const float tile_spacing = 2; @@ -209,7 +209,7 @@ namespace osu.Game.Overlays.BeatmapSet Difficulties.Children.ToList().ForEach(diff => diff.State = diff.Beatmap == Beatmap.Value ? DifficultySelectorState.Selected : DifficultySelectorState.NotSelected); } - public class DifficultiesContainer : FillFlowContainer + public partial class DifficultiesContainer : FillFlowContainer { public Action OnLostHover; @@ -220,7 +220,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - public class DifficultySelectorButton : OsuClickableContainer, IStateful + public partial class DifficultySelectorButton : OsuClickableContainer, IStateful { private const float transition_duration = 100; private const float size = 54; @@ -325,7 +325,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - private class Statistic : FillFlowContainer + private partial class Statistic : FillFlowContainer { private readonly OsuSpriteText text; diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index 0f5eb18c4e..9291988367 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -11,7 +11,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.BeatmapSet { - public class BeatmapRulesetSelector : OverlayRulesetSelector + public partial class BeatmapRulesetSelector : OverlayRulesetSelector { private readonly Bindable beatmapSet = new Bindable(); diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs index e9acca5bcd..f802807c3c 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets; namespace osu.Game.Overlays.BeatmapSet { - public class BeatmapRulesetTabItem : OverlayRulesetTabItem + public partial class BeatmapRulesetTabItem : OverlayRulesetTabItem { public readonly Bindable BeatmapSet = new Bindable(); diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs index 02da7812d1..fa9c9b5018 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeader.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet { - public class BeatmapSetHeader : OverlayHeader + public partial class BeatmapSetHeader : OverlayHeader { public readonly Bindable BeatmapSet = new Bindable(); @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.BeatmapSet protected override OverlayTitle CreateTitle() => new BeatmapHeaderTitle(); - private class BeatmapHeaderTitle : OverlayTitle + private partial class BeatmapHeaderTitle : OverlayTitle { public BeatmapHeaderTitle() { diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs index 9e14122ae4..0318dad0e3 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs @@ -26,7 +26,7 @@ using osuTK; namespace osu.Game.Overlays.BeatmapSet { - public class BeatmapSetHeaderContent : CompositeDrawable + public partial class BeatmapSetHeaderContent : CompositeDrawable { public readonly Bindable BeatmapSet = new Bindable(); diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs index 797b6716e7..305a3661a7 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet { - public class BeatmapSetLayoutSection : Container + public partial class BeatmapSetLayoutSection : Container { public BeatmapSetLayoutSection() { diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs index f7c8aa44ad..cbdb2ea190 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs @@ -21,7 +21,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.BeatmapSet.Buttons { - public class FavouriteButton : HeaderButton, IHasTooltip + public partial class FavouriteButton : HeaderButton, IHasTooltip { public readonly Bindable BeatmapSet = new Bindable(); diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs index 25d11bd6d7..c653b058ee 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.BeatmapSet.Buttons { - public class HeaderButton : TriangleButton + public partial class HeaderButton : TriangleButton { public HeaderButton() { diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs index c2de96f245..d8dcf2b51b 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs @@ -26,7 +26,7 @@ using CommonStrings = osu.Game.Localisation.CommonStrings; namespace osu.Game.Overlays.BeatmapSet.Buttons { - public class HeaderDownloadButton : CompositeDrawable, IHasTooltip + public partial class HeaderDownloadButton : CompositeDrawable, IHasTooltip { private const int text_size = 12; diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs index 0ce55ce549..c43be33290 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PlayButton.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet.Buttons { - public class PlayButton : Container + public partial class PlayButton : Container { public IBindable Playing => playing; diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs index 8fc8927c4b..b3b8b80a0d 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/PreviewButton.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Overlays.BeatmapSet.Buttons { - public class PreviewButton : OsuClickableContainer + public partial class PreviewButton : OsuClickableContainer { private readonly Box background, progress; private readonly PlayButton playButton; diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs index 6db54db811..cf78f605aa 100644 --- a/osu.Game/Overlays/BeatmapSet/Details.cs +++ b/osu.Game/Overlays/BeatmapSet/Details.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Overlays.BeatmapSet { - public class Details : FillFlowContainer + public partial class Details : FillFlowContainer { protected readonly UserRatings Ratings; @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.BeatmapSet updateDisplay(); } - private class DetailBox : Container + private partial class DetailBox : Container { private readonly Container content; private readonly Box background; diff --git a/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapBadge.cs b/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapBadge.cs index 18dcfc0385..f666961784 100644 --- a/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapBadge.cs +++ b/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapBadge.cs @@ -7,7 +7,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet { - public class ExplicitContentBeatmapBadge : BeatmapBadge + public partial class ExplicitContentBeatmapBadge : BeatmapBadge { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapBadge.cs b/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapBadge.cs index a0ee0a18ec..6090ec6fae 100644 --- a/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapBadge.cs +++ b/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapBadge.cs @@ -7,7 +7,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet { - public class FeaturedArtistBeatmapBadge : BeatmapBadge + public partial class FeaturedArtistBeatmapBadge : BeatmapBadge { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs index 08423f2aa7..514a4ea8cd 100644 --- a/osu.Game/Overlays/BeatmapSet/Info.cs +++ b/osu.Game/Overlays/BeatmapSet/Info.cs @@ -14,7 +14,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.BeatmapSet { - public class Info : Container + public partial class Info : Container { private const float metadata_width = 175; private const float spacing = 20; diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs index 8311368da3..9c8f810607 100644 --- a/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs @@ -20,7 +20,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Overlays.BeatmapSet { - public class LeaderboardModSelector : CompositeDrawable + public partial class LeaderboardModSelector : CompositeDrawable { public readonly BindableList SelectedMods = new BindableList(); public readonly Bindable Ruleset = new Bindable(); @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.BeatmapSet public void DeselectAll() => modsContainer.ForEach(mod => mod.Selected.Value = false); - private class ModButton : ModIcon + private partial class ModButton : ModIcon { private const int duration = 200; diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs index db7d04f597..476a252c7b 100644 --- a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics; namespace osu.Game.Overlays.BeatmapSet { - public class LeaderboardScopeSelector : GradientLineTabControl + public partial class LeaderboardScopeSelector : GradientLineTabControl { protected override bool AddEnumEntriesAutomatically => false; @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.BeatmapSet LineColour = colourProvider.Background1; } - private class ScopeSelectorTabItem : PageTabItem + private partial class ScopeSelectorTabItem : PageTabItem { public ScopeSelectorTabItem(BeatmapLeaderboardScope value) : base(value) diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs index 317b369d8f..6390c52ff3 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet { - public class MetadataSection : Container + public partial class MetadataSection : Container { private readonly FillFlowContainer textContainer; private readonly MetadataType type; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs index 06bf9e1d50..01e4416156 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet.Scores { - public class DrawableTopScore : CompositeDrawable + public partial class DrawableTopScore : CompositeDrawable { private readonly Box background; @@ -89,7 +89,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores background.Colour = colourProvider.Background4; } - private class AutoSizingGrid : GridContainer + private partial class AutoSizingGrid : GridContainer { public AutoSizingGrid() { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs b/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs index 47690bab1f..f7703af27d 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs @@ -12,7 +12,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet.Scores { - public class NoScoresPlaceholder : Container + public partial class NoScoresPlaceholder : Container { private readonly SpriteText text; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs b/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs index b83b4d6b26..04ab3ec72f 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs @@ -13,7 +13,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet.Scores { - public class NotSupporterPlaceholder : Container + public partial class NotSupporterPlaceholder : Container { public NotSupporterPlaceholder() { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 11aefd435d..006eec2838 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -28,7 +28,7 @@ using osu.Game.Scoring.Drawables; namespace osu.Game.Overlays.BeatmapSet.Scores { - public class ScoreTable : TableContainer + public partial class ScoreTable : TableContainer { private const float horizontal_inset = 20; private const float row_height = 22; @@ -207,7 +207,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default); - private class HeaderText : OsuSpriteText + private partial class HeaderText : OsuSpriteText { public HeaderText(LocalisableString text) { @@ -222,7 +222,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } } - private class StatisticText : OsuSpriteText, IHasTooltip + private partial class StatisticText : OsuSpriteText, IHasTooltip { private readonly double? count; private readonly double? maxCount; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs index c17bb70bc2..130dfd45e7 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs @@ -14,7 +14,7 @@ using osu.Game.Scoring; namespace osu.Game.Overlays.BeatmapSet.Scores { - public class ScoreTableRowBackground : CompositeDrawable + public partial class ScoreTableRowBackground : CompositeDrawable { private const int fade_duration = 100; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreboardTime.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreboardTime.cs index 72aa221432..04cbf171f6 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreboardTime.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreboardTime.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.BeatmapSet.Scores { - public class ScoreboardTime : DrawableDate + public partial class ScoreboardTime : DrawableDate { public ScoreboardTime(DateTimeOffset date, float textSize = OsuFont.DEFAULT_FONT_SIZE, bool italic = true) : base(date, textSize, italic) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 53818bbee3..9eb04d9cc5 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -24,7 +24,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.BeatmapSet.Scores { - public class ScoresContainer : BeatmapSetLayoutSection + public partial class ScoresContainer : BeatmapSetLayoutSection { private const int spacing = 15; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs index 653bfd6d2c..e030b1e34f 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Overlays.BeatmapSet.Scores { - public class TopScoreStatisticsSection : CompositeDrawable + public partial class TopScoreStatisticsSection : CompositeDrawable { private const float margin = 10; private const float top_columns_min_width = 64; @@ -143,7 +143,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Text = stat.MaxCount == null ? stat.Count.ToLocalisableString(@"N0") : (LocalisableString)$"{stat.Count}/{stat.MaxCount}" }; - private class InfoColumn : CompositeDrawable + private partial class InfoColumn : CompositeDrawable { private readonly Box separator; private readonly OsuSpriteText text; @@ -204,7 +204,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } } - private class TextColumn : InfoColumn, IHasCurrentValue + private partial class TextColumn : InfoColumn, IHasCurrentValue { private readonly OsuTextFlowContainer text; @@ -249,7 +249,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } } - private class ModsInfoColumn : InfoColumn + private partial class ModsInfoColumn : InfoColumn { private readonly FillFlowContainer modsContainer; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs index 2eaa03a05d..afaed85250 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapSet.Scores { - public class TopScoreUserSection : CompositeDrawable + public partial class TopScoreUserSection : CompositeDrawable { private readonly SpriteText rankText; private readonly UpdateableRank rank; diff --git a/osu.Game/Overlays/BeatmapSet/SpotlightBeatmapBadge.cs b/osu.Game/Overlays/BeatmapSet/SpotlightBeatmapBadge.cs index 44b3acea5f..00534ff700 100644 --- a/osu.Game/Overlays/BeatmapSet/SpotlightBeatmapBadge.cs +++ b/osu.Game/Overlays/BeatmapSet/SpotlightBeatmapBadge.cs @@ -7,7 +7,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet { - public class SpotlightBeatmapBadge : BeatmapBadge + public partial class SpotlightBeatmapBadge : BeatmapBadge { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index cbcef9fcec..48732ac586 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -18,7 +18,7 @@ using osu.Game.Screens.Select.Details; namespace osu.Game.Overlays.BeatmapSet { - public class SuccessRate : Container + public partial class SuccessRate : Container { protected readonly FailRetryGraph Graph; @@ -127,7 +127,7 @@ namespace osu.Game.Overlays.BeatmapSet Graph.Padding = new MarginPadding { Top = header.DrawHeight }; } - private class SuccessRatePercentage : OsuSpriteText, IHasTooltip + private partial class SuccessRatePercentage : OsuSpriteText, IHasTooltip { public LocalisableString TooltipText { get; set; } } diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs index 207dc91ca5..fd831ad4ae 100644 --- a/osu.Game/Overlays/BeatmapSetOverlay.cs +++ b/osu.Game/Overlays/BeatmapSetOverlay.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public class BeatmapSetOverlay : OnlineOverlay + public partial class BeatmapSetOverlay : OnlineOverlay { public const float X_PADDING = 40; public const float Y_PADDING = 25; @@ -118,7 +118,7 @@ namespace osu.Game.Overlays Show(); } - private class CommentsSection : BeatmapSetLayoutSection + private partial class CommentsSection : BeatmapSetLayoutSection { public readonly Bindable BeatmapSet = new Bindable(); diff --git a/osu.Game/Overlays/BreadcrumbControlOverlayHeader.cs b/osu.Game/Overlays/BreadcrumbControlOverlayHeader.cs index 5b83f0e62e..e730496b5c 100644 --- a/osu.Game/Overlays/BreadcrumbControlOverlayHeader.cs +++ b/osu.Game/Overlays/BreadcrumbControlOverlayHeader.cs @@ -11,11 +11,11 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays { - public abstract class BreadcrumbControlOverlayHeader : TabControlOverlayHeader + public abstract partial class BreadcrumbControlOverlayHeader : TabControlOverlayHeader { protected override OsuTabControl CreateTabControl() => new OverlayHeaderBreadcrumbControl(); - public class OverlayHeaderBreadcrumbControl : BreadcrumbControl + public partial class OverlayHeaderBreadcrumbControl : BreadcrumbControl { public OverlayHeaderBreadcrumbControl() { @@ -34,7 +34,7 @@ namespace osu.Game.Overlays AccentColour = AccentColour, }; - private class ControlTabItem : BreadcrumbTabItem + private partial class ControlTabItem : BreadcrumbTabItem { protected override float ChevronSize => 8; diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs index 575f1a398a..fd7a3f8791 100644 --- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs @@ -16,7 +16,7 @@ using osu.Framework.Allocation; namespace osu.Game.Overlays.Changelog { - public class ChangelogBuild : FillFlowContainer + public partial class ChangelogBuild : FillFlowContainer { public const float HORIZONTAL_PADDING = 70; diff --git a/osu.Game/Overlays/Changelog/ChangelogContent.cs b/osu.Game/Overlays/Changelog/ChangelogContent.cs index e04133f2e4..51ef4ddf94 100644 --- a/osu.Game/Overlays/Changelog/ChangelogContent.cs +++ b/osu.Game/Overlays/Changelog/ChangelogContent.cs @@ -8,7 +8,7 @@ using System; namespace osu.Game.Overlays.Changelog { - public class ChangelogContent : FillFlowContainer + public partial class ChangelogContent : FillFlowContainer { public Action? BuildSelected; diff --git a/osu.Game/Overlays/Changelog/ChangelogEntry.cs b/osu.Game/Overlays/Changelog/ChangelogEntry.cs index 4d034007b1..ab671d9c86 100644 --- a/osu.Game/Overlays/Changelog/ChangelogEntry.cs +++ b/osu.Game/Overlays/Changelog/ChangelogEntry.cs @@ -21,7 +21,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Changelog { - public class ChangelogEntry : FillFlowContainer + public partial class ChangelogEntry : FillFlowContainer { private readonly APIChangelogEntry entry; diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs index 6ce6b82c8f..54ada24987 100644 --- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs +++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs @@ -18,7 +18,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Changelog { - public class ChangelogHeader : BreadcrumbControlOverlayHeader + public partial class ChangelogHeader : BreadcrumbControlOverlayHeader { public readonly Bindable Build = new Bindable(); @@ -117,7 +117,7 @@ namespace osu.Game.Overlays.Changelog currentStream.Value = Streams.Items.FirstOrDefault(s => s.Name == Build.Value.UpdateStream.Name); } - private class ChangelogHeaderTitle : OverlayTitle + private partial class ChangelogHeaderTitle : OverlayTitle { public ChangelogHeaderTitle() { diff --git a/osu.Game/Overlays/Changelog/ChangelogListing.cs b/osu.Game/Overlays/Changelog/ChangelogListing.cs index e848f26587..d30fd97652 100644 --- a/osu.Game/Overlays/Changelog/ChangelogListing.cs +++ b/osu.Game/Overlays/Changelog/ChangelogListing.cs @@ -15,7 +15,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Changelog { - public class ChangelogListing : ChangelogContent + public partial class ChangelogListing : ChangelogContent { private readonly List entries; diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index e4f240f0e7..ddee6ff8bb 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Overlays.Changelog { - public class ChangelogSingleBuild : ChangelogContent + public partial class ChangelogSingleBuild : ChangelogContent { private APIChangelogBuild build; @@ -91,7 +91,7 @@ namespace osu.Game.Overlays.Changelog } } - public class ChangelogBuildWithNavigation : ChangelogBuild + public partial class ChangelogBuildWithNavigation : ChangelogBuild { public ChangelogBuildWithNavigation(APIChangelogBuild build) : base(build) @@ -140,7 +140,7 @@ namespace osu.Game.Overlays.Changelog } } - private class NavigationIconButton : IconButton + private partial class NavigationIconButton : IconButton { public Action SelectBuild; diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index d84ed3c807..04526eb7ba 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Changelog { - public class ChangelogSupporterPromo : CompositeDrawable + public partial class ChangelogSupporterPromo : CompositeDrawable { private const float image_container_width = 164; private const float heart_size = 75; @@ -160,7 +160,7 @@ namespace osu.Game.Overlays.Changelog supportLinkText.AddText(" today!"); } - private class SupporterPromoLinkFlowContainer : LinkFlowContainer + private partial class SupporterPromoLinkFlowContainer : LinkFlowContainer { public SupporterPromoLinkFlowContainer(Action defaultCreationParameters) : base(defaultCreationParameters) @@ -169,7 +169,7 @@ namespace osu.Game.Overlays.Changelog protected override DrawableLinkCompiler CreateLinkCompiler(ITextPart textPart) => new SupporterPromoLinkCompiler(textPart); - private class SupporterPromoLinkCompiler : DrawableLinkCompiler + private partial class SupporterPromoLinkCompiler : DrawableLinkCompiler { public SupporterPromoLinkCompiler(ITextPart part) : base(part) diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs index 1db2d2f172..155cbc7d65 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs @@ -7,7 +7,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Changelog { - public class ChangelogUpdateStreamControl : OverlayStreamControl + public partial class ChangelogUpdateStreamControl : OverlayStreamControl { public ChangelogUpdateStreamControl() { diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs index 974b283ccf..08ea373fb1 100644 --- a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs +++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Changelog { - public class ChangelogUpdateStreamItem : OverlayStreamItem + public partial class ChangelogUpdateStreamItem : OverlayStreamItem { public ChangelogUpdateStreamItem(APIUpdateStream stream) : base(stream) diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index 7e0d5e9432..90863a90a2 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public class ChangelogOverlay : OnlineOverlay + public partial class ChangelogOverlay : OnlineOverlay { public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index d9f962ca97..e6fe97f3c6 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -19,7 +19,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Chat.ChannelList { - public class ChannelList : Container + public partial class ChannelList : Container { public Action? OnRequestSelect; public Action? OnRequestLeave; @@ -140,7 +140,7 @@ namespace osu.Game.Overlays.Chat.ChannelList announceChannelGroup.Show(); } - private class ChannelGroup : FillFlowContainer + private partial class ChannelGroup : FillFlowContainer { public readonly FillFlowContainer ItemFlow; diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs index c18e9e11fa..57b6f6268c 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItem.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Overlays.Chat.ChannelList { - public class ChannelListItem : OsuClickableContainer + public partial class ChannelListItem : OsuClickableContainer { public event Action? OnRequestSelect; public event Action? OnRequestLeave; diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs index 46d70b2d67..204b9aab19 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemCloseButton.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Chat.ChannelList { - public class ChannelListItemCloseButton : OsuClickableContainer + public partial class ChannelListItemCloseButton : OsuClickableContainer { private SpriteIcon icon = null!; diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs index 2ead841f58..bbd042cfc9 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelListItemMentionPill.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Chat.ChannelList { - public class ChannelListItemMentionPill : CircularContainer + public partial class ChannelListItemMentionPill : CircularContainer { public readonly BindableInt Mentions = new BindableInt(); diff --git a/osu.Game/Overlays/Chat/ChannelScrollContainer.cs b/osu.Game/Overlays/Chat/ChannelScrollContainer.cs index dee7730e2c..090f7835ae 100644 --- a/osu.Game/Overlays/Chat/ChannelScrollContainer.cs +++ b/osu.Game/Overlays/Chat/ChannelScrollContainer.cs @@ -11,7 +11,7 @@ namespace osu.Game.Overlays.Chat /// /// An with functionality to automatically scroll whenever the maximum scrollable distance increases. /// - public class ChannelScrollContainer : OsuScrollContainer + public partial class ChannelScrollContainer : OsuScrollContainer { /// /// The chat will be automatically scrolled to end if and only if diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index a991103fac..1c768101bf 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -26,7 +26,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Chat { - public class ChatLine : CompositeDrawable + public partial class ChatLine : CompositeDrawable { public Message Message { @@ -248,7 +248,7 @@ namespace osu.Game.Overlays.Chat }; } - private class MessageSender : OsuClickableContainer, IHasContextMenu + private partial class MessageSender : OsuClickableContainer, IHasContextMenu { private readonly APIUser sender; diff --git a/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs b/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs index ad9ae412da..0410174dc1 100644 --- a/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs +++ b/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Chat { - public class ChatOverlayTopBar : Container + public partial class ChatOverlayTopBar : Container { private Box background = null!; diff --git a/osu.Game/Overlays/Chat/ChatTextBar.cs b/osu.Game/Overlays/Chat/ChatTextBar.cs index 73314c2e44..bcf5c1a409 100644 --- a/osu.Game/Overlays/Chat/ChatTextBar.cs +++ b/osu.Game/Overlays/Chat/ChatTextBar.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Overlays.Chat { - public class ChatTextBar : Container + public partial class ChatTextBar : Container { public readonly BindableBool ShowSearch = new BindableBool(); diff --git a/osu.Game/Overlays/Chat/ChatTextBox.cs b/osu.Game/Overlays/Chat/ChatTextBox.cs index f0bdbce08d..780c85a9c1 100644 --- a/osu.Game/Overlays/Chat/ChatTextBox.cs +++ b/osu.Game/Overlays/Chat/ChatTextBox.cs @@ -7,7 +7,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Chat { - public class ChatTextBox : HistoryTextBox + public partial class ChatTextBox : HistoryTextBox { public readonly BindableBool ShowSearch = new BindableBool(); diff --git a/osu.Game/Overlays/Chat/DaySeparator.cs b/osu.Game/Overlays/Chat/DaySeparator.cs index d68f325738..e737b787ba 100644 --- a/osu.Game/Overlays/Chat/DaySeparator.cs +++ b/osu.Game/Overlays/Chat/DaySeparator.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.Chat { - public class DaySeparator : Container + public partial class DaySeparator : Container { protected virtual float TextSize => 15; diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 65876fd7c5..aa17df4907 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Chat { - public class DrawableChannel : Container + public partial class DrawableChannel : Container { public readonly Channel Channel; protected FillFlowContainer ChatLineFlow; diff --git a/osu.Game/Overlays/Chat/Listing/ChannelListing.cs b/osu.Game/Overlays/Chat/Listing/ChannelListing.cs index 44255eb754..809ea2f11d 100644 --- a/osu.Game/Overlays/Chat/Listing/ChannelListing.cs +++ b/osu.Game/Overlays/Chat/Listing/ChannelListing.cs @@ -13,7 +13,7 @@ using osu.Game.Online.Chat; namespace osu.Game.Overlays.Chat.Listing { - public class ChannelListing : VisibilityContainer + public partial class ChannelListing : VisibilityContainer { public event Action? OnRequestJoin; public event Action? OnRequestLeave; diff --git a/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs b/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs index ffeab3b380..22a3bdc06f 100644 --- a/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs +++ b/osu.Game/Overlays/Chat/Listing/ChannelListingItem.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Overlays.Chat.Listing { - public class ChannelListingItem : OsuClickableContainer, IFilterable + public partial class ChannelListingItem : OsuClickableContainer, IFilterable { public event Action? OnRequestJoin; public event Action? OnRequestLeave; diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index e9d28dcf28..98e153108f 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -26,7 +26,7 @@ using osu.Game.Overlays.Chat.Listing; namespace osu.Game.Overlays { - public class ChatOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent, IKeyBindingHandler + public partial class ChatOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent, IKeyBindingHandler { public string IconTexture => "Icons/Hexacons/messaging"; public LocalisableString Title => ChatStrings.HeaderTitle; diff --git a/osu.Game/Overlays/Comments/Buttons/ChevronButton.cs b/osu.Game/Overlays/Comments/Buttons/ChevronButton.cs index 46a455cbb3..88e7d00476 100644 --- a/osu.Game/Overlays/Comments/Buttons/ChevronButton.cs +++ b/osu.Game/Overlays/Comments/Buttons/ChevronButton.cs @@ -12,7 +12,7 @@ using osu.Framework.Allocation; namespace osu.Game.Overlays.Comments.Buttons { - public class ChevronButton : OsuHoverContainer + public partial class ChevronButton : OsuHoverContainer { public readonly BindableBool Expanded = new BindableBool(true); diff --git a/osu.Game/Overlays/Comments/Buttons/CommentRepliesButton.cs b/osu.Game/Overlays/Comments/Buttons/CommentRepliesButton.cs index d24a0cd27b..d9576f5b72 100644 --- a/osu.Game/Overlays/Comments/Buttons/CommentRepliesButton.cs +++ b/osu.Game/Overlays/Comments/Buttons/CommentRepliesButton.cs @@ -17,7 +17,7 @@ using static osu.Game.Graphics.UserInterface.ShowMoreButton; namespace osu.Game.Overlays.Comments.Buttons { - public abstract class CommentRepliesButton : CompositeDrawable + public abstract partial class CommentRepliesButton : CompositeDrawable { protected LocalisableString Text { diff --git a/osu.Game/Overlays/Comments/Buttons/LoadRepliesButton.cs b/osu.Game/Overlays/Comments/Buttons/LoadRepliesButton.cs index 42aca2f4a3..65d8685403 100644 --- a/osu.Game/Overlays/Comments/Buttons/LoadRepliesButton.cs +++ b/osu.Game/Overlays/Comments/Buttons/LoadRepliesButton.cs @@ -9,7 +9,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments.Buttons { - public class LoadRepliesButton : LoadingButton + public partial class LoadRepliesButton : LoadingButton { private ButtonContent content; @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Comments.Buttons protected override void OnLoadFinished() => content.ToggleTextVisibility(true); - private class ButtonContent : CommentRepliesButton + private partial class ButtonContent : CommentRepliesButton { public ButtonContent() { diff --git a/osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs b/osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs index 6f3841d52e..0aedbe4c53 100644 --- a/osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs +++ b/osu.Game/Overlays/Comments/Buttons/ShowMoreRepliesButton.cs @@ -15,7 +15,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments.Buttons { - public class ShowMoreRepliesButton : LoadingButton + public partial class ShowMoreRepliesButton : LoadingButton { protected override IEnumerable EffectTargets => new[] { text }; diff --git a/osu.Game/Overlays/Comments/Buttons/ShowRepliesButton.cs b/osu.Game/Overlays/Comments/Buttons/ShowRepliesButton.cs index 845a630d97..aa9b2df7e4 100644 --- a/osu.Game/Overlays/Comments/Buttons/ShowRepliesButton.cs +++ b/osu.Game/Overlays/Comments/Buttons/ShowRepliesButton.cs @@ -9,7 +9,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Overlays.Comments.Buttons { - public class ShowRepliesButton : CommentRepliesButton + public partial class ShowRepliesButton : CommentRepliesButton { public readonly BindableBool Expanded = new BindableBool(true); diff --git a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs index 7ba6de86b7..2b597d5638 100644 --- a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs +++ b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs @@ -17,7 +17,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { - public abstract class CancellableCommentEditor : CommentEditor + public abstract partial class CancellableCommentEditor : CommentEditor { public Action OnCancel; @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Comments }); } - private class CancelButton : OsuHoverContainer + private partial class CancelButton : OsuHoverContainer { protected override IEnumerable EffectTargets => new[] { background }; diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs index e2a7e78356..72edd1877e 100644 --- a/osu.Game/Overlays/Comments/CommentEditor.cs +++ b/osu.Game/Overlays/Comments/CommentEditor.cs @@ -20,7 +20,7 @@ using osu.Framework.Bindables; namespace osu.Game.Overlays.Comments { - public abstract class CommentEditor : CompositeDrawable + public abstract partial class CommentEditor : CompositeDrawable { private const int side_padding = 8; @@ -133,7 +133,7 @@ namespace osu.Game.Overlays.Comments Current.BindValueChanged(text => commitButton.IsBlocked.Value = string.IsNullOrEmpty(text.NewValue), true); } - private class EditorTextBox : BasicTextBox + private partial class EditorTextBox : BasicTextBox { protected override float LeftRightPadding => side_padding; @@ -167,7 +167,7 @@ namespace osu.Game.Overlays.Comments }; } - private class CommitButton : LoadingButton + private partial class CommitButton : LoadingButton { private const int duration = 200; diff --git a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs index b32b1c74c4..664946fc63 100644 --- a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs +++ b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs @@ -9,13 +9,13 @@ using osu.Game.Graphics.Containers.Markdown; namespace osu.Game.Overlays.Comments { - public class CommentMarkdownContainer : OsuMarkdownContainer + public partial class CommentMarkdownContainer : OsuMarkdownContainer { protected override bool Autolinks => true; protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new CommentMarkdownHeading(headingBlock); - private class CommentMarkdownHeading : OsuMarkdownHeading + private partial class CommentMarkdownHeading : OsuMarkdownHeading { public CommentMarkdownHeading(HeadingBlock headingBlock) : base(headingBlock) diff --git a/osu.Game/Overlays/Comments/CommentReportButton.cs b/osu.Game/Overlays/Comments/CommentReportButton.cs index 4f5c5c6dcf..10bd3a64bf 100644 --- a/osu.Game/Overlays/Comments/CommentReportButton.cs +++ b/osu.Game/Overlays/Comments/CommentReportButton.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Overlays.Comments { - public class CommentReportButton : CompositeDrawable, IHasPopover + public partial class CommentReportButton : CompositeDrawable, IHasPopover { private readonly Comment comment; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 4a836e0e62..7bd2d6a5e6 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -23,7 +23,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Comments { - public class CommentsContainer : CompositeDrawable + public partial class CommentsContainer : CompositeDrawable { private readonly Bindable type = new Bindable(); private readonly BindableLong id = new BindableLong(); @@ -317,7 +317,7 @@ namespace osu.Game.Overlays.Comments base.Dispose(isDisposing); } - private class NoCommentsPlaceholder : CompositeDrawable + private partial class NoCommentsPlaceholder : CompositeDrawable { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs index 5684841c37..e6d44e618b 100644 --- a/osu.Game/Overlays/Comments/CommentsHeader.cs +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -20,7 +20,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { - public class CommentsHeader : CompositeDrawable + public partial class CommentsHeader : CompositeDrawable { public readonly Bindable Sort = new Bindable(); public readonly BindableBool ShowDeleted = new BindableBool(); @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Comments background.Colour = colourProvider.Background4; } - private class ShowDeletedButton : HeaderButton + private partial class ShowDeletedButton : HeaderButton { public readonly BindableBool Checked = new BindableBool(); diff --git a/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs b/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs index 84d1f67486..1770fcb269 100644 --- a/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs +++ b/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs @@ -11,7 +11,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { - public class CommentsShowMoreButton : ShowMoreButton + public partial class CommentsShowMoreButton : ShowMoreButton { public readonly BindableInt Current = new BindableInt(); diff --git a/osu.Game/Overlays/Comments/DeletedCommentsCounter.cs b/osu.Game/Overlays/Comments/DeletedCommentsCounter.cs index 2c7ed4f5b3..6adb388185 100644 --- a/osu.Game/Overlays/Comments/DeletedCommentsCounter.cs +++ b/osu.Game/Overlays/Comments/DeletedCommentsCounter.cs @@ -14,7 +14,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.Comments { - public class DeletedCommentsCounter : CompositeDrawable + public partial class DeletedCommentsCounter : CompositeDrawable { public readonly BindableBool ShowDeleted = new BindableBool(); diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index aa08de798c..6cb5a0fbac 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -32,7 +32,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { [Cached] - public class DrawableComment : CompositeDrawable + public partial class DrawableComment : CompositeDrawable { private const int avatar_size = 40; @@ -497,7 +497,7 @@ namespace osu.Game.Overlays.Comments }; } - private class PinnedCommentNotice : FillFlowContainer + private partial class PinnedCommentNotice : FillFlowContainer { public PinnedCommentNotice() { @@ -524,7 +524,7 @@ namespace osu.Game.Overlays.Comments } } - private class ParentUsername : FillFlowContainer, IHasTooltip + private partial class ParentUsername : FillFlowContainer, IHasTooltip { public LocalisableString TooltipText => getParentMessage(); diff --git a/osu.Game/Overlays/Comments/HeaderButton.cs b/osu.Game/Overlays/Comments/HeaderButton.cs index 186b892c4d..de99cd6cc8 100644 --- a/osu.Game/Overlays/Comments/HeaderButton.cs +++ b/osu.Game/Overlays/Comments/HeaderButton.cs @@ -11,7 +11,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Overlays.Comments { - public class HeaderButton : Container + public partial class HeaderButton : Container { private const int transition_duration = 200; diff --git a/osu.Game/Overlays/Comments/ReportCommentPopover.cs b/osu.Game/Overlays/Comments/ReportCommentPopover.cs index 39fd52aa2a..f3b2a2f97c 100644 --- a/osu.Game/Overlays/Comments/ReportCommentPopover.cs +++ b/osu.Game/Overlays/Comments/ReportCommentPopover.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Overlays.Comments { - public class ReportCommentPopover : OsuPopover + public partial class ReportCommentPopover : OsuPopover { public Action? Action; diff --git a/osu.Game/Overlays/Comments/TotalCommentsCounter.cs b/osu.Game/Overlays/Comments/TotalCommentsCounter.cs index 218d8383f6..38928f6f3d 100644 --- a/osu.Game/Overlays/Comments/TotalCommentsCounter.cs +++ b/osu.Game/Overlays/Comments/TotalCommentsCounter.cs @@ -15,7 +15,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { - public class TotalCommentsCounter : CompositeDrawable + public partial class TotalCommentsCounter : CompositeDrawable { public readonly BindableInt Current = new BindableInt(); diff --git a/osu.Game/Overlays/Comments/VotePill.cs b/osu.Game/Overlays/Comments/VotePill.cs index 7a4b83cc48..6cfa5cb9e8 100644 --- a/osu.Game/Overlays/Comments/VotePill.cs +++ b/osu.Game/Overlays/Comments/VotePill.cs @@ -24,7 +24,7 @@ using System.Linq; namespace osu.Game.Overlays.Comments { - public class VotePill : LoadingButton, IHasAccentColour + public partial class VotePill : LoadingButton, IHasAccentColour { private const int duration = 200; diff --git a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs index aae4932c22..632ba4b838 100644 --- a/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs +++ b/osu.Game/Overlays/Dashboard/CurrentlyPlayingDisplay.cs @@ -30,7 +30,7 @@ using osuTK; namespace osu.Game.Overlays.Dashboard { - internal class CurrentlyPlayingDisplay : CompositeDrawable + internal partial class CurrentlyPlayingDisplay : CompositeDrawable { private const float search_textbox_height = 40; private const float padding = 10; @@ -153,7 +153,7 @@ namespace osu.Game.Overlays.Dashboard panel.Origin = Anchor.TopCentre; }); - public class PlayingUserPanel : CompositeDrawable, IFilterable + public partial class PlayingUserPanel : CompositeDrawable, IFilterable { public readonly APIUser User; diff --git a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs index 370181a0cb..5cbeb8f306 100644 --- a/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs +++ b/osu.Game/Overlays/Dashboard/DashboardOverlayHeader.cs @@ -10,11 +10,11 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Dashboard { - public class DashboardOverlayHeader : TabControlOverlayHeader + public partial class DashboardOverlayHeader : TabControlOverlayHeader { protected override OverlayTitle CreateTitle() => new DashboardTitle(); - private class DashboardTitle : OverlayTitle + private partial class DashboardTitle : OverlayTitle { public DashboardTitle() { diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs index bfd356193d..73fab6d62b 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Overlays.Dashboard.Friends { - public class FriendDisplay : CompositeDrawable + public partial class FriendDisplay : CompositeDrawable { private List users = new List(); diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendOnlineStreamControl.cs b/osu.Game/Overlays/Dashboard/Friends/FriendOnlineStreamControl.cs index fc6158e747..9f429c23d8 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendOnlineStreamControl.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendOnlineStreamControl.cs @@ -9,7 +9,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Dashboard.Friends { - public class FriendOnlineStreamControl : OverlayStreamControl + public partial class FriendOnlineStreamControl : OverlayStreamControl { protected override OverlayStreamItem CreateStreamItem(FriendStream value) => new FriendsOnlineStatusItem(value); diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendsOnlineStatusItem.cs b/osu.Game/Overlays/Dashboard/Friends/FriendsOnlineStatusItem.cs index 7e2ec3f442..785eef38ad 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendsOnlineStatusItem.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendsOnlineStatusItem.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Dashboard.Friends { - public class FriendsOnlineStatusItem : OverlayStreamItem + public partial class FriendsOnlineStatusItem : OverlayStreamItem { public FriendsOnlineStatusItem(FriendStream value) : base(value) diff --git a/osu.Game/Overlays/Dashboard/Friends/UserListToolbar.cs b/osu.Game/Overlays/Dashboard/Friends/UserListToolbar.cs index 25ddb9e704..db8510325c 100644 --- a/osu.Game/Overlays/Dashboard/Friends/UserListToolbar.cs +++ b/osu.Game/Overlays/Dashboard/Friends/UserListToolbar.cs @@ -10,7 +10,7 @@ using osu.Framework.Bindables; namespace osu.Game.Overlays.Dashboard.Friends { - public class UserListToolbar : CompositeDrawable + public partial class UserListToolbar : CompositeDrawable { public Bindable SortCriteria => sortControl.Current; diff --git a/osu.Game/Overlays/Dashboard/Friends/UserSortTabControl.cs b/osu.Game/Overlays/Dashboard/Friends/UserSortTabControl.cs index 466e36c1a9..886ed08af2 100644 --- a/osu.Game/Overlays/Dashboard/Friends/UserSortTabControl.cs +++ b/osu.Game/Overlays/Dashboard/Friends/UserSortTabControl.cs @@ -9,7 +9,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Dashboard.Friends { - public class UserSortTabControl : OverlaySortTabControl + public partial class UserSortTabControl : OverlaySortTabControl { } diff --git a/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapListing.cs b/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapListing.cs index e9c7af3339..0282ba8785 100644 --- a/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapListing.cs +++ b/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapListing.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Overlays.Dashboard.Home { - public class DashboardBeatmapListing : CompositeDrawable + public partial class DashboardBeatmapListing : CompositeDrawable { private readonly List newBeatmaps; private readonly List popularBeatmaps; diff --git a/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapPanel.cs b/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapPanel.cs index 1e4ba2ef05..792d6cc785 100644 --- a/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/DashboardBeatmapPanel.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Overlays.Dashboard.Home { - public abstract class DashboardBeatmapPanel : OsuClickableContainer + public abstract partial class DashboardBeatmapPanel : OsuClickableContainer { [Resolved] protected OverlayColourProvider ColourProvider { get; private set; } diff --git a/osu.Game/Overlays/Dashboard/Home/DashboardNewBeatmapPanel.cs b/osu.Game/Overlays/Dashboard/Home/DashboardNewBeatmapPanel.cs index 258fd56dd7..fef33bdf5a 100644 --- a/osu.Game/Overlays/Dashboard/Home/DashboardNewBeatmapPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/DashboardNewBeatmapPanel.cs @@ -10,7 +10,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Dashboard.Home { - public class DashboardNewBeatmapPanel : DashboardBeatmapPanel + public partial class DashboardNewBeatmapPanel : DashboardBeatmapPanel { public DashboardNewBeatmapPanel(APIBeatmapSet beatmapSet) : base(beatmapSet) diff --git a/osu.Game/Overlays/Dashboard/Home/DashboardPopularBeatmapPanel.cs b/osu.Game/Overlays/Dashboard/Home/DashboardPopularBeatmapPanel.cs index 743bd5440f..54d95c994b 100644 --- a/osu.Game/Overlays/Dashboard/Home/DashboardPopularBeatmapPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/DashboardPopularBeatmapPanel.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Overlays.Dashboard.Home { - public class DashboardPopularBeatmapPanel : DashboardBeatmapPanel + public partial class DashboardPopularBeatmapPanel : DashboardBeatmapPanel { public DashboardPopularBeatmapPanel(APIBeatmapSet beatmapSet) : base(beatmapSet) diff --git a/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs b/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs index 8f140facef..af36f71dd2 100644 --- a/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs +++ b/osu.Game/Overlays/Dashboard/Home/DrawableBeatmapList.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Overlays.Dashboard.Home { - public abstract class DrawableBeatmapList : CompositeDrawable + public abstract partial class DrawableBeatmapList : CompositeDrawable { private readonly List beatmapSets; diff --git a/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs b/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs index c6917b41fb..8a60d8568c 100644 --- a/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs +++ b/osu.Game/Overlays/Dashboard/Home/DrawableNewBeatmapList.cs @@ -10,7 +10,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Dashboard.Home { - public class DrawableNewBeatmapList : DrawableBeatmapList + public partial class DrawableNewBeatmapList : DrawableBeatmapList { public DrawableNewBeatmapList(List beatmapSets) : base(beatmapSets) diff --git a/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs b/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs index 9ff12623e0..aab99d0ed3 100644 --- a/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs +++ b/osu.Game/Overlays/Dashboard/Home/DrawablePopularBeatmapList.cs @@ -10,7 +10,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Dashboard.Home { - public class DrawablePopularBeatmapList : DrawableBeatmapList + public partial class DrawablePopularBeatmapList : DrawableBeatmapList { public DrawablePopularBeatmapList(List beatmapSets) : base(beatmapSets) diff --git a/osu.Game/Overlays/Dashboard/Home/HomePanel.cs b/osu.Game/Overlays/Dashboard/Home/HomePanel.cs index 099e16cd55..8023c093aa 100644 --- a/osu.Game/Overlays/Dashboard/Home/HomePanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/HomePanel.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Dashboard.Home { - public class HomePanel : Container + public partial class HomePanel : Container { protected override Container Content => content; diff --git a/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs b/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs index 1d904526fd..3066d253eb 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Dashboard.Home.News { - public class FeaturedNewsItemPanel : HomePanel + public partial class FeaturedNewsItemPanel : HomePanel { private readonly APINewsPost post; @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.Dashboard.Home.News }; } - private class ClickableNewsBackground : OsuHoverContainer + private partial class ClickableNewsBackground : OsuHoverContainer { private readonly APINewsPost post; @@ -137,7 +137,7 @@ namespace osu.Game.Overlays.Dashboard.Home.News } } - private class Date : CompositeDrawable, IHasCustomTooltip + private partial class Date : CompositeDrawable, IHasCustomTooltip { private readonly DateTimeOffset date; diff --git a/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs b/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs index 9b66e5524b..e277a5fa16 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs @@ -14,7 +14,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Dashboard.Home.News { - public class NewsGroupItem : CompositeDrawable + public partial class NewsGroupItem : CompositeDrawable { private readonly APINewsPost post; @@ -69,7 +69,7 @@ namespace osu.Game.Overlays.Dashboard.Home.News }; } - private class Date : CompositeDrawable, IHasCustomTooltip + private partial class Date : CompositeDrawable, IHasCustomTooltip { private readonly DateTimeOffset date; diff --git a/osu.Game/Overlays/Dashboard/Home/News/NewsItemGroupPanel.cs b/osu.Game/Overlays/Dashboard/Home/News/NewsItemGroupPanel.cs index 4456a292a5..fa59f38690 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/NewsItemGroupPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/NewsItemGroupPanel.cs @@ -12,7 +12,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Dashboard.Home.News { - public class NewsItemGroupPanel : HomePanel + public partial class NewsItemGroupPanel : HomePanel { private readonly List posts; diff --git a/osu.Game/Overlays/Dashboard/Home/News/NewsTitleLink.cs b/osu.Game/Overlays/Dashboard/Home/News/NewsTitleLink.cs index e384c3e6e5..1960e0372e 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/NewsTitleLink.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/NewsTitleLink.cs @@ -13,7 +13,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Dashboard.Home.News { - public class NewsTitleLink : OsuHoverContainer + public partial class NewsTitleLink : OsuHoverContainer { private readonly APINewsPost post; diff --git a/osu.Game/Overlays/Dashboard/Home/News/ShowMoreNewsPanel.cs b/osu.Game/Overlays/Dashboard/Home/News/ShowMoreNewsPanel.cs index 9b1d77a8c2..3e61dd1938 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/ShowMoreNewsPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/ShowMoreNewsPanel.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Dashboard.Home.News { - public class ShowMoreNewsPanel : OsuHoverContainer + public partial class ShowMoreNewsPanel : OsuHoverContainer { protected override IEnumerable EffectTargets => new[] { text }; diff --git a/osu.Game/Overlays/DashboardOverlay.cs b/osu.Game/Overlays/DashboardOverlay.cs index d919022dbb..527ac1689b 100644 --- a/osu.Game/Overlays/DashboardOverlay.cs +++ b/osu.Game/Overlays/DashboardOverlay.cs @@ -9,7 +9,7 @@ using osu.Game.Overlays.Dashboard.Friends; namespace osu.Game.Overlays { - public class DashboardOverlay : TabbableOnlineOverlay + public partial class DashboardOverlay : TabbableOnlineOverlay { public DashboardOverlay() : base(OverlayColourScheme.Purple) diff --git a/osu.Game/Overlays/Dialog/ConfirmDialog.cs b/osu.Game/Overlays/Dialog/ConfirmDialog.cs index c17080f602..f1caac8b5d 100644 --- a/osu.Game/Overlays/Dialog/ConfirmDialog.cs +++ b/osu.Game/Overlays/Dialog/ConfirmDialog.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Dialog /// /// A dialog which confirms a user action. /// - public class ConfirmDialog : PopupDialog + public partial class ConfirmDialog : PopupDialog { /// /// Construct a new confirmation dialog. diff --git a/osu.Game/Overlays/Dialog/DeleteConfirmationDialog.cs b/osu.Game/Overlays/Dialog/DeleteConfirmationDialog.cs index fd26dd7e8e..ddb59c4c9e 100644 --- a/osu.Game/Overlays/Dialog/DeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Dialog/DeleteConfirmationDialog.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Dialog /// Differs from in that the confirmation button is a "dangerous" one /// (requires the confirm button to be held). /// - public abstract class DeleteConfirmationDialog : PopupDialog + public abstract partial class DeleteConfirmationDialog : PopupDialog { /// /// The action which performs the deletion. diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 864120cc49..80e0ffe427 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Overlays.Dialog { - public abstract class PopupDialog : VisibilityContainer + public abstract partial class PopupDialog : VisibilityContainer { public const float ENTER_DURATION = 500; public const float EXIT_DURATION = 200; diff --git a/osu.Game/Overlays/Dialog/PopupDialogButton.cs b/osu.Game/Overlays/Dialog/PopupDialogButton.cs index e1cc31da82..91a19add21 100644 --- a/osu.Game/Overlays/Dialog/PopupDialogButton.cs +++ b/osu.Game/Overlays/Dialog/PopupDialogButton.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Dialog { - public class PopupDialogButton : DialogButton + public partial class PopupDialogButton : DialogButton { public PopupDialogButton(HoverSampleSet sampleSet = HoverSampleSet.Button) : base(sampleSet) diff --git a/osu.Game/Overlays/Dialog/PopupDialogCancelButton.cs b/osu.Game/Overlays/Dialog/PopupDialogCancelButton.cs index f23a40b7ab..f4289c66f1 100644 --- a/osu.Game/Overlays/Dialog/PopupDialogCancelButton.cs +++ b/osu.Game/Overlays/Dialog/PopupDialogCancelButton.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Dialog { - public class PopupDialogCancelButton : PopupDialogButton + public partial class PopupDialogCancelButton : PopupDialogButton { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs index bd7cb4ed33..6b3716ac8d 100644 --- a/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs +++ b/osu.Game/Overlays/Dialog/PopupDialogDangerousButton.cs @@ -16,7 +16,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Dialog { - public class PopupDialogDangerousButton : PopupDialogButton + public partial class PopupDialogDangerousButton : PopupDialogButton { private Box progressBox; private DangerousConfirmContainer confirmContainer; @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Dialog confirmContainer.Progress.BindValueChanged(progress => progressBox.Width = (float)progress.NewValue, true); } - private class DangerousConfirmContainer : HoldToConfirmContainer + private partial class DangerousConfirmContainer : HoldToConfirmContainer { public DangerousConfirmContainer() : base(isDangerousAction: true) diff --git a/osu.Game/Overlays/Dialog/PopupDialogOkButton.cs b/osu.Game/Overlays/Dialog/PopupDialogOkButton.cs index 3496627c89..eb4a0f0709 100644 --- a/osu.Game/Overlays/Dialog/PopupDialogOkButton.cs +++ b/osu.Game/Overlays/Dialog/PopupDialogOkButton.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Dialog { - public class PopupDialogOkButton : PopupDialogButton + public partial class PopupDialogOkButton : PopupDialogButton { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/DialogOverlay.cs b/osu.Game/Overlays/DialogOverlay.cs index ba8083e535..098a5d0a33 100644 --- a/osu.Game/Overlays/DialogOverlay.cs +++ b/osu.Game/Overlays/DialogOverlay.cs @@ -16,7 +16,7 @@ using osu.Game.Audio.Effects; namespace osu.Game.Overlays { - public class DialogOverlay : OsuFocusedOverlayContainer, IDialogOverlay + public partial class DialogOverlay : OsuFocusedOverlayContainer, IDialogOverlay { private readonly Container dialogContainer; diff --git a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs index cef1f1c869..76921718f2 100644 --- a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs +++ b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Overlays.FirstRunSetup { - public abstract class FirstRunSetupScreen : Screen + public abstract partial class FirstRunSetupScreen : Screen { private const float offset = 100; diff --git a/osu.Game/Overlays/FirstRunSetup/ProgressRoundedButton.cs b/osu.Game/Overlays/FirstRunSetup/ProgressRoundedButton.cs index 95ebb256c4..a4762fdaed 100644 --- a/osu.Game/Overlays/FirstRunSetup/ProgressRoundedButton.cs +++ b/osu.Game/Overlays/FirstRunSetup/ProgressRoundedButton.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Overlays.FirstRunSetup { - public class ProgressRoundedButton : RoundedButton + public partial class ProgressRoundedButton : RoundedButton { public new Action? Action; diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenBeatmaps.cs b/osu.Game/Overlays/FirstRunSetup/ScreenBeatmaps.cs index 4963de7251..75bc8fd3a8 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenBeatmaps.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenBeatmaps.cs @@ -20,7 +20,7 @@ using Realms; namespace osu.Game.Overlays.FirstRunSetup { [LocalisableDescription(typeof(FirstRunSetupBeatmapScreenStrings), nameof(FirstRunSetupBeatmapScreenStrings.Header))] - public class ScreenBeatmaps : FirstRunSetupScreen + public partial class ScreenBeatmaps : FirstRunSetupScreen { private ProgressRoundedButton downloadBundledButton = null!; private ProgressRoundedButton downloadTutorialButton = null!; diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenBehaviour.cs b/osu.Game/Overlays/FirstRunSetup/ScreenBehaviour.cs index 9573b4859f..95af8ec0f3 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenBehaviour.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenBehaviour.cs @@ -19,7 +19,7 @@ using osu.Game.Overlays.Settings.Sections; namespace osu.Game.Overlays.FirstRunSetup { [LocalisableDescription(typeof(FirstRunSetupOverlayStrings), nameof(FirstRunSetupOverlayStrings.Behaviour))] - public class ScreenBehaviour : FirstRunSetupScreen + public partial class ScreenBehaviour : FirstRunSetupScreen { private SearchContainer searchContainer; diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index a34f8f0c1b..29cf3824fd 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -26,7 +26,7 @@ using osuTK; namespace osu.Game.Overlays.FirstRunSetup { [LocalisableDescription(typeof(FirstRunOverlayImportFromStableScreenStrings), nameof(FirstRunOverlayImportFromStableScreenStrings.Header))] - public class ScreenImportFromStable : FirstRunSetupScreen + public partial class ScreenImportFromStable : FirstRunSetupScreen { private static readonly Vector2 button_size = new Vector2(400, 50); @@ -139,7 +139,7 @@ namespace osu.Game.Overlays.FirstRunSetup c.Current.Disabled = !allow; } - private class ImportCheckbox : SettingsCheckbox + private partial class ImportCheckbox : SettingsCheckbox { public readonly StableContent StableContent; @@ -181,7 +181,7 @@ namespace osu.Game.Overlays.FirstRunSetup } } - internal class StableLocatorLabelledTextBox : LabelledTextBoxWithPopover, ICanAcceptFiles + internal partial class StableLocatorLabelledTextBox : LabelledTextBoxWithPopover, ICanAcceptFiles { [Resolved] private LegacyImportManager legacyImportManager { get; set; } = null!; @@ -245,7 +245,7 @@ namespace osu.Game.Overlays.FirstRunSetup public override Popover GetPopover() => new DirectoryChooserPopover(currentDirectory); - private class DirectoryChooserPopover : OsuPopover + private partial class DirectoryChooserPopover : OsuPopover { public DirectoryChooserPopover(Bindable currentDirectory) { diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index 0d4496a6a3..b28b04f228 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -32,7 +32,7 @@ using osuTK; namespace osu.Game.Overlays.FirstRunSetup { [LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.UIScaling))] - public class ScreenUIScale : FirstRunSetupScreen + public partial class ScreenUIScale : FirstRunSetupScreen { [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -80,7 +80,7 @@ namespace osu.Game.Overlays.FirstRunSetup }; } - private class InverseScalingDrawSizePreservingFillContainer : ScalingContainer.ScalingDrawSizePreservingFillContainer + private partial class InverseScalingDrawSizePreservingFillContainer : ScalingContainer.ScalingDrawSizePreservingFillContainer { private Vector2 initialSize; @@ -102,14 +102,14 @@ namespace osu.Game.Overlays.FirstRunSetup } } - private class NestedSongSelect : PlaySongSelect + private partial class NestedSongSelect : PlaySongSelect { protected override bool ControlGlobalMusic => false; public override bool? AllowTrackAdjustments => false; } - private class PinnedMainMenu : MainMenu + private partial class PinnedMainMenu : MainMenu { public override void OnEntering(ScreenTransitionEvent e) { @@ -120,12 +120,12 @@ namespace osu.Game.Overlays.FirstRunSetup } } - private class UIScaleSlider : OsuSliderBar + private partial class UIScaleSlider : OsuSliderBar { public override LocalisableString TooltipText => base.TooltipText + "x"; } - private class SampleScreenContainer : CompositeDrawable + private partial class SampleScreenContainer : CompositeDrawable { private readonly OsuScreen screen; diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs index 3113e11346..fe3aaeb9d8 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Overlays.FirstRunSetup { [LocalisableDescription(typeof(FirstRunSetupOverlayStrings), nameof(FirstRunSetupOverlayStrings.WelcomeTitle))] - public class ScreenWelcome : FirstRunSetupScreen + public partial class ScreenWelcome : FirstRunSetupScreen { [BackgroundDependencyLoader] private void load(FrameworkConfigManager frameworkConfig) @@ -66,7 +66,7 @@ namespace osu.Game.Overlays.FirstRunSetup }; } - private class LanguageSelectionFlow : FillFlowContainer + private partial class LanguageSelectionFlow : FillFlowContainer { private Bindable frameworkLocale = null!; private IBindable localisationParameters = null!; @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.FirstRunSetup c.Selected = c.Language == language; } - private class LanguageButton : OsuClickableContainer + private partial class LanguageButton : OsuClickableContainer { public readonly Language Language; diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 8c9ca7e35b..45fc9d27ea 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -31,7 +31,7 @@ using osu.Game.Screens.Menu; namespace osu.Game.Overlays { [Cached] - public class FirstRunSetupOverlay : ShearedOverlayContainer + public partial class FirstRunSetupOverlay : ShearedOverlayContainer { [Resolved] private IPerformFromScreenRunner performer { get; set; } = null!; diff --git a/osu.Game/Overlays/FullscreenOverlay.cs b/osu.Game/Overlays/FullscreenOverlay.cs index 63a9ebc750..2cc8354e50 100644 --- a/osu.Game/Overlays/FullscreenOverlay.cs +++ b/osu.Game/Overlays/FullscreenOverlay.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public abstract class FullscreenOverlay : WaveOverlayContainer, INamedOverlayComponent + public abstract partial class FullscreenOverlay : WaveOverlayContainer, INamedOverlayComponent where T : OverlayHeader { public virtual string IconTexture => Header.Title.IconTexture ?? string.Empty; diff --git a/osu.Game/Overlays/HoldToConfirmOverlay.cs b/osu.Game/Overlays/HoldToConfirmOverlay.cs index dd03206eab..ac8b4ad0a8 100644 --- a/osu.Game/Overlays/HoldToConfirmOverlay.cs +++ b/osu.Game/Overlays/HoldToConfirmOverlay.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays /// An overlay which will display a black screen that dims over a period before confirming an exit action. /// Action is BYO (derived class will need to call and from a user event). /// - public abstract class HoldToConfirmOverlay : HoldToConfirmContainer + public abstract partial class HoldToConfirmOverlay : HoldToConfirmContainer { private Box overlay; diff --git a/osu.Game/Overlays/Login/LoginForm.cs b/osu.Game/Overlays/Login/LoginForm.cs index 0042f4607d..af145c418c 100644 --- a/osu.Game/Overlays/Login/LoginForm.cs +++ b/osu.Game/Overlays/Login/LoginForm.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Overlays.Login { - public class LoginForm : FillFlowContainer + public partial class LoginForm : FillFlowContainer { private TextBox username = null!; private TextBox password = null!; diff --git a/osu.Game/Overlays/Login/LoginPanel.cs b/osu.Game/Overlays/Login/LoginPanel.cs index 32a7fca1a6..44f2f3273a 100644 --- a/osu.Game/Overlays/Login/LoginPanel.cs +++ b/osu.Game/Overlays/Login/LoginPanel.cs @@ -22,7 +22,7 @@ using Container = osu.Framework.Graphics.Containers.Container; namespace osu.Game.Overlays.Login { - public class LoginPanel : FillFlowContainer + public partial class LoginPanel : FillFlowContainer { private bool bounding = true; private LoginForm form; diff --git a/osu.Game/Overlays/Login/UserDropdown.cs b/osu.Game/Overlays/Login/UserDropdown.cs index 73ccfb3443..dfc9d12977 100644 --- a/osu.Game/Overlays/Login/UserDropdown.cs +++ b/osu.Game/Overlays/Login/UserDropdown.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Login { - public class UserDropdown : OsuEnumDropdown + public partial class UserDropdown : OsuEnumDropdown { protected override DropdownHeader CreateHeader() => new UserDropdownHeader(); @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Login } } - protected class UserDropdownMenu : OsuDropdownMenu + protected partial class UserDropdownMenu : OsuDropdownMenu { public UserDropdownMenu() { @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Login protected override DrawableDropdownMenuItem CreateDrawableDropdownMenuItem(MenuItem item) => new DrawableUserDropdownMenuItem(item); - private class DrawableUserDropdownMenuItem : DrawableOsuDropdownMenuItem + private partial class DrawableUserDropdownMenuItem : DrawableOsuDropdownMenuItem { public DrawableUserDropdownMenuItem(MenuItem item) : base(item) @@ -74,7 +74,7 @@ namespace osu.Game.Overlays.Login } } - private class UserDropdownHeader : OsuDropdownHeader + private partial class UserDropdownHeader : OsuDropdownHeader { public const float LABEL_LEFT_MARGIN = 20; diff --git a/osu.Game/Overlays/LoginOverlay.cs b/osu.Game/Overlays/LoginOverlay.cs index 2362b2ad88..536811dfcf 100644 --- a/osu.Game/Overlays/LoginOverlay.cs +++ b/osu.Game/Overlays/LoginOverlay.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.Login; namespace osu.Game.Overlays { - public class LoginOverlay : OsuFocusedOverlayContainer + public partial class LoginOverlay : OsuFocusedOverlayContainer { private LoginPanel panel; diff --git a/osu.Game/Overlays/MedalOverlay.cs b/osu.Game/Overlays/MedalOverlay.cs index 9b856014f9..bd895fe6bf 100644 --- a/osu.Game/Overlays/MedalOverlay.cs +++ b/osu.Game/Overlays/MedalOverlay.cs @@ -27,7 +27,7 @@ using osu.Framework.Utils; namespace osu.Game.Overlays { - public class MedalOverlay : FocusedOverlayContainer + public partial class MedalOverlay : FocusedOverlayContainer { public const float DISC_SIZE = 400; @@ -266,7 +266,7 @@ namespace osu.Game.Overlays Expire(); } - private class BackgroundStrip : Container + private partial class BackgroundStrip : Container { public BackgroundStrip(float start, float end) { @@ -286,7 +286,7 @@ namespace osu.Game.Overlays } } - private class MedalParticle : CircularContainer + private partial class MedalParticle : CircularContainer { private readonly float direction; diff --git a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs index 1c007c913e..a25147b69f 100644 --- a/osu.Game/Overlays/MedalSplash/DrawableMedal.cs +++ b/osu.Game/Overlays/MedalSplash/DrawableMedal.cs @@ -19,7 +19,7 @@ using osu.Game.Users; namespace osu.Game.Overlays.MedalSplash { [LongRunningLoad] - public class DrawableMedal : Container, IStateful + public partial class DrawableMedal : Container, IStateful { private const float scale_when_unlocked = 0.76f; private const float scale_when_full = 0.6f; diff --git a/osu.Game/Overlays/Mods/AddPresetButton.cs b/osu.Game/Overlays/Mods/AddPresetButton.cs index 1242088cf5..731079d1d9 100644 --- a/osu.Game/Overlays/Mods/AddPresetButton.cs +++ b/osu.Game/Overlays/Mods/AddPresetButton.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Overlays.Mods { - public class AddPresetButton : ShearedToggleButton, IHasPopover + public partial class AddPresetButton : ShearedToggleButton, IHasPopover { [Resolved] private OsuColour colours { get; set; } = null!; diff --git a/osu.Game/Overlays/Mods/AddPresetPopover.cs b/osu.Game/Overlays/Mods/AddPresetPopover.cs index 8188c98e46..33d72ff383 100644 --- a/osu.Game/Overlays/Mods/AddPresetPopover.cs +++ b/osu.Game/Overlays/Mods/AddPresetPopover.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Overlays.Mods { - internal class AddPresetPopover : OsuPopover + internal partial class AddPresetPopover : OsuPopover { private readonly AddPresetButton button; diff --git a/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs b/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs index b3a19e35ce..800ebe8b4e 100644 --- a/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs +++ b/osu.Game/Overlays/Mods/DeleteModPresetDialog.cs @@ -7,7 +7,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Overlays.Mods { - public class DeleteModPresetDialog : DeleteConfirmationDialog + public partial class DeleteModPresetDialog : DeleteConfirmationDialog { public DeleteModPresetDialog(Live modPreset) { diff --git a/osu.Game/Overlays/Mods/DeselectAllModsButton.cs b/osu.Game/Overlays/Mods/DeselectAllModsButton.cs index 61fca9e091..3e5a3b12d1 100644 --- a/osu.Game/Overlays/Mods/DeselectAllModsButton.cs +++ b/osu.Game/Overlays/Mods/DeselectAllModsButton.cs @@ -15,7 +15,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Overlays.Mods { - public class DeselectAllModsButton : ShearedButton, IKeyBindingHandler + public partial class DeselectAllModsButton : ShearedButton, IKeyBindingHandler { private readonly Bindable> selectedMods = new Bindable>(); diff --git a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs index f582a010c6..ee4f932326 100644 --- a/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs +++ b/osu.Game/Overlays/Mods/DifficultyMultiplierDisplay.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Mods { - public sealed class DifficultyMultiplierDisplay : ModsEffectDisplay + public sealed partial class DifficultyMultiplierDisplay : ModsEffectDisplay { protected override LocalisableString Label => DifficultyMultiplierDisplayStrings.DifficultyMultiplier; diff --git a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs index 8cedd6b374..93279b6e1c 100644 --- a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs +++ b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModPanel.cs @@ -14,7 +14,7 @@ using osu.Game.Utils; namespace osu.Game.Overlays.Mods { - public class IncompatibilityDisplayingModPanel : ModPanel, IHasCustomTooltip + public partial class IncompatibilityDisplayingModPanel : ModPanel, IHasCustomTooltip { private readonly BindableBool incompatible = new BindableBool(); diff --git a/osu.Game/Overlays/Mods/IncompatibilityDisplayingTooltip.cs b/osu.Game/Overlays/Mods/IncompatibilityDisplayingTooltip.cs index 3f44e82d50..1723634774 100644 --- a/osu.Game/Overlays/Mods/IncompatibilityDisplayingTooltip.cs +++ b/osu.Game/Overlays/Mods/IncompatibilityDisplayingTooltip.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Overlays.Mods { - internal class IncompatibilityDisplayingTooltip : ModButtonTooltip + internal partial class IncompatibilityDisplayingTooltip : ModButtonTooltip { private readonly OsuSpriteText incompatibleText; diff --git a/osu.Game/Overlays/Mods/ModButtonTooltip.cs b/osu.Game/Overlays/Mods/ModButtonTooltip.cs index e19f24103f..52b27f1e00 100644 --- a/osu.Game/Overlays/Mods/ModButtonTooltip.cs +++ b/osu.Game/Overlays/Mods/ModButtonTooltip.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Overlays.Mods { - public class ModButtonTooltip : VisibilityContainer, ITooltip + public partial class ModButtonTooltip : VisibilityContainer, ITooltip { private readonly OsuSpriteText descriptionText; private readonly Box background; diff --git a/osu.Game/Overlays/Mods/ModColumn.cs b/osu.Game/Overlays/Mods/ModColumn.cs index b9f7114f74..5d9f616e5f 100644 --- a/osu.Game/Overlays/Mods/ModColumn.cs +++ b/osu.Game/Overlays/Mods/ModColumn.cs @@ -25,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Mods { - public class ModColumn : ModSelectColumn + public partial class ModColumn : ModSelectColumn { public readonly ModType ModType; @@ -219,7 +219,7 @@ namespace osu.Game.Overlays.Mods dequeuedAction(); } - private class ToggleAllCheckbox : OsuCheckbox + private partial class ToggleAllCheckbox : OsuCheckbox { private Color4 accentColour; diff --git a/osu.Game/Overlays/Mods/ModPanel.cs b/osu.Game/Overlays/Mods/ModPanel.cs index 7bdb9511ac..b5fee9d116 100644 --- a/osu.Game/Overlays/Mods/ModPanel.cs +++ b/osu.Game/Overlays/Mods/ModPanel.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Overlays.Mods { - public class ModPanel : ModSelectPanel + public partial class ModPanel : ModSelectPanel { public Mod Mod => modState.Mod; public override BindableBool Active => modState.Active; diff --git a/osu.Game/Overlays/Mods/ModPresetColumn.cs b/osu.Game/Overlays/Mods/ModPresetColumn.cs index 176c527a10..bf5e576277 100644 --- a/osu.Game/Overlays/Mods/ModPresetColumn.cs +++ b/osu.Game/Overlays/Mods/ModPresetColumn.cs @@ -18,7 +18,7 @@ using Realms; namespace osu.Game.Overlays.Mods { - public class ModPresetColumn : ModSelectColumn + public partial class ModPresetColumn : ModSelectColumn { [Resolved] private RealmAccess realm { get; set; } = null!; diff --git a/osu.Game/Overlays/Mods/ModPresetPanel.cs b/osu.Game/Overlays/Mods/ModPresetPanel.cs index b314a19142..6e12e34124 100644 --- a/osu.Game/Overlays/Mods/ModPresetPanel.cs +++ b/osu.Game/Overlays/Mods/ModPresetPanel.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Overlays.Mods { - public class ModPresetPanel : ModSelectPanel, IHasCustomTooltip, IHasContextMenu + public partial class ModPresetPanel : ModSelectPanel, IHasCustomTooltip, IHasContextMenu { public readonly Live Preset; diff --git a/osu.Game/Overlays/Mods/ModPresetTooltip.cs b/osu.Game/Overlays/Mods/ModPresetTooltip.cs index 97d118fbfd..ff4f00da69 100644 --- a/osu.Game/Overlays/Mods/ModPresetTooltip.cs +++ b/osu.Game/Overlays/Mods/ModPresetTooltip.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Overlays.Mods { - public class ModPresetTooltip : VisibilityContainer, ITooltip + public partial class ModPresetTooltip : VisibilityContainer, ITooltip { protected override Container Content { get; } @@ -62,7 +62,7 @@ namespace osu.Game.Overlays.Mods public void Move(Vector2 pos) => Position = pos; - private class ModPresetRow : FillFlowContainer + private partial class ModPresetRow : FillFlowContainer { public ModPresetRow(Mod mod) { diff --git a/osu.Game/Overlays/Mods/ModSelectColumn.cs b/osu.Game/Overlays/Mods/ModSelectColumn.cs index d5dc079628..e5154fd631 100644 --- a/osu.Game/Overlays/Mods/ModSelectColumn.cs +++ b/osu.Game/Overlays/Mods/ModSelectColumn.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Mods { - public abstract class ModSelectColumn : CompositeDrawable, IHasAccentColour + public abstract partial class ModSelectColumn : CompositeDrawable, IHasAccentColour { public readonly Container TopLevelContent; diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index ccc075b190..16602db4be 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -28,7 +28,7 @@ using osuTK; namespace osu.Game.Overlays.Mods { - public abstract class ModSelectOverlay : ShearedOverlayContainer, ISamplePlaybackDisabler + public abstract partial class ModSelectOverlay : ShearedOverlayContainer, ISamplePlaybackDisabler { public const int BUTTON_WIDTH = 200; @@ -612,7 +612,7 @@ namespace osu.Game.Overlays.Mods /// Manages horizontal scrolling of mod columns, along with the "active" states of each column based on visibility. /// [Cached] - internal class ColumnScrollContainer : OsuScrollContainer + internal partial class ColumnScrollContainer : OsuScrollContainer { public ColumnScrollContainer() : base(Direction.Horizontal) @@ -653,7 +653,7 @@ namespace osu.Game.Overlays.Mods /// /// Manages layout of mod columns. /// - internal class ColumnFlowContainer : FillFlowContainer + internal partial class ColumnFlowContainer : FillFlowContainer { public IEnumerable Columns => Children.Select(dimWrapper => dimWrapper.Column); @@ -669,7 +669,7 @@ namespace osu.Game.Overlays.Mods /// /// Encapsulates a column and provides dim and input blocking based on an externally managed "active" state. /// - internal class ColumnDimContainer : Container + internal partial class ColumnDimContainer : Container { public ModSelectColumn Column { get; } @@ -759,7 +759,7 @@ namespace osu.Game.Overlays.Mods /// /// A container which blocks and handles input, managing the "return from customisation" state change. /// - private class ClickToReturnContainer : Container + private partial class ClickToReturnContainer : Container { public BindableBool HandleMouse { get; } = new BindableBool(); diff --git a/osu.Game/Overlays/Mods/ModSelectPanel.cs b/osu.Game/Overlays/Mods/ModSelectPanel.cs index 27abface0c..81285833bd 100644 --- a/osu.Game/Overlays/Mods/ModSelectPanel.cs +++ b/osu.Game/Overlays/Mods/ModSelectPanel.cs @@ -24,7 +24,7 @@ using osuTK.Input; namespace osu.Game.Overlays.Mods { - public abstract class ModSelectPanel : OsuClickableContainer, IHasAccentColour + public abstract partial class ModSelectPanel : OsuClickableContainer, IHasAccentColour { public abstract BindableBool Active { get; } diff --git a/osu.Game/Overlays/Mods/ModSettingsArea.cs b/osu.Game/Overlays/Mods/ModSettingsArea.cs index 0932c2c832..f11fef1299 100644 --- a/osu.Game/Overlays/Mods/ModSettingsArea.cs +++ b/osu.Game/Overlays/Mods/ModSettingsArea.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Overlays.Mods { - public class ModSettingsArea : CompositeDrawable + public partial class ModSettingsArea : CompositeDrawable { public Bindable> SelectedMods { get; } = new Bindable>(Array.Empty()); @@ -110,7 +110,7 @@ namespace osu.Game.Overlays.Mods protected override bool OnMouseDown(MouseDownEvent e) => true; protected override bool OnHover(HoverEvent e) => true; - private class ModSettingsColumn : CompositeDrawable + private partial class ModSettingsColumn : CompositeDrawable { public ModSettingsColumn(Mod mod, IEnumerable settingsControls) { diff --git a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs index eed3181e49..3f31736ee1 100644 --- a/osu.Game/Overlays/Mods/ModsEffectDisplay.cs +++ b/osu.Game/Overlays/Mods/ModsEffectDisplay.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Mods /// /// Base class for displays of mods effects. /// - public abstract class ModsEffectDisplay : Container, IHasCurrentValue + public abstract partial class ModsEffectDisplay : Container, IHasCurrentValue { public const float HEIGHT = 42; private const float transition_duration = 200; @@ -201,7 +201,7 @@ namespace osu.Game.Overlays.Mods DifficultyIncrease } - private class EffectCounter : RollingCounter + private partial class EffectCounter : RollingCounter { private readonly string? format; diff --git a/osu.Game/Overlays/Mods/SelectAllModsButton.cs b/osu.Game/Overlays/Mods/SelectAllModsButton.cs index fc24e99c7e..f4b8025227 100644 --- a/osu.Game/Overlays/Mods/SelectAllModsButton.cs +++ b/osu.Game/Overlays/Mods/SelectAllModsButton.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.OnlinePlay; namespace osu.Game.Overlays.Mods { - public class SelectAllModsButton : ShearedButton, IKeyBindingHandler + public partial class SelectAllModsButton : ShearedButton, IKeyBindingHandler { private readonly Bindable> selectedMods = new Bindable>(); private readonly Bindable>> availableMods = new Bindable>>(); diff --git a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs index 2585e44e05..7f7b09a62c 100644 --- a/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs +++ b/osu.Game/Overlays/Mods/ShearedOverlayContainer.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Mods /// A sheared overlay which provides a header and footer and basic animations. /// Exposes , and as valid targets for content. /// - public abstract class ShearedOverlayContainer : OsuFocusedOverlayContainer + public abstract partial class ShearedOverlayContainer : OsuFocusedOverlayContainer { protected const float PADDING = 14; diff --git a/osu.Game/Overlays/Mods/UserModSelectOverlay.cs b/osu.Game/Overlays/Mods/UserModSelectOverlay.cs index 1090306c5b..49469b99f3 100644 --- a/osu.Game/Overlays/Mods/UserModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/UserModSelectOverlay.cs @@ -8,7 +8,7 @@ using osu.Game.Utils; namespace osu.Game.Overlays.Mods { - public class UserModSelectOverlay : ModSelectOverlay + public partial class UserModSelectOverlay : ModSelectOverlay { public UserModSelectOverlay(OverlayColourScheme colourScheme = OverlayColourScheme.Green) : base(colourScheme) @@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Mods return modsAfterRemoval.ToList(); } - private class UserModColumn : ModColumn + private partial class UserModColumn : ModColumn { public UserModColumn(ModType modType, bool allowIncompatibleSelection) : base(modType, allowIncompatibleSelection) diff --git a/osu.Game/Overlays/Music/FilterControl.cs b/osu.Game/Overlays/Music/FilterControl.cs index ffa50c3a35..a61702645a 100644 --- a/osu.Game/Overlays/Music/FilterControl.cs +++ b/osu.Game/Overlays/Music/FilterControl.cs @@ -13,7 +13,7 @@ using osu.Framework.Allocation; namespace osu.Game.Overlays.Music { - public class FilterControl : Container + public partial class FilterControl : Container { public Action FilterChanged; @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Music Collection = collectionDropdown.Current.Value?.Collection }; - public class FilterTextBox : BasicSearchTextBox + public partial class FilterTextBox : BasicSearchTextBox { protected override bool AllowCommit => true; diff --git a/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs b/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs index 8df465e075..827caf0467 100644 --- a/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs +++ b/osu.Game/Overlays/Music/MusicKeyBindingHandler.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Music /// /// Handles s related to music playback, and displays s via the global accordingly. /// - public class MusicKeyBindingHandler : Component, IKeyBindingHandler + public partial class MusicKeyBindingHandler : Component, IKeyBindingHandler { [Resolved] private IBindable beatmap { get; set; } @@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Music { } - private class MusicActionToast : Toast + private partial class MusicActionToast : Toast { private readonly GlobalAction action; diff --git a/osu.Game/Overlays/Music/NowPlayingCollectionDropdown.cs b/osu.Game/Overlays/Music/NowPlayingCollectionDropdown.cs index 635a2e5044..ae59fbb35e 100644 --- a/osu.Game/Overlays/Music/NowPlayingCollectionDropdown.cs +++ b/osu.Game/Overlays/Music/NowPlayingCollectionDropdown.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Music /// /// A for use in the . /// - public class NowPlayingCollectionDropdown : CollectionDropdown + public partial class NowPlayingCollectionDropdown : CollectionDropdown { protected override bool ShowManageCollectionsItem => false; @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Music protected override CollectionDropdownMenu CreateCollectionMenu() => new CollectionsMenu(); - private class CollectionsMenu : CollectionDropdownMenu + private partial class CollectionsMenu : CollectionDropdownMenu { public CollectionsMenu() { @@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Music } } - private class CollectionsHeader : CollectionDropdownHeader + private partial class CollectionsHeader : CollectionDropdownHeader { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/Music/Playlist.cs b/osu.Game/Overlays/Music/Playlist.cs index b48257a61a..ab51ca7e1d 100644 --- a/osu.Game/Overlays/Music/Playlist.cs +++ b/osu.Game/Overlays/Music/Playlist.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Overlays.Music { - public class Playlist : OsuRearrangeableListContainer> + public partial class Playlist : OsuRearrangeableListContainer> { public Action>? RequestSelection; diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index b30ae095b1..00c5ce8002 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Music { - public class PlaylistItem : OsuRearrangeableListItem>, IFilterable + public partial class PlaylistItem : OsuRearrangeableListItem>, IFilterable { public readonly Bindable> SelectedSet = new Bindable>(); diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 63f1aa248c..43b9024303 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -22,7 +22,7 @@ using Realms; namespace osu.Game.Overlays.Music { - public class PlaylistOverlay : VisibilityContainer + public partial class PlaylistOverlay : VisibilityContainer { private const float transition_duration = 600; public const float PLAYLIST_HEIGHT = 510; diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 793b7e294f..1ad5a8c08b 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays /// /// Handles playback of the global music track. /// - public class MusicController : CompositeDrawable + public partial class MusicController : CompositeDrawable { [Resolved] private BeatmapManager beatmaps { get; set; } diff --git a/osu.Game/Overlays/News/Displays/ArticleListing.cs b/osu.Game/Overlays/News/Displays/ArticleListing.cs index 8465ebf07c..b6ce16ae7d 100644 --- a/osu.Game/Overlays/News/Displays/ArticleListing.cs +++ b/osu.Game/Overlays/News/Displays/ArticleListing.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.News.Displays /// /// Lists articles in a vertical flow for a specified year. /// - public class ArticleListing : CompositeDrawable + public partial class ArticleListing : CompositeDrawable { private readonly Action fetchMorePosts; diff --git a/osu.Game/Overlays/News/NewsCard.cs b/osu.Game/Overlays/News/NewsCard.cs index c8e0b0c7ef..e0be5cc4a9 100644 --- a/osu.Game/Overlays/News/NewsCard.cs +++ b/osu.Game/Overlays/News/NewsCard.cs @@ -21,7 +21,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.News { - public class NewsCard : OsuHoverContainer + public partial class NewsCard : OsuHoverContainer { protected override IEnumerable EffectTargets => new[] { background }; @@ -121,7 +121,7 @@ namespace osu.Game.Overlays.News main.AddText(post.Author, t => t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold)); } - private class DateContainer : CircularContainer, IHasCustomTooltip + private partial class DateContainer : CircularContainer, IHasCustomTooltip { private readonly DateTimeOffset date; diff --git a/osu.Game/Overlays/News/NewsHeader.cs b/osu.Game/Overlays/News/NewsHeader.cs index d204dfcf2e..44e2f6a8cb 100644 --- a/osu.Game/Overlays/News/NewsHeader.cs +++ b/osu.Game/Overlays/News/NewsHeader.cs @@ -12,7 +12,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.News { - public class NewsHeader : BreadcrumbControlOverlayHeader + public partial class NewsHeader : BreadcrumbControlOverlayHeader { public static LocalisableString FrontPageString => NewsStrings.IndexTitleInfo; @@ -62,7 +62,7 @@ namespace osu.Game.Overlays.News protected override OverlayTitle CreateTitle() => new NewsHeaderTitle(); - private class NewsHeaderTitle : OverlayTitle + private partial class NewsHeaderTitle : OverlayTitle { public NewsHeaderTitle() { diff --git a/osu.Game/Overlays/News/NewsPostBackground.cs b/osu.Game/Overlays/News/NewsPostBackground.cs index b77623842c..05f8a639fa 100644 --- a/osu.Game/Overlays/News/NewsPostBackground.cs +++ b/osu.Game/Overlays/News/NewsPostBackground.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Overlays.News { [LongRunningLoad] - public class NewsPostBackground : Sprite + public partial class NewsPostBackground : Sprite { private readonly string sourceUrl; diff --git a/osu.Game/Overlays/News/Sidebar/MonthSection.cs b/osu.Game/Overlays/News/Sidebar/MonthSection.cs index 894f8d5667..d205fcb908 100644 --- a/osu.Game/Overlays/News/Sidebar/MonthSection.cs +++ b/osu.Game/Overlays/News/Sidebar/MonthSection.cs @@ -23,7 +23,7 @@ using osu.Framework.Platform; namespace osu.Game.Overlays.News.Sidebar { - public class MonthSection : CompositeDrawable + public partial class MonthSection : CompositeDrawable { public int Year { get; private set; } public int Month { get; private set; } @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.News.Sidebar sampleClose = audio.Samples.Get(@"UI/dropdown-close"); } - private class DropdownHeader : OsuClickableContainer + private partial class DropdownHeader : OsuClickableContainer { public readonly BindableBool Expanded = new BindableBool(); @@ -122,7 +122,7 @@ namespace osu.Game.Overlays.News.Sidebar } } - private class PostButton : OsuHoverContainer + private partial class PostButton : OsuHoverContainer { protected override IEnumerable EffectTargets => new[] { text }; @@ -154,7 +154,7 @@ namespace osu.Game.Overlays.News.Sidebar } } - private class PostsContainer : Container + private partial class PostsContainer : Container { public readonly BindableBool Expanded = new BindableBool(); diff --git a/osu.Game/Overlays/News/Sidebar/NewsSidebar.cs b/osu.Game/Overlays/News/Sidebar/NewsSidebar.cs index 884e15c03b..939e5367b7 100644 --- a/osu.Game/Overlays/News/Sidebar/NewsSidebar.cs +++ b/osu.Game/Overlays/News/Sidebar/NewsSidebar.cs @@ -13,7 +13,7 @@ using System.Linq; namespace osu.Game.Overlays.News.Sidebar { - public class NewsSidebar : OverlaySidebar + public partial class NewsSidebar : OverlaySidebar { [Cached] public readonly Bindable Metadata = new Bindable(); diff --git a/osu.Game/Overlays/News/Sidebar/YearsPanel.cs b/osu.Game/Overlays/News/Sidebar/YearsPanel.cs index 915ed1817c..524ffbf63d 100644 --- a/osu.Game/Overlays/News/Sidebar/YearsPanel.cs +++ b/osu.Game/Overlays/News/Sidebar/YearsPanel.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.News.Sidebar { - public class YearsPanel : CompositeDrawable + public partial class YearsPanel : CompositeDrawable { private readonly Bindable metadata = new Bindable(); @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.News.Sidebar Show(); } - public class YearButton : OsuHoverContainer + public partial class YearButton : OsuHoverContainer { public int Year { get; } diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index 87b7ebbe89..cb9d940a05 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.News.Sidebar; namespace osu.Game.Overlays { - public class NewsOverlay : OnlineOverlay + public partial class NewsOverlay : OnlineOverlay { private readonly Bindable article = new Bindable(); diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 36548c893c..3f3c6551c6 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -20,7 +20,7 @@ using NotificationsStrings = osu.Game.Localisation.NotificationsStrings; namespace osu.Game.Overlays { - public class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent, INotificationOverlay + public partial class NotificationOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent, INotificationOverlay { public string IconTexture => "Icons/Hexacons/notification"; public LocalisableString Title => NotificationsStrings.HeaderTitle; diff --git a/osu.Game/Overlays/NotificationOverlayToastTray.cs b/osu.Game/Overlays/NotificationOverlayToastTray.cs index 329379de4a..7a793ee092 100644 --- a/osu.Game/Overlays/NotificationOverlayToastTray.cs +++ b/osu.Game/Overlays/NotificationOverlayToastTray.cs @@ -22,7 +22,7 @@ namespace osu.Game.Overlays /// /// A tray which attaches to the left of to show temporary toasts. /// - public class NotificationOverlayToastTray : CompositeDrawable + public partial class NotificationOverlayToastTray : CompositeDrawable { public override bool IsPresent => toastContentBackground.Height > 0 || toastFlow.Count > 0; diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 8be9d2072b..77d3317b1f 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Overlays.Notifications { - public abstract class Notification : Container + public abstract partial class Notification : Container { /// /// Notification was closed, either by user or otherwise. @@ -269,7 +269,7 @@ namespace osu.Game.Overlays.Notifications }); } - private class DragContainer : Container + private partial class DragContainer : Container { private Vector2 velocity; private Vector2 lastPosition; @@ -381,7 +381,7 @@ namespace osu.Game.Overlays.Notifications } } - internal class CloseButton : OsuClickableContainer + internal partial class CloseButton : OsuClickableContainer { private SpriteIcon icon = null!; private Box background = null!; @@ -436,7 +436,7 @@ namespace osu.Game.Overlays.Notifications } } - public class NotificationLight : Container + public partial class NotificationLight : Container { private bool pulsate; private Container pulsateLayer = null!; diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 16105f913f..d55a2abd2a 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Overlays.Notifications { - public class NotificationSection : AlwaysUpdateFillFlowContainer + public partial class NotificationSection : AlwaysUpdateFillFlowContainer { private OsuSpriteText countDrawable = null!; @@ -135,7 +135,7 @@ namespace osu.Game.Overlays.Notifications return count; } - private class ClearAllButton : OsuClickableContainer + private partial class ClearAllButton : OsuClickableContainer { private readonly OsuSpriteText text; @@ -162,7 +162,7 @@ namespace osu.Game.Overlays.Notifications } } - public class AlwaysUpdateFillFlowContainer : FillFlowContainer + public partial class AlwaysUpdateFillFlowContainer : FillFlowContainer where T : Drawable { // this is required to ensure correct layout and scheduling on children. diff --git a/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs index 3cbdf7edf7..46972d4b5e 100644 --- a/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Overlays.Notifications { - public class ProgressCompletionNotification : SimpleNotification + public partial class ProgressCompletionNotification : SimpleNotification { public ProgressCompletionNotification() { diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 9812feb4a1..5cce0f8c5b 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Notifications { - public class ProgressNotification : Notification, IHasCompletionTarget + public partial class ProgressNotification : Notification, IHasCompletionTarget { private const float loading_spinner_size = 22; @@ -255,7 +255,7 @@ namespace osu.Game.Overlays.Notifications } } - private class ProgressBar : Container + private partial class ProgressBar : Container { private readonly Box box; diff --git a/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs b/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs index ffefcb033f..7d0d07fc1b 100644 --- a/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Overlays.Notifications { - public class SimpleErrorNotification : SimpleNotification + public partial class SimpleErrorNotification : SimpleNotification { public override string PopInSampleName => "UI/error-notification-pop-in"; diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index f3bb6a0578..109b31ff71 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Overlays.Notifications { - public class SimpleNotification : Notification + public partial class SimpleNotification : Notification { private LocalisableString text; diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index 949f1e7b96..66fb3571ba 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -28,7 +28,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public class NowPlayingOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent + public partial class NowPlayingOverlay : OsuFocusedOverlayContainer, INamedOverlayComponent { public string IconTexture => "Icons/Hexacons/music"; public LocalisableString Title => NowPlayingStrings.HeaderTitle; @@ -356,7 +356,7 @@ namespace osu.Game.Overlays musicController.TrackChanged -= trackChanged; } - private class MusicIconButton : IconButton + private partial class MusicIconButton : IconButton { public MusicIconButton() { @@ -380,7 +380,7 @@ namespace osu.Game.Overlays } } - private class Background : BufferedContainer + private partial class Background : BufferedContainer { private readonly Sprite sprite; private readonly WorkingBeatmap beatmap; @@ -419,7 +419,7 @@ namespace osu.Game.Overlays } } - private class DragContainer : Container + private partial class DragContainer : Container { protected override bool OnDragStart(DragStartEvent e) { @@ -443,7 +443,7 @@ namespace osu.Game.Overlays } } - private class HoverableProgressBar : ProgressBar + private partial class HoverableProgressBar : ProgressBar { public HoverableProgressBar() : base(true) diff --git a/osu.Game/Overlays/OSD/CopyUrlToast.cs b/osu.Game/Overlays/OSD/CopyUrlToast.cs index ea835a1c5e..ce5a5f56c4 100644 --- a/osu.Game/Overlays/OSD/CopyUrlToast.cs +++ b/osu.Game/Overlays/OSD/CopyUrlToast.cs @@ -5,7 +5,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.OSD { - public class CopyUrlToast : Toast + public partial class CopyUrlToast : Toast { public CopyUrlToast() : base(UserInterfaceStrings.GeneralHeader, ToastStrings.UrlCopied, "") diff --git a/osu.Game/Overlays/OSD/Toast.cs b/osu.Game/Overlays/OSD/Toast.cs index a9fab0a23d..ff8696c04f 100644 --- a/osu.Game/Overlays/OSD/Toast.cs +++ b/osu.Game/Overlays/OSD/Toast.cs @@ -16,7 +16,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.OSD { - public abstract class Toast : Container + public abstract partial class Toast : Container { private const int toast_minimum_width = 240; diff --git a/osu.Game/Overlays/OSD/TrackedSettingToast.cs b/osu.Game/Overlays/OSD/TrackedSettingToast.cs index 3bed5e7e4c..1aa6de423e 100644 --- a/osu.Game/Overlays/OSD/TrackedSettingToast.cs +++ b/osu.Game/Overlays/OSD/TrackedSettingToast.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.OSD { - public class TrackedSettingToast : Toast + public partial class TrackedSettingToast : Toast { private const int lights_bottom_margin = 40; @@ -129,7 +129,7 @@ namespace osu.Game.Overlays.OSD sampleChange = audio.Samples.Get("UI/osd-change"); } - private class OptionLight : Container + private partial class OptionLight : Container { private Color4 glowingColour, idleColour; diff --git a/osu.Game/Overlays/OnScreenDisplay.cs b/osu.Game/Overlays/OnScreenDisplay.cs index f2836885ce..d60077cfa9 100644 --- a/osu.Game/Overlays/OnScreenDisplay.cs +++ b/osu.Game/Overlays/OnScreenDisplay.cs @@ -20,7 +20,7 @@ namespace osu.Game.Overlays /// An on-screen display which automatically tracks and displays toast notifications for . /// Can also display custom content via /// - public class OnScreenDisplay : Container + public partial class OnScreenDisplay : Container { private readonly Container box; diff --git a/osu.Game/Overlays/OnlineOverlay.cs b/osu.Game/Overlays/OnlineOverlay.cs index 24bc7a73e0..0e0ce56446 100644 --- a/osu.Game/Overlays/OnlineOverlay.cs +++ b/osu.Game/Overlays/OnlineOverlay.cs @@ -12,7 +12,7 @@ using osu.Game.Online; namespace osu.Game.Overlays { - public abstract class OnlineOverlay : FullscreenOverlay + public abstract partial class OnlineOverlay : FullscreenOverlay where T : OverlayHeader { protected override Container Content => content; diff --git a/osu.Game/Overlays/OverlayHeader.cs b/osu.Game/Overlays/OverlayHeader.cs index ed8e3849d4..f8935f7f0a 100644 --- a/osu.Game/Overlays/OverlayHeader.cs +++ b/osu.Game/Overlays/OverlayHeader.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public abstract class OverlayHeader : Container + public abstract partial class OverlayHeader : Container { public OverlayTitle Title { get; } diff --git a/osu.Game/Overlays/OverlayHeaderBackground.cs b/osu.Game/Overlays/OverlayHeaderBackground.cs index 540b28d9b2..a089001385 100644 --- a/osu.Game/Overlays/OverlayHeaderBackground.cs +++ b/osu.Game/Overlays/OverlayHeaderBackground.cs @@ -11,7 +11,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Overlays { - public class OverlayHeaderBackground : CompositeDrawable + public partial class OverlayHeaderBackground : CompositeDrawable { public OverlayHeaderBackground(string textureName) { @@ -21,7 +21,7 @@ namespace osu.Game.Overlays InternalChild = new DelayedLoadWrapper(() => new Background(textureName)); } - private class Background : Sprite + private partial class Background : Sprite { private readonly string textureName; diff --git a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs index 14a99cd5bb..d7d6bd4a2a 100644 --- a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs +++ b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs @@ -19,7 +19,7 @@ using osu.Framework.Extensions; namespace osu.Game.Overlays { - public class OverlayPanelDisplayStyleControl : OsuTabControl + public partial class OverlayPanelDisplayStyleControl : OsuTabControl { protected override Dropdown CreateDropdown() => null; @@ -51,7 +51,7 @@ namespace osu.Game.Overlays Direction = FillDirection.Horizontal }; - private class PanelDisplayTabItem : TabItem, IHasTooltip + private partial class PanelDisplayTabItem : TabItem, IHasTooltip { public IconUsage Icon { diff --git a/osu.Game/Overlays/OverlayRulesetSelector.cs b/osu.Game/Overlays/OverlayRulesetSelector.cs index a0efb197c2..bcce2ce433 100644 --- a/osu.Game/Overlays/OverlayRulesetSelector.cs +++ b/osu.Game/Overlays/OverlayRulesetSelector.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Overlays { - public class OverlayRulesetSelector : RulesetSelector + public partial class OverlayRulesetSelector : RulesetSelector { public OverlayRulesetSelector() { diff --git a/osu.Game/Overlays/OverlayRulesetTabItem.cs b/osu.Game/Overlays/OverlayRulesetTabItem.cs index ba0b81a514..d5c70a46d0 100644 --- a/osu.Game/Overlays/OverlayRulesetTabItem.cs +++ b/osu.Game/Overlays/OverlayRulesetTabItem.cs @@ -18,7 +18,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays { - public class OverlayRulesetTabItem : TabItem, IHasTooltip + public partial class OverlayRulesetTabItem : TabItem, IHasTooltip { private Color4 accentColour; diff --git a/osu.Game/Overlays/OverlayScrollContainer.cs b/osu.Game/Overlays/OverlayScrollContainer.cs index 95b27665f4..5bd7f014a9 100644 --- a/osu.Game/Overlays/OverlayScrollContainer.cs +++ b/osu.Game/Overlays/OverlayScrollContainer.cs @@ -23,7 +23,7 @@ namespace osu.Game.Overlays /// /// which provides . Mostly used in . /// - public class OverlayScrollContainer : UserTrackingScrollContainer + public partial class OverlayScrollContainer : UserTrackingScrollContainer { /// /// Scroll position at which the will be shown. @@ -62,7 +62,7 @@ namespace osu.Game.Overlays Button.State = Visibility.Hidden; } - public class ScrollToTopButton : OsuHoverContainer + public partial class ScrollToTopButton : OsuHoverContainer { private const int fade_duration = 500; diff --git a/osu.Game/Overlays/OverlaySidebar.cs b/osu.Game/Overlays/OverlaySidebar.cs index 62f3e1af13..87ce1b7e8c 100644 --- a/osu.Game/Overlays/OverlaySidebar.cs +++ b/osu.Game/Overlays/OverlaySidebar.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays { - public abstract class OverlaySidebar : CompositeDrawable + public abstract partial class OverlaySidebar : CompositeDrawable { private readonly Box sidebarBackground; private readonly Box scrollbarBackground; diff --git a/osu.Game/Overlays/OverlaySortTabControl.cs b/osu.Game/Overlays/OverlaySortTabControl.cs index befb011353..8af2ab3823 100644 --- a/osu.Game/Overlays/OverlaySortTabControl.cs +++ b/osu.Game/Overlays/OverlaySortTabControl.cs @@ -24,7 +24,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays { - public class OverlaySortTabControl : CompositeDrawable, IHasCurrentValue + public partial class OverlaySortTabControl : CompositeDrawable, IHasCurrentValue { public TabControl TabControl { get; } @@ -74,7 +74,7 @@ namespace osu.Game.Overlays [NotNull] protected virtual SortTabControl CreateControl() => new SortTabControl(); - protected class SortTabControl : OsuTabControl + protected partial class SortTabControl : OsuTabControl { protected override Dropdown CreateDropdown() => null; @@ -93,7 +93,7 @@ namespace osu.Game.Overlays } } - protected class SortTabItem : TabItem + protected partial class SortTabItem : TabItem { public SortTabItem(T value) : base(value) @@ -117,7 +117,7 @@ namespace osu.Game.Overlays } } - protected class TabButton : HeaderButton + protected partial class TabButton : HeaderButton { public readonly BindableBool Active = new BindableBool(); diff --git a/osu.Game/Overlays/OverlayStreamControl.cs b/osu.Game/Overlays/OverlayStreamControl.cs index 1bd244176e..84de384fb5 100644 --- a/osu.Game/Overlays/OverlayStreamControl.cs +++ b/osu.Game/Overlays/OverlayStreamControl.cs @@ -12,7 +12,7 @@ using JetBrains.Annotations; namespace osu.Game.Overlays { - public abstract class OverlayStreamControl : TabControl + public abstract partial class OverlayStreamControl : TabControl { protected OverlayStreamControl() { diff --git a/osu.Game/Overlays/OverlayStreamItem.cs b/osu.Game/Overlays/OverlayStreamItem.cs index 3e09956480..9b18e5cccf 100644 --- a/osu.Game/Overlays/OverlayStreamItem.cs +++ b/osu.Game/Overlays/OverlayStreamItem.cs @@ -18,7 +18,7 @@ using osu.Framework.Localisation; namespace osu.Game.Overlays { - public abstract class OverlayStreamItem : TabItem + public abstract partial class OverlayStreamItem : TabItem { public readonly Bindable SelectedItem = new Bindable(); diff --git a/osu.Game/Overlays/OverlayTabControl.cs b/osu.Game/Overlays/OverlayTabControl.cs index 35e073a3a1..884e31868f 100644 --- a/osu.Game/Overlays/OverlayTabControl.cs +++ b/osu.Game/Overlays/OverlayTabControl.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public abstract class OverlayTabControl : OsuTabControl + public abstract partial class OverlayTabControl : OsuTabControl { private readonly Box bar; @@ -58,7 +58,7 @@ namespace osu.Game.Overlays protected override TabItem CreateTabItem(T value) => new OverlayTabItem(value); - protected class OverlayTabItem : TabItem, IHasAccentColour + protected partial class OverlayTabItem : TabItem, IHasAccentColour { protected readonly ExpandingBar Bar; protected readonly OsuSpriteText Text; diff --git a/osu.Game/Overlays/OverlayTitle.cs b/osu.Game/Overlays/OverlayTitle.cs index f2c42034a3..1d207e5f7d 100644 --- a/osu.Game/Overlays/OverlayTitle.cs +++ b/osu.Game/Overlays/OverlayTitle.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Overlays { - public abstract class OverlayTitle : CompositeDrawable, INamedOverlayComponent + public abstract partial class OverlayTitle : CompositeDrawable, INamedOverlayComponent { public const float ICON_SIZE = 30; @@ -69,7 +69,7 @@ namespace osu.Game.Overlays }; } - private class OverlayTitleIcon : Sprite + private partial class OverlayTitleIcon : Sprite { private readonly string textureName; diff --git a/osu.Game/Overlays/OverlayView.cs b/osu.Game/Overlays/OverlayView.cs index 80df0c695f..e919641b9b 100644 --- a/osu.Game/Overlays/OverlayView.cs +++ b/osu.Game/Overlays/OverlayView.cs @@ -18,7 +18,7 @@ namespace osu.Game.Overlays /// Automatically performs a data fetch on load. /// /// The type of the API response. - public abstract class OverlayView : CompositeDrawable + public abstract partial class OverlayView : CompositeDrawable where T : class { [Resolved] diff --git a/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs index dcc8b19021..5ba3963a45 100644 --- a/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/BottomHeaderContainer.cs @@ -23,7 +23,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Profile.Header { - public class BottomHeaderContainer : CompositeDrawable + public partial class BottomHeaderContainer : CompositeDrawable { public readonly Bindable User = new Bindable(); diff --git a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs index b07817de46..5f6af7a6e2 100644 --- a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Header { - public class CentreHeaderContainer : CompositeDrawable + public partial class CentreHeaderContainer : CompositeDrawable { public readonly BindableBool DetailsVisible = new BindableBool(true); public readonly Bindable User = new Bindable(); diff --git a/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs b/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs index 2ee80a7494..5f100bc882 100644 --- a/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/DrawableBadge.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Header.Components { [LongRunningLoad] - public class DrawableBadge : OsuClickableContainer + public partial class DrawableBadge : OsuClickableContainer { public static readonly Vector2 DRAWABLE_BADGE_SIZE = new Vector2(86, 40); diff --git a/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs b/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs index 62b228c285..a778ddd2b1 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ExpandDetailsButton.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Header.Components { - public class ExpandDetailsButton : ProfileHeaderButton + public partial class ExpandDetailsButton : ProfileHeaderButton { public readonly BindableBool DetailsVisible = new BindableBool(); diff --git a/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs b/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs index 6fbfff1dd7..c278a6c48b 100644 --- a/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/FollowersButton.cs @@ -12,7 +12,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Header.Components { - public class FollowersButton : ProfileHeaderStatisticsButton + public partial class FollowersButton : ProfileHeaderStatisticsButton { public readonly Bindable User = new Bindable(); diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index fdf7478834..ef2f35e9a8 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -18,7 +18,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Header.Components { - public class LevelBadge : CompositeDrawable, IHasTooltip + public partial class LevelBadge : CompositeDrawable, IHasTooltip { public readonly Bindable User = new Bindable(); diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs b/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs index 1ba391431f..0351230fb3 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Profile.Header.Components { - public class LevelProgressBar : CompositeDrawable, IHasTooltip + public partial class LevelProgressBar : CompositeDrawable, IHasTooltip { public readonly Bindable User = new Bindable(); diff --git a/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs b/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs index 7bfc78cb2d..887cf10cce 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MappingSubscribersButton.cs @@ -12,7 +12,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Header.Components { - public class MappingSubscribersButton : ProfileHeaderStatisticsButton + public partial class MappingSubscribersButton : ProfileHeaderStatisticsButton { public readonly Bindable User = new Bindable(); diff --git a/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs b/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs index 46cb811846..4886324a22 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Header.Components { - public class MessageUserButton : ProfileHeaderButton + public partial class MessageUserButton : ProfileHeaderButton { public readonly Bindable User = new Bindable(); diff --git a/osu.Game/Overlays/Profile/Header/Components/OverlinedInfoContainer.cs b/osu.Game/Overlays/Profile/Header/Components/OverlinedInfoContainer.cs index 7ac472ee00..244f185e28 100644 --- a/osu.Game/Overlays/Profile/Header/Components/OverlinedInfoContainer.cs +++ b/osu.Game/Overlays/Profile/Header/Components/OverlinedInfoContainer.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Profile.Header.Components { - public class OverlinedInfoContainer : CompositeDrawable + public partial class OverlinedInfoContainer : CompositeDrawable { private readonly Circle line; private readonly OsuSpriteText title; diff --git a/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs b/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs index 9e5a0f5962..c040f5a787 100644 --- a/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs +++ b/osu.Game/Overlays/Profile/Header/Components/OverlinedTotalPlayTime.cs @@ -14,7 +14,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Header.Components { - public class OverlinedTotalPlayTime : CompositeDrawable, IHasTooltip + public partial class OverlinedTotalPlayTime : CompositeDrawable, IHasTooltip { public readonly Bindable User = new Bindable(); diff --git a/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs b/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs index 808c814928..0abc4de5ef 100644 --- a/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs +++ b/osu.Game/Overlays/Profile/Header/Components/PreviousUsernames.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Header.Components { - public class PreviousUsernames : CompositeDrawable + public partial class PreviousUsernames : CompositeDrawable { private const int duration = 200; private const int margin = 10; @@ -147,7 +147,7 @@ namespace osu.Game.Overlays.Profile.Header.Components this.MoveToY(0, duration, Easing.OutQuint); } - private class HoverIconContainer : Container + private partial class HoverIconContainer : Container { public Action ActivateHover; diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderButton.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderButton.cs index 5bdf9c19e1..c4a46440d2 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderButton.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Profile.Header.Components { - public abstract class ProfileHeaderButton : OsuHoverContainer + public abstract partial class ProfileHeaderButton : OsuHoverContainer { private readonly Box background; private readonly Container content; diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs index 3b3251fc4e..5ad726a3ea 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Header.Components { - public abstract class ProfileHeaderStatisticsButton : ProfileHeaderButton + public abstract partial class ProfileHeaderStatisticsButton : ProfileHeaderButton { private readonly OsuSpriteText drawableText; diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs index 3a47570cf7..72446bde3a 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetSelector.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets; namespace osu.Game.Overlays.Profile.Header.Components { - public class ProfileRulesetSelector : OverlayRulesetSelector + public partial class ProfileRulesetSelector : OverlayRulesetSelector { public readonly Bindable User = new Bindable(); diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetTabItem.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetTabItem.cs index d75fe1ae84..72adc96f9a 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetTabItem.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileRulesetTabItem.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Profile.Header.Components { - public class ProfileRulesetTabItem : OverlayRulesetTabItem + public partial class ProfileRulesetTabItem : OverlayRulesetTabItem { private bool isDefault; @@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Profile.Header.Components Add(icon = new DefaultRulesetIcon { Alpha = 0 }); } - public class DefaultRulesetIcon : SpriteIcon, IHasTooltip + public partial class DefaultRulesetIcon : SpriteIcon, IHasTooltip { public LocalisableString TooltipText => UsersStrings.ShowEditDefaultPlaymodeIsDefaultTooltip; diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index 85fb5c4e5c..51531977d2 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs @@ -17,7 +17,7 @@ using osu.Game.Users; namespace osu.Game.Overlays.Profile.Header.Components { - public class RankGraph : UserGraph + public partial class RankGraph : UserGraph { private const int ranked_days = 88; diff --git a/osu.Game/Overlays/Profile/Header/Components/SupporterIcon.cs b/osu.Game/Overlays/Profile/Header/Components/SupporterIcon.cs index a05d8ba152..4028eb1389 100644 --- a/osu.Game/Overlays/Profile/Header/Components/SupporterIcon.cs +++ b/osu.Game/Overlays/Profile/Header/Components/SupporterIcon.cs @@ -17,7 +17,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Header.Components { - public class SupporterIcon : OsuClickableContainer + public partial class SupporterIcon : OsuClickableContainer { private readonly Box background; private readonly FillFlowContainer iconContainer; diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index d65691f531..44986dc178 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Header { - public class DetailHeaderContainer : CompositeDrawable + public partial class DetailHeaderContainer : CompositeDrawable { private readonly Dictionary scoreRankInfos = new Dictionary(); private OverlinedInfoContainer medalInfo; @@ -187,7 +187,7 @@ namespace osu.Game.Overlays.Profile.Header rankGraph.Statistics.Value = user?.Statistics; } - private class ScoreRankInfo : CompositeDrawable + private partial class ScoreRankInfo : CompositeDrawable { private readonly OsuSpriteText rankCount; diff --git a/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs index deb675df1d..ab800d006d 100644 --- a/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/MedalHeaderContainer.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Profile.Header { - public class MedalHeaderContainer : CompositeDrawable + public partial class MedalHeaderContainer : CompositeDrawable { private FillFlowContainer badgeFlowContainer; diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 67a6df3228..8826dd982d 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -25,7 +25,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Header { - public class TopHeaderContainer : CompositeDrawable + public partial class TopHeaderContainer : CompositeDrawable { private const float avatar_size = 110; @@ -201,7 +201,7 @@ namespace osu.Game.Overlays.Profile.Header } } - private class UserStatsLine : Container + private partial class UserStatsLine : Container { public UserStatsLine(LocalisableString left, LocalisableString right) { diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 1eca6a81cf..8443678989 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -18,7 +18,7 @@ using osu.Game.Users; namespace osu.Game.Overlays.Profile { - public class ProfileHeader : TabControlOverlayHeader + public partial class ProfileHeader : TabControlOverlayHeader { private UserCoverBackground coverContainer; @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.Profile private void updateDisplay(APIUser user) => coverContainer.User = user; - private class ProfileHeaderTitle : OverlayTitle + private partial class ProfileHeaderTitle : OverlayTitle { public ProfileHeaderTitle() { @@ -113,7 +113,7 @@ namespace osu.Game.Overlays.Profile } } - private class ProfileCoverBackground : UserCoverBackground + private partial class ProfileCoverBackground : UserCoverBackground { protected override double LoadDelay => 0; } diff --git a/osu.Game/Overlays/Profile/ProfileSection.cs b/osu.Game/Overlays/Profile/ProfileSection.cs index 67738943e8..fc99050f73 100644 --- a/osu.Game/Overlays/Profile/ProfileSection.cs +++ b/osu.Game/Overlays/Profile/ProfileSection.cs @@ -19,7 +19,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile { - public abstract class ProfileSection : Container + public abstract partial class ProfileSection : Container { public abstract LocalisableString Title { get; } @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.Profile underscore.Colour = colourProvider.Highlight1; } - private class SectionTriangles : Container + private partial class SectionTriangles : Container { private readonly Triangles triangles; private readonly Box foreground; diff --git a/osu.Game/Overlays/Profile/Sections/AboutSection.cs b/osu.Game/Overlays/Profile/Sections/AboutSection.cs index 2b6ce732a2..ac3dca5107 100644 --- a/osu.Game/Overlays/Profile/Sections/AboutSection.cs +++ b/osu.Game/Overlays/Profile/Sections/AboutSection.cs @@ -8,7 +8,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Sections { - public class AboutSection : ProfileSection + public partial class AboutSection : ProfileSection { public override LocalisableString Title => UsersStrings.ShowExtraMeTitle; diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs index 5d36537c3e..5a80a4d444 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapMetadataContainer.cs @@ -14,7 +14,7 @@ namespace osu.Game.Overlays.Profile.Sections /// /// Display artist/title/mapper information, commonly used as the left portion of a profile or score display row. /// - public abstract class BeatmapMetadataContainer : OsuHoverContainer + public abstract partial class BeatmapMetadataContainer : OsuHoverContainer { private readonly IBeatmapInfo beatmapInfo; diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index aaaed5ad0a..8c1eea6520 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -17,7 +17,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Beatmaps { - public class PaginatedBeatmapContainer : PaginatedProfileSubsection + public partial class PaginatedBeatmapContainer : PaginatedProfileSubsection { private const float panel_padding = 10f; private readonly BeatmapSetType type; diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs index e3cff5da05..9f2e79b371 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs @@ -10,7 +10,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Sections { - public class BeatmapsSection : ProfileSection + public partial class BeatmapsSection : ProfileSection { public override LocalisableString Title => UsersStrings.ShowExtraBeatmapsTitle; diff --git a/osu.Game/Overlays/Profile/Sections/CounterPill.cs b/osu.Game/Overlays/Profile/Sections/CounterPill.cs index e9b55f62ef..c93cdb84f2 100644 --- a/osu.Game/Overlays/Profile/Sections/CounterPill.cs +++ b/osu.Game/Overlays/Profile/Sections/CounterPill.cs @@ -14,7 +14,7 @@ using osu.Framework.Extensions.LocalisationExtensions; namespace osu.Game.Overlays.Profile.Sections { - public class CounterPill : CircularContainer + public partial class CounterPill : CircularContainer { public readonly BindableInt Current = new BindableInt(); diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs index f0819c4474..e0837320b2 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ChartProfileSubsection.cs @@ -13,7 +13,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections.Historical { - public abstract class ChartProfileSubsection : ProfileSubsection + public abstract partial class ChartProfileSubsection : ProfileSubsection { private ProfileLineChart chart; diff --git a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs index 70ab95b848..414c6f194a 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs @@ -21,7 +21,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Sections.Historical { - public class DrawableMostPlayedBeatmap : CompositeDrawable + public partial class DrawableMostPlayedBeatmap : CompositeDrawable { private const int cover_width = 100; private const int corner_radius = 6; @@ -110,7 +110,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical }); } - private class MostPlayedBeatmapContainer : ProfileItemContainer + private partial class MostPlayedBeatmapContainer : ProfileItemContainer { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -120,7 +120,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical } } - private class MostPlayedBeatmapMetadataContainer : BeatmapMetadataContainer + private partial class MostPlayedBeatmapMetadataContainer : BeatmapMetadataContainer { public MostPlayedBeatmapMetadataContainer(IBeatmapInfo beatmapInfo) : base(beatmapInfo) @@ -159,7 +159,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical } } - private class PlayCountText : CompositeDrawable, IHasTooltip + private partial class PlayCountText : CompositeDrawable, IHasTooltip { public LocalisableString TooltipText => UsersStrings.ShowExtraHistoricalMostPlayedCount; diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs index 34c9892f06..222969bdfd 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs @@ -16,7 +16,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Historical { - public class PaginatedMostPlayedBeatmapContainer : PaginatedProfileSubsection + public partial class PaginatedMostPlayedBeatmapContainer : PaginatedProfileSubsection { public PaginatedMostPlayedBeatmapContainer(Bindable user) : base(user, UsersStrings.ShowExtraHistoricalMostPlayedTitle) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs index 73e39a2440..186bf73898 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/PlayHistorySubsection.cs @@ -10,7 +10,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Sections.Historical { - public class PlayHistorySubsection : ChartProfileSubsection + public partial class PlayHistorySubsection : ChartProfileSubsection { protected override LocalisableString GraphCounterName => UsersStrings.ShowExtraHistoricalMonthlyPlaycountsCountLabel; diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 78a28a39d2..da86d870fc 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -20,7 +20,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections.Historical { - public class ProfileLineChart : CompositeDrawable + public partial class ProfileLineChart : CompositeDrawable { private APIUserHistoryCount[] values; @@ -242,7 +242,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical return Math.Max((long)(tickMultiplier * tickBase), 1); } - private class TickText : OsuSpriteText + private partial class TickText : OsuSpriteText { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -251,7 +251,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical } } - private class TickLine : Box + private partial class TickLine : Box { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs b/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs index 89e8f51338..d1d1e76e14 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ReplaysSubsection.cs @@ -10,7 +10,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Sections.Historical { - public class ReplaysSubsection : ChartProfileSubsection + public partial class ReplaysSubsection : ChartProfileSubsection { protected override LocalisableString GraphCounterName => UsersStrings.ShowExtraHistoricalReplaysWatchedCountsCountLabel; diff --git a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs index 48d75a4953..3f68ffdd0e 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs @@ -13,7 +13,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections.Historical { - public class UserHistoryGraph : UserGraph + public partial class UserHistoryGraph : UserGraph { private readonly LocalisableString tooltipCounterName; diff --git a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs index f1e1c44734..13e0aefc65 100644 --- a/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs +++ b/osu.Game/Overlays/Profile/Sections/HistoricalSection.cs @@ -12,7 +12,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Sections { - public class HistoricalSection : ProfileSection + public partial class HistoricalSection : ProfileSection { public override LocalisableString Title => UsersStrings.ShowExtraHistoricalTitle; diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs index 44f1af4b72..122b20cbfc 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/DrawableKudosuHistoryItem.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Sections.Kudosu { - public class DrawableKudosuHistoryItem : CompositeDrawable + public partial class DrawableKudosuHistoryItem : CompositeDrawable { private const int height = 25; diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index bb9d48c473..2b4d58b845 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -20,7 +20,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections.Kudosu { - public class KudosuInfo : Container + public partial class KudosuInfo : Container { private readonly Bindable user = new Bindable(); @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu protected override bool OnClick(ClickEvent e) => true; - private class CountTotal : CountSection + private partial class CountTotal : CountSection { public CountTotal() : base(UsersStrings.ShowExtraKudosuTotal) @@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu } } - private class CountSection : Container + private partial class CountSection : Container { private readonly OsuSpriteText valueText; protected readonly LinkFlowContainer DescriptionText; diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs index 34e6866d25..c082c634a7 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/PaginatedKudosuHistoryContainer.cs @@ -14,7 +14,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Kudosu { - public class PaginatedKudosuHistoryContainer : PaginatedProfileSubsection + public partial class PaginatedKudosuHistoryContainer : PaginatedProfileSubsection { public PaginatedKudosuHistoryContainer(Bindable user) : base(user, missingText: UsersStrings.ShowExtraKudosuEntryEmpty) diff --git a/osu.Game/Overlays/Profile/Sections/KudosuSection.cs b/osu.Game/Overlays/Profile/Sections/KudosuSection.cs index 517b4d92cf..26cf78c537 100644 --- a/osu.Game/Overlays/Profile/Sections/KudosuSection.cs +++ b/osu.Game/Overlays/Profile/Sections/KudosuSection.cs @@ -10,7 +10,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Sections { - public class KudosuSection : ProfileSection + public partial class KudosuSection : ProfileSection { public override LocalisableString Title => UsersStrings.ShowExtraKudosuTitle; diff --git a/osu.Game/Overlays/Profile/Sections/MedalsSection.cs b/osu.Game/Overlays/Profile/Sections/MedalsSection.cs index a458bc4873..a511dc95a0 100644 --- a/osu.Game/Overlays/Profile/Sections/MedalsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/MedalsSection.cs @@ -8,7 +8,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Sections { - public class MedalsSection : ProfileSection + public partial class MedalsSection : ProfileSection { public override LocalisableString Title => UsersStrings.ShowExtraMedalsTitle; diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs index 8ed1dc3676..530391466a 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedProfileSubsection.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Sections { - public abstract class PaginatedProfileSubsection : ProfileSubsection + public abstract partial class PaginatedProfileSubsection : ProfileSubsection { /// /// The number of items displayed per page. diff --git a/osu.Game/Overlays/Profile/Sections/ProfileItemContainer.cs b/osu.Game/Overlays/Profile/Sections/ProfileItemContainer.cs index 392e35ac05..c81a08fa20 100644 --- a/osu.Game/Overlays/Profile/Sections/ProfileItemContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/ProfileItemContainer.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Profile.Sections { - public class ProfileItemContainer : Container + public partial class ProfileItemContainer : Container { private const int hover_duration = 200; diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs index 8e43519a17..9d88645c9a 100644 --- a/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs +++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsection.cs @@ -13,7 +13,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Profile.Sections { - public abstract class ProfileSubsection : FillFlowContainer + public abstract partial class ProfileSubsection : FillFlowContainer { protected readonly Bindable User = new Bindable(); diff --git a/osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.cs b/osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.cs index f2770d81cd..598ac19059 100644 --- a/osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.cs +++ b/osu.Game/Overlays/Profile/Sections/ProfileSubsectionHeader.cs @@ -17,7 +17,7 @@ using osu.Framework.Localisation; namespace osu.Game.Overlays.Profile.Sections { - public class ProfileSubsectionHeader : CompositeDrawable, IHasCurrentValue + public partial class ProfileSubsectionHeader : CompositeDrawable, IHasCurrentValue { private readonly BindableWithCurrent current = new BindableWithCurrent(); diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index fda2db7acc..f1f3ecd4fb 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -25,7 +25,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Sections.Ranks { - public class DrawableProfileScore : CompositeDrawable + public partial class DrawableProfileScore : CompositeDrawable { private const int height = 40; private const int performance_width = 100; @@ -258,7 +258,7 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks }; } - private class ScoreBeatmapMetadataContainer : BeatmapMetadataContainer + private partial class ScoreBeatmapMetadataContainer : BeatmapMetadataContainer { public ScoreBeatmapMetadataContainer(IBeatmapInfo beatmapInfo) : base(beatmapInfo) diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs index 8c46f10ba2..f04d7d9733 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Overlays.Profile.Sections.Ranks { - public class DrawableProfileWeightedScore : DrawableProfileScore + public partial class DrawableProfileWeightedScore : DrawableProfileScore { private readonly double weight; diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs index 2564692c87..38fac075fb 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/PaginatedScoreContainer.cs @@ -17,7 +17,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Ranks { - public class PaginatedScoreContainer : PaginatedProfileSubsection + public partial class PaginatedScoreContainer : PaginatedProfileSubsection { private readonly ScoreType type; diff --git a/osu.Game/Overlays/Profile/Sections/RanksSection.cs b/osu.Game/Overlays/Profile/Sections/RanksSection.cs index 581b6e1139..ca41bff2f9 100644 --- a/osu.Game/Overlays/Profile/Sections/RanksSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RanksSection.cs @@ -10,7 +10,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Sections { - public class RanksSection : ProfileSection + public partial class RanksSection : ProfileSection { public override LocalisableString Title => UsersStrings.ShowExtraTopRanksTitle; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs index 6b71ae73e3..4a8b020e33 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/DrawableRecentActivity.cs @@ -19,7 +19,7 @@ using osu.Game.Rulesets; namespace osu.Game.Overlays.Profile.Sections.Recent { - public class DrawableRecentActivity : CompositeDrawable + public partial class DrawableRecentActivity : CompositeDrawable { private const int font_size = 14; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs index e3072f3420..5eeed24469 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/MedalIcon.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Textures; namespace osu.Game.Overlays.Profile.Sections.Recent { [LongRunningLoad] - public class MedalIcon : Container + public partial class MedalIcon : Container { private readonly string slug; private readonly Sprite sprite; diff --git a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs index 2878e0e940..b07dfc154f 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/PaginatedRecentActivityContainer.cs @@ -16,7 +16,7 @@ using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; namespace osu.Game.Overlays.Profile.Sections.Recent { - public class PaginatedRecentActivityContainer : PaginatedProfileSubsection + public partial class PaginatedRecentActivityContainer : PaginatedProfileSubsection { public PaginatedRecentActivityContainer(Bindable user) : base(user, missingText: EventsStrings.Empty) diff --git a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs index c55eedd1ed..8c40c6c7a5 100644 --- a/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs +++ b/osu.Game/Overlays/Profile/Sections/Recent/RecentActivityIcon.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Profile.Sections.Recent { - public class RecentActivityIcon : Container + public partial class RecentActivityIcon : Container { private readonly SpriteIcon icon; private readonly APIRecentActivity activity; diff --git a/osu.Game/Overlays/Profile/Sections/RecentSection.cs b/osu.Game/Overlays/Profile/Sections/RecentSection.cs index c20594f974..f2ebf81504 100644 --- a/osu.Game/Overlays/Profile/Sections/RecentSection.cs +++ b/osu.Game/Overlays/Profile/Sections/RecentSection.cs @@ -9,7 +9,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Profile.Sections { - public class RecentSection : ProfileSection + public partial class RecentSection : ProfileSection { public override LocalisableString Title => UsersStrings.ShowExtraRecentActivityTitle; diff --git a/osu.Game/Overlays/Profile/UserGraph.cs b/osu.Game/Overlays/Profile/UserGraph.cs index a8a4de68ff..fa9cbe0449 100644 --- a/osu.Game/Overlays/Profile/UserGraph.cs +++ b/osu.Game/Overlays/Profile/UserGraph.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.Profile /// /// Type of data to be used for X-axis of the graph. /// Type of data to be used for Y-axis of the graph. - public abstract class UserGraph : Container, IHasCustomTooltip + public abstract partial class UserGraph : Container, IHasCustomTooltip { protected const float FADE_DURATION = 150; @@ -136,7 +136,7 @@ namespace osu.Game.Overlays.Profile protected abstract UserGraphTooltipContent GetTooltipContent(TKey key, TValue value); - protected class UserLineGraph : LineGraph + protected partial class UserLineGraph : LineGraph { private readonly CircularContainer movingBall; private readonly Container bar; @@ -207,7 +207,7 @@ namespace osu.Game.Overlays.Profile } } - private class UserGraphTooltip : VisibilityContainer, ITooltip + private partial class UserGraphTooltip : VisibilityContainer, ITooltip { protected readonly OsuSpriteText Label, Counter, BottomText; private readonly Box background; diff --git a/osu.Game/Overlays/Rankings/CountryFilter.cs b/osu.Game/Overlays/Rankings/CountryFilter.cs index 9376bafdff..e27fa7c7bd 100644 --- a/osu.Game/Overlays/Rankings/CountryFilter.cs +++ b/osu.Game/Overlays/Rankings/CountryFilter.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Overlays.Rankings { - public class CountryFilter : CompositeDrawable, IHasCurrentValue + public partial class CountryFilter : CompositeDrawable, IHasCurrentValue { private const int duration = 200; private const int height = 70; diff --git a/osu.Game/Overlays/Rankings/CountryPill.cs b/osu.Game/Overlays/Rankings/CountryPill.cs index ee4c4f08af..5efa9d12f0 100644 --- a/osu.Game/Overlays/Rankings/CountryPill.cs +++ b/osu.Game/Overlays/Rankings/CountryPill.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Rankings { - public class CountryPill : CompositeDrawable, IHasCurrentValue + public partial class CountryPill : CompositeDrawable, IHasCurrentValue { private const int duration = 200; @@ -140,7 +140,7 @@ namespace osu.Game.Overlays.Rankings countryName.Text = country.NewValue.GetDescription(); } - private class CloseButton : OsuHoverContainer + private partial class CloseButton : OsuHoverContainer { private readonly SpriteIcon icon; diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs index 936545bd49..3e0f780eeb 100644 --- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs +++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs @@ -12,7 +12,7 @@ using osu.Game.Users; namespace osu.Game.Overlays.Rankings { - public class RankingsOverlayHeader : TabControlOverlayHeader + public partial class RankingsOverlayHeader : TabControlOverlayHeader { public Bindable Ruleset => rulesetSelector.Current; @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Rankings protected override Drawable CreateBackground() => new OverlayHeaderBackground("Headers/rankings"); - private class RankingsTitle : OverlayTitle + private partial class RankingsTitle : OverlayTitle { public RankingsTitle() { diff --git a/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs b/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs index 905c0fae65..9e73c3adb0 100644 --- a/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs +++ b/osu.Game/Overlays/Rankings/RankingsSortTabControl.cs @@ -9,7 +9,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Rankings { - public class RankingsSortTabControl : OverlaySortTabControl + public partial class RankingsSortTabControl : OverlaySortTabControl { public RankingsSortTabControl() { diff --git a/osu.Game/Overlays/Rankings/SpotlightSelector.cs b/osu.Game/Overlays/Rankings/SpotlightSelector.cs index 234b91de66..31273e3b01 100644 --- a/osu.Game/Overlays/Rankings/SpotlightSelector.cs +++ b/osu.Game/Overlays/Rankings/SpotlightSelector.cs @@ -24,7 +24,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Rankings { - public class SpotlightSelector : CompositeDrawable, IHasCurrentValue + public partial class SpotlightSelector : CompositeDrawable, IHasCurrentValue { private readonly BindableWithCurrent current = new BindableWithCurrent(); public readonly Bindable Sort = new Bindable(); @@ -133,7 +133,7 @@ namespace osu.Game.Overlays.Rankings private LocalisableString dateToString(DateTimeOffset date) => date.ToLocalisableString(@"yyyy-MM-dd"); - private class InfoColumn : FillFlowContainer + private partial class InfoColumn : FillFlowContainer { public LocalisableString Value { @@ -175,7 +175,7 @@ namespace osu.Game.Overlays.Rankings } } - private class SpotlightsDropdown : OsuDropdown + private partial class SpotlightsDropdown : OsuDropdown { private OsuDropdownMenu menu; @@ -192,7 +192,7 @@ namespace osu.Game.Overlays.Rankings Padding = new MarginPadding { Vertical = 20 }; } - private class SpotlightsDropdownHeader : OsuDropdownHeader + private partial class SpotlightsDropdownHeader : OsuDropdownHeader { public SpotlightsDropdownHeader() { diff --git a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs index c23b9711dd..8a1b929753 100644 --- a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs +++ b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Overlays.Rankings { - public class SpotlightsLayout : CompositeDrawable + public partial class SpotlightsLayout : CompositeDrawable { public readonly Bindable Ruleset = new Bindable(); diff --git a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs index a6f0c7a123..3be5cc994c 100644 --- a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs @@ -17,7 +17,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Rankings.Tables { - public class CountriesTable : RankingsTable + public partial class CountriesTable : RankingsTable { public CountriesTable(int page, IReadOnlyList rankings) : base(page, rankings) @@ -66,7 +66,7 @@ namespace osu.Game.Overlays.Rankings.Tables } }; - private class CountryName : LinkFlowContainer + private partial class CountryName : LinkFlowContainer { [Resolved(canBeNull: true)] private RankingsOverlay rankings { get; set; } diff --git a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs index a77546d83f..19ed3afdca 100644 --- a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs @@ -12,7 +12,7 @@ using osu.Game.Users; namespace osu.Game.Overlays.Rankings.Tables { - public class PerformanceTable : UserBasedTable + public partial class PerformanceTable : UserBasedTable { public PerformanceTable(int page, IReadOnlyList rankings) : base(page, rankings) diff --git a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs index 073bf86a7a..affd9a2c44 100644 --- a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs @@ -20,7 +20,7 @@ using osu.Framework.Localisation; namespace osu.Game.Overlays.Rankings.Tables { - public abstract class RankingsTable : TableContainer + public abstract partial class RankingsTable : TableContainer { protected const int TEXT_SIZE = 12; private const float horizontal_inset = 20; @@ -119,7 +119,7 @@ namespace osu.Game.Overlays.Rankings.Tables public virtual HeaderText CreateHeaderText() => new HeaderText(Header, Highlighted); } - protected class HeaderText : OsuSpriteText + protected partial class HeaderText : OsuSpriteText { private readonly bool isHighlighted; @@ -140,7 +140,7 @@ namespace osu.Game.Overlays.Rankings.Tables } } - protected class RowText : OsuSpriteText + protected partial class RowText : OsuSpriteText { public RowText() { @@ -149,7 +149,7 @@ namespace osu.Game.Overlays.Rankings.Tables } } - protected class ColouredRowText : RowText + protected partial class ColouredRowText : RowText { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) diff --git a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs index 71c78baf3c..0da3fba8cc 100644 --- a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs @@ -12,7 +12,7 @@ using osu.Game.Users; namespace osu.Game.Overlays.Rankings.Tables { - public class ScoresTable : UserBasedTable + public partial class ScoresTable : UserBasedTable { public ScoresTable(int page, IReadOnlyList rankings) : base(page, rankings) diff --git a/osu.Game/Overlays/Rankings/Tables/TableRowBackground.cs b/osu.Game/Overlays/Rankings/Tables/TableRowBackground.cs index fd9f6da749..54ec45f4ff 100644 --- a/osu.Game/Overlays/Rankings/Tables/TableRowBackground.cs +++ b/osu.Game/Overlays/Rankings/Tables/TableRowBackground.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Rankings.Tables { - public class TableRowBackground : CompositeDrawable + public partial class TableRowBackground : CompositeDrawable { private const int fade_duration = 100; diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index 48185e6083..4d25065578 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -17,7 +17,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Rankings.Tables { - public abstract class UserBasedTable : RankingsTable + public abstract partial class UserBasedTable : RankingsTable { protected UserBasedTable(int page, IReadOnlyList rankings) : base(page, rankings) @@ -98,7 +98,7 @@ namespace osu.Game.Overlays.Rankings.Tables public override HeaderText CreateHeaderText() => new GradeHeaderText(Header, Highlighted); } - private class GradeHeaderText : HeaderText + private partial class GradeHeaderText : HeaderText { public GradeHeaderText(LocalisableString text, bool isHighlighted) : base(text, isHighlighted) diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index 586b883604..f25bf80b6a 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.Rankings.Tables; namespace osu.Game.Overlays { - public class RankingsOverlay : TabbableOnlineOverlay + public partial class RankingsOverlay : TabbableOnlineOverlay { protected Bindable Country => Header.Country; diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index a5da696f58..24dec44588 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Overlays { - public class RestoreDefaultValueButton : OsuButton, IHasTooltip, IHasCurrentValue + public partial class RestoreDefaultValueButton : OsuButton, IHasTooltip, IHasCurrentValue { public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; diff --git a/osu.Game/Overlays/Settings/DangerousSettingsButton.cs b/osu.Game/Overlays/Settings/DangerousSettingsButton.cs index bf7c9ccf2b..248b4d339a 100644 --- a/osu.Game/Overlays/Settings/DangerousSettingsButton.cs +++ b/osu.Game/Overlays/Settings/DangerousSettingsButton.cs @@ -11,7 +11,7 @@ namespace osu.Game.Overlays.Settings /// /// A with pink colours to mark dangerous/destructive actions. /// - public class DangerousSettingsButton : SettingsButton + public partial class DangerousSettingsButton : SettingsButton { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Overlays/Settings/OutlinedTextBox.cs b/osu.Game/Overlays/Settings/OutlinedTextBox.cs index de7fe75060..56b662ecf0 100644 --- a/osu.Game/Overlays/Settings/OutlinedTextBox.cs +++ b/osu.Game/Overlays/Settings/OutlinedTextBox.cs @@ -12,7 +12,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Settings { - public class OutlinedTextBox : OsuTextBox + public partial class OutlinedTextBox : OsuTextBox { private const float border_thickness = 3; diff --git a/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs b/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs index 76e75a5b3c..1bc2c08352 100644 --- a/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/RulesetSettingsSubsection.cs @@ -14,7 +14,7 @@ namespace osu.Game.Overlays.Settings /// A which provides subclasses with the /// from the 's . /// - public abstract class RulesetSettingsSubsection : SettingsSubsection + public abstract partial class RulesetSettingsSubsection : SettingsSubsection { private readonly Ruleset ruleset; diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index 9b53d62272..a71f2a6d29 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -14,7 +14,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Audio { - public class AudioDevicesSettings : SettingsSubsection + public partial class AudioDevicesSettings : SettingsSubsection { protected override LocalisableString Header => AudioSettingsStrings.AudioDevicesHeader; @@ -77,11 +77,11 @@ namespace osu.Game.Overlays.Settings.Sections.Audio } } - private class AudioDeviceSettingsDropdown : SettingsDropdown + private partial class AudioDeviceSettingsDropdown : SettingsDropdown { protected override OsuDropdown CreateDropdown() => new AudioDeviceDropdownControl(); - private class AudioDeviceDropdownControl : DropdownControl + private partial class AudioDeviceDropdownControl : DropdownControl { protected override LocalisableString GenerateItemText(string item) => string.IsNullOrEmpty(item) ? CommonStrings.Default : base.GenerateItemText(item); diff --git a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs index d25e9490b7..1755c12f94 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs @@ -14,7 +14,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Audio { - public class OffsetSettings : SettingsSubsection + public partial class OffsetSettings : SettingsSubsection { protected override LocalisableString Header => AudioSettingsStrings.OffsetHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs index 8f188f04d9..a83707b5f6 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs @@ -13,7 +13,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Audio { - public class VolumeSettings : SettingsSubsection + public partial class VolumeSettings : SettingsSubsection { protected override LocalisableString Header => AudioSettingsStrings.VolumeHeader; @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio }; } - private class VolumeAdjustSlider : SettingsSlider + private partial class VolumeAdjustSlider : SettingsSlider { protected override Drawable CreateControl() { diff --git a/osu.Game/Overlays/Settings/Sections/AudioSection.cs b/osu.Game/Overlays/Settings/Sections/AudioSection.cs index 70c74cd77c..542d5bc8fd 100644 --- a/osu.Game/Overlays/Settings/Sections/AudioSection.cs +++ b/osu.Game/Overlays/Settings/Sections/AudioSection.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays.Settings.Sections.Audio; namespace osu.Game.Overlays.Settings.Sections { - public class AudioSection : SettingsSection + public partial class AudioSection : SettingsSection { public override LocalisableString Header => AudioSettingsStrings.AudioSectionHeader; diff --git a/osu.Game/Overlays/Settings/Sections/DebugSection.cs b/osu.Game/Overlays/Settings/Sections/DebugSection.cs index a02e28d33a..2594962314 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSection.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSection.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays.Settings.Sections.DebugSettings; namespace osu.Game.Overlays.Settings.Sections { - public class DebugSection : SettingsSection + public partial class DebugSection : SettingsSection { public override LocalisableString Header => DebugSettingsStrings.DebugSectionHeader; diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs index e79d27ad2a..6c2bfedba0 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/GeneralSettings.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.Utility; namespace osu.Game.Overlays.Settings.Sections.DebugSettings { - public class GeneralSettings : SettingsSubsection + public partial class GeneralSettings : SettingsSubsection { protected override LocalisableString Header => DebugSettingsStrings.GeneralHeader; diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs index 3afb060e49..bf0a48d2c2 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs @@ -16,7 +16,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.DebugSettings { - public class MemorySettings : SettingsSubsection + public partial class MemorySettings : SettingsSubsection { protected override LocalisableString Header => DebugSettingsStrings.MemoryHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs index d369c4470b..00eb6fa62c 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/AudioSettings.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay { - public class AudioSettings : SettingsSubsection + public partial class AudioSettings : SettingsSubsection { protected override LocalisableString Header => GameplaySettingsStrings.AudioHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BackgroundSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BackgroundSettings.cs index cc224a4f7f..09e5f3e163 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BackgroundSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BackgroundSettings.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay { - public class BackgroundSettings : SettingsSubsection + public partial class BackgroundSettings : SettingsSubsection { protected override LocalisableString Header => GameplaySettingsStrings.BackgroundHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs index 14ff6ac2b5..e8db5fe58a 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/BeatmapSettings.cs @@ -12,7 +12,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay { - public class BeatmapSettings : SettingsSubsection + public partial class BeatmapSettings : SettingsSubsection { protected override LocalisableString Header => GameplaySettingsStrings.BeatmapHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index c16ee39191..96d458a942 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Overlays.Settings.Sections.Gameplay { - public class GeneralSettings : SettingsSubsection + public partial class GeneralSettings : SettingsSubsection { protected override LocalisableString Header => GameplaySettingsStrings.GeneralHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs index 88a27840d8..c67c14bb43 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/HUDSettings.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay { - public class HUDSettings : SettingsSubsection + public partial class HUDSettings : SettingsSubsection { protected override LocalisableString Header => GameplaySettingsStrings.HUDHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs index ac59a6c0ed..4d027cf8cb 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/InputSettings.cs @@ -12,7 +12,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay { - public class InputSettings : SettingsSubsection + public partial class InputSettings : SettingsSubsection { protected override LocalisableString Header => GameplaySettingsStrings.InputHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs index 53f7f52212..69e24bc616 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs @@ -12,7 +12,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay { - public class ModsSettings : SettingsSubsection + public partial class ModsSettings : SettingsSubsection { protected override LocalisableString Header => GameplaySettingsStrings.ModsHeader; diff --git a/osu.Game/Overlays/Settings/Sections/GameplaySection.cs b/osu.Game/Overlays/Settings/Sections/GameplaySection.cs index 48e76bfeb7..ae6145752b 100644 --- a/osu.Game/Overlays/Settings/Sections/GameplaySection.cs +++ b/osu.Game/Overlays/Settings/Sections/GameplaySection.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays.Settings.Sections.Gameplay; namespace osu.Game.Overlays.Settings.Sections { - public class GameplaySection : SettingsSection + public partial class GameplaySection : SettingsSection { public override LocalisableString Header => GameplaySettingsStrings.GameplaySectionHeader; diff --git a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs index b7e3bd90b0..a4ec919658 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs @@ -12,7 +12,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.General { - public class LanguageSettings : SettingsSubsection + public partial class LanguageSettings : SettingsSubsection { private SettingsDropdown languageSelection = null!; private Bindable frameworkLocale = null!; diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index d97cf699e5..55be06c765 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -19,7 +19,7 @@ using osu.Game.Updater; namespace osu.Game.Overlays.Settings.Sections.General { - public class UpdateSettings : SettingsSubsection + public partial class UpdateSettings : SettingsSubsection { [Resolved(CanBeNull = true)] private UpdateManager updateManager { get; set; } diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 59cbd8cd5a..c62d44fd30 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Settings.Sections.General; namespace osu.Game.Overlays.Settings.Sections { - public class GeneralSection : SettingsSection + public partial class GeneralSection : SettingsSection { [Resolved(CanBeNull = true)] private FirstRunSetupOverlay firstRunSetupOverlay { get; set; } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 7f0bded806..63689961e6 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -25,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Settings.Sections.Graphics { - public class LayoutSettings : SettingsSubsection + public partial class LayoutSettings : SettingsSubsection { protected override LocalisableString Header => GraphicsSettingsStrings.LayoutHeader; @@ -324,7 +324,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics base.Dispose(isDisposing); } - private class ScalingPreview : ScalingContainer + private partial class ScalingPreview : ScalingContainer { public ScalingPreview() { @@ -337,16 +337,16 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } } - private class UIScaleSlider : OsuSliderBar + private partial class UIScaleSlider : OsuSliderBar { public override LocalisableString TooltipText => base.TooltipText + "x"; } - private class DisplaySettingsDropdown : SettingsDropdown + private partial class DisplaySettingsDropdown : SettingsDropdown { protected override OsuDropdown CreateDropdown() => new DisplaySettingsDropdownControl(); - private class DisplaySettingsDropdownControl : DropdownControl + private partial class DisplaySettingsDropdownControl : DropdownControl { protected override LocalisableString GenerateItemText(Display item) { @@ -355,11 +355,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics } } - private class ResolutionSettingsDropdown : SettingsDropdown + private partial class ResolutionSettingsDropdown : SettingsDropdown { protected override OsuDropdown CreateDropdown() => new ResolutionDropdownControl(); - private class ResolutionDropdownControl : DropdownControl + private partial class ResolutionDropdownControl : DropdownControl { protected override LocalisableString GenerateItemText(Size item) { diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs index 2e15172e46..775606caf0 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs @@ -13,7 +13,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Graphics { - public class RendererSettings : SettingsSubsection + public partial class RendererSettings : SettingsSubsection { protected override LocalisableString Header => GraphicsSettingsStrings.RendererHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/ScreenshotSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/ScreenshotSettings.cs index 7f88cc23d2..8054b27de5 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/ScreenshotSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/ScreenshotSettings.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Graphics { - public class ScreenshotSettings : SettingsSubsection + public partial class ScreenshotSettings : SettingsSubsection { protected override LocalisableString Header => GraphicsSettingsStrings.Screenshots; diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs index 56d0a6421b..2e0bbe3c16 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/VideoSettings.cs @@ -13,7 +13,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Graphics { - public class VideoSettings : SettingsSubsection + public partial class VideoSettings : SettingsSubsection { protected override LocalisableString Header => GraphicsSettingsStrings.VideoHeader; diff --git a/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs b/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs index e094e0e051..323cdaf14d 100644 --- a/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays.Settings.Sections.Graphics; namespace osu.Game.Overlays.Settings.Sections { - public class GraphicsSection : SettingsSection + public partial class GraphicsSection : SettingsSection { public override LocalisableString Header => GraphicsSettingsStrings.GraphicsSectionHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs index 2f4840a384..dbd7949206 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/BindingSettings.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Input { - public class BindingSettings : SettingsSubsection + public partial class BindingSettings : SettingsSubsection { protected override LocalisableString Header => BindingSettingsStrings.ShortcutAndGameplayBindings; diff --git a/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs b/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs index 7ab10a3c3a..862bbbede0 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs @@ -9,7 +9,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Input { - public class GlobalKeyBindingsSection : SettingsSection + public partial class GlobalKeyBindingsSection : SettingsSection { public override Drawable CreateIcon() => new SpriteIcon { @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input Add(new EditorKeyBindingsSubsection(manager)); } - private class DefaultBindingsSubsection : KeyBindingsSubsection + private partial class DefaultBindingsSubsection : KeyBindingsSubsection { protected override LocalisableString Header => string.Empty; @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - private class OverlayBindingsSubsection : KeyBindingsSubsection + private partial class OverlayBindingsSubsection : KeyBindingsSubsection { protected override LocalisableString Header => InputSettingsStrings.OverlaysSection; @@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - private class SongSelectKeyBindingSubsection : KeyBindingsSubsection + private partial class SongSelectKeyBindingSubsection : KeyBindingsSubsection { protected override LocalisableString Header => InputSettingsStrings.SongSelectSection; @@ -61,7 +61,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - private class InGameKeyBindingsSubsection : KeyBindingsSubsection + private partial class InGameKeyBindingsSubsection : KeyBindingsSubsection { protected override LocalisableString Header => InputSettingsStrings.InGameSection; @@ -72,7 +72,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - private class AudioControlKeyBindingsSubsection : KeyBindingsSubsection + private partial class AudioControlKeyBindingsSubsection : KeyBindingsSubsection { protected override LocalisableString Header => InputSettingsStrings.AudioSection; @@ -83,7 +83,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - private class EditorKeyBindingsSubsection : KeyBindingsSubsection + private partial class EditorKeyBindingsSubsection : KeyBindingsSubsection { protected override LocalisableString Header => InputSettingsStrings.EditorSection; diff --git a/osu.Game/Overlays/Settings/Sections/Input/JoystickSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/JoystickSettings.cs index 34be846595..8455c09633 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/JoystickSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/JoystickSettings.cs @@ -12,7 +12,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Input { - public class JoystickSettings : SettingsSubsection + public partial class JoystickSettings : SettingsSubsection { protected override LocalisableString Header => JoystickSettingsStrings.JoystickGamepad; diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingPanel.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingPanel.cs index 0830241f2b..30429c84f0 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingPanel.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingPanel.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets; namespace osu.Game.Overlays.Settings.Sections.Input { - public class KeyBindingPanel : SettingsSubPanel + public partial class KeyBindingPanel : SettingsSubPanel { protected override Drawable CreateHeader() => new SettingsHeader(InputSettingsStrings.KeyBindingPanelHeader, InputSettingsStrings.KeyBindingPanelDescription); diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 25ab8cfad2..034e142e49 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -31,7 +31,7 @@ using osuTK.Input; namespace osu.Game.Overlays.Settings.Sections.Input { - public class KeyBindingRow : Container, IFilterable + public partial class KeyBindingRow : Container, IFilterable { /// /// Invoked when the binding of this row is updated with a change being written. @@ -446,7 +446,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input isDefault.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults); } - private class CancelButton : TriangleButton + private partial class CancelButton : TriangleButton { public CancelButton() { @@ -455,7 +455,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - public class ClearButton : DangerousTriangleButton + public partial class ClearButton : DangerousTriangleButton { public ClearButton() { @@ -464,7 +464,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - public class KeyButton : Container + public partial class KeyButton : Container { public readonly RealmKeyBinding KeyBinding; diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs index 98d569948f..d6d4abfa92 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Overlays.Settings.Sections.Input { - public abstract class KeyBindingsSubsection : SettingsSubsection + public abstract partial class KeyBindingsSubsection : SettingsSubsection { /// /// After a successful binding, automatically select the next binding row to make quickly @@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - public class ResetButton : DangerousSettingsButton + public partial class ResetButton : DangerousSettingsButton { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs index b815239c9f..5a6338dc09 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs @@ -17,7 +17,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Input { - public class MouseSettings : SettingsSubsection + public partial class MouseSettings : SettingsSubsection { private readonly MouseHandler mouseHandler; @@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input }, true); } - public class SensitivitySetting : SettingsSlider + public partial class SensitivitySetting : SettingsSlider { public SensitivitySetting() { @@ -135,7 +135,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } } - public class SensitivitySlider : OsuSliderBar + public partial class SensitivitySlider : OsuSliderBar { public override LocalisableString TooltipText => Current.Disabled ? MouseSettingsStrings.EnableHighPrecisionForSensitivityAdjust : $"{base.TooltipText}x"; } diff --git a/osu.Game/Overlays/Settings/Sections/Input/RotationPresetButtons.cs b/osu.Game/Overlays/Settings/Sections/Input/RotationPresetButtons.cs index 2172dc175e..a66e44f8cb 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/RotationPresetButtons.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/RotationPresetButtons.cs @@ -15,7 +15,7 @@ using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Overlays.Settings.Sections.Input { - internal class RotationPresetButtons : CompositeDrawable + internal partial class RotationPresetButtons : CompositeDrawable { public new MarginPadding Padding { @@ -86,7 +86,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input }, true); } - public class RotationButton : RoundedButton + public partial class RotationButton : RoundedButton { [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs b/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs index 6f3127a377..dcdb15fc19 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets; namespace osu.Game.Overlays.Settings.Sections.Input { - public class RulesetBindingsSection : SettingsSection + public partial class RulesetBindingsSection : SettingsSection { public override Drawable CreateIcon() => ruleset?.CreateInstance().CreateIcon() ?? new SpriteIcon { diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index 708cd5900a..6f7faf535b 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Settings.Sections.Input { - public class TabletAreaSelection : CompositeDrawable + public partial class TabletAreaSelection : CompositeDrawable { public bool IsWithinBounds { get; private set; } diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index b6efa00cdb..27612738df 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -21,7 +21,7 @@ using osu.Game.Online.Chat; namespace osu.Game.Overlays.Settings.Sections.Input { - public class TabletSettings : SettingsSubsection + public partial class TabletSettings : SettingsSubsection { public TabletAreaSelection AreaSelection { get; private set; } diff --git a/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs index a6f6c28463..d00de7f549 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/VariantBindingsSubsection.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets; namespace osu.Game.Overlays.Settings.Sections.Input { - public class VariantBindingsSubsection : KeyBindingsSubsection + public partial class VariantBindingsSubsection : KeyBindingsSubsection { protected override bool AutoAdvanceTarget => true; diff --git a/osu.Game/Overlays/Settings/Sections/InputSection.cs b/osu.Game/Overlays/Settings/Sections/InputSection.cs index 4d75537f6b..0647068da7 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSection.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays.Settings.Sections.Input; namespace osu.Game.Overlays.Settings.Sections { - public class InputSection : SettingsSection + public partial class InputSection : SettingsSection { private readonly KeyBindingPanel keyConfig; @@ -47,7 +47,7 @@ namespace osu.Game.Overlays.Settings.Sections } } - public class HandlerSection : SettingsSubsection + public partial class HandlerSection : SettingsSubsection { private readonly InputHandler handler; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs index beae5a6aad..9c0b86c862 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/BeatmapSettings.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class BeatmapSettings : SettingsSubsection + public partial class BeatmapSettings : SettingsSubsection { protected override LocalisableString Header => CommonStrings.Beatmaps; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs index 17fef37e40..4da5aaf492 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/CollectionsSettings.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays.Notifications; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class CollectionsSettings : SettingsSubsection + public partial class CollectionsSettings : SettingsSubsection { protected override LocalisableString Header => CommonStrings.Collections; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs index 1c9a758c6f..48ad6e2617 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs @@ -20,7 +20,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public abstract class DirectorySelectScreen : OsuScreen + public abstract partial class DirectorySelectScreen : OsuScreen { private TriangleButton selectionButton; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs index 19e6f83dac..948d646e3d 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassDeleteConfirmationDialog.cs @@ -6,7 +6,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class MassDeleteConfirmationDialog : DeleteConfirmationDialog + public partial class MassDeleteConfirmationDialog : DeleteConfirmationDialog { public MassDeleteConfirmationDialog(Action deleteAction) { diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs index fc8c9d497b..6312e09b3e 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MassVideoDeleteConfirmationDialog.cs @@ -5,7 +5,7 @@ using System; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class MassVideoDeleteConfirmationDialog : MassDeleteConfirmationDialog + public partial class MassVideoDeleteConfirmationDialog : MassDeleteConfirmationDialog { public MassVideoDeleteConfirmationDialog(Action deleteAction) : base(deleteAction) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs index 158e1a8aa0..5b24460ac2 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationRunScreen.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class MigrationRunScreen : OsuScreen + public partial class MigrationRunScreen : OsuScreen { private readonly DirectoryInfo destination; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs index 5de33fdd55..80bf292057 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/MigrationSelectScreen.cs @@ -17,7 +17,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class MigrationSelectScreen : DirectorySelectScreen + public partial class MigrationSelectScreen : DirectorySelectScreen { [Resolved] private Storage storage { get; set; } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs index 51f6e1bf60..ba45d9c896 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ModPresetSettings.cs @@ -14,7 +14,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class ModPresetSettings : SettingsSubsection + public partial class ModPresetSettings : SettingsSubsection { protected override LocalisableString Header => CommonStrings.ModPresets; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs index eb2d3171ea..1f09854843 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/ScoreSettings.cs @@ -10,7 +10,7 @@ using osu.Game.Scoring; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class ScoreSettings : SettingsSubsection + public partial class ScoreSettings : SettingsSubsection { protected override LocalisableString Header => CommonStrings.Scores; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs index 93c65513b7..e4185fe6c2 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/SkinSettings.cs @@ -10,7 +10,7 @@ using osu.Game.Skinning; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class SkinSettings : SettingsSubsection + public partial class SkinSettings : SettingsSubsection { protected override LocalisableString Header => CommonStrings.Skins; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs index 8aff4520b5..633bf8c5a5 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectoryLocationDialog.cs @@ -12,7 +12,7 @@ using osu.Game.Screens; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class StableDirectoryLocationDialog : PopupDialog + public partial class StableDirectoryLocationDialog : PopupDialog { [Resolved] private IPerformFromScreenRunner performer { get; set; } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs index 047d589689..048f3ee683 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs @@ -11,7 +11,7 @@ using osu.Framework.Screens; namespace osu.Game.Overlays.Settings.Sections.Maintenance { - public class StableDirectorySelectScreen : DirectorySelectScreen + public partial class StableDirectorySelectScreen : DirectorySelectScreen { private readonly TaskCompletionSource taskCompletionSource; diff --git a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs index 4be6d1653b..bb0a952164 100644 --- a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs +++ b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs @@ -9,7 +9,7 @@ using osu.Game.Overlays.Settings.Sections.Maintenance; namespace osu.Game.Overlays.Settings.Sections { - public class MaintenanceSection : SettingsSection + public partial class MaintenanceSection : SettingsSection { public override LocalisableString Header => MaintenanceSettingsStrings.MaintenanceSectionHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs index 529f1b5ee4..dc6743c042 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Online { - public class AlertsAndPrivacySettings : SettingsSubsection + public partial class AlertsAndPrivacySettings : SettingsSubsection { protected override LocalisableString Header => OnlineSettingsStrings.AlertsAndPrivacyHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs index 17228d6359..33748d0f5e 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Online { - public class IntegrationSettings : SettingsSubsection + public partial class IntegrationSettings : SettingsSubsection { protected override LocalisableString Header => OnlineSettingsStrings.IntegrationsHeader; diff --git a/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs index ba707e2145..d0707a434a 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Online { - public class WebSettings : SettingsSubsection + public partial class WebSettings : SettingsSubsection { protected override LocalisableString Header => OnlineSettingsStrings.WebHeader; diff --git a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs index feb281f1b8..775c6f9839 100644 --- a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs +++ b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays.Settings.Sections.Online; namespace osu.Game.Overlays.Settings.Sections { - public class OnlineSection : SettingsSection + public partial class OnlineSection : SettingsSection { public override LocalisableString Header => OnlineSettingsStrings.OnlineSectionHeader; diff --git a/osu.Game/Overlays/Settings/Sections/RulesetSection.cs b/osu.Game/Overlays/Settings/Sections/RulesetSection.cs index 6f0b3c27a0..aaad1ec4e2 100644 --- a/osu.Game/Overlays/Settings/Sections/RulesetSection.cs +++ b/osu.Game/Overlays/Settings/Sections/RulesetSection.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets; namespace osu.Game.Overlays.Settings.Sections { - public class RulesetSection : SettingsSection + public partial class RulesetSection : SettingsSection { public override LocalisableString Header => RulesetSettingsStrings.Rulesets; diff --git a/osu.Game/Overlays/Settings/Sections/SizeSlider.cs b/osu.Game/Overlays/Settings/Sections/SizeSlider.cs index 28b4cd6418..26d6147bb7 100644 --- a/osu.Game/Overlays/Settings/Sections/SizeSlider.cs +++ b/osu.Game/Overlays/Settings/Sections/SizeSlider.cs @@ -13,7 +13,7 @@ namespace osu.Game.Overlays.Settings.Sections /// /// A slider intended to show a "size" multiplier number, where 1x is 1.0. /// - public class SizeSlider : OsuSliderBar + public partial class SizeSlider : OsuSliderBar where T : struct, IEquatable, IComparable, IConvertible, IFormattable { public override LocalisableString TooltipText => Current.Value.ToString(@"0.##x", NumberFormatInfo.CurrentInfo); diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index f602b73065..826a1e7404 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -24,7 +24,7 @@ using Realms; namespace osu.Game.Overlays.Settings.Sections { - public class SkinSection : SettingsSection + public partial class SkinSection : SettingsSection { private SkinSettingsDropdown skinDropdown; @@ -123,17 +123,17 @@ namespace osu.Game.Overlays.Settings.Sections realmSubscription?.Dispose(); } - private class SkinSettingsDropdown : SettingsDropdown> + private partial class SkinSettingsDropdown : SettingsDropdown> { protected override OsuDropdown> CreateDropdown() => new SkinDropdownControl(); - private class SkinDropdownControl : DropdownControl + private partial class SkinDropdownControl : DropdownControl { protected override LocalisableString GenerateItemText(Live item) => item.ToString(); } } - public class ExportSkinButton : SettingsButton + public partial class ExportSkinButton : SettingsButton { [Resolved] private SkinManager skins { get; set; } @@ -171,7 +171,7 @@ namespace osu.Game.Overlays.Settings.Sections } } - public class DeleteSkinButton : DangerousSettingsButton + public partial class DeleteSkinButton : DangerousSettingsButton { [Resolved] private SkinManager skins { get; set; } diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs index 85cfdb33d5..2e8d005401 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs @@ -12,7 +12,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.UserInterface { - public class GeneralSettings : SettingsSubsection + public partial class GeneralSettings : SettingsSubsection { protected override LocalisableString Header => UserInterfaceStrings.GeneralHeader; diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs index 7ca45bb6b8..4577fadb01 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs @@ -14,7 +14,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Settings.Sections.UserInterface { - public class MainMenuSettings : SettingsSubsection + public partial class MainMenuSettings : SettingsSubsection { protected override LocalisableString Header => UserInterfaceStrings.MainMenuHeader; diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 708bee6fbd..8b5e0b75b7 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Mods.Input; namespace osu.Game.Overlays.Settings.Sections.UserInterface { - public class SongSelectSettings : SettingsSubsection + public partial class SongSelectSettings : SettingsSubsection { protected override LocalisableString Header => UserInterfaceStrings.SongSelectHeader; diff --git a/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs b/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs index b2711af612..0926574a54 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays.Settings.Sections.UserInterface; namespace osu.Game.Overlays.Settings.Sections { - public class UserInterfaceSection : SettingsSection + public partial class UserInterfaceSection : SettingsSection { public override LocalisableString Header => UserInterfaceStrings.UserInterfaceSectionHeader; diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index 5f2a416f58..2d7e78d17a 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -15,7 +15,7 @@ using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Overlays.Settings { - public class SettingsButton : RoundedButton, IHasTooltip + public partial class SettingsButton : RoundedButton, IHasTooltip { public SettingsButton() { diff --git a/osu.Game/Overlays/Settings/SettingsCheckbox.cs b/osu.Game/Overlays/Settings/SettingsCheckbox.cs index efe7fb6d9e..a413bcf220 100644 --- a/osu.Game/Overlays/Settings/SettingsCheckbox.cs +++ b/osu.Game/Overlays/Settings/SettingsCheckbox.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public class SettingsCheckbox : SettingsItem + public partial class SettingsCheckbox : SettingsItem { private LocalisableString labelText; diff --git a/osu.Game/Overlays/Settings/SettingsDropdown.cs b/osu.Game/Overlays/Settings/SettingsDropdown.cs index 347ef03b42..5798d02e03 100644 --- a/osu.Game/Overlays/Settings/SettingsDropdown.cs +++ b/osu.Game/Overlays/Settings/SettingsDropdown.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public class SettingsDropdown : SettingsItem + public partial class SettingsDropdown : SettingsItem { protected new OsuDropdown Control => (OsuDropdown)base.Control; @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Settings protected virtual OsuDropdown CreateDropdown() => new DropdownControl(); - protected class DropdownControl : OsuDropdown + protected partial class DropdownControl : OsuDropdown { public DropdownControl() { diff --git a/osu.Game/Overlays/Settings/SettingsEnumDropdown.cs b/osu.Game/Overlays/Settings/SettingsEnumDropdown.cs index 9408e4a9ce..62dd4f2905 100644 --- a/osu.Game/Overlays/Settings/SettingsEnumDropdown.cs +++ b/osu.Game/Overlays/Settings/SettingsEnumDropdown.cs @@ -9,12 +9,12 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public class SettingsEnumDropdown : SettingsDropdown + public partial class SettingsEnumDropdown : SettingsDropdown where T : struct, Enum { protected override OsuDropdown CreateDropdown() => new DropdownControl(); - protected new class DropdownControl : OsuEnumDropdown + protected new partial class DropdownControl : OsuEnumDropdown { public DropdownControl() { diff --git a/osu.Game/Overlays/Settings/SettingsFooter.cs b/osu.Game/Overlays/Settings/SettingsFooter.cs index db0dc8fd5e..62933ed556 100644 --- a/osu.Game/Overlays/Settings/SettingsFooter.cs +++ b/osu.Game/Overlays/Settings/SettingsFooter.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Settings { - public class SettingsFooter : FillFlowContainer + public partial class SettingsFooter : FillFlowContainer { [BackgroundDependencyLoader] private void load(OsuGameBase game, RulesetStore rulesets) @@ -78,7 +78,7 @@ namespace osu.Game.Overlays.Settings } } - private class BuildDisplay : OsuAnimatedButton + private partial class BuildDisplay : OsuAnimatedButton { private readonly string version; private readonly bool isDebug; diff --git a/osu.Game/Overlays/Settings/SettingsHeader.cs b/osu.Game/Overlays/Settings/SettingsHeader.cs index 56360fc4a1..f2b84c4ba9 100644 --- a/osu.Game/Overlays/Settings/SettingsHeader.cs +++ b/osu.Game/Overlays/Settings/SettingsHeader.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Settings { - public class SettingsHeader : Container + public partial class SettingsHeader : Container { private readonly LocalisableString heading; private readonly LocalisableString subheading; diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index c34964fa96..577f1738ba 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Overlays.Settings { - public abstract class SettingsItem : Container, IFilterable, ISettingsItem, IHasCurrentValue, IHasTooltip + public abstract partial class SettingsItem : Container, IFilterable, ISettingsItem, IHasCurrentValue, IHasTooltip { protected abstract Drawable CreateControl(); diff --git a/osu.Game/Overlays/Settings/SettingsNumberBox.cs b/osu.Game/Overlays/Settings/SettingsNumberBox.cs index 4f98954289..97b8f6de60 100644 --- a/osu.Game/Overlays/Settings/SettingsNumberBox.cs +++ b/osu.Game/Overlays/Settings/SettingsNumberBox.cs @@ -11,14 +11,14 @@ using osu.Framework.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public class SettingsNumberBox : SettingsItem + public partial class SettingsNumberBox : SettingsItem { protected override Drawable CreateControl() => new NumberControl { RelativeSizeAxes = Axes.X, }; - private sealed class NumberControl : CompositeDrawable, IHasCurrentValue + private sealed partial class NumberControl : CompositeDrawable, IHasCurrentValue { private readonly BindableWithCurrent current = new BindableWithCurrent(); @@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Settings } } - private class OutlinedNumberBox : OutlinedTextBox + private partial class OutlinedNumberBox : OutlinedTextBox { protected override bool AllowIme => false; diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index dfdc850ed8..dced187035 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Overlays.Settings { - public abstract class SettingsSection : Container, IHasFilterableChildren + public abstract partial class SettingsSection : Container, IHasFilterableChildren { protected FillFlowContainer FlowContent; protected override Container Content => FlowContent; diff --git a/osu.Game/Overlays/Settings/SettingsSidebar.cs b/osu.Game/Overlays/Settings/SettingsSidebar.cs index ca6bcae6e4..36411e01cc 100644 --- a/osu.Game/Overlays/Settings/SettingsSidebar.cs +++ b/osu.Game/Overlays/Settings/SettingsSidebar.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Settings { - public class SettingsSidebar : ExpandingButtonContainer + public partial class SettingsSidebar : ExpandingButtonContainer { public const float DEFAULT_WIDTH = 70; public const int EXPANDED_WIDTH = 200; diff --git a/osu.Game/Overlays/Settings/SettingsSlider.cs b/osu.Game/Overlays/Settings/SettingsSlider.cs index 43f007f201..babac8ec69 100644 --- a/osu.Game/Overlays/Settings/SettingsSlider.cs +++ b/osu.Game/Overlays/Settings/SettingsSlider.cs @@ -10,12 +10,12 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public class SettingsSlider : SettingsSlider> + public partial class SettingsSlider : SettingsSlider> where T : struct, IEquatable, IComparable, IConvertible { } - public class SettingsSlider : SettingsItem + public partial class SettingsSlider : SettingsItem where TValue : struct, IEquatable, IComparable, IConvertible where TSlider : OsuSliderBar, new() { diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index 72788c55cd..78fb53230e 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -17,7 +17,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Settings { [ExcludeFromDynamicCompile] - public abstract class SettingsSubsection : FillFlowContainer, IHasFilterableChildren + public abstract partial class SettingsSubsection : FillFlowContainer, IHasFilterableChildren { protected override Container Content => FlowContent; diff --git a/osu.Game/Overlays/Settings/SettingsTextBox.cs b/osu.Game/Overlays/Settings/SettingsTextBox.cs index 4d0f4253eb..3f9fa06384 100644 --- a/osu.Game/Overlays/Settings/SettingsTextBox.cs +++ b/osu.Game/Overlays/Settings/SettingsTextBox.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics; namespace osu.Game.Overlays.Settings { - public class SettingsTextBox : SettingsItem + public partial class SettingsTextBox : SettingsItem { protected override Drawable CreateControl() => new OutlinedTextBox { diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs index 2c4832c68a..aec0509394 100644 --- a/osu.Game/Overlays/Settings/SidebarButton.cs +++ b/osu.Game/Overlays/Settings/SidebarButton.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { - public abstract class SidebarButton : OsuButton + public abstract partial class SidebarButton : OsuButton { protected const double FADE_DURATION = 500; diff --git a/osu.Game/Overlays/Settings/SidebarIconButton.cs b/osu.Game/Overlays/Settings/SidebarIconButton.cs index b32337eb2e..4e5b361460 100644 --- a/osu.Game/Overlays/Settings/SidebarIconButton.cs +++ b/osu.Game/Overlays/Settings/SidebarIconButton.cs @@ -15,7 +15,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Settings { - public class SidebarIconButton : SidebarButton + public partial class SidebarIconButton : SidebarButton { private const float selection_indicator_height_active = 18; private const float selection_indicator_height_inactive = 4; diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index b28ac4ab8b..291281124c 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -17,7 +17,7 @@ using osu.Game.Localisation; namespace osu.Game.Overlays { - public class SettingsOverlay : SettingsPanel, INamedOverlayComponent + public partial class SettingsOverlay : SettingsPanel, INamedOverlayComponent { public string IconTexture => "Icons/Hexacons/settings"; public LocalisableString Title => SettingsStrings.HeaderTitle; diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index eb457032ea..aefaccdb5d 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -23,7 +23,7 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Overlays { [Cached] - public abstract class SettingsPanel : OsuFocusedOverlayContainer + public abstract partial class SettingsPanel : OsuFocusedOverlayContainer { public const float CONTENT_MARGINS = 20; @@ -273,13 +273,13 @@ namespace osu.Game.Overlays } } - private class NonMaskedContent : Container + private partial class NonMaskedContent : Container { // masking breaks the pan-out transform with nested sub-settings panels. protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false; } - public class SettingsSectionsContainer : SectionsContainer + public partial class SettingsSectionsContainer : SectionsContainer { public SearchContainer SearchContainer; diff --git a/osu.Game/Overlays/SettingsSubPanel.cs b/osu.Game/Overlays/SettingsSubPanel.cs index 4548cdfb5d..5890d1c8fa 100644 --- a/osu.Game/Overlays/SettingsSubPanel.cs +++ b/osu.Game/Overlays/SettingsSubPanel.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Overlays { - public abstract class SettingsSubPanel : SettingsPanel + public abstract partial class SettingsSubPanel : SettingsPanel { protected SettingsSubPanel() : base(true) @@ -34,7 +34,7 @@ namespace osu.Game.Overlays protected override bool DimMainContent => false; // dimming is handled by main overlay - public class BackButton : SidebarButton + public partial class BackButton : SidebarButton { private Container content; diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index 6dd9e2a56d..56c890e9e2 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public class SettingsToolboxGroup : Container, IExpandable + public partial class SettingsToolboxGroup : Container, IExpandable { private readonly string title; public const int CONTAINER_WIDTH = 270; diff --git a/osu.Game/Overlays/TabControlOverlayHeader.cs b/osu.Game/Overlays/TabControlOverlayHeader.cs index caec4aeed0..cad94eba71 100644 --- a/osu.Game/Overlays/TabControlOverlayHeader.cs +++ b/osu.Game/Overlays/TabControlOverlayHeader.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays /// An overlay header which contains a . /// /// The type of item to be represented by tabs. - public abstract class TabControlOverlayHeader : OverlayHeader, IHasCurrentValue + public abstract partial class TabControlOverlayHeader : OverlayHeader, IHasCurrentValue { protected OsuTabControl TabControl; @@ -80,7 +80,7 @@ namespace osu.Game.Overlays [NotNull] protected virtual OsuTabControl CreateTabControl() => new OverlayHeaderTabControl(); - public class OverlayHeaderTabControl : OverlayTabControl + public partial class OverlayHeaderTabControl : OverlayTabControl { private const float bar_height = 1; @@ -103,7 +103,7 @@ namespace osu.Game.Overlays Direction = FillDirection.Horizontal, }; - private class OverlayHeaderTabItem : OverlayTabItem + private partial class OverlayHeaderTabItem : OverlayTabItem { public OverlayHeaderTabItem(T value) : base(value) diff --git a/osu.Game/Overlays/TabbableOnlineOverlay.cs b/osu.Game/Overlays/TabbableOnlineOverlay.cs index a99be4cc18..d92dd4ae54 100644 --- a/osu.Game/Overlays/TabbableOnlineOverlay.cs +++ b/osu.Game/Overlays/TabbableOnlineOverlay.cs @@ -12,7 +12,7 @@ using osu.Game.Online.API; namespace osu.Game.Overlays { - public abstract class TabbableOnlineOverlay : OnlineOverlay + public abstract partial class TabbableOnlineOverlay : OnlineOverlay where THeader : TabControlOverlayHeader { private readonly IBindable apiState = new Bindable(); diff --git a/osu.Game/Overlays/Toolbar/AnalogClockDisplay.cs b/osu.Game/Overlays/Toolbar/AnalogClockDisplay.cs index 477991f599..a5ed0d65bd 100644 --- a/osu.Game/Overlays/Toolbar/AnalogClockDisplay.cs +++ b/osu.Game/Overlays/Toolbar/AnalogClockDisplay.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Toolbar { - public class AnalogClockDisplay : ClockDisplay + public partial class AnalogClockDisplay : ClockDisplay { private const float hand_thickness = 2.4f; @@ -76,7 +76,7 @@ namespace osu.Game.Overlays.Toolbar hand.RotateTo(rotation, duration, Easing.OutElastic); } - private class CentreCircle : CompositeDrawable + private partial class CentreCircle : CompositeDrawable { [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -101,7 +101,7 @@ namespace osu.Game.Overlays.Toolbar } } - private class SecondHand : CompositeDrawable + private partial class SecondHand : CompositeDrawable { [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Toolbar } } - private class LargeHand : CompositeDrawable + private partial class LargeHand : CompositeDrawable { public LargeHand(float length) { diff --git a/osu.Game/Overlays/Toolbar/ClockDisplay.cs b/osu.Game/Overlays/Toolbar/ClockDisplay.cs index 0711341445..088631f8d6 100644 --- a/osu.Game/Overlays/Toolbar/ClockDisplay.cs +++ b/osu.Game/Overlays/Toolbar/ClockDisplay.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Overlays.Toolbar { - public abstract class ClockDisplay : CompositeDrawable + public abstract partial class ClockDisplay : CompositeDrawable { private int? lastSecond; diff --git a/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs b/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs index 5592590fd9..bc803db739 100644 --- a/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs +++ b/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.Toolbar { - public class DigitalClockDisplay : ClockDisplay + public partial class DigitalClockDisplay : ClockDisplay { private OsuSpriteText realTime; private OsuSpriteText gameTime; diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 9d0f43c45a..ac0f822f68 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -21,7 +21,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { - public class Toolbar : OverlayContainer, IKeyBindingHandler + public partial class Toolbar : OverlayContainer, IKeyBindingHandler { public const float HEIGHT = 40; public const float TOOLTIP_HEIGHT = 30; @@ -194,7 +194,7 @@ namespace osu.Game.Overlays.Toolbar rulesetSelector.Current.BindTo(ruleset); } - public class ToolbarBackground : Container + public partial class ToolbarBackground : Container { private readonly Box gradientBackground; diff --git a/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs b/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs index a2de186488..efcb011293 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarBeatmapListingButton.cs @@ -9,7 +9,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { - public class ToolbarBeatmapListingButton : ToolbarOverlayToggleButton + public partial class ToolbarBeatmapListingButton : ToolbarOverlayToggleButton { protected override Anchor TooltipAnchor => Anchor.TopRight; diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 96d4da1112..ea5fc5bb38 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -28,7 +28,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Toolbar { - public abstract class ToolbarButton : OsuClickableContainer, IKeyBindingHandler + public abstract partial class ToolbarButton : OsuClickableContainer, IKeyBindingHandler { protected GlobalAction? Hotkey { get; set; } @@ -219,7 +219,7 @@ namespace osu.Game.Overlays.Toolbar } } - public class OpaqueBackground : Container + public partial class OpaqueBackground : Container { public OpaqueBackground() { diff --git a/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs index 5ce6387196..30e32d831c 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarChangelogButton.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; namespace osu.Game.Overlays.Toolbar { - public class ToolbarChangelogButton : ToolbarOverlayToggleButton + public partial class ToolbarChangelogButton : ToolbarOverlayToggleButton { protected override Anchor TooltipAnchor => Anchor.TopRight; diff --git a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs index 86f87deabd..7bb94067ab 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs @@ -9,7 +9,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { - public class ToolbarChatButton : ToolbarOverlayToggleButton + public partial class ToolbarChatButton : ToolbarOverlayToggleButton { protected override Anchor TooltipAnchor => Anchor.TopRight; diff --git a/osu.Game/Overlays/Toolbar/ToolbarClock.cs b/osu.Game/Overlays/Toolbar/ToolbarClock.cs index 3fd37d9a62..f1310d8535 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarClock.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarClock.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Toolbar { - public class ToolbarClock : OsuClickableContainer + public partial class ToolbarClock : OsuClickableContainer { private Bindable clockDisplayMode; private Bindable prefer24HourTime; diff --git a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs index f170ec84ac..5a1fe40fbf 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs @@ -8,7 +8,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { - public class ToolbarHomeButton : ToolbarButton + public partial class ToolbarHomeButton : ToolbarButton { public ToolbarHomeButton() { diff --git a/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs b/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs index bd56c60582..69597c6b46 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarMusicButton.cs @@ -19,7 +19,7 @@ using osuTK.Input; namespace osu.Game.Overlays.Toolbar { - public class ToolbarMusicButton : ToolbarOverlayToggleButton + public partial class ToolbarMusicButton : ToolbarOverlayToggleButton { private Circle volumeBar; diff --git a/osu.Game/Overlays/Toolbar/ToolbarNewsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNewsButton.cs index 286cfa20f0..bdcf6c3fec 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNewsButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNewsButton.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; namespace osu.Game.Overlays.Toolbar { - public class ToolbarNewsButton : ToolbarOverlayToggleButton + public partial class ToolbarNewsButton : ToolbarOverlayToggleButton { protected override Anchor TooltipAnchor => Anchor.TopRight; diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs index 265eb044e0..3dfec2cba0 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Toolbar { - public class ToolbarNotificationButton : ToolbarOverlayToggleButton + public partial class ToolbarNotificationButton : ToolbarOverlayToggleButton { protected override Anchor TooltipAnchor => Anchor.TopRight; @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Toolbar }; } - private class CountCircle : CompositeDrawable + private partial class CountCircle : CompositeDrawable { private readonly OsuSpriteText countText; private readonly Circle circle; diff --git a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs index 03c365e49e..7bd48174db 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarOverlayToggleButton.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Toolbar { - public class ToolbarOverlayToggleButton : ToolbarButton + public partial class ToolbarOverlayToggleButton : ToolbarButton { private readonly Box stateBackground; diff --git a/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs index 1bda6da419..ddbf4889b6 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; namespace osu.Game.Overlays.Toolbar { - public class ToolbarRankingsButton : ToolbarOverlayToggleButton + public partial class ToolbarRankingsButton : ToolbarOverlayToggleButton { protected override Anchor TooltipAnchor => Anchor.TopRight; diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs index 1ca492f81a..715076b368 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetSelector.cs @@ -21,7 +21,7 @@ using osu.Framework.Audio.Sample; namespace osu.Game.Overlays.Toolbar { - public class ToolbarRulesetSelector : RulesetSelector + public partial class ToolbarRulesetSelector : RulesetSelector { protected Drawable ModeButtonLine { get; private set; } diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs index 31c6802fda..8f9930e910 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs @@ -12,7 +12,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Overlays.Toolbar { - public class ToolbarRulesetTabButton : TabItem + public partial class ToolbarRulesetTabButton : TabItem { private readonly RulesetButton ruleset; @@ -37,7 +37,7 @@ namespace osu.Game.Overlays.Toolbar protected override void OnDeactivated() => ruleset.Active = false; - private class RulesetButton : ToolbarButton + private partial class RulesetButton : ToolbarButton { public bool Active { diff --git a/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs index c3d48bc60e..6ebf2a4c02 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSettingsButton.cs @@ -8,7 +8,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { - public class ToolbarSettingsButton : ToolbarOverlayToggleButton + public partial class ToolbarSettingsButton : ToolbarOverlayToggleButton { public ToolbarSettingsButton() { diff --git a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs index f8ee39d56e..a8a88813d2 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs @@ -9,7 +9,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { - public class ToolbarSocialButton : ToolbarOverlayToggleButton + public partial class ToolbarSocialButton : ToolbarOverlayToggleButton { protected override Anchor TooltipAnchor => Anchor.TopRight; diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 4ebd19a1f7..028decea1e 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Toolbar { - public class ToolbarUserButton : ToolbarOverlayToggleButton + public partial class ToolbarUserButton : ToolbarOverlayToggleButton { private UpdateableAvatar avatar = null!; diff --git a/osu.Game/Overlays/Toolbar/ToolbarWikiButton.cs b/osu.Game/Overlays/Toolbar/ToolbarWikiButton.cs index 5511902fa8..49e6be7978 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarWikiButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarWikiButton.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; namespace osu.Game.Overlays.Toolbar { - public class ToolbarWikiButton : ToolbarOverlayToggleButton + public partial class ToolbarWikiButton : ToolbarOverlayToggleButton { protected override Anchor TooltipAnchor => Anchor.TopRight; diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index c0ca63bbd9..b1a9b2096e 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public class UserProfileOverlay : FullscreenOverlay + public partial class UserProfileOverlay : FullscreenOverlay { private ProfileSection lastSection; private ProfileSection[] sections; @@ -152,7 +152,7 @@ namespace osu.Game.Overlays } } - private class ProfileSectionTabControl : OverlayTabControl + private partial class ProfileSectionTabControl : OverlayTabControl { private const float bar_height = 2; @@ -182,7 +182,7 @@ namespace osu.Game.Overlays protected override bool OnHover(HoverEvent e) => true; - private class ProfileSectionTabItem : OverlayTabItem + private partial class ProfileSectionTabItem : OverlayTabItem { public ProfileSectionTabItem(ProfileSection value) : base(value) @@ -196,7 +196,7 @@ namespace osu.Game.Overlays } } - private class ProfileSectionsContainer : SectionsContainer + private partial class ProfileSectionsContainer : SectionsContainer { public ProfileSectionsContainer() { diff --git a/osu.Game/Overlays/VersionManager.cs b/osu.Game/Overlays/VersionManager.cs index a1cfdf4594..0e74cada29 100644 --- a/osu.Game/Overlays/VersionManager.cs +++ b/osu.Game/Overlays/VersionManager.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public class VersionManager : VisibilityContainer + public partial class VersionManager : VisibilityContainer { [BackgroundDependencyLoader] private void load(OsuColour colours, TextureStore textures, OsuGameBase game) diff --git a/osu.Game/Overlays/Volume/MuteButton.cs b/osu.Game/Overlays/Volume/MuteButton.cs index 744b2bafbd..3bea1c840e 100644 --- a/osu.Game/Overlays/Volume/MuteButton.cs +++ b/osu.Game/Overlays/Volume/MuteButton.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Volume { - public class MuteButton : OsuButton, IHasCurrentValue + public partial class MuteButton : OsuButton, IHasCurrentValue { private readonly Bindable current = new Bindable(); diff --git a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs index 624be0b25c..4ddbc9dd48 100644 --- a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs +++ b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs @@ -12,7 +12,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Volume { - public class VolumeControlReceptor : Container, IScrollBindingHandler, IHandleGlobalKeyboardInput + public partial class VolumeControlReceptor : Container, IScrollBindingHandler, IHandleGlobalKeyboardInput { public Func ActionRequested; public Func ScrollActionRequested; diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index e01890ddc2..d366f0bddb 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -29,7 +29,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Volume { - public class VolumeMeter : Container, IStateful + public partial class VolumeMeter : Container, IStateful { private CircularProgress volumeCircle; private CircularProgress volumeCircleGlow; diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index 4cedd87eac..5470c70400 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Overlays { - public class VolumeOverlay : VisibilityContainer + public partial class VolumeOverlay : VisibilityContainer { private const float offset = 10; diff --git a/osu.Game/Overlays/WaveOverlayContainer.cs b/osu.Game/Overlays/WaveOverlayContainer.cs index faf2cca8cf..d25f6a9ae5 100644 --- a/osu.Game/Overlays/WaveOverlayContainer.cs +++ b/osu.Game/Overlays/WaveOverlayContainer.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays { - public abstract class WaveOverlayContainer : OsuFocusedOverlayContainer + public abstract partial class WaveOverlayContainer : OsuFocusedOverlayContainer { protected readonly WaveContainer Waves; diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index 15c455416c..4ef9be90c9 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -14,7 +14,7 @@ using osu.Game.Graphics.Containers.Markdown; namespace osu.Game.Overlays.Wiki.Markdown { - public class WikiMarkdownContainer : OsuMarkdownContainer + public partial class WikiMarkdownContainer : OsuMarkdownContainer { protected override bool Footnotes => true; protected override bool CustomContainers => true; @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.Wiki.Markdown public override MarkdownTextFlowContainer CreateTextFlow() => new WikiMarkdownTextFlowContainer(); - private class WikiMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer + private partial class WikiMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer { protected override void AddImage(LinkInline linkInline) => AddDrawable(new WikiMarkdownImage(linkInline)); } diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs index 1c7a08930b..71c2df538d 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImage.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics.Containers.Markdown; namespace osu.Game.Overlays.Wiki.Markdown { - public class WikiMarkdownImage : OsuMarkdownImage + public partial class WikiMarkdownImage : OsuMarkdownImage { public WikiMarkdownImage(LinkInline linkInline) : base(linkInline) diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImageBlock.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImageBlock.cs index 5ce3f179a4..641c6242b6 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImageBlock.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownImageBlock.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Overlays.Wiki.Markdown { - public class WikiMarkdownImageBlock : FillFlowContainer + public partial class WikiMarkdownImageBlock : FillFlowContainer { [Resolved] private IMarkdownTextFlowComponent parentFlowComponent { get; set; } @@ -49,7 +49,7 @@ namespace osu.Game.Overlays.Wiki.Markdown textFlow.AddText(linkInline.Title); } - private class BlockMarkdownImage : WikiMarkdownImage + private partial class BlockMarkdownImage : WikiMarkdownImage { public BlockMarkdownImage(LinkInline linkInline) : base(linkInline) @@ -60,7 +60,7 @@ namespace osu.Game.Overlays.Wiki.Markdown protected override ImageContainer CreateImageContainer(string url) => new BlockImageContainer(url); - private class BlockImageContainer : ImageContainer + private partial class BlockImageContainer : ImageContainer { public BlockImageContainer(string url) : base(url) @@ -71,7 +71,7 @@ namespace osu.Game.Overlays.Wiki.Markdown protected override Sprite CreateImageSprite() => new ImageSprite(); - private class ImageSprite : Sprite + private partial class ImageSprite : Sprite { public ImageSprite() { diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs index 64d7e20d9b..5f8bee7558 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiNoticeContainer.cs @@ -15,7 +15,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Wiki.Markdown { - public class WikiNoticeContainer : FillFlowContainer + public partial class WikiNoticeContainer : FillFlowContainer { private readonly bool isOutdated; private readonly bool needsCleanup; @@ -62,7 +62,7 @@ namespace osu.Game.Overlays.Wiki.Markdown } } - private class NoticeBox : Container + private partial class NoticeBox : Container { [Resolved] private IMarkdownTextFlowComponent parentFlowComponent { get; set; } diff --git a/osu.Game/Overlays/Wiki/WikiArticlePage.cs b/osu.Game/Overlays/Wiki/WikiArticlePage.cs index f4ba0a4d8d..6c1dbe3181 100644 --- a/osu.Game/Overlays/Wiki/WikiArticlePage.cs +++ b/osu.Game/Overlays/Wiki/WikiArticlePage.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Wiki.Markdown; namespace osu.Game.Overlays.Wiki { - public class WikiArticlePage : CompositeDrawable + public partial class WikiArticlePage : CompositeDrawable { public Container SidebarContainer { get; } @@ -65,7 +65,7 @@ namespace osu.Game.Overlays.Wiki }; } - private class ArticleMarkdownContainer : WikiMarkdownContainer + private partial class ArticleMarkdownContainer : WikiMarkdownContainer { public Action OnAddHeading; diff --git a/osu.Game/Overlays/Wiki/WikiHeader.cs b/osu.Game/Overlays/Wiki/WikiHeader.cs index fc8df03892..9317813fc4 100644 --- a/osu.Game/Overlays/Wiki/WikiHeader.cs +++ b/osu.Game/Overlays/Wiki/WikiHeader.cs @@ -14,7 +14,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Wiki { - public class WikiHeader : BreadcrumbControlOverlayHeader + public partial class WikiHeader : BreadcrumbControlOverlayHeader { private const string index_path = "Main_Page"; @@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Wiki protected override OverlayTitle CreateTitle() => new WikiHeaderTitle(); - private class WikiHeaderTitle : OverlayTitle + private partial class WikiHeaderTitle : OverlayTitle { public WikiHeaderTitle() { diff --git a/osu.Game/Overlays/Wiki/WikiMainPage.cs b/osu.Game/Overlays/Wiki/WikiMainPage.cs index 67e4bdf2e5..457309ae44 100644 --- a/osu.Game/Overlays/Wiki/WikiMainPage.cs +++ b/osu.Game/Overlays/Wiki/WikiMainPage.cs @@ -15,7 +15,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Wiki { - public class WikiMainPage : FillFlowContainer + public partial class WikiMainPage : FillFlowContainer { public string Markdown; diff --git a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs index 552770f098..ef31e9cfdd 100644 --- a/osu.Game/Overlays/Wiki/WikiPanelContainer.cs +++ b/osu.Game/Overlays/Wiki/WikiPanelContainer.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Wiki { - public class WikiPanelContainer : Container + public partial class WikiPanelContainer : Container { private WikiPanelMarkdownContainer panelContainer; @@ -78,7 +78,7 @@ namespace osu.Game.Overlays.Wiki Height = Math.Max(panelContainer.Height, Parent.DrawHeight); } - private class WikiPanelMarkdownContainer : WikiMarkdownContainer + private partial class WikiPanelMarkdownContainer : WikiMarkdownContainer { private readonly bool isFullWidth; @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.Wiki }; } - private class WikiPanelHeading : OsuMarkdownHeading + private partial class WikiPanelHeading : OsuMarkdownHeading { public bool IsFullWidth; diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index 78ce9c8a24..4c8fe83703 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -15,7 +15,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Wiki { - public class WikiSidebar : OverlaySidebar + public partial class WikiSidebar : OverlaySidebar { private WikiTableOfContents tableOfContents; diff --git a/osu.Game/Overlays/Wiki/WikiTableOfContents.cs b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs index d60d728aca..5566233c39 100644 --- a/osu.Game/Overlays/Wiki/WikiTableOfContents.cs +++ b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Overlays.Wiki { - public class WikiTableOfContents : CompositeDrawable + public partial class WikiTableOfContents : CompositeDrawable { private readonly FillFlowContainer content; @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Wiki content.Add(lastMainTitle = entry.With(d => d.Margin = new MarginPadding { Bottom = 5 })); } - private class TableOfContentsEntry : OsuHoverContainer + private partial class TableOfContentsEntry : OsuHoverContainer { private readonly MarkdownHeading target; diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 148d2977c7..a06c180948 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -17,7 +17,7 @@ using osu.Game.Overlays.Wiki; namespace osu.Game.Overlays { - public class WikiOverlay : OnlineOverlay + public partial class WikiOverlay : OnlineOverlay { private const string index_path = @"main_page"; diff --git a/osu.Game/PerformFromMenuRunner.cs b/osu.Game/PerformFromMenuRunner.cs index 158350b43d..21beadf366 100644 --- a/osu.Game/PerformFromMenuRunner.cs +++ b/osu.Game/PerformFromMenuRunner.cs @@ -18,7 +18,7 @@ using osu.Game.Screens.Menu; namespace osu.Game { - internal class PerformFromMenuRunner : Component + internal partial class PerformFromMenuRunner : Component { private readonly Action finalAction; private readonly Type[] validScreens; diff --git a/osu.Game/Performance/HighPerformanceSession.cs b/osu.Game/Performance/HighPerformanceSession.cs index dd5de03077..c113e7a342 100644 --- a/osu.Game/Performance/HighPerformanceSession.cs +++ b/osu.Game/Performance/HighPerformanceSession.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Performance { - public class HighPerformanceSession : Component + public partial class HighPerformanceSession : Component { private readonly IBindable localUserPlaying = new Bindable(); diff --git a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs index b0a2694a0a..0df481737e 100644 --- a/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/DistancedHitObjectComposer.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Edit /// Represents a for rulesets with the concept of distances between objects. /// /// The base type of supported objects. - public abstract class DistancedHitObjectComposer : HitObjectComposer, IDistanceSnapProvider, IScrollBindingHandler + public abstract partial class DistancedHitObjectComposer : HitObjectComposer, IDistanceSnapProvider, IScrollBindingHandler where TObject : HitObject { private const float adjust_step = 0.1f; @@ -297,7 +297,7 @@ namespace osu.Game.Rulesets.Edit return DurationToDistance(referenceObject, snappedEndTime - startTime); } - private class DistanceSpacingToast : Toast + private partial class DistanceSpacingToast : Toast { private readonly ValueChangedEvent change; diff --git a/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs b/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs index 9588a092a8..20ee409937 100644 --- a/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs +++ b/osu.Game/Rulesets/Edit/DrawableEditorRulesetWrapper.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Edit /// /// A wrapper for a . Handles adding visual representations of s to the underlying . /// - internal class DrawableEditorRulesetWrapper : CompositeDrawable + internal partial class DrawableEditorRulesetWrapper : CompositeDrawable where TObject : HitObject { public Playfield Playfield => drawableRuleset.Playfield; diff --git a/osu.Game/Rulesets/Edit/EditorToolboxGroup.cs b/osu.Game/Rulesets/Edit/EditorToolboxGroup.cs index 7dcc90b16d..312ba62b61 100644 --- a/osu.Game/Rulesets/Edit/EditorToolboxGroup.cs +++ b/osu.Game/Rulesets/Edit/EditorToolboxGroup.cs @@ -8,7 +8,7 @@ using osu.Game.Overlays; namespace osu.Game.Rulesets.Edit { - public class EditorToolboxGroup : SettingsToolboxGroup + public partial class EditorToolboxGroup : SettingsToolboxGroup { public EditorToolboxGroup(string title) : base(title) diff --git a/osu.Game/Rulesets/Edit/ExpandableButton.cs b/osu.Game/Rulesets/Edit/ExpandableButton.cs index a66600bd58..d512aa287a 100644 --- a/osu.Game/Rulesets/Edit/ExpandableButton.cs +++ b/osu.Game/Rulesets/Edit/ExpandableButton.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Rulesets.Edit { - internal class ExpandableButton : RoundedButton, IExpandable + internal partial class ExpandableButton : RoundedButton, IExpandable { private float actualHeight; diff --git a/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs b/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs index 26dd5dfa55..7bf10f6beb 100644 --- a/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs +++ b/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Rulesets.Edit { - public class ExpandingToolboxContainer : ExpandingContainer + public partial class ExpandingToolboxContainer : ExpandingContainer { protected override double HoverExpansionDelay => 250; diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 520fcb0290..aff242d63f 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Edit /// Responsible for providing snapping and generally gluing components together. /// /// The base type of supported objects. - public abstract class HitObjectComposer : HitObjectComposer, IPlacementHandler + public abstract partial class HitObjectComposer : HitObjectComposer, IPlacementHandler where TObject : HitObject { protected IRulesetConfigManager Config { get; private set; } @@ -417,7 +417,7 @@ namespace osu.Game.Rulesets.Edit /// Generally used to access certain methods without requiring a generic type for . /// [Cached] - public abstract class HitObjectComposer : CompositeDrawable, IPositionSnapProvider + public abstract partial class HitObjectComposer : CompositeDrawable, IPositionSnapProvider { protected HitObjectComposer() { diff --git a/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs b/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs index 408fbfc04f..93b889792b 100644 --- a/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/HitObjectSelectionBlueprint.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Rulesets.Edit { - public abstract class HitObjectSelectionBlueprint : SelectionBlueprint + public abstract partial class HitObjectSelectionBlueprint : SelectionBlueprint { /// /// The which this applies to. @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Edit public override Quad SelectionQuad => DrawableObject.ScreenSpaceDrawQuad; } - public abstract class HitObjectSelectionBlueprint : HitObjectSelectionBlueprint + public abstract partial class HitObjectSelectionBlueprint : HitObjectSelectionBlueprint where T : HitObject { public T HitObject => (T)Item; diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index c8196b6865..dd8dd93d66 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Edit /// /// A blueprint which governs the creation of a new to actualisation. /// - public abstract class PlacementBlueprint : CompositeDrawable + public abstract partial class PlacementBlueprint : CompositeDrawable { /// /// Whether the is currently mid-placement, but has not necessarily finished being placed. diff --git a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs index fc24b55d21..4e0e45e0f5 100644 --- a/osu.Game/Rulesets/Edit/SelectionBlueprint.cs +++ b/osu.Game/Rulesets/Edit/SelectionBlueprint.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Edit /// /// A blueprint placed above a displaying item adding editing functionality. /// - public abstract class SelectionBlueprint : CompositeDrawable, IStateful + public abstract partial class SelectionBlueprint : CompositeDrawable, IStateful { public readonly T Item; diff --git a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs index c2b27d4ce8..2b8bd08ede 100644 --- a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs +++ b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Rulesets.Judgements { - public class DefaultJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class DefaultJudgementPiece : CompositeDrawable, IAnimatableJudgement { protected readonly HitResult Result; diff --git a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs index 48955c729f..15434fcc04 100644 --- a/osu.Game/Rulesets/Judgements/DrawableJudgement.cs +++ b/osu.Game/Rulesets/Judgements/DrawableJudgement.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Judgements /// /// A drawable object which visualises the hit result of a . /// - public class DrawableJudgement : PoolableDrawable + public partial class DrawableJudgement : PoolableDrawable { private const float judgement_size = 128; diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs index 599e81f2b8..9d9c10b3ea 100644 --- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs +++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Rulesets.Mods { - public class DifficultyAdjustSettingsControl : SettingsItem + public partial class DifficultyAdjustSettingsControl : SettingsItem { [Resolved] private IBindable beatmap { get; set; } @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Mods isInternalChange = false; } - private class SliderControl : CompositeDrawable, IHasCurrentValue + private partial class SliderControl : CompositeDrawable, IHasCurrentValue { // This is required as SettingsItem relies heavily on this bindable for internal use. // The actual update flow is done via the bindable provided in the constructor. diff --git a/osu.Game/Rulesets/Mods/MetronomeBeat.cs b/osu.Game/Rulesets/Mods/MetronomeBeat.cs index 149af1e30a..265970ea46 100644 --- a/osu.Game/Rulesets/Mods/MetronomeBeat.cs +++ b/osu.Game/Rulesets/Mods/MetronomeBeat.cs @@ -11,7 +11,7 @@ using osu.Game.Skinning; namespace osu.Game.Rulesets.Mods { - public class MetronomeBeat : BeatSyncedContainer, IAdjustableAudioComponent + public partial class MetronomeBeat : BeatSyncedContainer, IAdjustableAudioComponent { private readonly double firstHitTime; diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index d58a901154..45fa55c7f2 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Mods public abstract float DefaultFlashlightSize { get; } } - public abstract class ModFlashlight : ModFlashlight, IApplicableToDrawableRuleset, IApplicableToScoreProcessor + public abstract partial class ModFlashlight : ModFlashlight, IApplicableToDrawableRuleset, IApplicableToScoreProcessor where T : HitObject { public const double FLASHLIGHT_FADE_DURATION = 800; @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Mods protected abstract Flashlight CreateFlashlight(); - public abstract class Flashlight : Drawable + public abstract partial class Flashlight : Drawable { public readonly BindableInt Combo = new BindableInt(); diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs index 27a777bff7..59c4cfa85b 100644 --- a/osu.Game/Rulesets/Mods/ModMuted.cs +++ b/osu.Game/Rulesets/Mods/ModMuted.cs @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.Mods public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank; } - public class MuteComboSlider : OsuSliderBar + public partial class MuteComboSlider : OsuSliderBar { public override LocalisableString TooltipText => Current.Value == 0 ? "always muted" : base.TooltipText; } diff --git a/osu.Game/Rulesets/Mods/ModNightcore.cs b/osu.Game/Rulesets/Mods/ModNightcore.cs index 099bf386f3..9b1f7d5cf7 100644 --- a/osu.Game/Rulesets/Mods/ModNightcore.cs +++ b/osu.Game/Rulesets/Mods/ModNightcore.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Mods public override LocalisableString Description => "Uguuuuuuuu..."; } - public abstract class ModNightcore : ModNightcore, IApplicableToDrawableRuleset + public abstract partial class ModNightcore : ModNightcore, IApplicableToDrawableRuleset where TObject : HitObject { private readonly BindableNumber tempoAdjust = new BindableDouble(1); @@ -54,7 +54,7 @@ namespace osu.Game.Rulesets.Mods drawableRuleset.Overlays.Add(new NightcoreBeatContainer()); } - public class NightcoreBeatContainer : BeatSyncedContainer + public partial class NightcoreBeatContainer : BeatSyncedContainer { private PausableSkinnableSound? hatSample; private PausableSkinnableSound? clapSample; diff --git a/osu.Game/Rulesets/Mods/ModNoScope.cs b/osu.Game/Rulesets/Mods/ModNoScope.cs index 36fbb88943..cfac44066e 100644 --- a/osu.Game/Rulesets/Mods/ModNoScope.cs +++ b/osu.Game/Rulesets/Mods/ModNoScope.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mods } } - public class HiddenComboSlider : OsuSliderBar + public partial class HiddenComboSlider : OsuSliderBar { public override LocalisableString TooltipText => Current.Value == 0 ? "always hidden" : base.TooltipText; } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 60792445cd..d6c151028e 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -30,7 +30,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Objects.Drawables { [Cached(typeof(DrawableHitObject))] - public abstract class DrawableHitObject : PoolableDrawableWithLifetime + public abstract partial class DrawableHitObject : PoolableDrawableWithLifetime { /// /// Invoked after this 's applied has had its defaults applied. @@ -745,7 +745,7 @@ namespace osu.Game.Rulesets.Objects.Drawables } } - public abstract class DrawableHitObject : DrawableHitObject + public abstract partial class DrawableHitObject : DrawableHitObject where TObject : HitObject { public new TObject HitObject => (TObject)base.HitObject; diff --git a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs index 8dc588da9e..a06f810cfe 100644 --- a/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs +++ b/osu.Game/Rulesets/Objects/Pooling/PoolableDrawableWithLifetime.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Objects.Pooling /// A that is controlled by to implement drawable pooling and replay rewinding. /// /// The type storing state and controlling this drawable. - public abstract class PoolableDrawableWithLifetime : PoolableDrawable where TEntry : LifetimeEntry + public abstract partial class PoolableDrawableWithLifetime : PoolableDrawable where TEntry : LifetimeEntry { private TEntry? entry; diff --git a/osu.Game/Rulesets/Objects/Pooling/PooledDrawableWithLifetimeContainer.cs b/osu.Game/Rulesets/Objects/Pooling/PooledDrawableWithLifetimeContainer.cs index d5b4390ce8..3b45acc7bb 100644 --- a/osu.Game/Rulesets/Objects/Pooling/PooledDrawableWithLifetimeContainer.cs +++ b/osu.Game/Rulesets/Objects/Pooling/PooledDrawableWithLifetimeContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Objects.Pooling /// /// The type of entries managed by this container. /// The type of drawables corresponding to the entries. - public abstract class PooledDrawableWithLifetimeContainer : CompositeDrawable + public abstract partial class PooledDrawableWithLifetimeContainer : CompositeDrawable where TEntry : LifetimeEntry where TDrawable : Drawable { diff --git a/osu.Game/Rulesets/RulesetConfigCache.cs b/osu.Game/Rulesets/RulesetConfigCache.cs index ab44e86048..79dff37280 100644 --- a/osu.Game/Rulesets/RulesetConfigCache.cs +++ b/osu.Game/Rulesets/RulesetConfigCache.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Configuration; namespace osu.Game.Rulesets { - public class RulesetConfigCache : Component, IRulesetConfigCache + public partial class RulesetConfigCache : Component, IRulesetConfigCache { private readonly RealmAccess realm; private readonly RulesetStore rulesets; diff --git a/osu.Game/Rulesets/RulesetSelector.cs b/osu.Game/Rulesets/RulesetSelector.cs index 701e60eec9..062f8d6450 100644 --- a/osu.Game/Rulesets/RulesetSelector.cs +++ b/osu.Game/Rulesets/RulesetSelector.cs @@ -9,7 +9,7 @@ using osu.Framework.Logging; namespace osu.Game.Rulesets { - public abstract class RulesetSelector : TabControl + public abstract partial class RulesetSelector : TabControl { [Resolved] protected RulesetStore Rulesets { get; private set; } diff --git a/osu.Game/Rulesets/Scoring/AccumulatingHealthProcessor.cs b/osu.Game/Rulesets/Scoring/AccumulatingHealthProcessor.cs index c6b9d227af..af6e825b06 100644 --- a/osu.Game/Rulesets/Scoring/AccumulatingHealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/AccumulatingHealthProcessor.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Scoring /// A that accumulates health and causes a fail if the final health /// is less than a value required to pass the beatmap. /// - public class AccumulatingHealthProcessor : HealthProcessor + public partial class AccumulatingHealthProcessor : HealthProcessor { protected override bool DefaultFailCondition => JudgedHits == MaxHits && Health.Value < requiredHealth; diff --git a/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs b/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs index 65af161393..d94c6dd2e0 100644 --- a/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/DrainingHealthProcessor.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Scoring /// At HP=5, the minimum health reached for a perfect play is 70%.
/// At HP=10, the minimum health reached for a perfect play is 30%. ///
- public class DrainingHealthProcessor : HealthProcessor + public partial class DrainingHealthProcessor : HealthProcessor { /// /// A reasonable allowable error for the minimum health offset from . A 1% error is unnoticeable. diff --git a/osu.Game/Rulesets/Scoring/HealthProcessor.cs b/osu.Game/Rulesets/Scoring/HealthProcessor.cs index 0a1e6b729f..cdfe71943e 100644 --- a/osu.Game/Rulesets/Scoring/HealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/HealthProcessor.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.Judgements; namespace osu.Game.Rulesets.Scoring { - public abstract class HealthProcessor : JudgementProcessor + public abstract partial class HealthProcessor : JudgementProcessor { /// /// Invoked when the is in a failed state. diff --git a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs index bc8f2c22f3..09b5f0a6bc 100644 --- a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs +++ b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.Replays; namespace osu.Game.Rulesets.Scoring { - public abstract class JudgementProcessor : Component + public abstract partial class JudgementProcessor : Component { /// /// Invoked when a new judgement has occurred. This occurs after the judgement has been processed by this . diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 899d149cbc..29c37c31d5 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -21,7 +21,7 @@ using osu.Game.Localisation; namespace osu.Game.Rulesets.Scoring { - public class ScoreProcessor : JudgementProcessor + public partial class ScoreProcessor : JudgementProcessor { private const double max_score = 1000000; diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index dd3a950264..71b452c309 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.UI /// Displays an interactive ruleset gameplay instance. /// /// The type of HitObject contained by this DrawableRuleset. - public abstract class DrawableRuleset : DrawableRuleset, IProvideCursor, ICanAttachHUDPieces + public abstract partial class DrawableRuleset : DrawableRuleset, IProvideCursor, ICanAttachHUDPieces where TObject : HitObject { public override event Action NewResult; @@ -414,7 +414,7 @@ namespace osu.Game.Rulesets.UI /// /// [Cached(typeof(DrawableRuleset))] - public abstract class DrawableRuleset : CompositeDrawable + public abstract partial class DrawableRuleset : CompositeDrawable { /// /// Invoked when a has been applied by a . diff --git a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs index 3b35fba122..4bb145973d 100644 --- a/osu.Game/Rulesets/UI/FrameStabilityContainer.cs +++ b/osu.Game/Rulesets/UI/FrameStabilityContainer.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.UI /// [Cached(typeof(IGameplayClock))] [Cached(typeof(IFrameStableClock))] - public sealed class FrameStabilityContainer : Container, IHasReplayHandler, IFrameStableClock + public sealed partial class FrameStabilityContainer : Container, IHasReplayHandler, IFrameStableClock { public ReplayInputHandler? ReplayInputHandler { get; set; } diff --git a/osu.Game/Rulesets/UI/GameplayCursorContainer.cs b/osu.Game/Rulesets/UI/GameplayCursorContainer.cs index 3149b7f890..cbce397d1e 100644 --- a/osu.Game/Rulesets/UI/GameplayCursorContainer.cs +++ b/osu.Game/Rulesets/UI/GameplayCursorContainer.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Cursor; namespace osu.Game.Rulesets.UI { - public class GameplayCursorContainer : CursorContainer + public partial class GameplayCursorContainer : CursorContainer { /// /// Because Show/Hide are executed by a parent, is updated immediately even if the cursor diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index fd8fcfddab..d068f8d016 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.UI /// /// A component which can trigger the most appropriate hit sound for a given point in time, based on the state of a /// - public class GameplaySampleTriggerSource : CompositeDrawable + public partial class GameplaySampleTriggerSource : CompositeDrawable { /// /// The number of concurrent samples allowed to be played concurrently so that it feels better when spam-pressing a key. diff --git a/osu.Game/Rulesets/UI/HitObjectContainer.cs b/osu.Game/Rulesets/UI/HitObjectContainer.cs index bbced9e58c..7cbf49aa31 100644 --- a/osu.Game/Rulesets/UI/HitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/HitObjectContainer.cs @@ -17,7 +17,7 @@ using osu.Game.Rulesets.Objects.Pooling; namespace osu.Game.Rulesets.UI { - public class HitObjectContainer : PooledDrawableWithLifetimeContainer, IHitObjectContainer + public partial class HitObjectContainer : PooledDrawableWithLifetimeContainer, IHitObjectContainer { public IEnumerable Objects => InternalChildren.Cast().OrderBy(h => h.HitObject.StartTime); diff --git a/osu.Game/Rulesets/UI/JudgementContainer.cs b/osu.Game/Rulesets/UI/JudgementContainer.cs index 471a62cab3..8381e6d6b5 100644 --- a/osu.Game/Rulesets/UI/JudgementContainer.cs +++ b/osu.Game/Rulesets/UI/JudgementContainer.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Judgements; namespace osu.Game.Rulesets.UI { - public class JudgementContainer : Container + public partial class JudgementContainer : Container where T : DrawableJudgement { public override void Add(T judgement) diff --git a/osu.Game/Rulesets/UI/ModIcon.cs b/osu.Game/Rulesets/UI/ModIcon.cs index b1f355a789..bf212ad72f 100644 --- a/osu.Game/Rulesets/UI/ModIcon.cs +++ b/osu.Game/Rulesets/UI/ModIcon.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.UI /// /// Display the specified mod at a fixed size. /// - public class ModIcon : Container, IHasTooltip + public partial class ModIcon : Container, IHasTooltip { public readonly BindableBool Selected = new BindableBool(); diff --git a/osu.Game/Rulesets/UI/ModSwitchSmall.cs b/osu.Game/Rulesets/UI/ModSwitchSmall.cs index 1b777f3e88..b6058c16ce 100644 --- a/osu.Game/Rulesets/UI/ModSwitchSmall.cs +++ b/osu.Game/Rulesets/UI/ModSwitchSmall.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.UI { - public class ModSwitchSmall : CompositeDrawable + public partial class ModSwitchSmall : CompositeDrawable { public BindableBool Active { get; } = new BindableBool(); diff --git a/osu.Game/Rulesets/UI/ModSwitchTiny.cs b/osu.Game/Rulesets/UI/ModSwitchTiny.cs index 1bb0fe535f..a5cf75bd07 100644 --- a/osu.Game/Rulesets/UI/ModSwitchTiny.cs +++ b/osu.Game/Rulesets/UI/ModSwitchTiny.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.UI { - public class ModSwitchTiny : CompositeDrawable + public partial class ModSwitchTiny : CompositeDrawable { public BindableBool Active { get; } = new BindableBool(); diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index e59e45722a..859be6e210 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.UI { [Cached(typeof(IPooledHitObjectProvider))] [Cached(typeof(IPooledSampleProvider))] - public abstract class Playfield : CompositeDrawable, IPooledHitObjectProvider, IPooledSampleProvider + public abstract partial class Playfield : CompositeDrawable, IPooledHitObjectProvider, IPooledSampleProvider { /// /// Invoked when a is judged. @@ -427,7 +427,7 @@ namespace osu.Game.Rulesets.UI return pool; } - private class DrawableSamplePool : DrawablePool + private partial class DrawableSamplePool : DrawablePool { private readonly ISampleInfo sampleInfo; diff --git a/osu.Game/Rulesets/UI/PlayfieldAdjustmentContainer.cs b/osu.Game/Rulesets/UI/PlayfieldAdjustmentContainer.cs index d0e79281a7..0f440adef8 100644 --- a/osu.Game/Rulesets/UI/PlayfieldAdjustmentContainer.cs +++ b/osu.Game/Rulesets/UI/PlayfieldAdjustmentContainer.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.UI /// /// A container which handles sizing of the and any other components that need to match their size. /// - public class PlayfieldAdjustmentContainer : Container + public partial class PlayfieldAdjustmentContainer : Container { public PlayfieldAdjustmentContainer() { diff --git a/osu.Game/Rulesets/UI/PlayfieldBorder.cs b/osu.Game/Rulesets/UI/PlayfieldBorder.cs index a129760ef3..211a87de84 100644 --- a/osu.Game/Rulesets/UI/PlayfieldBorder.cs +++ b/osu.Game/Rulesets/UI/PlayfieldBorder.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.UI /// /// Provides a border around the playfield. /// - public class PlayfieldBorder : CompositeDrawable + public partial class PlayfieldBorder : CompositeDrawable { public Bindable PlayfieldBorderStyle { get; } = new Bindable(); @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.UI } } - private class Line : Box + private partial class Line : Box { private readonly Direction direction; diff --git a/osu.Game/Rulesets/UI/ReplayRecorder.cs b/osu.Game/Rulesets/UI/ReplayRecorder.cs index 79da56fc8a..28e25c72e1 100644 --- a/osu.Game/Rulesets/UI/ReplayRecorder.cs +++ b/osu.Game/Rulesets/UI/ReplayRecorder.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Rulesets.UI { - public abstract class ReplayRecorder : ReplayRecorder, IKeyBindingHandler + public abstract partial class ReplayRecorder : ReplayRecorder, IKeyBindingHandler where T : struct { private readonly Score target; @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.UI protected abstract ReplayFrame HandleFrame(Vector2 mousePosition, List actions, ReplayFrame previousFrame); } - public abstract class ReplayRecorder : Component + public abstract partial class ReplayRecorder : Component { public Func ScreenSpaceToGamefield; } diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 64ac021204..a5e442b7de 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -25,7 +25,7 @@ using static osu.Game.Input.Handlers.ReplayInputHandler; namespace osu.Game.Rulesets.UI { - public abstract class RulesetInputManager : PassThroughInputManager, ICanAttachHUDPieces, IHasReplayHandler, IHasRecordingHandler + public abstract partial class RulesetInputManager : PassThroughInputManager, ICanAttachHUDPieces, IHasReplayHandler, IHasRecordingHandler where T : struct { public readonly KeyBindingContainer KeyBindingContainer; @@ -169,7 +169,7 @@ namespace osu.Game.Rulesets.UI .Select(action => new KeyCounterAction(action))); } - private class ActionReceptor : KeyCounterDisplay.Receptor, IKeyBindingHandler + private partial class ActionReceptor : KeyCounterDisplay.Receptor, IKeyBindingHandler { public ActionReceptor(KeyCounterDisplay target) : base(target) @@ -196,7 +196,7 @@ namespace osu.Game.Rulesets.UI KeyBindingContainer.Add(listener); } - private class ActionListener : Component, IKeyBindingHandler + private partial class ActionListener : Component, IKeyBindingHandler { private readonly ClicksPerSecondCalculator calculator; @@ -221,7 +221,7 @@ namespace osu.Game.Rulesets.UI protected virtual KeyBindingContainer CreateKeyBindingContainer(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) => new RulesetKeyBindingContainer(ruleset, variant, unique); - public class RulesetKeyBindingContainer : DatabasedKeyBindingContainer + public partial class RulesetKeyBindingContainer : DatabasedKeyBindingContainer { protected override bool HandleRepeats => false; diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 2cb57966e7..52853d3979 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// A type of that supports a . /// s inside this will scroll within the playfield. /// - public abstract class DrawableScrollingRuleset : DrawableRuleset, IDrawableScrollingRuleset, IKeyBindingHandler + public abstract partial class DrawableScrollingRuleset : DrawableRuleset, IDrawableScrollingRuleset, IKeyBindingHandler where TObject : HitObject { /// diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 424fc7c44c..3559a1521c 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Rulesets.UI.Scrolling { - public class ScrollingHitObjectContainer : HitObjectContainer + public partial class ScrollingHitObjectContainer : HitObjectContainer { private readonly IBindable timeRange = new BindableDouble(); private readonly IBindable direction = new Bindable(); diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs index 34e5b7f9de..7d141113df 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingPlayfield.cs @@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.UI.Scrolling /// /// A type of specialized towards scrolling s. /// - public abstract class ScrollingPlayfield : Playfield + public abstract partial class ScrollingPlayfield : Playfield { protected readonly IBindable Direction = new Bindable(); diff --git a/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs b/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs index 6087ca9eb9..99eb7e964d 100644 --- a/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs +++ b/osu.Game/Scoring/Drawables/UnprocessedPerformancePointsPlaceholder.cs @@ -13,7 +13,7 @@ namespace osu.Game.Scoring.Drawables /// /// A placeholder used in PP columns for scores with unprocessed PP value. /// - public class UnprocessedPerformancePointsPlaceholder : SpriteIcon, IHasTooltip + public partial class UnprocessedPerformancePointsPlaceholder : SpriteIcon, IHasTooltip { public LocalisableString TooltipText => ScoresStrings.StatusProcessing; diff --git a/osu.Game/Scoring/ScorePerformanceCache.cs b/osu.Game/Scoring/ScorePerformanceCache.cs index f51fb41497..17a0c0ea6a 100644 --- a/osu.Game/Scoring/ScorePerformanceCache.cs +++ b/osu.Game/Scoring/ScorePerformanceCache.cs @@ -18,7 +18,7 @@ namespace osu.Game.Scoring /// A component which performs and acts as a central cache for performance calculations of locally databased scores. /// Currently not persisted between game sessions. /// - public class ScorePerformanceCache : MemoryCachingComponent + public partial class ScorePerformanceCache : MemoryCachingComponent { [Resolved] private BeatmapDifficultyCache difficultyCache { get; set; } diff --git a/osu.Game/Screens/BackgroundScreen.cs b/osu.Game/Screens/BackgroundScreen.cs index 8e1fd63040..a7502f22d5 100644 --- a/osu.Game/Screens/BackgroundScreen.cs +++ b/osu.Game/Screens/BackgroundScreen.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Screens { - public abstract class BackgroundScreen : Screen, IEquatable + public abstract partial class BackgroundScreen : Screen, IEquatable { protected const float TRANSITION_LENGTH = 500; private const float x_movement_amount = 50; diff --git a/osu.Game/Screens/BackgroundScreenStack.cs b/osu.Game/Screens/BackgroundScreenStack.cs index bafd1ff348..ca0dad83c8 100644 --- a/osu.Game/Screens/BackgroundScreenStack.cs +++ b/osu.Game/Screens/BackgroundScreenStack.cs @@ -9,7 +9,7 @@ using osu.Framework.Screens; namespace osu.Game.Screens { - public class BackgroundScreenStack : ScreenStack + public partial class BackgroundScreenStack : ScreenStack { public BackgroundScreenStack() : base(false) diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs index 4d84a8194d..42a81ad3fa 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Screens.Backgrounds { - public class BackgroundScreenBeatmap : BackgroundScreen + public partial class BackgroundScreenBeatmap : BackgroundScreen { /// /// The amount of blur to apply when full user blur is requested. @@ -122,7 +122,7 @@ namespace osu.Game.Screens.Backgrounds return base.Equals(other) && beatmap == otherBeatmapBackground.Beatmap; } - public class DimmableBackground : UserDimContainer + public partial class DimmableBackground : UserDimContainer { /// /// The amount of blur to be applied to the background in addition to user-specified blur. diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs index 4b0f262ab1..09778c5cdf 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs @@ -10,7 +10,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Backgrounds { - public class BackgroundScreenBlack : BackgroundScreen + public partial class BackgroundScreenBlack : BackgroundScreen { public BackgroundScreenBlack() { diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenCustom.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenCustom.cs index 3dd72685e9..3c8ed6fe76 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenCustom.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenCustom.cs @@ -7,7 +7,7 @@ using osu.Game.Graphics.Backgrounds; namespace osu.Game.Screens.Backgrounds { - public class BackgroundScreenCustom : BackgroundScreen + public partial class BackgroundScreenCustom : BackgroundScreen { private readonly string textureName; diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 44b6fcce4a..0d9b39f099 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -19,7 +19,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Backgrounds { - public class BackgroundScreenDefault : BackgroundScreen + public partial class BackgroundScreenDefault : BackgroundScreen { private Background background; diff --git a/osu.Game/Screens/Edit/BottomBar.cs b/osu.Game/Screens/Edit/BottomBar.cs index 444911cf2d..b8fed4b935 100644 --- a/osu.Game/Screens/Edit/BottomBar.cs +++ b/osu.Game/Screens/Edit/BottomBar.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit { - internal class BottomBar : CompositeDrawable + internal partial class BottomBar : CompositeDrawable { public TestGameplayButton TestGameplayButton { get; private set; } diff --git a/osu.Game/Screens/Edit/Components/BottomBarContainer.cs b/osu.Game/Screens/Edit/Components/BottomBarContainer.cs index 482a0bbe5f..32ec3b6833 100644 --- a/osu.Game/Screens/Edit/Components/BottomBarContainer.cs +++ b/osu.Game/Screens/Edit/Components/BottomBarContainer.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Components { - public class BottomBarContainer : Container + public partial class BottomBarContainer : Container { private const float contents_padding = 15; diff --git a/osu.Game/Screens/Edit/Components/EditorSidebar.cs b/osu.Game/Screens/Edit/Components/EditorSidebar.cs index da15512cdc..cfcfcd75e6 100644 --- a/osu.Game/Screens/Edit/Components/EditorSidebar.cs +++ b/osu.Game/Screens/Edit/Components/EditorSidebar.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Edit.Components /// A sidebar area that can be attached to the left or right edge of the screen. /// Houses scrolling sectionised content. /// - internal class EditorSidebar : Container + internal partial class EditorSidebar : Container { public const float WIDTH = 250; diff --git a/osu.Game/Screens/Edit/Components/EditorSidebarSection.cs b/osu.Game/Screens/Edit/Components/EditorSidebarSection.cs index 6782b2f357..4e8c55efa1 100644 --- a/osu.Game/Screens/Edit/Components/EditorSidebarSection.cs +++ b/osu.Game/Screens/Edit/Components/EditorSidebarSection.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Components { - public class EditorSidebarSection : Container + public partial class EditorSidebarSection : Container { protected override Container Content { get; } @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Edit.Components }; } - public class SectionHeader : CompositeDrawable + public partial class SectionHeader : CompositeDrawable { private readonly LocalisableString text; diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs index 20b8bba6da..a911b4e1d8 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Components.Menus { - public class EditorMenuBar : OsuMenu + public partial class EditorMenuBar : OsuMenu { public EditorMenuBar() : base(Direction.Horizontal, true) @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Edit.Components.Menus protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableEditorBarMenuItem(item); - private class DrawableEditorBarMenuItem : DrawableOsuMenuItem + private partial class DrawableEditorBarMenuItem : DrawableOsuMenuItem { public DrawableEditorBarMenuItem(MenuItem item) : base(item) @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Edit.Components.Menus protected override DrawableOsuMenuItem.TextContainer CreateTextContainer() => new TextContainer(); - private new class TextContainer : DrawableOsuMenuItem.TextContainer + private new partial class TextContainer : DrawableOsuMenuItem.TextContainer { public TextContainer() { @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Edit.Components.Menus } } - private class SubMenu : OsuMenu + private partial class SubMenu : OsuMenu { public SubMenu() : base(Direction.Vertical) @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Edit.Components.Menus } } - private class EditorStatefulMenuItem : DrawableStatefulMenuItem + private partial class EditorStatefulMenuItem : DrawableStatefulMenuItem { public EditorStatefulMenuItem(StatefulMenuItem item) : base(item) @@ -135,7 +135,7 @@ namespace osu.Game.Screens.Edit.Components.Menus } } - private class EditorMenuItem : DrawableOsuMenuItem + private partial class EditorMenuItem : DrawableOsuMenuItem { public EditorMenuItem(MenuItem item) : base(item) @@ -152,7 +152,7 @@ namespace osu.Game.Screens.Edit.Components.Menus } } - private class DrawableSpacer : DrawableOsuMenuItem + private partial class DrawableSpacer : DrawableOsuMenuItem { public DrawableSpacer(MenuItem item) : base(item) diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs b/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs index 0bba5a79ab..e88138def4 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Components.Menus { - public class EditorScreenSwitcherControl : OsuTabControl + public partial class EditorScreenSwitcherControl : OsuTabControl { public EditorScreenSwitcherControl() { @@ -42,7 +42,7 @@ namespace osu.Game.Screens.Edit.Components.Menus protected override TabItem CreateTabItem(EditorScreenMode value) => new TabItem(value); - private class TabItem : OsuTabItem + private partial class TabItem : OsuTabItem { private const float transition_length = 250; diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 30316cb12c..f403551a62 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -23,7 +23,7 @@ using osuTK.Input; namespace osu.Game.Screens.Edit.Components { - public class PlaybackControl : BottomBarContainer + public partial class PlaybackControl : BottomBarContainer { private IconButton playButton; @@ -102,7 +102,7 @@ namespace osu.Game.Screens.Edit.Components playButton.Icon = editorClock.IsRunning ? FontAwesome.Regular.PauseCircle : FontAwesome.Regular.PlayCircle; } - private class PlaybackTabControl : OsuTabControl + private partial class PlaybackTabControl : OsuTabControl { private static readonly double[] tempo_values = { 0.25, 0.5, 0.75, 1 }; @@ -120,7 +120,7 @@ namespace osu.Game.Screens.Edit.Components Current.Value = tempo_values.Last(); } - public class PlaybackTabItem : TabItem + public partial class PlaybackTabItem : TabItem { private const float fade_duration = 200; diff --git a/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButton.cs b/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButton.cs index 071bb9fdcb..bfcc0084bd 100644 --- a/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButton.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButton.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Components.RadioButtons { - public class EditorRadioButton : OsuButton, IHasTooltip + public partial class EditorRadioButton : OsuButton, IHasTooltip { /// /// Invoked when this has been selected. diff --git a/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButtonCollection.cs b/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButtonCollection.cs index b8d1cca061..92dd47dc81 100644 --- a/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButtonCollection.cs +++ b/osu.Game/Screens/Edit/Components/RadioButtons/EditorRadioButtonCollection.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Components.RadioButtons { - public class EditorRadioButtonCollection : CompositeDrawable + public partial class EditorRadioButtonCollection : CompositeDrawable { private IReadOnlyList items; diff --git a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs index 1fb5c0285d..45b7cd1b7c 100644 --- a/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs +++ b/osu.Game/Screens/Edit/Components/TernaryButtons/DrawableTernaryButton.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Components.TernaryButtons { - internal class DrawableTernaryButton : OsuButton + internal partial class DrawableTernaryButton : OsuButton { private Color4 defaultBackgroundColour; private Color4 defaultIconColour; diff --git a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs index 7051dd226c..1c16671ce4 100644 --- a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs +++ b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Components { - public class TimeInfoContainer : BottomBarContainer + public partial class TimeInfoContainer : BottomBarContainer { private OsuSpriteText trackTimer; private OsuSpriteText bpm; diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs index 058aa83b97..f1023ade8c 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BookmarkPart.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// /// The part of the timeline that displays bookmarks. /// - public class BookmarkPart : TimelinePart + public partial class BookmarkPart : TimelinePart { protected override void LoadBeatmap(EditorBeatmap beatmap) { @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts Add(new BookmarkVisualisation(bookmark)); } - private class BookmarkVisualisation : PointVisualisation + private partial class BookmarkVisualisation : PointVisualisation { public BookmarkVisualisation(double startTime) : base(startTime) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs index 4dbec880dc..de5d074c51 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/BreakPart.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// /// The part of the timeline that displays breaks in the song. /// - public class BreakPart : TimelinePart + public partial class BreakPart : TimelinePart { protected override void LoadBeatmap(EditorBeatmap beatmap) { @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts Add(new BreakVisualisation(breakPeriod)); } - private class BreakVisualisation : DurationVisualisation + private partial class BreakVisualisation : DurationVisualisation { public BreakVisualisation(BreakPeriod breakPeriod) : base(breakPeriod.StartTime, breakPeriod.EndTime) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs index 54ef5a2bd7..2d26e6f90b 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// /// The part of the timeline that displays the control points. /// - public class ControlPointPart : TimelinePart + public partial class ControlPointPart : TimelinePart { private readonly IBindableList controlPointGroups = new BindableList(); diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointVisualisation.cs index 89c0309222..aa494271f8 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointVisualisation.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointVisualisation.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations; namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { - public class ControlPointVisualisation : PointVisualisation, IControlPointVisualisation + public partial class ControlPointVisualisation : PointVisualisation, IControlPointVisualisation { protected readonly ControlPoint Point; diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/EffectPointVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/EffectPointVisualisation.cs index b61fcf4482..d92beba38a 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/EffectPointVisualisation.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/EffectPointVisualisation.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations; namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { - public class EffectPointVisualisation : CompositeDrawable, IControlPointVisualisation + public partial class EffectPointVisualisation : CompositeDrawable, IControlPointVisualisation { private readonly EffectControlPoint effect; private Bindable kiai = null!; diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs index e058cae191..64c0745596 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/GroupVisualisation.cs @@ -11,7 +11,7 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { - public class GroupVisualisation : CompositeDrawable + public partial class GroupVisualisation : CompositeDrawable { public readonly ControlPointGroup Group; diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs index c00ebb32bc..5be6db55a4 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts /// /// The part of the timeline that displays the current position of the song. /// - public class MarkerPart : TimelinePart + public partial class MarkerPart : TimelinePart { private Drawable marker; @@ -71,7 +71,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts // block base call so we don't clear our marker (can be reused on beatmap change). } - private class MarkerVisualisation : CompositeDrawable + private partial class MarkerVisualisation : CompositeDrawable { public MarkerVisualisation() { diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs index bb5b4a6cea..e380a2063b 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/TimelinePart.cs @@ -14,14 +14,14 @@ using osu.Game.Beatmaps; namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts { - public class TimelinePart : TimelinePart + public partial class TimelinePart : TimelinePart { } /// /// Represents a part of the summary timeline.. /// - public class TimelinePart : Container where T : Drawable + public partial class TimelinePart : Container where T : Drawable { private readonly IBindable beatmap = new Bindable(); diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs index afaedee0a9..7f762b9d50 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/SummaryTimeline.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary /// /// The timeline that sits at the bottom of the editor. /// - public class SummaryTimeline : BottomBarContainer + public partial class SummaryTimeline : BottomBarContainer { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs index d38596b9be..a3a003947c 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; namespace osu.Game.Screens.Edit.Components.Timelines.Summary { - public class TestGameplayButton : OsuButton + public partial class TestGameplayButton : OsuButton { protected override SpriteText CreateText() => new OsuSpriteText { diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs index 88e40cb305..6fc994b8b1 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/DurationVisualisation.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations /// /// Represents a spanning point on a timeline part. /// - public class DurationVisualisation : Circle + public partial class DurationVisualisation : Circle { protected DurationVisualisation(double startTime, double endTime) { diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs index b8e55c8db8..75dacdf3e7 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Visualisations/PointVisualisation.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Visualisations /// /// Represents a singular point on a timeline part. /// - public class PointVisualisation : Circle + public partial class PointVisualisation : Circle { public const float MAX_WIDTH = 4; diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 6dca799549..903c117422 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -29,7 +29,7 @@ using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components { - public class BeatDivisorControl : CompositeDrawable + public partial class BeatDivisorControl : CompositeDrawable { private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); @@ -220,7 +220,7 @@ namespace osu.Game.Screens.Edit.Compose.Components return base.OnKeyDown(e); } - internal class DivisorDisplay : OsuAnimatedButton, IHasPopover + internal partial class DivisorDisplay : OsuAnimatedButton, IHasPopover { public BindableBeatDivisor BeatDivisor { get; } = new BindableBeatDivisor(); @@ -270,7 +270,7 @@ namespace osu.Game.Screens.Edit.Compose.Components }; } - internal class CustomDivisorPopover : OsuPopover + internal partial class CustomDivisorPopover : OsuPopover { public BindableBeatDivisor BeatDivisor { get; } = new BindableBeatDivisor(); @@ -328,7 +328,7 @@ namespace osu.Game.Screens.Edit.Compose.Components } } - private class DivisorTypeText : OsuSpriteText + private partial class DivisorTypeText : OsuSpriteText { public BindableBeatDivisor BeatDivisor { get; } = new BindableBeatDivisor(); @@ -347,7 +347,7 @@ namespace osu.Game.Screens.Edit.Compose.Components } } - internal class ChevronButton : IconButton + internal partial class ChevronButton : IconButton { public ChevronButton() { @@ -370,7 +370,7 @@ namespace osu.Game.Screens.Edit.Compose.Components } } - private class TickSliderBar : SliderBar + private partial class TickSliderBar : SliderBar { private Marker marker; @@ -485,7 +485,7 @@ namespace osu.Game.Screens.Edit.Compose.Components private float getMappedPosition(float divisor) => MathF.Pow((divisor - 1) / (beatDivisor.ValidDivisors.Value.Presets.Last() - 1), 0.90f); - private class Tick : Circle + private partial class Tick : Circle { public Tick(int divisor) { @@ -494,7 +494,7 @@ namespace osu.Game.Screens.Edit.Compose.Components } } - private class Marker : CompositeDrawable + private partial class Marker : CompositeDrawable { [Resolved] private OverlayColourProvider colourProvider { get; set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 43ad270c16..60fec5bcc6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// A container which provides a "blueprint" display of items. /// Includes selection and manipulation support via a . /// - public abstract class BlueprintContainer : CompositeDrawable, IKeyBindingHandler + public abstract partial class BlueprintContainer : CompositeDrawable, IKeyBindingHandler where T : class { protected DragBox DragBox { get; private set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs index 6e54e98740..d6e4e1f030 100644 --- a/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose.Components { - public abstract class CircularDistanceSnapGrid : DistanceSnapGrid + public abstract partial class CircularDistanceSnapGrid : DistanceSnapGrid { protected CircularDistanceSnapGrid(HitObject referenceObject, Vector2 startPosition, double startTime, double? endTime = null) : base(referenceObject, startPosition, startTime, endTime) @@ -117,7 +117,7 @@ namespace osu.Game.Screens.Edit.Compose.Components return (snappedPosition, snappedTime); } - private class Ring : CircularProgress + private partial class Ring : CircularProgress { [Resolved] private IDistanceSnapProvider snapProvider { get; set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index ec07da43a0..f955ae9cd6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// A blueprint container generally displayed as an overlay to a ruleset's playfield. /// - public class ComposeBlueprintContainer : EditorBlueprintContainer + public partial class ComposeBlueprintContainer : EditorBlueprintContainer { private readonly Container placementBlueprintContainer; diff --git a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs index c179e7f0c2..6092ebc08f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// A grid which takes user input and returns a quantized ("snapped") position and time. /// - public abstract class DistanceSnapGrid : CompositeDrawable + public abstract partial class DistanceSnapGrid : CompositeDrawable { /// /// The spacing between each tick of the beat snapping grid. diff --git a/osu.Game/Screens/Edit/Compose/Components/DragBox.cs b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs index 905d47533a..4d1f81228e 100644 --- a/osu.Game/Screens/Edit/Compose/Components/DragBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/DragBox.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// A box that displays the drag selection and provides selection events for users to handle. /// - public class DragBox : CompositeDrawable, IStateful + public partial class DragBox : CompositeDrawable, IStateful { public Drawable Box { get; private set; } @@ -71,7 +71,7 @@ namespace osu.Game.Screens.Edit.Compose.Components public event Action StateChanged; - public class BoxWithBorders : CompositeDrawable + public partial class BoxWithBorders : CompositeDrawable { private readonly LayoutValue cache = new LayoutValue(Invalidation.RequiredParentSizeToFit); diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs index 7423b368b4..65797a968d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorBlueprintContainer.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets.Objects.Drawables; namespace osu.Game.Screens.Edit.Compose.Components { - public class EditorBlueprintContainer : BlueprintContainer + public partial class EditorBlueprintContainer : BlueprintContainer { [Resolved] protected EditorClock EditorClock { get; private set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs index 0bdfc5b0a0..357cc940f2 100644 --- a/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/EditorSelectionHandler.cs @@ -18,7 +18,7 @@ using osu.Game.Rulesets.Objects.Types; namespace osu.Game.Screens.Edit.Compose.Components { - public class EditorSelectionHandler : SelectionHandler + public partial class EditorSelectionHandler : SelectionHandler { [Resolved] protected EditorBeatmap EditorBeatmap { get; private set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs b/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs index 18bb6284b8..849a526556 100644 --- a/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/HitObjectOrderedSelectionContainer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// A container for ordered by their start times. /// - public sealed class HitObjectOrderedSelectionContainer : Container> + public sealed partial class HitObjectOrderedSelectionContainer : Container> { [Resolved] private EditorBeatmap editorBeatmap { get; set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/RectangularPositionSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/RectangularPositionSnapGrid.cs index 64fb2ccaba..06b73c8af4 100644 --- a/osu.Game/Screens/Edit/Compose/Components/RectangularPositionSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/RectangularPositionSnapGrid.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Compose.Components { - public class RectangularPositionSnapGrid : CompositeDrawable + public partial class RectangularPositionSnapGrid : CompositeDrawable { /// /// The position of the origin of this in local coordinates. diff --git a/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs b/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs index 58bfaf56ff..599e64760d 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ScrollingDragBox.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// A that scrolls along with the scrolling playfield. /// - public class ScrollingDragBox : DragBox + public partial class ScrollingDragBox : DragBox { public double MinTime { get; private set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs index 2c4c220ad0..17790547ed 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBox.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components { [Cached] - public class SelectionBox : CompositeDrawable + public partial class SelectionBox : CompositeDrawable { public const float BORDER_RADIUS = 3; diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxButton.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxButton.cs index 3d6dacc95e..832d8b65e5 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxButton.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxButton.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose.Components { - public sealed class SelectionBoxButton : SelectionBoxControl, IHasTooltip + public sealed partial class SelectionBoxButton : SelectionBoxControl, IHasTooltip { private SpriteIcon icon; diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxControl.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxControl.cs index c4675685f6..35c67a1c67 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxControl.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// Represents the base appearance for UI controls of the , /// such as scale handles, rotation handles, buttons, etc... /// - public abstract class SelectionBoxControl : CompositeDrawable + public abstract partial class SelectionBoxControl : CompositeDrawable { public const double TRANSFORM_DURATION = 100; diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandle.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandle.cs index 308d0cc893..757ff655f5 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandle.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandle.cs @@ -8,7 +8,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Screens.Edit.Compose.Components { - public abstract class SelectionBoxDragHandle : SelectionBoxControl + public abstract partial class SelectionBoxDragHandle : SelectionBoxControl { protected override bool OnDragStart(DragStartEvent e) { diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleContainer.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleContainer.cs index 5c7debf57e..5c87271493 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleContainer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// Represents a display composite containing and managing the visibility state of the selection box's drag handles. /// - public class SelectionBoxDragHandleContainer : CompositeDrawable + public partial class SelectionBoxDragHandleContainer : CompositeDrawable { private Container scaleHandles; private Container rotationHandles; diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxRotationHandle.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxRotationHandle.cs index 761cd118bf..0f702e1c49 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxRotationHandle.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxRotationHandle.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose.Components { - public class SelectionBoxRotationHandle : SelectionBoxDragHandle, IHasTooltip + public partial class SelectionBoxRotationHandle : SelectionBoxDragHandle, IHasTooltip { public Action HandleRotate { get; set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxScaleHandle.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxScaleHandle.cs index bd1e2f4649..7943065c82 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxScaleHandle.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxScaleHandle.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Compose.Components { - public class SelectionBoxScaleHandle : SelectionBoxDragHandle + public partial class SelectionBoxScaleHandle : SelectionBoxDragHandle { public Action HandleScale { get; set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs index 269c19f846..a0ac99fec2 100644 --- a/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionHandler.cs @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// A component which outlines items and handles movement of selections. /// - public abstract class SelectionHandler : CompositeDrawable, IKeyBindingHandler, IKeyBindingHandler, IHasContextMenu + public abstract partial class SelectionHandler : CompositeDrawable, IKeyBindingHandler, IKeyBindingHandler, IHasContextMenu { /// /// The currently selected blueprints. diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs index 6c545f8f78..44daf70577 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class CentreMarker : CompositeDrawable + public partial class CentreMarker : CompositeDrawable { private const float triangle_width = 15; private const float triangle_height = 10; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs index b028f67ba1..d3cdd461ea 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/DifficultyPointPiece.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class DifficultyPointPiece : HitObjectPointPiece, IHasPopover + public partial class DifficultyPointPiece : HitObjectPointPiece, IHasPopover { public readonly HitObject HitObject; @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public Popover GetPopover() => new DifficultyEditPopover(HitObject); - public class DifficultyEditPopover : OsuPopover + public partial class DifficultyEditPopover : OsuPopover { private readonly HitObject hitObject; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/HitObjectPointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/HitObjectPointPiece.cs index 1091afe226..5b0a5729c8 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/HitObjectPointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/HitObjectPointPiece.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class HitObjectPointPiece : CircularContainer + public partial class HitObjectPointPiece : CircularContainer { private readonly ControlPoint point; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs index 648ffd9609..314137a565 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/SamplePointPiece.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class SamplePointPiece : HitObjectPointPiece, IHasPopover + public partial class SamplePointPiece : HitObjectPointPiece, IHasPopover { public readonly HitObject HitObject; @@ -55,7 +55,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public Popover GetPopover() => new SampleEditPopover(HitObject); - public class SampleEditPopover : OsuPopover + public partial class SampleEditPopover : OsuPopover { private readonly HitObject hitObject; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs index 8befda82e8..45f902d0de 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs @@ -22,7 +22,7 @@ using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { [Cached] - public class Timeline : ZoomableScrollContainer, IPositionSnapProvider + public partial class Timeline : ZoomableScrollContainer, IPositionSnapProvider { private const float timeline_height = 72; private const float timeline_expanded_height = 94; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs index 58d378154a..615925ff91 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class TimelineArea : CompositeDrawable + public partial class TimelineArea : CompositeDrawable { public Timeline Timeline; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs index b79c2675c8..f93fb0679f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineBlueprintContainer.cs @@ -24,7 +24,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - internal class TimelineBlueprintContainer : EditorBlueprintContainer + internal partial class TimelineBlueprintContainer : EditorBlueprintContainer { [Resolved(CanBeNull = true)] private Timeline timeline { get; set; } @@ -198,7 +198,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline timeline.ScrollBy((float)((mouseX - timelineQuad.TopLeft.X) / 10 * Clock.ElapsedFrameTime)); } - private class SelectableAreaBackground : CompositeDrawable + private partial class SelectableAreaBackground : CompositeDrawable { [Resolved] private OsuColour colours { get; set; } @@ -246,7 +246,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } } - protected class TimelineSelectionBlueprintContainer : Container> + protected partial class TimelineSelectionBlueprintContainer : Container> { protected override Container> Content { get; } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs index 0832dc02a9..c94de0fe67 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Edit.Timing; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class TimelineButton : IconButton + public partial class TimelineButton : IconButton { [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs index cfc71256e8..9783c4184a 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline /// /// The part of the timeline that displays the control points. /// - public class TimelineControlPointDisplay : TimelinePart + public partial class TimelineControlPointDisplay : TimelinePart { private readonly IBindableList controlPointGroups = new BindableList(); diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs index 10355045be..257cc9e635 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointGroup.cs @@ -10,7 +10,7 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class TimelineControlPointGroup : CompositeDrawable + public partial class TimelineControlPointGroup : CompositeDrawable { public readonly ControlPointGroup Group; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs index 65d9293b7e..a1dfd0718b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineDragBox.cs @@ -11,7 +11,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class TimelineDragBox : DragBox + public partial class TimelineDragBox : DragBox { public double MinTime { get; private set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs index 20ef128ee9..3e49c31b1e 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs @@ -27,7 +27,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class TimelineHitObjectBlueprint : SelectionBlueprint + public partial class TimelineHitObjectBlueprint : SelectionBlueprint { private const float circle_size = 38; @@ -262,7 +262,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public override Vector2 ScreenSpaceSelectionPoint => ScreenSpaceDrawQuad.TopLeft; - private class Tick : Circle + private partial class Tick : Circle { public Tick() { @@ -273,7 +273,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } } - public class DragArea : Circle + public partial class DragArea : Circle { private readonly HitObject? hitObject; @@ -444,7 +444,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } } - public class Border : ExtendableCircle + public partial class Border : ExtendableCircle { [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -460,7 +460,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline /// /// A circle with externalised end caps so it can take up the full width of a relative width area. /// - public class ExtendableCircle : CompositeDrawable + public partial class ExtendableCircle : CompositeDrawable { protected readonly Circle Content; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineSelectionHandler.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineSelectionHandler.cs index d91b95888b..0a5a0e99ac 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineSelectionHandler.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineSelectionHandler.cs @@ -16,7 +16,7 @@ using osuTK.Input; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - internal class TimelineSelectionHandler : EditorSelectionHandler + internal partial class TimelineSelectionHandler : EditorSelectionHandler { // for now we always allow movement. snapping is provided by the Timeline's "distance" snap implementation public override bool HandleMovement(MoveSelectionEvent moveEvent) => true; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs index c1c9b2493b..6a0688e19c 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineTickDisplay.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class TimelineTickDisplay : TimelinePart + public partial class TimelineTickDisplay : TimelinePart { [Resolved] private EditorBeatmap beatmap { get; set; } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimingPointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimingPointPiece.cs index cf62707839..4191864e5c 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimingPointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimingPointPiece.cs @@ -9,7 +9,7 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class TimingPointPiece : TopPointPiece + public partial class TimingPointPiece : TopPointPiece { private readonly BindableNumber beatLength; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TopPointPiece.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TopPointPiece.cs index 28ae77c931..69fb001a66 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TopPointPiece.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TopPointPiece.cs @@ -13,7 +13,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class TopPointPiece : CompositeDrawable + public partial class TopPointPiece : CompositeDrawable { private readonly ControlPoint point; diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index 839b2b5bad..28f7731354 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline { - public class ZoomableScrollContainer : OsuScrollContainer + public partial class ZoomableScrollContainer : OsuScrollContainer { /// /// The time to zoom into/out of a point. diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index d3c330c6d7..3af7a400e2 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -20,7 +20,7 @@ using osu.Game.Screens.Edit.Compose.Components.Timeline; namespace osu.Game.Screens.Edit.Compose { - public class ComposeScreen : EditorScreenWithTimeline, IGameplaySettings + public partial class ComposeScreen : EditorScreenWithTimeline, IGameplaySettings { [Resolved] private GameHost host { get; set; } diff --git a/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs b/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs index 36c4e397a7..85466c5056 100644 --- a/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs +++ b/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs @@ -8,7 +8,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Edit { - public class CreateNewDifficultyDialog : PopupDialog + public partial class CreateNewDifficultyDialog : PopupDialog { /// /// Delegate used to create new difficulties. diff --git a/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs b/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs index 594042b426..68a0ef4250 100644 --- a/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs +++ b/osu.Game/Screens/Edit/DeleteDifficultyConfirmationDialog.cs @@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Edit { - public class DeleteDifficultyConfirmationDialog : DeleteConfirmationDialog + public partial class DeleteDifficultyConfirmationDialog : DeleteConfirmationDialog { public DeleteDifficultyConfirmationDialog(BeatmapInfo beatmapInfo, Action deleteAction) { diff --git a/osu.Game/Screens/Edit/Design/DesignScreen.cs b/osu.Game/Screens/Edit/Design/DesignScreen.cs index 546a07f17d..10b351ded1 100644 --- a/osu.Game/Screens/Edit/Design/DesignScreen.cs +++ b/osu.Game/Screens/Edit/Design/DesignScreen.cs @@ -5,7 +5,7 @@ namespace osu.Game.Screens.Edit.Design { - public class DesignScreen : EditorScreen + public partial class DesignScreen : EditorScreen { public DesignScreen() : base(EditorScreenMode.Design) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 4c44117581..0676c372a8 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -58,7 +58,7 @@ namespace osu.Game.Screens.Edit { [Cached(typeof(IBeatSnapProvider))] [Cached] - public class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler, IKeyBindingHandler, IBeatSnapProvider, ISamplePlaybackDisabler, IBeatSyncProvider + public partial class Editor : ScreenWithBeatmapBackground, IKeyBindingHandler, IKeyBindingHandler, IBeatSnapProvider, ISamplePlaybackDisabler, IBeatSyncProvider { public override float BackgroundParallaxAmount => 0.1f; @@ -1034,7 +1034,7 @@ namespace osu.Game.Screens.Edit IClock IBeatSyncProvider.Clock => clock; ChannelAmplitudes IHasAmplitudes.CurrentAmplitudes => Beatmap.Value.TrackLoaded ? Beatmap.Value.Track.CurrentAmplitudes : ChannelAmplitudes.Empty; - private class BeatmapEditorToast : Toast + private partial class BeatmapEditorToast : Toast { public BeatmapEditorToast(LocalisableString value, string beatmapDisplayName) : base(InputSettingsStrings.EditorSection, value, beatmapDisplayName) diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 839535b99f..e204b44db3 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -20,7 +20,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Edit { - public class EditorBeatmap : TransactionalCommitComponent, IBeatmap, IBeatSnapProvider + public partial class EditorBeatmap : TransactionalCommitComponent, IBeatmap, IBeatSnapProvider { /// /// Will become true when a new update is queued, and false when all updates have been applied. diff --git a/osu.Game/Screens/Edit/EditorChangeHandler.cs b/osu.Game/Screens/Edit/EditorChangeHandler.cs index 1a93f3f101..964b86cad3 100644 --- a/osu.Game/Screens/Edit/EditorChangeHandler.cs +++ b/osu.Game/Screens/Edit/EditorChangeHandler.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Edit /// /// Tracks changes to the . /// - public class EditorChangeHandler : TransactionalCommitComponent, IEditorChangeHandler + public partial class EditorChangeHandler : TransactionalCommitComponent, IEditorChangeHandler { public readonly Bindable CanUndo = new Bindable(); public readonly Bindable CanRedo = new Bindable(); diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index f83874e4a0..e5e88a04d9 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Edit /// /// A decoupled clock which adds editor-specific functionality, such as snapping to a user-defined beat divisor. /// - public class EditorClock : CompositeComponent, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock + public partial class EditorClock : CompositeComponent, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock { public IBindable Track => track; diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index d6af990b52..f665b7c511 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Edit /// Transition screen for the editor. /// Used to avoid backing out to main menu/song select when switching difficulties from within the editor. /// - public class EditorLoader : ScreenWithBeatmapBackground + public partial class EditorLoader : ScreenWithBeatmapBackground { /// /// The stored state from the last editor opened. diff --git a/osu.Game/Screens/Edit/EditorRoundedScreenSettings.cs b/osu.Game/Screens/Edit/EditorRoundedScreenSettings.cs index 013971960b..1c083b4fab 100644 --- a/osu.Game/Screens/Edit/EditorRoundedScreenSettings.cs +++ b/osu.Game/Screens/Edit/EditorRoundedScreenSettings.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.Edit { - public abstract class EditorRoundedScreenSettings : CompositeDrawable + public abstract partial class EditorRoundedScreenSettings : CompositeDrawable { [BackgroundDependencyLoader] private void load(OverlayColourProvider colours) diff --git a/osu.Game/Screens/Edit/EditorRoundedScreenSettingsSection.cs b/osu.Game/Screens/Edit/EditorRoundedScreenSettingsSection.cs index be1545cac8..751b6f61d1 100644 --- a/osu.Game/Screens/Edit/EditorRoundedScreenSettingsSection.cs +++ b/osu.Game/Screens/Edit/EditorRoundedScreenSettingsSection.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Screens.Edit { - public abstract class EditorRoundedScreenSettingsSection : CompositeDrawable + public abstract partial class EditorRoundedScreenSettingsSection : CompositeDrawable { private const int header_height = 50; diff --git a/osu.Game/Screens/Edit/EditorScreen.cs b/osu.Game/Screens/Edit/EditorScreen.cs index 92709484ff..069a5490bb 100644 --- a/osu.Game/Screens/Edit/EditorScreen.cs +++ b/osu.Game/Screens/Edit/EditorScreen.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Edit /// /// TODO: eventually make this inherit Screen and add a local screen stack inside the Editor. /// - public abstract class EditorScreen : VisibilityContainer + public abstract partial class EditorScreen : VisibilityContainer { [Resolved] protected EditorBeatmap EditorBeatmap { get; private set; } diff --git a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs index b3aafb9730..84cfac8f65 100644 --- a/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs +++ b/osu.Game/Screens/Edit/EditorScreenWithTimeline.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.Edit.Compose.Components.Timeline; namespace osu.Game.Screens.Edit { - public abstract class EditorScreenWithTimeline : EditorScreen + public abstract partial class EditorScreenWithTimeline : EditorScreen { private const float padding = 10; diff --git a/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs b/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs index d4387a0263..814b5dc18e 100644 --- a/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs +++ b/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs @@ -9,7 +9,7 @@ namespace osu.Game.Screens.Edit /// A that fires when users have made a change to the beatmap skin /// of the map being edited. /// - public class EditorSkinProvidingContainer : RulesetSkinProvidingContainer + public partial class EditorSkinProvidingContainer : RulesetSkinProvidingContainer { private readonly EditorBeatmapSkin? beatmapSkin; diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs index a290cce708..f97a8c5572 100644 --- a/osu.Game/Screens/Edit/EditorTable.cs +++ b/osu.Game/Screens/Edit/EditorTable.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit { - public abstract class EditorTable : TableContainer + public abstract partial class EditorTable : TableContainer { private const float horizontal_inset = 20; @@ -47,7 +47,7 @@ namespace osu.Game.Screens.Edit protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default); - private class HeaderText : OsuSpriteText + private partial class HeaderText : OsuSpriteText { public HeaderText(LocalisableString text) { @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Edit } } - public class RowBackground : OsuClickableContainer + public partial class RowBackground : OsuClickableContainer { public readonly object Item; diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs index ad09618279..e7db1c105b 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayer.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.Edit.GameplayTest { - public class EditorPlayer : Player + public partial class EditorPlayer : Player { private readonly Editor editor; private readonly EditorState editorState; diff --git a/osu.Game/Screens/Edit/GameplayTest/EditorPlayerLoader.cs b/osu.Game/Screens/Edit/GameplayTest/EditorPlayerLoader.cs index d3260f1e7d..a74d97cdc7 100644 --- a/osu.Game/Screens/Edit/GameplayTest/EditorPlayerLoader.cs +++ b/osu.Game/Screens/Edit/GameplayTest/EditorPlayerLoader.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.Edit.GameplayTest { - public class EditorPlayerLoader : PlayerLoader + public partial class EditorPlayerLoader : PlayerLoader { [Resolved] private OsuLogo osuLogo { get; set; } diff --git a/osu.Game/Screens/Edit/GameplayTest/SaveBeforeGameplayTestDialog.cs b/osu.Game/Screens/Edit/GameplayTest/SaveBeforeGameplayTestDialog.cs index 37e1c99d98..5a5572b508 100644 --- a/osu.Game/Screens/Edit/GameplayTest/SaveBeforeGameplayTestDialog.cs +++ b/osu.Game/Screens/Edit/GameplayTest/SaveBeforeGameplayTestDialog.cs @@ -9,7 +9,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Edit.GameplayTest { - public class SaveBeforeGameplayTestDialog : PopupDialog + public partial class SaveBeforeGameplayTestDialog : PopupDialog { public SaveBeforeGameplayTestDialog(Action saveAndPreview) { diff --git a/osu.Game/Screens/Edit/PromptForSaveDialog.cs b/osu.Game/Screens/Edit/PromptForSaveDialog.cs index 59a697d91c..2a2cd019ea 100644 --- a/osu.Game/Screens/Edit/PromptForSaveDialog.cs +++ b/osu.Game/Screens/Edit/PromptForSaveDialog.cs @@ -9,7 +9,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Edit { - public class PromptForSaveDialog : PopupDialog + public partial class PromptForSaveDialog : PopupDialog { public PromptForSaveDialog(Action exit, Action saveAndExit, Action cancel) { diff --git a/osu.Game/Screens/Edit/Setup/ColoursSection.cs b/osu.Game/Screens/Edit/Setup/ColoursSection.cs index e3fcdedd1b..10ab272a87 100644 --- a/osu.Game/Screens/Edit/Setup/ColoursSection.cs +++ b/osu.Game/Screens/Edit/Setup/ColoursSection.cs @@ -11,7 +11,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { - internal class ColoursSection : SetupSection + internal partial class ColoursSection : SetupSection { public override LocalisableString Title => EditorSetupStrings.ColoursHeader; diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index cc3e9b91ab..3428366510 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -17,7 +17,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { - internal class DesignSection : SetupSection + internal partial class DesignSection : SetupSection { protected LabelledSwitchButton EnableCountdown; diff --git a/osu.Game/Screens/Edit/Setup/DifficultySection.cs b/osu.Game/Screens/Edit/Setup/DifficultySection.cs index 01e31bd688..afe6b36cba 100644 --- a/osu.Game/Screens/Edit/Setup/DifficultySection.cs +++ b/osu.Game/Screens/Edit/Setup/DifficultySection.cs @@ -15,7 +15,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { - internal class DifficultySection : SetupSection + internal partial class DifficultySection : SetupSection { private LabelledSliderBar circleSizeSlider; private LabelledSliderBar healthDrainSlider; diff --git a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs index efc8b6978e..57d28824b1 100644 --- a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs +++ b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Edit.Setup /// A labelled drawable displaying file chooser on click, with placeholder text support. /// todo: this should probably not use PopoverTextBox just to display placeholder text, but is the best way for now. /// - internal class LabelledFileChooser : LabelledDrawable, IHasCurrentValue, ICanAcceptFiles, IHasPopover + internal partial class LabelledFileChooser : LabelledDrawable, IHasCurrentValue, ICanAcceptFiles, IHasPopover { private readonly string[] handledExtensions; @@ -112,7 +112,7 @@ namespace osu.Game.Screens.Edit.Setup public Popover GetPopover() => new FileChooserPopover(handledExtensions, Current, initialChooserPath); - private class FileChooserPopover : OsuPopover + private partial class FileChooserPopover : OsuPopover { public FileChooserPopover(string[] handledExtensions, Bindable currentFile, string? chooserPath) { diff --git a/osu.Game/Screens/Edit/Setup/LabelledRomanisedTextBox.cs b/osu.Game/Screens/Edit/Setup/LabelledRomanisedTextBox.cs index a9cf5357c8..43c20b5e40 100644 --- a/osu.Game/Screens/Edit/Setup/LabelledRomanisedTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/LabelledRomanisedTextBox.cs @@ -9,11 +9,11 @@ using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Screens.Edit.Setup { - internal class LabelledRomanisedTextBox : LabelledTextBox + internal partial class LabelledRomanisedTextBox : LabelledTextBox { protected override OsuTextBox CreateTextBox() => new RomanisedTextBox(); - private class RomanisedTextBox : OsuTextBox + private partial class RomanisedTextBox : OsuTextBox { protected override bool AllowIme => false; diff --git a/osu.Game/Screens/Edit/Setup/LabelledTextBoxWithPopover.cs b/osu.Game/Screens/Edit/Setup/LabelledTextBoxWithPopover.cs index 0eb74df575..05c8f88444 100644 --- a/osu.Game/Screens/Edit/Setup/LabelledTextBoxWithPopover.cs +++ b/osu.Game/Screens/Edit/Setup/LabelledTextBoxWithPopover.cs @@ -14,7 +14,7 @@ using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Screens.Edit.Setup { - internal abstract class LabelledTextBoxWithPopover : LabelledTextBox, IHasPopover + internal abstract partial class LabelledTextBoxWithPopover : LabelledTextBox, IHasPopover { public abstract Popover GetPopover(); @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Edit.Setup OnFocused = this.ShowPopover }; - internal class PopoverTextBox : OsuTextBox + internal partial class PopoverTextBox : OsuTextBox { public Action OnFocused; diff --git a/osu.Game/Screens/Edit/Setup/MetadataSection.cs b/osu.Game/Screens/Edit/Setup/MetadataSection.cs index 1da7a87f83..c2c853f7b2 100644 --- a/osu.Game/Screens/Edit/Setup/MetadataSection.cs +++ b/osu.Game/Screens/Edit/Setup/MetadataSection.cs @@ -14,7 +14,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { - public class MetadataSection : SetupSection + public partial class MetadataSection : SetupSection { protected LabelledTextBox ArtistTextBox; protected LabelledTextBox RomanisedArtistTextBox; diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index cbaa2d8b42..ca0f50cd34 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -14,7 +14,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { - internal class ResourcesSection : SetupSection + internal partial class ResourcesSection : SetupSection { private LabelledFileChooser audioTrackChooser; private LabelledFileChooser backgroundChooser; diff --git a/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs b/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs index d6664e860b..0914bd47bc 100644 --- a/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs +++ b/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs @@ -9,7 +9,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { - public abstract class RulesetSetupSection : SetupSection + public abstract partial class RulesetSetupSection : SetupSection { public sealed override LocalisableString Title => EditorSetupStrings.RulesetHeader(rulesetInfo.Name); diff --git a/osu.Game/Screens/Edit/Setup/SetupScreen.cs b/osu.Game/Screens/Edit/Setup/SetupScreen.cs index 036202a503..cc705547de 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreen.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreen.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays; namespace osu.Game.Screens.Edit.Setup { - public class SetupScreen : EditorScreen + public partial class SetupScreen : EditorScreen { [Cached] private SectionsContainer sections { get; } = new SetupScreenSectionsContainer(); @@ -55,7 +55,7 @@ namespace osu.Game.Screens.Edit.Setup })); } - private class SetupScreenSectionsContainer : SectionsContainer + private partial class SetupScreenSectionsContainer : SectionsContainer { protected override UserTrackingScrollContainer CreateScrollContainer() { diff --git a/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs b/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs index 9486b3728b..0a6643efeb 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreenHeader.cs @@ -16,7 +16,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { - internal class SetupScreenHeader : OverlayHeader + internal partial class SetupScreenHeader : OverlayHeader { public SetupScreenHeaderBackground Background { get; private set; } @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Edit.Setup }); } - private class SetupScreenTitle : OverlayTitle + private partial class SetupScreenTitle : OverlayTitle { public SetupScreenTitle() { @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Edit.Setup } } - internal class SetupScreenTabControl : OverlayTabControl + internal partial class SetupScreenTabControl : OverlayTabControl { private readonly Box background; @@ -111,7 +111,7 @@ namespace osu.Game.Screens.Edit.Setup AccentColour = AccentColour }; - private class SetupScreenTabItem : OverlayTabItem + private partial class SetupScreenTabItem : OverlayTabItem { public SetupScreenTabItem(SetupSection value) : base(value) diff --git a/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs b/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs index 5680d75f4e..50743476bf 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs @@ -15,7 +15,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Edit.Setup { - public class SetupScreenHeaderBackground : CompositeDrawable + public partial class SetupScreenHeaderBackground : CompositeDrawable { [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game/Screens/Edit/Setup/SetupSection.cs b/osu.Game/Screens/Edit/Setup/SetupSection.cs index 727a94a590..c7690623ad 100644 --- a/osu.Game/Screens/Edit/Setup/SetupSection.cs +++ b/osu.Game/Screens/Edit/Setup/SetupSection.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Setup { - public abstract class SetupSection : Container + public abstract partial class SetupSection : Container { private FillFlowContainer flow; diff --git a/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs b/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs index 1f95156aba..97bd84b1b6 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointSettings.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; namespace osu.Game.Screens.Edit.Timing { - public class ControlPointSettings : EditorRoundedScreenSettings + public partial class ControlPointSettings : EditorRoundedScreenSettings { protected override IReadOnlyList CreateSections() => new Drawable[] { diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index b51da2c53d..5c131c0b6d 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Timing { - public class ControlPointTable : EditorTable + public partial class ControlPointTable : EditorTable { [Resolved] private Bindable selectedGroup { get; set; } @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Edit.Timing }; } - private class ControlGroupAttributes : CompositeDrawable + private partial class ControlGroupAttributes : CompositeDrawable { private readonly Func matchFunction; diff --git a/osu.Game/Screens/Edit/Timing/EffectSection.cs b/osu.Game/Screens/Edit/Timing/EffectSection.cs index 9be663bb26..1f5400c03b 100644 --- a/osu.Game/Screens/Edit/Timing/EffectSection.cs +++ b/osu.Game/Screens/Edit/Timing/EffectSection.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.UI.Scrolling; namespace osu.Game.Screens.Edit.Timing { - internal class EffectSection : Section + internal partial class EffectSection : Section { private LabelledSwitchButton kiai; private LabelledSwitchButton omitBarLine; diff --git a/osu.Game/Screens/Edit/Timing/GroupSection.cs b/osu.Game/Screens/Edit/Timing/GroupSection.cs index e78cd18024..f36989cf32 100644 --- a/osu.Game/Screens/Edit/Timing/GroupSection.cs +++ b/osu.Game/Screens/Edit/Timing/GroupSection.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Timing { - internal class GroupSection : CompositeDrawable + internal partial class GroupSection : CompositeDrawable { private LabelledTextBox textBox; diff --git a/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs b/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs index ea6c6f31e4..36186353f8 100644 --- a/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs +++ b/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Edit.Timing /// where multiple objects with multiple different property values are selected /// by providing an "indeterminate state". /// - public class IndeterminateSliderWithTextBoxInput : CompositeDrawable, IHasCurrentValue + public partial class IndeterminateSliderWithTextBoxInput : CompositeDrawable, IHasCurrentValue where T : struct, IEquatable, IComparable, IConvertible { /// diff --git a/osu.Game/Screens/Edit/Timing/LabelledTimeSignature.cs b/osu.Game/Screens/Edit/Timing/LabelledTimeSignature.cs index 998e49a6ab..217aa46c3f 100644 --- a/osu.Game/Screens/Edit/Timing/LabelledTimeSignature.cs +++ b/osu.Game/Screens/Edit/Timing/LabelledTimeSignature.cs @@ -16,7 +16,7 @@ using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Screens.Edit.Timing { - public class LabelledTimeSignature : LabelledComponent + public partial class LabelledTimeSignature : LabelledComponent { public LabelledTimeSignature() : base(false) @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Edit.Timing protected override TimeSignatureBox CreateComponent() => new TimeSignatureBox(); - public class TimeSignatureBox : CompositeDrawable, IHasCurrentValue + public partial class TimeSignatureBox : CompositeDrawable, IHasCurrentValue { private readonly BindableWithCurrent current = new BindableWithCurrent(TimeSignature.SimpleQuadruple); diff --git a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs index 3895959982..dfe2ec1f17 100644 --- a/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/MetronomeDisplay.cs @@ -26,7 +26,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Timing { - public class MetronomeDisplay : BeatSyncedContainer + public partial class MetronomeDisplay : BeatSyncedContainer { private Container swing; diff --git a/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs b/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs index cd3ced53da..0b442fe5da 100644 --- a/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs +++ b/osu.Game/Screens/Edit/Timing/RepeatingButtonBehaviour.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Edit.Timing /// /// Represents a component that provides the behaviour of triggering button clicks repeatedly while holding with mouse. /// - public class RepeatingButtonBehaviour : Component + public partial class RepeatingButtonBehaviour : Component { private const double initial_delay = 300; private const double minimum_delay = 80; diff --git a/osu.Game/Screens/Edit/Timing/RowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttribute.cs index e73a343583..6f0553c771 100644 --- a/osu.Game/Screens/Edit/Timing/RowAttribute.cs +++ b/osu.Game/Screens/Edit/Timing/RowAttribute.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Timing { - public class RowAttribute : CompositeDrawable + public partial class RowAttribute : CompositeDrawable { protected readonly ControlPoint Point; diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeProgressBar.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeProgressBar.cs index a8d2172f58..49791bd99a 100644 --- a/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeProgressBar.cs +++ b/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeProgressBar.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Timing.RowAttributes { - public class AttributeProgressBar : ProgressBar + public partial class AttributeProgressBar : ProgressBar { private readonly ControlPoint controlPoint; diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeText.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeText.cs index d65ef1799a..c9d7aab5d8 100644 --- a/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeText.cs +++ b/osu.Game/Screens/Edit/Timing/RowAttributes/AttributeText.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Edit.Timing.RowAttributes { - public class AttributeText : OsuSpriteText + public partial class AttributeText : OsuSpriteText { private readonly ControlPoint controlPoint; diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/DifficultyRowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/DifficultyRowAttribute.cs index 17f8b01d07..4d3704d44a 100644 --- a/osu.Game/Screens/Edit/Timing/RowAttributes/DifficultyRowAttribute.cs +++ b/osu.Game/Screens/Edit/Timing/RowAttributes/DifficultyRowAttribute.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Edit.Timing.RowAttributes { - public class DifficultyRowAttribute : RowAttribute + public partial class DifficultyRowAttribute : RowAttribute { private readonly BindableNumber speedMultiplier; diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/EffectRowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/EffectRowAttribute.cs index ef682dd3ad..88943e5578 100644 --- a/osu.Game/Screens/Edit/Timing/RowAttributes/EffectRowAttribute.cs +++ b/osu.Game/Screens/Edit/Timing/RowAttributes/EffectRowAttribute.cs @@ -10,7 +10,7 @@ using osu.Game.Beatmaps.ControlPoints; namespace osu.Game.Screens.Edit.Timing.RowAttributes { - public class EffectRowAttribute : RowAttribute + public partial class EffectRowAttribute : RowAttribute { private readonly Bindable kiaiMode; private readonly Bindable omitBarLine; diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/SampleRowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/SampleRowAttribute.cs index e06f6b7bfb..915cf63baa 100644 --- a/osu.Game/Screens/Edit/Timing/RowAttributes/SampleRowAttribute.cs +++ b/osu.Game/Screens/Edit/Timing/RowAttributes/SampleRowAttribute.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Edit.Timing.RowAttributes { - public class SampleRowAttribute : RowAttribute + public partial class SampleRowAttribute : RowAttribute { private AttributeText sampleText; private OsuSpriteText volumeText; diff --git a/osu.Game/Screens/Edit/Timing/RowAttributes/TimingRowAttribute.cs b/osu.Game/Screens/Edit/Timing/RowAttributes/TimingRowAttribute.cs index 0b498650d4..3887282c6a 100644 --- a/osu.Game/Screens/Edit/Timing/RowAttributes/TimingRowAttribute.cs +++ b/osu.Game/Screens/Edit/Timing/RowAttributes/TimingRowAttribute.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; namespace osu.Game.Screens.Edit.Timing.RowAttributes { - public class TimingRowAttribute : RowAttribute + public partial class TimingRowAttribute : RowAttribute { private readonly BindableNumber beatLength; private readonly Bindable timeSignature; diff --git a/osu.Game/Screens/Edit/Timing/Section.cs b/osu.Game/Screens/Edit/Timing/Section.cs index 02789c0cbf..ebba481099 100644 --- a/osu.Game/Screens/Edit/Timing/Section.cs +++ b/osu.Game/Screens/Edit/Timing/Section.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Timing { - internal abstract class Section : CompositeDrawable + internal abstract partial class Section : CompositeDrawable where T : ControlPoint { private OsuCheckbox checkbox; diff --git a/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs b/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs index 4dcb5ad2ba..e1a5c3b23c 100644 --- a/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs +++ b/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Timing { - public class SliderWithTextBoxInput : CompositeDrawable, IHasCurrentValue + public partial class SliderWithTextBoxInput : CompositeDrawable, IHasCurrentValue where T : struct, IEquatable, IComparable, IConvertible { private readonly SettingsSlider slider; diff --git a/osu.Game/Screens/Edit/Timing/TapButton.cs b/osu.Game/Screens/Edit/Timing/TapButton.cs index 2944eea4fe..af5e6aa180 100644 --- a/osu.Game/Screens/Edit/Timing/TapButton.cs +++ b/osu.Game/Screens/Edit/Timing/TapButton.cs @@ -28,7 +28,7 @@ using osuTK.Input; namespace osu.Game.Screens.Edit.Timing { - internal class TapButton : CircularContainer, IKeyBindingHandler + internal partial class TapButton : CircularContainer, IKeyBindingHandler { public const float SIZE = 140; @@ -343,7 +343,7 @@ namespace osu.Game.Screens.Edit.Timing IsHandlingTapping.Value = false; } - private class Light : CompositeDrawable + private partial class Light : CompositeDrawable { public Drawable Glow { get; private set; } = null!; diff --git a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs index 3b26e335d9..09b3851333 100644 --- a/osu.Game/Screens/Edit/Timing/TapTimingControl.cs +++ b/osu.Game/Screens/Edit/Timing/TapTimingControl.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Timing { - public class TapTimingControl : CompositeDrawable + public partial class TapTimingControl : CompositeDrawable { [Resolved] private EditorClock editorClock { get; set; } = null!; @@ -233,7 +233,7 @@ namespace osu.Game.Screens.Edit.Timing timing.BeatLength = 60000 / (timing.BPM + adjust); } - private class InlineButton : OsuButton + private partial class InlineButton : OsuButton { private readonly IconUsage icon; private readonly Anchor anchor; diff --git a/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs b/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs index 16dea328da..4018eff5d6 100644 --- a/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs +++ b/osu.Game/Screens/Edit/Timing/TimingAdjustButton.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Edit.Timing /// /// A button with variable constant output based on hold position and length. /// - public class TimingAdjustButton : CompositeDrawable + public partial class TimingAdjustButton : CompositeDrawable { public Action Action; @@ -112,7 +112,7 @@ namespace osu.Game.Screens.Edit.Timing return true; } - private class IncrementBox : CompositeDrawable + private partial class IncrementBox : CompositeDrawable { public readonly float Multiplier; diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index fd218209d4..43fca40526 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Timing { - public class TimingScreen : EditorScreenWithTimeline + public partial class TimingScreen : EditorScreenWithTimeline { [Cached] public readonly Bindable SelectedGroup = new Bindable(); @@ -48,7 +48,7 @@ namespace osu.Game.Screens.Edit.Timing } }; - public class ControlPointList : CompositeDrawable + public partial class ControlPointList : CompositeDrawable { private OsuButton deleteButton; private ControlPointTable table; diff --git a/osu.Game/Screens/Edit/Timing/TimingSection.cs b/osu.Game/Screens/Edit/Timing/TimingSection.cs index 9b86969db1..81abb266d4 100644 --- a/osu.Game/Screens/Edit/Timing/TimingSection.cs +++ b/osu.Game/Screens/Edit/Timing/TimingSection.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Screens.Edit.Timing { - internal class TimingSection : Section + internal partial class TimingSection : Section { private LabelledTimeSignature timeSignature; private BPMTextBox bpmTextEntry; @@ -69,7 +69,7 @@ namespace osu.Game.Screens.Edit.Timing }; } - private class BPMTextBox : LabelledTextBox + private partial class BPMTextBox : LabelledTextBox { private readonly BindableNumber beatLengthBindable = new TimingControlPoint().BeatLengthBindable; diff --git a/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs b/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs index 2956a28547..6c17aeed54 100644 --- a/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs +++ b/osu.Game/Screens/Edit/Timing/WaveformComparisonDisplay.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Edit.Timing { - internal class WaveformComparisonDisplay : CompositeDrawable + internal partial class WaveformComparisonDisplay : CompositeDrawable { private const int total_waveforms = 8; @@ -222,7 +222,7 @@ namespace osu.Game.Screens.Edit.Timing } } - internal class LockedOverlay : CompositeDrawable + internal partial class LockedOverlay : CompositeDrawable { private OsuSpriteText text = null!; @@ -285,7 +285,7 @@ namespace osu.Game.Screens.Edit.Timing } } - internal class WaveformRow : CompositeDrawable + internal partial class WaveformRow : CompositeDrawable { private readonly bool isMainRow; private OsuSpriteText beatIndexText = null!; diff --git a/osu.Game/Screens/Edit/TransactionalCommitComponent.cs b/osu.Game/Screens/Edit/TransactionalCommitComponent.cs index 78d052702a..55c9cf86c3 100644 --- a/osu.Game/Screens/Edit/TransactionalCommitComponent.cs +++ b/osu.Game/Screens/Edit/TransactionalCommitComponent.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Edit /// /// A component that tracks a batch change, only applying after all active changes are completed. /// - public abstract class TransactionalCommitComponent : Component + public abstract partial class TransactionalCommitComponent : Component { /// /// Fires whenever a transaction begins. Will not fire on nested transactions. diff --git a/osu.Game/Screens/Edit/Verify/InterpretationSection.cs b/osu.Game/Screens/Edit/Verify/InterpretationSection.cs index 276c2a3ea9..5b6eea098c 100644 --- a/osu.Game/Screens/Edit/Verify/InterpretationSection.cs +++ b/osu.Game/Screens/Edit/Verify/InterpretationSection.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Screens.Edit.Verify { - internal class InterpretationSection : EditorRoundedScreenSettingsSection + internal partial class InterpretationSection : EditorRoundedScreenSettingsSection { protected override string HeaderText => "Interpretation"; diff --git a/osu.Game/Screens/Edit/Verify/IssueList.cs b/osu.Game/Screens/Edit/Verify/IssueList.cs index bffda4ec41..907949aee8 100644 --- a/osu.Game/Screens/Edit/Verify/IssueList.cs +++ b/osu.Game/Screens/Edit/Verify/IssueList.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Screens.Edit.Verify { [Cached] - public class IssueList : CompositeDrawable + public partial class IssueList : CompositeDrawable { private IssueTable table; diff --git a/osu.Game/Screens/Edit/Verify/IssueSettings.cs b/osu.Game/Screens/Edit/Verify/IssueSettings.cs index 70065f6f0d..e8275c3684 100644 --- a/osu.Game/Screens/Edit/Verify/IssueSettings.cs +++ b/osu.Game/Screens/Edit/Verify/IssueSettings.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics; namespace osu.Game.Screens.Edit.Verify { - public class IssueSettings : EditorRoundedScreenSettings + public partial class IssueSettings : EditorRoundedScreenSettings { protected override IReadOnlyList CreateSections() => new Drawable[] { diff --git a/osu.Game/Screens/Edit/Verify/IssueTable.cs b/osu.Game/Screens/Edit/Verify/IssueTable.cs index f1a76dcbf5..6fdf9c76e2 100644 --- a/osu.Game/Screens/Edit/Verify/IssueTable.cs +++ b/osu.Game/Screens/Edit/Verify/IssueTable.cs @@ -18,7 +18,7 @@ using osu.Game.Rulesets.Edit.Checks.Components; namespace osu.Game.Screens.Edit.Verify { - public class IssueTable : EditorTable + public partial class IssueTable : EditorTable { [Resolved] private VerifyScreen verify { get; set; } diff --git a/osu.Game/Screens/Edit/Verify/VerifyScreen.cs b/osu.Game/Screens/Edit/Verify/VerifyScreen.cs index 3030018138..b17cf3379e 100644 --- a/osu.Game/Screens/Edit/Verify/VerifyScreen.cs +++ b/osu.Game/Screens/Edit/Verify/VerifyScreen.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.Edit.Checks.Components; namespace osu.Game.Screens.Edit.Verify { [Cached] - public class VerifyScreen : EditorScreen + public partial class VerifyScreen : EditorScreen { public readonly Bindable SelectedIssue = new Bindable(); diff --git a/osu.Game/Screens/Edit/Verify/VisibilitySection.cs b/osu.Game/Screens/Edit/Verify/VisibilitySection.cs index fbf6982984..e2e2e518ae 100644 --- a/osu.Game/Screens/Edit/Verify/VisibilitySection.cs +++ b/osu.Game/Screens/Edit/Verify/VisibilitySection.cs @@ -11,7 +11,7 @@ using osu.Game.Rulesets.Edit.Checks.Components; namespace osu.Game.Screens.Edit.Verify { - internal class VisibilitySection : EditorRoundedScreenSettingsSection + internal partial class VisibilitySection : EditorRoundedScreenSettingsSection { private readonly IssueType[] configurableIssueTypes = { diff --git a/osu.Game/Screens/Import/FileImportScreen.cs b/osu.Game/Screens/Import/FileImportScreen.cs index e3d8de2dfd..dde4e9c326 100644 --- a/osu.Game/Screens/Import/FileImportScreen.cs +++ b/osu.Game/Screens/Import/FileImportScreen.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Screens.Import { - public class FileImportScreen : OsuScreen + public partial class FileImportScreen : OsuScreen { public override bool HideOverlaysOnEnter => true; diff --git a/osu.Game/Screens/Loader.cs b/osu.Game/Screens/Loader.cs index ac22fdce71..b70c1f7ddf 100644 --- a/osu.Game/Screens/Loader.cs +++ b/osu.Game/Screens/Loader.cs @@ -19,7 +19,7 @@ using IntroSequence = osu.Game.Configuration.IntroSequence; namespace osu.Game.Screens { - public class Loader : StartupScreen + public partial class Loader : StartupScreen { private bool showDisclaimer; @@ -116,7 +116,7 @@ namespace osu.Game.Screens /// /// Compiles a set of shaders before continuing. Attempts to draw some frames between compilation by limiting to one compile per draw frame. /// - public class ShaderPrecompiler : Drawable + public partial class ShaderPrecompiler : Drawable { private readonly List loadTargets = new List(); diff --git a/osu.Game/Screens/Menu/ButtonArea.cs b/osu.Game/Screens/Menu/ButtonArea.cs index bf6e0cee83..69ba68442f 100644 --- a/osu.Game/Screens/Menu/ButtonArea.cs +++ b/osu.Game/Screens/Menu/ButtonArea.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Screens.Menu { - public class ButtonArea : Container, IStateful + public partial class ButtonArea : Container, IStateful { public FlowContainerWithOrigin Flow; @@ -90,7 +90,7 @@ namespace osu.Game.Screens.Menu public event Action StateChanged; - private class ButtonAreaBackground : Box, IStateful + private partial class ButtonAreaBackground : Box, IStateful { private ButtonAreaBackgroundState state; diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 04bffda81b..2ead18c3d6 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -34,7 +34,7 @@ using osuTK.Input; namespace osu.Game.Screens.Menu { - public class ButtonSystem : Container, IStateful, IKeyBindingHandler + public partial class ButtonSystem : Container, IStateful, IKeyBindingHandler { public event Action StateChanged; diff --git a/osu.Game/Screens/Menu/ConfirmDiscardChangesDialog.cs b/osu.Game/Screens/Menu/ConfirmDiscardChangesDialog.cs index 450c559450..0cd3e9ce71 100644 --- a/osu.Game/Screens/Menu/ConfirmDiscardChangesDialog.cs +++ b/osu.Game/Screens/Menu/ConfirmDiscardChangesDialog.cs @@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Menu { - public class ConfirmDiscardChangesDialog : PopupDialog + public partial class ConfirmDiscardChangesDialog : PopupDialog { /// /// Construct a new discard changes confirmation dialog. diff --git a/osu.Game/Screens/Menu/ConfirmExitDialog.cs b/osu.Game/Screens/Menu/ConfirmExitDialog.cs index 20fa889986..4906232d21 100644 --- a/osu.Game/Screens/Menu/ConfirmExitDialog.cs +++ b/osu.Game/Screens/Menu/ConfirmExitDialog.cs @@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Menu { - public class ConfirmExitDialog : PopupDialog + public partial class ConfirmExitDialog : PopupDialog { /// /// Construct a new exit confirmation dialog. diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index a81658a4b6..e30be72704 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -22,7 +22,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Menu { - public class Disclaimer : StartupScreen + public partial class Disclaimer : StartupScreen { private SpriteIcon icon; private Color4 iconColour; diff --git a/osu.Game/Screens/Menu/ExitConfirmOverlay.cs b/osu.Game/Screens/Menu/ExitConfirmOverlay.cs index f82a6c9736..bc2f6ea00f 100644 --- a/osu.Game/Screens/Menu/ExitConfirmOverlay.cs +++ b/osu.Game/Screens/Menu/ExitConfirmOverlay.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays; namespace osu.Game.Screens.Menu { - public class ExitConfirmOverlay : HoldToConfirmOverlay, IKeyBindingHandler + public partial class ExitConfirmOverlay : HoldToConfirmOverlay, IKeyBindingHandler { protected override bool AllowMultipleFires => true; diff --git a/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs b/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs index 24a365ffd1..e36cc4a152 100644 --- a/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs +++ b/osu.Game/Screens/Menu/FlowContainerWithOrigin.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.Menu /// /// A flow container with an origin based on one of its contained drawables. /// - public class FlowContainerWithOrigin : FillFlowContainer + public partial class FlowContainerWithOrigin : FillFlowContainer { /// /// A target drawable which this flowcontainer should be centered around. diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs index 7a4bdb231f..57a3fd9c38 100644 --- a/osu.Game/Screens/Menu/IntroCircles.cs +++ b/osu.Game/Screens/Menu/IntroCircles.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics; namespace osu.Game.Screens.Menu { - public class IntroCircles : IntroScreen + public partial class IntroCircles : IntroScreen { protected override string BeatmapHash => "3c8b1fcc9434dbb29e2fb613d3b9eada9d7bb6c125ceb32396c3b53437280c83"; diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index dcead4a3a8..f632d9ee73 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -32,7 +32,7 @@ using Realms; namespace osu.Game.Screens.Menu { - public abstract class IntroScreen : StartupScreen + public abstract partial class IntroScreen : StartupScreen { /// /// Whether we have loaded the menu previously. diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs index bc5aa83503..722f884ac5 100644 --- a/osu.Game/Screens/Menu/IntroSequence.cs +++ b/osu.Game/Screens/Menu/IntroSequence.cs @@ -16,7 +16,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Menu { - public class IntroSequence : Container + public partial class IntroSequence : Container { private const float logo_size = 460; //todo: this should probably be 480 @@ -266,7 +266,7 @@ namespace osu.Game.Screens.Menu } } - private class Ring : Container + private partial class Ring : Container { public readonly Circle Foreground; diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 4ec877b85a..a9c86b10c4 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -25,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Menu { - public class IntroTriangles : IntroScreen + public partial class IntroTriangles : IntroScreen { protected override string BeatmapHash => "a1556d0801b3a6b175dda32ef546f0ec812b400499f575c44fccbe9c67f9b1e5"; @@ -107,7 +107,7 @@ namespace osu.Game.Screens.Menu intro.Expire(); } - private class TrianglesIntroSequence : CompositeDrawable + private partial class TrianglesIntroSequence : CompositeDrawable { private readonly OsuLogo logo; private readonly Action showBackgroundAction; @@ -269,7 +269,7 @@ namespace osu.Game.Screens.Menu } } - private class GameWideFlash : Box + private partial class GameWideFlash : Box { private const double flash_length = 1000; @@ -287,7 +287,7 @@ namespace osu.Game.Screens.Menu } } - private class LazerLogo : CompositeDrawable + private partial class LazerLogo : CompositeDrawable { private LogoAnimation highlight, background; @@ -327,7 +327,7 @@ namespace osu.Game.Screens.Menu } } - private class RulesetFlow : FillFlowContainer + private partial class RulesetFlow : FillFlowContainer { [BackgroundDependencyLoader] private void load(RulesetStore rulesets) @@ -357,7 +357,7 @@ namespace osu.Game.Screens.Menu } } - private class GlitchingTriangles : CompositeDrawable + private partial class GlitchingTriangles : CompositeDrawable { public GlitchingTriangles() { @@ -391,7 +391,7 @@ namespace osu.Game.Screens.Menu /// /// Represents a sprite that is drawn in a triangle shape, instead of a rectangle shape. /// - public class OutlineTriangle : BufferedContainer + public partial class OutlineTriangle : BufferedContainer { public OutlineTriangle(bool outlineOnly, float size) : base(cachedFrameBuffer: true) diff --git a/osu.Game/Screens/Menu/IntroWelcome.cs b/osu.Game/Screens/Menu/IntroWelcome.cs index 5ae2158172..da44161507 100644 --- a/osu.Game/Screens/Menu/IntroWelcome.cs +++ b/osu.Game/Screens/Menu/IntroWelcome.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Menu { - public class IntroWelcome : IntroScreen + public partial class IntroWelcome : IntroScreen { protected override string BeatmapHash => "64e00d7022195959bfa3109d09c2e2276c8f12f486b91fcf6175583e973b48f2"; protected override string BeatmapFile => "welcome.osz"; @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Menu } } - private class WelcomeIntroSequence : Container + private partial class WelcomeIntroSequence : Container { private Drawable welcomeText; private Container scaleContainer; diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index 4a20d7cb2b..c67850bdf6 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Menu /// /// A visualiser that reacts to music coming from beatmaps. /// - public class LogoVisualisation : Drawable + public partial class LogoVisualisation : Drawable { /// /// The number of bars to jump each update iteration. diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 0071ada05a..69b8596474 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -32,7 +32,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Menu { - public class MainMenu : OsuScreen, IHandlePresentBeatmap, IKeyBindingHandler + public partial class MainMenu : OsuScreen, IHandlePresentBeatmap, IKeyBindingHandler { public const float FADE_IN_DURATION = 300; diff --git a/osu.Game/Screens/Menu/MainMenuButton.cs b/osu.Game/Screens/Menu/MainMenuButton.cs index f2b57b185e..cd3795711e 100644 --- a/osu.Game/Screens/Menu/MainMenuButton.cs +++ b/osu.Game/Screens/Menu/MainMenuButton.cs @@ -30,7 +30,7 @@ namespace osu.Game.Screens.Menu /// Button designed specifically for the osu!next main menu. /// In order to correctly flow, we have to use a negative margin on the parent container (due to the parallelogram shape). /// - public class MainMenuButton : BeatSyncedContainer, IStateful + public partial class MainMenuButton : BeatSyncedContainer, IStateful { public event Action StateChanged; diff --git a/osu.Game/Screens/Menu/MenuLogoVisualisation.cs b/osu.Game/Screens/Menu/MenuLogoVisualisation.cs index 4324f02c84..f4e992be9a 100644 --- a/osu.Game/Screens/Menu/MenuLogoVisualisation.cs +++ b/osu.Game/Screens/Menu/MenuLogoVisualisation.cs @@ -12,7 +12,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Screens.Menu { - internal class MenuLogoVisualisation : LogoVisualisation + internal partial class MenuLogoVisualisation : LogoVisualisation { private IBindable user; private Bindable skin; diff --git a/osu.Game/Screens/Menu/MenuSideFlashes.cs b/osu.Game/Screens/Menu/MenuSideFlashes.cs index 5214d87ee9..533c39826c 100644 --- a/osu.Game/Screens/Menu/MenuSideFlashes.cs +++ b/osu.Game/Screens/Menu/MenuSideFlashes.cs @@ -22,7 +22,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Screens.Menu { - public class MenuSideFlashes : BeatSyncedContainer + public partial class MenuSideFlashes : BeatSyncedContainer { private readonly IBindable beatmap = new Bindable(); diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs index 3efd74d2c8..2d6a0736e9 100644 --- a/osu.Game/Screens/Menu/OsuLogo.cs +++ b/osu.Game/Screens/Menu/OsuLogo.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Menu /// /// osu! logo and its attachments (pulsing, visualiser etc.) /// - public class OsuLogo : BeatSyncedContainer + public partial class OsuLogo : BeatSyncedContainer { public readonly Color4 OsuPink = Color4Extensions.FromHex(@"e967a1"); diff --git a/osu.Game/Screens/Menu/SongTicker.cs b/osu.Game/Screens/Menu/SongTicker.cs index 6574c9a696..bac7e15461 100644 --- a/osu.Game/Screens/Menu/SongTicker.cs +++ b/osu.Game/Screens/Menu/SongTicker.cs @@ -15,7 +15,7 @@ using osu.Game.Beatmaps; namespace osu.Game.Screens.Menu { - public class SongTicker : Container + public partial class SongTicker : Container { private const int fade_duration = 800; diff --git a/osu.Game/Screens/Menu/StorageErrorDialog.cs b/osu.Game/Screens/Menu/StorageErrorDialog.cs index 28ef413179..ba05ad8b76 100644 --- a/osu.Game/Screens/Menu/StorageErrorDialog.cs +++ b/osu.Game/Screens/Menu/StorageErrorDialog.cs @@ -12,7 +12,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Menu { - public class StorageErrorDialog : PopupDialog + public partial class StorageErrorDialog : PopupDialog { [Resolved] private IDialogOverlay dialogOverlay { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs index 39a887f820..ebcc08360e 100644 --- a/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs +++ b/osu.Game/Screens/OnlinePlay/Components/BeatmapTitle.cs @@ -13,7 +13,7 @@ using osu.Game.Online.Chat; namespace osu.Game.Screens.OnlinePlay.Components { - public class BeatmapTitle : OnlinePlayComposite + public partial class BeatmapTitle : OnlinePlayComposite { private readonly LinkFlowContainer textFlow; diff --git a/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs b/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs index 22839ab4d4..3f7f38f3bc 100644 --- a/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs +++ b/osu.Game/Screens/OnlinePlay/Components/DisableableTabControl.cs @@ -9,7 +9,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Screens.OnlinePlay.Components { - public abstract class DisableableTabControl : TabControl + public abstract partial class DisableableTabControl : TabControl { public readonly BindableBool Enabled = new BindableBool(true); @@ -20,7 +20,7 @@ namespace osu.Game.Screens.OnlinePlay.Components base.AddTabItem(tab, addToDropdown); } - protected abstract class DisableableTabItem : TabItem + protected abstract partial class DisableableTabItem : TabItem { protected DisableableTabItem(T value) : base(value) diff --git a/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs b/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs index c97e52c247..77e461ce41 100644 --- a/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs +++ b/osu.Game/Screens/OnlinePlay/Components/DrawableGameType.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Components { - public class DrawableGameType : CircularContainer, IHasTooltip + public partial class DrawableGameType : CircularContainer, IHasTooltip { private readonly MatchType type; @@ -132,7 +132,7 @@ namespace osu.Game.Screens.OnlinePlay.Components } } - private class VersusRow : FillFlowContainer + private partial class VersusRow : FillFlowContainer { public VersusRow(Color4 first, Color4 second, float size) { diff --git a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs index 1ea84b60b9..c296e2a86b 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.OnlinePlay.Components /// /// A that polls for the lounge listing. /// - public class ListingPollingComponent : RoomPollingComponent + public partial class ListingPollingComponent : RoomPollingComponent { public IBindable InitialRoomsReceived => initialRoomsReceived; private readonly Bindable initialRoomsReceived = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs index 9a48769405..b2a8575c3d 100644 --- a/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs +++ b/osu.Game/Screens/OnlinePlay/Components/MatchBeatmapDetailArea.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Components { - public class MatchBeatmapDetailArea : BeatmapDetailArea + public partial class MatchBeatmapDetailArea : BeatmapDetailArea { public Action CreateNewItem; diff --git a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs index 8c65649cc6..014473dfee 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Components { - public abstract class OnlinePlayBackgroundScreen : BackgroundScreen + public abstract partial class OnlinePlayBackgroundScreen : BackgroundScreen { private CancellationTokenSource? cancellationSource; private PlaylistItemBackground? background; diff --git a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs index fe89eaf591..0d4cd30090 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs @@ -10,7 +10,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Components { - public class OnlinePlayBackgroundSprite : OnlinePlayComposite + public partial class OnlinePlayBackgroundSprite : OnlinePlayComposite { protected readonly BeatmapSetCoverType BeatmapSetCoverType; private UpdateableBeatmapBackgroundSprite sprite; diff --git a/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs b/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs index b953136fdd..0e2ce6703f 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OverlinedHeader.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.OnlinePlay.Components /// /// A header used in the multiplayer interface which shows text / details beneath a line. /// - public class OverlinedHeader : OnlinePlayComposite + public partial class OverlinedHeader : OnlinePlayComposite { private bool showLine = true; diff --git a/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs b/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs index a268d4d917..f8dcd7b75d 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OverlinedPlaylistHeader.cs @@ -7,7 +7,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Components { - public class OverlinedPlaylistHeader : OverlinedHeader + public partial class OverlinedPlaylistHeader : OverlinedHeader { public OverlinedPlaylistHeader() : base("Playlist") diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs index 71b33bf247..9f7e700ab3 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantCountDisplay.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.OnlinePlay.Components { - public class ParticipantCountDisplay : OnlinePlayComposite + public partial class ParticipantCountDisplay : OnlinePlayComposite { private const float text_size = 30; private const float transition_duration = 100; diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs index c66ae8b6d5..4fdf41d0f7 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantsDisplay.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Screens.OnlinePlay.Components { - public class ParticipantsDisplay : OnlinePlayComposite + public partial class ParticipantsDisplay : OnlinePlayComposite { public Bindable Details = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs index 2f38321e13..00f0889cc8 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ParticipantsList.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Components { - public class ParticipantsList : OnlinePlayComposite + public partial class ParticipantsList : OnlinePlayComposite { public const float TILE_SIZE = 35; @@ -92,7 +92,7 @@ namespace osu.Game.Screens.OnlinePlay.Components }); } - private class UserTile : CompositeDrawable + private partial class UserTile : CompositeDrawable { public APIUser User { diff --git a/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs b/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs index d882b3d97f..997ba6b639 100644 --- a/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs +++ b/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs @@ -9,7 +9,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Components { - public class PlaylistItemBackground : Background + public partial class PlaylistItemBackground : Background { public readonly IBeatmapInfo? Beatmap; diff --git a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs index 0871fc9a72..81ed88b8a3 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs @@ -13,7 +13,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Components { - public abstract class ReadyButton : TriangleButton, IHasTooltip + public abstract partial class ReadyButton : TriangleButton, IHasTooltip { public new readonly BindableBool Enabled = new BindableBool(); diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomLocalUserInfo.cs b/osu.Game/Screens/OnlinePlay/Components/RoomLocalUserInfo.cs index cc517ca080..0c3b53266c 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomLocalUserInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomLocalUserInfo.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.OnlinePlay.Components { - public class RoomLocalUserInfo : OnlinePlayComposite + public partial class RoomLocalUserInfo : OnlinePlayComposite { private OsuSpriteText attemptDisplay; diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs index 35dc251e4d..539d5b74b3 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs @@ -17,7 +17,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Components { - public class RoomManager : Component, IRoomManager + public partial class RoomManager : Component, IRoomManager { public event Action RoomsUpdated; diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs index 039e1d92b7..395a77b9e6 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs @@ -9,7 +9,7 @@ using osu.Game.Online.API; namespace osu.Game.Screens.OnlinePlay.Components { - public abstract class RoomPollingComponent : PollingComponent + public abstract partial class RoomPollingComponent : PollingComponent { [Resolved] protected IAPIProvider API { get; private set; } diff --git a/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs index 3b8ba739d9..780ee29e41 100644 --- a/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.OnlinePlay.Components /// /// A that polls for the currently-selected room. /// - public class SelectionPollingComponent : RoomPollingComponent + public partial class SelectionPollingComponent : RoomPollingComponent { private readonly Room room; diff --git a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs index b6ef080e44..93c8faf0b0 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Components { - public class StarRatingRangeDisplay : OnlinePlayComposite + public partial class StarRatingRangeDisplay : OnlinePlayComposite { [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs b/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs index 6122e7ec5e..ed39021a73 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs @@ -12,7 +12,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Components { - public class StatusColouredContainer : Container + public partial class StatusColouredContainer : Container { private readonly double transitionDuration; diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs index ed554ebd34..f5477837b0 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylist.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.OnlinePlay /// /// A scrollable list which displays the s in a . /// - public class DrawableRoomPlaylist : OsuRearrangeableListContainer, IKeyBindingHandler + public partial class DrawableRoomPlaylist : OsuRearrangeableListContainer, IKeyBindingHandler { /// /// The currently-selected item. Selection is visually represented with a border. diff --git a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs index bda616d5c3..3fab0fc180 100644 --- a/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs +++ b/osu.Game/Screens/OnlinePlay/DrawableRoomPlaylistItem.cs @@ -42,7 +42,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay { - public class DrawableRoomPlaylistItem : OsuRearrangeableListItem, IHasContextMenu + public partial class DrawableRoomPlaylistItem : OsuRearrangeableListItem, IHasContextMenu { public const float HEIGHT = 50; @@ -512,7 +512,7 @@ namespace osu.Game.Screens.OnlinePlay } } - public class PlaylistEditButton : GrayButton + public partial class PlaylistEditButton : GrayButton { public PlaylistEditButton() : base(FontAwesome.Solid.Edit) @@ -520,7 +520,7 @@ namespace osu.Game.Screens.OnlinePlay } } - public class PlaylistRemoveButton : GrayButton + public partial class PlaylistRemoveButton : GrayButton { public PlaylistRemoveButton() : base(FontAwesome.Solid.MinusSquare) @@ -528,7 +528,7 @@ namespace osu.Game.Screens.OnlinePlay } } - private sealed class PlaylistDownloadButton : BeatmapDownloadButton + private sealed partial class PlaylistDownloadButton : BeatmapDownloadButton { private readonly IBeatmapInfo beatmap; @@ -586,7 +586,7 @@ namespace osu.Game.Screens.OnlinePlay } // For now, this is the same implementation as in PanelBackground, but supports a beatmap info rather than a working beatmap - private class PanelBackground : Container // todo: should be a buffered container (https://github.com/ppy/osu-framework/issues/3222) + private partial class PanelBackground : Container // todo: should be a buffered container (https://github.com/ppy/osu-framework/issues/3222) { public readonly Bindable Beatmap = new Bindable(); @@ -641,7 +641,7 @@ namespace osu.Game.Screens.OnlinePlay } } - private class OwnerAvatar : UpdateableAvatar, IHasTooltip + private partial class OwnerAvatar : UpdateableAvatar, IHasTooltip { public OwnerAvatar() { @@ -654,7 +654,7 @@ namespace osu.Game.Screens.OnlinePlay public LocalisableString TooltipText => User == null ? string.Empty : $"queued by {User.Username}"; - private class TooltipArea : Component, IHasTooltip + private partial class TooltipArea : Component, IHasTooltip { private readonly OwnerAvatar avatar; diff --git a/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs b/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs index 9e589b362b..98f3df525d 100644 --- a/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs +++ b/osu.Game/Screens/OnlinePlay/FooterButtonFreeMods.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay { - public class FooterButtonFreeMods : FooterButton, IHasCurrentValue> + public partial class FooterButtonFreeMods : FooterButton, IHasCurrentValue> { public Bindable> Current { diff --git a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs index 0f02692eda..6313d907a5 100644 --- a/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/FreeModSelectOverlay.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Screens.OnlinePlay { - public class FreeModSelectOverlay : ModSelectOverlay + public partial class FreeModSelectOverlay : ModSelectOverlay { protected override bool ShowTotalMultiplier => false; diff --git a/osu.Game/Screens/OnlinePlay/Header.cs b/osu.Game/Screens/OnlinePlay/Header.cs index a9e9f046e2..4c4851c3ac 100644 --- a/osu.Game/Screens/OnlinePlay/Header.cs +++ b/osu.Game/Screens/OnlinePlay/Header.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay { - public class Header : Container + public partial class Header : Container { public const float HEIGHT = 80; @@ -44,7 +44,7 @@ namespace osu.Game.Screens.OnlinePlay private void updateSubScreenTitle() => title.Screen = stack.CurrentScreen as IOnlinePlaySubScreen; - private class MultiHeaderTitle : CompositeDrawable + private partial class MultiHeaderTitle : CompositeDrawable { private const float spacing = 6; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 7e39a52c0a..8c85a8235c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -29,7 +29,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class DrawableRoom : CompositeDrawable + public partial class DrawableRoom : CompositeDrawable { protected const float CORNER_RADIUS = 10; private const float height = 100; @@ -311,7 +311,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components return pills; } - private class RoomNameText : OsuSpriteText + private partial class RoomNameText : OsuSpriteText { [Resolved(typeof(Room), nameof(Online.Rooms.Room.Name))] private Bindable name { get; set; } @@ -328,7 +328,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } - private class RoomStatusText : OnlinePlayComposite + private partial class RoomStatusText : OnlinePlayComposite { [Resolved] private OsuColour colours { get; set; } @@ -434,7 +434,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } - public class PasswordProtectedIcon : CompositeDrawable + public partial class PasswordProtectedIcon : CompositeDrawable { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs index 9e2bd41fd0..3b66355dab 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class DrawableRoomParticipantsList : OnlinePlayComposite + public partial class DrawableRoomParticipantsList : OnlinePlayComposite { private const float avatar_size = 36; @@ -270,7 +270,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } - private class CircularAvatar : CompositeDrawable + private partial class CircularAvatar : CompositeDrawable { public APIUser User { @@ -302,7 +302,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } - public class HiddenUserCount : CompositeDrawable + public partial class HiddenUserCount : CompositeDrawable { public int Count { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/EndDateInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/EndDateInfo.cs index d951b42854..c25dd6f158 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/EndDateInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/EndDateInfo.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class EndDateInfo : OnlinePlayComposite + public partial class EndDateInfo : OnlinePlayComposite { public EndDateInfo() { @@ -30,7 +30,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }; } - private class EndDatePart : DrawableDate + private partial class EndDatePart : DrawableDate { public readonly IBindable EndDate = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/MatchTypePill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/MatchTypePill.cs index b2e527766a..f96d547747 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/MatchTypePill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/MatchTypePill.cs @@ -13,7 +13,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class MatchTypePill : OnlinePlayComposite + public partial class MatchTypePill : OnlinePlayComposite { private OsuTextFlowContainer textFlow; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs index b17873b1c8..263261143d 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components /// /// Displays contents in a "pill". /// - public class PillContainer : Container + public partial class PillContainer : Container { private const float padding = 8; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs index 474463d5f1..81ba48d135 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components /// /// A pill that displays the playlist item count. /// - public class PlaylistCountPill : OnlinePlayComposite + public partial class PlaylistCountPill : OnlinePlayComposite { private OsuTextFlowContainer count; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/QueueModePill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/QueueModePill.cs index 85177ee32c..0175418a96 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/QueueModePill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/QueueModePill.cs @@ -13,7 +13,7 @@ using osu.Game.Online.Multiplayer; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class QueueModePill : OnlinePlayComposite + public partial class QueueModePill : OnlinePlayComposite { private OsuTextFlowContainer textFlow; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs index fa531a0d14..adfc44fbd4 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class RankRangePill : MultiplayerRoomComposite + public partial class RankRangePill : MultiplayerRoomComposite { private OsuTextFlowContainer rankFlow; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs index 0f9bfb22e8..5d67a18d1f 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs @@ -13,7 +13,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class RoomSpecialCategoryPill : OnlinePlayComposite + public partial class RoomSpecialCategoryPill : OnlinePlayComposite { private SpriteText text; private PillContainer pill; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs index f37ec9d9d4..201314851e 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components /// /// A pill that displays the room's current status. /// - public class RoomStatusPill : OnlinePlayComposite + public partial class RoomStatusPill : OnlinePlayComposite { [Resolved] private OsuColour colours { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index e6b1942506..e723dfe3e6 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -21,7 +21,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class RoomsContainer : CompositeDrawable, IKeyBindingHandler + public partial class RoomsContainer : CompositeDrawable, IKeyBindingHandler { public readonly Bindable SelectedRoom = new Bindable(); public readonly Bindable Filter = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index 8a2aeb9e5e..79ffa5f666 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge /// /// A with lounge-specific interactions such as selection and hover sounds. /// - public class DrawableLoungeRoom : DrawableRoom, IFilterable, IHasContextMenu, IHasPopover, IKeyBindingHandler + public partial class DrawableLoungeRoom : DrawableRoom, IFilterable, IHasContextMenu, IHasPopover, IKeyBindingHandler { private const float transition_duration = 60; private const float selection_border_width = 4; @@ -180,7 +180,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge return true; } - public class PasswordEntryPopover : OsuPopover + public partial class PasswordEntryPopover : OsuPopover { private readonly Room room; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs index d2a57f21db..b31c351b82 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs @@ -8,7 +8,7 @@ using osu.Game.Screens.OnlinePlay.Components; namespace osu.Game.Screens.OnlinePlay.Lounge { - public class LoungeBackgroundScreen : OnlinePlayBackgroundScreen + public partial class LoungeBackgroundScreen : OnlinePlayBackgroundScreen { public readonly Bindable SelectedRoom = new Bindable(); private readonly BindableList playlist = new BindableList(); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 09bc496da5..fc4a5357c6 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -35,7 +35,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Lounge { [Cached] - public abstract class LoungeSubScreen : OnlinePlaySubScreen + public abstract partial class LoungeSubScreen : OnlinePlaySubScreen { public override string Title => "Lounge"; diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs index 3d0c181d9d..0e865b8a09 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs @@ -10,7 +10,7 @@ using osu.Framework.Input.Events; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public abstract class CreateRoomButton : PurpleTriangleButton, IKeyBindingHandler + public abstract partial class CreateRoomButton : PurpleTriangleButton, IKeyBindingHandler { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs index 880bba895a..55d39407b0 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs @@ -10,7 +10,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public class MatchChatDisplay : StandAloneChatDisplay + public partial class MatchChatDisplay : StandAloneChatDisplay { private readonly IBindable channelId = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs index ee5ee576d8..4627cd4072 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboard.cs @@ -11,7 +11,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public class MatchLeaderboard : Leaderboard + public partial class MatchLeaderboard : Leaderboard { [Resolved(typeof(Room), nameof(Room.RoomID))] private Bindable roomId { get; set; } = null!; diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs index 5bd8f9e066..fabebc3859 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchLeaderboardScore.cs @@ -13,7 +13,7 @@ using osu.Game.Scoring; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public class MatchLeaderboardScore : LeaderboardScore + public partial class MatchLeaderboardScore : LeaderboardScore { private readonly APIUserScoreAggregate score; diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs index 91477879c6..995fce085e 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public class MatchTypePicker : DisableableTabControl + public partial class MatchTypePicker : DisableableTabControl { private const float height = 40; private const float selection_width = 3; @@ -35,7 +35,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components AddItem(MatchType.TeamVersus); } - private class GameTypePickerItem : DisableableTabItem + private partial class GameTypePickerItem : DisableableTabItem { private const float transition_duration = 200; diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs index 5c751f238f..a444d9ee1c 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/PurpleTriangleButton.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public class PurpleTriangleButton : TriangleButton + public partial class PurpleTriangleButton : TriangleButton { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/RoomAvailabilityPicker.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomAvailabilityPicker.cs index 408742d8e1..85fac9228b 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/RoomAvailabilityPicker.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomAvailabilityPicker.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public class RoomAvailabilityPicker : DisableableTabControl + public partial class RoomAvailabilityPicker : DisableableTabControl { protected override TabItem CreateTabItem(RoomAvailability value) => new RoomAvailabilityPickerItem(value); protected override Dropdown CreateDropdown() => null; @@ -36,7 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components AddItem(RoomAvailability.InviteOnly); } - private class RoomAvailabilityPickerItem : DisableableTabItem + private partial class RoomAvailabilityPickerItem : DisableableTabItem { private const float transition_duration = 200; diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs index 71447b15e2..4d4fe4ea56 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public abstract class RoomSettingsOverlay : FocusedOverlayContainer, IKeyBindingHandler + public abstract partial class RoomSettingsOverlay : FocusedOverlayContainer, IKeyBindingHandler { protected const float TRANSITION_DURATION = 350; protected const float FIELD_PADDING = 25; @@ -101,7 +101,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components /// use expanded overhanging content (like an 's dropdown), /// then the overhanging content will be correctly Z-ordered. /// - protected class SectionContainer : ReverseChildIDFillFlowContainer
+ protected partial class SectionContainer : ReverseChildIDFillFlowContainer
{ public SectionContainer() { @@ -113,7 +113,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components } } - protected class Section : Container + protected partial class Section : Container { private readonly Container content; diff --git a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs index 7c444b9bbd..38f3d54837 100644 --- a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs @@ -19,7 +19,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Match { - public class DrawableMatchRoom : DrawableRoom + public partial class DrawableMatchRoom : DrawableRoom { public readonly IBindable SelectedItem = new Bindable(); public Action OnEdit; @@ -70,7 +70,7 @@ namespace osu.Game.Screens.OnlinePlay.Match protected override Drawable CreateBackground() => background = new BackgroundSprite(); - private class BackgroundSprite : UpdateableBeatmapBackgroundSprite + private partial class BackgroundSprite : UpdateableBeatmapBackgroundSprite { protected override double LoadDelay => 0; } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs index 74c37b865c..c9e51d376c 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs @@ -9,7 +9,7 @@ using osu.Game.Screens.OnlinePlay.Components; namespace osu.Game.Screens.OnlinePlay.Match { - public class RoomBackgroundScreen : OnlinePlayBackgroundScreen + public partial class RoomBackgroundScreen : OnlinePlayBackgroundScreen { public readonly Bindable SelectedItem = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 00c819e5e4..e3f31fc1ad 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -35,7 +35,7 @@ using osu.Game.Screens.OnlinePlay.Multiplayer; namespace osu.Game.Screens.OnlinePlay.Match { [Cached(typeof(IPreviewTrackOwner))] - public abstract class RoomSubScreen : OnlinePlaySubScreen, IPreviewTrackOwner + public abstract partial class RoomSubScreen : OnlinePlaySubScreen, IPreviewTrackOwner { [Cached(typeof(IBindable))] public readonly Bindable SelectedItem = new Bindable(); @@ -517,7 +517,7 @@ namespace osu.Game.Screens.OnlinePlay.Match /// The room to change the settings of. protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room); - public class UserModSelectButton : PurpleTriangleButton, IKeyBindingHandler + public partial class UserModSelectButton : PurpleTriangleButton, IKeyBindingHandler { public bool OnPressed(KeyBindingPressEvent e) { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs index fd535f979d..7975597beb 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class CreateMultiplayerMatchButton : CreateRoomButton + public partial class CreateMultiplayerMatchButton : CreateRoomButton { private IBindable isConnected; private IBindable operationInProgress; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs index 270f15a98d..d003110039 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class GameplayChatDisplay : MatchChatDisplay, IKeyBindingHandler + public partial class GameplayChatDisplay : MatchChatDisplay, IKeyBindingHandler { [Resolved(CanBeNull = true)] [CanBeNull] diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayMatchScoreDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayMatchScoreDisplay.cs index c7fb6a82d5..8c08390c73 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayMatchScoreDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayMatchScoreDisplay.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class GameplayMatchScoreDisplay : MatchScoreDisplay + public partial class GameplayMatchScoreDisplay : MatchScoreDisplay { public Bindable Expanded = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs index f048ae59cd..44e18dd2bb 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class MatchStartControl : MultiplayerRoomComposite + public partial class MatchStartControl : MultiplayerRoomComposite { [Resolved] private OngoingOperationTracker ongoingOperationTracker { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs index cd94b47d9e..a13315edd2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerCountdownButton.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class MultiplayerCountdownButton : IconButton, IHasPopover + public partial class MultiplayerCountdownButton : IconButton, IHasPopover { private static readonly TimeSpan[] available_delays = { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs index c28bd4892a..fcb6480b58 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class MultiplayerMatchFooter : CompositeDrawable + public partial class MultiplayerMatchFooter : CompositeDrawable { private const float ready_button_width = 600; private const float spectate_button_width = 200; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index bbdfed0a00..be1f4d121d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -25,7 +25,7 @@ using Container = osu.Framework.Graphics.Containers.Container; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class MultiplayerMatchSettingsOverlay : RoomSettingsOverlay + public partial class MultiplayerMatchSettingsOverlay : RoomSettingsOverlay { private MatchSettings settings = null!; @@ -50,7 +50,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match SettingsApplied = Hide }; - protected class MatchSettings : OnlinePlayComposite + protected partial class MatchSettings : OnlinePlayComposite { private const float disabled_alpha = 0.2f; @@ -460,7 +460,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match }); } - public class CreateOrUpdateButton : TriangleButton + public partial class CreateOrUpdateButton : TriangleButton { [Resolved(typeof(Room), nameof(Room.RoomID))] private Bindable roomId { get; set; } = null!; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs index b4ff34cbc2..d794163a9e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs @@ -18,7 +18,7 @@ using osu.Game.Screens.OnlinePlay.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class MultiplayerReadyButton : ReadyButton + public partial class MultiplayerReadyButton : ReadyButton { public new Triangles Triangles => base.Triangles; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs index b55a7d0731..a9233f091a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class MultiplayerSpectateButton : MultiplayerRoomComposite + public partial class MultiplayerSpectateButton : MultiplayerRoomComposite { [Resolved] private OngoingOperationTracker ongoingOperationTracker { get; set; } @@ -84,7 +84,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match && !operationInProgress.Value; } - private class ButtonWithTrianglesExposed : TriangleButton + private partial class ButtonWithTrianglesExposed : TriangleButton { public new Triangles Triangles => base.Triangles; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerHistoryList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerHistoryList.cs index 3def73accb..a19f61787b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerHistoryList.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerHistoryList.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist /// /// A historically-ordered list of s. /// - public class MultiplayerHistoryList : DrawableRoomPlaylist + public partial class MultiplayerHistoryList : DrawableRoomPlaylist { public MultiplayerHistoryList() { @@ -27,7 +27,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist Spacing = new Vector2(0, 2) }; - private class HistoryFillFlowContainer : FillFlowContainer> + private partial class HistoryFillFlowContainer : FillFlowContainer> { public override IEnumerable FlowingChildren => base.FlowingChildren.OfType>().OrderByDescending(item => item.Model.PlayedAt); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs index bc96bd61d7..2d08d8ecf6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist /// /// The multiplayer playlist, containing lists to show the items from a in both gameplay-order and historical-order. /// - public class MultiplayerPlaylist : MultiplayerRoomComposite + public partial class MultiplayerPlaylist : MultiplayerRoomComposite { public readonly Bindable DisplayMode = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs index f7abc91227..a5589c48b9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylistTabControl.cs @@ -10,7 +10,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist { - public class MultiplayerPlaylistTabControl : OsuTabControl + public partial class MultiplayerPlaylistTabControl : OsuTabControl { public readonly IBindableList QueueItems = new BindableList(); @@ -22,7 +22,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist return base.CreateTabItem(value); } - private class QueueTabItem : OsuTabItem + private partial class QueueTabItem : OsuTabItem { public readonly IBindableList QueueItems = new BindableList(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs index ba6b482729..77d82c4347 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerQueueList.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist /// /// A gameplay-ordered list of s. /// - public class MultiplayerQueueList : DrawableRoomPlaylist + public partial class MultiplayerQueueList : DrawableRoomPlaylist { public MultiplayerQueueList() { @@ -33,7 +33,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist protected override DrawableRoomPlaylistItem CreateDrawablePlaylistItem(PlaylistItem item) => new QueuePlaylistItem(item); - private class QueueFillFlowContainer : FillFlowContainer> + private partial class QueueFillFlowContainer : FillFlowContainer> { [Resolved(typeof(Room), nameof(Room.Playlist))] private BindableList roomPlaylist { get; set; } @@ -47,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist public override IEnumerable FlowingChildren => base.FlowingChildren.OfType>().OrderBy(item => item.Model.PlaylistOrder); } - private class QueuePlaylistItem : DrawableRoomPlaylistItem + private partial class QueuePlaylistItem : DrawableRoomPlaylistItem { [Resolved] private IAPIProvider api { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs index 03a2f00c0d..164d1c9a4b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.OnlinePlay.Lounge; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class Multiplayer : OnlinePlayScreen + public partial class Multiplayer : OnlinePlayScreen { [Resolved] private MultiplayerClient client { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index 8206d4b64d..dd4f35cdd4 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -23,7 +23,7 @@ using osu.Game.Screens.OnlinePlay.Match; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class MultiplayerLoungeSubScreen : LoungeSubScreen + public partial class MultiplayerLoungeSubScreen : LoungeSubScreen { [Resolved] private IAPIProvider api { get; set; } @@ -90,7 +90,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer base.OpenNewRoom(room); } - private class MultiplayerListingPollingComponent : ListingPollingComponent + private partial class MultiplayerListingPollingComponent : ListingPollingComponent { [Resolved] private MultiplayerClient client { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 3fe236bd7a..873a1b0d50 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.Select; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class MultiplayerMatchSongSelect : OnlinePlaySongSelect + public partial class MultiplayerMatchSongSelect : OnlinePlaySongSelect { [Resolved] private MultiplayerClient client { get; set; } = null!; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index db752f2b42..c08410f43a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -38,7 +38,7 @@ using ParticipantsList = osu.Game.Screens.OnlinePlay.Multiplayer.Participants.Pa namespace osu.Game.Screens.OnlinePlay.Multiplayer { [Cached] - public class MultiplayerMatchSubScreen : RoomSubScreen, IHandlePresentBeatmap + public partial class MultiplayerMatchSubScreen : RoomSubScreen, IHandlePresentBeatmap { public override string Title { get; } @@ -430,7 +430,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer modSettingChangeTracker?.Dispose(); } - public class AddItemButton : PurpleTriangleButton + public partial class AddItemButton : PurpleTriangleButton { } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index a2c43898f7..7b448e4b5c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -22,7 +22,7 @@ using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class MultiplayerPlayer : RoomSubmittingPlayer + public partial class MultiplayerPlayer : RoomSubmittingPlayer { protected override bool PauseOnFocusLost => false; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs index f79af664d8..f682508319 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayerLoader.cs @@ -13,7 +13,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class MultiplayerPlayerLoader : PlayerLoader + public partial class MultiplayerPlayerLoader : PlayerLoader { public bool GameplayPassed => player?.GameplayState.HasPassed == true; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs index d98b837883..de19d3a0e9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs @@ -9,7 +9,7 @@ using osu.Game.Screens.OnlinePlay.Playlists; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class MultiplayerResultsScreen : PlaylistsResultsScreen + public partial class MultiplayerResultsScreen : PlaylistsResultsScreen { public MultiplayerResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem) : base(score, roomId, playlistItem, false, false) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs index 5a297f18db..ee5c84bf40 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs @@ -10,7 +10,7 @@ using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public abstract class MultiplayerRoomComposite : OnlinePlayComposite + public abstract partial class MultiplayerRoomComposite : OnlinePlayComposite { [CanBeNull] protected MultiplayerRoom Room => Client.Room; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs index 7e83d72c77..5f51ccc8d4 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.OnlinePlay.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class MultiplayerRoomManager : RoomManager + public partial class MultiplayerRoomManager : RoomManager { [Resolved] private MultiplayerClient multiplayerClient { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomSounds.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomSounds.cs index 1aafcea20c..90595bc33b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomSounds.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomSounds.cs @@ -12,7 +12,7 @@ using osu.Game.Online.Multiplayer; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class MultiplayerRoomSounds : MultiplayerRoomComposite + public partial class MultiplayerRoomSounds : MultiplayerRoomComposite { private Sample hostChangedSample; private Sample userJoinedSample; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs index 6fbed03e44..a8c513603c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class MultiplayerTeamResultsScreen : MultiplayerResultsScreen + public partial class MultiplayerTeamResultsScreen : MultiplayerResultsScreen { private readonly SortedDictionary teamScores; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index 3ef2f033b0..c79c210e30 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -30,7 +30,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { - public class ParticipantPanel : MultiplayerRoomComposite, IHasContextMenu + public partial class ParticipantPanel : MultiplayerRoomComposite, IHasContextMenu { public readonly MultiplayerRoomUser User; @@ -250,7 +250,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants } } - public class KickButton : IconButton + public partial class KickButton : IconButton { public KickButton() { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs index 7c93c6084e..6a7a3758c3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { - public class ParticipantsList : MultiplayerRoomComposite + public partial class ParticipantsList : MultiplayerRoomComposite { private FillFlowContainer panels; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs index b0acda03df..7f4e3360e4 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsListHeader.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.OnlinePlay.Components; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { - public class ParticipantsListHeader : OverlinedHeader + public partial class ParticipantsListHeader : OverlinedHeader { [Resolved] private MultiplayerClient client { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs index ecef7509d9..bfdc0c02ac 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/StateDisplay.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { - public class StateDisplay : CompositeDrawable + public partial class StateDisplay : CompositeDrawable { private const double fade_time = 50; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs index 5500d96eea..fe57ad26a5 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { - internal class TeamDisplay : MultiplayerRoomComposite + internal partial class TeamDisplay : MultiplayerRoomComposite { private readonly MultiplayerRoomUser user; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs index 4e9ab07e4c..ed92b719fc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs @@ -8,7 +8,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { - public class MultiSpectatorLeaderboard : MultiplayerGameplayLeaderboard + public partial class MultiSpectatorLeaderboard : MultiplayerGameplayLeaderboard { public MultiSpectatorLeaderboard(MultiplayerRoomUser[] users) : base(users) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 6e939c3916..5a686ffa72 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// A single spectated player within a . /// - public class MultiSpectatorPlayer : SpectatorPlayer + public partial class MultiSpectatorPlayer : SpectatorPlayer { /// /// All adjustments applied to the clock of this which come from mods. diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs index 36a6487289..eb55b0d18a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// Used to load a single in a . /// - public class MultiSpectatorPlayerLoader : SpectatorPlayerLoader + public partial class MultiSpectatorPlayerLoader : SpectatorPlayerLoader { public MultiSpectatorPlayerLoader([NotNull] Score score, [NotNull] Func createPlayer) : base(score, createPlayer) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 1fd04d35f8..fe27e2cf20 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// A that spectates multiple users in a match. /// - public class MultiSpectatorScreen : SpectatorScreen + public partial class MultiSpectatorScreen : SpectatorScreen { // Isolates beatmap/ruleset to this screen. public override bool DisallowExternalBeatmapRulesetChanges => true; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index 96f134568d..dc4a2df9d8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// Provides an area for and manages the hierarchy of a spectated player within a . /// - public class PlayerArea : CompositeDrawable + public partial class PlayerArea : CompositeDrawable { /// /// Raised after is called on . @@ -131,7 +131,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// Isolates each player instance from the game-wide ruleset/beatmap/mods (to allow for different players having different settings). /// - private class PlayerIsolationContainer : Container + private partial class PlayerIsolationContainer : Container { [Cached] private readonly Bindable ruleset = new Bindable(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Cell.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Cell.cs index ee213f7be1..4a8b8f49e1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Cell.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Cell.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// A cell of the grid. Contains the content and tracks to the linked facade. /// - private class Cell : CompositeDrawable + private partial class Cell : CompositeDrawable { /// /// The index of the original facade of this cell. diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Facade.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Facade.cs index f7b8d48d0a..2f4ed35392 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Facade.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerGrid_Facade.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// A facade of the grid which is used as a dummy object to store the required position/size of cells. /// - private class Facade : Drawable + private partial class Facade : Drawable { public Facade() { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index 8d087aa25c..615c0d7c2b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// Manages the synchronisation between one or more s in relation to a master clock. /// - public class SpectatorSyncManager : Component + public partial class SpectatorSyncManager : Component { /// /// The offset from the master clock to which player clocks should remain within to be considered in-sync. diff --git a/osu.Game/Screens/OnlinePlay/OngoingOperationTracker.cs b/osu.Game/Screens/OnlinePlay/OngoingOperationTracker.cs index c87cf32c73..7f73d6655f 100644 --- a/osu.Game/Screens/OnlinePlay/OngoingOperationTracker.cs +++ b/osu.Game/Screens/OnlinePlay/OngoingOperationTracker.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.OnlinePlay /// Utility class to track ongoing online operations' progress. /// Can be used to disable interactivity while waiting for a response from online sources. /// - public class OngoingOperationTracker : Component + public partial class OngoingOperationTracker : Component { /// /// Whether there is an online operation in progress. diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index 50ad3228e5..ff536a65c4 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.OnlinePlay /// /// A that exposes bindables for properties. /// - public class OnlinePlayComposite : CompositeDrawable + public partial class OnlinePlayComposite : CompositeDrawable { [Resolved(typeof(Room))] protected Bindable RoomID { get; private set; } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 7e5d90bd4f..ccf6cebb12 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -21,7 +21,7 @@ using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay { [Cached] - public abstract class OnlinePlayScreen : OsuScreen, IHasSubScreenStack + public abstract partial class OnlinePlayScreen : OsuScreen, IHasSubScreenStack { [Cached] protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); @@ -217,7 +217,7 @@ namespace osu.Game.Screens.OnlinePlay protected abstract LoungeSubScreen CreateLounge(); - private class MultiplayerWaveContainer : WaveContainer + private partial class MultiplayerWaveContainer : WaveContainer { protected override bool StartHidden => true; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index ea20270c1e..b9d8912170 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -24,7 +24,7 @@ using osu.Game.Utils; namespace osu.Game.Screens.OnlinePlay { - public abstract class OnlinePlaySongSelect : SongSelect, IOnlinePlaySubScreen + public abstract partial class OnlinePlaySongSelect : SongSelect, IOnlinePlaySubScreen { public string ShortTitle => "song selection"; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs index 5c0a158c97..c7b32131cf 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs @@ -9,7 +9,7 @@ using osu.Framework.Screens; namespace osu.Game.Screens.OnlinePlay { - public abstract class OnlinePlaySubScreen : OsuScreen, IOnlinePlaySubScreen + public abstract partial class OnlinePlaySubScreen : OsuScreen, IOnlinePlaySubScreen { public override bool DisallowExternalBeatmapRulesetChanges => false; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs index ae6988f0d6..7ecb7d954e 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs @@ -7,7 +7,7 @@ using osu.Framework.Screens; namespace osu.Game.Screens.OnlinePlay { - public class OnlinePlaySubScreenStack : OsuScreenStack + public partial class OnlinePlaySubScreenStack : OsuScreenStack { protected override void ScreenChanged(IScreen prev, IScreen next) { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs index 8cdae954ce..9507169e0f 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs @@ -8,7 +8,7 @@ using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class CreatePlaylistsRoomButton : CreateRoomButton + public partial class CreatePlaylistsRoomButton : CreateRoomButton { [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs index b84079b955..f9324840dc 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs @@ -7,7 +7,7 @@ using osu.Game.Screens.OnlinePlay.Lounge; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class Playlists : OnlinePlayScreen + public partial class Playlists : OnlinePlayScreen { protected override string ScreenTitle => "Playlists"; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs index 0827e2031d..e1d747c3b0 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs @@ -19,7 +19,7 @@ using osu.Game.Screens.OnlinePlay.Match; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsLoungeSubScreen : LoungeSubScreen + public partial class PlaylistsLoungeSubScreen : LoungeSubScreen { [Resolved] private IAPIProvider api { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs index 2444729118..0c25a32259 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs @@ -21,7 +21,7 @@ using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsPlayer : RoomSubmittingPlayer + public partial class PlaylistsPlayer : RoomSubmittingPlayer { public Action Exited; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs index b8ab514721..5cc2d9b5da 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsReadyButton.cs @@ -15,7 +15,7 @@ using osu.Game.Screens.OnlinePlay.Components; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsReadyButton : ReadyButton + public partial class PlaylistsReadyButton : ReadyButton { [Resolved(typeof(Room), nameof(Room.EndDate))] private Bindable endDate { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs index 27193d3cb6..d40d43cd54 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs @@ -20,7 +20,7 @@ using osu.Game.Screens.Ranking; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsResultsScreen : ResultsScreen + public partial class PlaylistsResultsScreen : ResultsScreen { private readonly long roomId; private readonly PlaylistItem playlistItem; @@ -235,7 +235,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists } } - private class PanelListLoadingSpinner : LoadingSpinner + private partial class PanelListLoadingSpinner : LoadingSpinner { private readonly ScorePanelList list; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFooter.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFooter.cs index b1b400713f..5161de5f64 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFooter.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFooter.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsRoomFooter : CompositeDrawable + public partial class PlaylistsRoomFooter : CompositeDrawable { public Action OnStart; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index cd52981528..ee6c07e3ca 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -25,7 +25,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsRoomSettingsOverlay : RoomSettingsOverlay + public partial class PlaylistsRoomSettingsOverlay : RoomSettingsOverlay { public Action? EditPlaylist; @@ -49,7 +49,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists EditPlaylist = () => EditPlaylist?.Invoke() }; - protected class MatchSettings : OnlinePlayComposite + protected partial class MatchSettings : OnlinePlayComposite { private const float disabled_alpha = 0.2f; @@ -414,7 +414,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists } } - public class CreateRoomButton : TriangleButton + public partial class CreateRoomButton : TriangleButton { public CreateRoomButton() { @@ -430,7 +430,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists } } - private class DurationDropdown : OsuDropdown + private partial class DurationDropdown : OsuDropdown { public DurationDropdown() { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsPlaylist.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsPlaylist.cs index 80f38d0cd8..df502ae09c 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsPlaylist.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsPlaylist.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists /// /// A which is displayed during the setup stage of a playlists room. /// - public class PlaylistsRoomSettingsPlaylist : DrawableRoomPlaylist + public partial class PlaylistsRoomSettingsPlaylist : DrawableRoomPlaylist { public PlaylistsRoomSettingsPlaylist() { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 228ecd4bf3..cf5a8e1985 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -25,7 +25,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsRoomSubScreen : RoomSubScreen + public partial class PlaylistsRoomSubScreen : RoomSubScreen { public override string Title { get; } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs index e3f7b5dfc4..cedea4af70 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs @@ -10,7 +10,7 @@ using osu.Game.Screens.Select; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsSongSelect : OnlinePlaySongSelect + public partial class PlaylistsSongSelect : OnlinePlaySongSelect { public PlaylistsSongSelect(Room room) : base(room) diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index 6be13bbda3..bc4cc2b00f 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -21,7 +21,7 @@ using osu.Game.Users; namespace osu.Game.Screens { - public abstract class OsuScreen : Screen, IOsuScreen, IHasDescription + public abstract partial class OsuScreen : Screen, IOsuScreen, IHasDescription { /// /// The amount of negative padding that should be applied to game background content which touches both the left and right sides of the screen. diff --git a/osu.Game/Screens/OsuScreenStack.cs b/osu.Game/Screens/OsuScreenStack.cs index 49f1255ec7..dffbbdbc55 100644 --- a/osu.Game/Screens/OsuScreenStack.cs +++ b/osu.Game/Screens/OsuScreenStack.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Screens { - public class OsuScreenStack : ScreenStack + public partial class OsuScreenStack : ScreenStack { [Cached] private BackgroundScreenStack backgroundScreenStack; diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 0e56cafaaa..06509b6465 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Play /// /// Displays beatmap metadata inside /// - public class BeatmapMetadataDisplay : Container + public partial class BeatmapMetadataDisplay : Container { private readonly IWorkingBeatmap beatmap; private readonly Bindable> mods; @@ -212,7 +212,7 @@ namespace osu.Game.Screens.Play }; } - private class MetadataLineLabel : OsuSpriteText + private partial class MetadataLineLabel : OsuSpriteText { public MetadataLineLabel(LocalisableString text) { @@ -224,7 +224,7 @@ namespace osu.Game.Screens.Play } } - private class MetadataLineInfo : OsuSpriteText + private partial class MetadataLineInfo : OsuSpriteText { public MetadataLineInfo(string text) { diff --git a/osu.Game/Screens/Play/Break/BlurredIcon.cs b/osu.Game/Screens/Play/Break/BlurredIcon.cs index 97eafa01fa..cd38390324 100644 --- a/osu.Game/Screens/Play/Break/BlurredIcon.cs +++ b/osu.Game/Screens/Play/Break/BlurredIcon.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Screens.Play.Break { - public class BlurredIcon : BufferedContainer + public partial class BlurredIcon : BufferedContainer { private readonly SpriteIcon icon; diff --git a/osu.Game/Screens/Play/Break/BreakArrows.cs b/osu.Game/Screens/Play/Break/BreakArrows.cs index f2feda4d76..f0f1e8cc3d 100644 --- a/osu.Game/Screens/Play/Break/BreakArrows.cs +++ b/osu.Game/Screens/Play/Break/BreakArrows.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Screens.Play.Break { - public class BreakArrows : CompositeDrawable + public partial class BreakArrows : CompositeDrawable { private const int glow_icon_size = 60; private const int glow_icon_blur_sigma = 10; diff --git a/osu.Game/Screens/Play/Break/BreakInfo.cs b/osu.Game/Screens/Play/Break/BreakInfo.cs index 5aed8b7df1..f99c1d1817 100644 --- a/osu.Game/Screens/Play/Break/BreakInfo.cs +++ b/osu.Game/Screens/Play/Break/BreakInfo.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Screens.Play.Break { - public class BreakInfo : Container + public partial class BreakInfo : Container { public PercentageBreakInfoLine AccuracyDisplay; diff --git a/osu.Game/Screens/Play/Break/BreakInfoLine.cs b/osu.Game/Screens/Play/Break/BreakInfoLine.cs index 690d7c7e63..7261155c94 100644 --- a/osu.Game/Screens/Play/Break/BreakInfoLine.cs +++ b/osu.Game/Screens/Play/Break/BreakInfoLine.cs @@ -16,7 +16,7 @@ using osu.Game.Utils; namespace osu.Game.Screens.Play.Break { - public class BreakInfoLine : Container + public partial class BreakInfoLine : Container where T : struct { private const int margin = 2; @@ -82,7 +82,7 @@ namespace osu.Game.Screens.Play.Break } } - public class PercentageBreakInfoLine : BreakInfoLine + public partial class PercentageBreakInfoLine : BreakInfoLine { public PercentageBreakInfoLine(LocalisableString name, string prefix = "") : base(name, prefix) diff --git a/osu.Game/Screens/Play/Break/GlowIcon.cs b/osu.Game/Screens/Play/Break/GlowIcon.cs index 9222e8f890..595c4dd494 100644 --- a/osu.Game/Screens/Play/Break/GlowIcon.cs +++ b/osu.Game/Screens/Play/Break/GlowIcon.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Screens.Play.Break { - public class GlowIcon : Container + public partial class GlowIcon : Container { private readonly SpriteIcon spriteIcon; private readonly BlurredIcon blurredIcon; diff --git a/osu.Game/Screens/Play/Break/LetterboxOverlay.cs b/osu.Game/Screens/Play/Break/LetterboxOverlay.cs index 3eb58da469..92b432831d 100644 --- a/osu.Game/Screens/Play/Break/LetterboxOverlay.cs +++ b/osu.Game/Screens/Play/Break/LetterboxOverlay.cs @@ -11,7 +11,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.Break { - public class LetterboxOverlay : CompositeDrawable + public partial class LetterboxOverlay : CompositeDrawable { private const int height = 350; diff --git a/osu.Game/Screens/Play/Break/RemainingTimeCounter.cs b/osu.Game/Screens/Play/Break/RemainingTimeCounter.cs index 4b84f7c69e..da83f8c29f 100644 --- a/osu.Game/Screens/Play/Break/RemainingTimeCounter.cs +++ b/osu.Game/Screens/Play/Break/RemainingTimeCounter.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Play.Break { - public class RemainingTimeCounter : Counter + public partial class RemainingTimeCounter : Counter { private readonly OsuSpriteText counter; diff --git a/osu.Game/Screens/Play/BreakOverlay.cs b/osu.Game/Screens/Play/BreakOverlay.cs index 492c9c27ff..4927800059 100644 --- a/osu.Game/Screens/Play/BreakOverlay.cs +++ b/osu.Game/Screens/Play/BreakOverlay.cs @@ -14,7 +14,7 @@ using osu.Game.Screens.Play.Break; namespace osu.Game.Screens.Play { - public class BreakOverlay : Container + public partial class BreakOverlay : Container { /// /// The duration of the break overlay fading. diff --git a/osu.Game/Screens/Play/BreakTracker.cs b/osu.Game/Screens/Play/BreakTracker.cs index 8679db01a0..20ef1dc4bf 100644 --- a/osu.Game/Screens/Play/BreakTracker.cs +++ b/osu.Game/Screens/Play/BreakTracker.cs @@ -13,7 +13,7 @@ using osu.Game.Utils; namespace osu.Game.Screens.Play { - public class BreakTracker : Component + public partial class BreakTracker : Component { private readonly ScoreProcessor scoreProcessor; private readonly double gameplayStartTime; diff --git a/osu.Game/Screens/Play/ComboEffects.cs b/osu.Game/Screens/Play/ComboEffects.cs index 442b061af7..09c94a8f1d 100644 --- a/osu.Game/Screens/Play/ComboEffects.cs +++ b/osu.Game/Screens/Play/ComboEffects.cs @@ -13,7 +13,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play { - public class ComboEffects : CompositeDrawable + public partial class ComboEffects : CompositeDrawable { private readonly ScoreProcessor processor; diff --git a/osu.Game/Screens/Play/DimmableStoryboard.cs b/osu.Game/Screens/Play/DimmableStoryboard.cs index ae43d3d70d..40cc0f66ad 100644 --- a/osu.Game/Screens/Play/DimmableStoryboard.cs +++ b/osu.Game/Screens/Play/DimmableStoryboard.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Play /// /// A container that handles loading, as well as applies user-specified visual settings to it. /// - public class DimmableStoryboard : UserDimContainer + public partial class DimmableStoryboard : UserDimContainer { public Container OverlayLayerContainer { get; private set; } diff --git a/osu.Game/Screens/Play/EpilepsyWarning.cs b/osu.Game/Screens/Play/EpilepsyWarning.cs index 4f87853158..6316bbdb4e 100644 --- a/osu.Game/Screens/Play/EpilepsyWarning.cs +++ b/osu.Game/Screens/Play/EpilepsyWarning.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.Play { - public class EpilepsyWarning : VisibilityContainer + public partial class EpilepsyWarning : VisibilityContainer { public const double FADE_DURATION = 250; diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs index a4b4bf4d2b..24171c25a8 100644 --- a/osu.Game/Screens/Play/FailAnimation.cs +++ b/osu.Game/Screens/Play/FailAnimation.cs @@ -29,7 +29,7 @@ namespace osu.Game.Screens.Play /// Manage the animation to be applied when a player fails. /// Single use and automatically disposed after use. /// - public class FailAnimation : Container + public partial class FailAnimation : Container { public Action? OnComplete; diff --git a/osu.Game/Screens/Play/FailOverlay.cs b/osu.Game/Screens/Play/FailOverlay.cs index 2af5102369..4fbc937b59 100644 --- a/osu.Game/Screens/Play/FailOverlay.cs +++ b/osu.Game/Screens/Play/FailOverlay.cs @@ -18,7 +18,7 @@ using osu.Framework.Graphics.Shapes; namespace osu.Game.Screens.Play { - public class FailOverlay : GameplayMenuOverlay + public partial class FailOverlay : GameplayMenuOverlay { public Func> SaveReplay; diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs index 35b79fd628..c42f607908 100644 --- a/osu.Game/Screens/Play/GameplayClockContainer.cs +++ b/osu.Game/Screens/Play/GameplayClockContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Play /// Encapsulates gameplay timing logic and provides a via DI for gameplay components to use. /// [Cached(typeof(IGameplayClock))] - public class GameplayClockContainer : Container, IAdjustableClock, IGameplayClock + public partial class GameplayClockContainer : Container, IAdjustableClock, IGameplayClock { /// /// Whether gameplay is paused. diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index c2652e9212..c681ef8f96 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -25,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play { - public abstract class GameplayMenuOverlay : OverlayContainer, IKeyBindingHandler + public abstract partial class GameplayMenuOverlay : OverlayContainer, IKeyBindingHandler { protected const int TRANSITION_DURATION = 200; @@ -248,7 +248,7 @@ namespace osu.Game.Screens.Play }; } - private class Button : DialogButton + private partial class Button : DialogButton { // required to ensure keyboard navigation always starts from an extremity (unless the cursor is moved) protected override bool OnHover(HoverEvent e) => true; diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs index 04774b974f..bf1f508d7b 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCalculator.cs @@ -8,7 +8,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Play.HUD.ClicksPerSecond { - public class ClicksPerSecondCalculator : Component + public partial class ClicksPerSecondCalculator : Component { private readonly List timestamps = new List(); diff --git a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs index 243d8ed1e8..cb72bb5f6f 100644 --- a/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs +++ b/osu.Game/Screens/Play/HUD/ClicksPerSecond/ClicksPerSecondCounter.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD.ClicksPerSecond { - public class ClicksPerSecondCounter : RollingCounter, ISkinnableDrawable + public partial class ClicksPerSecondCounter : RollingCounter, ISkinnableDrawable { [Resolved] private ClicksPerSecondCalculator calculator { get; set; } = null!; @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Play.HUD.ClicksPerSecond protected override IHasText CreateText() => new TextComponent(); - private class TextComponent : CompositeDrawable, IHasText + private partial class TextComponent : CompositeDrawable, IHasText { public LocalisableString Text { diff --git a/osu.Game/Screens/Play/HUD/ComboCounter.cs b/osu.Game/Screens/Play/HUD/ComboCounter.cs index 4179d41646..afccbc4ef0 100644 --- a/osu.Game/Screens/Play/HUD/ComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/ComboCounter.cs @@ -7,7 +7,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public abstract class ComboCounter : RollingCounter, ISkinnableDrawable + public abstract partial class ComboCounter : RollingCounter, ISkinnableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs index 018720510c..1a082e58b7 100644 --- a/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultAccuracyCounter.cs @@ -9,7 +9,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public class DefaultAccuracyCounter : GameplayAccuracyCounter, ISkinnableDrawable + public partial class DefaultAccuracyCounter : GameplayAccuracyCounter, ISkinnableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs b/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs index 0c9c363280..1377055c30 100644 --- a/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultComboCounter.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD { - public class DefaultComboCounter : ComboCounter + public partial class DefaultComboCounter : ComboCounter { [BackgroundDependencyLoader] private void load(OsuColour colours, ScoreProcessor scoreProcessor) diff --git a/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs b/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs index 37e1d2fb84..76027f9e5d 100644 --- a/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/DefaultHealthDisplay.cs @@ -19,7 +19,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public class DefaultHealthDisplay : HealthDisplay, IHasAccentColour, ISkinnableDrawable + public partial class DefaultHealthDisplay : HealthDisplay, IHasAccentColour, ISkinnableDrawable { /// /// The base opacity of the glow. diff --git a/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs b/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs index 4450ad53d8..f116617271 100644 --- a/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs +++ b/osu.Game/Screens/Play/HUD/DefaultScoreCounter.cs @@ -10,7 +10,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public class DefaultScoreCounter : GameplayScoreCounter, ISkinnableDrawable + public partial class DefaultScoreCounter : GameplayScoreCounter, ISkinnableDrawable { public DefaultScoreCounter() { diff --git a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs index 45d0cf8462..53866312a0 100644 --- a/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs +++ b/osu.Game/Screens/Play/HUD/DefaultSongProgress.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public class DefaultSongProgress : SongProgress + public partial class DefaultSongProgress : SongProgress { private const float bottom_bar_height = 5; private const float graph_height = SquareGraph.Column.WIDTH * 6; diff --git a/osu.Game/Screens/Play/HUD/FailingLayer.cs b/osu.Game/Screens/Play/HUD/FailingLayer.cs index 10c1d418ee..67e7ae8f3f 100644 --- a/osu.Game/Screens/Play/HUD/FailingLayer.cs +++ b/osu.Game/Screens/Play/HUD/FailingLayer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Play.HUD /// /// An overlay layer on top of the playfield which fades to red when the current player health falls below a certain threshold defined by . /// - public class FailingLayer : HealthDisplay + public partial class FailingLayer : HealthDisplay { /// /// Whether the current player health should be shown on screen. diff --git a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs index afb6749436..1933193515 100644 --- a/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayAccuracyCounter.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD { - public abstract class GameplayAccuracyCounter : PercentageCounter + public abstract partial class GameplayAccuracyCounter : PercentageCounter { [BackgroundDependencyLoader] private void load(ScoreProcessor scoreProcessor) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 47b67fba00..f6f289db55 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { - public abstract class GameplayLeaderboard : CompositeDrawable + public abstract partial class GameplayLeaderboard : CompositeDrawable { private readonly Cached sorting = new Cached(); @@ -179,7 +179,7 @@ namespace osu.Game.Screens.Play.HUD protected virtual bool CheckValidScorePosition(int i) => true; - private class InputDisabledScrollContainer : OsuScrollContainer + private partial class InputDisabledScrollContainer : OsuScrollContainer { public InputDisabledScrollContainer() { diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 0d03d8d090..07b80feb3e 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { - public class GameplayLeaderboardScore : CompositeDrawable, ILeaderboardScore + public partial class GameplayLeaderboardScore : CompositeDrawable, ILeaderboardScore { public const float EXTENDED_WIDTH = regular_width + top_player_left_width_extension; diff --git a/osu.Game/Screens/Play/HUD/GameplayScoreCounter.cs b/osu.Game/Screens/Play/HUD/GameplayScoreCounter.cs index 7a6292ccbf..a11cccd97c 100644 --- a/osu.Game/Screens/Play/HUD/GameplayScoreCounter.cs +++ b/osu.Game/Screens/Play/HUD/GameplayScoreCounter.cs @@ -12,7 +12,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Screens.Play.HUD { - public abstract class GameplayScoreCounter : ScoreCounter + public abstract partial class GameplayScoreCounter : ScoreCounter { private Bindable scoreDisplayMode; diff --git a/osu.Game/Screens/Play/HUD/HealthDisplay.cs b/osu.Game/Screens/Play/HUD/HealthDisplay.cs index 569b37aea5..7a73eb1657 100644 --- a/osu.Game/Screens/Play/HUD/HealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HealthDisplay.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.Play.HUD /// A container for components displaying the current player health. /// Gets bound automatically to the when inserted to hierarchy. /// - public abstract class HealthDisplay : CompositeDrawable + public abstract partial class HealthDisplay : CompositeDrawable { private readonly Bindable showHealthBar = new Bindable(true); diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index c9f1571dfe..eeca2be7cd 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -23,7 +23,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { [Cached] - public class BarHitErrorMeter : HitErrorMeter + public partial class BarHitErrorMeter : HitErrorMeter { [SettingSource("Judgement line thickness", "How thick the individual lines should be.")] public BindableNumber JudgementLineThickness { get; } = new BindableNumber(4) @@ -422,7 +422,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private float getRelativeJudgementPosition(double value) => Math.Clamp((float)((value / maxHitWindow) + 1) / 2, 0, 1); - internal class JudgementLine : PoolableDrawable + internal partial class JudgementLine : PoolableDrawable { public readonly BindableNumber JudgementLineThickness = new BindableFloat(); diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 86ba85168f..ec5dc5f52f 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { [Cached] - public class ColourHitErrorMeter : HitErrorMeter + public partial class ColourHitErrorMeter : HitErrorMeter { private const int animation_duration = 200; private const int drawable_judgement_size = 8; @@ -63,7 +63,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters public override void Clear() => judgementsFlow.Clear(); - private class JudgementFlow : FillFlowContainer + private partial class JudgementFlow : FillFlowContainer { public override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); @@ -122,7 +122,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters } } - public class HitErrorShape : PoolableDrawable + public partial class HitErrorShape : PoolableDrawable { public bool IsRemoved { get; private set; } diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index dda17c25e6..191f63e97d 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD.HitErrorMeters { - public abstract class HitErrorMeter : CompositeDrawable, ISkinnableDrawable + public abstract partial class HitErrorMeter : CompositeDrawable, ISkinnableDrawable { protected HitWindows HitWindows { get; private set; } diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs index 39a8f1e783..f902e0903d 100644 --- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs +++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs @@ -25,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { - public class HoldForMenuButton : FillFlowContainer + public partial class HoldForMenuButton : FillFlowContainer { public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; @@ -102,7 +102,7 @@ namespace osu.Game.Screens.Play.HUD } } - private class HoldButton : HoldToConfirmContainer, IKeyBindingHandler + private partial class HoldButton : HoldToConfirmContainer, IKeyBindingHandler { private SpriteIcon icon; private CircularProgress circularProgress; diff --git a/osu.Game/Screens/Play/HUD/LongestComboCounter.cs b/osu.Game/Screens/Play/HUD/LongestComboCounter.cs index 0e7af69af2..fdc3768aab 100644 --- a/osu.Game/Screens/Play/HUD/LongestComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/LongestComboCounter.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public class LongestComboCounter : ComboCounter + public partial class LongestComboCounter : ComboCounter { [BackgroundDependencyLoader] private void load(OsuColour colours, ScoreProcessor scoreProcessor) @@ -24,7 +24,7 @@ namespace osu.Game.Screens.Play.HUD protected override IHasText CreateText() => new TextComponent(); - private class TextComponent : CompositeDrawable, IHasText + private partial class TextComponent : CompositeDrawable, IHasText { public LocalisableString Text { diff --git a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs index 00dc586448..58bf4eea4b 100644 --- a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs +++ b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public class MatchScoreDisplay : CompositeDrawable + public partial class MatchScoreDisplay : CompositeDrawable { private const float bar_height = 18; private const float font_size = 50; @@ -148,7 +148,7 @@ namespace osu.Game.Screens.Play.HUD Score2Text.X = Math.Max(5 + Score2Text.DrawWidth / 2, score2Bar.DrawWidth); } - protected class MatchScoreCounter : CommaSeparatedScoreCounter + protected partial class MatchScoreCounter : CommaSeparatedScoreCounter { private OsuSpriteText displayedSpriteText; diff --git a/osu.Game/Screens/Play/HUD/ModDisplay.cs b/osu.Game/Screens/Play/HUD/ModDisplay.cs index 0badc063ce..3b50a22e3c 100644 --- a/osu.Game/Screens/Play/HUD/ModDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ModDisplay.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Play.HUD /// /// Displays a single-line horizontal auto-sized flow of mods. For cases where wrapping is required, use instead. /// - public class ModDisplay : CompositeDrawable, IHasCurrentValue> + public partial class ModDisplay : CompositeDrawable, IHasCurrentValue> { private const int fade_duration = 1000; diff --git a/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs b/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs index 86fece84fa..23030e640b 100644 --- a/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Play.HUD /// /// A horizontally wrapping display of mods. For cases where wrapping is not required, use instead. /// - public class ModFlowDisplay : ReverseChildIDFillFlowContainer, IHasCurrentValue> + public partial class ModFlowDisplay : ReverseChildIDFillFlowContainer, IHasCurrentValue> { private const int fade_duration = 1000; diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 4ac92056ef..2743173a6d 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -25,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { [LongRunningLoad] - public class MultiplayerGameplayLeaderboard : GameplayLeaderboard + public partial class MultiplayerGameplayLeaderboard : GameplayLeaderboard { protected readonly Dictionary UserScores = new Dictionary(); diff --git a/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs b/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs index 97a120f9bd..15484f2965 100644 --- a/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs +++ b/osu.Game/Screens/Play/HUD/PerformancePointsCounter.cs @@ -35,7 +35,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public class PerformancePointsCounter : RollingCounter, ISkinnableDrawable + public partial class PerformancePointsCounter : RollingCounter, ISkinnableDrawable { public bool UsesFixedAnchor { get; set; } @@ -171,7 +171,7 @@ namespace osu.Game.Screens.Play.HUD loadCancellationSource?.Cancel(); } - private class TextComponent : CompositeDrawable, IHasText + private partial class TextComponent : CompositeDrawable, IHasText { public LocalisableString Text { diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index 5f6f040959..a885336a3a 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -12,7 +12,7 @@ using osuTK.Input; namespace osu.Game.Screens.Play.HUD { - public class PlayerSettingsOverlay : VisibilityContainer + public partial class PlayerSettingsOverlay : VisibilityContainer { private const int fade_duration = 200; diff --git a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs index 0df3200adb..0f3e54ecdd 100644 --- a/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/SoloGameplayLeaderboard.cs @@ -15,7 +15,7 @@ using osu.Game.Users; namespace osu.Game.Screens.Play.HUD { - public class SoloGameplayLeaderboard : GameplayLeaderboard + public partial class SoloGameplayLeaderboard : GameplayLeaderboard { private const int duration = 100; diff --git a/osu.Game/Screens/Play/HUD/SongProgress.cs b/osu.Game/Screens/Play/HUD/SongProgress.cs index 0b6494bd8a..4504745eb9 100644 --- a/osu.Game/Screens/Play/HUD/SongProgress.cs +++ b/osu.Game/Screens/Play/HUD/SongProgress.cs @@ -12,7 +12,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Play.HUD { - public abstract class SongProgress : OverlayContainer, ISkinnableDrawable + public abstract partial class SongProgress : OverlayContainer, ISkinnableDrawable { // Some implementations of this element allow seeking during gameplay playback. // Set a sane default of never handling input to override the behaviour provided by OverlayContainer. diff --git a/osu.Game/Screens/Play/HUD/SongProgressBar.cs b/osu.Game/Screens/Play/HUD/SongProgressBar.cs index db4e200724..28059d4911 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressBar.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressBar.cs @@ -15,7 +15,7 @@ using osu.Framework.Threading; namespace osu.Game.Screens.Play.HUD { - public class SongProgressBar : SliderBar + public partial class SongProgressBar : SliderBar { public Action OnSeek; diff --git a/osu.Game/Screens/Play/HUD/SongProgressGraph.cs b/osu.Game/Screens/Play/HUD/SongProgressGraph.cs index f234b45922..f69a1eccd6 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressGraph.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressGraph.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play.HUD { - public class SongProgressGraph : SquareGraph + public partial class SongProgressGraph : SquareGraph { private IEnumerable objects; diff --git a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs index d0eb8f8ca1..fb5f5cc916 100644 --- a/osu.Game/Screens/Play/HUD/SongProgressInfo.cs +++ b/osu.Game/Screens/Play/HUD/SongProgressInfo.cs @@ -13,7 +13,7 @@ using System; namespace osu.Game.Screens.Play.HUD { - public class SongProgressInfo : Container + public partial class SongProgressInfo : Container { private SizePreservingSpriteText timeCurrent; private SizePreservingSpriteText timeLeft; diff --git a/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs b/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs index 0ba88c549e..f450ae799e 100644 --- a/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs +++ b/osu.Game/Screens/Play/HUD/UnstableRateCounter.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Screens.Play.HUD { - public class UnstableRateCounter : RollingCounter, ISkinnableDrawable + public partial class UnstableRateCounter : RollingCounter, ISkinnableDrawable { public bool UsesFixedAnchor { get; set; } @@ -83,7 +83,7 @@ namespace osu.Game.Screens.Play.HUD scoreProcessor.JudgementReverted -= updateDisplay; } - private class TextComponent : CompositeDrawable, IHasText + private partial class TextComponent : CompositeDrawable, IHasText { public LocalisableString Text { diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index fa38eeb9aa..4c2483a0e6 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -28,7 +28,7 @@ using osuTK; namespace osu.Game.Screens.Play { [Cached] - public class HUDOverlay : Container, IKeyBindingHandler + public partial class HUDOverlay : Container, IKeyBindingHandler { public const float FADE_DURATION = 300; @@ -383,7 +383,7 @@ namespace osu.Game.Screens.Play } } - private class MainComponentsContainer : SkinnableTargetContainer + private partial class MainComponentsContainer : SkinnableTargetContainer { private Bindable scoringMode; diff --git a/osu.Game/Screens/Play/HotkeyExitOverlay.cs b/osu.Game/Screens/Play/HotkeyExitOverlay.cs index 07595a43c4..4c1265c699 100644 --- a/osu.Game/Screens/Play/HotkeyExitOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyExitOverlay.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays; namespace osu.Game.Screens.Play { - public class HotkeyExitOverlay : HoldToConfirmOverlay, IKeyBindingHandler + public partial class HotkeyExitOverlay : HoldToConfirmOverlay, IKeyBindingHandler { public bool OnPressed(KeyBindingPressEvent e) { diff --git a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs index 94c0f0a89d..582b5a1691 100644 --- a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs +++ b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays; namespace osu.Game.Screens.Play { - public class HotkeyRetryOverlay : HoldToConfirmOverlay, IKeyBindingHandler + public partial class HotkeyRetryOverlay : HoldToConfirmOverlay, IKeyBindingHandler { public bool OnPressed(KeyBindingPressEvent e) { diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs index 1e5ada5295..4405542b3b 100644 --- a/osu.Game/Screens/Play/KeyCounter.cs +++ b/osu.Game/Screens/Play/KeyCounter.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play { - public abstract class KeyCounter : Container + public abstract partial class KeyCounter : Container { private Sprite buttonSprite; private Sprite glowSprite; diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterAction.cs index f636796436..900d9bcd0e 100644 --- a/osu.Game/Screens/Play/KeyCounterAction.cs +++ b/osu.Game/Screens/Play/KeyCounterAction.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; namespace osu.Game.Screens.Play { - public class KeyCounterAction : KeyCounter + public partial class KeyCounterAction : KeyCounter where T : struct { public T Action { get; } diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs index 1b726b0f7b..d9ad3cfaf7 100644 --- a/osu.Game/Screens/Play/KeyCounterDisplay.cs +++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play { - public class KeyCounterDisplay : Container + public partial class KeyCounterDisplay : Container { private const int duration = 100; private const double key_fade_time = 80; @@ -141,7 +141,7 @@ namespace osu.Game.Screens.Play this.receptor = receptor; } - public class Receptor : Drawable + public partial class Receptor : Drawable { protected readonly KeyCounterDisplay Target; diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboard.cs index 1005de4ea4..c5c8b7eeae 100644 --- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs +++ b/osu.Game/Screens/Play/KeyCounterKeyboard.cs @@ -8,7 +8,7 @@ using osuTK.Input; namespace osu.Game.Screens.Play { - public class KeyCounterKeyboard : KeyCounter + public partial class KeyCounterKeyboard : KeyCounter { public Key Key { get; } diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouse.cs index 0dc2830665..cf9c7c029f 100644 --- a/osu.Game/Screens/Play/KeyCounterMouse.cs +++ b/osu.Game/Screens/Play/KeyCounterMouse.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Screens.Play { - public class KeyCounterMouse : KeyCounter + public partial class KeyCounterMouse : KeyCounter { public MouseButton Button { get; } diff --git a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs index c3c351ac36..489a4ef8b3 100644 --- a/osu.Game/Screens/Play/MasterGameplayClockContainer.cs +++ b/osu.Game/Screens/Play/MasterGameplayClockContainer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Play /// /// This is intended to be used as a single controller for gameplay, or as a reference source for other s. /// - public class MasterGameplayClockContainer : GameplayClockContainer, IBeatSyncProvider + public partial class MasterGameplayClockContainer : GameplayClockContainer, IBeatSyncProvider { /// /// Duration before gameplay start time required before skip button displays. diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index cb98fefcfe..28044653e6 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play { - public class PauseOverlay : GameplayMenuOverlay + public partial class PauseOverlay : GameplayMenuOverlay { public Action OnResume; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 7048f83c09..4306d13ac2 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -44,7 +44,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play { [Cached] - public abstract class Player : ScreenWithBeatmapBackground, ISamplePlaybackDisabler, ILocalUserPlayInfo + public abstract partial class Player : ScreenWithBeatmapBackground, ISamplePlaybackDisabler, ILocalUserPlayInfo { /// /// The delay upon completion of the beatmap before displaying the results screen. diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 4ff5083107..5cedd4f793 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -31,7 +31,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play { - public class PlayerLoader : ScreenWithBeatmapBackground + public partial class PlayerLoader : ScreenWithBeatmapBackground { protected const float BACKGROUND_BLUR = 15; @@ -544,7 +544,7 @@ namespace osu.Game.Screens.Play } } - private class MutedNotification : SimpleNotification + private partial class MutedNotification : SimpleNotification { public override bool IsImportant => true; @@ -599,7 +599,7 @@ namespace osu.Game.Screens.Play } } - private class BatteryWarningNotification : SimpleNotification + private partial class BatteryWarningNotification : SimpleNotification { public override bool IsImportant => true; diff --git a/osu.Game/Screens/Play/PlayerSettings/AudioSettings.cs b/osu.Game/Screens/Play/PlayerSettings/AudioSettings.cs index 606b5c198c..010d8115fa 100644 --- a/osu.Game/Screens/Play/PlayerSettings/AudioSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/AudioSettings.cs @@ -12,7 +12,7 @@ using osu.Game.Scoring; namespace osu.Game.Screens.Play.PlayerSettings { - public class AudioSettings : PlayerSettingsGroup + public partial class AudioSettings : PlayerSettingsGroup { public Bindable ReferenceScore { get; } = new Bindable(); diff --git a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs index fc89effe1b..9492614b66 100644 --- a/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs +++ b/osu.Game/Screens/Play/PlayerSettings/BeatmapOffsetControl.cs @@ -25,7 +25,7 @@ using osuTK; namespace osu.Game.Screens.Play.PlayerSettings { - public class BeatmapOffsetControl : CompositeDrawable + public partial class BeatmapOffsetControl : CompositeDrawable { public Bindable ReferenceScore { get; } = new Bindable(); @@ -87,11 +87,11 @@ namespace osu.Game.Screens.Play.PlayerSettings }; } - public class OffsetSliderBar : PlayerSliderBar + public partial class OffsetSliderBar : PlayerSliderBar { protected override Drawable CreateControl() => new CustomSliderBar(); - protected class CustomSliderBar : SliderBar + protected partial class CustomSliderBar : SliderBar { public override LocalisableString TooltipText => Current.Value == 0 diff --git a/osu.Game/Screens/Play/PlayerSettings/DiscussionSettings.cs b/osu.Game/Screens/Play/PlayerSettings/DiscussionSettings.cs index afbd5caef3..7c76936621 100644 --- a/osu.Game/Screens/Play/PlayerSettings/DiscussionSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/DiscussionSettings.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Play.PlayerSettings { - public class DiscussionSettings : PlayerSettingsGroup + public partial class DiscussionSettings : PlayerSettingsGroup { public DiscussionSettings() : base("discussions") diff --git a/osu.Game/Screens/Play/PlayerSettings/InputSettings.cs b/osu.Game/Screens/Play/PlayerSettings/InputSettings.cs index 04cf79873c..13e5b66a70 100644 --- a/osu.Game/Screens/Play/PlayerSettings/InputSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/InputSettings.cs @@ -10,7 +10,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Play.PlayerSettings { - public class InputSettings : PlayerSettingsGroup + public partial class InputSettings : PlayerSettingsGroup { private readonly PlayerCheckbox mouseButtonsCheckbox; diff --git a/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs b/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs index 14e3123028..cb6fcb2413 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlaybackSettings.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Play.PlayerSettings { - public class PlaybackSettings : PlayerSettingsGroup + public partial class PlaybackSettings : PlayerSettingsGroup { private const int padding = 10; diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs index cea03d2155..49c9cbf385 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerCheckbox.cs @@ -9,11 +9,11 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Screens.Play.PlayerSettings { - public class PlayerCheckbox : SettingsCheckbox + public partial class PlayerCheckbox : SettingsCheckbox { protected override Drawable CreateControl() => new PlayerCheckboxControl(); - public class PlayerCheckboxControl : OsuCheckbox + public partial class PlayerCheckboxControl : OsuCheckbox { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index 6c6f62a8ac..c930513c70 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -8,7 +8,7 @@ using osu.Game.Overlays; namespace osu.Game.Screens.Play.PlayerSettings { - public class PlayerSettingsGroup : SettingsToolboxGroup + public partial class PlayerSettingsGroup : SettingsToolboxGroup { public PlayerSettingsGroup(string title) : base(title) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs index 063056e83e..45d4995753 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSliderBar.cs @@ -12,14 +12,14 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Screens.Play.PlayerSettings { - public class PlayerSliderBar : SettingsSlider + public partial class PlayerSliderBar : SettingsSlider where T : struct, IEquatable, IComparable, IConvertible { public OsuSliderBar Bar => (OsuSliderBar)Control; protected override Drawable CreateControl() => new SliderBar(); - protected class SliderBar : OsuSliderBar + protected partial class SliderBar : OsuSliderBar { public SliderBar() { diff --git a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs index 6a7eabc6a2..ff857ddb12 100644 --- a/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs +++ b/osu.Game/Screens/Play/PlayerSettings/VisualSettings.cs @@ -8,7 +8,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Play.PlayerSettings { - public class VisualSettings : PlayerSettingsGroup + public partial class VisualSettings : PlayerSettingsGroup { private readonly PlayerSliderBar dimSliderBar; private readonly PlayerSliderBar blurSliderBar; diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 5382e283e0..4395b96139 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -20,7 +20,7 @@ using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Play { - public class ReplayPlayer : Player, IKeyBindingHandler + public partial class ReplayPlayer : Player, IKeyBindingHandler { private readonly Func, Score> createScore; diff --git a/osu.Game/Screens/Play/ReplayPlayerLoader.cs b/osu.Game/Screens/Play/ReplayPlayerLoader.cs index a961f90d00..1c9d694325 100644 --- a/osu.Game/Screens/Play/ReplayPlayerLoader.cs +++ b/osu.Game/Screens/Play/ReplayPlayerLoader.cs @@ -9,7 +9,7 @@ using osu.Game.Scoring; namespace osu.Game.Screens.Play { - public class ReplayPlayerLoader : PlayerLoader + public partial class ReplayPlayerLoader : PlayerLoader { public readonly ScoreInfo Score; diff --git a/osu.Game/Screens/Play/ResumeOverlay.cs b/osu.Game/Screens/Play/ResumeOverlay.cs index 7ed95c4ce3..fae406bd6b 100644 --- a/osu.Game/Screens/Play/ResumeOverlay.cs +++ b/osu.Game/Screens/Play/ResumeOverlay.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Play /// /// An overlay which can be used to require further user actions before gameplay is resumed. /// - public abstract class ResumeOverlay : VisibilityContainer + public abstract partial class ResumeOverlay : VisibilityContainer { public CursorContainer GameplayCursor { get; set; } diff --git a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs index 3eb659664a..e21daa737e 100644 --- a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs +++ b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs @@ -13,7 +13,7 @@ namespace osu.Game.Screens.Play /// /// A player instance which submits to a room backing. This is generally used by playlists and multiplayer. /// - public abstract class RoomSubmittingPlayer : SubmittingPlayer + public abstract partial class RoomSubmittingPlayer : SubmittingPlayer { protected readonly PlaylistItem PlaylistItem; protected readonly Room Room; diff --git a/osu.Game/Screens/Play/SaveFailedScoreButton.cs b/osu.Game/Screens/Play/SaveFailedScoreButton.cs index 7358ff3de4..20d2130e76 100644 --- a/osu.Game/Screens/Play/SaveFailedScoreButton.cs +++ b/osu.Game/Screens/Play/SaveFailedScoreButton.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Screens.Play { - public class SaveFailedScoreButton : CompositeDrawable + public partial class SaveFailedScoreButton : CompositeDrawable { private readonly Bindable state = new Bindable(); diff --git a/osu.Game/Screens/Play/ScreenSuspensionHandler.cs b/osu.Game/Screens/Play/ScreenSuspensionHandler.cs index cc1254975c..85948ea3f7 100644 --- a/osu.Game/Screens/Play/ScreenSuspensionHandler.cs +++ b/osu.Game/Screens/Play/ScreenSuspensionHandler.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Play /// /// Ensures screen is not suspended / dimmed while gameplay is active. /// - public class ScreenSuspensionHandler : Component + public partial class ScreenSuspensionHandler : Component { private readonly GameplayClockContainer gameplayClockContainer; private IBindable isPaused; diff --git a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs index 7152fb7473..d6c8a0ad6a 100644 --- a/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs +++ b/osu.Game/Screens/Play/ScreenWithBeatmapBackground.cs @@ -8,7 +8,7 @@ using osu.Game.Screens.Backgrounds; namespace osu.Game.Screens.Play { - public abstract class ScreenWithBeatmapBackground : OsuScreen + public abstract partial class ScreenWithBeatmapBackground : OsuScreen { protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap.Value); diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 99fe659bf3..7d69f0ca18 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -25,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Play { - public class SkipOverlay : CompositeDrawable, IKeyBindingHandler + public partial class SkipOverlay : CompositeDrawable, IKeyBindingHandler { /// /// The total number of successful skips performed by this overlay. @@ -209,7 +209,7 @@ namespace osu.Game.Screens.Play { } - public class FadeContainer : Container, IStateful + public partial class FadeContainer : Container, IStateful { public event Action StateChanged; @@ -287,14 +287,14 @@ namespace osu.Game.Screens.Play public override void Show() => State = Visibility.Visible; } - private class ButtonContainer : VisibilityContainer + private partial class ButtonContainer : VisibilityContainer { protected override void PopIn() => this.FadeIn(fade_time); protected override void PopOut() => this.FadeOut(fade_time); } - private class Button : OsuClickableContainer + private partial class Button : OsuClickableContainer { private Color4 colourNormal; private Color4 colourHover; diff --git a/osu.Game/Screens/Play/SoloPlayer.cs b/osu.Game/Screens/Play/SoloPlayer.cs index ee19391b89..dafdf00136 100644 --- a/osu.Game/Screens/Play/SoloPlayer.cs +++ b/osu.Game/Screens/Play/SoloPlayer.cs @@ -17,7 +17,7 @@ using osu.Game.Screens.Play.HUD; namespace osu.Game.Screens.Play { - public class SoloPlayer : SubmittingPlayer + public partial class SoloPlayer : SubmittingPlayer { public SoloPlayer() : this(null) diff --git a/osu.Game/Screens/Play/SoloSpectator.cs b/osu.Game/Screens/Play/SoloSpectator.cs index 9ef05c3a05..e1692af351 100644 --- a/osu.Game/Screens/Play/SoloSpectator.cs +++ b/osu.Game/Screens/Play/SoloSpectator.cs @@ -33,7 +33,7 @@ using osuTK; namespace osu.Game.Screens.Play { [Cached(typeof(IPreviewTrackOwner))] - public class SoloSpectator : SpectatorScreen, IPreviewTrackOwner + public partial class SoloSpectator : SpectatorScreen, IPreviewTrackOwner { [NotNull] private readonly APIUser targetUser; diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs index 5aa310750b..240fbcf662 100644 --- a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -10,7 +10,7 @@ using osu.Game.Scoring; namespace osu.Game.Screens.Play { - public class SoloSpectatorPlayer : SpectatorPlayer + public partial class SoloSpectatorPlayer : SpectatorPlayer { private readonly Score score; diff --git a/osu.Game/Screens/Play/SpectatorPlayer.cs b/osu.Game/Screens/Play/SpectatorPlayer.cs index 68cc21fc1c..30a5ac3741 100644 --- a/osu.Game/Screens/Play/SpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SpectatorPlayer.cs @@ -18,7 +18,7 @@ using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Play { - public abstract class SpectatorPlayer : Player + public abstract partial class SpectatorPlayer : Player { [Resolved] protected SpectatorClient SpectatorClient { get; private set; } diff --git a/osu.Game/Screens/Play/SpectatorPlayerLoader.cs b/osu.Game/Screens/Play/SpectatorPlayerLoader.cs index 6b664a4f96..3830443ce8 100644 --- a/osu.Game/Screens/Play/SpectatorPlayerLoader.cs +++ b/osu.Game/Screens/Play/SpectatorPlayerLoader.cs @@ -9,7 +9,7 @@ using osu.Game.Scoring; namespace osu.Game.Screens.Play { - public class SpectatorPlayerLoader : PlayerLoader + public partial class SpectatorPlayerLoader : PlayerLoader { public readonly ScoreInfo Score; diff --git a/osu.Game/Screens/Play/SpectatorResultsScreen.cs b/osu.Game/Screens/Play/SpectatorResultsScreen.cs index 3d320bd294..b54dbb387a 100644 --- a/osu.Game/Screens/Play/SpectatorResultsScreen.cs +++ b/osu.Game/Screens/Play/SpectatorResultsScreen.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Play { - public class SpectatorResultsScreen : SoloResultsScreen + public partial class SpectatorResultsScreen : SoloResultsScreen { public SpectatorResultsScreen(ScoreInfo score) : base(score, false) diff --git a/osu.Game/Screens/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs index 9ac673ae52..57b7c84e89 100644 --- a/osu.Game/Screens/Play/SquareGraph.cs +++ b/osu.Game/Screens/Play/SquareGraph.cs @@ -19,7 +19,7 @@ using osu.Framework.Threading; namespace osu.Game.Screens.Play { - public class SquareGraph : Container + public partial class SquareGraph : Container { private BufferedContainer columns; @@ -176,7 +176,7 @@ namespace osu.Game.Screens.Play calculatedValues = newValues.ToArray(); } - public class Column : Container, IStateful + public partial class Column : Container, IStateful { protected readonly Color4 EmptyColour = Color4.White.Opacity(20); public Color4 LitColour = Color4.LightBlue; diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index fb296d7988..14453c8cbe 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play /// /// A player instance which supports submitting scores to an online store. /// - public abstract class SubmittingPlayer : Player + public abstract partial class SubmittingPlayer : Player { /// /// The token to be used for the current submission. This is fetched via a request created by . diff --git a/osu.Game/Screens/Ranking/AspectContainer.cs b/osu.Game/Screens/Ranking/AspectContainer.cs index 1c93d08474..9ec2a15044 100644 --- a/osu.Game/Screens/Ranking/AspectContainer.cs +++ b/osu.Game/Screens/Ranking/AspectContainer.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Screens.Ranking { - public class AspectContainer : Container + public partial class AspectContainer : Container { protected override void Update() { diff --git a/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs index 3e67868f34..402322c611 100644 --- a/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Contracted/ContractedPanelMiddleContent.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Ranking.Contracted /// /// The content that appears in the middle of a contracted . /// - public class ContractedPanelMiddleContent : CompositeDrawable + public partial class ContractedPanelMiddleContent : CompositeDrawable { private readonly ScoreInfo score; diff --git a/osu.Game/Screens/Ranking/Contracted/ContractedPanelTopContent.cs b/osu.Game/Screens/Ranking/Contracted/ContractedPanelTopContent.cs index 74b2f4ef93..93bc7c41e1 100644 --- a/osu.Game/Screens/Ranking/Contracted/ContractedPanelTopContent.cs +++ b/osu.Game/Screens/Ranking/Contracted/ContractedPanelTopContent.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Screens.Ranking.Contracted { - public class ContractedPanelTopContent : CompositeDrawable + public partial class ContractedPanelTopContent : CompositeDrawable { public readonly Bindable ScorePosition = new Bindable(); diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index a1879c5c9b..3285ebc914 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// /// The component that displays the player's accuracy on the results screen. /// - public class AccuracyCircle : CompositeDrawable + public partial class AccuracyCircle : CompositeDrawable { /// /// Duration for the transforms causing this component to appear. diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs index 80415dbbc2..5432b4cbeb 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankBadge.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// /// Contains a that is positioned around the . /// - public class RankBadge : CompositeDrawable + public partial class RankBadge : CompositeDrawable { /// /// The accuracy value corresponding to the displayed by this badge. diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs index 573833932f..7e73767318 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankNotch.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// /// A solid "notch" of the that appears at the ends of the rank circles to add separation. /// - public class RankNotch : CompositeDrawable + public partial class RankNotch : CompositeDrawable { private readonly float position; diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs index 2d9c1f9d07..b7adcb032f 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/RankText.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// /// The text that appears in the middle of the displaying the user's rank. /// - public class RankText : CompositeDrawable + public partial class RankText : CompositeDrawable { private readonly ScoreRank rank; diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs index b4f41e0f39..601c47ea55 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy /// /// Contains a with smoothened edges. /// - public class SmoothCircularProgress : CompositeDrawable + public partial class SmoothCircularProgress : CompositeDrawable { public Bindable Current { diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 829ba83696..8fe0ae509b 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Ranking.Expanded /// /// The content that appears in the middle section of the . /// - public class ExpandedPanelMiddleContent : CompositeDrawable + public partial class ExpandedPanelMiddleContent : CompositeDrawable { private const float padding = 10; @@ -280,7 +280,7 @@ namespace osu.Game.Screens.Ranking.Expanded }); } - public class PlayedOnText : OsuSpriteText + public partial class PlayedOnText : OsuSpriteText { private readonly DateTimeOffset time; private readonly Bindable prefer24HourTime = new Bindable(); diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs index 2708090855..c834d541eb 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelTopContent.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Ranking.Expanded /// /// The content that appears in the middle section of the . /// - public class ExpandedPanelTopContent : CompositeDrawable + public partial class ExpandedPanelTopContent : CompositeDrawable { private readonly APIUser user; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs index 824156598c..4b8c057235 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/AccuracyStatistic.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics /// /// A to display the player's accuracy. /// - public class AccuracyStatistic : StatisticDisplay + public partial class AccuracyStatistic : StatisticDisplay { private readonly double accuracy; @@ -42,7 +42,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics protected override Drawable CreateContent() => counter = new Counter(); - private class Counter : RollingCounter + private partial class Counter : RollingCounter { protected override double RollingDuration => AccuracyCircle.ACCURACY_TRANSFORM_DURATION; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs index 3505786b64..6290cee6da 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/ComboStatistic.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics /// /// A to display the player's combo. /// - public class ComboStatistic : CounterStatistic + public partial class ComboStatistic : CounterStatistic { private readonly bool isPerfect; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs index 17a12a76a5..8528dac83b 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/CounterStatistic.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics /// /// A to display general numeric values. /// - public class CounterStatistic : StatisticDisplay + public partial class CounterStatistic : StatisticDisplay { private readonly int count; private readonly int? maxCount; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs index c23a5e668d..863c450617 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/HitResultStatistic.cs @@ -10,7 +10,7 @@ using osu.Game.Scoring; namespace osu.Game.Screens.Ranking.Expanded.Statistics { - public class HitResultStatistic : CounterStatistic + public partial class HitResultStatistic : CounterStatistic { public readonly HitResult Result; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs index 332215e15d..22509b2cea 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs @@ -15,7 +15,7 @@ using osu.Game.Scoring; namespace osu.Game.Screens.Ranking.Expanded.Statistics { - public class PerformanceStatistic : StatisticDisplay + public partial class PerformanceStatistic : StatisticDisplay { private readonly ScoreInfo score; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticCounter.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticCounter.cs index 36d6d6fa7c..ecadc9eed6 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticCounter.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticCounter.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Screens.Ranking.Expanded.Statistics { - public class StatisticCounter : RollingCounter + public partial class StatisticCounter : RollingCounter { protected override double RollingDuration => AccuracyCircle.ACCURACY_TRANSFORM_DURATION; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs index 0d8dcda895..686b6c7d47 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/StatisticDisplay.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics /// /// A statistic from the score to be displayed in the . /// - public abstract class StatisticDisplay : CompositeDrawable + public abstract partial class StatisticDisplay : CompositeDrawable { protected SpriteText HeaderText { get; private set; } diff --git a/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs b/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs index c7286a1838..b017a3a63d 100644 --- a/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs +++ b/osu.Game/Screens/Ranking/Expanded/TotalScoreCounter.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Ranking.Expanded /// /// A counter for the player's total score to be displayed in the . /// - public class TotalScoreCounter : RollingCounter + public partial class TotalScoreCounter : RollingCounter { protected override double RollingDuration => AccuracyCircle.ACCURACY_TRANSFORM_DURATION; diff --git a/osu.Game/Screens/Ranking/ReplayDownloadButton.cs b/osu.Game/Screens/Ranking/ReplayDownloadButton.cs index 7081a0156e..5c5cb61b79 100644 --- a/osu.Game/Screens/Ranking/ReplayDownloadButton.cs +++ b/osu.Game/Screens/Ranking/ReplayDownloadButton.cs @@ -15,7 +15,7 @@ using osuTK; namespace osu.Game.Screens.Ranking { - public class ReplayDownloadButton : CompositeDrawable + public partial class ReplayDownloadButton : CompositeDrawable { public readonly Bindable Score = new Bindable(); diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index 486df8653f..f3aca43a9d 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -29,7 +29,7 @@ using osuTK; namespace osu.Game.Screens.Ranking { - public abstract class ResultsScreen : ScreenWithBeatmapBackground, IKeyBindingHandler + public abstract partial class ResultsScreen : ScreenWithBeatmapBackground, IKeyBindingHandler { protected const float BACKGROUND_BLUR = 20; private static readonly float screen_height = 768 - TwoLayerButton.SIZE_EXTENDED.Y; @@ -357,7 +357,7 @@ namespace osu.Game.Screens.Ranking { } - protected class VerticalScrollContainer : OsuScrollContainer + protected partial class VerticalScrollContainer : OsuScrollContainer { protected override Container Content => content; diff --git a/osu.Game/Screens/Ranking/RetryButton.cs b/osu.Game/Screens/Ranking/RetryButton.cs index c56f364ae8..c7d2416e29 100644 --- a/osu.Game/Screens/Ranking/RetryButton.cs +++ b/osu.Game/Screens/Ranking/RetryButton.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Screens.Ranking { - public class RetryButton : OsuAnimatedButton + public partial class RetryButton : OsuAnimatedButton { private readonly Box background; diff --git a/osu.Game/Screens/Ranking/ScorePanel.cs b/osu.Game/Screens/Ranking/ScorePanel.cs index cb777de144..5aecf18033 100644 --- a/osu.Game/Screens/Ranking/ScorePanel.cs +++ b/osu.Game/Screens/Ranking/ScorePanel.cs @@ -25,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Ranking { - public class ScorePanel : CompositeDrawable, IStateful + public partial class ScorePanel : CompositeDrawable, IStateful { /// /// Width of the panel when contracted. diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index 46f9efd126..29dec42083 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -21,7 +21,7 @@ using osuTK.Input; namespace osu.Game.Screens.Ranking { - public class ScorePanelList : CompositeDrawable + public partial class ScorePanelList : CompositeDrawable { /// /// Normal spacing between all panels. @@ -322,7 +322,7 @@ namespace osu.Game.Screens.Ranking loadCancellationSource?.Cancel(); } - private class Flow : FillFlowContainer + private partial class Flow : FillFlowContainer { public override IEnumerable FlowingChildren => applySorting(AliveInternalChildren); @@ -339,7 +339,7 @@ namespace osu.Game.Screens.Ranking .ThenBy(s => s.Panel.Score.OnlineID); } - private class Scroll : OsuScrollContainer + private partial class Scroll : OsuScrollContainer { public new float Target => base.Target; diff --git a/osu.Game/Screens/Ranking/ScorePanelTrackingContainer.cs b/osu.Game/Screens/Ranking/ScorePanelTrackingContainer.cs index b4d6d481ef..ec153cbd63 100644 --- a/osu.Game/Screens/Ranking/ScorePanelTrackingContainer.cs +++ b/osu.Game/Screens/Ranking/ScorePanelTrackingContainer.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Ranking /// /// A which tracks the size of a , to which the can be added or removed. /// - public class ScorePanelTrackingContainer : CompositeDrawable + public partial class ScorePanelTrackingContainer : CompositeDrawable { /// /// The that created this . diff --git a/osu.Game/Screens/Ranking/SoloResultsScreen.cs b/osu.Game/Screens/Ranking/SoloResultsScreen.cs index 4312c9528f..3774cf16b1 100644 --- a/osu.Game/Screens/Ranking/SoloResultsScreen.cs +++ b/osu.Game/Screens/Ranking/SoloResultsScreen.cs @@ -15,7 +15,7 @@ using osu.Game.Scoring; namespace osu.Game.Screens.Ranking { - public class SoloResultsScreen : ResultsScreen + public partial class SoloResultsScreen : ResultsScreen { private GetScoresRequest getScoreRequest; diff --git a/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs b/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs index a0a9c1c1e2..bb9905d29c 100644 --- a/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs +++ b/osu.Game/Screens/Ranking/Statistics/AverageHitError.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// /// Displays the unstable rate statistic for a given play. /// - public class AverageHitError : SimpleStatisticItem + public partial class AverageHitError : SimpleStatisticItem { /// /// Creates and computes an statistic. diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 764237ef96..6b1850002d 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// /// A graph which displays the distribution of hit timing in a series of s. /// - public class HitEventTimingDistributionGraph : CompositeDrawable + public partial class HitEventTimingDistributionGraph : CompositeDrawable { /// /// The number of bins on each side of the timing distribution. @@ -204,7 +204,7 @@ namespace osu.Game.Screens.Ranking.Statistics } } - private class Bar : CompositeDrawable + private partial class Bar : CompositeDrawable { private readonly IReadOnlyList> values; private readonly float maxValue; diff --git a/osu.Game/Screens/Ranking/Statistics/PerformanceBreakdownChart.cs b/osu.Game/Screens/Ranking/Statistics/PerformanceBreakdownChart.cs index 3462a85e1c..10cb77fa91 100644 --- a/osu.Game/Screens/Ranking/Statistics/PerformanceBreakdownChart.cs +++ b/osu.Game/Screens/Ranking/Statistics/PerformanceBreakdownChart.cs @@ -26,7 +26,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Ranking.Statistics { - public class PerformanceBreakdownChart : Container + public partial class PerformanceBreakdownChart : Container { private readonly ScoreInfo score; private readonly IBeatmap playableBeatmap; diff --git a/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs b/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs index ecff631c7e..99f4e1e342 100644 --- a/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs +++ b/osu.Game/Screens/Ranking/Statistics/SimpleStatisticItem.cs @@ -14,7 +14,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// Represents a simple statistic item (one that only needs textual display). /// Richer visualisations should be done with s. /// - public abstract class SimpleStatisticItem : Container + public abstract partial class SimpleStatisticItem : Container { /// /// The text to display as the statistic's value. @@ -59,7 +59,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// /// Strongly-typed generic specialisation for . /// - public class SimpleStatisticItem : SimpleStatisticItem + public partial class SimpleStatisticItem : SimpleStatisticItem { private TValue value; diff --git a/osu.Game/Screens/Ranking/Statistics/SimpleStatisticTable.cs b/osu.Game/Screens/Ranking/Statistics/SimpleStatisticTable.cs index f1eb16ca80..d10888be43 100644 --- a/osu.Game/Screens/Ranking/Statistics/SimpleStatisticTable.cs +++ b/osu.Game/Screens/Ranking/Statistics/SimpleStatisticTable.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// Represents a table with simple statistics (ones that only need textual display). /// Richer visualisations should be done with s and s. /// - public class SimpleStatisticTable : CompositeDrawable + public partial class SimpleStatisticTable : CompositeDrawable { private readonly SimpleStatisticItem[] items; private readonly int columnCount; @@ -98,7 +98,7 @@ namespace osu.Game.Screens.Ranking.Statistics Direction = FillDirection.Vertical }; - private class Spacer : CompositeDrawable + private partial class Spacer : CompositeDrawable { public Spacer() { diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs index 1505585205..d3327224dc 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticContainer.cs @@ -18,7 +18,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// /// Wraps a to add a header and suitable layout for use in . /// - internal class StatisticContainer : CompositeDrawable + internal partial class StatisticContainer : CompositeDrawable { /// /// Creates a new . diff --git a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs index 79d7b99e51..91102d6647 100644 --- a/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs +++ b/osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs @@ -24,7 +24,7 @@ using osuTK; namespace osu.Game.Screens.Ranking.Statistics { - public class StatisticsPanel : VisibilityContainer + public partial class StatisticsPanel : VisibilityContainer { public const float SIDE_PADDING = 30; diff --git a/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs b/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs index 4ab085fa23..de01668029 100644 --- a/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs +++ b/osu.Game/Screens/Ranking/Statistics/UnstableRate.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Ranking.Statistics /// /// Displays the unstable rate statistic for a given play. /// - public class UnstableRate : SimpleStatisticItem + public partial class UnstableRate : SimpleStatisticItem { /// /// Creates and computes an statistic. diff --git a/osu.Game/Screens/ScreenWhiteBox.cs b/osu.Game/Screens/ScreenWhiteBox.cs index 550fda5480..25afe119be 100644 --- a/osu.Game/Screens/ScreenWhiteBox.cs +++ b/osu.Game/Screens/ScreenWhiteBox.cs @@ -20,7 +20,7 @@ using osu.Framework.Graphics.Sprites; namespace osu.Game.Screens { - public class ScreenWhiteBox : OsuScreen + public partial class ScreenWhiteBox : OsuScreen { private readonly UnderConstructionMessage message; @@ -95,7 +95,7 @@ namespace osu.Game.Screens return new Color4(r, g, b, 255); } - private class ChildModeButton : TwoLayerButton + private partial class ChildModeButton : TwoLayerButton { public ChildModeButton() { @@ -105,7 +105,7 @@ namespace osu.Game.Screens } } - public class UnderConstructionMessage : CompositeDrawable + public partial class UnderConstructionMessage : CompositeDrawable { public FillFlowContainer TextContainer { get; } diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 752a1ede64..6955b8ef56 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -32,7 +32,7 @@ using Realms; namespace osu.Game.Screens.Select { - public class BeatmapCarousel : CompositeDrawable, IKeyBindingHandler + public partial class BeatmapCarousel : CompositeDrawable, IKeyBindingHandler { /// /// Height of the area above the carousel that should be treated as visible due to transparency of elements in front of it. @@ -1075,7 +1075,7 @@ namespace osu.Game.Screens.Select } } - protected class CarouselScrollContainer : UserTrackingScrollContainer + protected partial class CarouselScrollContainer : UserTrackingScrollContainer { private bool rightMouseScrollBlocked; diff --git a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs index 0996e3e202..c0f97a05e2 100644 --- a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs +++ b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs @@ -10,7 +10,7 @@ using osu.Game.Scoring; namespace osu.Game.Screens.Select { - public class BeatmapClearScoresDialog : DeleteConfirmationDialog + public partial class BeatmapClearScoresDialog : DeleteConfirmationDialog { [Resolved] private ScoreManager scoreManager { get; set; } = null!; diff --git a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs index 3d3e8b6d73..4ab23c3a3a 100644 --- a/osu.Game/Screens/Select/BeatmapDeleteDialog.cs +++ b/osu.Game/Screens/Select/BeatmapDeleteDialog.cs @@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Select { - public class BeatmapDeleteDialog : DeleteConfirmationDialog + public partial class BeatmapDeleteDialog : DeleteConfirmationDialog { private readonly BeatmapSetInfo beatmapSet; diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index bf6803f551..595b86924b 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -11,7 +11,7 @@ using osu.Game.Beatmaps; namespace osu.Game.Screens.Select { - public abstract class BeatmapDetailArea : Container + public abstract partial class BeatmapDetailArea : Container { private const float details_padding = 10; diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs index 3c0d621abe..f9dab2bb1d 100644 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs @@ -17,7 +17,7 @@ using osu.Framework.Graphics.Shapes; namespace osu.Game.Screens.Select { - public class BeatmapDetailAreaTabControl : Container + public partial class BeatmapDetailAreaTabControl : Container { public const float HEIGHT = 24; diff --git a/osu.Game/Screens/Select/BeatmapDetails.cs b/osu.Game/Screens/Select/BeatmapDetails.cs index 90418efe15..0a14df6480 100644 --- a/osu.Game/Screens/Select/BeatmapDetails.cs +++ b/osu.Game/Screens/Select/BeatmapDetails.cs @@ -23,7 +23,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Select { - public class BeatmapDetails : Container + public partial class BeatmapDetails : Container { private const float spacing = 10; private const float transition_duration = 250; @@ -273,7 +273,7 @@ namespace osu.Game.Screens.Select loading.Hide(); } - private class DetailBox : Container + private partial class DetailBox : Container { private readonly Container content; protected override Container Content => content; diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 3ee9a11b24..2102df1022 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -33,7 +33,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Select { - public class BeatmapInfoWedge : VisibilityContainer + public partial class BeatmapInfoWedge : VisibilityContainer { public const float BORDER_THICKNESS = 2.5f; private const float shear_width = 36.75f; @@ -148,7 +148,7 @@ namespace osu.Game.Screens.Select } } - public class WedgeInfoText : Container + public partial class WedgeInfoText : Container { public OsuSpriteText VersionLabel { get; private set; } public OsuSpriteText TitleLabel { get; private set; } @@ -456,7 +456,7 @@ namespace osu.Game.Screens.Select cancellationSource?.Cancel(); } - public class InfoLabel : Container, IHasTooltip + public partial class InfoLabel : Container, IHasTooltip { public LocalisableString TooltipText { get; } diff --git a/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs b/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs index 68f0c92097..d5d258704b 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedgeBackground.cs @@ -15,7 +15,7 @@ using osu.Framework.Graphics.Shapes; namespace osu.Game.Screens.Select { - internal class BeatmapInfoWedgeBackground : CompositeDrawable + internal partial class BeatmapInfoWedgeBackground : CompositeDrawable { private readonly IWorkingBeatmap beatmap; diff --git a/osu.Game/Screens/Select/Carousel/CarouselHeader.cs b/osu.Game/Screens/Select/Carousel/CarouselHeader.cs index 5cde5f7d5a..1ae69bc951 100644 --- a/osu.Game/Screens/Select/Carousel/CarouselHeader.cs +++ b/osu.Game/Screens/Select/Carousel/CarouselHeader.cs @@ -21,7 +21,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Select.Carousel { - public class CarouselHeader : Container + public partial class CarouselHeader : Container { public Container BorderContainer; @@ -93,7 +93,7 @@ namespace osu.Game.Screens.Select.Carousel } } - public class HoverLayer : HoverSampleDebounceComponent + public partial class HoverLayer : HoverSampleDebounceComponent { private Sample sampleHover; diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs index c3cb04680b..4e10961e55 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs @@ -34,7 +34,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Select.Carousel { - public class DrawableCarouselBeatmap : DrawableCarouselItem, IHasContextMenu + public partial class DrawableCarouselBeatmap : DrawableCarouselItem, IHasContextMenu { public const float CAROUSEL_BEATMAP_SPACING = 5; diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs index 040f954bba..a7fb25bc1b 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmapSet.cs @@ -23,7 +23,7 @@ using osu.Game.Overlays; namespace osu.Game.Screens.Select.Carousel { - public class DrawableCarouselBeatmapSet : DrawableCarouselItem, IHasContextMenu + public partial class DrawableCarouselBeatmapSet : DrawableCarouselItem, IHasContextMenu { public const float HEIGHT = MAX_HEIGHT; diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs index 133bf5f9c3..26a32c23dd 100644 --- a/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs +++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs @@ -13,7 +13,7 @@ using osuTK; namespace osu.Game.Screens.Select.Carousel { - public abstract class DrawableCarouselItem : PoolableDrawable + public abstract partial class DrawableCarouselItem : PoolableDrawable { public const float MAX_HEIGHT = 80; diff --git a/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs b/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs index cc904fc1da..911b8fd4da 100644 --- a/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs +++ b/osu.Game/Screens/Select/Carousel/FilterableDifficultyIcon.cs @@ -10,7 +10,7 @@ using osu.Game.Beatmaps.Drawables; namespace osu.Game.Screens.Select.Carousel { - public class FilterableDifficultyIcon : DifficultyIcon + public partial class FilterableDifficultyIcon : DifficultyIcon { private readonly BindableBool filtered = new BindableBool(); diff --git a/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs b/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs index 8b4140df56..6e01c82a08 100644 --- a/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs +++ b/osu.Game/Screens/Select/Carousel/GroupedDifficultyIcon.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Select.Carousel /// /// Used in cases when there are too many difficulty icons to show. /// - public class GroupedDifficultyIcon : DifficultyIcon + public partial class GroupedDifficultyIcon : DifficultyIcon { public readonly List Items; diff --git a/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs b/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs index 2a435e084c..a9dc59cc39 100644 --- a/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs +++ b/osu.Game/Screens/Select/Carousel/SetPanelBackground.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Select.Carousel { - public class SetPanelBackground : BufferedContainer + public partial class SetPanelBackground : BufferedContainer { public SetPanelBackground(IWorkingBeatmap working) : base(cachedFrameBuffer: true) diff --git a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs b/osu.Game/Screens/Select/Carousel/SetPanelContent.cs index a95d9078a2..0de507edce 100644 --- a/osu.Game/Screens/Select/Carousel/SetPanelContent.cs +++ b/osu.Game/Screens/Select/Carousel/SetPanelContent.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Screens.Select.Carousel { - public class SetPanelContent : CompositeDrawable + public partial class SetPanelContent : CompositeDrawable { // Disallow interacting with difficulty icons on a panel until the panel has been selected. public override bool PropagatePositionalInputSubTree => carouselSet.State.Value == CarouselItemState.Selected; diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs index 0f000555d5..f1b773c831 100644 --- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs +++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs @@ -19,7 +19,7 @@ using Realms; namespace osu.Game.Screens.Select.Carousel { - public class TopLocalRank : CompositeDrawable + public partial class TopLocalRank : CompositeDrawable { private readonly BeatmapInfo beatmapInfo; diff --git a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs b/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs index 1bb607bcf3..e45583887a 100644 --- a/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs +++ b/osu.Game/Screens/Select/Carousel/UpdateBeatmapSetButton.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Select.Carousel { - public class UpdateBeatmapSetButton : OsuAnimatedButton + public partial class UpdateBeatmapSetButton : OsuAnimatedButton { private readonly BeatmapSetInfo beatmapSetInfo; private SpriteIcon icon = null!; diff --git a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs b/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs index f5267e905e..e1aa662942 100644 --- a/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs +++ b/osu.Game/Screens/Select/Carousel/UpdateLocalConfirmationDialog.cs @@ -8,7 +8,7 @@ using osu.Game.Localisation; namespace osu.Game.Screens.Select.Carousel { - public class UpdateLocalConfirmationDialog : DeleteConfirmationDialog + public partial class UpdateLocalConfirmationDialog : DeleteConfirmationDialog { public UpdateLocalConfirmationDialog(Action onConfirm) { diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs index 693f182065..5d0588e67b 100644 --- a/osu.Game/Screens/Select/Details/AdvancedStats.cs +++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs @@ -28,7 +28,7 @@ using osu.Game.Rulesets; namespace osu.Game.Screens.Select.Details { - public class AdvancedStats : Container + public partial class AdvancedStats : Container { [Resolved] private IBindable> mods { get; set; } @@ -173,7 +173,7 @@ namespace osu.Game.Screens.Select.Details starDifficultyCancellationSource?.Cancel(); } - public class StatisticRow : Container, IHasAccentColour + public partial class StatisticRow : Container, IHasAccentColour { private const float value_width = 25; private const float name_width = 70; diff --git a/osu.Game/Screens/Select/Details/FailRetryGraph.cs b/osu.Game/Screens/Select/Details/FailRetryGraph.cs index 6fa6d50217..9891ef6463 100644 --- a/osu.Game/Screens/Select/Details/FailRetryGraph.cs +++ b/osu.Game/Screens/Select/Details/FailRetryGraph.cs @@ -14,7 +14,7 @@ using osu.Game.Beatmaps; namespace osu.Game.Screens.Select.Details { - public class FailRetryGraph : Container + public partial class FailRetryGraph : Container { private readonly BarGraph retryGraph, failGraph; diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index 39cb9c3d15..3664a89394 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -15,7 +15,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Select.Details { - public class UserRatings : Container + public partial class UserRatings : Container { private readonly FillFlowContainer header; private readonly Bar ratingsBar; diff --git a/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs b/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs index 45e7ff4caa..523fdf4628 100644 --- a/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs +++ b/osu.Game/Screens/Select/DifficultyRangeFilterControl.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Select { - internal class DifficultyRangeFilterControl : CompositeDrawable + internal partial class DifficultyRangeFilterControl : CompositeDrawable { private Bindable lowerStars = null!; private Bindable upperStars = null!; @@ -63,7 +63,7 @@ namespace osu.Game.Screens.Select upperStars.ValueChanged += max => lowerStars.Value = Math.Min(max.NewValue - 0.1, lowerStars.Value); } - private class MinimumStarsSlider : StarsSlider + private partial class MinimumStarsSlider : StarsSlider { public MinimumStarsSlider() : base("0") @@ -87,7 +87,7 @@ namespace osu.Game.Screens.Select && screenSpacePos.X <= Nub.ScreenSpaceDrawQuad.TopRight.X; } - private class MaximumStarsSlider : StarsSlider + private partial class MaximumStarsSlider : StarsSlider { public MaximumStarsSlider() : base("∞") @@ -106,7 +106,7 @@ namespace osu.Game.Screens.Select && screenSpacePos.X >= Nub.ScreenSpaceDrawQuad.TopLeft.X; } - private class StarsSlider : OsuSliderBar + private partial class StarsSlider : OsuSliderBar { private readonly string defaultString; diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index ae82285fba..4aebb96e18 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -24,7 +24,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Select { - public class FilterControl : Container + public partial class FilterControl : Container { public const float HEIGHT = 2 * side_margin + 85; private const float side_margin = 20; diff --git a/osu.Game/Screens/Select/Footer.cs b/osu.Game/Screens/Select/Footer.cs index f9fc2890b0..933df2464a 100644 --- a/osu.Game/Screens/Select/Footer.cs +++ b/osu.Game/Screens/Select/Footer.cs @@ -16,7 +16,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Select { - public class Footer : Container + public partial class Footer : Container { private readonly Box modeLight; diff --git a/osu.Game/Screens/Select/FooterButton.cs b/osu.Game/Screens/Select/FooterButton.cs index 230cdfc13e..128e750dca 100644 --- a/osu.Game/Screens/Select/FooterButton.cs +++ b/osu.Game/Screens/Select/FooterButton.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.Select { - public class FooterButton : OsuClickableContainer, IKeyBindingHandler + public partial class FooterButton : OsuClickableContainer, IKeyBindingHandler { public const float SHEAR_WIDTH = 7.5f; diff --git a/osu.Game/Screens/Select/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs index 21f81995be..9a84f9a0aa 100644 --- a/osu.Game/Screens/Select/FooterButtonMods.cs +++ b/osu.Game/Screens/Select/FooterButtonMods.cs @@ -22,7 +22,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Screens.Select { - public class FooterButtonMods : FooterButton, IHasCurrentValue> + public partial class FooterButtonMods : FooterButton, IHasCurrentValue> { public Bindable> Current { diff --git a/osu.Game/Screens/Select/FooterButtonOptions.cs b/osu.Game/Screens/Select/FooterButtonOptions.cs index 764f56e79c..e56efcb458 100644 --- a/osu.Game/Screens/Select/FooterButtonOptions.cs +++ b/osu.Game/Screens/Select/FooterButtonOptions.cs @@ -10,7 +10,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Screens.Select { - public class FooterButtonOptions : FooterButton + public partial class FooterButtonOptions : FooterButton { [BackgroundDependencyLoader] private void load(OsuColour colours) diff --git a/osu.Game/Screens/Select/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs index aad7fdff39..8d7463067e 100644 --- a/osu.Game/Screens/Select/FooterButtonRandom.cs +++ b/osu.Game/Screens/Select/FooterButtonRandom.cs @@ -17,7 +17,7 @@ using osuTK.Input; namespace osu.Game.Screens.Select { - public class FooterButtonRandom : FooterButton + public partial class FooterButtonRandom : FooterButton { public Action NextRandom { get; set; } public Action PreviousRandom { get; set; } diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 4cc3a30a1e..b8a2eec526 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -21,7 +21,7 @@ using Realms; namespace osu.Game.Screens.Select.Leaderboards { - public class BeatmapLeaderboard : Leaderboard + public partial class BeatmapLeaderboard : Leaderboard { public Action? ScoreSelected; diff --git a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs index d9312679bc..6349e9e5eb 100644 --- a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs +++ b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs @@ -10,7 +10,7 @@ using osu.Game.Beatmaps; namespace osu.Game.Screens.Select { - public class LocalScoreDeleteDialog : DeleteConfirmationDialog + public partial class LocalScoreDeleteDialog : DeleteConfirmationDialog { private readonly ScoreInfo score; diff --git a/osu.Game/Screens/Select/NoResultsPlaceholder.cs b/osu.Game/Screens/Select/NoResultsPlaceholder.cs index 73b53defe0..9f870503d3 100644 --- a/osu.Game/Screens/Select/NoResultsPlaceholder.cs +++ b/osu.Game/Screens/Select/NoResultsPlaceholder.cs @@ -17,7 +17,7 @@ using osuTK; namespace osu.Game.Screens.Select { - public class NoResultsPlaceholder : VisibilityContainer + public partial class NoResultsPlaceholder : VisibilityContainer { private FilterCriteria? filter; diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index 69800c4e86..0d3e1238f3 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -20,7 +20,7 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Select.Options { - public class BeatmapOptionsButton : OsuClickableContainer + public partial class BeatmapOptionsButton : OsuClickableContainer { private const float width = 130; diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs index 8785dac0aa..c92dc2e343 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsOverlay.cs @@ -19,7 +19,7 @@ using osu.Framework.Localisation; namespace osu.Game.Screens.Select.Options { - public class BeatmapOptionsOverlay : OsuFocusedOverlayContainer + public partial class BeatmapOptionsOverlay : OsuFocusedOverlayContainer { private const float transition_duration = 500; private const float x_position = 0.2f; diff --git a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs index a19acddb48..8a1b9ef3e1 100644 --- a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs @@ -14,7 +14,7 @@ using osu.Game.Screens.Select.Leaderboards; namespace osu.Game.Screens.Select { - public class PlayBeatmapDetailArea : BeatmapDetailArea + public partial class PlayBeatmapDetailArea : BeatmapDetailArea { public readonly BeatmapLeaderboard Leaderboard; diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index 94e4215175..f73cfe8d55 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Screens.Select { - public class PlaySongSelect : SongSelect + public partial class PlaySongSelect : SongSelect { private OsuScreen? playerLoader; diff --git a/osu.Game/Screens/Select/SkinDeleteDialog.cs b/osu.Game/Screens/Select/SkinDeleteDialog.cs index c701d9049f..9e11629890 100644 --- a/osu.Game/Screens/Select/SkinDeleteDialog.cs +++ b/osu.Game/Screens/Select/SkinDeleteDialog.cs @@ -7,7 +7,7 @@ using osu.Game.Overlays.Dialog; namespace osu.Game.Screens.Select { - public class SkinDeleteDialog : DeleteConfirmationDialog + public partial class SkinDeleteDialog : DeleteConfirmationDialog { private readonly Skin skin; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 18ea0f69a2..f4804c6a6c 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -42,7 +42,7 @@ using osu.Game.Skinning; namespace osu.Game.Screens.Select { - public abstract class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler + public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler { public static readonly float WEDGE_HEIGHT = 245; @@ -925,7 +925,7 @@ namespace osu.Game.Screens.Select return base.OnKeyDown(e); } - private class VerticalMaskingContainer : Container + private partial class VerticalMaskingContainer : Container { private const float panel_overflow = 1.2f; @@ -948,7 +948,7 @@ namespace osu.Game.Screens.Select } } - private class ResetScrollContainer : Container + private partial class ResetScrollContainer : Container { private readonly Action onHoverAction; @@ -964,7 +964,7 @@ namespace osu.Game.Screens.Select } } - internal class SoloModSelectOverlay : UserModSelectOverlay + internal partial class SoloModSelectOverlay : UserModSelectOverlay { protected override bool ShowPresets => true; } diff --git a/osu.Game/Screens/Select/WedgeBackground.cs b/osu.Game/Screens/Select/WedgeBackground.cs index 4a5b9d8911..da12c1a67a 100644 --- a/osu.Game/Screens/Select/WedgeBackground.cs +++ b/osu.Game/Screens/Select/WedgeBackground.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Shapes; namespace osu.Game.Screens.Select { - public class WedgeBackground : Container + public partial class WedgeBackground : Container { public WedgeBackground() { diff --git a/osu.Game/Screens/Spectate/SpectatorScreen.cs b/osu.Game/Screens/Spectate/SpectatorScreen.cs index 259ac0160d..2b56767bd0 100644 --- a/osu.Game/Screens/Spectate/SpectatorScreen.cs +++ b/osu.Game/Screens/Spectate/SpectatorScreen.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Spectate /// /// A which spectates one or more users. /// - public abstract class SpectatorScreen : OsuScreen + public abstract partial class SpectatorScreen : OsuScreen { protected IReadOnlyList Users => users; diff --git a/osu.Game/Screens/StartupScreen.cs b/osu.Game/Screens/StartupScreen.cs index 89761d80de..84ef3eac78 100644 --- a/osu.Game/Screens/StartupScreen.cs +++ b/osu.Game/Screens/StartupScreen.cs @@ -10,7 +10,7 @@ namespace osu.Game.Screens /// /// A screen which is shown once as part of the startup procedure. /// - public abstract class StartupScreen : OsuScreen + public abstract partial class StartupScreen : OsuScreen { public override bool AllowBackButton => false; diff --git a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs index 7df9a22ce4..29e9cd2515 100644 --- a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs +++ b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs @@ -11,7 +11,7 @@ using osuTK.Input; namespace osu.Game.Screens.Utility { - public class ButtonWithKeyBind : SettingsButton + public partial class ButtonWithKeyBind : SettingsButton { private readonly Key key; diff --git a/osu.Game/Screens/Utility/CircleGameplay.cs b/osu.Game/Screens/Utility/CircleGameplay.cs index 1ee5567c43..d97812acb4 100644 --- a/osu.Game/Screens/Utility/CircleGameplay.cs +++ b/osu.Game/Screens/Utility/CircleGameplay.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Screens.Utility { - public class CircleGameplay : LatencySampleComponent + public partial class CircleGameplay : LatencySampleComponent { private int nextLocation; @@ -111,7 +111,7 @@ namespace osu.Game.Screens.Utility hitEvents.Add(h); } - public class SampleHitCircle : LatencySampleComponent + public partial class SampleHitCircle : LatencySampleComponent { public HitEvent? HitEvent; diff --git a/osu.Game/Screens/Utility/LatencyArea.cs b/osu.Game/Screens/Utility/LatencyArea.cs index b7d45ba642..b225171f5d 100644 --- a/osu.Game/Screens/Utility/LatencyArea.cs +++ b/osu.Game/Screens/Utility/LatencyArea.cs @@ -17,7 +17,7 @@ using osuTK.Input; namespace osu.Game.Screens.Utility { [Cached] - public class LatencyArea : CompositeDrawable, IProvideCursor + public partial class LatencyArea : CompositeDrawable, IProvideCursor { [Resolved] private OverlayColourProvider overlayColourProvider { get; set; } = null!; diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index bacaccd68e..8ff6d3cf4f 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -30,7 +30,7 @@ using osuTK.Input; namespace osu.Game.Screens.Utility { [Cached] - public class LatencyCertifierScreen : OsuScreen + public partial class LatencyCertifierScreen : OsuScreen { private FrameSync previousFrameSyncMode; private double previousActiveHz; diff --git a/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs b/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs index aaf837eb60..251d283242 100644 --- a/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs +++ b/osu.Game/Screens/Utility/SampleComponents/LatencyCursorContainer.cs @@ -12,7 +12,7 @@ using osuTK.Input; namespace osu.Game.Screens.Utility.SampleComponents { - public class LatencyCursorContainer : CursorContainer + public partial class LatencyCursorContainer : CursorContainer { protected override Drawable CreateCursor() => new LatencyCursor(); @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Utility.SampleComponents return false; } - private class LatencyCursor : LatencySampleComponent + private partial class LatencyCursor : LatencySampleComponent { public LatencyCursor() { diff --git a/osu.Game/Screens/Utility/SampleComponents/LatencyMovableBox.cs b/osu.Game/Screens/Utility/SampleComponents/LatencyMovableBox.cs index 8b6841caf0..dcfcf602bf 100644 --- a/osu.Game/Screens/Utility/SampleComponents/LatencyMovableBox.cs +++ b/osu.Game/Screens/Utility/SampleComponents/LatencyMovableBox.cs @@ -10,7 +10,7 @@ using osuTK.Input; namespace osu.Game.Screens.Utility.SampleComponents { - public class LatencyMovableBox : LatencySampleComponent + public partial class LatencyMovableBox : LatencySampleComponent { private Box box = null!; diff --git a/osu.Game/Screens/Utility/SampleComponents/LatencySampleComponent.cs b/osu.Game/Screens/Utility/SampleComponents/LatencySampleComponent.cs index 834865d237..690376cf52 100644 --- a/osu.Game/Screens/Utility/SampleComponents/LatencySampleComponent.cs +++ b/osu.Game/Screens/Utility/SampleComponents/LatencySampleComponent.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays; namespace osu.Game.Screens.Utility.SampleComponents { - public abstract class LatencySampleComponent : CompositeDrawable + public abstract partial class LatencySampleComponent : CompositeDrawable { protected readonly BindableDouble SampleBPM = new BindableDouble(); protected readonly BindableDouble SampleApproachRate = new BindableDouble(); diff --git a/osu.Game/Screens/Utility/ScrollingGameplay.cs b/osu.Game/Screens/Utility/ScrollingGameplay.cs index 1f40514cd5..f1331d8fb2 100644 --- a/osu.Game/Screens/Utility/ScrollingGameplay.cs +++ b/osu.Game/Screens/Utility/ScrollingGameplay.cs @@ -18,7 +18,7 @@ using osuTK.Input; namespace osu.Game.Screens.Utility { - public class ScrollingGameplay : LatencySampleComponent + public partial class ScrollingGameplay : LatencySampleComponent { private const float judgement_position = 0.8f; private const float bar_height = 20; @@ -100,7 +100,7 @@ namespace osu.Game.Screens.Utility hitEvents.Add(h); } - public class SampleNote : LatencySampleComponent + public partial class SampleNote : LatencySampleComponent { public HitEvent? HitEvent; diff --git a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs index e14287c318..4486c8a9f0 100644 --- a/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs +++ b/osu.Game/Skinning/BeatmapSkinProvidingContainer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Skinning /// /// A container which overrides existing skin options with beatmap-local values. /// - public class BeatmapSkinProvidingContainer : SkinProvidingContainer + public partial class BeatmapSkinProvidingContainer : SkinProvidingContainer { private Bindable beatmapSkins; private Bindable beatmapColours; diff --git a/osu.Game/Skinning/Components/BigBlackBox.cs b/osu.Game/Skinning/Components/BigBlackBox.cs index 5bdee827ca..4210a70b72 100644 --- a/osu.Game/Skinning/Components/BigBlackBox.cs +++ b/osu.Game/Skinning/Components/BigBlackBox.cs @@ -21,7 +21,7 @@ namespace osu.Game.Skinning.Components /// Intended to be a test bed for skinning. May be removed at some point in the future. /// [UsedImplicitly] - public class BigBlackBox : CompositeDrawable, ISkinnableDrawable + public partial class BigBlackBox : CompositeDrawable, ISkinnableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Skinning/Editor/SkinBlueprint.cs b/osu.Game/Skinning/Editor/SkinBlueprint.cs index ecf1de89da..fc7e9e8ef1 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprint.cs +++ b/osu.Game/Skinning/Editor/SkinBlueprint.cs @@ -18,7 +18,7 @@ using osuTK.Graphics; namespace osu.Game.Skinning.Editor { - public class SkinBlueprint : SelectionBlueprint + public partial class SkinBlueprint : SelectionBlueprint { private Container box; @@ -131,7 +131,7 @@ namespace osu.Game.Skinning.Editor public override Quad SelectionQuad => drawable.ScreenSpaceDrawQuad; } - internal class AnchorOriginVisualiser : CompositeDrawable + internal partial class AnchorOriginVisualiser : CompositeDrawable { private readonly Drawable drawable; diff --git a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs index 2937b62eec..8e9256214f 100644 --- a/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs +++ b/osu.Game/Skinning/Editor/SkinBlueprintContainer.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Skinning.Editor { - public class SkinBlueprintContainer : BlueprintContainer + public partial class SkinBlueprintContainer : BlueprintContainer { private readonly Drawable target; diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs index 469657c03c..68ac84df48 100644 --- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Skinning.Editor { - public class SkinComponentToolbox : EditorSidebarSection + public partial class SkinComponentToolbox : EditorSidebarSection { public Action? RequestPlacement; @@ -81,7 +81,7 @@ namespace osu.Game.Skinning.Editor } } - public class ToolboxComponentButton : OsuButton + public partial class ToolboxComponentButton : OsuButton { public Action? RequestPlacement; @@ -171,7 +171,7 @@ namespace osu.Game.Skinning.Editor } } - public class DependencyBorrowingContainer : Container + public partial class DependencyBorrowingContainer : Container { protected override bool ShouldBeConsideredForInput(Drawable child) => false; diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 410f5d9347..1dd9c93845 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -32,7 +32,7 @@ using osu.Game.Screens.Edit.Components.Menus; namespace osu.Game.Skinning.Editor { [Cached(typeof(SkinEditor))] - public class SkinEditor : VisibilityContainer, ICanAcceptFiles, IKeyBindingHandler + public partial class SkinEditor : VisibilityContainer, ICanAcceptFiles, IKeyBindingHandler { public const double TRANSITION_DURATION = 500; @@ -424,7 +424,7 @@ namespace osu.Game.Skinning.Editor game?.UnregisterImportHandler(this); } - private class SkinEditorToast : Toast + private partial class SkinEditorToast : Toast { public SkinEditorToast(LocalisableString value, string skinDisplayName) : base(SkinSettingsStrings.SkinLayoutEditor, value, skinDisplayName) diff --git a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs index 000917f728..35e28ee665 100644 --- a/osu.Game/Skinning/Editor/SkinEditorOverlay.cs +++ b/osu.Game/Skinning/Editor/SkinEditorOverlay.cs @@ -23,7 +23,7 @@ namespace osu.Game.Skinning.Editor /// A container which handles loading a skin editor on user request for a specified target. /// This also handles the scaling / positioning adjustment of the target. /// - public class SkinEditorOverlay : OverlayContainer, IKeyBindingHandler + public partial class SkinEditorOverlay : OverlayContainer, IKeyBindingHandler { private readonly ScalingContainer scalingContainer; diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index 4efbf58881..c3907ea60d 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -27,7 +27,7 @@ using osuTK; namespace osu.Game.Skinning.Editor { - public class SkinEditorSceneLibrary : CompositeDrawable + public partial class SkinEditorSceneLibrary : CompositeDrawable { public const float HEIGHT = BUTTON_HEIGHT + padding * 2; @@ -120,7 +120,7 @@ namespace osu.Game.Skinning.Editor }; } - public class SceneButton : OsuButton + public partial class SceneButton : OsuButton { public SceneButton() { diff --git a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs index 2e2122f7c2..2c3f6238ec 100644 --- a/osu.Game/Skinning/Editor/SkinSelectionHandler.cs +++ b/osu.Game/Skinning/Editor/SkinSelectionHandler.cs @@ -20,7 +20,7 @@ using osuTK; namespace osu.Game.Skinning.Editor { - public class SkinSelectionHandler : SelectionHandler + public partial class SkinSelectionHandler : SelectionHandler { [Resolved] private SkinEditor skinEditor { get; set; } diff --git a/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs b/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs index 3e19fc3afe..8c08f40b70 100644 --- a/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Skinning.Editor { - internal class SkinSettingsToolbox : EditorSidebarSection + internal partial class SkinSettingsToolbox : EditorSidebarSection { protected override Container Content { get; } diff --git a/osu.Game/Skinning/LegacyAccuracyCounter.cs b/osu.Game/Skinning/LegacyAccuracyCounter.cs index bdcb85456a..e75fb1e7e9 100644 --- a/osu.Game/Skinning/LegacyAccuracyCounter.cs +++ b/osu.Game/Skinning/LegacyAccuracyCounter.cs @@ -8,7 +8,7 @@ using osuTK; namespace osu.Game.Skinning { - public class LegacyAccuracyCounter : GameplayAccuracyCounter, ISkinnableDrawable + public partial class LegacyAccuracyCounter : GameplayAccuracyCounter, ISkinnableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Skinning/LegacyComboCounter.cs b/osu.Game/Skinning/LegacyComboCounter.cs index f4caef26c2..c132a72001 100644 --- a/osu.Game/Skinning/LegacyComboCounter.cs +++ b/osu.Game/Skinning/LegacyComboCounter.cs @@ -15,7 +15,7 @@ namespace osu.Game.Skinning /// /// Uses the 'x' symbol and has a pop-out effect while rolling over. /// - public class LegacyComboCounter : CompositeDrawable, ISkinnableDrawable + public partial class LegacyComboCounter : CompositeDrawable, ISkinnableDrawable { public Bindable Current { get; } = new BindableInt { MinValue = 0 }; diff --git a/osu.Game/Skinning/LegacyHealthDisplay.cs b/osu.Game/Skinning/LegacyHealthDisplay.cs index 236e9c355e..c3cb9770fa 100644 --- a/osu.Game/Skinning/LegacyHealthDisplay.cs +++ b/osu.Game/Skinning/LegacyHealthDisplay.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Skinning { - public class LegacyHealthDisplay : HealthDisplay, ISkinnableDrawable + public partial class LegacyHealthDisplay : HealthDisplay, ISkinnableDrawable { private const double epic_cutoff = 0.5; @@ -94,7 +94,7 @@ namespace osu.Game.Skinning return Color4.White; } - public class LegacyOldStyleMarker : LegacyMarker + public partial class LegacyOldStyleMarker : LegacyMarker { private readonly Texture normalTexture; private readonly Texture dangerTexture; @@ -129,7 +129,7 @@ namespace osu.Game.Skinning } } - public class LegacyNewStyleMarker : LegacyMarker + public partial class LegacyNewStyleMarker : LegacyMarker { private readonly ISkin skin; @@ -153,7 +153,7 @@ namespace osu.Game.Skinning } } - internal abstract class LegacyFill : LegacyHealthPiece + internal abstract partial class LegacyFill : LegacyHealthPiece { protected LegacyFill(ISkin skin) { @@ -175,7 +175,7 @@ namespace osu.Game.Skinning } } - internal class LegacyOldStyleFill : LegacyFill + internal partial class LegacyOldStyleFill : LegacyFill { public LegacyOldStyleFill(ISkin skin) : base(skin) @@ -184,7 +184,7 @@ namespace osu.Game.Skinning } } - internal class LegacyNewStyleFill : LegacyFill + internal partial class LegacyNewStyleFill : LegacyFill { public LegacyNewStyleFill(ISkin skin) : base(skin) @@ -199,7 +199,7 @@ namespace osu.Game.Skinning } } - public abstract class LegacyMarker : LegacyHealthPiece + public abstract partial class LegacyMarker : LegacyHealthPiece { protected Sprite Main; @@ -252,7 +252,7 @@ namespace osu.Game.Skinning Main.ScaleTo(1.4f).Then().ScaleTo(1, 200, Easing.Out); } - public class LegacyHealthPiece : CompositeDrawable + public partial class LegacyHealthPiece : CompositeDrawable { public Bindable Current { get; } = new Bindable(); diff --git a/osu.Game/Skinning/LegacyJudgementPieceNew.cs b/osu.Game/Skinning/LegacyJudgementPieceNew.cs index 39b266ab9f..2430e511c4 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceNew.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceNew.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Skinning { - public class LegacyJudgementPieceNew : CompositeDrawable, IAnimatableJudgement + public partial class LegacyJudgementPieceNew : CompositeDrawable, IAnimatableJudgement { private readonly HitResult result; diff --git a/osu.Game/Skinning/LegacyJudgementPieceOld.cs b/osu.Game/Skinning/LegacyJudgementPieceOld.cs index 3f4d13c082..0223e7a5a2 100644 --- a/osu.Game/Skinning/LegacyJudgementPieceOld.cs +++ b/osu.Game/Skinning/LegacyJudgementPieceOld.cs @@ -13,7 +13,7 @@ using osu.Game.Rulesets.Scoring; namespace osu.Game.Skinning { - public class LegacyJudgementPieceOld : CompositeDrawable, IAnimatableJudgement + public partial class LegacyJudgementPieceOld : CompositeDrawable, IAnimatableJudgement { private readonly HitResult result; diff --git a/osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs b/osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs index 2bcdd5b5a1..fd9434e02a 100644 --- a/osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs +++ b/osu.Game/Skinning/LegacyKiaiFlashingDrawable.cs @@ -9,7 +9,7 @@ using osu.Game.Graphics.Containers; namespace osu.Game.Skinning { - public class LegacyKiaiFlashingDrawable : BeatSyncedContainer + public partial class LegacyKiaiFlashingDrawable : BeatSyncedContainer { private readonly Drawable flashingDrawable; diff --git a/osu.Game/Skinning/LegacyRollingCounter.cs b/osu.Game/Skinning/LegacyRollingCounter.cs index fd17b06a21..465f1c3a20 100644 --- a/osu.Game/Skinning/LegacyRollingCounter.cs +++ b/osu.Game/Skinning/LegacyRollingCounter.cs @@ -12,7 +12,7 @@ namespace osu.Game.Skinning /// /// An integer that uses number sprites from a legacy skin. /// - public class LegacyRollingCounter : RollingCounter + public partial class LegacyRollingCounter : RollingCounter { private readonly LegacyFont font; diff --git a/osu.Game/Skinning/LegacyScoreCounter.cs b/osu.Game/Skinning/LegacyScoreCounter.cs index aee594454f..6a14ed93e9 100644 --- a/osu.Game/Skinning/LegacyScoreCounter.cs +++ b/osu.Game/Skinning/LegacyScoreCounter.cs @@ -10,7 +10,7 @@ using osuTK; namespace osu.Game.Skinning { - public class LegacyScoreCounter : GameplayScoreCounter, ISkinnableDrawable + public partial class LegacyScoreCounter : GameplayScoreCounter, ISkinnableDrawable { protected override double RollingDuration => 1000; protected override Easing RollingEasing => Easing.Out; diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs index 8765882af2..0d2461567f 100644 --- a/osu.Game/Skinning/LegacySkinExtensions.cs +++ b/osu.Game/Skinning/LegacySkinExtensions.cs @@ -15,7 +15,7 @@ using static osu.Game.Skinning.SkinConfiguration; namespace osu.Game.Skinning { - public static class LegacySkinExtensions + public static partial class LegacySkinExtensions { public static Drawable? GetAnimation(this ISkin? source, string componentName, bool animatable, bool looping, bool applyConfigFrameRate = false, string animationSeparator = "-", bool startAtCurrentTime = true, double? frameLength = null) @@ -146,7 +146,7 @@ namespace osu.Game.Skinning } } - public class SkinnableTextureAnimation : TextureAnimation + public partial class SkinnableTextureAnimation : TextureAnimation { [Resolved(canBeNull: true)] private IAnimationTimeReference? timeReference { get; set; } diff --git a/osu.Game/Skinning/LegacySongProgress.cs b/osu.Game/Skinning/LegacySongProgress.cs index f828e301f2..10d1431ed4 100644 --- a/osu.Game/Skinning/LegacySongProgress.cs +++ b/osu.Game/Skinning/LegacySongProgress.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Skinning { - public class LegacySongProgress : SongProgress + public partial class LegacySongProgress : SongProgress { private CircularProgress circularProgress = null!; diff --git a/osu.Game/Skinning/LegacySpriteText.cs b/osu.Game/Skinning/LegacySpriteText.cs index c5d65cb0c7..b89f85778b 100644 --- a/osu.Game/Skinning/LegacySpriteText.cs +++ b/osu.Game/Skinning/LegacySpriteText.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Skinning { - public sealed class LegacySpriteText : OsuSpriteText + public sealed partial class LegacySpriteText : OsuSpriteText { private readonly LegacyFont font; diff --git a/osu.Game/Skinning/PausableSkinnableSound.cs b/osu.Game/Skinning/PausableSkinnableSound.cs index ebcaeaa3ff..e752160984 100644 --- a/osu.Game/Skinning/PausableSkinnableSound.cs +++ b/osu.Game/Skinning/PausableSkinnableSound.cs @@ -13,7 +13,7 @@ using osu.Game.Audio; namespace osu.Game.Skinning { - public class PausableSkinnableSound : SkinnableSound + public partial class PausableSkinnableSound : SkinnableSound { public double Length => !DrawableSamples.Any() ? 0 : DrawableSamples.Max(sample => sample.Length); diff --git a/osu.Game/Skinning/PoolableSkinnableSample.cs b/osu.Game/Skinning/PoolableSkinnableSample.cs index d0a22f9656..0158c47ea3 100644 --- a/osu.Game/Skinning/PoolableSkinnableSample.cs +++ b/osu.Game/Skinning/PoolableSkinnableSample.cs @@ -20,7 +20,7 @@ namespace osu.Game.Skinning /// /// A sample corresponding to an that supports being pooled and responding to skin changes. /// - public class PoolableSkinnableSample : SkinReloadableDrawable, IAdjustableAudioComponent + public partial class PoolableSkinnableSample : SkinReloadableDrawable, IAdjustableAudioComponent { /// /// The currently-loaded . diff --git a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs index 7267ebd92d..07e238243b 100644 --- a/osu.Game/Skinning/RulesetSkinProvidingContainer.cs +++ b/osu.Game/Skinning/RulesetSkinProvidingContainer.cs @@ -23,7 +23,7 @@ namespace osu.Game.Skinning /// A type of specialized for and other gameplay-related components. /// Providing access to parent skin sources and the beatmap skin each surrounded with the ruleset legacy skin transformer. /// - public class RulesetSkinProvidingContainer : SkinProvidingContainer + public partial class RulesetSkinProvidingContainer : SkinProvidingContainer { protected readonly Ruleset Ruleset; protected readonly IBeatmap Beatmap; diff --git a/osu.Game/Skinning/SkinProvidingContainer.cs b/osu.Game/Skinning/SkinProvidingContainer.cs index e7d0683005..afead7b072 100644 --- a/osu.Game/Skinning/SkinProvidingContainer.cs +++ b/osu.Game/Skinning/SkinProvidingContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Skinning /// /// A container which adds a local to the hierarchy. /// - public class SkinProvidingContainer : Container, ISkinSource + public partial class SkinProvidingContainer : Container, ISkinSource { public event Action? SourceChanged; diff --git a/osu.Game/Skinning/SkinReloadableDrawable.cs b/osu.Game/Skinning/SkinReloadableDrawable.cs index f1c8388f71..1c947a4a84 100644 --- a/osu.Game/Skinning/SkinReloadableDrawable.cs +++ b/osu.Game/Skinning/SkinReloadableDrawable.cs @@ -11,7 +11,7 @@ namespace osu.Game.Skinning /// /// A drawable which has a callback when the skin changes. /// - public abstract class SkinReloadableDrawable : PoolableDrawable + public abstract partial class SkinReloadableDrawable : PoolableDrawable { /// /// Invoked when has changed. diff --git a/osu.Game/Skinning/SkinnableDrawable.cs b/osu.Game/Skinning/SkinnableDrawable.cs index 15d371cdd5..255aba94ae 100644 --- a/osu.Game/Skinning/SkinnableDrawable.cs +++ b/osu.Game/Skinning/SkinnableDrawable.cs @@ -12,7 +12,7 @@ namespace osu.Game.Skinning /// /// A drawable which can be skinned via an . /// - public class SkinnableDrawable : SkinReloadableDrawable + public partial class SkinnableDrawable : SkinReloadableDrawable { /// /// The displayed component. diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs index 8f71b40801..aeced9b517 100644 --- a/osu.Game/Skinning/SkinnableSound.cs +++ b/osu.Game/Skinning/SkinnableSound.cs @@ -21,7 +21,7 @@ namespace osu.Game.Skinning /// /// A sound consisting of one or more samples to be played. /// - public class SkinnableSound : SkinReloadableDrawable, IAdjustableAudioComponent + public partial class SkinnableSound : SkinReloadableDrawable, IAdjustableAudioComponent { public override bool RemoveWhenNotAlive => false; public override bool RemoveCompletedTransforms => false; diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 7fd0e43562..1a8a3a26c9 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -20,7 +20,7 @@ namespace osu.Game.Skinning /// /// A skinnable element which uses a single texture backing. /// - public class SkinnableSprite : SkinnableDrawable, ISkinnableDrawable + public partial class SkinnableSprite : SkinnableDrawable, ISkinnableDrawable { protected override bool ApplySizeRestrictionsToDefault => true; @@ -75,7 +75,7 @@ namespace osu.Game.Skinning } } - public class SpriteSelectorControl : SettingsDropdown + public partial class SpriteSelectorControl : SettingsDropdown { protected override void LoadComplete() { @@ -117,7 +117,7 @@ namespace osu.Game.Skinning } } - public class SpriteNotFound : CompositeDrawable + public partial class SpriteNotFound : CompositeDrawable { public SpriteNotFound(string lookup) { diff --git a/osu.Game/Skinning/SkinnableSpriteText.cs b/osu.Game/Skinning/SkinnableSpriteText.cs index c01cec2f0c..7c42449ae7 100644 --- a/osu.Game/Skinning/SkinnableSpriteText.cs +++ b/osu.Game/Skinning/SkinnableSpriteText.cs @@ -7,7 +7,7 @@ using osu.Framework.Localisation; namespace osu.Game.Skinning { - public class SkinnableSpriteText : SkinnableDrawable, IHasText + public partial class SkinnableSpriteText : SkinnableDrawable, IHasText { public SkinnableSpriteText(ISkinComponentLookup lookup, Func defaultImplementation, ConfineMode confineMode = ConfineMode.NoScaling) : base(lookup, defaultImplementation, confineMode) diff --git a/osu.Game/Skinning/SkinnableTargetComponentsContainer.cs b/osu.Game/Skinning/SkinnableTargetComponentsContainer.cs index e38afedeb9..8c6726c3f4 100644 --- a/osu.Game/Skinning/SkinnableTargetComponentsContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetComponentsContainer.cs @@ -13,7 +13,7 @@ namespace osu.Game.Skinning /// Optionally also applies a default layout to the components. /// [Serializable] - public class SkinnableTargetComponentsContainer : Container, ISkinnableDrawable + public partial class SkinnableTargetComponentsContainer : Container, ISkinnableDrawable { public bool IsEditable => false; diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index a8038f5f5c..794a12da82 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -9,7 +9,7 @@ using osu.Framework.Graphics; namespace osu.Game.Skinning { - public class SkinnableTargetContainer : SkinReloadableDrawable, ISkinnableTarget + public partial class SkinnableTargetContainer : SkinReloadableDrawable, ISkinnableTarget { private SkinnableTargetComponentsContainer? content; diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs index 6295604438..aa264fa719 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboard.cs @@ -20,7 +20,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboard : Container + public partial class DrawableStoryboard : Container { [Cached] public Storyboard Storyboard { get; } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs index 07e1e86617..e86ee9e63d 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs @@ -16,7 +16,7 @@ using osuTK; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboardAnimation : TextureAnimation, IFlippable, IVectorScalable + public partial class DrawableStoryboardAnimation : TextureAnimation, IFlippable, IVectorScalable { public StoryboardAnimation Animation { get; } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs index 13f116af24..6fc8d124c7 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardLayer.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboardLayer : CompositeDrawable + public partial class DrawableStoryboardLayer : CompositeDrawable { public StoryboardLayer Layer { get; } public bool Enabled; @@ -32,7 +32,7 @@ namespace osu.Game.Storyboards.Drawables InternalChild = ElementContainer = new LayerElementContainer(layer); } - protected class LayerElementContainer : LifetimeManagementContainer + protected partial class LayerElementContainer : LifetimeManagementContainer { private readonly StoryboardLayer storyboardLayer; diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs index 2e7ca31fe9..c281d23804 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSample.cs @@ -12,7 +12,7 @@ using osu.Game.Skinning; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboardSample : PausableSkinnableSound + public partial class DrawableStoryboardSample : PausableSkinnableSound { /// /// The amount of time allowable beyond the start time of the sample, for the sample to start. diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs index b86b021d51..f9b09ed57c 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboardSprite : Sprite, IFlippable, IVectorScalable + public partial class DrawableStoryboardSprite : Sprite, IFlippable, IVectorScalable { public StoryboardSprite Sprite { get; } diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs index ebd056ba50..f4b0692619 100644 --- a/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs +++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardVideo.cs @@ -11,7 +11,7 @@ using osu.Game.Beatmaps; namespace osu.Game.Storyboards.Drawables { - public class DrawableStoryboardVideo : CompositeDrawable + public partial class DrawableStoryboardVideo : CompositeDrawable { public readonly StoryboardVideo Video; diff --git a/osu.Game/Storyboards/StoryboardVideoLayer.cs b/osu.Game/Storyboards/StoryboardVideoLayer.cs index 339e70d677..f08c02cfd2 100644 --- a/osu.Game/Storyboards/StoryboardVideoLayer.cs +++ b/osu.Game/Storyboards/StoryboardVideoLayer.cs @@ -9,7 +9,7 @@ using osuTK; namespace osu.Game.Storyboards { - public class StoryboardVideoLayer : StoryboardLayer + public partial class StoryboardVideoLayer : StoryboardLayer { public StoryboardVideoLayer(string name, int depth, bool masking) : base(name, depth, masking) @@ -19,7 +19,7 @@ namespace osu.Game.Storyboards public override DrawableStoryboardLayer CreateDrawable() => new DrawableStoryboardVideoLayer(this) { Depth = Depth, Name = Name }; - public class DrawableStoryboardVideoLayer : DrawableStoryboardLayer + public partial class DrawableStoryboardVideoLayer : DrawableStoryboardLayer { public DrawableStoryboardVideoLayer(StoryboardVideoLayer layer) : base(layer) diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index c97eec116c..fbc920f7de 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -33,7 +33,7 @@ using osu.Game.Tests.Visual; namespace osu.Game.Tests.Beatmaps { [HeadlessTest] - public abstract class HitObjectSampleTest : PlayerTestScene, IStorageResourceProvider + public abstract partial class HitObjectSampleTest : PlayerTestScene, IStorageResourceProvider { protected abstract IResourceStore RulesetResources { get; } protected LegacySkin Skin { get; private set; } diff --git a/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs b/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs index 06600c4681..2488aecced 100644 --- a/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs +++ b/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Beatmaps { - public abstract class LegacyBeatmapSkinColourTest : ScreenTestScene + public abstract partial class LegacyBeatmapSkinColourTest : ScreenTestScene { protected readonly Bindable BeatmapSkins = new Bindable(); protected readonly Bindable BeatmapColours = new Bindable(); @@ -60,7 +60,7 @@ namespace osu.Game.Tests.Beatmaps protected virtual ExposedPlayer CreateTestPlayer(bool userHasCustomColours) => new ExposedPlayer(userHasCustomColours); - protected class ExposedPlayer : TestPlayer + protected partial class ExposedPlayer : TestPlayer { protected readonly bool UserHasCustomColours; diff --git a/osu.Game/Tests/OsuTestBrowser.cs b/osu.Game/Tests/OsuTestBrowser.cs index 064fdeee94..7431679ab9 100644 --- a/osu.Game/Tests/OsuTestBrowser.cs +++ b/osu.Game/Tests/OsuTestBrowser.cs @@ -12,7 +12,7 @@ using osu.Game.Screens.Backgrounds; namespace osu.Game.Tests { - public class OsuTestBrowser : OsuGameBase + public partial class OsuTestBrowser : OsuGameBase { protected override void LoadComplete() { diff --git a/osu.Game/Tests/Visual/DependencyProvidingContainer.cs b/osu.Game/Tests/Visual/DependencyProvidingContainer.cs index 8d9108f376..ae0225d8df 100644 --- a/osu.Game/Tests/Visual/DependencyProvidingContainer.cs +++ b/osu.Game/Tests/Visual/DependencyProvidingContainer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Tests.Visual /// /// The must be set while this is not loaded. /// - public class DependencyProvidingContainer : Container + public partial class DependencyProvidingContainer : Container { /// /// The dependencies provided to the children. diff --git a/osu.Game/Tests/Visual/EditorClockTestScene.cs b/osu.Game/Tests/Visual/EditorClockTestScene.cs index 8f1e7abd9e..204a817b3a 100644 --- a/osu.Game/Tests/Visual/EditorClockTestScene.cs +++ b/osu.Game/Tests/Visual/EditorClockTestScene.cs @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual /// Provides a clock, beat-divisor, and scrolling capability for test cases of editor components that /// are preferrably tested within the presence of a clock and seek controls. /// - public abstract class EditorClockTestScene : OsuManualInputManagerTestScene + public abstract partial class EditorClockTestScene : OsuManualInputManagerTestScene { [Cached] private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Aquamarine); diff --git a/osu.Game/Tests/Visual/EditorSavingTestScene.cs b/osu.Game/Tests/Visual/EditorSavingTestScene.cs index 3b7b6780b1..cd9e9e1d52 100644 --- a/osu.Game/Tests/Visual/EditorSavingTestScene.cs +++ b/osu.Game/Tests/Visual/EditorSavingTestScene.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual /// /// Tests the general expected flow of creating a new beatmap, saving it, then loading it back from song select. /// - public abstract class EditorSavingTestScene : OsuGameTestScene + public abstract partial class EditorSavingTestScene : OsuGameTestScene { protected Editor Editor => Game.ChildrenOfType().FirstOrDefault(); diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 0e7bb72162..833c12ba54 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -23,7 +23,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual { - public abstract class EditorTestScene : ScreenTestScene + public abstract partial class EditorTestScene : ScreenTestScene { private TestEditorLoader editorLoader; @@ -83,7 +83,7 @@ namespace osu.Game.Tests.Visual protected sealed override Ruleset CreateRuleset() => CreateEditorRuleset(); - protected class TestEditorLoader : EditorLoader + protected partial class TestEditorLoader : EditorLoader { public TestEditor Editor { get; private set; } @@ -92,7 +92,7 @@ namespace osu.Game.Tests.Visual protected virtual TestEditor CreateTestEditor(EditorLoader loader) => new TestEditor(loader); } - protected class TestEditor : Editor + protected partial class TestEditor : Editor { [Resolved(canBeNull: true)] [CanBeNull] diff --git a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs index f6b5d861be..c5efdf36b4 100644 --- a/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs +++ b/osu.Game/Tests/Visual/LegacySkinPlayerTestScene.cs @@ -14,7 +14,7 @@ using osu.Game.Skinning; namespace osu.Game.Tests.Visual { [TestFixture] - public abstract class LegacySkinPlayerTestScene : PlayerTestScene + public abstract partial class LegacySkinPlayerTestScene : PlayerTestScene { protected LegacySkin LegacySkin { get; private set; } @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual AddUntilStep("wait for components to load", () => this.ChildrenOfType().All(t => t.ComponentsLoaded)); } - public class SkinProvidingPlayer : TestPlayer + public partial class SkinProvidingPlayer : TestPlayer { [Cached(typeof(ISkinSource))] private readonly ISkinSource skinSource; diff --git a/osu.Game/Tests/Visual/ModPerfectTestScene.cs b/osu.Game/Tests/Visual/ModPerfectTestScene.cs index f1ad2656cd..167d5450e9 100644 --- a/osu.Game/Tests/Visual/ModPerfectTestScene.cs +++ b/osu.Game/Tests/Visual/ModPerfectTestScene.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Objects; namespace osu.Game.Tests.Visual { - public abstract class ModPerfectTestScene : ModTestScene + public abstract partial class ModPerfectTestScene : ModTestScene { private readonly ModPerfect mod; @@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual protected override TestPlayer CreateModPlayer(Ruleset ruleset) => new PerfectModTestPlayer(); - private class PerfectModTestPlayer : TestPlayer + private partial class PerfectModTestPlayer : TestPlayer { public PerfectModTestPlayer() : base(showResults: false) diff --git a/osu.Game/Tests/Visual/ModTestScene.cs b/osu.Game/Tests/Visual/ModTestScene.cs index 28778f1ac3..0559d80384 100644 --- a/osu.Game/Tests/Visual/ModTestScene.cs +++ b/osu.Game/Tests/Visual/ModTestScene.cs @@ -16,7 +16,7 @@ using osu.Game.Scoring; namespace osu.Game.Tests.Visual { - public abstract class ModTestScene : PlayerTestScene + public abstract partial class ModTestScene : PlayerTestScene { protected sealed override bool HasCustomSteps => true; @@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual protected virtual TestPlayer CreateModPlayer(Ruleset ruleset) => new ModTestPlayer(currentTestData, AllowFail); - protected class ModTestPlayer : TestPlayer + protected partial class ModTestPlayer : TestPlayer { private readonly bool allowFail; private readonly ModTestData currentTestData; diff --git a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs index 101a347749..93c6e72aa2 100644 --- a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs +++ b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs @@ -13,7 +13,7 @@ namespace osu.Game.Tests.Visual.Multiplayer /// /// The base test scene for all multiplayer components and screens. /// - public abstract class MultiplayerTestScene : OnlinePlayTestScene, IMultiplayerTestSceneDependencies + public abstract partial class MultiplayerTestScene : OnlinePlayTestScene, IMultiplayerTestSceneDependencies { public const int PLAYER_1_ID = 55; public const int PLAYER_2_ID = 56; diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 84737bce3f..765c665966 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Multiplayer /// /// A for use in multiplayer test scenes. Should generally not be used by itself outside of a . /// - public class TestMultiplayerClient : MultiplayerClient + public partial class TestMultiplayerClient : MultiplayerClient { public override IBindable IsConnected => isConnected; private readonly Bindable isConnected = new Bindable(true); diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs index b2283af9e7..8d04c808fd 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tests.Visual.Multiplayer /// A for use in multiplayer test scenes. /// Should generally not be used by itself outside of a . /// - public class TestMultiplayerRoomManager : MultiplayerRoomManager + public partial class TestMultiplayerRoomManager : MultiplayerRoomManager { private readonly TestRoomRequestsHandler requestsHandler; diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs index b9c293c3aa..5350030276 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay /// /// A base test scene for all online play components and screens. /// - public abstract class OnlinePlayTestScene : ScreenTestScene, IOnlinePlayTestSceneDependencies + public abstract partial class OnlinePlayTestScene : ScreenTestScene, IOnlinePlayTestSceneDependencies { public Bindable SelectedRoom => OnlinePlayDependencies?.SelectedRoom; public IRoomManager RoomManager => OnlinePlayDependencies?.RoomManager; diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs index f905eb26d3..e9980e822c 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs @@ -15,7 +15,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay /// /// A very simple for use in online play test scenes. /// - public class TestRoomManager : RoomManager + public partial class TestRoomManager : RoomManager { public Action JoinRoomRequested; diff --git a/osu.Game/Tests/Visual/OsuGameTestScene.cs b/osu.Game/Tests/Visual/OsuGameTestScene.cs index 3ca83a4781..1bf1fbf6ab 100644 --- a/osu.Game/Tests/Visual/OsuGameTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGameTestScene.cs @@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual /// /// A scene which tests full game flow. /// - public abstract class OsuGameTestScene : OsuManualInputManagerTestScene + public abstract partial class OsuGameTestScene : OsuManualInputManagerTestScene { protected TestOsuGame Game; @@ -114,7 +114,7 @@ namespace osu.Game.Tests.Visual /// protected void DismissAnyNotifications() => Game.Notifications.State.Value = Visibility.Hidden; - public class TestOsuGame : OsuGame + public partial class TestOsuGame : OsuGame { public new const float SIDE_OVERLAY_OFFSET_RATIO = OsuGame.SIDE_OVERLAY_OFFSET_RATIO; @@ -189,11 +189,11 @@ namespace osu.Game.Tests.Visual } } - public class TestLoader : Loader + public partial class TestLoader : Loader { protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler(); - private class TestShaderPrecompiler : ShaderPrecompiler + private partial class TestShaderPrecompiler : ShaderPrecompiler { protected override bool AllLoaded => true; } diff --git a/osu.Game/Tests/Visual/OsuGridTestScene.cs b/osu.Game/Tests/Visual/OsuGridTestScene.cs index f9a609f663..9ef3b2a59d 100644 --- a/osu.Game/Tests/Visual/OsuGridTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGridTestScene.cs @@ -13,7 +13,7 @@ namespace osu.Game.Tests.Visual /// An abstract test case which exposes small cells arranged in a grid. /// Useful for displaying multiple configurations of a tested component at a glance. /// - public abstract class OsuGridTestScene : OsuTestScene + public abstract partial class OsuGridTestScene : OsuTestScene { private readonly Drawable[,] cells; diff --git a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs index e56c546bac..b4fb29eb11 100644 --- a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs +++ b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs @@ -20,7 +20,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual { - public abstract class OsuManualInputManagerTestScene : OsuTestScene + public abstract partial class OsuManualInputManagerTestScene : OsuTestScene { protected override Container Content => content; private readonly Container content; diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 5055153691..46c7c3a57c 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -37,7 +37,7 @@ using osu.Game.Tests.Rulesets; namespace osu.Game.Tests.Visual { [ExcludeFromDynamicCompile] - public abstract class OsuTestScene : TestScene + public abstract partial class OsuTestScene : TestScene { [Cached] protected Bindable Beatmap { get; } = new Bindable(); @@ -503,7 +503,7 @@ namespace osu.Game.Tests.Visual } } - public class OsuTestSceneTestRunner : OsuGameBase, ITestSceneTestRunner + public partial class OsuTestSceneTestRunner : OsuGameBase, ITestSceneTestRunner { private TestSceneTestRunner.TestRunner runner; diff --git a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs index 7e5681ee81..0027e03492 100644 --- a/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/PlacementBlueprintTestScene.cs @@ -16,7 +16,7 @@ using osu.Game.Screens.Edit.Compose; namespace osu.Game.Tests.Visual { - public abstract class PlacementBlueprintTestScene : OsuManualInputManagerTestScene, IPlacementHandler + public abstract partial class PlacementBlueprintTestScene : OsuManualInputManagerTestScene, IPlacementHandler { protected readonly Container HitObjectContainer; protected PlacementBlueprint CurrentBlueprint { get; private set; } diff --git a/osu.Game/Tests/Visual/PlayerTestScene.cs b/osu.Game/Tests/Visual/PlayerTestScene.cs index 9bad867206..3ecc5a3280 100644 --- a/osu.Game/Tests/Visual/PlayerTestScene.cs +++ b/osu.Game/Tests/Visual/PlayerTestScene.cs @@ -14,7 +14,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Tests.Visual { - public abstract class PlayerTestScene : RateAdjustedBeatmapTestScene + public abstract partial class PlayerTestScene : RateAdjustedBeatmapTestScene { /// /// Whether custom test steps are provided. Custom tests should invoke to create the test steps. diff --git a/osu.Game/Tests/Visual/RateAdjustedBeatmapTestScene.cs b/osu.Game/Tests/Visual/RateAdjustedBeatmapTestScene.cs index a4f768800c..0f3f9f2199 100644 --- a/osu.Game/Tests/Visual/RateAdjustedBeatmapTestScene.cs +++ b/osu.Game/Tests/Visual/RateAdjustedBeatmapTestScene.cs @@ -8,7 +8,7 @@ namespace osu.Game.Tests.Visual /// /// Test case which adjusts the beatmap's rate to match any speed adjustments in visual tests. /// - public abstract class RateAdjustedBeatmapTestScene : ScreenTestScene + public abstract partial class RateAdjustedBeatmapTestScene : ScreenTestScene { protected override void Update() { diff --git a/osu.Game/Tests/Visual/ScreenTestScene.cs b/osu.Game/Tests/Visual/ScreenTestScene.cs index 803db07fa0..7d382ca1bc 100644 --- a/osu.Game/Tests/Visual/ScreenTestScene.cs +++ b/osu.Game/Tests/Visual/ScreenTestScene.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual /// /// A test case which can be used to test a screen (that relies on OnEntering being called to execute startup instructions). /// - public abstract class ScreenTestScene : OsuManualInputManagerTestScene, IOverlayManager + public abstract partial class ScreenTestScene : OsuManualInputManagerTestScene, IOverlayManager { protected readonly OsuScreenStack Stack; diff --git a/osu.Game/Tests/Visual/ScrollingTestContainer.cs b/osu.Game/Tests/Visual/ScrollingTestContainer.cs index 1817a704b9..b8b39e16b5 100644 --- a/osu.Game/Tests/Visual/ScrollingTestContainer.cs +++ b/osu.Game/Tests/Visual/ScrollingTestContainer.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual /// A container which provides a to children. /// This should only be used when testing /// - public class ScrollingTestContainer : Container + public partial class ScrollingTestContainer : Container { public SortedList ControlPoints => scrollingInfo.Algorithm.ControlPoints; diff --git a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs index ac0d1cd366..350410e7c6 100644 --- a/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs +++ b/osu.Game/Tests/Visual/SelectionBlueprintTestScene.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Edit; namespace osu.Game.Tests.Visual { - public abstract class SelectionBlueprintTestScene : OsuManualInputManagerTestScene + public abstract partial class SelectionBlueprintTestScene : OsuManualInputManagerTestScene { [Cached] private readonly EditorClock editorClock = new EditorClock(); diff --git a/osu.Game/Tests/Visual/SkinnableTestScene.cs b/osu.Game/Tests/Visual/SkinnableTestScene.cs index f8f15e2729..e8f51f9afa 100644 --- a/osu.Game/Tests/Visual/SkinnableTestScene.cs +++ b/osu.Game/Tests/Visual/SkinnableTestScene.cs @@ -27,7 +27,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual { - public abstract class SkinnableTestScene : OsuGridTestScene, IStorageResourceProvider + public abstract partial class SkinnableTestScene : OsuGridTestScene, IStorageResourceProvider { private TrianglesSkin trianglesSkin; private Skin metricsSkin; @@ -171,7 +171,7 @@ namespace osu.Game.Tests.Visual #endregion - private class OutlineBox : CompositeDrawable + private partial class OutlineBox : CompositeDrawable { public OutlineBox() { diff --git a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs index e6d8e473bb..a76f6c7052 100644 --- a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs +++ b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs @@ -17,7 +17,7 @@ using osu.Game.Scoring; namespace osu.Game.Tests.Visual.Spectator { - public class TestSpectatorClient : SpectatorClient + public partial class TestSpectatorClient : SpectatorClient { /// /// Maximum number of frames sent per bundle via . diff --git a/osu.Game/Tests/Visual/TestPlayer.cs b/osu.Game/Tests/Visual/TestPlayer.cs index 93a155e083..81195ebed9 100644 --- a/osu.Game/Tests/Visual/TestPlayer.cs +++ b/osu.Game/Tests/Visual/TestPlayer.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual /// /// A player that exposes many components that would otherwise not be available, for testing purposes. /// - public class TestPlayer : SoloPlayer + public partial class TestPlayer : SoloPlayer { protected override bool PauseOnFocusLost { get; } diff --git a/osu.Game/Tests/Visual/TestReplayPlayer.cs b/osu.Game/Tests/Visual/TestReplayPlayer.cs index a33a6763af..bc6dc9bb27 100644 --- a/osu.Game/Tests/Visual/TestReplayPlayer.cs +++ b/osu.Game/Tests/Visual/TestReplayPlayer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tests.Visual /// /// A player that exposes many components that would otherwise not be available, for testing purposes. /// - public class TestReplayPlayer : ReplayPlayer + public partial class TestReplayPlayer : ReplayPlayer { protected override bool PauseOnFocusLost { get; } diff --git a/osu.Game/Tests/Visual/TestUserLookupCache.cs b/osu.Game/Tests/Visual/TestUserLookupCache.cs index 414166fdd8..a3028f1a34 100644 --- a/osu.Game/Tests/Visual/TestUserLookupCache.cs +++ b/osu.Game/Tests/Visual/TestUserLookupCache.cs @@ -10,7 +10,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Tests.Visual { - public class TestUserLookupCache : UserLookupCache + public partial class TestUserLookupCache : UserLookupCache { /// /// A special user ID which would return a for. diff --git a/osu.Game/Updater/NoActionUpdateManager.cs b/osu.Game/Updater/NoActionUpdateManager.cs index 8a96cdb968..97d3275757 100644 --- a/osu.Game/Updater/NoActionUpdateManager.cs +++ b/osu.Game/Updater/NoActionUpdateManager.cs @@ -16,7 +16,7 @@ namespace osu.Game.Updater /// An update manager that shows notifications if a newer release is detected. /// This is a case where updates are handled externally by a package manager or other means, so no action is performed on clicking the notification. /// - public class NoActionUpdateManager : UpdateManager + public partial class NoActionUpdateManager : UpdateManager { private string version; diff --git a/osu.Game/Updater/SimpleUpdateManager.cs b/osu.Game/Updater/SimpleUpdateManager.cs index fb5794d92e..1ecb73a154 100644 --- a/osu.Game/Updater/SimpleUpdateManager.cs +++ b/osu.Game/Updater/SimpleUpdateManager.cs @@ -20,7 +20,7 @@ namespace osu.Game.Updater /// An update manager that shows notifications if a newer release is detected. /// Installation is left up to the user. /// - public class SimpleUpdateManager : UpdateManager + public partial class SimpleUpdateManager : UpdateManager { private string version; diff --git a/osu.Game/Updater/UpdateManager.cs b/osu.Game/Updater/UpdateManager.cs index 7b540cb564..47c2a169ed 100644 --- a/osu.Game/Updater/UpdateManager.cs +++ b/osu.Game/Updater/UpdateManager.cs @@ -17,7 +17,7 @@ namespace osu.Game.Updater /// /// An update manager which only shows notifications after an update completes. /// - public class UpdateManager : CompositeDrawable + public partial class UpdateManager : CompositeDrawable { /// /// Whether this UpdateManager should be or is capable of checking for updates. @@ -85,7 +85,7 @@ namespace osu.Game.Updater /// Whether any update is waiting. May return true if an error occured (there is potentially an update available). protected virtual Task PerformUpdateCheck() => Task.FromResult(false); - private class UpdateCompleteNotification : SimpleNotification + private partial class UpdateCompleteNotification : SimpleNotification { private readonly string version; @@ -110,7 +110,7 @@ namespace osu.Game.Updater } } - public class UpdateApplicationCompleteNotification : ProgressCompletionNotification + public partial class UpdateApplicationCompleteNotification : ProgressCompletionNotification { public UpdateApplicationCompleteNotification() { @@ -118,7 +118,7 @@ namespace osu.Game.Updater } } - public class UpdateProgressNotification : ProgressNotification + public partial class UpdateProgressNotification : ProgressNotification { protected override Notification CreateCompletionNotification() => new UpdateApplicationCompleteNotification { diff --git a/osu.Game/Users/Drawables/ClickableAvatar.cs b/osu.Game/Users/Drawables/ClickableAvatar.cs index 62e966c48f..5a3009dfcd 100644 --- a/osu.Game/Users/Drawables/ClickableAvatar.cs +++ b/osu.Game/Users/Drawables/ClickableAvatar.cs @@ -13,7 +13,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users.Drawables { - public class ClickableAvatar : Container + public partial class ClickableAvatar : Container { private const string default_tooltip_text = "view profile"; @@ -71,7 +71,7 @@ namespace osu.Game.Users.Drawables game?.ShowUser(user); } - private class ClickableArea : OsuClickableContainer + private partial class ClickableArea : OsuClickableContainer { private LocalisableString tooltip = default_tooltip_text; diff --git a/osu.Game/Users/Drawables/DrawableAvatar.cs b/osu.Game/Users/Drawables/DrawableAvatar.cs index 155f63dc18..bd09b95164 100644 --- a/osu.Game/Users/Drawables/DrawableAvatar.cs +++ b/osu.Game/Users/Drawables/DrawableAvatar.cs @@ -12,7 +12,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users.Drawables { [LongRunningLoad] - public class DrawableAvatar : Sprite + public partial class DrawableAvatar : Sprite { private readonly IUser user; diff --git a/osu.Game/Users/Drawables/DrawableFlag.cs b/osu.Game/Users/Drawables/DrawableFlag.cs index 253835b415..0d209f47e8 100644 --- a/osu.Game/Users/Drawables/DrawableFlag.cs +++ b/osu.Game/Users/Drawables/DrawableFlag.cs @@ -13,7 +13,7 @@ using osu.Framework.Localisation; namespace osu.Game.Users.Drawables { - public class DrawableFlag : Sprite, IHasTooltip + public partial class DrawableFlag : Sprite, IHasTooltip { private readonly CountryCode countryCode; diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs index dab3dc59f9..9c04eb5706 100644 --- a/osu.Game/Users/Drawables/UpdateableAvatar.cs +++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs @@ -13,7 +13,7 @@ namespace osu.Game.Users.Drawables /// /// An avatar which can update to a new user when needed. /// - public class UpdateableAvatar : ModelBackedDrawable + public partial class UpdateableAvatar : ModelBackedDrawable { public APIUser User { diff --git a/osu.Game/Users/Drawables/UpdateableFlag.cs b/osu.Game/Users/Drawables/UpdateableFlag.cs index 9b101131b3..a208f3c7c4 100644 --- a/osu.Game/Users/Drawables/UpdateableFlag.cs +++ b/osu.Game/Users/Drawables/UpdateableFlag.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays; namespace osu.Game.Users.Drawables { - public class UpdateableFlag : ModelBackedDrawable + public partial class UpdateableFlag : ModelBackedDrawable { public CountryCode CountryCode { diff --git a/osu.Game/Users/ExtendedUserPanel.cs b/osu.Game/Users/ExtendedUserPanel.cs index a4cba8b920..85b71a5bc7 100644 --- a/osu.Game/Users/ExtendedUserPanel.cs +++ b/osu.Game/Users/ExtendedUserPanel.cs @@ -17,7 +17,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users { - public abstract class ExtendedUserPanel : UserPanel + public abstract partial class ExtendedUserPanel : UserPanel { public readonly Bindable Status = new Bindable(); diff --git a/osu.Game/Users/UserBrickPanel.cs b/osu.Game/Users/UserBrickPanel.cs index a214b72795..69b390b36e 100644 --- a/osu.Game/Users/UserBrickPanel.cs +++ b/osu.Game/Users/UserBrickPanel.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Users { - public class UserBrickPanel : UserPanel + public partial class UserBrickPanel : UserPanel { public UserBrickPanel(APIUser user) : base(user) diff --git a/osu.Game/Users/UserCoverBackground.cs b/osu.Game/Users/UserCoverBackground.cs index c799bbb1ea..69a5fba876 100644 --- a/osu.Game/Users/UserCoverBackground.cs +++ b/osu.Game/Users/UserCoverBackground.cs @@ -17,7 +17,7 @@ using osuTK.Graphics; namespace osu.Game.Users { - public class UserCoverBackground : ModelBackedDrawable + public partial class UserCoverBackground : ModelBackedDrawable { public APIUser User { @@ -38,7 +38,7 @@ namespace osu.Game.Users => new DelayedLoadUnloadWrapper(createContentFunc, timeBeforeLoad, UnloadDelay); [LongRunningLoad] - private class Cover : CompositeDrawable + private partial class Cover : CompositeDrawable { private readonly APIUser user; diff --git a/osu.Game/Users/UserGridPanel.cs b/osu.Game/Users/UserGridPanel.cs index 38d8f6fb33..90b6c11f0e 100644 --- a/osu.Game/Users/UserGridPanel.cs +++ b/osu.Game/Users/UserGridPanel.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Users { - public class UserGridPanel : ExtendedUserPanel + public partial class UserGridPanel : ExtendedUserPanel { private const int margin = 10; diff --git a/osu.Game/Users/UserListPanel.cs b/osu.Game/Users/UserListPanel.cs index 6d45481dbe..bbd3c60a33 100644 --- a/osu.Game/Users/UserListPanel.cs +++ b/osu.Game/Users/UserListPanel.cs @@ -15,7 +15,7 @@ using osu.Game.Overlays.Profile.Header.Components; namespace osu.Game.Users { - public class UserListPanel : ExtendedUserPanel + public partial class UserListPanel : ExtendedUserPanel { public UserListPanel(APIUser user) : base(user) diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index d150b38c45..e7af127a30 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -19,7 +19,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Users { - public abstract class UserPanel : OsuClickableContainer, IHasContextMenu + public abstract partial class UserPanel : OsuClickableContainer, IHasContextMenu { public readonly APIUser User; From 212d78865a6b5f091173a347bad5686834d1d5fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Nov 2022 16:30:10 +0100 Subject: [PATCH 2409/2686] Add a few more missing partial specs --- .../Visual/Background/TestSceneTriangleBorderShader.cs | 4 ++-- .../Visual/Background/TestSceneTrianglesV2Background.cs | 2 +- osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs | 2 +- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 2 +- osu.Game/Skinning/Components/BeatmapAttributeText.cs | 2 +- osu.Game/Skinning/Components/TextElement.cs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs b/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs index 64512bc651..185b83d1cc 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTriangleBorderShader.cs @@ -12,7 +12,7 @@ using osu.Framework.Graphics.Rendering; namespace osu.Game.Tests.Visual.Background { - public class TestSceneTriangleBorderShader : OsuTestScene + public partial class TestSceneTriangleBorderShader : OsuTestScene { private readonly TriangleBorder border; @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Background AddSliderStep("Thickness", 0f, 1f, 0.02f, t => border.Thickness = t); } - private class TriangleBorder : Sprite + private partial class TriangleBorder : Sprite { private float thickness = 0.02f; diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs index 0c3a21d510..8d6aef99ad 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs @@ -10,7 +10,7 @@ using osu.Game.Graphics.Backgrounds; namespace osu.Game.Tests.Visual.Background { - public class TestSceneTrianglesV2Background : OsuTestScene + public partial class TestSceneTrianglesV2Background : OsuTestScene { private readonly TrianglesV2 triangles; diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs index dc1e00ee8f..4830c7b856 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableChannel.cs @@ -13,7 +13,7 @@ using osu.Game.Overlays.Chat; namespace osu.Game.Tests.Visual.Online { [TestFixture] - public class TestSceneDrawableChannel : OsuTestScene + public partial class TestSceneDrawableChannel : OsuTestScene { private Channel channel = null!; private DrawableChannel drawableChannel = null!; diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 77d30d50d6..70f4981c36 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -19,7 +19,7 @@ using osu.Framework.Graphics; namespace osu.Game.Graphics.Backgrounds { - public class TrianglesV2 : Drawable + public partial class TrianglesV2 : Drawable { private const float triangle_size = 100; private const float base_velocity = 50; diff --git a/osu.Game/Skinning/Components/BeatmapAttributeText.cs b/osu.Game/Skinning/Components/BeatmapAttributeText.cs index ec84831fb4..0a5f0d22cb 100644 --- a/osu.Game/Skinning/Components/BeatmapAttributeText.cs +++ b/osu.Game/Skinning/Components/BeatmapAttributeText.cs @@ -24,7 +24,7 @@ using osu.Game.Resources.Localisation.Web; namespace osu.Game.Skinning.Components { [UsedImplicitly] - public class BeatmapAttributeText : Container, ISkinnableDrawable + public partial class BeatmapAttributeText : Container, ISkinnableDrawable { public bool UsesFixedAnchor { get; set; } diff --git a/osu.Game/Skinning/Components/TextElement.cs b/osu.Game/Skinning/Components/TextElement.cs index 1e618a7f82..74a0acb979 100644 --- a/osu.Game/Skinning/Components/TextElement.cs +++ b/osu.Game/Skinning/Components/TextElement.cs @@ -12,7 +12,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Skinning.Components { [UsedImplicitly] - public class TextElement : Container, ISkinnableDrawable + public partial class TextElement : Container, ISkinnableDrawable { public bool UsesFixedAnchor { get; set; } From 0abf6ad5b07371c9547819b93984d8ba4a592701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Nov 2022 16:32:42 +0100 Subject: [PATCH 2410/2686] Ignore partial modifier application in blame --- .git-blame-ignore-revs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 8be6479043..e331778e7f 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,2 +1,6 @@ # Normalize all the line endings 32a74f95a5c80a0ed18e693f13a47522099df5c3 +# Partial everything +7bc8908ca9c026fed1d831eb6e58df7624a8d614 +# Add a few more missing partial specs +212d78865a6b5f091173a347bad5686834d1d5fe From 00c11b2b4e389e48f3995d63484a6bc66a7afbdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Nov 2022 17:59:38 +0100 Subject: [PATCH 2411/2686] Add partial specs in mobile projects too --- osu.Android/AndroidJoystickSettings.cs | 2 +- osu.Android/AndroidMouseSettings.cs | 2 +- osu.Android/GameplayScreenRotationLocker.cs | 2 +- osu.Android/OsuGameAndroid.cs | 2 +- osu.iOS/IOSMouseSettings.cs | 2 +- osu.iOS/OsuGameIOS.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Android/AndroidJoystickSettings.cs b/osu.Android/AndroidJoystickSettings.cs index 26e921a426..bf69461f0d 100644 --- a/osu.Android/AndroidJoystickSettings.cs +++ b/osu.Android/AndroidJoystickSettings.cs @@ -11,7 +11,7 @@ using osu.Game.Overlays.Settings; namespace osu.Android { - public class AndroidJoystickSettings : SettingsSubsection + public partial class AndroidJoystickSettings : SettingsSubsection { protected override LocalisableString Header => JoystickSettingsStrings.JoystickGamepad; diff --git a/osu.Android/AndroidMouseSettings.cs b/osu.Android/AndroidMouseSettings.cs index 54b787fd17..d6d7750448 100644 --- a/osu.Android/AndroidMouseSettings.cs +++ b/osu.Android/AndroidMouseSettings.cs @@ -14,7 +14,7 @@ using osu.Game.Overlays.Settings.Sections.Input; namespace osu.Android { - public class AndroidMouseSettings : SettingsSubsection + public partial class AndroidMouseSettings : SettingsSubsection { private readonly AndroidMouseHandler mouseHandler; diff --git a/osu.Android/GameplayScreenRotationLocker.cs b/osu.Android/GameplayScreenRotationLocker.cs index 9e849bdc7c..3c39a820cc 100644 --- a/osu.Android/GameplayScreenRotationLocker.cs +++ b/osu.Android/GameplayScreenRotationLocker.cs @@ -11,7 +11,7 @@ using osu.Game; namespace osu.Android { - public class GameplayScreenRotationLocker : Component + public partial class GameplayScreenRotationLocker : Component { private Bindable localUserPlaying; diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs index 6b88f21bcd..1c6f41a7ec 100644 --- a/osu.Android/OsuGameAndroid.cs +++ b/osu.Android/OsuGameAndroid.cs @@ -18,7 +18,7 @@ using Xamarin.Essentials; namespace osu.Android { - public class OsuGameAndroid : OsuGame + public partial class OsuGameAndroid : OsuGame { [Cached] private readonly OsuGameActivity gameActivity; diff --git a/osu.iOS/IOSMouseSettings.cs b/osu.iOS/IOSMouseSettings.cs index 1979a881f7..f464bd93b8 100644 --- a/osu.iOS/IOSMouseSettings.cs +++ b/osu.iOS/IOSMouseSettings.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays.Settings; namespace osu.iOS { - public class IOSMouseSettings : SettingsSubsection + public partial class IOSMouseSettings : SettingsSubsection { protected override LocalisableString Header => MouseSettingsStrings.Mouse; diff --git a/osu.iOS/OsuGameIOS.cs b/osu.iOS/OsuGameIOS.cs index ecbea42d74..b3194e497b 100644 --- a/osu.iOS/OsuGameIOS.cs +++ b/osu.iOS/OsuGameIOS.cs @@ -16,7 +16,7 @@ using Xamarin.Essentials; namespace osu.iOS { - public class OsuGameIOS : OsuGame + public partial class OsuGameIOS : OsuGame { public override Version AssemblyVersion => new Version(NSBundle.MainBundle.InfoDictionary["CFBundleVersion"].ToString()); From f6d47f84ad2b2497ee9a690dcde6ebe87610d2aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Nov 2022 18:00:37 +0100 Subject: [PATCH 2412/2686] Add one more partial modifier commit ignore --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index e331778e7f..b85862270b 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -4,3 +4,5 @@ 7bc8908ca9c026fed1d831eb6e58df7624a8d614 # Add a few more missing partial specs 212d78865a6b5f091173a347bad5686834d1d5fe +# Add partial specs in mobile projects too +00c11b2b4e389e48f3995d63484a6bc66a7afbdb From c42720acd440f1dec1917ec381d8d50693f02752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 26 Nov 2022 18:05:08 +0100 Subject: [PATCH 2413/2686] Temporarily disable "partial class with one part" inspection --- osu.Game/Online/Rooms/APICreatedRoom.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Online/Rooms/APICreatedRoom.cs b/osu.Game/Online/Rooms/APICreatedRoom.cs index 254a338a60..7f2bd13aec 100644 --- a/osu.Game/Online/Rooms/APICreatedRoom.cs +++ b/osu.Game/Online/Rooms/APICreatedRoom.cs @@ -7,6 +7,8 @@ using Newtonsoft.Json; namespace osu.Game.Online.Rooms { + // TODO: Remove disable below after merging https://github.com/ppy/osu-framework/pull/5548 and applying follow-up changes game-side. + // ReSharper disable once PartialTypeWithSinglePart public partial class APICreatedRoom : Room { [JsonProperty("error")] From 7ab5136e12123124637ea1a7827d29a461a059a5 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 26 Nov 2022 20:05:34 +0300 Subject: [PATCH 2414/2686] Compute texel size in the DrawNode --- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 77d30d50d6..01e7fc7514 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -229,6 +229,7 @@ namespace osu.Game.Graphics.Backgrounds private readonly List parts = new List(); private Vector2 size; private float thickness; + private float texelSize; private IVertexBatch? vertexBatch; @@ -245,6 +246,7 @@ namespace osu.Game.Graphics.Backgrounds texture = Source.texture; size = Source.DrawSize; thickness = Source.Thickness; + texelSize = Math.Max(1.5f / Source.ScreenSpaceDrawQuad.Size.X, 1.5f / Source.ScreenSpaceDrawQuad.Size.Y); parts.Clear(); parts.AddRange(Source.parts); @@ -265,6 +267,7 @@ namespace osu.Game.Graphics.Backgrounds shader.Bind(); shader.GetUniform("thickness").UpdateValue(ref thickness); + shader.GetUniform("texelSize").UpdateValue(ref texelSize); foreach (TriangleParticle particle in parts) { From d1eedd081cb3b500c168893fbe6c4302748287a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 27 Nov 2022 02:46:11 +0900 Subject: [PATCH 2415/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index b1d6231210..8f4750e831 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9d7ef7fb22..afc80d073f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index ae0bc2d0c0..4d8c1af28b 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + From 8ecb4aa30b35256edbae8b532c7ab9f20216a955 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Sun, 27 Nov 2022 09:41:08 +0900 Subject: [PATCH 2416/2686] better method name --- osu.Game/Online/Chat/NowPlayingCommand.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index ea44bd93d8..63df052644 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -67,14 +67,14 @@ namespace osu.Game.Online.Chat break; } - string beatmapString() + string getBeatmapPart() { string beatmapInfoString = localisation.GetLocalisedBindableString(beatmapInfo.GetDisplayTitleRomanisable()).Value; return beatmapInfo.OnlineID > 0 ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfoString}]" : beatmapInfoString; } - string modString() + string getModPart() { if (selectedMods.Value.Count == 0) { @@ -91,7 +91,7 @@ namespace osu.Game.Online.Chat return modS.ToString(); } - channelManager.PostMessage($"is {verb} {beatmapString()} {modString()}", true, target); + channelManager.PostMessage($"is {verb} {getBeatmapPart()} {getModPart()}", true, target); Expire(); } } From 653875bbb452e8ac9297fcc345ec7af027518c99 Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Sun, 27 Nov 2022 09:41:41 +0900 Subject: [PATCH 2417/2686] only post mod when ingame --- osu.Game/Online/Chat/NowPlayingCommand.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index 63df052644..93ea597afa 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -76,6 +76,8 @@ namespace osu.Game.Online.Chat string getModPart() { + if (api.Activity.Value is UserActivity.InGame) return string.Empty; + if (selectedMods.Value.Count == 0) { return string.Empty; From 02e3ebe1a01a39fb692ac13d2c37f6c7bdbc138a Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Sun, 27 Nov 2022 09:42:55 +0900 Subject: [PATCH 2418/2686] DifficultyIncrease use `+` and other all `-` mod.Name to mod.Acronym --- osu.Game/Online/Chat/NowPlayingCommand.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index 93ea597afa..6d3e1ad50c 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.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 System.Text; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -76,7 +77,7 @@ namespace osu.Game.Online.Chat string getModPart() { - if (api.Activity.Value is UserActivity.InGame) return string.Empty; + if (api.Activity.Value is not UserActivity.InGame) return string.Empty; if (selectedMods.Value.Count == 0) { @@ -85,9 +86,14 @@ namespace osu.Game.Online.Chat StringBuilder modS = new StringBuilder(); - foreach (var mod in selectedMods.Value) + foreach (var mod in selectedMods.Value.Where(mod => mod.Type == ModType.DifficultyIncrease)) { - modS.Append($"+{mod.Name} "); + modS.Append($"+{mod.Acronym} "); + } + + foreach (var mod in selectedMods.Value.Where(mod => mod.Type != ModType.DifficultyIncrease)) + { + modS.Append($"-{mod.Acronym} "); } return modS.ToString(); From 54681217be3cf85387d2673ce172e2155b01e41b Mon Sep 17 00:00:00 2001 From: cdwcgt Date: Sun, 27 Nov 2022 10:44:06 +0900 Subject: [PATCH 2419/2686] fix test --- osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs index 1bd2118d5a..362ebd1e74 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs @@ -81,11 +81,13 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestModPresence() { + AddStep("Set activity", () => api.Activity.Value = new UserActivity.InSoloGame(new BeatmapInfo(), new RulesetInfo())); + AddStep("Add Hidden mod", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateMod() }); AddStep("Run command", () => Add(new NowPlayingCommand())); - AddAssert("Check mod is present", () => postTarget.LastMessage.Contains("+Hidden")); + AddAssert("Check mod is present", () => postTarget.LastMessage.Contains("+HD")); } public partial class PostTarget : Component, IChannelPostTarget From 1a914d0df7b4e413be152327756b683f117a3d88 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sun, 27 Nov 2022 02:43:22 +0000 Subject: [PATCH 2420/2686] Remove `#nullable disable` from `TimingScreen` --- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 26 +++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 43fca40526..4a38d64583 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.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. -#nullable disable - using System; using System.Linq; using osu.Framework.Allocation; @@ -50,24 +48,24 @@ namespace osu.Game.Screens.Edit.Timing public partial class ControlPointList : CompositeDrawable { - private OsuButton deleteButton; - private ControlPointTable table; + private OsuButton deleteButton = null!; + private ControlPointTable table = null!; + private OsuScrollContainer scroll = null!; + private RoundedButton addButton = null!; private readonly IBindableList controlPointGroups = new BindableList(); - private RoundedButton addButton; + [Resolved] + private EditorClock clock { get; set; } = null!; [Resolved] - private EditorClock clock { get; set; } + protected EditorBeatmap Beatmap { get; private set; } = null!; [Resolved] - protected EditorBeatmap Beatmap { get; private set; } + private Bindable selectedGroup { get; set; } = null!; [Resolved] - private Bindable selectedGroup { get; set; } - - [Resolved(canBeNull: true)] - private IEditorChangeHandler changeHandler { get; set; } + private IEditorChangeHandler? changeHandler { get; set; } [BackgroundDependencyLoader] private void load(OverlayColourProvider colours) @@ -132,8 +130,8 @@ namespace osu.Game.Screens.Edit.Timing deleteButton.Enabled.Value = selected.NewValue != null; addButton.Text = selected.NewValue != null - ? "+ Clone to current time" - : "+ Add at current time"; + ? @"+ Clone to current time" + : @"+ Add at current time"; }, true); controlPointGroups.BindTo(Beatmap.ControlPointInfo.Groups); @@ -159,7 +157,7 @@ namespace osu.Game.Screens.Edit.Timing addButton.Enabled.Value = clock.CurrentTimeAccurate != selectedGroup.Value?.Time; } - private Type trackedType; + private Type? trackedType; /// /// Given the user has selected a control point group, we want to track any group which is From b6d7bec2405299d5d7428a40473462671e30b6be Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sun, 27 Nov 2022 02:45:56 +0000 Subject: [PATCH 2421/2686] Remove `#nullable disabled` from `EditorTable` and it's derived classes --- osu.Game/Screens/Edit/EditorTable.cs | 8 +------ .../Screens/Edit/Timing/ControlPointTable.cs | 18 +++++++------- osu.Game/Screens/Edit/Verify/IssueTable.cs | 24 +++++++++---------- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs index f97a8c5572..f62106745b 100644 --- a/osu.Game/Screens/Edit/EditorTable.cs +++ b/osu.Game/Screens/Edit/EditorTable.cs @@ -1,8 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - +using System; using osu.Framework.Allocation; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; @@ -84,11 +83,6 @@ namespace osu.Game.Screens.Edit Alpha = 0, }, }; - - // todo delete - Action = () => - { - }; } private Color4 colourHover; diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index 5c131c0b6d..7bc59c77f8 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.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. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -23,10 +21,10 @@ namespace osu.Game.Screens.Edit.Timing public partial class ControlPointTable : EditorTable { [Resolved] - private Bindable selectedGroup { get; set; } + private Bindable selectedGroup { get; set; } = null!; [Resolved] - private EditorClock clock { get; set; } + private EditorClock clock { get; set; } = null!; public const float TIMING_COLUMN_WIDTH = 230; @@ -81,8 +79,8 @@ namespace osu.Game.Screens.Edit.Timing { var columns = new List { - new TableColumn("Time", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, TIMING_COLUMN_WIDTH)), - new TableColumn("Attributes", Anchor.CentreLeft), + new TableColumn(@"Time", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, TIMING_COLUMN_WIDTH)), + new TableColumn(@"Attributes", Anchor.CentreLeft), }; return columns.ToArray(); @@ -162,12 +160,13 @@ namespace osu.Game.Screens.Edit.Timing .Where(matchFunction) .Select(createAttribute) .Where(c => c != null) + .Select(c => c!) // arbitrary ordering to make timing points first. // probably want to explicitly define order in the future. .OrderByDescending(c => c.GetType().Name); } - private Drawable createAttribute(ControlPoint controlPoint) + private Drawable? createAttribute(ControlPoint controlPoint) { switch (controlPoint) { @@ -182,9 +181,10 @@ namespace osu.Game.Screens.Edit.Timing case SampleControlPoint sample: return new SampleRowAttribute(sample); - } - return null; + default: + return null; + } } } } diff --git a/osu.Game/Screens/Edit/Verify/IssueTable.cs b/osu.Game/Screens/Edit/Verify/IssueTable.cs index 6fdf9c76e2..3c72815d1f 100644 --- a/osu.Game/Screens/Edit/Verify/IssueTable.cs +++ b/osu.Game/Screens/Edit/Verify/IssueTable.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. -#nullable disable - using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; @@ -20,19 +18,19 @@ namespace osu.Game.Screens.Edit.Verify { public partial class IssueTable : EditorTable { - [Resolved] - private VerifyScreen verify { get; set; } - - private Bindable selectedIssue; + private Bindable selectedIssue = null!; [Resolved] - private EditorClock clock { get; set; } + private VerifyScreen verify { get; set; } = null!; [Resolved] - private EditorBeatmap editorBeatmap { get; set; } + private EditorClock clock { get; set; } = null!; [Resolved] - private Editor editor { get; set; } + private EditorBeatmap editorBeatmap { get; set; } = null!; + + [Resolved] + private Editor editor { get; set; } = null!; public IEnumerable Issues { @@ -88,10 +86,10 @@ namespace osu.Game.Screens.Edit.Verify var columns = new List { new TableColumn(string.Empty, Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)), - new TableColumn("Type", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize, minSize: 60)), - new TableColumn("Time", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize, minSize: 60)), - new TableColumn("Message", Anchor.CentreLeft), - new TableColumn("Category", Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)), + new TableColumn(@"Type", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize, minSize: 60)), + new TableColumn(@"Time", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize, minSize: 60)), + new TableColumn(@"Message", Anchor.CentreLeft), + new TableColumn(@"Category", Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)), }; return columns.ToArray(); From 792334a1902e8ea80a18b0d1a232c1ade5c4638d Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sun, 27 Nov 2022 02:47:02 +0000 Subject: [PATCH 2422/2686] Move Control Group timing data into it's own component --- .../Screens/Edit/Timing/ControlPointTable.cs | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index 7bc59c77f8..e8fd71afa3 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -90,32 +90,38 @@ namespace osu.Game.Screens.Edit.Timing { return new Drawable[] { - new FillFlowContainer - { - RelativeSizeAxes = Axes.Y, - Width = TIMING_COLUMN_WIDTH, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new OsuSpriteText - { - Text = group.Time.ToEditorFormattedString(), - Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold), - Width = 70, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - new ControlGroupAttributes(group, c => c is TimingControlPoint) - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - } - } - }, - new ControlGroupAttributes(group, c => !(c is TimingControlPoint)) + new ControlGroupTiming(group), + new ControlGroupAttributes(group, c => c is not TimingControlPoint) }; } + private partial class ControlGroupTiming : FillFlowContainer + { + public ControlGroupTiming(ControlPointGroup group) + { + Name = @"ControlGroupTiming"; + RelativeSizeAxes = Axes.Y; + Width = TIMING_COLUMN_WIDTH; + Spacing = new Vector2(5); + Children = new Drawable[] + { + new OsuSpriteText + { + Text = group.Time.ToEditorFormattedString(), + Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold), + Width = 70, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + new ControlGroupAttributes(group, c => c is TimingControlPoint) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + } + }; + } + } + private partial class ControlGroupAttributes : CompositeDrawable { private readonly Func matchFunction; @@ -130,6 +136,7 @@ namespace osu.Game.Screens.Edit.Timing AutoSizeAxes = Axes.X; RelativeSizeAxes = Axes.Y; + Name = @"ControlGroupAttributes"; InternalChild = fill = new FillFlowContainer { From 3c56b9c93a24638907466361adf45919713bcbfb Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sun, 27 Nov 2022 02:47:54 +0000 Subject: [PATCH 2423/2686] Add `OnRowSelected` event to `EditorTable` --- osu.Game/Screens/Edit/EditorTable.cs | 13 +++++++++++++ osu.Game/Screens/Edit/Timing/ControlPointTable.cs | 8 +------- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 4 +++- osu.Game/Screens/Edit/Verify/IssueTable.cs | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs index f62106745b..7b607e9afc 100644 --- a/osu.Game/Screens/Edit/EditorTable.cs +++ b/osu.Game/Screens/Edit/EditorTable.cs @@ -19,6 +19,8 @@ namespace osu.Game.Screens.Edit { public abstract partial class EditorTable : TableContainer { + public event Action? OnRowSelected; + private const float horizontal_inset = 20; protected const float ROW_HEIGHT = 25; @@ -44,6 +46,17 @@ namespace osu.Game.Screens.Edit }); } + protected void SetRowSelected(object? item) + { + foreach (var b in BackgroundFlow) + { + b.Selected = ReferenceEquals(b.Item, item); + + if (b.Selected) + OnRowSelected?.Invoke(b); + } + } + protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default); private partial class HeaderText : OsuSpriteText diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index e8fd71afa3..464a8e92ad 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -63,17 +63,11 @@ namespace osu.Game.Screens.Edit.Timing selectedGroup.BindValueChanged(_ => { - // TODO: This should scroll the selected row into view. updateSelectedGroup(); }, true); } - private void updateSelectedGroup() - { - // TODO: This should scroll the selected row into view. - foreach (var b in BackgroundFlow) - b.Selected = ReferenceEquals(b.Item, selectedGroup?.Value); - } + private void updateSelectedGroup() => SetRowSelected(selectedGroup?.Value); private TableColumn[] createHeaders() { diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 4a38d64583..2c40add77c 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -86,7 +86,7 @@ namespace osu.Game.Screens.Edit.Timing RelativeSizeAxes = Axes.Y, Width = ControlPointTable.TIMING_COLUMN_WIDTH + margins, }, - new OsuScrollContainer + scroll = new OsuScrollContainer { RelativeSizeAxes = Axes.Both, Child = table = new ControlPointTable(), @@ -140,6 +140,8 @@ namespace osu.Game.Screens.Edit.Timing table.ControlGroups = controlPointGroups; changeHandler?.SaveState(); }, true); + + table.OnRowSelected += (drawable) => scroll.ScrollIntoView(drawable); } protected override bool OnClick(ClickEvent e) diff --git a/osu.Game/Screens/Edit/Verify/IssueTable.cs b/osu.Game/Screens/Edit/Verify/IssueTable.cs index 3c72815d1f..75e7c2e43d 100644 --- a/osu.Game/Screens/Edit/Verify/IssueTable.cs +++ b/osu.Game/Screens/Edit/Verify/IssueTable.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Edit.Verify selectedIssue = verify.SelectedIssue.GetBoundCopy(); selectedIssue.BindValueChanged(issue => { - foreach (var b in BackgroundFlow) b.Selected = b.Item == issue.NewValue; + SetRowSelected(issue); }, true); } From 8dcd1a206713f375adde35d6adb80efc9685a29a Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sun, 27 Nov 2022 02:48:15 +0000 Subject: [PATCH 2424/2686] Add test to verify selected timing point will be scrolled into view --- .../Visual/Editing/TestSceneTimingScreen.cs | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs index 86a977fd3f..216c35de65 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs @@ -10,6 +10,8 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; using osu.Game.Overlays; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; @@ -26,6 +28,7 @@ namespace osu.Game.Tests.Visual.Editing private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); private TimingScreen timingScreen; + private EditorBeatmap editorBeatmap; protected override bool ScrollUsingMouseWheel => false; @@ -35,8 +38,11 @@ namespace osu.Game.Tests.Visual.Editing Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); Beatmap.Disabled = true; + } - var editorBeatmap = new EditorBeatmap(Beatmap.Value.GetPlayableBeatmap(Ruleset.Value)); + private void reloadEditorBeatmap() + { + editorBeatmap = new EditorBeatmap(Beatmap.Value.GetPlayableBeatmap(Ruleset.Value)); Child = new DependencyProvidingContainer { @@ -58,7 +64,9 @@ namespace osu.Game.Tests.Visual.Editing { AddStep("Stop clock", () => EditorClock.Stop()); - AddUntilStep("wait for rows to load", () => Child.ChildrenOfType().Any()); + AddStep("Reload Editor Beatmap", reloadEditorBeatmap); + + AddUntilStep("Wait for rows to load", () => Child.ChildrenOfType().Any()); } [Test] @@ -95,6 +103,37 @@ namespace osu.Game.Tests.Visual.Editing AddUntilStep("Selection changed", () => timingScreen.SelectedGroup.Value.Time == 69670); } + [Test] + public void TestScrollControlGroupIntoView() + { + AddStep("Add many control points", () => + { + editorBeatmap.ControlPointInfo.Clear(); + + editorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint()); + + for (int i = 0; i < 100; i++) + { + editorBeatmap.ControlPointInfo.Add((i + 1) * 1000, new EffectControlPoint + { + KiaiMode = Convert.ToBoolean(i % 2), + }); + } + }); + + AddStep("Select first effect point", () => + { + InputManager.MoveMouseTo(Child.ChildrenOfType().First()); + InputManager.Click(MouseButton.Left); + }); + + AddStep("Seek to beginning", () => EditorClock.Seek(0)); + + AddStep("Seek to last point", () => EditorClock.Seek(101 * 1000)); + + AddUntilStep("Scrolled to end", () => timingScreen.ChildrenOfType().First().IsScrolledToEnd()); + } + protected override void Dispose(bool isDisposing) { Beatmap.Disabled = false; From 6000e146681d2feb5423addf7dbbd8edeffa99e6 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sun, 27 Nov 2022 03:08:54 +0000 Subject: [PATCH 2425/2686] Correctly select issue row --- osu.Game/Screens/Edit/Verify/IssueTable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Verify/IssueTable.cs b/osu.Game/Screens/Edit/Verify/IssueTable.cs index 75e7c2e43d..d78108b026 100644 --- a/osu.Game/Screens/Edit/Verify/IssueTable.cs +++ b/osu.Game/Screens/Edit/Verify/IssueTable.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Edit.Verify selectedIssue = verify.SelectedIssue.GetBoundCopy(); selectedIssue.BindValueChanged(issue => { - SetRowSelected(issue); + SetRowSelected(issue.NewValue); }, true); } From 218c04c1749ea4a591bee3ad7b3c1b3fc8ecf57d Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Sun, 27 Nov 2022 03:23:08 +0000 Subject: [PATCH 2426/2686] Code quality --- osu.Game/Screens/Edit/EditorTable.cs | 2 +- osu.Game/Screens/Edit/Timing/ControlPointTable.cs | 4 ++-- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 2 +- osu.Game/Screens/Edit/Verify/IssueTable.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs index 7b607e9afc..2443cfcbf0 100644 --- a/osu.Game/Screens/Edit/EditorTable.cs +++ b/osu.Game/Screens/Edit/EditorTable.cs @@ -57,7 +57,7 @@ namespace osu.Game.Screens.Edit } } - protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default); + protected override Drawable CreateHeader(int index, TableColumn? column) => new HeaderText(column?.Header ?? default); private partial class HeaderText : OsuSpriteText { diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index 464a8e92ad..b3cc41af72 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -35,7 +35,7 @@ namespace osu.Game.Screens.Edit.Timing Content = null; BackgroundFlow.Clear(); - if (value?.Any() != true) + if (!value.Any()) return; foreach (var group in value) @@ -67,7 +67,7 @@ namespace osu.Game.Screens.Edit.Timing }, true); } - private void updateSelectedGroup() => SetRowSelected(selectedGroup?.Value); + private void updateSelectedGroup() => SetRowSelected(selectedGroup.Value); private TableColumn[] createHeaders() { diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 2c40add77c..69eff776e6 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -141,7 +141,7 @@ namespace osu.Game.Screens.Edit.Timing changeHandler?.SaveState(); }, true); - table.OnRowSelected += (drawable) => scroll.ScrollIntoView(drawable); + table.OnRowSelected += drawable => scroll.ScrollIntoView(drawable); } protected override bool OnClick(ClickEvent e) diff --git a/osu.Game/Screens/Edit/Verify/IssueTable.cs b/osu.Game/Screens/Edit/Verify/IssueTable.cs index d78108b026..b37fb2b72d 100644 --- a/osu.Game/Screens/Edit/Verify/IssueTable.cs +++ b/osu.Game/Screens/Edit/Verify/IssueTable.cs @@ -39,7 +39,7 @@ namespace osu.Game.Screens.Edit.Verify Content = null; BackgroundFlow.Clear(); - if (value == null) + if (!value.Any()) return; foreach (var issue in value) From db7f429e39b892226a30c62cd2635104e14e21af Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sun, 27 Nov 2022 10:44:05 +0100 Subject: [PATCH 2427/2686] Fix partial class issues and adjust test slightly --- .../Visual/UserInterface/TestSceneRangeSlider.cs | 2 +- osu.Game/Graphics/UserInterface/RangeSlider.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs index 189a6b61f5..d0e3ff737c 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs @@ -11,7 +11,7 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneRangeSlider : OsuTestScene + public partial class TestSceneRangeSlider : OsuTestScene { [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Red); diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs index d654adf626..c8306b70fb 100644 --- a/osu.Game/Graphics/UserInterface/RangeSlider.cs +++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { - public class RangeSlider : CompositeDrawable + public partial class RangeSlider : CompositeDrawable { /// /// The lower limiting value @@ -125,7 +125,7 @@ namespace osu.Game.Graphics.UserInterface upperBound.Current.ValueChanged += max => lowerBound.Current.Value = Math.Min(max.NewValue - minRange, lowerBound.Current.Value); } - private class LowerBoundSlider : BoundSlider + private partial class LowerBoundSlider : BoundSlider { protected override void LoadComplete() { @@ -142,7 +142,7 @@ namespace osu.Game.Graphics.UserInterface && screenSpacePos.X <= Nub.ScreenSpaceDrawQuad.TopRight.X; } - private class UpperBoundSlider : BoundSlider + private partial class UpperBoundSlider : BoundSlider { protected override void LoadComplete() { @@ -156,7 +156,7 @@ namespace osu.Game.Graphics.UserInterface && screenSpacePos.X >= Nub.ScreenSpaceDrawQuad.TopLeft.X; } - protected class BoundSlider : OsuSliderBar + protected partial class BoundSlider : OsuSliderBar { public string? DefaultString; public LocalisableString? DefaultTooltip; From cff3e06ad6cc68b97e2e80baa5526a7c10ba4746 Mon Sep 17 00:00:00 2001 From: Derrick Timmermans Date: Sun, 27 Nov 2022 20:57:00 +0100 Subject: [PATCH 2428/2686] Update state based on result during LoadComplete --- .../Objects/Drawables/DrawableHitObject.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index d6c151028e..4b074f00aa 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -199,7 +199,7 @@ namespace osu.Game.Rulesets.Objects.Drawables comboColourBrightness.BindValueChanged(_ => UpdateComboColour()); // Apply transforms - updateState(State.Value, true); + updateStateBasedOnResults(); } /// @@ -266,12 +266,7 @@ namespace osu.Game.Rulesets.Objects.Drawables // If not loaded, the state update happens in LoadComplete(). if (IsLoaded) { - if (Result.IsHit) - updateState(ArmedState.Hit, true); - else if (Result.HasResult) - updateState(ArmedState.Miss, true); - else - updateState(ArmedState.Idle, true); + updateStateBasedOnResults(); // Combo colour may have been applied via a bindable flow while no object entry was attached. // Update here to ensure we're in a good state. @@ -279,6 +274,16 @@ namespace osu.Game.Rulesets.Objects.Drawables } } + private void updateStateBasedOnResults() + { + if (Result.IsHit) + updateState(ArmedState.Hit, true); + else if (Result.HasResult) + updateState(ArmedState.Miss, true); + else + updateState(ArmedState.Idle, true); + } + protected sealed override void OnFree(HitObjectLifetimeEntry entry) { StartTimeBindable.UnbindFrom(HitObject.StartTimeBindable); From 70c320b2e8efef9ea3775513a547310b2f022440 Mon Sep 17 00:00:00 2001 From: Derrick Timmermans Date: Sun, 27 Nov 2022 21:43:33 +0100 Subject: [PATCH 2429/2686] Provide ruleset dependencies only to Compose Placement Blueprints --- .../Edit/CatchBlueprintContainer.cs | 4 +-- .../Edit/CatchHitObjectComposer.cs | 2 +- .../Edit/ManiaBlueprintContainer.cs | 4 +-- .../Edit/ManiaHitObjectComposer.cs | 2 +- .../Edit/OsuBlueprintContainer.cs | 4 +-- .../Edit/OsuHitObjectComposer.cs | 2 +- .../Edit/TaikoBlueprintContainer.cs | 4 +-- .../Edit/TaikoHitObjectComposer.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 13 ++----- ...leRulesetDependenciesProvidingContainer.cs | 34 +++++++++++++++++++ .../Components/ComposeBlueprintContainer.cs | 13 +++++-- 11 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs diff --git a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs index a0a11424d0..19642c521e 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs @@ -13,8 +13,8 @@ namespace osu.Game.Rulesets.Catch.Edit { public class CatchBlueprintContainer : ComposeBlueprintContainer { - public CatchBlueprintContainer(CatchHitObjectComposer composer) - : base(composer) + public CatchBlueprintContainer(CatchHitObjectComposer composer, Ruleset ruleset) + : base(composer, ruleset) { } diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index 220bc49203..7cc65a834a 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -148,7 +148,7 @@ namespace osu.Game.Rulesets.Catch.Edit return result; } - protected override ComposeBlueprintContainer CreateBlueprintContainer() => new CatchBlueprintContainer(this); + protected override ComposeBlueprintContainer CreateBlueprintContainer() => new CatchBlueprintContainer(this, Ruleset); [CanBeNull] private PalpableCatchHitObject getLastSnappableHitObject(double time) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs index f438d6497c..597e94396a 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs @@ -13,8 +13,8 @@ namespace osu.Game.Rulesets.Mania.Edit { public class ManiaBlueprintContainer : ComposeBlueprintContainer { - public ManiaBlueprintContainer(HitObjectComposer composer) - : base(composer) + public ManiaBlueprintContainer(HitObjectComposer composer, Ruleset ruleset) + : base(composer, ruleset) { } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index 3585fd4e8c..529cf77078 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Mania.Edit } protected override ComposeBlueprintContainer CreateBlueprintContainer() - => new ManiaBlueprintContainer(this); + => new ManiaBlueprintContainer(this, Ruleset); protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] { diff --git a/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs index c0fb0ae7db..7330ed6bb9 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs @@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Osu.Edit { public class OsuBlueprintContainer : ComposeBlueprintContainer { - public OsuBlueprintContainer(HitObjectComposer composer) - : base(composer) + public OsuBlueprintContainer(HitObjectComposer composer, Ruleset ruleset) + : base(composer, ruleset) { } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index 1460fae4d7..c044b2cc79 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Edit } protected override ComposeBlueprintContainer CreateBlueprintContainer() - => new OsuBlueprintContainer(this); + => new OsuBlueprintContainer(this, Ruleset); public override string ConvertSelectionToString() => string.Join(',', selectedHitObjects.Cast().OrderBy(h => h.StartTime).Select(h => (h.IndexInCurrentCombo + 1).ToString())); diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs index 6107c8009a..b149fbcd4b 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs @@ -12,8 +12,8 @@ namespace osu.Game.Rulesets.Taiko.Edit { public class TaikoBlueprintContainer : ComposeBlueprintContainer { - public TaikoBlueprintContainer(HitObjectComposer composer) - : base(composer) + public TaikoBlueprintContainer(HitObjectComposer composer, Ruleset ruleset) + : base(composer, ruleset) { } diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs index 161799c980..1b6a4a1cdf 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs @@ -24,6 +24,6 @@ namespace osu.Game.Rulesets.Taiko.Edit }; protected override ComposeBlueprintContainer CreateBlueprintContainer() - => new TaikoBlueprintContainer(this); + => new TaikoBlueprintContainer(this, Ruleset); } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index d0164d0f2e..dea28667c6 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Edit protected readonly Ruleset Ruleset; // Provides `Playfield` - private DrawableRulesetDependencies dependencies; + private DependencyContainer dependencies; [Resolved] protected EditorClock EditorClock { get; private set; } @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Edit } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => - dependencies = new DrawableRulesetDependencies(Ruleset, base.CreateChildDependencies(parent)); + dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -218,7 +218,7 @@ namespace osu.Game.Rulesets.Edit /// /// Construct a relevant blueprint container. This will manage hitobject selection/placement input handling and display logic. /// - protected virtual ComposeBlueprintContainer CreateBlueprintContainer() => new ComposeBlueprintContainer(this); + protected virtual ComposeBlueprintContainer CreateBlueprintContainer() => new ComposeBlueprintContainer( this, Ruleset); /// /// Construct a drawable ruleset for the provided ruleset. @@ -410,13 +410,6 @@ namespace osu.Game.Rulesets.Edit } #endregion - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - dependencies.Dispose(); - } } /// diff --git a/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs b/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs new file mode 100644 index 0000000000..414cfe3a97 --- /dev/null +++ b/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs @@ -0,0 +1,34 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Rulesets.UI +{ + public class DrawableRulesetDependenciesProvidingContainer : Container + { + private Ruleset ruleset; + + private DrawableRulesetDependencies rulesetDependencies = null!; + + public DrawableRulesetDependenciesProvidingContainer(Ruleset ruleset) + { + this.ruleset = ruleset; + RelativeSizeAxes = Axes.Both; + } + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + return rulesetDependencies = new DrawableRulesetDependencies(ruleset, base.CreateChildDependencies(parent)); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + rulesetDependencies?.Dispose(); + } + } +} diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index ec07da43a0..c1100c3d7f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -15,11 +15,13 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Audio; using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.UI; using osu.Game.Screens.Edit.Components.TernaryButtons; using osuTK; using osuTK.Input; @@ -37,15 +39,19 @@ namespace osu.Game.Screens.Edit.Compose.Components private PlacementBlueprint currentPlacement; + private readonly Ruleset ruleset; + /// /// Positional input must be received outside the container's bounds, /// in order to handle composer blueprints which are partially offscreen. /// public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; - public ComposeBlueprintContainer(HitObjectComposer composer) + public ComposeBlueprintContainer(HitObjectComposer composer, Ruleset ruleset) : base(composer) { + this.ruleset = ruleset; + placementBlueprintContainer = new Container { RelativeSizeAxes = Axes.Both @@ -57,7 +63,10 @@ namespace osu.Game.Screens.Edit.Compose.Components { TernaryStates = CreateTernaryButtons().ToArray(); - AddInternal(placementBlueprintContainer); + AddInternal(new DrawableRulesetDependenciesProvidingContainer(ruleset) + { + Child = placementBlueprintContainer + }); } protected override void LoadComplete() From 93ba84e5ff187db13f5a368101722f9226ebfed3 Mon Sep 17 00:00:00 2001 From: Derrick Timmermans Date: Sun, 27 Nov 2022 21:48:44 +0100 Subject: [PATCH 2430/2686] Fix code style --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 2 +- .../UI/DrawableRulesetDependenciesProvidingContainer.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index dea28667c6..cf10c9deca 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -218,7 +218,7 @@ namespace osu.Game.Rulesets.Edit /// /// Construct a relevant blueprint container. This will manage hitobject selection/placement input handling and display logic. /// - protected virtual ComposeBlueprintContainer CreateBlueprintContainer() => new ComposeBlueprintContainer( this, Ruleset); + protected virtual ComposeBlueprintContainer CreateBlueprintContainer() => new ComposeBlueprintContainer(this, Ruleset); /// /// Construct a drawable ruleset for the provided ruleset. diff --git a/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs b/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs index 414cfe3a97..1efe72fdf3 100644 --- a/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs +++ b/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs @@ -7,9 +7,9 @@ using osu.Framework.Graphics.Containers; namespace osu.Game.Rulesets.UI { - public class DrawableRulesetDependenciesProvidingContainer : Container + public partial class DrawableRulesetDependenciesProvidingContainer : Container { - private Ruleset ruleset; + private readonly Ruleset ruleset; private DrawableRulesetDependencies rulesetDependencies = null!; From ba1717c2ca9710dbaaf4ab146d7c51fd018f3abb Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 29 Nov 2022 02:36:27 +0300 Subject: [PATCH 2431/2686] Don't draw 0 thickness triangles --- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 6e9e7591a8..ed9b6019f1 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -256,7 +256,7 @@ namespace osu.Game.Graphics.Backgrounds { base.Draw(renderer); - if (Source.AimCount == 0) + if (Source.AimCount == 0 || thickness == 0) return; if (vertexBatch == null || vertexBatch.Size != Source.AimCount) From 3e277a92e963bb709e22a3625edae25dc9f2f4b5 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 29 Nov 2022 03:21:59 +0300 Subject: [PATCH 2432/2686] Fix incorrect texel size calculation --- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 30 ++++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index ed9b6019f1..6e6514690d 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -227,6 +227,9 @@ namespace osu.Game.Graphics.Backgrounds private Texture texture = null!; private readonly List parts = new List(); + + private readonly Vector2 triangleSize = new Vector2(1f, equilateral_triangle_ratio) * triangle_size; + private Vector2 size; private float thickness; private float texelSize; @@ -246,7 +249,15 @@ namespace osu.Game.Graphics.Backgrounds texture = Source.texture; size = Source.DrawSize; thickness = Source.Thickness; - texelSize = Math.Max(1.5f / Source.ScreenSpaceDrawQuad.Size.X, 1.5f / Source.ScreenSpaceDrawQuad.Size.Y); + + Quad triangleQuad = new Quad( + Vector2Extensions.Transform(Vector2.Zero, DrawInfo.Matrix), + Vector2Extensions.Transform(new Vector2(triangle_size, 0f), DrawInfo.Matrix), + Vector2Extensions.Transform(new Vector2(0f, triangleSize.Y), DrawInfo.Matrix), + Vector2Extensions.Transform(triangleSize, DrawInfo.Matrix) + ); + + texelSize = 1.5f / triangleQuad.Height; parts.Clear(); parts.AddRange(Source.parts); @@ -269,14 +280,15 @@ namespace osu.Game.Graphics.Backgrounds shader.GetUniform("thickness").UpdateValue(ref thickness); shader.GetUniform("texelSize").UpdateValue(ref texelSize); + float texturePartWidth = triangleSize.X / size.X; + float texturePartHeight = triangleSize.Y / size.Y * texture_height; + foreach (TriangleParticle particle in parts) { - var offset = triangle_size * new Vector2(0.5f, equilateral_triangle_ratio); - - Vector2 topLeft = particle.Position * size + new Vector2(-offset.X, 0f); - Vector2 topRight = particle.Position * size + new Vector2(offset.X, 0); - Vector2 bottomLeft = particle.Position * size + new Vector2(-offset.X, offset.Y); - Vector2 bottomRight = particle.Position * size + new Vector2(offset.X, offset.Y); + Vector2 topLeft = particle.Position * size - new Vector2(triangleSize.X * 0.5f, 0f); + Vector2 topRight = topLeft + new Vector2(triangleSize.X, 0f); + Vector2 bottomLeft = topLeft + new Vector2(0f, triangleSize.Y); + Vector2 bottomRight = topLeft + triangleSize; var drawQuad = new Quad( Vector2Extensions.Transform(topLeft, DrawInfo.Matrix), @@ -288,8 +300,8 @@ namespace osu.Game.Graphics.Backgrounds var tRect = new Quad( topLeft.X / size.X, topLeft.Y / size.Y * texture_height, - (topRight.X - topLeft.X) / size.X, - (bottomRight.Y - topRight.Y) / size.Y * texture_height + texturePartWidth, + texturePartHeight ).AABBFloat; renderer.DrawQuad(texture, drawQuad, DrawColourInfo.Colour, tRect, vertexBatch.AddAction, textureCoords: tRect); From c2d8ffc225f8a9e8a4cde803f0d03d3927771465 Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 28 Nov 2022 17:50:12 -0800 Subject: [PATCH 2433/2686] Refactor `ChatLine` username drawable creation --- .../Visual/Online/TestSceneChatLink.cs | 4 +- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 2 +- osu.Game/Overlays/Chat/ChatLine.cs | 367 ++++++++++-------- 3 files changed, 199 insertions(+), 174 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs index de44986001..3bb8b948d0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs @@ -130,11 +130,11 @@ namespace osu.Game.Tests.Visual.Online Color4 textColour = isAction && hasBackground ? Color4Extensions.FromHex(newLine.Message.Sender.Colour) : Color4.White; - var linkCompilers = newLine.ContentFlow.Where(d => d is DrawableLinkCompiler).ToList(); + var linkCompilers = newLine.DrawableContentFlow.Where(d => d is DrawableLinkCompiler).ToList(); var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts); return linkSprites.All(d => d.Colour == linkColour) - && newLine.ContentFlow.Except(linkSprites.Concat(linkCompilers)).All(d => d.Colour == textColour); + && newLine.DrawableContentFlow.Except(linkSprites.Concat(linkCompilers)).All(d => d.Colour == textColour); } } } diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 81db3f0d53..667ba8c742 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -189,7 +189,7 @@ namespace osu.Game.Online.Chat protected class StandAloneMessage : ChatLine { - protected override float TextSize => 15; + protected override float FontSize => 15; protected override float Spacing => 5; protected override float UsernameWidth => 75; diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index bfbffabd2b..422dcf63df 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -24,11 +24,15 @@ using osu.Game.Online.Chat; using osuTK; using osuTK.Graphics; using osu.Framework.Input.Events; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; namespace osu.Game.Overlays.Chat { public class ChatLine : CompositeDrawable { + private Message message = null!; + public Message Message { get => message; @@ -45,55 +49,35 @@ namespace osu.Game.Overlays.Chat } } - public LinkFlowContainer ContentFlow { get; private set; } = null!; + public IReadOnlyCollection DrawableContentFlow => drawableContentFlow; - protected virtual float TextSize => 20; + protected virtual float FontSize => 20; protected virtual float Spacing => 15; protected virtual float UsernameWidth => 130; - private Color4 usernameColour; - - private OsuSpriteText timestamp = null!; - - private Message message = null!; - - private OsuSpriteText username = null!; - - private Drawable usernameColouredDrawable = null!; - - private Container? highlight; - - private readonly Bindable prefer24HourTime = new Bindable(); - - private bool senderHasColour => !string.IsNullOrEmpty(message.Sender.Colour); - - private bool messageHasColour => Message.IsAction && senderHasColour; - [Resolved] private ChannelManager? chatManager { get; set; } [Resolved] - private OsuColour colours { get; set; } = null!; + private OverlayColourProvider? colourProvider { get; set; } + + private readonly OsuSpriteText drawableTimestamp; + + private readonly DrawableUsername drawableUsername; + + private readonly LinkFlowContainer drawableContentFlow; + + private readonly Bindable prefer24HourTime = new Bindable(); + + private Container? highlight; public ChatLine(Message message) { Message = message; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - } - - [BackgroundDependencyLoader] - private void load(OverlayColourProvider? colourProvider, OsuConfigManager configManager) - { - usernameColour = senderHasColour - ? Color4Extensions.FromHex(message.Sender.Colour) - : username_colours[message.Sender.Id % username_colours.Length]; - - // this can be either the username sprite text or a container - // around it depending on which branch is taken in createUsername() - var usernameDrawable = createUsername(); InternalChild = new GridContainer { @@ -110,30 +94,24 @@ namespace osu.Game.Overlays.Chat { new Drawable[] { - timestamp = new OsuSpriteText + drawableTimestamp = new OsuSpriteText { Shadow = false, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: TextSize * 0.75f, weight: FontWeight.SemiBold, fixedWidth: true), - Colour = colourProvider?.Background1 ?? Colour4.White, + Font = OsuFont.GetFont(size: FontSize * 0.75f, weight: FontWeight.SemiBold, fixedWidth: true), AlwaysPresent = true, }, - new MessageSender(message.Sender, usernameColouredDrawable) + drawableUsername = new DrawableUsername(message.Sender) { Width = UsernameWidth, + FontSize = FontSize, AutoSizeAxes = Axes.Y, Origin = Anchor.TopRight, Anchor = Anchor.TopRight, - Child = usernameDrawable, Margin = new MarginPadding { Horizontal = Spacing }, }, - ContentFlow = new LinkFlowContainer(t => - { - t.Shadow = false; - t.Font = t.Font.With(size: TextSize, italics: Message.IsAction); - t.Colour = messageHasColour ? Color4Extensions.FromHex(message.Sender.Colour) : colourProvider?.Content1 ?? Colour4.White; - }) + drawableContentFlow = new LinkFlowContainer(styleMessageContent) { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, @@ -141,18 +119,23 @@ namespace osu.Game.Overlays.Chat }, } }; + } + [BackgroundDependencyLoader] + private void load(OsuConfigManager configManager) + { configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime); + prefer24HourTime.BindValueChanged(_ => updateTimestamp()); } protected override void LoadComplete() { base.LoadComplete(); + drawableTimestamp.Colour = colourProvider?.Background1 ?? Colour4.White; + updateMessageContent(); FinishTransforms(true); - - prefer24HourTime.BindValueChanged(_ => updateTimestamp()); } /// @@ -167,7 +150,7 @@ namespace osu.Game.Overlays.Chat CornerRadius = 2f, Masking = true, RelativeSizeAxes = Axes.Both, - Colour = usernameColour.Darken(1f), + Colour = drawableUsername.Colour.Darken(1f), Depth = float.MaxValue, Child = new Box { RelativeSizeAxes = Axes.Both } }); @@ -177,140 +160,182 @@ namespace osu.Game.Overlays.Chat highlight.Expire(); } + private void styleMessageContent(SpriteText text) + { + text.Shadow = false; + text.Font = text.Font.With(size: FontSize, italics: Message.IsAction); + + bool messageHasColour = Message.IsAction && !string.IsNullOrEmpty(message.Sender.Colour); + text.Colour = messageHasColour ? Color4Extensions.FromHex(message.Sender.Colour) : colourProvider?.Content1 ?? Colour4.White; + } + private void updateMessageContent() { this.FadeTo(message is LocalEchoMessage ? 0.4f : 1.0f, 500, Easing.OutQuint); - timestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint); + drawableTimestamp.FadeTo(message is LocalEchoMessage ? 0 : 1, 500, Easing.OutQuint); updateTimestamp(); - username.Text = $@"{message.Sender.Username}"; + drawableUsername.Text = $@"{message.Sender.Username}"; // remove non-existent channels from the link list message.Links.RemoveAll(link => link.Action == LinkAction.OpenChannel && chatManager?.AvailableChannels.Any(c => c.Name == link.Argument.ToString()) != true); - ContentFlow.Clear(); - ContentFlow.AddLinks(message.DisplayContent, message.Links); + drawableContentFlow.Clear(); + drawableContentFlow.AddLinks(message.DisplayContent, message.Links); } private void updateTimestamp() { - timestamp.Text = prefer24HourTime.Value + drawableTimestamp.Text = prefer24HourTime.Value ? $@"{message.Timestamp.LocalDateTime:HH:mm:ss}" : $@"{message.Timestamp.LocalDateTime:hh:mm:ss tt}"; } - private Drawable createUsername() + private class DrawableUsername : OsuClickableContainer, IHasContextMenu { - username = new OsuSpriteText - { - Shadow = false, - Truncate = true, - EllipsisString = "…", - Font = OsuFont.GetFont(size: TextSize, weight: FontWeight.Bold, italics: true), - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - MaxWidth = UsernameWidth, - }; + public new Color4 Colour { get; private set; } - if (!senderHasColour) + public float FontSize { - usernameColouredDrawable = username; - usernameColouredDrawable.Colour = usernameColour; - return username; + set => drawableText.Font = OsuFont.GetFont(size: value, weight: FontWeight.Bold, italics: true); } - username.Colour = colours.ChatBlue; - - // Background effect - return new Container + public LocalisableString Text { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 4, - EdgeEffect = new EdgeEffectParameters - { - Roundness = 1, - Radius = 1, - Colour = Color4.Black.Opacity(0.3f), - Offset = new Vector2(0, 1), - Type = EdgeEffectType.Shadow, - }, - Child = new Container - { - AutoSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 4, - Children = new Drawable[] - { - usernameColouredDrawable = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = usernameColour, - }, - new Container - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = 4, Right = 4, Bottom = 1, Top = -2 }, - Child = username - } - } - } - }; - } + set => drawableText.Text = value; + } - private class MessageSender : OsuClickableContainer, IHasContextMenu - { - private readonly APIUser sender; - private readonly Drawable colouredDrawable; - private readonly Color4 defaultColour; + public override float Width + { + get => base.Width; + set => base.Width = drawableText.MaxWidth = value; + } - private Action startChatAction = null!; - - [Resolved] + [Resolved(canBeNull: false)] private IAPIProvider api { get; set; } = null!; - public MessageSender(APIUser sender, Drawable colouredDrawable) + [Resolved(canBeNull: false)] + private OsuColour osuColours { get; set; } = null!; + + [Resolved] + private ChannelManager? chatManager { get; set; } + + [Resolved] + private ChatOverlay? chatOverlay { get; set; } + + [Resolved] + private UserProfileOverlay? profileOverlay { get; set; } + + private readonly APIUser user; + private readonly OsuSpriteText drawableText; + + private readonly Drawable colouredDrawable; + + public DrawableUsername(APIUser user) { - this.sender = sender; - this.colouredDrawable = colouredDrawable; - defaultColour = colouredDrawable.Colour; + this.user = user; + + Action = openUserProfile; + + drawableText = new OsuSpriteText + { + Shadow = false, + Truncate = true, + EllipsisString = "…", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }; + + if (string.IsNullOrWhiteSpace(user.Colour)) + { + Colour = default_colours[user.Id % default_colours.Length]; + + Child = colouredDrawable = drawableText; + } + else + { + + Colour = Color4Extensions.FromHex(user.Colour); + + Child = new Container + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4, + EdgeEffect = new EdgeEffectParameters + { + Roundness = 1, + Radius = 1, + Colour = Color4.Black.Opacity(0.3f), + Offset = new Vector2(0, 1), + Type = EdgeEffectType.Shadow, + }, + Child = new Container + { + AutoSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4, + Children = new[] + { + colouredDrawable = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 4, Right = 4, Bottom = 1, Top = -2 }, + Child = drawableText, + } + } + } + }; + } } - [BackgroundDependencyLoader] - private void load(UserProfileOverlay? profile, ChannelManager? chatManager, ChatOverlay? chatOverlay) + protected override void LoadComplete() { - Action = () => profile?.ShowUser(sender); - startChatAction = () => - { - chatManager?.OpenPrivateChannel(sender); - chatOverlay?.Show(); - }; + base.LoadComplete(); + + drawableText.Colour = osuColours.ChatBlue; + colouredDrawable.Colour = Colour; } public MenuItem[] ContextMenuItems { get { - if (sender.Equals(APIUser.SYSTEM_USER)) + if (user.Equals(APIUser.SYSTEM_USER)) return Array.Empty(); List items = new List { - new OsuMenuItem("View Profile", MenuItemType.Highlighted, Action) + new OsuMenuItem("View Profile", MenuItemType.Highlighted, openUserProfile) }; - if (!sender.Equals(api.LocalUser.Value)) - items.Add(new OsuMenuItem("Start Chat", MenuItemType.Standard, startChatAction)); + if (!user.Equals(api.LocalUser.Value)) + items.Add(new OsuMenuItem("Start Chat", MenuItemType.Standard, openUserChannel)); return items.ToArray(); } } + private void openUserChannel() + { + chatManager?.OpenPrivateChannel(user); + chatOverlay?.Show(); + } + + private void openUserProfile() + { + profileOverlay?.ShowUser(user); + } + protected override bool OnHover(HoverEvent e) { - colouredDrawable.FadeColour(defaultColour.Lighten(0.4f), 150, Easing.OutQuint); + colouredDrawable.FadeColour(Colour.Lighten(0.4f), 150, Easing.OutQuint); return base.OnHover(e); } @@ -319,47 +344,47 @@ namespace osu.Game.Overlays.Chat { base.OnHoverLost(e); - colouredDrawable.FadeColour(defaultColour, 250, Easing.OutQuint); + colouredDrawable.FadeColour(Colour, 250, Easing.OutQuint); } + + private static readonly Color4[] default_colours = + { + Color4Extensions.FromHex("588c7e"), + Color4Extensions.FromHex("b2a367"), + Color4Extensions.FromHex("c98f65"), + Color4Extensions.FromHex("bc5151"), + Color4Extensions.FromHex("5c8bd6"), + Color4Extensions.FromHex("7f6ab7"), + Color4Extensions.FromHex("a368ad"), + Color4Extensions.FromHex("aa6880"), + + Color4Extensions.FromHex("6fad9b"), + Color4Extensions.FromHex("f2e394"), + Color4Extensions.FromHex("f2ae72"), + Color4Extensions.FromHex("f98f8a"), + Color4Extensions.FromHex("7daef4"), + Color4Extensions.FromHex("a691f2"), + Color4Extensions.FromHex("c894d3"), + Color4Extensions.FromHex("d895b0"), + + Color4Extensions.FromHex("53c4a1"), + Color4Extensions.FromHex("eace5c"), + Color4Extensions.FromHex("ea8c47"), + Color4Extensions.FromHex("fc4f4f"), + Color4Extensions.FromHex("3d94ea"), + Color4Extensions.FromHex("7760ea"), + Color4Extensions.FromHex("af52c6"), + Color4Extensions.FromHex("e25696"), + + Color4Extensions.FromHex("677c66"), + Color4Extensions.FromHex("9b8732"), + Color4Extensions.FromHex("8c5129"), + Color4Extensions.FromHex("8c3030"), + Color4Extensions.FromHex("1f5d91"), + Color4Extensions.FromHex("4335a5"), + Color4Extensions.FromHex("812a96"), + Color4Extensions.FromHex("992861"), + }; } - - private static readonly Color4[] username_colours = - { - Color4Extensions.FromHex("588c7e"), - Color4Extensions.FromHex("b2a367"), - Color4Extensions.FromHex("c98f65"), - Color4Extensions.FromHex("bc5151"), - Color4Extensions.FromHex("5c8bd6"), - Color4Extensions.FromHex("7f6ab7"), - Color4Extensions.FromHex("a368ad"), - Color4Extensions.FromHex("aa6880"), - - Color4Extensions.FromHex("6fad9b"), - Color4Extensions.FromHex("f2e394"), - Color4Extensions.FromHex("f2ae72"), - Color4Extensions.FromHex("f98f8a"), - Color4Extensions.FromHex("7daef4"), - Color4Extensions.FromHex("a691f2"), - Color4Extensions.FromHex("c894d3"), - Color4Extensions.FromHex("d895b0"), - - Color4Extensions.FromHex("53c4a1"), - Color4Extensions.FromHex("eace5c"), - Color4Extensions.FromHex("ea8c47"), - Color4Extensions.FromHex("fc4f4f"), - Color4Extensions.FromHex("3d94ea"), - Color4Extensions.FromHex("7760ea"), - Color4Extensions.FromHex("af52c6"), - Color4Extensions.FromHex("e25696"), - - Color4Extensions.FromHex("677c66"), - Color4Extensions.FromHex("9b8732"), - Color4Extensions.FromHex("8c5129"), - Color4Extensions.FromHex("8c3030"), - Color4Extensions.FromHex("1f5d91"), - Color4Extensions.FromHex("4335a5"), - Color4Extensions.FromHex("812a96"), - Color4Extensions.FromHex("992861"), - }; } } From 8ec4dd046ee7a18ab59df4c4881815e208a0ff0b Mon Sep 17 00:00:00 2001 From: Alden Wu Date: Mon, 28 Nov 2022 18:06:44 -0800 Subject: [PATCH 2434/2686] Fix InspectCode errors --- osu.Game/Overlays/Chat/ChatLine.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index ad33f54848..e974db9fba 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -254,7 +254,6 @@ namespace osu.Game.Overlays.Chat } else { - Colour = Color4Extensions.FromHex(user.Colour); Child = new Container From a4819e5c9c0b37cadaf50bfdabfb4e763fae70b8 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 29 Nov 2022 07:01:52 +0300 Subject: [PATCH 2435/2686] Localize actions --- osu.Game/Overlays/Comments/DrawableComment.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 6cb5a0fbac..8c01633fe8 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -331,11 +331,11 @@ namespace osu.Game.Overlays.Comments if (WasDeleted) makeDeleted(); - actionsContainer.AddLink("Copy link", copyUrl); + actionsContainer.AddLink(CommonStrings.ButtonsPermalink, copyUrl); actionsContainer.AddArbitraryDrawable(Empty().With(d => d.Width = 10)); if (Comment.UserId.HasValue && Comment.UserId.Value == api.LocalUser.Value.Id) - actionsContainer.AddLink("Delete", deleteComment); + actionsContainer.AddLink(CommonStrings.ButtonsDelete, deleteComment); else actionsContainer.AddArbitraryDrawable(new CommentReportButton(Comment)); From 16962d9a57699d7c610f21d079987b2f8e338887 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Tue, 29 Nov 2022 07:02:02 +0300 Subject: [PATCH 2436/2686] Localize deleted string --- osu.Game/Overlays/Comments/DrawableComment.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 8c01633fe8..7bada5ef2a 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -553,12 +553,12 @@ namespace osu.Game.Overlays.Comments }; } - private string getParentMessage() + private LocalisableString getParentMessage() { if (parentComment == null) return string.Empty; - return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? "deleted" : string.Empty; + return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? CommentsStrings.Deleted : string.Empty; } } } From 96e19d4d84c97ff952d0271da2ef792be0e8b71e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Nov 2022 14:36:23 +0900 Subject: [PATCH 2437/2686] 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 8f4750e831..17237c5ca7 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index afc80d073f..9301670825 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 4d8c1af28b..57e58dc16a 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 24deb5f5f45f3e3e2c260ed3a08baeff659e3c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 16 Nov 2022 15:54:52 +0900 Subject: [PATCH 2438/2686] Remove all unnecessary usage of `IHasFilterableChildren` --- osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs | 1 - osu.Game/Overlays/Settings/SettingsSection.cs | 4 +--- osu.Game/Overlays/Settings/SettingsSubsection.cs | 5 +---- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs index 4e295ba665..24c2eee783 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs @@ -62,7 +62,6 @@ namespace osu.Game.Tests.Visual.Settings section.Children.Where(f => f.IsPresent) .OfType() .OfType() - .Where(f => !(f is IHasFilterableChildren)) .All(f => f.FilterTerms.Any(t => t.ToString().Contains("scaling"))) )); diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index dced187035..9602e4373f 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -19,7 +18,7 @@ using osuTK; namespace osu.Game.Overlays.Settings { - public abstract partial class SettingsSection : Container, IHasFilterableChildren + public abstract partial class SettingsSection : Container, IFilterable { protected FillFlowContainer FlowContent; protected override Container Content => FlowContent; @@ -33,7 +32,6 @@ namespace osu.Game.Overlays.Settings public abstract Drawable CreateIcon(); public abstract LocalisableString Header { get; } - public IEnumerable FilterableChildren => Children.OfType(); public virtual IEnumerable FilterTerms => new[] { Header }; public const int ITEM_SPACING = 14; diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index 78fb53230e..784f20a6e8 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Sprites; using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Localisation; using osu.Framework.Testing; @@ -17,7 +16,7 @@ using osu.Game.Graphics; namespace osu.Game.Overlays.Settings { [ExcludeFromDynamicCompile] - public abstract partial class SettingsSubsection : FillFlowContainer, IHasFilterableChildren + public abstract partial class SettingsSubsection : FillFlowContainer, IFilterable { protected override Container Content => FlowContent; @@ -25,8 +24,6 @@ namespace osu.Game.Overlays.Settings protected abstract LocalisableString Header { get; } - public IEnumerable FilterableChildren => Children.OfType(); - public virtual IEnumerable FilterTerms => new[] { Header }; public bool MatchingFilter From 8f78d6179bf907efe9f442c5a42a2439031a31ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 16 Nov 2022 22:58:32 +0900 Subject: [PATCH 2439/2686] Fix multiple issues with settings items unhiding on search --- .../Sections/Graphics/LayoutSettings.cs | 32 ++++++------------- .../Settings/Sections/Input/TabletSettings.cs | 25 ++++++++++----- osu.Game/Overlays/Settings/SettingsButton.cs | 7 +++- osu.Game/Overlays/Settings/SettingsItem.cs | 5 ++- 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 63689961e6..bad06732d0 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -177,13 +177,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics updateScreenModeWarning(); }, true); - windowModes.BindCollectionChanged((_, _) => - { - if (windowModes.Count > 1) - windowModeDropdown.Show(); - else - windowModeDropdown.Hide(); - }, true); + windowModes.BindCollectionChanged((_, _) => updateDisplaySettingsVisibility()); currentDisplay.BindValueChanged(display => Schedule(() => { @@ -219,7 +213,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint); scalingSettings.AutoSizeAxes = scalingMode.Value != ScalingMode.Off ? Axes.Y : Axes.None; - scalingSettings.ForEach(s => s.TransferValueOnCommit = scalingMode.Value == ScalingMode.Everything); + scalingSettings.ForEach(s => + { + s.TransferValueOnCommit = scalingMode.Value == ScalingMode.Everything; + s.CanBeShown.Value = scalingMode.Value != ScalingMode.Off; + }); } } @@ -234,20 +232,10 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics private void updateDisplaySettingsVisibility() { - if (resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen) - resolutionDropdown.Show(); - else - resolutionDropdown.Hide(); - - if (displayDropdown.Items.Count() > 1) - displayDropdown.Show(); - else - displayDropdown.Hide(); - - if (host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero) - safeAreaConsiderationsCheckbox.Show(); - else - safeAreaConsiderationsCheckbox.Hide(); + windowModeDropdown.CanBeShown.Value = windowModes.Count > 1; + resolutionDropdown.CanBeShown.Value = resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen; + displayDropdown.CanBeShown.Value = displayDropdown.Items.Count() > 1; + safeAreaConsiderationsCheckbox.CanBeShown.Value = host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero; } private void updateScreenModeWarning() diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 27612738df..951cf3802f 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -143,6 +143,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input areaOffset.SetDefault(); areaSize.SetDefault(); }, + CanBeShown = { BindTarget = enabled } }, new SettingsButton { @@ -150,25 +151,29 @@ namespace osu.Game.Overlays.Settings.Sections.Input Action = () => { forceAspectRatio((float)host.Window.ClientSize.Width / host.Window.ClientSize.Height); - } + }, + CanBeShown = { BindTarget = enabled } }, new SettingsSlider { TransferValueOnCommit = true, LabelText = TabletSettingsStrings.XOffset, - Current = offsetX + Current = offsetX, + CanBeShown = { BindTarget = enabled } }, new SettingsSlider { TransferValueOnCommit = true, LabelText = TabletSettingsStrings.YOffset, - Current = offsetY + Current = offsetY, + CanBeShown = { BindTarget = enabled } }, new SettingsSlider { TransferValueOnCommit = true, LabelText = TabletSettingsStrings.Rotation, - Current = rotation + Current = rotation, + CanBeShown = { BindTarget = enabled } }, new RotationPresetButtons(tabletHandler) { @@ -181,24 +186,28 @@ namespace osu.Game.Overlays.Settings.Sections.Input { TransferValueOnCommit = true, LabelText = TabletSettingsStrings.AspectRatio, - Current = aspectRatio + Current = aspectRatio, + CanBeShown = { BindTarget = enabled } }, new SettingsCheckbox { LabelText = TabletSettingsStrings.LockAspectRatio, - Current = aspectLock + Current = aspectLock, + CanBeShown = { BindTarget = enabled } }, new SettingsSlider { TransferValueOnCommit = true, LabelText = CommonStrings.Width, - Current = sizeX + Current = sizeX, + CanBeShown = { BindTarget = enabled } }, new SettingsSlider { TransferValueOnCommit = true, LabelText = CommonStrings.Height, - Current = sizeY + Current = sizeY, + CanBeShown = { BindTarget = enabled } }, } }, diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index dc1be1ce9f..5091ddc2d0 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -3,14 +3,16 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterfaceV2; namespace osu.Game.Overlays.Settings { - public partial class SettingsButton : RoundedButton, IHasTooltip + public partial class SettingsButton : RoundedButton, IHasTooltip, IConditionalFilterable { public SettingsButton() { @@ -20,6 +22,9 @@ namespace osu.Game.Overlays.Settings public LocalisableString TooltipText { get; set; } + public BindableBool CanBeShown { get; } = new BindableBool(true); + IBindable IConditionalFilterable.CanBeShown => CanBeShown; + public override IEnumerable FilterTerms { get diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 577f1738ba..5f4bb9d57f 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Overlays.Settings { - public abstract partial class SettingsItem : Container, IFilterable, ISettingsItem, IHasCurrentValue, IHasTooltip + public abstract partial class SettingsItem : Container, IConditionalFilterable, ISettingsItem, IHasCurrentValue, IHasTooltip { protected abstract Drawable CreateControl(); @@ -144,6 +144,9 @@ namespace osu.Game.Overlays.Settings public bool FilteringActive { get; set; } + public BindableBool CanBeShown { get; } = new BindableBool(true); + IBindable IConditionalFilterable.CanBeShown => CanBeShown; + public event Action SettingChanged; private T classicDefault; From b5b79e09e4c9d46fd5bea0da7f7ed664bd7b7afa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Nov 2022 14:45:08 +0900 Subject: [PATCH 2440/2686] Remove unnecessary CQ disable --- osu.Game/Online/Rooms/APICreatedRoom.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Online/Rooms/APICreatedRoom.cs b/osu.Game/Online/Rooms/APICreatedRoom.cs index 7f2bd13aec..254a338a60 100644 --- a/osu.Game/Online/Rooms/APICreatedRoom.cs +++ b/osu.Game/Online/Rooms/APICreatedRoom.cs @@ -7,8 +7,6 @@ using Newtonsoft.Json; namespace osu.Game.Online.Rooms { - // TODO: Remove disable below after merging https://github.com/ppy/osu-framework/pull/5548 and applying follow-up changes game-side. - // ReSharper disable once PartialTypeWithSinglePart public partial class APICreatedRoom : Room { [JsonProperty("error")] From 61c702c02ec94f39aafafb3267665cf207a3a9ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Nov 2022 14:45:26 +0900 Subject: [PATCH 2441/2686] Add new `IDependencyInjectionCandidate` interface to non-drawable cached classes --- osu.Game/Online/Rooms/Room.cs | 2 +- osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs | 2 +- osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs | 2 +- osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs | 2 +- .../Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index bdd7d6ce1c..8f346c4057 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -16,7 +16,7 @@ using osu.Game.Online.Rooms.RoomStatuses; namespace osu.Game.Online.Rooms { [JsonObject(MemberSerialization.OptIn)] - public partial class Room + public partial class Room : IDependencyInjectionCandidate { [Cached] [JsonProperty("id")] diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index b28b04f228..63688841d0 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -233,7 +233,7 @@ namespace osu.Game.Overlays.FirstRunSetup return parentDependencies.Get(type, info); } - public void Inject(T instance) where T : class + public void Inject(T instance) where T : class, IDependencyInjectionCandidate { parentDependencies.Inject(instance); } diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index fbc920f7de..bb4e06654a 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -164,7 +164,7 @@ namespace osu.Game.Tests.Beatmaps return fallback.Get(type, info); } - public void Inject(T instance) where T : class + public void Inject(T instance) where T : class, IDependencyInjectionCandidate { // Never used directly } diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs index 5350030276..87488710a7 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs @@ -128,7 +128,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay => OnlinePlayDependencies?.Get(type, info) ?? parent.Get(type, info); public void Inject(T instance) - where T : class + where T : class, IDependencyInjectionCandidate => injectableDependencies.Inject(instance); } } diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs index 35bdba0038..a9acbdcd7e 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay => dependencies.Get(type, info); public void Inject(T instance) - where T : class + where T : class, IDependencyInjectionCandidate => dependencies.Inject(instance); protected void Cache(object instance) From 56a694fb04bf200be1183cae1038c41a7ad59cac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 29 Nov 2022 15:10:21 +0900 Subject: [PATCH 2442/2686] Add automated test coverage of simple scenarios for `RangeSlider` --- .../UserInterface/TestSceneRangeSlider.cs | 26 ++++++++++++++++--- .../Graphics/UserInterface/RangeSlider.cs | 2 ++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs index d0e3ff737c..b780764e7f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneRangeSlider.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osuTK; @@ -30,10 +31,12 @@ namespace osu.Game.Tests.Visual.UserInterface Precision = 0.1f }; - [Test] - public void TestBasic() + private RangeSlider rangeSlider = null!; + + [SetUpSteps] + public void SetUpSteps() { - AddStep("create Control", () => Child = new RangeSlider + AddStep("create control", () => Child = rangeSlider = new RangeSlider { Width = 200, Anchor = Anchor.Centre, @@ -47,15 +50,30 @@ namespace osu.Game.Tests.Visual.UserInterface DefaultStringUpperBound = "End", MinRange = 10 }); - AddStep("Test Range", () => + } + + [Test] + public void TestAdjustRange() + { + AddAssert("Initial lower bound is correct", () => rangeSlider.LowerBound.Value, () => Is.EqualTo(0).Within(0.1f)); + AddAssert("Initial upper bound is correct", () => rangeSlider.UpperBound.Value, () => Is.EqualTo(100).Within(0.1f)); + + AddStep("Adjust range", () => { customStart.Value = 50; customEnd.Value = 75; }); + + AddAssert("Adjusted lower bound is correct", () => rangeSlider.LowerBound.Value, () => Is.EqualTo(50).Within(0.1f)); + AddAssert("Adjusted upper bound is correct", () => rangeSlider.UpperBound.Value, () => Is.EqualTo(75).Within(0.1f)); + AddStep("Test nub pushing", () => { customStart.Value = 90; }); + + AddAssert("Pushed lower bound is correct", () => rangeSlider.LowerBound.Value, () => Is.EqualTo(90).Within(0.1f)); + AddAssert("Pushed upper bound is correct", () => rangeSlider.UpperBound.Value, () => Is.EqualTo(100).Within(0.1f)); } } } diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs index c8306b70fb..483119cd58 100644 --- a/osu.Game/Graphics/UserInterface/RangeSlider.cs +++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs @@ -22,6 +22,7 @@ namespace osu.Game.Graphics.UserInterface /// public Bindable LowerBound { + get => lowerBound.Current; set => lowerBound.Current = value; } @@ -30,6 +31,7 @@ namespace osu.Game.Graphics.UserInterface /// public Bindable UpperBound { + get => upperBound.Current; set => upperBound.Current = value; } From 7dbf3793515ba9dde17ec8b79de95d26006f360e Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 29 Nov 2022 18:22:07 +0000 Subject: [PATCH 2443/2686] Don't use verbatim string literals --- osu.Game/Screens/Edit/Timing/ControlPointTable.cs | 4 ++-- osu.Game/Screens/Edit/Timing/TimingScreen.cs | 4 ++-- osu.Game/Screens/Edit/Verify/IssueTable.cs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index b3cc41af72..eeae1bcb9a 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -73,8 +73,8 @@ namespace osu.Game.Screens.Edit.Timing { var columns = new List { - new TableColumn(@"Time", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, TIMING_COLUMN_WIDTH)), - new TableColumn(@"Attributes", Anchor.CentreLeft), + new TableColumn("Time", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, TIMING_COLUMN_WIDTH)), + new TableColumn("Attributes", Anchor.CentreLeft), }; return columns.ToArray(); diff --git a/osu.Game/Screens/Edit/Timing/TimingScreen.cs b/osu.Game/Screens/Edit/Timing/TimingScreen.cs index 69eff776e6..2450909929 100644 --- a/osu.Game/Screens/Edit/Timing/TimingScreen.cs +++ b/osu.Game/Screens/Edit/Timing/TimingScreen.cs @@ -130,8 +130,8 @@ namespace osu.Game.Screens.Edit.Timing deleteButton.Enabled.Value = selected.NewValue != null; addButton.Text = selected.NewValue != null - ? @"+ Clone to current time" - : @"+ Add at current time"; + ? "+ Clone to current time" + : "+ Add at current time"; }, true); controlPointGroups.BindTo(Beatmap.ControlPointInfo.Groups); diff --git a/osu.Game/Screens/Edit/Verify/IssueTable.cs b/osu.Game/Screens/Edit/Verify/IssueTable.cs index b37fb2b72d..dbd007e423 100644 --- a/osu.Game/Screens/Edit/Verify/IssueTable.cs +++ b/osu.Game/Screens/Edit/Verify/IssueTable.cs @@ -86,10 +86,10 @@ namespace osu.Game.Screens.Edit.Verify var columns = new List { new TableColumn(string.Empty, Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)), - new TableColumn(@"Type", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize, minSize: 60)), - new TableColumn(@"Time", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize, minSize: 60)), - new TableColumn(@"Message", Anchor.CentreLeft), - new TableColumn(@"Category", Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)), + new TableColumn("Type", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize, minSize: 60)), + new TableColumn("Time", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize, minSize: 60)), + new TableColumn("Message", Anchor.CentreLeft), + new TableColumn("Category", Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)), }; return columns.ToArray(); From f3fa39f2541c640398b2d312d167acd26b647386 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Wed, 30 Nov 2022 00:44:20 +0100 Subject: [PATCH 2444/2686] Add legacy taiko kiai glow element --- .../Skinning/Legacy/LegacyKiaiGlow.cs | 67 +++++++++++++++++++ .../Legacy/TaikoLegacySkinTransformer.cs | 6 ++ .../TaikoSkinComponents.cs | 1 + osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 4 ++ 4 files changed, 78 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs new file mode 100644 index 0000000000..07eb052b20 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs @@ -0,0 +1,67 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Rulesets.Taiko.Skinning.Legacy +{ + internal partial class LegacyKiaiGlow : Container + { + public LegacyKiaiGlow() + { + AlwaysPresent = true; + Alpha = 0; + } + + [BackgroundDependencyLoader] + private void load(ISkinSource skin) + { + Child = new Sprite + { + Texture = skin.GetTexture("taiko-glow"), + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Scale = new Vector2(0.75f), + }; + } + + [Resolved(CanBeNull = true)] + private IBeatSyncProvider? beatSyncProvider { get; set; } + + [Resolved(CanBeNull = true)] + private HealthProcessor? healthProcessor { get; set; } + + protected override void Update() + { + base.Update(); + + if (healthProcessor != null) + healthProcessor.NewJudgement += onNewJudgement; + + if (beatSyncProvider != null) + { + if (beatSyncProvider.CheckIsKiaiTime()) + this.FadeIn(180); + else + this.FadeOut(180); + } + } + + private void onNewJudgement(JudgementResult result) + { + if (!result.IsHit) + return; + + this.ScaleTo(1.1f, 50) + .Then().ScaleTo(1f, 50); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs index 7bf99306f0..d61f9ac35d 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacySkinTransformer.cs @@ -129,6 +129,12 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy case TaikoSkinComponents.Mascot: return new DrawableTaikoMascot(); + case TaikoSkinComponents.KiaiGlow: + if (GetTexture("taiko-glow") != null) + return new LegacyKiaiGlow(); + + return null; + default: throw new UnsupportedSkinComponentException(lookup); } diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs index bf48898dd2..b8e3313e1b 100644 --- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs +++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs @@ -21,5 +21,6 @@ namespace osu.Game.Rulesets.Taiko TaikoExplosionKiai, Scroller, Mascot, + KiaiGlow } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 6ce0be5868..9493de624a 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -112,6 +112,10 @@ namespace osu.Game.Rulesets.Taiko.UI FillMode = FillMode.Fit, Children = new[] { + new SkinnableDrawable(new TaikoSkinComponentLookup(TaikoSkinComponents.KiaiGlow), _ => Empty()) + { + RelativeSizeAxes = Axes.Both, + }, hitExplosionContainer = new Container { RelativeSizeAxes = Axes.Both, From dc1dfacbb17b8be5106830f5ed456b6c03e427c8 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Wed, 30 Nov 2022 00:44:39 +0100 Subject: [PATCH 2445/2686] Add very basic test coverage --- .../Skinning/TestSceneTaikoKiaiGlow.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoKiaiGlow.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoKiaiGlow.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoKiaiGlow.cs new file mode 100644 index 0000000000..26e2202124 --- /dev/null +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoKiaiGlow.cs @@ -0,0 +1,33 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Taiko.Skinning.Legacy; + +namespace osu.Game.Rulesets.Taiko.Tests.Skinning +{ + public partial class TestSceneTaikoKiaiGlow : TaikoSkinnableTestScene + { + [Test] + public void TestKiaiGlow() + { + AddStep("Create kiai glow", () => SetContents(_ => new LegacyKiaiGlow())); + AddToggleStep("Toggle kiai mode", setUpBeatmap); + } + + private void setUpBeatmap(bool withKiai) + { + var controlPointInfo = new ControlPointInfo(); + + if (withKiai) + controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); + + Beatmap.Value = CreateWorkingBeatmap(new Beatmap + { + ControlPointInfo = controlPointInfo + }); + } + } +} From c3b5b19c327cae91684e02d6825533459743cf23 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 30 Nov 2022 04:02:35 +0300 Subject: [PATCH 2446/2686] Make TrianglesV2 test scene consistent --- .../Visual/Background/TestSceneTrianglesV2Background.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs index 8d6aef99ad..e8e3c80d48 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs @@ -54,7 +54,11 @@ namespace osu.Game.Tests.Visual.Background { base.LoadComplete(); - AddSliderStep("Spawn ratio", 0f, 2f, 1f, s => triangles.SpawnRatio = s); + AddSliderStep("Spawn ratio", 0f, 5f, 1f, s => + { + triangles.SpawnRatio = s; + triangles.Reset(1234); + }); AddSliderStep("Thickness", 0f, 1f, 0.02f, t => triangles.Thickness = t); } } From 3b13ca116719271c197aa5ab1f8dbbf063056ceb Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 30 Nov 2022 04:09:46 +0300 Subject: [PATCH 2447/2686] Remove texture from TrianglesV2 --- .../TestSceneTrianglesV2Background.cs | 4 +- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 87 ++++++------------- .../Graphics/UserInterfaceV2/RoundedButton.cs | 4 +- 3 files changed, 30 insertions(+), 65 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs index e8e3c80d48..4f37d5e988 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Shapes; using osuTK; using osuTK.Graphics; using osu.Game.Graphics.Backgrounds; +using osu.Framework.Graphics.Colour; namespace osu.Game.Tests.Visual.Background { @@ -42,8 +43,7 @@ namespace osu.Game.Tests.Visual.Background Anchor = Anchor.Centre, Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - ColourTop = Color4.White, - ColourBottom = Color4.Red + Colour = ColourInfo.GradientVertical(Color4.White, Color4.Red) } } } diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 6e6514690d..4838c1ec04 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -11,9 +11,7 @@ using osu.Framework.Allocation; using System.Collections.Generic; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering.Vertices; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp; -using osuTK.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -23,28 +21,12 @@ namespace osu.Game.Graphics.Backgrounds { private const float triangle_size = 100; private const float base_velocity = 50; - private const int texture_height = 128; /// /// sqrt(3) / 2 /// private const float equilateral_triangle_ratio = 0.866f; - private readonly Bindable colourTop = new Bindable(Color4.White); - private readonly Bindable colourBottom = new Bindable(Color4.Black); - - public Color4 ColourTop - { - get => colourTop.Value; - set => colourTop.Value = value; - } - - public Color4 ColourBottom - { - get => colourBottom.Value; - set => colourBottom.Value = value; - } - public float Thickness { get; set; } = 0.02f; // No need for invalidation since it's happening in Update() /// @@ -89,42 +71,19 @@ namespace osu.Game.Graphics.Backgrounds } [BackgroundDependencyLoader] - private void load(ShaderManager shaders) + private void load(ShaderManager shaders, IRenderer renderer) { shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, "TriangleBorder"); + texture = renderer.WhitePixel; } protected override void LoadComplete() { base.LoadComplete(); - colourTop.BindValueChanged(_ => updateTexture()); - colourBottom.BindValueChanged(_ => updateTexture(), true); - spawnRatio.BindValueChanged(_ => Reset(), true); } - private void updateTexture() - { - var image = new Image(texture_height, 1); - - texture = renderer.CreateTexture(1, texture_height, true); - - for (int i = 0; i < texture_height; i++) - { - float ratio = (float)i / texture_height; - - image[i, 0] = new Rgba32( - colourBottom.Value.R * ratio + colourTop.Value.R * (1f - ratio), - colourBottom.Value.G * ratio + colourTop.Value.G * (1f - ratio), - colourBottom.Value.B * ratio + colourTop.Value.B * (1f - ratio) - ); - } - - texture.SetData(new TextureUpload(image)); - Invalidate(Invalidation.DrawNode); - } - protected override void Update() { base.Update(); @@ -280,36 +239,42 @@ namespace osu.Game.Graphics.Backgrounds shader.GetUniform("thickness").UpdateValue(ref thickness); shader.GetUniform("texelSize").UpdateValue(ref texelSize); - float texturePartWidth = triangleSize.X / size.X; - float texturePartHeight = triangleSize.Y / size.Y * texture_height; + float relativeHeight = triangleSize.Y / size.Y; + float relativeWidth = triangleSize.X / size.X; foreach (TriangleParticle particle in parts) { - Vector2 topLeft = particle.Position * size - new Vector2(triangleSize.X * 0.5f, 0f); - Vector2 topRight = topLeft + new Vector2(triangleSize.X, 0f); - Vector2 bottomLeft = topLeft + new Vector2(0f, triangleSize.Y); - Vector2 bottomRight = topLeft + triangleSize; + Vector2 topLeft = particle.Position - new Vector2(relativeWidth * 0.5f, 0f); + Vector2 topRight = topLeft + new Vector2(relativeWidth, 0f); + Vector2 bottomLeft = topLeft + new Vector2(0f, relativeHeight); + Vector2 bottomRight = bottomLeft + new Vector2(relativeWidth, 0f); var drawQuad = new Quad( - Vector2Extensions.Transform(topLeft, DrawInfo.Matrix), - Vector2Extensions.Transform(topRight, DrawInfo.Matrix), - Vector2Extensions.Transform(bottomLeft, DrawInfo.Matrix), - Vector2Extensions.Transform(bottomRight, DrawInfo.Matrix) + Vector2Extensions.Transform(topLeft * size, DrawInfo.Matrix), + Vector2Extensions.Transform(topRight * size, DrawInfo.Matrix), + Vector2Extensions.Transform(bottomLeft * size, DrawInfo.Matrix), + Vector2Extensions.Transform(bottomRight * size, DrawInfo.Matrix) ); - var tRect = new Quad( - topLeft.X / size.X, - topLeft.Y / size.Y * texture_height, - texturePartWidth, - texturePartHeight - ).AABBFloat; + ColourInfo colourInfo = triangleColourInfo(DrawColourInfo.Colour, new Quad(topLeft, topRight, bottomLeft, bottomRight)); - renderer.DrawQuad(texture, drawQuad, DrawColourInfo.Colour, tRect, vertexBatch.AddAction, textureCoords: tRect); + renderer.DrawQuad(texture, drawQuad, colourInfo, vertexAction: vertexBatch.AddAction); } shader.Unbind(); } + private static ColourInfo triangleColourInfo(ColourInfo source, Quad quad) + { + return new ColourInfo + { + TopLeft = source.Interpolate(quad.TopLeft), + TopRight = source.Interpolate(quad.TopRight), + BottomLeft = source.Interpolate(quad.BottomLeft), + BottomRight = source.Interpolate(quad.BottomRight) + }; + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); diff --git a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs index 6dc99f5269..6aded3fe32 100644 --- a/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs +++ b/osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Framework.Localisation; @@ -79,8 +80,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 Debug.Assert(triangleGradientSecondColour != null); - Triangles.ColourTop = triangleGradientSecondColour.Value; - Triangles.ColourBottom = BackgroundColour; + Triangles.Colour = ColourInfo.GradientVertical(triangleGradientSecondColour.Value, BackgroundColour); } protected override bool OnHover(HoverEvent e) From 745cb0b13aea51f224b646bfa7beace70ee836ec Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 30 Nov 2022 04:17:37 +0300 Subject: [PATCH 2448/2686] Improve test scene --- .../Visual/Background/TestSceneTrianglesV2Background.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs index 4f37d5e988..2a4e9a7356 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs @@ -42,8 +42,7 @@ namespace osu.Game.Tests.Visual.Background { Anchor = Anchor.Centre, Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.White, Color4.Red) + RelativeSizeAxes = Axes.Both } } } @@ -60,6 +59,10 @@ namespace osu.Game.Tests.Visual.Background triangles.Reset(1234); }); AddSliderStep("Thickness", 0f, 1f, 0.02f, t => triangles.Thickness = t); + + AddStep("White colour", () => triangles.Colour = Color4.White); + AddStep("Vertical gradient", () => triangles.Colour = ColourInfo.GradientVertical(Color4.White, Color4.Red)); + AddStep("Horizontal gradient", () => triangles.Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.Red)); } } } From 2eaefcad304c8da2780f5ab5f503f898c9e717f7 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 30 Nov 2022 04:56:07 +0300 Subject: [PATCH 2449/2686] Remove unused renderer --- osu.Game/Graphics/Backgrounds/TrianglesV2.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs index 4838c1ec04..d543f082b4 100644 --- a/osu.Game/Graphics/Backgrounds/TrianglesV2.cs +++ b/osu.Game/Graphics/Backgrounds/TrianglesV2.cs @@ -52,9 +52,6 @@ namespace osu.Game.Graphics.Backgrounds private readonly List parts = new List(); - [Resolved] - private IRenderer renderer { get; set; } = null!; - private Random? stableRandom; private IShader shader = null!; From fa1000777dec3af022757550bf2b9578906c8f03 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 30 Nov 2022 05:12:26 +0300 Subject: [PATCH 2450/2686] Add box for gradient comparison --- .../TestSceneTrianglesV2Background.cs | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs index 2a4e9a7356..ae1f3de6bf 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneTrianglesV2Background.cs @@ -14,6 +14,7 @@ namespace osu.Game.Tests.Visual.Background public partial class TestSceneTrianglesV2Background : OsuTestScene { private readonly TrianglesV2 triangles; + private readonly Box box; public TestSceneTrianglesV2Background() { @@ -24,25 +25,44 @@ namespace osu.Game.Tests.Visual.Background RelativeSizeAxes = Axes.Both, Colour = Color4.Gray }, - new Container + new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(500, 100), - Masking = true, - CornerRadius = 40, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 5), Children = new Drawable[] { - new Box + new Container { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Red + Size = new Vector2(500, 100), + Masking = true, + CornerRadius = 40, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Red + }, + triangles = new TrianglesV2 + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both + } + } }, - triangles = new TrianglesV2 + new Container { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both + Size = new Vector2(500, 100), + Masking = true, + CornerRadius = 40, + Child = box = new Box + { + RelativeSizeAxes = Axes.Both + } } } } @@ -53,16 +73,16 @@ namespace osu.Game.Tests.Visual.Background { base.LoadComplete(); - AddSliderStep("Spawn ratio", 0f, 5f, 1f, s => + AddSliderStep("Spawn ratio", 0f, 10f, 1f, s => { triangles.SpawnRatio = s; triangles.Reset(1234); }); AddSliderStep("Thickness", 0f, 1f, 0.02f, t => triangles.Thickness = t); - AddStep("White colour", () => triangles.Colour = Color4.White); - AddStep("Vertical gradient", () => triangles.Colour = ColourInfo.GradientVertical(Color4.White, Color4.Red)); - AddStep("Horizontal gradient", () => triangles.Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.Red)); + AddStep("White colour", () => box.Colour = triangles.Colour = Color4.White); + AddStep("Vertical gradient", () => box.Colour = triangles.Colour = ColourInfo.GradientVertical(Color4.White, Color4.Red)); + AddStep("Horizontal gradient", () => box.Colour = triangles.Colour = ColourInfo.GradientHorizontal(Color4.White, Color4.Red)); } } } From 3f4d8b39caa4acf0a86b0af332c69f2a80308804 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 30 Nov 2022 12:55:45 +0900 Subject: [PATCH 2451/2686] Update package again --- 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 17237c5ca7..75828147a5 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9301670825..6e75450594 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 57e58dc16a..bb20b0474d 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 0659c8434156e3f2da41b6abb82317a5cafc8c46 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 14:17:49 +0900 Subject: [PATCH 2452/2686] Rename method to be more in line with project naming --- osu.Game/Screens/Edit/EditorTable.cs | 2 +- osu.Game/Screens/Edit/Timing/ControlPointTable.cs | 7 ++----- osu.Game/Screens/Edit/Verify/IssueTable.cs | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs index 2443cfcbf0..b79d71b42b 100644 --- a/osu.Game/Screens/Edit/EditorTable.cs +++ b/osu.Game/Screens/Edit/EditorTable.cs @@ -46,7 +46,7 @@ namespace osu.Game.Screens.Edit }); } - protected void SetRowSelected(object? item) + protected void SetSelectedRow(object? item) { foreach (var b in BackgroundFlow) { diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index eeae1bcb9a..b10959d224 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -61,13 +61,10 @@ namespace osu.Game.Screens.Edit.Timing { base.LoadComplete(); - selectedGroup.BindValueChanged(_ => - { - updateSelectedGroup(); - }, true); + selectedGroup.BindValueChanged(_ => updateSelectedGroup(), true); } - private void updateSelectedGroup() => SetRowSelected(selectedGroup.Value); + private void updateSelectedGroup() => SetSelectedRow(selectedGroup.Value); private TableColumn[] createHeaders() { diff --git a/osu.Game/Screens/Edit/Verify/IssueTable.cs b/osu.Game/Screens/Edit/Verify/IssueTable.cs index dbd007e423..ba5f98a772 100644 --- a/osu.Game/Screens/Edit/Verify/IssueTable.cs +++ b/osu.Game/Screens/Edit/Verify/IssueTable.cs @@ -77,7 +77,7 @@ namespace osu.Game.Screens.Edit.Verify selectedIssue = verify.SelectedIssue.GetBoundCopy(); selectedIssue.BindValueChanged(issue => { - SetRowSelected(issue.NewValue); + SetSelectedRow(issue.NewValue); }, true); } From 2a3b24d058eb1be089c503367bb60bfdf008319d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 14:20:54 +0900 Subject: [PATCH 2453/2686] Avoid need for implicit null casting --- osu.Game/Screens/Edit/Timing/ControlPointTable.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs index b10959d224..08b2ce8562 100644 --- a/osu.Game/Screens/Edit/Timing/ControlPointTable.cs +++ b/osu.Game/Screens/Edit/Timing/ControlPointTable.cs @@ -157,14 +157,12 @@ namespace osu.Game.Screens.Edit.Timing fill.ChildrenEnumerable = controlPoints .Where(matchFunction) .Select(createAttribute) - .Where(c => c != null) - .Select(c => c!) // arbitrary ordering to make timing points first. // probably want to explicitly define order in the future. .OrderByDescending(c => c.GetType().Name); } - private Drawable? createAttribute(ControlPoint controlPoint) + private Drawable createAttribute(ControlPoint controlPoint) { switch (controlPoint) { @@ -179,10 +177,9 @@ namespace osu.Game.Screens.Edit.Timing case SampleControlPoint sample: return new SampleRowAttribute(sample); - - default: - return null; } + + throw new ArgumentOutOfRangeException(nameof(controlPoint), $"Control point type {controlPoint.GetType()} is not supported"); } } } From b5c514a8f0eeb6da346e007d4d0a7a6e932579b2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 14:30:20 +0900 Subject: [PATCH 2454/2686] Make incoming `Channel` target non-nullable --- .../Visual/Online/TestSceneNowPlayingCommand.cs | 10 +++++----- osu.Game/Online/Chat/NowPlayingCommand.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs index 362ebd1e74..4675410164 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("Set activity", () => api.Activity.Value = new UserActivity.InLobby(null)); - AddStep("Run command", () => Add(new NowPlayingCommand())); + AddStep("Run command", () => Add(new NowPlayingCommand(new Channel()))); AddAssert("Check correct response", () => postTarget.LastMessage.Contains("is listening")); } @@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("Set activity", () => api.Activity.Value = new UserActivity.Editing(new BeatmapInfo())); - AddStep("Run command", () => Add(new NowPlayingCommand())); + AddStep("Run command", () => Add(new NowPlayingCommand(new Channel()))); AddAssert("Check correct response", () => postTarget.LastMessage.Contains("is editing")); } @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("Set activity", () => api.Activity.Value = new UserActivity.InSoloGame(new BeatmapInfo(), new RulesetInfo())); - AddStep("Run command", () => Add(new NowPlayingCommand())); + AddStep("Run command", () => Add(new NowPlayingCommand(new Channel()))); AddAssert("Check correct response", () => postTarget.LastMessage.Contains("is playing")); } @@ -70,7 +70,7 @@ namespace osu.Game.Tests.Visual.Online BeatmapInfo = { OnlineID = hasOnlineId ? 1234 : -1 } }); - AddStep("Run command", () => Add(new NowPlayingCommand())); + AddStep("Run command", () => Add(new NowPlayingCommand(new Channel()))); if (hasOnlineId) AddAssert("Check link presence", () => postTarget.LastMessage.Contains("/b/1234")); @@ -85,7 +85,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Add Hidden mod", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateMod() }); - AddStep("Run command", () => Add(new NowPlayingCommand())); + AddStep("Run command", () => Add(new NowPlayingCommand(new Channel()))); AddAssert("Check mod is present", () => postTarget.LastMessage.Contains("+HD")); } diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index 540e0b0dc1..0e39f5ac91 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -38,7 +38,7 @@ namespace osu.Game.Online.Chat /// Creates a new to post the currently-playing beatmap to a parenting . /// /// The target channel to post to. If null, the currently-selected channel will be posted to. - public NowPlayingCommand(Channel? target = null) + public NowPlayingCommand(Channel target) { this.target = target; } From 2df6ccf33e2c9b5fa80ebcde33b8c46d126622e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 14:31:54 +0900 Subject: [PATCH 2455/2686] Tidy up code --- osu.Game/Online/Chat/NowPlayingCommand.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index 0e39f5ac91..c65b06c6d8 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -68,6 +68,9 @@ namespace osu.Game.Online.Chat break; } + channelManager.PostMessage($"is {verb} {getBeatmapPart()} {getModPart()}", true, target); + Expire(); + string getBeatmapPart() { string beatmapInfoString = localisation.GetLocalisedBindableString(beatmapInfo.GetDisplayTitleRomanisable()).Value; @@ -84,23 +87,20 @@ namespace osu.Game.Online.Chat return string.Empty; } - StringBuilder modS = new StringBuilder(); + StringBuilder modsString = new StringBuilder(); foreach (var mod in selectedMods.Value.Where(mod => mod.Type == ModType.DifficultyIncrease)) { - modS.Append($"+{mod.Acronym} "); + modsString.Append($"+{mod.Acronym} "); } foreach (var mod in selectedMods.Value.Where(mod => mod.Type != ModType.DifficultyIncrease)) { - modS.Append($"-{mod.Acronym} "); + modsString.Append($"-{mod.Acronym} "); } - return modS.ToString(); + return modsString.ToString().Trim(); } - - channelManager.PostMessage($"is {verb} {getBeatmapPart()} {getModPart()}", true, target); - Expire(); } } } From b453eecebe494acdf95de02feb38536b8f78228e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 14:43:21 +0900 Subject: [PATCH 2456/2686] Ensure empty pieces do not result in whitespace between elements --- osu.Game/Online/Chat/NowPlayingCommand.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index c65b06c6d8..2734b4e6dd 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -68,7 +68,15 @@ namespace osu.Game.Online.Chat break; } - channelManager.PostMessage($"is {verb} {getBeatmapPart()} {getModPart()}", true, target); + string[] pieces = + { + "is", + verb, + getBeatmapPart(), + getModPart(), + }; + + channelManager.PostMessage(string.Join(' ', pieces.Where(p => !string.IsNullOrEmpty(p))), true, target); Expire(); string getBeatmapPart() From 8bf5d6884d33ea13c06e72ed716b0fa0a15b089a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 14:47:16 +0900 Subject: [PATCH 2457/2686] Add ruleset to now playing string --- osu.Game/Online/Chat/NowPlayingCommand.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index 2734b4e6dd..9902704883 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Online.API; +using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Users; @@ -29,6 +30,9 @@ namespace osu.Game.Online.Chat [Resolved] private Bindable> selectedMods { get; set; } = null!; + [Resolved] + private IBindable currentRuleset { get; set; } = null!; + [Resolved] private LocalisationManager localisation { get; set; } = null!; @@ -73,6 +77,7 @@ namespace osu.Game.Online.Chat "is", verb, getBeatmapPart(), + getRulesetPart(), getModPart(), }; @@ -86,6 +91,13 @@ namespace osu.Game.Online.Chat return beatmapInfo.OnlineID > 0 ? $"[{api.WebsiteRootUrl}/b/{beatmapInfo.OnlineID} {beatmapInfoString}]" : beatmapInfoString; } + string getRulesetPart() + { + if (api.Activity.Value is not UserActivity.InGame) return string.Empty; + + return $"<{currentRuleset.Value.Name}>"; + } + string getModPart() { if (api.Activity.Value is not UserActivity.InGame) return string.Empty; From b0039c9b1b4898d6bd0211f8391f62fc38a02a5a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 15:27:12 +0900 Subject: [PATCH 2458/2686] Add test coverage of incorrect system message ordering --- .../Online/TestSceneStandAloneChatDisplay.cs | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index 7d2ac90939..b858b4e355 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -73,6 +73,11 @@ namespace osu.Game.Tests.Visual.Online messageIdSequence = 0; channelManager.CurrentChannel.Value = testChannel = new Channel(); + reinitialiseDrawableDisplay(); + }); + + private void reinitialiseDrawableDisplay() + { Children = new[] { chatDisplay = new TestStandAloneChatDisplay @@ -92,7 +97,7 @@ namespace osu.Game.Tests.Visual.Online Channel = { Value = testChannel }, } }; - }); + } [Test] public void TestSystemMessageOrdering() @@ -106,14 +111,44 @@ namespace osu.Game.Tests.Visual.Online var infoMessage1 = new InfoMessage($"the system is calling {messageIdSequence++}"); var infoMessage2 = new InfoMessage($"the system is calling {messageIdSequence++}"); + var standardMessage2 = new Message(messageIdSequence++) + { + Sender = admin, + Content = "I am a wang!" + }; + AddStep("message from admin", () => testChannel.AddNewMessages(standardMessage)); AddStep("message from system", () => testChannel.AddNewMessages(infoMessage1)); AddStep("message from system", () => testChannel.AddNewMessages(infoMessage2)); + AddStep("message from admin", () => testChannel.AddNewMessages(standardMessage2)); - AddAssert("message order is correct", () => testChannel.Messages.Count == 3 - && testChannel.Messages[0] == standardMessage - && testChannel.Messages[1] == infoMessage1 - && testChannel.Messages[2] == infoMessage2); + AddAssert("count is correct", () => testChannel.Messages.Count, () => Is.EqualTo(4)); + + AddAssert("message order is correct", () => testChannel.Messages, () => Is.EqualTo(new[] + { + standardMessage, + infoMessage1, + infoMessage2, + standardMessage2 + })); + + AddAssert("displayed order is correct", () => chatDisplay.DrawableChannel.ChildrenOfType().Select(c => c.Message), () => Is.EqualTo(new[] + { + standardMessage, + infoMessage1, + infoMessage2, + standardMessage2 + })); + + AddStep("reinit drawable channel", reinitialiseDrawableDisplay); + + AddAssert("displayed order is still correct", () => chatDisplay.DrawableChannel.ChildrenOfType().Select(c => c.Message), () => Is.EqualTo(new[] + { + standardMessage, + infoMessage1, + infoMessage2, + standardMessage2 + })); } [Test] From c84f011bb7d4566fdc6a7a558a55be35687af365 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 15:36:22 +0900 Subject: [PATCH 2459/2686] Improve `ToString` output of `Message` --- osu.Game/Online/Chat/Message.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 9f6f9c8d6b..2569434df7 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -85,6 +85,6 @@ namespace osu.Game.Online.Chat // ReSharper disable once ImpureMethodCallOnReadonlyValueField public override int GetHashCode() => Id.GetHashCode(); - public override string ToString() => $"[{ChannelId}] ({Id}) {Sender}: {Content}"; + public override string ToString() => $"({(Id?.ToString() ?? "null")}) {Timestamp} {Sender}: {Content}"; } } From 9e34fe360a081853fbaf61e0021bf63ed6ba3375 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 15:46:36 +0900 Subject: [PATCH 2460/2686] Ensure all `LocalMessage`s get a timestamp --- .../Visual/Online/TestSceneStandAloneChatDisplay.cs | 2 ++ osu.Game/Online/Chat/InfoMessage.cs | 4 ---- osu.Game/Online/Chat/LocalEchoMessage.cs | 2 -- osu.Game/Online/Chat/LocalMessage.cs | 3 ++- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index b858b4e355..ebd5e12acb 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -104,6 +104,7 @@ namespace osu.Game.Tests.Visual.Online { var standardMessage = new Message(messageIdSequence++) { + Timestamp = DateTimeOffset.Now, Sender = admin, Content = "I am a wang!" }; @@ -113,6 +114,7 @@ namespace osu.Game.Tests.Visual.Online var standardMessage2 = new Message(messageIdSequence++) { + Timestamp = DateTimeOffset.Now, Sender = admin, Content = "I am a wang!" }; diff --git a/osu.Game/Online/Chat/InfoMessage.cs b/osu.Game/Online/Chat/InfoMessage.cs index d98c67de34..2ade99dcb2 100644 --- a/osu.Game/Online/Chat/InfoMessage.cs +++ b/osu.Game/Online/Chat/InfoMessage.cs @@ -1,9 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using System; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.Chat @@ -13,7 +10,6 @@ namespace osu.Game.Online.Chat public InfoMessage(string message) : base(null) { - Timestamp = DateTimeOffset.Now; Content = message; Sender = APIUser.SYSTEM_USER; diff --git a/osu.Game/Online/Chat/LocalEchoMessage.cs b/osu.Game/Online/Chat/LocalEchoMessage.cs index b226fe6cad..8a39515575 100644 --- a/osu.Game/Online/Chat/LocalEchoMessage.cs +++ b/osu.Game/Online/Chat/LocalEchoMessage.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. -#nullable disable - namespace osu.Game.Online.Chat { public class LocalEchoMessage : LocalMessage diff --git a/osu.Game/Online/Chat/LocalMessage.cs b/osu.Game/Online/Chat/LocalMessage.cs index 5736f5cabf..57caca2287 100644 --- a/osu.Game/Online/Chat/LocalMessage.cs +++ b/osu.Game/Online/Chat/LocalMessage.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable +using System; namespace osu.Game.Online.Chat { @@ -13,6 +13,7 @@ namespace osu.Game.Online.Chat protected LocalMessage(long? id) : base(id) { + Timestamp = DateTimeOffset.Now; } } } From 2d8854cbac6dbb5f86e965282321e0b8d1270197 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 15:46:58 +0900 Subject: [PATCH 2461/2686] Change message comparator to always use timestamp comparison if either message has a missing `Id` --- osu.Game/Online/Chat/Message.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 2569434df7..4c86c963b7 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -66,12 +66,10 @@ namespace osu.Game.Online.Chat public int CompareTo(Message other) { - if (!Id.HasValue) - return other.Id.HasValue ? 1 : Timestamp.CompareTo(other.Timestamp); - if (!other.Id.HasValue) - return -1; + if (Id.HasValue && other.Id.HasValue) + return Id.Value.CompareTo(other.Id.Value); - return Id.Value.CompareTo(other.Id.Value); + return Timestamp.CompareTo(other.Timestamp); } public virtual bool Equals(Message other) From 7fca5ee28dceb89f189232b51937bc541d16979a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 16:04:00 +0900 Subject: [PATCH 2462/2686] Move `DrawableUsername` into own file It's too large at this point to be a nested class. --- osu.Game/Overlays/Chat/ChatLine.cs | 206 ------------------- osu.Game/Overlays/Chat/DrawableUsername.cs | 222 +++++++++++++++++++++ 2 files changed, 222 insertions(+), 206 deletions(-) create mode 100644 osu.Game/Overlays/Chat/DrawableUsername.cs diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index e974db9fba..4d5fbaac42 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -1,7 +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 System; using System.Linq; using System.Collections.Generic; using osu.Framework.Allocation; @@ -9,23 +8,13 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -using osuTK; -using osuTK.Graphics; -using osu.Framework.Input.Events; using osu.Framework.Graphics.Sprites; -using osu.Framework.Localisation; namespace osu.Game.Overlays.Chat { @@ -190,200 +179,5 @@ namespace osu.Game.Overlays.Chat ? $@"{message.Timestamp.LocalDateTime:HH:mm:ss}" : $@"{message.Timestamp.LocalDateTime:hh:mm:ss tt}"; } - - private partial class DrawableUsername : OsuClickableContainer, IHasContextMenu - { - public new Color4 Colour { get; private set; } - - public float FontSize - { - set => drawableText.Font = OsuFont.GetFont(size: value, weight: FontWeight.Bold, italics: true); - } - - public LocalisableString Text - { - set => drawableText.Text = value; - } - - public override float Width - { - get => base.Width; - set => base.Width = drawableText.MaxWidth = value; - } - - [Resolved(canBeNull: false)] - private IAPIProvider api { get; set; } = null!; - - [Resolved(canBeNull: false)] - private OsuColour osuColours { get; set; } = null!; - - [Resolved] - private ChannelManager? chatManager { get; set; } - - [Resolved] - private ChatOverlay? chatOverlay { get; set; } - - [Resolved] - private UserProfileOverlay? profileOverlay { get; set; } - - private readonly APIUser user; - private readonly OsuSpriteText drawableText; - - private readonly Drawable colouredDrawable; - - public DrawableUsername(APIUser user) - { - this.user = user; - - Action = openUserProfile; - - drawableText = new OsuSpriteText - { - Shadow = false, - Truncate = true, - EllipsisString = "…", - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - }; - - if (string.IsNullOrWhiteSpace(user.Colour)) - { - Colour = default_colours[user.Id % default_colours.Length]; - - Child = colouredDrawable = drawableText; - } - else - { - Colour = Color4Extensions.FromHex(user.Colour); - - Child = new Container - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 4, - EdgeEffect = new EdgeEffectParameters - { - Roundness = 1, - Radius = 1, - Colour = Color4.Black.Opacity(0.3f), - Offset = new Vector2(0, 1), - Type = EdgeEffectType.Shadow, - }, - Child = new Container - { - AutoSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 4, - Children = new[] - { - colouredDrawable = new Box - { - RelativeSizeAxes = Axes.Both, - }, - new Container - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = 4, Right = 4, Bottom = 1, Top = -2 }, - Child = drawableText, - } - } - } - }; - } - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - drawableText.Colour = osuColours.ChatBlue; - colouredDrawable.Colour = Colour; - } - - public MenuItem[] ContextMenuItems - { - get - { - if (user.Equals(APIUser.SYSTEM_USER)) - return Array.Empty(); - - List items = new List - { - new OsuMenuItem("View Profile", MenuItemType.Highlighted, openUserProfile) - }; - - if (!user.Equals(api.LocalUser.Value)) - items.Add(new OsuMenuItem("Start Chat", MenuItemType.Standard, openUserChannel)); - - return items.ToArray(); - } - } - - private void openUserChannel() - { - chatManager?.OpenPrivateChannel(user); - chatOverlay?.Show(); - } - - private void openUserProfile() - { - profileOverlay?.ShowUser(user); - } - - protected override bool OnHover(HoverEvent e) - { - colouredDrawable.FadeColour(Colour.Lighten(0.4f), 150, Easing.OutQuint); - - return base.OnHover(e); - } - - protected override void OnHoverLost(HoverLostEvent e) - { - base.OnHoverLost(e); - - colouredDrawable.FadeColour(Colour, 250, Easing.OutQuint); - } - - private static readonly Color4[] default_colours = - { - Color4Extensions.FromHex("588c7e"), - Color4Extensions.FromHex("b2a367"), - Color4Extensions.FromHex("c98f65"), - Color4Extensions.FromHex("bc5151"), - Color4Extensions.FromHex("5c8bd6"), - Color4Extensions.FromHex("7f6ab7"), - Color4Extensions.FromHex("a368ad"), - Color4Extensions.FromHex("aa6880"), - - Color4Extensions.FromHex("6fad9b"), - Color4Extensions.FromHex("f2e394"), - Color4Extensions.FromHex("f2ae72"), - Color4Extensions.FromHex("f98f8a"), - Color4Extensions.FromHex("7daef4"), - Color4Extensions.FromHex("a691f2"), - Color4Extensions.FromHex("c894d3"), - Color4Extensions.FromHex("d895b0"), - - Color4Extensions.FromHex("53c4a1"), - Color4Extensions.FromHex("eace5c"), - Color4Extensions.FromHex("ea8c47"), - Color4Extensions.FromHex("fc4f4f"), - Color4Extensions.FromHex("3d94ea"), - Color4Extensions.FromHex("7760ea"), - Color4Extensions.FromHex("af52c6"), - Color4Extensions.FromHex("e25696"), - - Color4Extensions.FromHex("677c66"), - Color4Extensions.FromHex("9b8732"), - Color4Extensions.FromHex("8c5129"), - Color4Extensions.FromHex("8c3030"), - Color4Extensions.FromHex("1f5d91"), - Color4Extensions.FromHex("4335a5"), - Color4Extensions.FromHex("812a96"), - Color4Extensions.FromHex("992861"), - }; - } } } diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs new file mode 100644 index 0000000000..c8c7d38ce6 --- /dev/null +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -0,0 +1,222 @@ +// 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.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Chat; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Chat +{ + public partial class DrawableUsername : OsuClickableContainer, IHasContextMenu + { + public new Color4 Colour { get; private set; } + + public float FontSize + { + set => drawableText.Font = OsuFont.GetFont(size: value, weight: FontWeight.Bold, italics: true); + } + + public LocalisableString Text + { + set => drawableText.Text = value; + } + + public override float Width + { + get => base.Width; + set => base.Width = drawableText.MaxWidth = value; + } + + [Resolved(canBeNull: false)] + private IAPIProvider api { get; set; } = null!; + + [Resolved(canBeNull: false)] + private OsuColour osuColours { get; set; } = null!; + + [Resolved] + private ChannelManager? chatManager { get; set; } + + [Resolved] + private ChatOverlay? chatOverlay { get; set; } + + [Resolved] + private UserProfileOverlay? profileOverlay { get; set; } + + private readonly APIUser user; + private readonly OsuSpriteText drawableText; + + private readonly Drawable colouredDrawable; + + public DrawableUsername(APIUser user) + { + this.user = user; + + Action = openUserProfile; + + drawableText = new OsuSpriteText + { + Shadow = false, + Truncate = true, + EllipsisString = "…", + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }; + + if (string.IsNullOrWhiteSpace(user.Colour)) + { + Colour = default_colours[user.Id % default_colours.Length]; + + Child = colouredDrawable = drawableText; + } + else + { + Colour = Color4Extensions.FromHex(user.Colour); + + Child = new Container + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4, + EdgeEffect = new EdgeEffectParameters + { + Roundness = 1, + Radius = 1, + Colour = Color4.Black.Opacity(0.3f), + Offset = new Vector2(0, 1), + Type = EdgeEffectType.Shadow, + }, + Child = new Container + { + AutoSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 4, + Children = new[] + { + colouredDrawable = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 4, Right = 4, Bottom = 1, Top = -2 }, + Child = drawableText, + } + } + } + }; + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + drawableText.Colour = osuColours.ChatBlue; + colouredDrawable.Colour = Colour; + } + + public MenuItem[] ContextMenuItems + { + get + { + if (user.Equals(APIUser.SYSTEM_USER)) + return Array.Empty(); + + List items = new List + { + new OsuMenuItem("View Profile", MenuItemType.Highlighted, openUserProfile) + }; + + if (!user.Equals(api.LocalUser.Value)) + items.Add(new OsuMenuItem("Start Chat", MenuItemType.Standard, openUserChannel)); + + return items.ToArray(); + } + } + + private void openUserChannel() + { + chatManager?.OpenPrivateChannel(user); + chatOverlay?.Show(); + } + + private void openUserProfile() + { + profileOverlay?.ShowUser(user); + } + + protected override bool OnHover(HoverEvent e) + { + colouredDrawable.FadeColour(Colour.Lighten(0.4f), 150, Easing.OutQuint); + + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + base.OnHoverLost(e); + + colouredDrawable.FadeColour(Colour, 250, Easing.OutQuint); + } + + private static readonly Color4[] default_colours = + { + Color4Extensions.FromHex("588c7e"), + Color4Extensions.FromHex("b2a367"), + Color4Extensions.FromHex("c98f65"), + Color4Extensions.FromHex("bc5151"), + Color4Extensions.FromHex("5c8bd6"), + Color4Extensions.FromHex("7f6ab7"), + Color4Extensions.FromHex("a368ad"), + Color4Extensions.FromHex("aa6880"), + + Color4Extensions.FromHex("6fad9b"), + Color4Extensions.FromHex("f2e394"), + Color4Extensions.FromHex("f2ae72"), + Color4Extensions.FromHex("f98f8a"), + Color4Extensions.FromHex("7daef4"), + Color4Extensions.FromHex("a691f2"), + Color4Extensions.FromHex("c894d3"), + Color4Extensions.FromHex("d895b0"), + + Color4Extensions.FromHex("53c4a1"), + Color4Extensions.FromHex("eace5c"), + Color4Extensions.FromHex("ea8c47"), + Color4Extensions.FromHex("fc4f4f"), + Color4Extensions.FromHex("3d94ea"), + Color4Extensions.FromHex("7760ea"), + Color4Extensions.FromHex("af52c6"), + Color4Extensions.FromHex("e25696"), + + Color4Extensions.FromHex("677c66"), + Color4Extensions.FromHex("9b8732"), + Color4Extensions.FromHex("8c5129"), + Color4Extensions.FromHex("8c3030"), + Color4Extensions.FromHex("1f5d91"), + Color4Extensions.FromHex("4335a5"), + Color4Extensions.FromHex("812a96"), + Color4Extensions.FromHex("992861"), + }; + } +} From 80b0e4a99da48122dd4cfbc2224ab3681bda8a45 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 16:07:21 +0900 Subject: [PATCH 2463/2686] Rename `Colour` to avoid conflict with `Drawable.Colour` --- osu.Game/Overlays/Chat/ChatLine.cs | 2 +- osu.Game/Overlays/Chat/DrawableUsername.cs | 26 +++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 4d5fbaac42..2b8718939e 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -139,7 +139,7 @@ namespace osu.Game.Overlays.Chat CornerRadius = 2f, Masking = true, RelativeSizeAxes = Axes.Both, - Colour = drawableUsername.Colour.Darken(1f), + Colour = drawableUsername.AccentColour.Darken(1f), Depth = float.MaxValue, Child = new Box { RelativeSizeAxes = Axes.Both } }); diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs index c8c7d38ce6..d6dbb76f37 100644 --- a/osu.Game/Overlays/Chat/DrawableUsername.cs +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Chat { public partial class DrawableUsername : OsuClickableContainer, IHasContextMenu { - public new Color4 Colour { get; private set; } + public Color4 AccentColour { get; } public float FontSize { @@ -45,19 +45,19 @@ namespace osu.Game.Overlays.Chat set => base.Width = drawableText.MaxWidth = value; } - [Resolved(canBeNull: false)] + [Resolved] private IAPIProvider api { get; set; } = null!; - [Resolved(canBeNull: false)] - private OsuColour osuColours { get; set; } = null!; - [Resolved] + private OsuColour colours { get; set; } = null!; + + [Resolved(canBeNull: true)] private ChannelManager? chatManager { get; set; } - [Resolved] + [Resolved(canBeNull: true)] private ChatOverlay? chatOverlay { get; set; } - [Resolved] + [Resolved(canBeNull: true)] private UserProfileOverlay? profileOverlay { get; set; } private readonly APIUser user; @@ -82,13 +82,13 @@ namespace osu.Game.Overlays.Chat if (string.IsNullOrWhiteSpace(user.Colour)) { - Colour = default_colours[user.Id % default_colours.Length]; + AccentColour = default_colours[user.Id % default_colours.Length]; Child = colouredDrawable = drawableText; } else { - Colour = Color4Extensions.FromHex(user.Colour); + AccentColour = Color4Extensions.FromHex(user.Colour); Child = new Container { @@ -132,8 +132,8 @@ namespace osu.Game.Overlays.Chat { base.LoadComplete(); - drawableText.Colour = osuColours.ChatBlue; - colouredDrawable.Colour = Colour; + drawableText.Colour = colours.ChatBlue; + colouredDrawable.Colour = AccentColour; } public MenuItem[] ContextMenuItems @@ -168,7 +168,7 @@ namespace osu.Game.Overlays.Chat protected override bool OnHover(HoverEvent e) { - colouredDrawable.FadeColour(Colour.Lighten(0.4f), 150, Easing.OutQuint); + colouredDrawable.FadeColour(AccentColour.Lighten(0.4f), 150, Easing.OutQuint); return base.OnHover(e); } @@ -177,7 +177,7 @@ namespace osu.Game.Overlays.Chat { base.OnHoverLost(e); - colouredDrawable.FadeColour(Colour, 250, Easing.OutQuint); + colouredDrawable.FadeColour(AccentColour, 250, Easing.OutQuint); } private static readonly Color4[] default_colours = From 24ee363563d23cf558011b1bad1e0cacdfa17295 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 16:12:17 +0900 Subject: [PATCH 2464/2686] Only hover when hovering actual text --- osu.Game/Overlays/Chat/DrawableUsername.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs index d6dbb76f37..4a3aa6e53f 100644 --- a/osu.Game/Overlays/Chat/DrawableUsername.cs +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -29,6 +29,9 @@ namespace osu.Game.Overlays.Chat { public Color4 AccentColour { get; } + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + Child.ReceivePositionalInputAt(screenSpacePos); + public float FontSize { set => drawableText.Font = OsuFont.GetFont(size: value, weight: FontWeight.Bold, italics: true); From f7b7b58718fbff59fdb39a382f5a1c06374245ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 16:20:01 +0900 Subject: [PATCH 2465/2686] Adjust colour and tween to feel better --- osu.Game/Overlays/Chat/DrawableUsername.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs index 4a3aa6e53f..7026d519a5 100644 --- a/osu.Game/Overlays/Chat/DrawableUsername.cs +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -171,7 +171,7 @@ namespace osu.Game.Overlays.Chat protected override bool OnHover(HoverEvent e) { - colouredDrawable.FadeColour(AccentColour.Lighten(0.4f), 150, Easing.OutQuint); + colouredDrawable.FadeColour(AccentColour.Lighten(0.6f), 30, Easing.OutQuint); return base.OnHover(e); } @@ -180,7 +180,7 @@ namespace osu.Game.Overlays.Chat { base.OnHoverLost(e); - colouredDrawable.FadeColour(AccentColour, 250, Easing.OutQuint); + colouredDrawable.FadeColour(AccentColour, 800, Easing.OutQuint); } private static readonly Color4[] default_colours = From b1ce93e7bff368d6852d4cc914b79ee43b574ed9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 16:55:39 +0900 Subject: [PATCH 2466/2686] Add fallback stable sort to avoid any change of misordered local messages --- osu.Game/Online/Chat/Message.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 4c86c963b7..8ea3ca0fc7 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Threading; using Newtonsoft.Json; using osu.Game.Online.API.Requests.Responses; @@ -59,9 +60,14 @@ namespace osu.Game.Online.Chat /// The s' and s are according to public List Links; + private static long constructionOrderStatic; + private readonly long constructionOrder; + public Message(long? id) { Id = id; + + constructionOrder = Interlocked.Increment(ref constructionOrderStatic); } public int CompareTo(Message other) @@ -69,7 +75,13 @@ namespace osu.Game.Online.Chat if (Id.HasValue && other.Id.HasValue) return Id.Value.CompareTo(other.Id.Value); - return Timestamp.CompareTo(other.Timestamp); + int timestampComparison = Timestamp.CompareTo(other.Timestamp); + + if (timestampComparison != 0) + return timestampComparison; + + // Timestamp might not be accurate enough to make a stable sorting decision. + return constructionOrder.CompareTo(other.constructionOrder); } public virtual bool Equals(Message other) From c4b88e4e5a53b09ce62921c57a039cc8de5cdcf2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 17:07:57 +0900 Subject: [PATCH 2467/2686] Fix flaky test conditions in `TestSceneReplayDownloadButton` --- .../Gameplay/TestSceneReplayDownloadButton.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs index c473278fdc..6ccf73d8ff 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayDownloadButton.cs @@ -107,7 +107,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for load", () => downloadButton.IsLoaded); - AddAssert("state is available", () => downloadButton.State.Value == DownloadState.NotDownloaded); + checkState(DownloadState.NotDownloaded); AddStep("click button", () => { @@ -133,7 +133,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for load", () => downloadButton.IsLoaded); - AddAssert("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded); + checkState(DownloadState.NotDownloaded); AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType().First().Enabled.Value); } @@ -155,7 +155,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for load", () => downloadButton.IsLoaded); - AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded); + checkState(DownloadState.NotDownloaded); AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType().First().Enabled.Value); } @@ -174,17 +174,16 @@ namespace osu.Game.Tests.Visual.Gameplay }); AddUntilStep("wait for load", () => downloadButton.IsLoaded); - - AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded); + checkState(DownloadState.NotDownloaded); AddStep("import score", () => imported = scoreManager.Import(getScoreInfo(true))); - AddUntilStep("state is available", () => downloadButton.State.Value == DownloadState.LocallyAvailable); + checkState(DownloadState.LocallyAvailable); AddAssert("button is enabled", () => downloadButton.ChildrenOfType().First().Enabled.Value); AddStep("delete score", () => scoreManager.Delete(imported.Value)); - AddUntilStep("state is not downloaded", () => downloadButton.State.Value == DownloadState.NotDownloaded); + checkState(DownloadState.NotDownloaded); AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType().First().Enabled.Value); } @@ -202,10 +201,13 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for load", () => downloadButton.IsLoaded); - AddAssert("state is unknown", () => downloadButton.State.Value == DownloadState.Unknown); + checkState(DownloadState.Unknown); AddAssert("button is not enabled", () => !downloadButton.ChildrenOfType().First().Enabled.Value); } + private void checkState(DownloadState expectedState) => + AddUntilStep($"state is {expectedState}", () => downloadButton.State.Value, () => Is.EqualTo(expectedState)); + private ScoreInfo getScoreInfo(bool replayAvailable, bool hasOnlineId = true) => new ScoreInfo { OnlineID = hasOnlineId ? online_score_id : 0, From 1bb32ec24d73681c74690451ce2a513169ec8289 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 17:35:50 +0900 Subject: [PATCH 2468/2686] Attempt to fix flaky `TestHoldForMenuDoesWorkWhenHidden` Seems like the most likely cause. --- osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 94f9b4262d..29fadd151f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -187,18 +188,22 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestInputDoesntWorkWhenHUDHidden() { - SongProgressBar getSongProgress() => hudOverlay.ChildrenOfType().Single(); + SongProgressBar? getSongProgress() => hudOverlay.ChildrenOfType().SingleOrDefault(); bool seeked = false; createNew(); + AddUntilStep("wait for song progress", () => getSongProgress() != null); + AddStep("bind seek", () => { seeked = false; var progress = getSongProgress(); + Debug.Assert(progress != null); + progress.ShowHandle = true; progress.OnSeek += _ => seeked = true; }); From bb0237d4a96a75e17034c5309b0e25269977896e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 17:49:08 +0900 Subject: [PATCH 2469/2686] Fix nullability inspection on disposal path --- .../UI/DrawableRulesetDependenciesProvidingContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs b/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs index 1efe72fdf3..6c213497dd 100644 --- a/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs +++ b/osu.Game/Rulesets/UI/DrawableRulesetDependenciesProvidingContainer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -28,7 +29,8 @@ namespace osu.Game.Rulesets.UI { base.Dispose(isDisposing); - rulesetDependencies?.Dispose(); + if (rulesetDependencies.IsNotNull()) + rulesetDependencies.Dispose(); } } } From 5ce2d6f54a78235bff651cfabce5152207724d81 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 30 Nov 2022 18:13:53 +0900 Subject: [PATCH 2470/2686] Hide the game mouse cursor when playing osu!catch with relax mod --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 12 ++++++++++++ .../UI/CatchRelaxCursorContainer.cs | 15 +++++++++++++++ osu.Game/Rulesets/UI/Playfield.cs | 10 +++++----- 3 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/UI/CatchRelaxCursorContainer.cs diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 4df297565e..cd8caa43b8 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -3,15 +3,19 @@ #nullable disable +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.UI { @@ -49,6 +53,14 @@ namespace osu.Game.Rulesets.Catch.UI this.difficulty = difficulty; } + protected override GameplayCursorContainer CreateCursor() + { + if (Mods.Any(m => m is ModRelax)) + return new CatchRelaxCursorContainer(); + + return base.CreateCursor(); + } + [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game.Rulesets.Catch/UI/CatchRelaxCursorContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchRelaxCursorContainer.cs new file mode 100644 index 0000000000..f30b8f0f36 --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/CatchRelaxCursorContainer.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.Framework.Graphics; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Catch.UI +{ + public partial class CatchRelaxCursorContainer : GameplayCursorContainer + { + // Just hide the cursor in relax. + // The main goal here is to show that we have a cursor so the game never shows the global one. + protected override Drawable CreateCursor() => Empty(); + } +} diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index 859be6e210..abb057f9af 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -93,7 +93,7 @@ namespace osu.Game.Rulesets.UI public readonly BindableBool DisplayJudgements = new BindableBool(true); [Resolved(CanBeNull = true)] - private IReadOnlyList mods { get; set; } + protected IReadOnlyList Mods { get; private set; } private readonly HitObjectEntryManager entryManager = new HitObjectEntryManager(); @@ -243,9 +243,9 @@ namespace osu.Game.Rulesets.UI { base.Update(); - if (!IsNested && mods != null) + if (!IsNested && Mods != null) { - foreach (var mod in mods) + foreach (var mod in Mods) { if (mod is IUpdatableByPlayfield updatable) updatable.Update(this); @@ -374,9 +374,9 @@ namespace osu.Game.Rulesets.UI // If this is the first time this DHO is being used, then apply the DHO mods. // This is done before Apply() so that the state is updated once when the hitobject is applied. - if (mods != null) + if (Mods != null) { - foreach (var m in mods.OfType()) + foreach (var m in Mods.OfType()) m.ApplyToDrawableHitObject(dho); } } From f5d85f5774a8de446420434a0d931c5c4f724dd8 Mon Sep 17 00:00:00 2001 From: Piggey Date: Wed, 30 Nov 2022 10:51:42 +0100 Subject: [PATCH 2471/2686] make `ExportStorage` protected --- osu.Game/Database/LegacyExporter.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 16d7441dde..9f440f3728 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -23,11 +23,11 @@ namespace osu.Game.Database protected readonly Storage UserFileStorage; - private readonly Storage exportStorage; + protected readonly Storage ExportStorage; protected LegacyExporter(Storage storage) { - exportStorage = storage.GetStorageForDirectory(@"exports"); + ExportStorage = storage.GetStorageForDirectory(@"exports"); UserFileStorage = storage.GetStorageForDirectory(@"files"); } @@ -35,14 +35,14 @@ namespace osu.Game.Database /// Exports an item to a legacy (.zip based) package. /// /// The item to export. - public void Export(TModel item) + public virtual void Export(TModel item) { string filename = $"{item.GetDisplayString().GetValidFilename()}{FileExtension}"; - using (var stream = exportStorage.CreateFileSafely(filename)) + using (var stream = ExportStorage.CreateFileSafely(filename)) ExportModelTo(item, stream); - exportStorage.PresentFileExternally(filename); + ExportStorage.PresentFileExternally(filename); } /// From 5e74c4e3b7cbf96e7c635bd05739166835f71ce3 Mon Sep 17 00:00:00 2001 From: Piggey Date: Wed, 30 Nov 2022 10:52:41 +0100 Subject: [PATCH 2472/2686] override `LegacyScoreExporter.Export()` to not overwrite files --- osu.Game/Database/LegacyScoreExporter.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs index 6fa02b957d..76828ad102 100644 --- a/osu.Game/Database/LegacyScoreExporter.cs +++ b/osu.Game/Database/LegacyScoreExporter.cs @@ -8,6 +8,7 @@ using System.Linq; using osu.Framework.Platform; using osu.Game.Extensions; using osu.Game.Scoring; +using osu.Game.Utils; namespace osu.Game.Database { @@ -29,5 +30,22 @@ namespace osu.Game.Database using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath())) inputStream.CopyTo(outputStream); } + + public override void Export(ScoreInfo item) + { + var itemFilename = item.GetDisplayString().GetValidFilename(); + + var existingExports = ExportStorage.GetFiles("", $"{itemFilename}*{FileExtension}").ToArray(); + + // trim the file extension + for (int i = 0; i < existingExports.Length; i++) + existingExports[i] = existingExports[i].TrimEnd(FileExtension.ToCharArray()); + + string filename = $"{NamingUtils.GetNextBestName(existingExports, itemFilename)}{FileExtension}"; + using (var stream = ExportStorage.CreateFileSafely(filename)) + ExportModelTo(item, stream); + + ExportStorage.PresentFileExternally(filename); + } } } From 660ad913ec54db3f6192e0e10bd69dca6dc7f049 Mon Sep 17 00:00:00 2001 From: Piggey Date: Wed, 30 Nov 2022 11:06:44 +0100 Subject: [PATCH 2473/2686] oh wait this affects all of the legacy exporters --- osu.Game/Database/LegacyExporter.cs | 21 +++++++++++++++------ osu.Game/Database/LegacyScoreExporter.cs | 18 ------------------ 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 9f440f3728..430505e855 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -4,8 +4,10 @@ #nullable disable using System.IO; +using System.Linq; using osu.Framework.Platform; using osu.Game.Extensions; +using osu.Game.Utils; using SharpCompress.Archives.Zip; namespace osu.Game.Database @@ -23,11 +25,11 @@ namespace osu.Game.Database protected readonly Storage UserFileStorage; - protected readonly Storage ExportStorage; + private readonly Storage exportStorage; protected LegacyExporter(Storage storage) { - ExportStorage = storage.GetStorageForDirectory(@"exports"); + exportStorage = storage.GetStorageForDirectory(@"exports"); UserFileStorage = storage.GetStorageForDirectory(@"files"); } @@ -35,14 +37,21 @@ namespace osu.Game.Database /// Exports an item to a legacy (.zip based) package. /// /// The item to export. - public virtual void Export(TModel item) + public void Export(TModel item) { - string filename = $"{item.GetDisplayString().GetValidFilename()}{FileExtension}"; + var itemFilename = item.GetDisplayString().GetValidFilename(); - using (var stream = ExportStorage.CreateFileSafely(filename)) + var existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}").ToArray(); + + // trim the file extension + for (int i = 0; i < existingExports.Length; i++) + existingExports[i] = existingExports[i].TrimEnd(FileExtension.ToCharArray()); + + string filename = $"{NamingUtils.GetNextBestName(existingExports, itemFilename)}{FileExtension}"; + using (var stream = exportStorage.CreateFileSafely(filename)) ExportModelTo(item, stream); - ExportStorage.PresentFileExternally(filename); + exportStorage.PresentFileExternally(filename); } /// diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs index 76828ad102..6fa02b957d 100644 --- a/osu.Game/Database/LegacyScoreExporter.cs +++ b/osu.Game/Database/LegacyScoreExporter.cs @@ -8,7 +8,6 @@ using System.Linq; using osu.Framework.Platform; using osu.Game.Extensions; using osu.Game.Scoring; -using osu.Game.Utils; namespace osu.Game.Database { @@ -30,22 +29,5 @@ namespace osu.Game.Database using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath())) inputStream.CopyTo(outputStream); } - - public override void Export(ScoreInfo item) - { - var itemFilename = item.GetDisplayString().GetValidFilename(); - - var existingExports = ExportStorage.GetFiles("", $"{itemFilename}*{FileExtension}").ToArray(); - - // trim the file extension - for (int i = 0; i < existingExports.Length; i++) - existingExports[i] = existingExports[i].TrimEnd(FileExtension.ToCharArray()); - - string filename = $"{NamingUtils.GetNextBestName(existingExports, itemFilename)}{FileExtension}"; - using (var stream = ExportStorage.CreateFileSafely(filename)) - ExportModelTo(item, stream); - - ExportStorage.PresentFileExternally(filename); - } } } From 6a61e7076628ac7ffddc860c75c0ff352e6d14ee Mon Sep 17 00:00:00 2001 From: Derrick Timmermans Date: Wed, 30 Nov 2022 12:17:58 +0100 Subject: [PATCH 2474/2686] Expose Ruleset from HitObjectComposer instead --- .../Edit/CatchBlueprintContainer.cs | 4 ++-- .../Edit/CatchHitObjectComposer.cs | 2 +- .../Editor/TestSceneManiaBeatSnapGrid.cs | 1 + .../Edit/ManiaBlueprintContainer.cs | 4 ++-- .../Edit/ManiaHitObjectComposer.cs | 2 +- osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs | 4 ++-- osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs | 2 +- .../Edit/TaikoBlueprintContainer.cs | 4 ++-- .../Edit/TaikoHitObjectComposer.cs | 2 +- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 11 ++++++----- .../Compose/Components/ComposeBlueprintContainer.cs | 8 ++------ 11 files changed, 21 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs index da45e952ab..9408a9f95c 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchBlueprintContainer.cs @@ -13,8 +13,8 @@ namespace osu.Game.Rulesets.Catch.Edit { public partial class CatchBlueprintContainer : ComposeBlueprintContainer { - public CatchBlueprintContainer(CatchHitObjectComposer composer, Ruleset ruleset) - : base(composer, ruleset) + public CatchBlueprintContainer(CatchHitObjectComposer composer) + : base(composer) { } diff --git a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs index fec678a4b6..bbdffbf39c 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchHitObjectComposer.cs @@ -148,7 +148,7 @@ namespace osu.Game.Rulesets.Catch.Edit return result; } - protected override ComposeBlueprintContainer CreateBlueprintContainer() => new CatchBlueprintContainer(this, Ruleset); + protected override ComposeBlueprintContainer CreateBlueprintContainer() => new CatchBlueprintContainer(this); [CanBeNull] private PalpableCatchHitObject getLastSnappableHitObject(double time) diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs index 653c75baac..aca555552f 100644 --- a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaBeatSnapGrid.cs @@ -90,6 +90,7 @@ namespace osu.Game.Rulesets.Mania.Tests.Editor public override bool CursorInPlacementArea => false; public TestHitObjectComposer(Playfield playfield) + : base(new ManiaRuleset()) { Playfield = playfield; } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs index 060073889d..05d8ccc73f 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs @@ -13,8 +13,8 @@ namespace osu.Game.Rulesets.Mania.Edit { public partial class ManiaBlueprintContainer : ComposeBlueprintContainer { - public ManiaBlueprintContainer(HitObjectComposer composer, Ruleset ruleset) - : base(composer, ruleset) + public ManiaBlueprintContainer(HitObjectComposer composer) + : base(composer) { } diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs index ff59131c8a..5e577a2964 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs @@ -68,7 +68,7 @@ namespace osu.Game.Rulesets.Mania.Edit } protected override ComposeBlueprintContainer CreateBlueprintContainer() - => new ManiaBlueprintContainer(this, Ruleset); + => new ManiaBlueprintContainer(this); protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[] { diff --git a/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs index 58bae7e2b2..173a664902 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs @@ -15,8 +15,8 @@ namespace osu.Game.Rulesets.Osu.Edit { public partial class OsuBlueprintContainer : ComposeBlueprintContainer { - public OsuBlueprintContainer(HitObjectComposer composer, Ruleset ruleset) - : base(composer, ruleset) + public OsuBlueprintContainer(HitObjectComposer composer) + : base(composer) { } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs index cf22059133..09ddc420a7 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Edit } protected override ComposeBlueprintContainer CreateBlueprintContainer() - => new OsuBlueprintContainer(this, Ruleset); + => new OsuBlueprintContainer(this); public override string ConvertSelectionToString() => string.Join(',', selectedHitObjects.Cast().OrderBy(h => h.StartTime).Select(h => (h.IndexInCurrentCombo + 1).ToString())); diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs index 0081f89b7c..6be22f3af0 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoBlueprintContainer.cs @@ -12,8 +12,8 @@ namespace osu.Game.Rulesets.Taiko.Edit { public partial class TaikoBlueprintContainer : ComposeBlueprintContainer { - public TaikoBlueprintContainer(HitObjectComposer composer, Ruleset ruleset) - : base(composer, ruleset) + public TaikoBlueprintContainer(HitObjectComposer composer) + : base(composer) { } diff --git a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs index 4109bc4887..cff5731181 100644 --- a/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs +++ b/osu.Game.Rulesets.Taiko/Edit/TaikoHitObjectComposer.cs @@ -24,6 +24,6 @@ namespace osu.Game.Rulesets.Taiko.Edit }; protected override ComposeBlueprintContainer CreateBlueprintContainer() - => new TaikoBlueprintContainer(this, Ruleset); + => new TaikoBlueprintContainer(this); } } diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index 8279150aa8..b5b7400f64 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -45,8 +45,6 @@ namespace osu.Game.Rulesets.Edit { protected IRulesetConfigManager Config { get; private set; } - protected readonly Ruleset Ruleset; - // Provides `Playfield` private DependencyContainer dependencies; @@ -74,8 +72,8 @@ namespace osu.Game.Rulesets.Edit private IBindable hasTiming; protected HitObjectComposer(Ruleset ruleset) + : base(ruleset) { - Ruleset = ruleset; } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) => @@ -218,7 +216,7 @@ namespace osu.Game.Rulesets.Edit /// /// Construct a relevant blueprint container. This will manage hitobject selection/placement input handling and display logic. /// - protected virtual ComposeBlueprintContainer CreateBlueprintContainer() => new ComposeBlueprintContainer(this, Ruleset); + protected virtual ComposeBlueprintContainer CreateBlueprintContainer() => new ComposeBlueprintContainer(this); /// /// Construct a drawable ruleset for the provided ruleset. @@ -419,8 +417,11 @@ namespace osu.Game.Rulesets.Edit [Cached] public abstract partial class HitObjectComposer : CompositeDrawable, IPositionSnapProvider { - protected HitObjectComposer() + public readonly Ruleset Ruleset; + + protected HitObjectComposer(Ruleset ruleset) { + Ruleset = ruleset; RelativeSizeAxes = Axes.Both; } diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index fc23f1d1b4..cf38cd7261 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -15,7 +15,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Game.Audio; using osu.Game.Graphics.UserInterface; -using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects; @@ -39,7 +38,6 @@ namespace osu.Game.Screens.Edit.Compose.Components private PlacementBlueprint currentPlacement; - private readonly Ruleset ruleset; /// /// Positional input must be received outside the container's bounds, @@ -47,11 +45,9 @@ namespace osu.Game.Screens.Edit.Compose.Components /// public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; - public ComposeBlueprintContainer(HitObjectComposer composer, Ruleset ruleset) + public ComposeBlueprintContainer(HitObjectComposer composer) : base(composer) { - this.ruleset = ruleset; - placementBlueprintContainer = new Container { RelativeSizeAxes = Axes.Both @@ -63,7 +59,7 @@ namespace osu.Game.Screens.Edit.Compose.Components { TernaryStates = CreateTernaryButtons().ToArray(); - AddInternal(new DrawableRulesetDependenciesProvidingContainer(ruleset) + AddInternal(new DrawableRulesetDependenciesProvidingContainer(Composer.Ruleset) { Child = placementBlueprintContainer }); From 5c8fce1c087cf7ecc8cf642dd8011b3708d15cb5 Mon Sep 17 00:00:00 2001 From: Derrick Timmermans Date: Wed, 30 Nov 2022 13:05:14 +0100 Subject: [PATCH 2475/2686] Remove extra blank line --- .../Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index cf38cd7261..713625c15f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -38,7 +38,6 @@ namespace osu.Game.Screens.Edit.Compose.Components private PlacementBlueprint currentPlacement; - /// /// Positional input must be received outside the container's bounds, /// in order to handle composer blueprints which are partially offscreen. From b99ddc2acf47f65e2c0c25290dbff44d0d06ec13 Mon Sep 17 00:00:00 2001 From: Piggey Date: Wed, 30 Nov 2022 15:36:08 +0100 Subject: [PATCH 2476/2686] use `.Select()` to trim the file extension from filename --- osu.Game/Database/LegacyExporter.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 430505e855..4b65e26145 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -3,6 +3,7 @@ #nullable disable +using System.Collections.Generic; using System.IO; using System.Linq; using osu.Framework.Platform; @@ -39,13 +40,11 @@ namespace osu.Game.Database /// The item to export. public void Export(TModel item) { - var itemFilename = item.GetDisplayString().GetValidFilename(); + string itemFilename = item.GetDisplayString().GetValidFilename(); - var existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}").ToArray(); - - // trim the file extension - for (int i = 0; i < existingExports.Length; i++) - existingExports[i] = existingExports[i].TrimEnd(FileExtension.ToCharArray()); + IEnumerable existingExports = exportStorage + .GetFiles("", $"{itemFilename}*{FileExtension}") + .Select(export => export.Substring(0, export.Length - FileExtension.Length)); string filename = $"{NamingUtils.GetNextBestName(existingExports, itemFilename)}{FileExtension}"; using (var stream = exportStorage.CreateFileSafely(filename)) From 8412a441796b5d8bbea63b9a45b5a727084ab725 Mon Sep 17 00:00:00 2001 From: Piggey Date: Wed, 30 Nov 2022 18:32:14 +0100 Subject: [PATCH 2477/2686] create `NamingUtils.GetNextBestFilename()` --- osu.Game/Utils/NamingUtils.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game/Utils/NamingUtils.cs b/osu.Game/Utils/NamingUtils.cs index 482e3d0954..ca4667b82a 100644 --- a/osu.Game/Utils/NamingUtils.cs +++ b/osu.Game/Utils/NamingUtils.cs @@ -1,7 +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; using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; namespace osu.Game.Utils @@ -57,5 +59,19 @@ namespace osu.Game.Utils ? desiredName : $"{desiredName} ({bestNumber})"; } + + /// + /// Given a set of and a desired target + /// finds a filename closest to that is not in + /// + /// SHOULD NOT CONTAIN the file extension. + /// + /// + public static string GetNextBestFilename(IEnumerable existingFilenames, string desiredName, string fileExtension) + { + var stripped = existingFilenames.Select(filename => filename.Substring(0, filename.Length - fileExtension.Length)); + + return $"{GetNextBestName(stripped, desiredName)}{fileExtension}"; + } } } From 8b856f1c89d9f45d566984e0b4c5319f18ddd346 Mon Sep 17 00:00:00 2001 From: Piggey Date: Wed, 30 Nov 2022 18:32:53 +0100 Subject: [PATCH 2478/2686] make `LegacyExporter` use `NamingUtils.GetNextBestFilename()` --- osu.Game/Database/LegacyExporter.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 4b65e26145..e9789ca777 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -3,9 +3,9 @@ #nullable disable +using System; using System.Collections.Generic; using System.IO; -using System.Linq; using osu.Framework.Platform; using osu.Game.Extensions; using osu.Game.Utils; @@ -42,11 +42,9 @@ namespace osu.Game.Database { string itemFilename = item.GetDisplayString().GetValidFilename(); - IEnumerable existingExports = exportStorage - .GetFiles("", $"{itemFilename}*{FileExtension}") - .Select(export => export.Substring(0, export.Length - FileExtension.Length)); + IEnumerable existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}"); - string filename = $"{NamingUtils.GetNextBestName(existingExports, itemFilename)}{FileExtension}"; + string filename = NamingUtils.GetNextBestFilename(existingExports, itemFilename, FileExtension); using (var stream = exportStorage.CreateFileSafely(filename)) ExportModelTo(item, stream); From 8f59aad91c77982d7f99dbf81036bfd2601efa9b Mon Sep 17 00:00:00 2001 From: Piggey Date: Wed, 30 Nov 2022 18:37:50 +0100 Subject: [PATCH 2479/2686] unnecessary includes --- osu.Game/Database/LegacyExporter.cs | 1 - osu.Game/Utils/NamingUtils.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index e9789ca777..0a5f787469 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -3,7 +3,6 @@ #nullable disable -using System; using System.Collections.Generic; using System.IO; using osu.Framework.Platform; diff --git a/osu.Game/Utils/NamingUtils.cs b/osu.Game/Utils/NamingUtils.cs index ca4667b82a..2439d4ba22 100644 --- a/osu.Game/Utils/NamingUtils.cs +++ b/osu.Game/Utils/NamingUtils.cs @@ -1,7 +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 System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; From f9a9ab1d9be3f74a2f90cea0ba8176260d775d7a Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Wed, 30 Nov 2022 19:50:47 +0100 Subject: [PATCH 2480/2686] Use BeatSyncedContainer and adjust values to be in line with stable --- .../Skinning/Legacy/LegacyKiaiGlow.cs | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs index 07eb052b20..955deb7f3a 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs @@ -2,10 +2,11 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Audio.Track; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Graphics.Containers; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; @@ -13,8 +14,10 @@ using osuTK; namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { - internal partial class LegacyKiaiGlow : Container + internal partial class LegacyKiaiGlow : BeatSyncedContainer { + private const float colour_compensation = 1.58f; + public LegacyKiaiGlow() { AlwaysPresent = true; @@ -29,13 +32,11 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy Texture = skin.GetTexture("taiko-glow"), Origin = Anchor.Centre, Anchor = Anchor.Centre, - Scale = new Vector2(0.75f), + Scale = new Vector2(0.7f), + Colour = new Colour4(255, 228, 0, 255), }; } - [Resolved(CanBeNull = true)] - private IBeatSyncProvider? beatSyncProvider { get; set; } - [Resolved(CanBeNull = true)] private HealthProcessor? healthProcessor { get; set; } @@ -45,14 +46,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy if (healthProcessor != null) healthProcessor.NewJudgement += onNewJudgement; - - if (beatSyncProvider != null) - { - if (beatSyncProvider.CheckIsKiaiTime()) - this.FadeIn(180); - else - this.FadeOut(180); - } } private void onNewJudgement(JudgementResult result) @@ -60,8 +53,16 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy if (!result.IsHit) return; - this.ScaleTo(1.1f, 50) - .Then().ScaleTo(1f, 50); + this.ScaleTo(1.2f) + .Then().ScaleTo(1f, 80, Easing.OutQuad); + } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + if (effectPoint.KiaiMode) + this.FadeTo(colour_compensation, 180); + else + this.FadeOut(180); } } } From 6ebde9a7473c3e93a3eee67bb844cbad1f5c0eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 30 Nov 2022 20:00:25 +0100 Subject: [PATCH 2481/2686] Annotate `Playfield.Mods` as maybe-null --- osu.Game/Rulesets/UI/Playfield.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Rulesets/UI/Playfield.cs b/osu.Game/Rulesets/UI/Playfield.cs index abb057f9af..a7881678f1 100644 --- a/osu.Game/Rulesets/UI/Playfield.cs +++ b/osu.Game/Rulesets/UI/Playfield.cs @@ -93,6 +93,7 @@ namespace osu.Game.Rulesets.UI public readonly BindableBool DisplayJudgements = new BindableBool(true); [Resolved(CanBeNull = true)] + [CanBeNull] protected IReadOnlyList Mods { get; private set; } private readonly HitObjectEntryManager entryManager = new HitObjectEntryManager(); From 285248d55412c9c26ff3648499c64d455dffc7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 30 Nov 2022 20:01:11 +0100 Subject: [PATCH 2482/2686] Fix potential null dereference in `CatchPlayfield` --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index cd8caa43b8..3df63bbe30 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -55,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override GameplayCursorContainer CreateCursor() { - if (Mods.Any(m => m is ModRelax)) + if (Mods != null && Mods.Any(m => m is ModRelax)) return new CatchRelaxCursorContainer(); return base.CreateCursor(); From 7f68fe429f7f3fb5c1d533d9f8731cada420d42f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 30 Nov 2022 20:01:59 +0100 Subject: [PATCH 2483/2686] Remove unused using directive --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 3df63bbe30..184ff38cc6 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -15,7 +15,6 @@ using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.UI { From 77e282ada9522547b887ee18d386dadebbfa2bf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 30 Nov 2022 20:14:35 +0100 Subject: [PATCH 2484/2686] Add test coverage for catch relax mod hiding cursor --- .../Mods/TestSceneCatchModRelax.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs index 8472b995e8..5835ccaf78 100644 --- a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs +++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModRelax.cs @@ -4,8 +4,10 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Graphics.Cursor; using osu.Game.Rulesets.Catch.Mods; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.UI; @@ -55,6 +57,21 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods } }); + [Test] + public void TestGameCursorHidden() + { + CreateModTest(new ModTestData + { + Mod = new CatchModRelax(), + Autoplay = false, + PassCondition = () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + return this.ChildrenOfType().Single().State.Value == Visibility.Hidden; + } + }); + } + private bool passCondition() { var playfield = this.ChildrenOfType().Single(); From 830e243d12719f2887ab1b67a3601aaed5186275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 30 Nov 2022 22:53:56 +0100 Subject: [PATCH 2485/2686] Add test coverage for failure case --- .../Gameplay/TestSceneDrawableHitObject.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs index 62863524fe..04fc4cafbd 100644 --- a/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs +++ b/osu.Game.Tests/Gameplay/TestSceneDrawableHitObject.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Scoring; @@ -137,6 +138,31 @@ namespace osu.Game.Tests.Gameplay AddAssert("DHO state is correct", () => dho.State.Value == ArmedState.Miss); } + [Test] + public void TestResultSetBeforeLoadComplete() + { + TestDrawableHitObject dho = null; + HitObjectLifetimeEntry lifetimeEntry = null; + AddStep("Create lifetime entry", () => + { + var hitObject = new HitObject { StartTime = Time.Current }; + lifetimeEntry = new HitObjectLifetimeEntry(hitObject) + { + Result = new JudgementResult(hitObject, hitObject.CreateJudgement()) + { + Type = HitResult.Great + } + }; + }); + AddStep("Create DHO and apply entry", () => + { + dho = new TestDrawableHitObject(); + dho.Apply(lifetimeEntry); + Child = dho; + }); + AddAssert("DHO state is correct", () => dho.State.Value, () => Is.EqualTo(ArmedState.Hit)); + } + private partial class TestDrawableHitObject : DrawableHitObject { public const double INITIAL_LIFETIME_OFFSET = 100; From 2e19e93036baf5ccd2ee73fa5cf824fa08ad36a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 30 Nov 2022 22:54:14 +0100 Subject: [PATCH 2486/2686] Rename method --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 4b074f00aa..096132d024 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -199,7 +199,7 @@ namespace osu.Game.Rulesets.Objects.Drawables comboColourBrightness.BindValueChanged(_ => UpdateComboColour()); // Apply transforms - updateStateBasedOnResults(); + updateStateFromResult(); } /// @@ -266,7 +266,7 @@ namespace osu.Game.Rulesets.Objects.Drawables // If not loaded, the state update happens in LoadComplete(). if (IsLoaded) { - updateStateBasedOnResults(); + updateStateFromResult(); // Combo colour may have been applied via a bindable flow while no object entry was attached. // Update here to ensure we're in a good state. @@ -274,7 +274,7 @@ namespace osu.Game.Rulesets.Objects.Drawables } } - private void updateStateBasedOnResults() + private void updateStateFromResult() { if (Result.IsHit) updateState(ArmedState.Hit, true); From bbf023cf682b95fb6bd00bff8bc5800163b78a3d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Dec 2022 16:08:14 +0900 Subject: [PATCH 2487/2686] Fix incorrect culture used when parsing timeline popup textbox content --- .../Timing/IndeterminateSliderWithTextBoxInput.cs | 15 ++++++++++++++- .../Screens/Edit/Timing/SliderWithTextBoxInput.cs | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs b/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs index 36186353f8..64713c7714 100644 --- a/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs +++ b/osu.Game/Screens/Edit/Timing/IndeterminateSliderWithTextBoxInput.cs @@ -94,7 +94,20 @@ namespace osu.Game.Screens.Edit.Timing try { - slider.Current.Parse(t.Text); + switch (slider.Current) + { + case Bindable bindableInt: + bindableInt.Value = int.Parse(t.Text); + break; + + case Bindable bindableDouble: + bindableDouble.Value = double.Parse(t.Text); + break; + + default: + slider.Current.Parse(t.Text); + break; + } } catch { diff --git a/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs b/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs index e1a5c3b23c..65c5128438 100644 --- a/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs +++ b/osu.Game/Screens/Edit/Timing/SliderWithTextBoxInput.cs @@ -58,7 +58,20 @@ namespace osu.Game.Screens.Edit.Timing try { - slider.Current.Parse(t.Text); + switch (slider.Current) + { + case Bindable bindableInt: + bindableInt.Value = int.Parse(t.Text); + break; + + case Bindable bindableDouble: + bindableDouble.Value = double.Parse(t.Text); + break; + + default: + slider.Current.Parse(t.Text); + break; + } } catch { From f34a79b1a9a986615f691130f5ed3c057e98d1e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Dec 2022 17:03:53 +0900 Subject: [PATCH 2488/2686] Set a better default colour for timeline blueprints when no colour information is available --- .../Compose/Components/Timeline/TimelineHitObjectBlueprint.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs index 3e49c31b1e..d089b1e744 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs @@ -165,7 +165,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline break; default: - return; + colour = Color4.Gray; + break; } if (IsSelected) From 896f2d8f74041d279dca91bb9dbe8b47e017d2b3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Dec 2022 17:43:54 +0900 Subject: [PATCH 2489/2686] Fix multiple instances of last hitobject time being calculated incorrectly --- osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs | 5 ++--- osu.Game/Beatmaps/Beatmap.cs | 5 ++++- osu.Game/Beatmaps/IBeatmap.cs | 12 ++++++++++++ osu.Game/Rulesets/Objects/BarLineGenerator.cs | 7 ++----- .../UI/Scrolling/DrawableScrollingRuleset.cs | 2 +- osu.Game/Screens/Edit/Editor.cs | 7 ++----- osu.Game/Screens/Play/ReplayPlayer.cs | 4 +--- 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs index 55c20eebe9..77cf340b95 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModTargetPractice.cs @@ -17,7 +17,6 @@ using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Overlays.Settings; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Beatmaps; @@ -196,8 +195,8 @@ namespace osu.Game.Rulesets.Osu.Mods private IEnumerable generateBeats(IBeatmap beatmap, IReadOnlyCollection originalHitObjects) { - double startTime = originalHitObjects.First().StartTime; - double endTime = originalHitObjects.Last().GetEndTime(); + double startTime = beatmap.HitObjects.First().StartTime; + double endTime = beatmap.GetLastObjectTime(); var beats = beatmap.ControlPointInfo.TimingPoints // Ignore timing points after endTime diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 2d02fb6200..2ab4fe0c79 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -81,9 +81,12 @@ namespace osu.Game.Beatmaps public double GetMostCommonBeatLength() { + if (!HitObjects.Any()) + return ControlPointInfo.TimingPoints.LastOrDefault()?.Time ?? 0; + // The last playable time in the beatmap - the last timing point extends to this time. // Note: This is more accurate and may present different results because osu-stable didn't have the ability to calculate slider durations in this context. - double lastTime = HitObjects.LastOrDefault()?.GetEndTime() ?? ControlPointInfo.TimingPoints.LastOrDefault()?.Time ?? 0; + double lastTime = this.GetLastObjectTime(); var mostCommon = // Construct a set of (beatLength, duration) tuples for each individual timing point. diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs index 0e892b6581..f6771f7adf 100644 --- a/osu.Game/Beatmaps/IBeatmap.cs +++ b/osu.Game/Beatmaps/IBeatmap.cs @@ -4,6 +4,7 @@ #nullable disable using System.Collections.Generic; +using System.Linq; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Timing; using osu.Game.Rulesets.Objects; @@ -102,5 +103,16 @@ namespace osu.Game.Beatmaps addCombo(nested, ref combo); } } + + /// + /// Find the absolute end time of the latest in a beatmap. Will throw if beatmap contains no objects. + /// + /// + /// This correctly accounts for rulesets which have concurrent hitobjects which may have durations, causing the .Last() object + /// to not necessarily have the latest end time. + /// + /// It's not super efficient so calls should be kept to a minimum. + /// + public static double GetLastObjectTime(this IBeatmap beatmap) => beatmap.HitObjects.Max(h => h.GetEndTime()); } } diff --git a/osu.Game/Rulesets/Objects/BarLineGenerator.cs b/osu.Game/Rulesets/Objects/BarLineGenerator.cs index 5c76c43f20..af32c7def3 100644 --- a/osu.Game/Rulesets/Objects/BarLineGenerator.cs +++ b/osu.Game/Rulesets/Objects/BarLineGenerator.cs @@ -27,11 +27,8 @@ namespace osu.Game.Rulesets.Objects if (beatmap.HitObjects.Count == 0) return; - HitObject firstObject = beatmap.HitObjects.First(); - HitObject lastObject = beatmap.HitObjects.Last(); - - double firstHitTime = firstObject.StartTime; - double lastHitTime = 1 + lastObject.GetEndTime(); + double firstHitTime = beatmap.HitObjects.First().StartTime; + double lastHitTime = 1 + beatmap.GetLastObjectTime(); var timingPoints = beatmap.ControlPointInfo.TimingPoints; diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 52853d3979..123be0f117 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.UI.Scrolling break; } - double lastObjectTime = Objects.LastOrDefault()?.GetEndTime() ?? double.MaxValue; + double lastObjectTime = Beatmap.GetLastObjectTime(); double baseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH; if (RelativeScaleBeatLengths) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 02130b9662..b8d308cc7c 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -40,7 +40,6 @@ using osu.Game.Overlays.Notifications; using osu.Game.Overlays.OSD; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; -using osu.Game.Rulesets.Objects; using osu.Game.Screens.Edit.Components.Menus; using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Compose.Components.Timeline; @@ -538,12 +537,10 @@ namespace osu.Game.Screens.Edit // Seek to last object time, or track end if already there. // Note that in osu-stable subsequent presses when at track end won't return to last object. // This has intentionally been changed to make it more useful. - double? lastObjectTime = editorBeatmap.HitObjects.LastOrDefault()?.GetEndTime(); - - if (lastObjectTime == null || clock.CurrentTime == lastObjectTime) + if (!editorBeatmap.HitObjects.Any() || clock.CurrentTime == editorBeatmap.GetLastObjectTime()) clock.Seek(clock.TrackLength); else - clock.Seek(lastObjectTime.Value); + clock.Seek(editorBeatmap.GetLastObjectTime()); return true; } diff --git a/osu.Game/Screens/Play/ReplayPlayer.cs b/osu.Game/Screens/Play/ReplayPlayer.cs index 4395b96139..c5ef6b1585 100644 --- a/osu.Game/Screens/Play/ReplayPlayer.cs +++ b/osu.Game/Screens/Play/ReplayPlayer.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using osu.Framework.Bindables; using osu.Framework.Input.Bindings; @@ -13,7 +12,6 @@ using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Input.Bindings; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Objects; using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; @@ -94,7 +92,7 @@ namespace osu.Game.Screens.Play void keyboardSeek(int direction) { - double target = Math.Clamp(GameplayClockContainer.CurrentTime + direction * keyboard_seek_amount, 0, GameplayState.Beatmap.HitObjects.Last().GetEndTime()); + double target = Math.Clamp(GameplayClockContainer.CurrentTime + direction * keyboard_seek_amount, 0, GameplayState.Beatmap.GetLastObjectTime()); Seek(target); } From d9d48516fce4a8cfda3d8b91fd3f1aa55270ce8f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Dec 2022 18:04:04 +0900 Subject: [PATCH 2490/2686] Add test coverage of getting last object time --- .../Formats/LegacyBeatmapDecoderTest.cs | 18 +++++++++ .../mania-last-object-not-latest.osu | 39 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 osu.Game.Tests/Resources/mania-last-object-not-latest.osu diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index c6bdd25e8b..5787bd6066 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -314,6 +314,24 @@ namespace osu.Game.Tests.Beatmaps.Formats } } + [Test] + public void TestGetLastObjectTime() + { + var decoder = new LegacyBeatmapDecoder(); + + using (var resStream = TestResources.OpenResource("mania-last-object-not-latest.osu")) + using (var stream = new LineBufferedReader(resStream)) + { + var beatmap = decoder.Decode(stream); + + Assert.That(beatmap.HitObjects.Last().StartTime, Is.EqualTo(2494)); + Assert.That(beatmap.HitObjects.Last().GetEndTime(), Is.EqualTo(2494)); + + Assert.That(beatmap.HitObjects.Max(h => h.GetEndTime()), Is.EqualTo(2582)); + Assert.That(beatmap.GetLastObjectTime(), Is.EqualTo(2582)); + } + } + [Test] public void TestDecodeBeatmapComboOffsetsOsu() { diff --git a/osu.Game.Tests/Resources/mania-last-object-not-latest.osu b/osu.Game.Tests/Resources/mania-last-object-not-latest.osu new file mode 100644 index 0000000000..51893383d8 --- /dev/null +++ b/osu.Game.Tests/Resources/mania-last-object-not-latest.osu @@ -0,0 +1,39 @@ +osu file format v14 + +[General] +SampleSet: Normal +StackLeniency: 0.7 +Mode: 3 + +[Difficulty] +HPDrainRate:3 +CircleSize:5 +OverallDifficulty:8 +ApproachRate:8 +SliderMultiplier:3.59999990463257 +SliderTickRate:2 + +[TimingPoints] +24,352.941176470588,4,1,1,100,1,0 +6376,-50,4,1,1,100,0,0 + +[HitObjects] +51,192,24,1,0,0:0:0:0: +153,192,200,1,0,0:0:0:0: +358,192,376,1,0,0:0:0:0: +460,192,553,1,0,0:0:0:0: +460,192,729,128,0,1435:0:0:0:0: +358,192,906,128,0,1612:0:0:0:0: +256,192,1082,128,0,1788:0:0:0:0: +153,192,1259,128,0,1965:0:0:0:0: +51,192,1435,128,0,2141:0:0:0:0: +51,192,2318,1,12,0:0:0:0: +153,192,2318,1,4,0:0:0:0: +256,192,2318,1,6,0:0:0:0: +358,192,2318,1,14,0:0:0:0: +460,192,2318,1,0,0:0:0:0: +51,192,2494,128,0,2582:0:0:0:0: +153,192,2494,128,14,2582:0:0:0:0: +256,192,2494,128,6,2582:0:0:0:0: +358,192,2494,128,4,2582:0:0:0:0: +460,192,2494,1,12,0:0:0:0:0: From a7f4325d3c473bb616b7b82cc23ceefe7044d115 Mon Sep 17 00:00:00 2001 From: Joppe27 Date: Thu, 1 Dec 2022 12:16:58 +0100 Subject: [PATCH 2491/2686] Revert hacky fade value and fix test --- .../Skinning/TestSceneTaikoKiaiGlow.cs | 4 ++++ osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoKiaiGlow.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoKiaiGlow.cs index 26e2202124..a5e2eb0dbb 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoKiaiGlow.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoKiaiGlow.cs @@ -21,6 +21,8 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning { var controlPointInfo = new ControlPointInfo(); + controlPointInfo.Add(0, new TimingControlPoint { BeatLength = 500 }); + if (withKiai) controlPointInfo.Add(0, new EffectControlPoint { KiaiMode = true }); @@ -28,6 +30,8 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning { ControlPointInfo = controlPointInfo }); + + Beatmap.Value.Track.Start(); } } } diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs index 955deb7f3a..80b8bc9b11 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs @@ -16,8 +16,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { internal partial class LegacyKiaiGlow : BeatSyncedContainer { - private const float colour_compensation = 1.58f; - public LegacyKiaiGlow() { AlwaysPresent = true; @@ -60,7 +58,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { if (effectPoint.KiaiMode) - this.FadeTo(colour_compensation, 180); + this.FadeIn(180); else this.FadeOut(180); } From d8dd7e7e0ff8a9476949d3ab73e27777fa638e83 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 1 Dec 2022 21:42:03 +0900 Subject: [PATCH 2492/2686] Fix test failures when no hitobjects are present in a scrolling ruleset --- osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 123be0f117..5218ddfe15 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.UI.Scrolling break; } - double lastObjectTime = Beatmap.GetLastObjectTime(); + double lastObjectTime = Beatmap.HitObjects.Any() ? Beatmap.GetLastObjectTime() : 0; double baseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH; if (RelativeScaleBeatLengths) From 5de01686a9d60c80c0f4afb5d6a3a57a9693fce1 Mon Sep 17 00:00:00 2001 From: Piggey Date: Thu, 1 Dec 2022 18:42:52 +0100 Subject: [PATCH 2493/2686] extract `findBestNumber()` from `GetNextBestName()` into private method --- osu.Game/Utils/NamingUtils.cs | 42 +++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/osu.Game/Utils/NamingUtils.cs b/osu.Game/Utils/NamingUtils.cs index 2439d4ba22..0f55c79e84 100644 --- a/osu.Game/Utils/NamingUtils.cs +++ b/osu.Game/Utils/NamingUtils.cs @@ -31,6 +31,30 @@ namespace osu.Game.Utils { string pattern = $@"^(?i){Regex.Escape(desiredName)}(?-i)( \((?[1-9][0-9]*)\))?$"; var regex = new Regex(pattern, RegexOptions.Compiled); + + int bestNumber = findBestNumber(existingNames, regex); + + return bestNumber == 0 + ? desiredName + : $"{desiredName} ({bestNumber.ToString()})"; + } + + /// + /// Given a set of and a desired target + /// finds a filename closest to that is not in + /// + /// SHOULD NOT CONTAIN the file extension. + /// + /// + public static string GetNextBestFilename(IEnumerable existingFilenames, string desiredName, string fileExtension) + { + var stripped = existingFilenames.Select(filename => filename.Substring(0, filename.Length - fileExtension.Length)); + + return $"{GetNextBestName(stripped, desiredName)}{fileExtension}"; + } + + private static int findBestNumber(IEnumerable existingNames, Regex regex) + { var takenNumbers = new HashSet(); foreach (string name in existingNames) @@ -54,23 +78,7 @@ namespace osu.Game.Utils while (takenNumbers.Contains(bestNumber)) bestNumber += 1; - return bestNumber == 0 - ? desiredName - : $"{desiredName} ({bestNumber})"; - } - - /// - /// Given a set of and a desired target - /// finds a filename closest to that is not in - /// - /// SHOULD NOT CONTAIN the file extension. - /// - /// - public static string GetNextBestFilename(IEnumerable existingFilenames, string desiredName, string fileExtension) - { - var stripped = existingFilenames.Select(filename => filename.Substring(0, filename.Length - fileExtension.Length)); - - return $"{GetNextBestName(stripped, desiredName)}{fileExtension}"; + return bestNumber; } } } From 75cf7bd1d2262fd09633f64182e2d5acbe4758bd Mon Sep 17 00:00:00 2001 From: Piggey Date: Thu, 1 Dec 2022 18:43:34 +0100 Subject: [PATCH 2494/2686] change `GetNextBestFilename()`'s parameters --- osu.Game/Database/LegacyExporter.cs | 2 +- osu.Game/Utils/NamingUtils.cs | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 0a5f787469..374f9f557a 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -43,7 +43,7 @@ namespace osu.Game.Database IEnumerable existingExports = exportStorage.GetFiles("", $"{itemFilename}*{FileExtension}"); - string filename = NamingUtils.GetNextBestFilename(existingExports, itemFilename, FileExtension); + string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}"); using (var stream = exportStorage.CreateFileSafely(filename)) ExportModelTo(item, stream); diff --git a/osu.Game/Utils/NamingUtils.cs b/osu.Game/Utils/NamingUtils.cs index 0f55c79e84..fa102ff56f 100644 --- a/osu.Game/Utils/NamingUtils.cs +++ b/osu.Game/Utils/NamingUtils.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Linq; +using System.IO; using System.Text.RegularExpressions; namespace osu.Game.Utils @@ -40,17 +40,22 @@ namespace osu.Game.Utils } /// - /// Given a set of and a desired target - /// finds a filename closest to that is not in - /// - /// SHOULD NOT CONTAIN the file extension. - /// + /// Given a set of and a desired target + /// finds a filename closest to that is not in /// - public static string GetNextBestFilename(IEnumerable existingFilenames, string desiredName, string fileExtension) + public static string GetNextBestFilename(IEnumerable existingFilenames, string desiredFilename) { - var stripped = existingFilenames.Select(filename => filename.Substring(0, filename.Length - fileExtension.Length)); + string name = Path.GetFileNameWithoutExtension(desiredFilename); + string extension = Path.GetExtension(desiredFilename); - return $"{GetNextBestName(stripped, desiredName)}{fileExtension}"; + string pattern = $@"^(?i){Regex.Escape(name)}(?-i)( \((?[1-9][0-9]*)\))?(?i){Regex.Escape(extension)}(?-i)$"; + var regex = new Regex(pattern, RegexOptions.Compiled); + + int bestNumber = findBestNumber(existingFilenames, regex); + + return bestNumber == 0 + ? desiredFilename + : $"{name} ({bestNumber.ToString()}){extension}"; } private static int findBestNumber(IEnumerable existingNames, Regex regex) From 4308120912e995db07dd165b368d039ff3830310 Mon Sep 17 00:00:00 2001 From: Piggey Date: Thu, 1 Dec 2022 18:44:26 +0100 Subject: [PATCH 2495/2686] add tests for `GetNextBestFilename()` --- osu.Game.Tests/Utils/NamingUtilsTest.cs | 166 ++++++++++++++++++++++-- 1 file changed, 157 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Utils/NamingUtilsTest.cs b/osu.Game.Tests/Utils/NamingUtilsTest.cs index 62e688db90..1f7e06f996 100644 --- a/osu.Game.Tests/Utils/NamingUtilsTest.cs +++ b/osu.Game.Tests/Utils/NamingUtilsTest.cs @@ -11,7 +11,7 @@ namespace osu.Game.Tests.Utils public class NamingUtilsTest { [Test] - public void TestEmptySet() + public void TestNextBestNameEmptySet() { string nextBestName = NamingUtils.GetNextBestName(Enumerable.Empty(), "New Difficulty"); @@ -19,7 +19,7 @@ namespace osu.Game.Tests.Utils } [Test] - public void TestNotTaken() + public void TestNextBestNameNotTaken() { string[] existingNames = { @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Utils } [Test] - public void TestNotTakenButClose() + public void TestNextBestNameNotTakenButClose() { string[] existingNames = { @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Utils } [Test] - public void TestAlreadyTaken() + public void TestNextBestNameAlreadyTaken() { string[] existingNames = { @@ -62,7 +62,7 @@ namespace osu.Game.Tests.Utils } [Test] - public void TestAlreadyTakenWithDifferentCase() + public void TestNextBestNameAlreadyTakenWithDifferentCase() { string[] existingNames = { @@ -75,7 +75,7 @@ namespace osu.Game.Tests.Utils } [Test] - public void TestAlreadyTakenWithBrackets() + public void TestNextBestNameAlreadyTakenWithBrackets() { string[] existingNames = { @@ -88,7 +88,7 @@ namespace osu.Game.Tests.Utils } [Test] - public void TestMultipleAlreadyTaken() + public void TestNextBestNameMultipleAlreadyTaken() { string[] existingNames = { @@ -104,7 +104,7 @@ namespace osu.Game.Tests.Utils } [Test] - public void TestEvenMoreAlreadyTaken() + public void TestNextBestNameEvenMoreAlreadyTaken() { string[] existingNames = Enumerable.Range(1, 30).Select(i => $"New Difficulty ({i})").Append("New Difficulty").ToArray(); @@ -114,7 +114,7 @@ namespace osu.Game.Tests.Utils } [Test] - public void TestMultipleAlreadyTakenWithGaps() + public void TestNextBestNameMultipleAlreadyTakenWithGaps() { string[] existingNames = { @@ -128,5 +128,153 @@ namespace osu.Game.Tests.Utils Assert.AreEqual("New Difficulty (2)", nextBestName); } + + [Test] + public void TestNextBestFilenameEmptySet() + { + string nextBestFilename = NamingUtils.GetNextBestFilename(Enumerable.Empty(), "test_file.osr"); + + Assert.AreEqual("test_file.osr", nextBestFilename); + } + + [Test] + public void TestNextBestFilenameNotTaken() + { + string[] existingFiles = + { + "this file exists.zip", + "that file exists.too", + "three.4", + }; + + string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "test_file.osr"); + + Assert.AreEqual("test_file.osr", nextBestFilename); + } + + [Test] + public void TestNextBestFilenameNotTakenButClose() + { + string[] existingFiles = + { + "replay_file(1).osr", + "replay_file (not a number).zip", + "replay_file (1 <- now THAT is a number right here).lol", + }; + + string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); + + Assert.AreEqual("replay_file.osr", nextBestFilename); + } + + [Test] + public void TestNextBestFilenameAlreadyTaken() + { + string[] existingFiles = + { + "replay_file.osr", + }; + + string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); + + Assert.AreEqual("replay_file (1).osr", nextBestFilename); + } + + [Test] + public void TestNextBestFilenameAlreadyTakenDifferentCase() + { + string[] existingFiles = + { + "replay_file.osr", + "RePlAy_FiLe (1).OsR", + "REPLAY_FILE (2).OSR", + }; + + string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); + Assert.AreEqual("replay_file (3).osr", nextBestFilename); + } + + [Test] + public void TestNextBestFilenameAlreadyTakenWithBrackets() + { + string[] existingFiles = + { + "replay_file.osr", + "replay_file (copy).osr", + }; + + string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); + Assert.AreEqual("replay_file (1).osr", nextBestFilename); + + nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file (copy).osr"); + Assert.AreEqual("replay_file (copy) (1).osr", nextBestFilename); + } + + [Test] + public void TestNextBestFilenameMultipleAlreadyTaken() + { + string[] existingFiles = + { + "replay_file.osr", + "replay_file (1).osr", + "replay_file (2).osr", + "replay_file (3).osr", + }; + + string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); + + Assert.AreEqual("replay_file (4).osr", nextBestFilename); + } + + [Test] + public void TestNextBestFilenameMultipleAlreadyTakenWithGaps() + { + string[] existingFiles = + { + "replay_file.osr", + "replay_file (1).osr", + "replay_file (2).osr", + "replay_file (4).osr", + "replay_file (5).osr", + }; + + string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); + + Assert.AreEqual("replay_file (3).osr", nextBestFilename); + } + + [Test] + public void TestNextBestFilenameNoExtensions() + { + string[] existingFiles = + { + "those", + "are definitely", + "files", + }; + + string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "surely"); + Assert.AreEqual("surely", nextBestFilename); + + nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "those"); + Assert.AreEqual("those (1)", nextBestFilename); + } + + [Test] + public void TestNextBestFilenameDifferentExtensions() + { + string[] existingFiles = + { + "replay_file.osr", + "replay_file (1).osr", + "replay_file.txt", + }; + + string nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.osr"); + Assert.AreEqual("replay_file (2).osr", nextBestFilename); + + nextBestFilename = NamingUtils.GetNextBestFilename(existingFiles, "replay_file.txt"); + Assert.AreEqual("replay_file (1).txt", nextBestFilename); + } } } From 8cf89fcb81c663fbaee4b6576e231028bda73cd4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Dec 2022 15:30:47 +0900 Subject: [PATCH 2496/2686] Use `Highlight1` instead of dull grey --- .../Components/Timeline/TimelineHitObjectBlueprint.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs index d089b1e744..a7569daf93 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs @@ -18,6 +18,7 @@ using osu.Framework.Utils; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -54,6 +55,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline [Resolved] private ISkinSource skin { get; set; } = null!; + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + public TimelineHitObjectBlueprint(HitObject item) : base(item) { @@ -165,7 +169,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline break; default: - colour = Color4.Gray; + colour = colourProvider.Highlight1; break; } From 809d02cda0156032360471aa5bf287c829529ea0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Dec 2022 16:05:14 +0900 Subject: [PATCH 2497/2686] Fix two implementation oversights --- osu.Game/Beatmaps/Beatmap.cs | 8 +++++--- .../Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/Beatmap.cs b/osu.Game/Beatmaps/Beatmap.cs index 2ab4fe0c79..416d655cc3 100644 --- a/osu.Game/Beatmaps/Beatmap.cs +++ b/osu.Game/Beatmaps/Beatmap.cs @@ -81,12 +81,14 @@ namespace osu.Game.Beatmaps public double GetMostCommonBeatLength() { - if (!HitObjects.Any()) - return ControlPointInfo.TimingPoints.LastOrDefault()?.Time ?? 0; + double lastTime; // The last playable time in the beatmap - the last timing point extends to this time. // Note: This is more accurate and may present different results because osu-stable didn't have the ability to calculate slider durations in this context. - double lastTime = this.GetLastObjectTime(); + if (!HitObjects.Any()) + lastTime = ControlPointInfo.TimingPoints.LastOrDefault()?.Time ?? 0; + else + lastTime = this.GetLastObjectTime(); var mostCommon = // Construct a set of (beatLength, duration) tuples for each individual timing point. diff --git a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs index 5218ddfe15..4c7564b791 100644 --- a/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs +++ b/osu.Game/Rulesets/UI/Scrolling/DrawableScrollingRuleset.cs @@ -114,7 +114,7 @@ namespace osu.Game.Rulesets.UI.Scrolling break; } - double lastObjectTime = Beatmap.HitObjects.Any() ? Beatmap.GetLastObjectTime() : 0; + double lastObjectTime = Beatmap.HitObjects.Any() ? Beatmap.GetLastObjectTime() : double.MaxValue; double baseBeatLength = TimingControlPoint.DEFAULT_BEAT_LENGTH; if (RelativeScaleBeatLengths) From a2db0afe1922cb1e6a99247b222c4800b9bea36f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Dec 2022 16:07:24 +0900 Subject: [PATCH 2498/2686] Avoid querying `GetLastObjectTime` twice in editor seek flow --- osu.Game/Screens/Edit/Editor.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index b8d308cc7c..f3f2b8ad6b 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -537,10 +537,14 @@ namespace osu.Game.Screens.Edit // Seek to last object time, or track end if already there. // Note that in osu-stable subsequent presses when at track end won't return to last object. // This has intentionally been changed to make it more useful. - if (!editorBeatmap.HitObjects.Any() || clock.CurrentTime == editorBeatmap.GetLastObjectTime()) + if (!editorBeatmap.HitObjects.Any()) + { clock.Seek(clock.TrackLength); - else - clock.Seek(editorBeatmap.GetLastObjectTime()); + return true; + } + + double lastObjectTime = editorBeatmap.GetLastObjectTime(); + clock.Seek(clock.CurrentTime == lastObjectTime ? clock.TrackLength : lastObjectTime); return true; } From 25120060aa16f05d32d80119c1bf1bb0379bd020 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Dec 2022 16:09:26 +0900 Subject: [PATCH 2499/2686] Use new helper method in `ModTimeRamp` --- osu.Game/Rulesets/Mods/ModTimeRamp.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModTimeRamp.cs b/osu.Game/Rulesets/Mods/ModTimeRamp.cs index c4cb41fb6a..7285315c3b 100644 --- a/osu.Game/Rulesets/Mods/ModTimeRamp.cs +++ b/osu.Game/Rulesets/Mods/ModTimeRamp.cs @@ -7,7 +7,6 @@ using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Game.Beatmaps; using osu.Game.Configuration; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mods @@ -71,7 +70,7 @@ namespace osu.Game.Rulesets.Mods SpeedChange.SetDefault(); double firstObjectStart = beatmap.HitObjects.FirstOrDefault()?.StartTime ?? 0; - double lastObjectEnd = beatmap.HitObjects.LastOrDefault()?.GetEndTime() ?? 0; + double lastObjectEnd = beatmap.HitObjects.Any() ? beatmap.GetLastObjectTime() : 0; beginRampTime = firstObjectStart; finalRateTime = firstObjectStart + FINAL_RATE_PROGRESS * (lastObjectEnd - firstObjectStart); From 47855de6ab69536bce3fde959db249283acbe069 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Dec 2022 16:54:58 +0900 Subject: [PATCH 2500/2686] Fix multiple issues with transform handling --- .../Skinning/Legacy/LegacyKiaiGlow.cs | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs index 80b8bc9b11..d06571eba2 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs @@ -16,15 +16,13 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { internal partial class LegacyKiaiGlow : BeatSyncedContainer { - public LegacyKiaiGlow() - { - AlwaysPresent = true; - Alpha = 0; - } + private bool isKiaiActive; - [BackgroundDependencyLoader] - private void load(ISkinSource skin) + [BackgroundDependencyLoader(true)] + private void load(ISkinSource skin, HealthProcessor? healthProcessor) { + Alpha = 0; + Child = new Sprite { Texture = skin.GetTexture("taiko-glow"), @@ -33,14 +31,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy Scale = new Vector2(0.7f), Colour = new Colour4(255, 228, 0, 255), }; - } - - [Resolved(CanBeNull = true)] - private HealthProcessor? healthProcessor { get; set; } - - protected override void Update() - { - base.Update(); if (healthProcessor != null) healthProcessor.NewJudgement += onNewJudgement; @@ -48,16 +38,21 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy private void onNewJudgement(JudgementResult result) { - if (!result.IsHit) + if (!result.IsHit || !isKiaiActive) return; - this.ScaleTo(1.2f) - .Then().ScaleTo(1f, 80, Easing.OutQuad); + this.ScaleTo(1.2f).Then() + .ScaleTo(1f, 80, Easing.OutQuad); } protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { - if (effectPoint.KiaiMode) + if (effectPoint.KiaiMode == isKiaiActive) + return; + + isKiaiActive = effectPoint.KiaiMode; + + if (isKiaiActive) this.FadeIn(180); else this.FadeOut(180); From ebc75d40d2a7478950ba3e5544ef5dcb19346bdf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Dec 2022 17:32:57 +0900 Subject: [PATCH 2501/2686] Switch to using immediate transforms to make rewind handle better --- .../Skinning/Legacy/LegacyKiaiGlow.cs | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs index d06571eba2..623243e9e1 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyKiaiGlow.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 osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Graphics; @@ -18,16 +19,17 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { private bool isKiaiActive; + private Sprite sprite = null!; + [BackgroundDependencyLoader(true)] private void load(ISkinSource skin, HealthProcessor? healthProcessor) { - Alpha = 0; - - Child = new Sprite + Child = sprite = new Sprite { Texture = skin.GetTexture("taiko-glow"), Origin = Anchor.Centre, Anchor = Anchor.Centre, + Alpha = 0, Scale = new Vector2(0.7f), Colour = new Colour4(255, 228, 0, 255), }; @@ -36,26 +38,28 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy healthProcessor.NewJudgement += onNewJudgement; } + protected override void Update() + { + base.Update(); + + if (isKiaiActive) + sprite.Alpha = (float)Math.Min(1, sprite.Alpha + Math.Abs(Clock.ElapsedFrameTime) / 100f); + else + sprite.Alpha = (float)Math.Max(0, sprite.Alpha - Math.Abs(Clock.ElapsedFrameTime) / 600f); + } + + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) + { + isKiaiActive = effectPoint.KiaiMode; + } + private void onNewJudgement(JudgementResult result) { if (!result.IsHit || !isKiaiActive) return; - this.ScaleTo(1.2f).Then() - .ScaleTo(1f, 80, Easing.OutQuad); - } - - protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) - { - if (effectPoint.KiaiMode == isKiaiActive) - return; - - isKiaiActive = effectPoint.KiaiMode; - - if (isKiaiActive) - this.FadeIn(180); - else - this.FadeOut(180); + sprite.ScaleTo(0.85f).Then() + .ScaleTo(0.7f, 80, Easing.OutQuad); } } } From 2fd535ea2066251a44f07cc4019a5b816067650a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Dec 2022 17:33:18 +0900 Subject: [PATCH 2502/2686] Apply same immediate transform logic to `TaikoLegacyPlayfieldBackgroundRight` to fix it sticking during rewind --- .../TaikoLegacyPlayfieldBackgroundRight.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs index 86175d3bca..85870d0fd6 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/TaikoLegacyPlayfieldBackgroundRight.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 osu.Framework.Allocation; using osu.Framework.Audio.Track; using osu.Framework.Graphics; @@ -16,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy { private Sprite kiai = null!; - private bool kiaiDisplayed; + private bool isKiaiActive; [BackgroundDependencyLoader] private void load(ISkinSource skin) @@ -41,17 +42,19 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy }; } + protected override void Update() + { + base.Update(); + + if (isKiaiActive) + kiai.Alpha = (float)Math.Min(1, kiai.Alpha + Math.Abs(Clock.ElapsedFrameTime) / 200f); + else + kiai.Alpha = (float)Math.Max(0, kiai.Alpha - Math.Abs(Clock.ElapsedFrameTime) / 200f); + } + protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes) { - base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes); - - if (effectPoint.KiaiMode != kiaiDisplayed) - { - kiaiDisplayed = effectPoint.KiaiMode; - - kiai.ClearTransforms(); - kiai.FadeTo(kiaiDisplayed ? 1 : 0, 200); - } + isKiaiActive = effectPoint.KiaiMode; } } } From ba99f1288c0be9a727cbcdfcbec90812298dc325 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Dec 2022 17:47:29 +0900 Subject: [PATCH 2503/2686] Update `IBeatSnapProvider` documentation to mention the pre-divided `BeatSnap` --- osu.Game/Rulesets/Edit/IBeatSnapProvider.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Edit/IBeatSnapProvider.cs b/osu.Game/Rulesets/Edit/IBeatSnapProvider.cs index dbad407b75..5e45cefe8c 100644 --- a/osu.Game/Rulesets/Edit/IBeatSnapProvider.cs +++ b/osu.Game/Rulesets/Edit/IBeatSnapProvider.cs @@ -1,14 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - namespace osu.Game.Rulesets.Edit { public interface IBeatSnapProvider { /// - /// Snaps a duration to the closest beat of a timing point applicable at the reference time. + /// Snaps a duration to the closest beat of a timing point applicable at the reference time, factoring in the current . /// /// The time to snap. /// An optional reference point to use for timing point lookup. @@ -16,10 +14,10 @@ namespace osu.Game.Rulesets.Edit double SnapTime(double time, double? referenceTime = null); /// - /// Get the most appropriate beat length at a given time. + /// Get the most appropriate beat length at a given time, pre-divided by . /// /// A reference time used for lookup. - /// The most appropriate beat length. + /// The most appropriate beat length, divided by . double GetBeatLengthAtTime(double referenceTime); /// From 45ea183cc36bcee3050daec63af63e6f059695df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Dec 2022 17:56:34 +0900 Subject: [PATCH 2504/2686] Fix being able to place zero-length spinners Also always snap a spinner's end time using beat snap (matches stable). --- .../Blueprints/Spinners/SpinnerPlacementBlueprint.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index e412c47c09..52f845f358 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; @@ -22,6 +23,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners private bool isPlacingEnd; + [Resolved] + private IBeatSnapProvider beatSnapProvider { get; set; } + public SpinnerPlacementBlueprint() : base(new Spinner { Position = OsuPlayfield.BASE_SIZE / 2 }) { @@ -33,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners base.Update(); if (isPlacingEnd) - HitObject.EndTime = Math.Max(HitObject.StartTime, EditorClock.CurrentTime); + updateEndTimeFromCurrent(); piece.UpdateFrom(HitObject); } @@ -45,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners if (e.Button != MouseButton.Right) return false; - HitObject.EndTime = EditorClock.CurrentTime; + updateEndTimeFromCurrent(); EndPlacement(true); } else @@ -61,5 +65,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners return true; } + + private void updateEndTimeFromCurrent() => + HitObject.EndTime = Math.Max(HitObject.StartTime + beatSnapProvider.GetBeatLengthAtTime(HitObject.StartTime), beatSnapProvider.SnapTime(EditorClock.CurrentTime)); } } From d1296a22ce0e9d61beb39feb02ff8c7adafebdef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Dec 2022 17:57:13 +0900 Subject: [PATCH 2505/2686] Update timeline blueprint's end time logic to better match new blueprint implementation --- .../Compose/Components/Timeline/TimelineHitObjectBlueprint.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs index a7569daf93..03e67306df 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs @@ -424,9 +424,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline break; case IHasDuration endTimeHitObject: - double snappedTime = Math.Max(hitObject.StartTime, beatSnapProvider.SnapTime(time)); + double snappedTime = Math.Max(hitObject.StartTime + beatSnapProvider.GetBeatLengthAtTime(hitObject.StartTime), beatSnapProvider.SnapTime(time)); - if (endTimeHitObject.EndTime == snappedTime || Precision.AlmostEquals(snappedTime, hitObject.StartTime, beatmap.GetBeatLengthAtTime(snappedTime))) + if (endTimeHitObject.EndTime == snappedTime) return; endTimeHitObject.Duration = snappedTime - hitObject.StartTime; From ee62f3c0d3f061762cf2370b93f9901eab81b171 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 2 Dec 2022 18:32:40 +0900 Subject: [PATCH 2506/2686] Fix test failure Similar to SliderPlacementBlueprint. --- .../Blueprints/Spinners/SpinnerPlacementBlueprint.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index 52f845f358..73ee5df9dc 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Input.Events; @@ -23,7 +24,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners private bool isPlacingEnd; - [Resolved] + [Resolved(CanBeNull = true)] + [CanBeNull] private IBeatSnapProvider beatSnapProvider { get; set; } public SpinnerPlacementBlueprint() @@ -66,7 +68,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners return true; } - private void updateEndTimeFromCurrent() => - HitObject.EndTime = Math.Max(HitObject.StartTime + beatSnapProvider.GetBeatLengthAtTime(HitObject.StartTime), beatSnapProvider.SnapTime(EditorClock.CurrentTime)); + private void updateEndTimeFromCurrent() + { + HitObject.EndTime = beatSnapProvider == null + ? Math.Max(HitObject.StartTime, EditorClock.CurrentTime) + : Math.Max(HitObject.StartTime + beatSnapProvider.GetBeatLengthAtTime(HitObject.StartTime), beatSnapProvider.SnapTime(EditorClock.CurrentTime)); + } } } From 49f5ac57b8ab109f7a4b62f20f05a02f94900ead Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 3 Dec 2022 18:48:53 +0900 Subject: [PATCH 2507/2686] Fix first run beatmap screen button colours looking incorrect with new triangle effect Addresses #21500. --- osu.Game/Overlays/FirstRunSetup/ProgressRoundedButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ProgressRoundedButton.cs b/osu.Game/Overlays/FirstRunSetup/ProgressRoundedButton.cs index a4762fdaed..a1e61e66f8 100644 --- a/osu.Game/Overlays/FirstRunSetup/ProgressRoundedButton.cs +++ b/osu.Game/Overlays/FirstRunSetup/ProgressRoundedButton.cs @@ -81,7 +81,7 @@ namespace osu.Game.Overlays.FirstRunSetup loading.Hide(); tick.FadeIn(500, Easing.OutQuint); - Background.FadeColour(colours.Green, 500, Easing.OutQuint); + this.TransformTo(nameof(BackgroundColour), colours.Green, 500, Easing.OutQuint); progressBar.FillColour = colours.Green; this.TransformBindableTo(progressBar.Current, 1, 500, Easing.OutQuint); From 94cfcdb338690f2cdd174bcdf8b789a44929c5be Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 3 Dec 2022 16:16:21 +0300 Subject: [PATCH 2508/2686] Remove SmoothCircularProgress usage in BeatmapCardThumbnail --- osu.Game/Beatmaps/Drawables/Cards/BeatmapCardThumbnail.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardThumbnail.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardThumbnail.cs index 781133aac7..c99d1f0c76 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardThumbnail.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardThumbnail.cs @@ -11,7 +11,7 @@ using osu.Game.Beatmaps.Drawables.Cards.Buttons; using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; -using osu.Game.Screens.Ranking.Expanded.Accuracy; +using osu.Framework.Graphics.UserInterface; using osuTK; using osuTK.Graphics; @@ -30,7 +30,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards private readonly UpdateableOnlineBeatmapSetCover cover; private readonly Container foreground; private readonly PlayButton playButton; - private readonly SmoothCircularProgress progress; + private readonly CircularProgress progress; private readonly Container content; protected override Container Content => content; @@ -53,7 +53,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards { RelativeSizeAxes = Axes.Both }, - progress = new SmoothCircularProgress + progress = new CircularProgress { Anchor = Anchor.Centre, Origin = Anchor.Centre, From 97b6d88f003ffa1230ac03da372c0508c467adb6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 3 Dec 2022 16:39:44 +0300 Subject: [PATCH 2509/2686] Remove SmoothCircularProgress usage in AccuracyCircle --- .../Expanded/Accuracy/AccuracyCircle.cs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs index 3285ebc914..8e04bb68fb 100644 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs +++ b/osu.Game/Screens/Ranking/Expanded/Accuracy/AccuracyCircle.cs @@ -12,6 +12,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Utils; using osu.Game.Audio; using osu.Game.Graphics; @@ -79,8 +80,8 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy private readonly ScoreInfo score; - private SmoothCircularProgress accuracyCircle; - private SmoothCircularProgress innerMask; + private CircularProgress accuracyCircle; + private CircularProgress innerMask; private Container badges; private RankText rankText; @@ -109,7 +110,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy { InternalChildren = new Drawable[] { - new SmoothCircularProgress + new CircularProgress { Name = "Background circle", Anchor = Anchor.Centre, @@ -120,7 +121,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy InnerRadius = accuracy_circle_radius + 0.01f, // Extends a little bit into the circle Current = { Value = 1 }, }, - accuracyCircle = new SmoothCircularProgress + accuracyCircle = new CircularProgress { Name = "Accuracy circle", Anchor = Anchor.Centre, @@ -139,42 +140,42 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Padding = new MarginPadding(2), Children = new Drawable[] { - new SmoothCircularProgress + new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.X), InnerRadius = RANK_CIRCLE_RADIUS, Current = { Value = 1 } }, - new SmoothCircularProgress + new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.S), InnerRadius = RANK_CIRCLE_RADIUS, Current = { Value = 1 - virtual_ss_percentage } }, - new SmoothCircularProgress + new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.A), InnerRadius = RANK_CIRCLE_RADIUS, Current = { Value = 0.95f } }, - new SmoothCircularProgress + new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.B), InnerRadius = RANK_CIRCLE_RADIUS, Current = { Value = 0.9f } }, - new SmoothCircularProgress + new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.C), InnerRadius = RANK_CIRCLE_RADIUS, Current = { Value = 0.8f } }, - new SmoothCircularProgress + new CircularProgress { RelativeSizeAxes = Axes.Both, Colour = OsuColour.ForRank(ScoreRank.D), @@ -195,14 +196,14 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy Blending = new BlendingParameters { Source = BlendingType.DstColor, - Destination = BlendingType.OneMinusSrcAlpha, + Destination = BlendingType.OneMinusSrcColor, SourceAlpha = BlendingType.One, DestinationAlpha = BlendingType.SrcAlpha }, - Child = innerMask = new SmoothCircularProgress + Child = innerMask = new CircularProgress { RelativeSizeAxes = Axes.Both, - InnerRadius = RANK_CIRCLE_RADIUS - 0.01f, + InnerRadius = RANK_CIRCLE_RADIUS - 0.02f, } } } From 41f7dad8e96c3b8135277d4151eb5d0d553c1fd7 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sat, 3 Dec 2022 16:40:41 +0300 Subject: [PATCH 2510/2686] Delete SmoothCircularProgress.cs --- .../Accuracy/SmoothCircularProgress.cs | 128 ------------------ 1 file changed, 128 deletions(-) delete mode 100644 osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs diff --git a/osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs b/osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs deleted file mode 100644 index 601c47ea55..0000000000 --- a/osu.Game/Screens/Ranking/Expanded/Accuracy/SmoothCircularProgress.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Transforms; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics; -using osuTK; - -namespace osu.Game.Screens.Ranking.Expanded.Accuracy -{ - /// - /// Contains a with smoothened edges. - /// - public partial class SmoothCircularProgress : CompositeDrawable - { - public Bindable Current - { - get => progress.Current; - set => progress.Current = value; - } - - public float InnerRadius - { - get => progress.InnerRadius; - set - { - progress.InnerRadius = value; - innerSmoothingContainer.Size = new Vector2(1 - value); - smoothingWedge.Height = value / 2; - } - } - - private readonly CircularProgress progress; - private readonly Container innerSmoothingContainer; - private readonly Drawable smoothingWedge; - - public SmoothCircularProgress() - { - Container smoothingWedgeContainer; - - InternalChild = new BufferedContainer - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - progress = new CircularProgress { RelativeSizeAxes = Axes.Both }, - smoothingWedgeContainer = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Child = smoothingWedge = new Box - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Y, - Width = 1f, - EdgeSmoothness = new Vector2(2, 0), - } - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(-1), - Child = new CircularContainer - { - RelativeSizeAxes = Axes.Both, - BorderThickness = 2, - Masking = true, - BorderColour = OsuColour.Gray(0.5f).Opacity(0.75f), - Blending = new BlendingParameters - { - AlphaEquation = BlendingEquation.ReverseSubtract, - }, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - } - } - }, - innerSmoothingContainer = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = Vector2.Zero, - Padding = new MarginPadding(-1), - Child = new CircularContainer - { - RelativeSizeAxes = Axes.Both, - BorderThickness = 2, - BorderColour = OsuColour.Gray(0.5f).Opacity(0.75f), - Masking = true, - Blending = new BlendingParameters - { - AlphaEquation = BlendingEquation.ReverseSubtract, - }, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - } - } - }, - } - }; - - Current.BindValueChanged(c => - { - smoothingWedgeContainer.Alpha = c.NewValue > 0 ? 1 : 0; - smoothingWedgeContainer.Rotation = (float)(360 * c.NewValue); - }, true); - } - - public TransformSequence FillTo(double newValue, double duration = 0, Easing easing = Easing.None) - => progress.FillTo(newValue, duration, easing); - } -} From 7f0d366d0169521beb33335dadfbd306375096d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 3 Dec 2022 16:59:43 +0100 Subject: [PATCH 2511/2686] Extract common part of regex to separate method --- osu.Game/Utils/NamingUtils.cs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/osu.Game/Utils/NamingUtils.cs b/osu.Game/Utils/NamingUtils.cs index fa102ff56f..97220f4201 100644 --- a/osu.Game/Utils/NamingUtils.cs +++ b/osu.Game/Utils/NamingUtils.cs @@ -29,7 +29,7 @@ namespace osu.Game.Utils /// public static string GetNextBestName(IEnumerable existingNames, string desiredName) { - string pattern = $@"^(?i){Regex.Escape(desiredName)}(?-i)( \((?[1-9][0-9]*)\))?$"; + string pattern = $@"^{getBaselineNameDetectingPattern(desiredName)}$"; var regex = new Regex(pattern, RegexOptions.Compiled); int bestNumber = findBestNumber(existingNames, regex); @@ -48,7 +48,7 @@ namespace osu.Game.Utils string name = Path.GetFileNameWithoutExtension(desiredFilename); string extension = Path.GetExtension(desiredFilename); - string pattern = $@"^(?i){Regex.Escape(name)}(?-i)( \((?[1-9][0-9]*)\))?(?i){Regex.Escape(extension)}(?-i)$"; + string pattern = $@"^{getBaselineNameDetectingPattern(name)}(?i){Regex.Escape(extension)}(?-i)$"; var regex = new Regex(pattern, RegexOptions.Compiled); int bestNumber = findBestNumber(existingFilenames, regex); @@ -58,6 +58,22 @@ namespace osu.Game.Utils : $"{name} ({bestNumber.ToString()}){extension}"; } + /// + /// Generates a basic regex pattern that will match all possible conflicting filenames when picking the best available name, given the . + /// The generated pattern can be composed into more complicated regexes for particular uses, such as picking filenames, which need additional file extension handling. + /// + /// + /// The regex shall detect: + /// + /// all strings that are equal to , + /// all strings of the format desiredName (number), where number is a number written using Arabic numerals. + /// + /// All comparisons are made in a case-insensitive manner. + /// If a number is detected in the matches, it will be output to the copyNumber named group. + /// + private static string getBaselineNameDetectingPattern(string desiredName) + => $@"(?i){Regex.Escape(desiredName)}(?-i)( \((?[1-9][0-9]*)\))?"; + private static int findBestNumber(IEnumerable existingNames, Regex regex) { var takenNumbers = new HashSet(); From 36ab6bc64e6559a88b7d3f3ee1944903f40219b7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 3 Dec 2022 23:03:43 +0900 Subject: [PATCH 2512/2686] Update framework 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 75828147a5..0bf415e764 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6e75450594..a176d73854 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index bb20b0474d..e192467247 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 6c95b1d90dbf1e6aa0dfb2039aa2747bd786b3ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 3 Dec 2022 21:59:57 +0100 Subject: [PATCH 2513/2686] Bump `dorny/test-reporter` action to 1.6.0 The only reason I'm bothering to do this is that I mistakenly clicked on one of the execution logs of the "Annotate CI with test results" workflow and noticed a bunch of deprecation warnings: https://github.com/ppy/osu/actions/runs/3610166871 Judging from the release notes [[1]] and diffstat [[2]] of version 1.6.0 of the action affected, a bump should silence these. [1]: https://github.com/dorny/test-reporter/blob/main/CHANGELOG.md [2]: https://github.com/dorny/test-reporter/compare/v1.4.2...v1.6.0 --- .github/workflows/report-nunit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/report-nunit.yml b/.github/workflows/report-nunit.yml index bfc9620174..99e39f6f56 100644 --- a/.github/workflows/report-nunit.yml +++ b/.github/workflows/report-nunit.yml @@ -28,7 +28,7 @@ jobs: timeout-minutes: 5 steps: - name: Annotate CI run with test results - uses: dorny/test-reporter@v1.4.2 + uses: dorny/test-reporter@v1.6.0 with: artifact: osu-test-results-${{matrix.os.prettyname}}-${{matrix.threadingMode}} name: Test Results (${{matrix.os.prettyname}}, ${{matrix.threadingMode}}) From af000c6e9205161e48bc988ed80eb65430401ca4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 4 Dec 2022 21:58:00 +0300 Subject: [PATCH 2514/2686] Fix `RangeSlider` potentially throwing exception on mobile platforms --- osu.Game/Graphics/UserInterface/RangeSlider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/RangeSlider.cs b/osu.Game/Graphics/UserInterface/RangeSlider.cs index 483119cd58..4e23b06c2b 100644 --- a/osu.Game/Graphics/UserInterface/RangeSlider.cs +++ b/osu.Game/Graphics/UserInterface/RangeSlider.cs @@ -197,7 +197,7 @@ namespace osu.Game.Graphics.UserInterface }, true); } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(true)] private void load(OverlayColourProvider? colourProvider) { if (colourProvider == null) return; From 486ea153fe752d6b1dc94aabc73073d76c668023 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Dec 2022 19:00:04 +0900 Subject: [PATCH 2515/2686] Add failing test --- .../Rulesets/Scoring/ScoreProcessorTest.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs index e9e94aa897..826c610f56 100644 --- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs +++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Difficulty; @@ -355,6 +356,28 @@ namespace osu.Game.Tests.Rulesets.Scoring } #pragma warning restore CS0618 + [Test] + public void TestAccuracyWhenNearPerfect() + { + const int count_judgements = 1000; + const int count_misses = 1; + + double actual = new TestScoreProcessor().ComputeAccuracy(new ScoreInfo + { + Statistics = new Dictionary + { + { HitResult.Great, count_judgements - count_misses }, + { HitResult.Miss, count_misses } + } + }); + + const double expected = (count_judgements - count_misses) / (double)count_judgements; + + Assert.That(actual, Is.Not.EqualTo(0.0)); + Assert.That(actual, Is.Not.EqualTo(1.0)); + Assert.That(actual, Is.EqualTo(expected).Within(Precision.FLOAT_EPSILON)); + } + private class TestRuleset : Ruleset { public override IEnumerable GetModsFor(ModType type) => throw new NotImplementedException(); From 9e64f8dab1ea4ec5aa847ab838d359a03e8a8755 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 5 Dec 2022 19:08:50 +0900 Subject: [PATCH 2516/2686] Fix loss of precision when computing accuracy --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 29c37c31d5..18c88dff2a 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -285,7 +285,7 @@ namespace osu.Game.Rulesets.Scoring // We only extract scoring values from the score's statistics. This is because accuracy is always relative to the point of pass or fail rather than relative to the whole beatmap. extractScoringValues(scoreInfo.Statistics, out var current, out var maximum); - return maximum.BaseScore > 0 ? current.BaseScore / maximum.BaseScore : 1; + return maximum.BaseScore > 0 ? (double)current.BaseScore / maximum.BaseScore : 1; } /// From a457a2fbbf5edd1c297cb367467b5b85974fea61 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 5 Dec 2022 14:45:29 +0300 Subject: [PATCH 2517/2686] Fix disposal of playing preview track not unmuting game track --- osu.Game/Audio/PreviewTrack.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Audio/PreviewTrack.cs b/osu.Game/Audio/PreviewTrack.cs index ea226ab650..2c63c16274 100644 --- a/osu.Game/Audio/PreviewTrack.cs +++ b/osu.Game/Audio/PreviewTrack.cs @@ -109,6 +109,8 @@ namespace osu.Game.Audio protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); + + Stop(); Track?.Dispose(); } } From b66409bd37e519d40584fcb1d06a3690595f39ce Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 5 Dec 2022 23:38:45 +0300 Subject: [PATCH 2518/2686] Perform rewind with right click only if cursor didn't leave the button --- osu.Game/Screens/Select/FooterButtonRandom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/FooterButtonRandom.cs b/osu.Game/Screens/Select/FooterButtonRandom.cs index 8d7463067e..f413126e87 100644 --- a/osu.Game/Screens/Select/FooterButtonRandom.cs +++ b/osu.Game/Screens/Select/FooterButtonRandom.cs @@ -119,7 +119,7 @@ namespace osu.Game.Screens.Select protected override void OnMouseUp(MouseUpEvent e) { - if (e.Button == MouseButton.Right) + if (e.Button == MouseButton.Right && IsHovered) { rewindSearch = true; TriggerClick(); From 0bfc46963b7ddd37ee2096b8bb1623f507d24988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 6 Dec 2022 22:46:39 +0100 Subject: [PATCH 2519/2686] Add failing test case --- .../TestSceneModDifficultyAdjustSettings.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs index 0d02a72d87..f45f5b9f59 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs @@ -126,6 +126,21 @@ namespace osu.Game.Tests.Visual.UserInterface checkBindableAtValue("Circle Size", 9); } + [Test] + public void TestExtendedLimitsRetainedAfterBoundCopyCreation() + { + setExtendedLimits(true); + setSliderValue("Circle Size", 11); + + checkSliderAtValue("Circle Size", 11); + checkBindableAtValue("Circle Size", 11); + + AddStep("create bound copy", () => _ = modDifficultyAdjust.CircleSize.GetBoundCopy()); + + checkSliderAtValue("Circle Size", 11); + checkBindableAtValue("Circle Size", 11); + } + [Test] public void TestResetToDefault() { From 81a42dc05d53d714b128b1704730d45fac85d454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 6 Dec 2022 22:50:14 +0100 Subject: [PATCH 2520/2686] Fix extended values in difficulty adjust being truncated to 10 on beatmap change --- osu.Game/Rulesets/Mods/DifficultyBindable.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/DifficultyBindable.cs b/osu.Game/Rulesets/Mods/DifficultyBindable.cs index cca72cf3ac..c21ce756c9 100644 --- a/osu.Game/Rulesets/Mods/DifficultyBindable.cs +++ b/osu.Game/Rulesets/Mods/DifficultyBindable.cs @@ -118,11 +118,18 @@ namespace osu.Game.Rulesets.Mods if (!(them is DifficultyBindable otherDifficultyBindable)) throw new InvalidOperationException($"Cannot bind to a non-{nameof(DifficultyBindable)}."); + // ensure that MaxValue and ExtendedMaxValue are copied across first before continuing. + // not doing so may cause the value of CurrentNumber to be truncated to 10. + otherDifficultyBindable.CopyTo(this); + + // set up mutual binding for ExtendedLimits to correctly set the upper bound of CurrentNumber. ExtendedLimits.BindTarget = otherDifficultyBindable.ExtendedLimits; - // the actual values need to be copied after the max value constraints. + // set up mutual binding for CurrentNumber. this must happen after all of the above. CurrentNumber.BindTarget = otherDifficultyBindable.CurrentNumber; + // finish up the binding by setting up weak references via the base call. + // unfortunately this will call `.CopyTo()` again, but fixing that is problematic and messy. base.BindTo(them); } From 30952199b8b4da83878f59fbeec88103e641a9fa Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Wed, 7 Dec 2022 00:40:18 +0100 Subject: [PATCH 2521/2686] Allow random mod to flip sliders --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 5 ++++ .../Utils/OsuHitObjectGenerationUtils.cs | 23 ++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 1621bb50b1..fc92696e9a 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -65,6 +65,11 @@ namespace osu.Game.Rulesets.Osu.Mods flowDirection = !flowDirection; } + if (positionInfos[i].HitObject is Slider slider && random.NextDouble() < 0.5) + { + OsuHitObjectGenerationUtils.FlipSlider(slider); + } + if (i == 0) { positionInfos[i].DistanceFromPrevious = (float)(random.NextDouble() * OsuPlayfield.BASE_SIZE.Y / 2); diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index 3a8b3f67d0..b081978803 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -160,14 +160,31 @@ namespace osu.Game.Rulesets.Osu.Utils public static void RotateSlider(Slider slider, float rotation) { void rotateNestedObject(OsuHitObject nested) => nested.Position = rotateVector(nested.Position - slider.Position, rotation) + slider.Position; + void rotateControlPoint(PathControlPoint point) => point.Position = rotateVector(point.Position, rotation); + modifySlider(slider, rotateNestedObject, rotateControlPoint); + } + + /// + /// Flips the slider about its start position. + /// + public static void FlipSlider(Slider slider) + { + void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(slider.Position.X - (nested.X - slider.Position.X), nested.Y); + static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y); + + modifySlider(slider, flipNestedObject, flipControlPoint); + } + + private static void modifySlider(Slider slider, Action modifyNestedObject, Action modifyControlPoint) + { // No need to update the head and tail circles, since slider handles that when the new slider path is set - slider.NestedHitObjects.OfType().ForEach(rotateNestedObject); - slider.NestedHitObjects.OfType().ForEach(rotateNestedObject); + slider.NestedHitObjects.OfType().ForEach(modifyNestedObject); + slider.NestedHitObjects.OfType().ForEach(modifyNestedObject); var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray(); foreach (var point in controlPoints) - point.Position = rotateVector(point.Position, rotation); + modifyControlPoint(point); slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); } From 91e9c275078d7ec098cacdf14fb5cb766899a65d Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Wed, 7 Dec 2022 00:48:25 +0100 Subject: [PATCH 2522/2686] Rename `FlipSlider()` to `FlipSliderHorizontally` --- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 2 +- osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index fc92696e9a..58f5b2fa8d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (positionInfos[i].HitObject is Slider slider && random.NextDouble() < 0.5) { - OsuHitObjectGenerationUtils.FlipSlider(slider); + OsuHitObjectGenerationUtils.FlipSliderHorizontally(slider); } if (i == 0) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index b081978803..42c6946414 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -166,9 +166,9 @@ namespace osu.Game.Rulesets.Osu.Utils } /// - /// Flips the slider about its start position. + /// Flips the slider about its start position horizontally. /// - public static void FlipSlider(Slider slider) + public static void FlipSliderHorizontally(Slider slider) { void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(slider.Position.X - (nested.X - slider.Position.X), nested.Y); static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y); From 8f3023ffd9c64c91258e3d7642d57f8431c12cd4 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Wed, 7 Dec 2022 01:05:15 +0100 Subject: [PATCH 2523/2686] Update `ReflectHorizontally()` and `ReflectVertically()` to use `FlipSliderHorizontally()` and `modifySlider()`. --- .../Utils/OsuHitObjectGenerationUtils.cs | 27 +++++-------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index 42c6946414..f565456911 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -116,18 +116,10 @@ namespace osu.Game.Rulesets.Osu.Utils { osuObject.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - osuObject.X, osuObject.Position.Y); - if (!(osuObject is Slider slider)) + if (osuObject is not Slider slider) return; - // No need to update the head and tail circles, since slider handles that when the new slider path is set - slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); - slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); - - var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray(); - foreach (var point in controlPoints) - point.Position = new Vector2(-point.Position.X, point.Position.Y); - - slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); + FlipSliderHorizontally(slider); } /// @@ -138,18 +130,13 @@ namespace osu.Game.Rulesets.Osu.Utils { osuObject.Position = new Vector2(osuObject.Position.X, OsuPlayfield.BASE_SIZE.Y - osuObject.Y); - if (!(osuObject is Slider slider)) + if (osuObject is not Slider slider) return; - // No need to update the head and tail circles, since slider handles that when the new slider path is set - slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); - slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); + void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(nested.X, slider.Y - (nested.Y - slider.Y)); + static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(point.Position.X, -point.Position.Y); - var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray(); - foreach (var point in controlPoints) - point.Position = new Vector2(point.Position.X, -point.Position.Y); - - slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); + modifySlider(slider, flipNestedObject, flipControlPoint); } /// @@ -170,7 +157,7 @@ namespace osu.Game.Rulesets.Osu.Utils /// public static void FlipSliderHorizontally(Slider slider) { - void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(slider.Position.X - (nested.X - slider.Position.X), nested.Y); + void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(slider.X - (nested.X - slider.X), nested.Y); static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y); modifySlider(slider, flipNestedObject, flipControlPoint); From df181acffe1869cba648a75d9dc13b1f453cb98f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 6 Dec 2022 20:10:51 +0900 Subject: [PATCH 2524/2686] Append lazer score data to .osr files --- .../Legacy/LegacyReplaySoloScoreInfo.cs | 38 +++++++++++ osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 64 ++++++++++++------- osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs | 12 +++- 3 files changed, 89 insertions(+), 25 deletions(-) create mode 100644 osu.Game/Scoring/Legacy/LegacyReplaySoloScoreInfo.cs diff --git a/osu.Game/Scoring/Legacy/LegacyReplaySoloScoreInfo.cs b/osu.Game/Scoring/Legacy/LegacyReplaySoloScoreInfo.cs new file mode 100644 index 0000000000..f2e8cf141b --- /dev/null +++ b/osu.Game/Scoring/Legacy/LegacyReplaySoloScoreInfo.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 System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Scoring.Legacy +{ + /// + /// A minified version of retrofit onto the end of legacy replay files (.osr), + /// containing the minimum data required to support storage of non-legacy replays. + /// + [Serializable] + [JsonObject(MemberSerialization.OptIn)] + public class LegacyReplaySoloScoreInfo + { + [JsonProperty("mods")] + public APIMod[] Mods { get; set; } = Array.Empty(); + + [JsonProperty("statistics")] + public Dictionary Statistics { get; set; } = new Dictionary(); + + [JsonProperty("maximum_statistics")] + public Dictionary MaximumStatistics { get; set; } = new Dictionary(); + + public static LegacyReplaySoloScoreInfo FromScore(ScoreInfo score) => new LegacyReplaySoloScoreInfo + { + Mods = score.APIMods, + Statistics = score.Statistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value), + MaximumStatistics = score.MaximumStatistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value), + }; + } +} diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs index f64e730c06..2f7727ac49 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs @@ -6,6 +6,7 @@ using System; using System.IO; using System.Linq; +using Newtonsoft.Json; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Legacy; @@ -91,31 +92,23 @@ namespace osu.Game.Scoring.Legacy else if (version >= 20121008) scoreInfo.OnlineID = sr.ReadInt32(); + byte[] compressedScoreInfo = null; + + if (version >= 30000001) + compressedScoreInfo = sr.ReadByteArray(); + if (compressedReplay?.Length > 0) + readCompressedData(compressedReplay, reader => readLegacyReplay(score.Replay, reader)); + + if (compressedScoreInfo?.Length > 0) { - using (var replayInStream = new MemoryStream(compressedReplay)) + readCompressedData(compressedScoreInfo, reader => { - byte[] properties = new byte[5]; - if (replayInStream.Read(properties, 0, 5) != 5) - throw new IOException("input .lzma is too short"); - - long outSize = 0; - - for (int i = 0; i < 8; i++) - { - int v = replayInStream.ReadByte(); - if (v < 0) - throw new IOException("Can't Read 1"); - - outSize |= (long)(byte)v << (8 * i); - } - - long compressedSize = replayInStream.Length - replayInStream.Position; - - using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize)) - using (var reader = new StreamReader(lzma)) - readLegacyReplay(score.Replay, reader); - } + LegacyReplaySoloScoreInfo readScore = JsonConvert.DeserializeObject(reader.ReadToEnd()); + score.ScoreInfo.Statistics = readScore.Statistics; + score.ScoreInfo.MaximumStatistics = readScore.MaximumStatistics; + score.ScoreInfo.Mods = readScore.Mods.Select(m => m.ToMod(currentRuleset)).ToArray(); + }); } } @@ -128,6 +121,33 @@ namespace osu.Game.Scoring.Legacy return score; } + private void readCompressedData(byte[] data, Action readFunc) + { + using (var replayInStream = new MemoryStream(data)) + { + byte[] properties = new byte[5]; + if (replayInStream.Read(properties, 0, 5) != 5) + throw new IOException("input .lzma is too short"); + + long outSize = 0; + + for (int i = 0; i < 8; i++) + { + int v = replayInStream.ReadByte(); + if (v < 0) + throw new IOException("Can't Read 1"); + + outSize |= (long)(byte)v << (8 * i); + } + + long compressedSize = replayInStream.Length - replayInStream.Position; + + using (var lzma = new LzmaStream(properties, replayInStream, compressedSize, outSize)) + using (var reader = new StreamReader(lzma)) + readFunc(reader); + } + } + /// /// Populates the accuracy of a given from its contained statistics. /// diff --git a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs index 750bb50be3..024b691de2 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs @@ -11,6 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Formats; using osu.Game.Extensions; using osu.Game.IO.Legacy; +using osu.Game.IO.Serialization; using osu.Game.Replays.Legacy; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays.Types; @@ -29,7 +30,7 @@ namespace osu.Game.Scoring.Legacy /// /// The first stable-compatible YYYYMMDD format version given to lazer usage of replays. /// - public const int FIRST_LAZER_VERSION = 30000000; + public const int FIRST_LAZER_VERSION = 30000001; private readonly Score score; private readonly IBeatmap? beatmap; @@ -77,6 +78,7 @@ namespace osu.Game.Scoring.Legacy sw.WriteByteArray(createReplayData()); sw.Write((long)0); writeModSpecificData(score.ScoreInfo, sw); + sw.WriteByteArray(createScoreInfoData()); } } @@ -84,9 +86,13 @@ namespace osu.Game.Scoring.Legacy { } - private byte[] createReplayData() + private byte[] createReplayData() => compress(replayStringContent); + + private byte[] createScoreInfoData() => compress(LegacyReplaySoloScoreInfo.FromScore(score.ScoreInfo).Serialize()); + + private byte[] compress(string data) { - byte[] content = new ASCIIEncoding().GetBytes(replayStringContent); + byte[] content = new ASCIIEncoding().GetBytes(data); using (var outStream = new MemoryStream()) { From 8709b1f2eaa2ef158149b1aaa08bfafe6109d7fc Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 7 Dec 2022 14:23:52 +0900 Subject: [PATCH 2525/2686] Immediately send ack request when joining new channels --- osu.Game/Online/Chat/ChannelManager.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index eaef940d5f..a4661dcbd7 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -529,6 +529,10 @@ namespace osu.Game.Online.Chat { Logger.Log($"Joined public channel {channel}"); joinChannel(channel, fetchInitialMessages); + + // Required after joining public channels to mark the user as online in them. + // Todo: Temporary workaround for https://github.com/ppy/osu-web/issues/9602 + SendAck(); }; req.Failure += e => { From eea7984ba936b5896b9afb26479150dafb1358cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Dec 2022 14:53:56 +0900 Subject: [PATCH 2526/2686] Remove triangle effect from latency certifier buttons --- osu.Game/Screens/Utility/ButtonWithKeyBind.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs index 29e9cd2515..7c78836b12 100644 --- a/osu.Game/Screens/Utility/ButtonWithKeyBind.cs +++ b/osu.Game/Screens/Utility/ButtonWithKeyBind.cs @@ -47,6 +47,8 @@ namespace osu.Game.Screens.Utility Height = 100; SpriteText.Colour = overlayColourProvider.Background6; SpriteText.Font = OsuFont.TorusAlternate.With(size: 34); + + Triangles?.Hide(); } } } From 49df05dd07a162955788a4cfde863272d18c1420 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 7 Dec 2022 15:07:39 +0900 Subject: [PATCH 2527/2686] Add test --- .../Formats/LegacyScoreDecoderTest.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs index cd6e5e7919..93cda34ef7 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyScoreDecoderTest.cs @@ -16,7 +16,9 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Mania.Mods; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.Osu.UI; using osu.Game.Rulesets.Replays; @@ -179,6 +181,40 @@ namespace osu.Game.Tests.Beatmaps.Formats }); } + [Test] + public void TestSoloScoreData() + { + var ruleset = new OsuRuleset().RulesetInfo; + + var scoreInfo = TestResources.CreateTestScoreInfo(ruleset); + scoreInfo.Mods = new Mod[] + { + new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } + }; + + var beatmap = new TestBeatmap(ruleset); + var score = new Score + { + ScoreInfo = scoreInfo, + Replay = new Replay + { + Frames = new List + { + new OsuReplayFrame(2000, OsuPlayfield.BASE_SIZE / 2, OsuAction.LeftButton) + } + } + }; + + var decodedAfterEncode = encodeThenDecode(LegacyBeatmapDecoder.LATEST_VERSION, score, beatmap); + + Assert.Multiple(() => + { + Assert.That(decodedAfterEncode.ScoreInfo.Statistics, Is.EqualTo(scoreInfo.Statistics)); + Assert.That(decodedAfterEncode.ScoreInfo.MaximumStatistics, Is.EqualTo(scoreInfo.MaximumStatistics)); + Assert.That(decodedAfterEncode.ScoreInfo.Mods, Is.EqualTo(scoreInfo.Mods)); + }); + } + private static Score encodeThenDecode(int beatmapVersion, Score score, TestBeatmap beatmap) { var encodeStream = new MemoryStream(); From e8766570c518cf35421db0a5a8ade5bb3caca0f0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Dec 2022 16:06:53 +0900 Subject: [PATCH 2528/2686] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 0bf415e764..5494460de2 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a176d73854..725d1d6209 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index e192467247..29777c6584 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -61,7 +61,7 @@ - + From c5e461e734f47364333432af118d398b78f6f4c9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Dec 2022 16:28:51 +0900 Subject: [PATCH 2529/2686] 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 5494460de2..61c968ebc9 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 725d1d6209..fbac6f38b0 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 29777c6584..4683437173 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From 0497e433b1de18dd7c176fd6ab63e24d74581e1c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Dec 2022 16:30:15 +0900 Subject: [PATCH 2530/2686] Change `SectionsContainer` to use flowing children for section update logic --- osu.Game/Graphics/Containers/SectionsContainer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 123589c552..8dd6eac7bb 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -240,7 +240,9 @@ namespace osu.Game.Graphics.Containers headerBackgroundContainer.Height = expandableHeaderSize + fixedHeaderSize; headerBackgroundContainer.Y = ExpandableHeader?.Y ?? 0; - float smallestSectionHeight = Children.Count > 0 ? Children.Min(d => d.Height) : 0; + var flowChildren = scrollContentContainer.FlowingChildren.OfType(); + + float smallestSectionHeight = flowChildren.Any() ? flowChildren.Min(d => d.Height) : 0; // scroll offset is our fixed header height if we have it plus 10% of content height // plus 5% to fix floating point errors and to not have a section instantly unselect when scrolling upwards @@ -249,7 +251,7 @@ namespace osu.Game.Graphics.Containers float scrollCentre = fixedHeaderSize + scrollContainer.DisplayableContent * scroll_y_centre + selectionLenienceAboveSection; - var presentChildren = Children.Where(c => c.IsPresent); + var presentChildren = flowChildren.Where(c => c.IsPresent); if (lastClickedSection != null) SelectedSection.Value = lastClickedSection; From 56e94e49a36473178712f3e865e06ea68cabb5e0 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 6 Dec 2022 23:36:11 -0800 Subject: [PATCH 2531/2686] Display nominated ranked beatmaps in user profile --- osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs | 3 ++- osu.Game/Online/API/Requests/Responses/APIUser.cs | 3 +++ .../Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs | 3 +++ osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs | 3 ++- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs index d723786f23..e4134980b1 100644 --- a/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserBeatmapsRequest.cs @@ -32,6 +32,7 @@ namespace osu.Game.Online.API.Requests Loved, Pending, Guest, - Graveyard + Graveyard, + Nominated, } } diff --git a/osu.Game/Online/API/Requests/Responses/APIUser.cs b/osu.Game/Online/API/Requests/Responses/APIUser.cs index d3ddcffaf5..2b6193f661 100644 --- a/osu.Game/Online/API/Requests/Responses/APIUser.cs +++ b/osu.Game/Online/API/Requests/Responses/APIUser.cs @@ -164,6 +164,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"guest_beatmapset_count")] public int GuestBeatmapsetCount; + [JsonProperty(@"nominated_beatmapset_count")] + public int NominatedBeatmapsetCount; + [JsonProperty(@"scores_best_count")] public int ScoresBestCount; diff --git a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs index 8c1eea6520..56d9fb9ec6 100644 --- a/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/Beatmaps/PaginatedBeatmapContainer.cs @@ -58,6 +58,9 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps case BeatmapSetType.Guest: return user.GuestBeatmapsetCount; + case BeatmapSetType.Nominated: + return user.NominatedBeatmapsetCount; + default: return 0; } diff --git a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs index 9f2e79b371..cf80ebd66f 100644 --- a/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs +++ b/osu.Game/Overlays/Profile/Sections/BeatmapsSection.cs @@ -25,7 +25,8 @@ namespace osu.Game.Overlays.Profile.Sections new PaginatedBeatmapContainer(BeatmapSetType.Loved, User, UsersStrings.ShowExtraBeatmapsLovedTitle), new PaginatedBeatmapContainer(BeatmapSetType.Guest, User, UsersStrings.ShowExtraBeatmapsGuestTitle), new PaginatedBeatmapContainer(BeatmapSetType.Pending, User, UsersStrings.ShowExtraBeatmapsPendingTitle), - new PaginatedBeatmapContainer(BeatmapSetType.Graveyard, User, UsersStrings.ShowExtraBeatmapsGraveyardTitle) + new PaginatedBeatmapContainer(BeatmapSetType.Graveyard, User, UsersStrings.ShowExtraBeatmapsGraveyardTitle), + new PaginatedBeatmapContainer(BeatmapSetType.Nominated, User, UsersStrings.ShowExtraBeatmapsNominatedTitle), }; } } From 62b0436bcf81d7274dd0c3a92c3301dc45699bc5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Dec 2022 16:31:24 +0900 Subject: [PATCH 2532/2686] Reverse depth of profile sections to allow for overflowing expanded beatmap cards Closes #21554. --- osu.Game/Overlays/UserProfileOverlay.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index b1a9b2096e..386f95cf0a 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -205,7 +205,9 @@ namespace osu.Game.Overlays protected override UserTrackingScrollContainer CreateScrollContainer() => new OverlayScrollContainer(); - protected override FlowContainer CreateScrollContentContainer() => new FillFlowContainer + // Reverse child ID is required so expanding beatmap panels can appear above sections below them. + // This can also be done by setting Depth when adding new sections above if using ReverseChildID turns out to have any issues. + protected override FlowContainer CreateScrollContentContainer() => new ReverseChildIDFillFlowContainer { Direction = FillDirection.Vertical, AutoSizeAxes = Axes.Y, From 819fd5f950f82a196ed8d4ce1b1b617a05e2f4e2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Dec 2022 17:52:57 +0900 Subject: [PATCH 2533/2686] Fix incorrect resolution of `GameHost` in `LegacyImportManager` --- osu.Game/Database/LegacyImportManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/LegacyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs index 901b953bf2..b5338fbe1f 100644 --- a/osu.Game/Database/LegacyImportManager.cs +++ b/osu.Game/Database/LegacyImportManager.cs @@ -42,8 +42,8 @@ namespace osu.Game.Database [Resolved] private RealmAccess realmAccess { get; set; } = null!; - [Resolved(canBeNull: true)] // canBeNull required while we remain on mono for mobile platforms. - private DesktopGameHost? desktopGameHost { get; set; } + [Resolved] + private GameHost gameHost { get; set; } = null!; [Resolved] private INotificationOverlay? notifications { get; set; } @@ -52,7 +52,7 @@ namespace osu.Game.Database public bool SupportsImportFromStable => RuntimeInfo.IsDesktop; - public void UpdateStorage(string stablePath) => cachedStorage = new StableStorage(stablePath, desktopGameHost); + public void UpdateStorage(string stablePath) => cachedStorage = new StableStorage(stablePath, gameHost as DesktopGameHost); public virtual async Task GetImportCount(StableContent content, CancellationToken cancellationToken) { From 0aeee8d6ab6ef72a33b09444cfff5546683df091 Mon Sep 17 00:00:00 2001 From: Loreos7 <86934170+Loreos7@users.noreply.github.com> Date: Wed, 7 Dec 2022 17:47:37 +0300 Subject: [PATCH 2534/2686] fix typo in today's tip --- osu.Game/Screens/Menu/Disclaimer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index e30be72704..539d58d2d7 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -239,7 +239,7 @@ namespace osu.Game.Screens.Menu "New features are coming online every update. Make sure to stay up-to-date!", "If you find the UI too large or small, try adjusting UI scale in settings!", "Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!", - "What used to be \"osu!direct\" is available to all users just like on the website. You can access it anywhere using Ctrl-D!", + "What used to be \"osu!direct\" is available to all users just like on the website. You can access it anywhere using Ctrl-B!", "Seeking in replays is available by dragging on the difficulty bar at the bottom of the screen!", "Multithreading support means that even with low \"FPS\" your input and judgements will be accurate!", "Try scrolling down in the mod select panel to find a bunch of new fun mods!", From 1776485b93eeb2ff0b7e5ccf1657aa5704dac997 Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Wed, 7 Dec 2022 20:20:11 +0000 Subject: [PATCH 2535/2686] Reflect nested objects vertically in the playfield correctly --- osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index f565456911..5b327fc3b0 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -133,7 +133,7 @@ namespace osu.Game.Rulesets.Osu.Utils if (osuObject is not Slider slider) return; - void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(nested.X, slider.Y - (nested.Y - slider.Y)); + void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(nested.Position.X, OsuPlayfield.BASE_SIZE.Y - nested.Position.Y); static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(point.Position.X, -point.Position.Y); modifySlider(slider, flipNestedObject, flipControlPoint); From 684b16cef5dc7338ef3333106e3433de8085153f Mon Sep 17 00:00:00 2001 From: apollo-dw <83023433+apollo-dw@users.noreply.github.com> Date: Wed, 7 Dec 2022 21:09:53 +0000 Subject: [PATCH 2536/2686] Disambiguate object flipping and reflection methods --- osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs | 2 +- osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs | 8 ++--- osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs | 2 +- .../Utils/OsuHitObjectGenerationUtils.cs | 32 +++++++++++-------- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs index 5430929143..19d4a1bf83 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModHardRock.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods { var osuObject = (OsuHitObject)hitObject; - OsuHitObjectGenerationUtils.ReflectVertically(osuObject); + OsuHitObjectGenerationUtils.ReflectVerticallyAlongPlayfield(osuObject); } } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs index 0a54d58718..6d01808fb5 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModMirror.cs @@ -27,16 +27,16 @@ namespace osu.Game.Rulesets.Osu.Mods switch (Reflection.Value) { case MirrorType.Horizontal: - OsuHitObjectGenerationUtils.ReflectHorizontally(osuObject); + OsuHitObjectGenerationUtils.ReflectHorizontallyAlongPlayfield(osuObject); break; case MirrorType.Vertical: - OsuHitObjectGenerationUtils.ReflectVertically(osuObject); + OsuHitObjectGenerationUtils.ReflectVerticallyAlongPlayfield(osuObject); break; case MirrorType.Both: - OsuHitObjectGenerationUtils.ReflectHorizontally(osuObject); - OsuHitObjectGenerationUtils.ReflectVertically(osuObject); + OsuHitObjectGenerationUtils.ReflectHorizontallyAlongPlayfield(osuObject); + OsuHitObjectGenerationUtils.ReflectVerticallyAlongPlayfield(osuObject); break; } } diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs index 58f5b2fa8d..307d731fd4 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRandom.cs @@ -67,7 +67,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (positionInfos[i].HitObject is Slider slider && random.NextDouble() < 0.5) { - OsuHitObjectGenerationUtils.FlipSliderHorizontally(slider); + OsuHitObjectGenerationUtils.FlipSliderInPlaceHorizontally(slider); } if (i == 0) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index 5b327fc3b0..15bc03261f 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -112,21 +112,24 @@ namespace osu.Game.Rulesets.Osu.Utils /// Reflects the position of the in the playfield horizontally. /// /// The object to reflect. - public static void ReflectHorizontally(OsuHitObject osuObject) + public static void ReflectHorizontallyAlongPlayfield(OsuHitObject osuObject) { osuObject.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - osuObject.X, osuObject.Position.Y); if (osuObject is not Slider slider) return; - FlipSliderHorizontally(slider); + void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - nested.Position.X, nested.Position.Y); + static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y); + + modifySlider(slider, flipNestedObject, flipControlPoint); } /// /// Reflects the position of the in the playfield vertically. /// /// The object to reflect. - public static void ReflectVertically(OsuHitObject osuObject) + public static void ReflectVerticallyAlongPlayfield(OsuHitObject osuObject) { osuObject.Position = new Vector2(osuObject.Position.X, OsuPlayfield.BASE_SIZE.Y - osuObject.Y); @@ -139,6 +142,18 @@ namespace osu.Game.Rulesets.Osu.Utils modifySlider(slider, flipNestedObject, flipControlPoint); } + /// + /// Flips the position of the around its start position horizontally. + /// + /// The slider to be flipped. + public static void FlipSliderInPlaceHorizontally(Slider slider) + { + void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(slider.X - (nested.X - slider.X), nested.Y); + static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y); + + modifySlider(slider, flipNestedObject, flipControlPoint); + } + /// /// Rotate a slider about its start position by the specified angle. /// @@ -152,17 +167,6 @@ namespace osu.Game.Rulesets.Osu.Utils modifySlider(slider, rotateNestedObject, rotateControlPoint); } - /// - /// Flips the slider about its start position horizontally. - /// - public static void FlipSliderHorizontally(Slider slider) - { - void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(slider.X - (nested.X - slider.X), nested.Y); - static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y); - - modifySlider(slider, flipNestedObject, flipControlPoint); - } - private static void modifySlider(Slider slider, Action modifyNestedObject, Action modifyControlPoint) { // No need to update the head and tail circles, since slider handles that when the new slider path is set From 7676838cc04d162c37d87749d275b582cbed8e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 7 Dec 2022 23:27:02 +0100 Subject: [PATCH 2537/2686] Apply "reflect" vernacular in nested methods --- .../Utils/OsuHitObjectGenerationUtils.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index 15bc03261f..aa4cd0af14 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -119,10 +119,10 @@ namespace osu.Game.Rulesets.Osu.Utils if (osuObject is not Slider slider) return; - void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - nested.Position.X, nested.Position.Y); - static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y); + void reflectNestedObject(OsuHitObject nested) => nested.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - nested.Position.X, nested.Position.Y); + static void reflectControlPoint(PathControlPoint point) => point.Position = new Vector2(-point.Position.X, point.Position.Y); - modifySlider(slider, flipNestedObject, flipControlPoint); + modifySlider(slider, reflectNestedObject, reflectControlPoint); } /// @@ -136,10 +136,10 @@ namespace osu.Game.Rulesets.Osu.Utils if (osuObject is not Slider slider) return; - void flipNestedObject(OsuHitObject nested) => nested.Position = new Vector2(nested.Position.X, OsuPlayfield.BASE_SIZE.Y - nested.Position.Y); - static void flipControlPoint(PathControlPoint point) => point.Position = new Vector2(point.Position.X, -point.Position.Y); + void reflectNestedObject(OsuHitObject nested) => nested.Position = new Vector2(nested.Position.X, OsuPlayfield.BASE_SIZE.Y - nested.Position.Y); + static void reflectControlPoint(PathControlPoint point) => point.Position = new Vector2(point.Position.X, -point.Position.Y); - modifySlider(slider, flipNestedObject, flipControlPoint); + modifySlider(slider, reflectNestedObject, reflectControlPoint); } /// From 5807d4c43dcc2dfd7f8b9b61e277b2dc35c862da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 7 Dec 2022 23:50:01 +0100 Subject: [PATCH 2538/2686] Add test coverage for slider transformations --- .../OsuHitObjectGenerationUtilsTest.cs | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/OsuHitObjectGenerationUtilsTest.cs diff --git a/osu.Game.Rulesets.Osu.Tests/OsuHitObjectGenerationUtilsTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuHitObjectGenerationUtilsTest.cs new file mode 100644 index 0000000000..daa914cac2 --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/OsuHitObjectGenerationUtilsTest.cs @@ -0,0 +1,91 @@ +// 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 NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.Osu.Utils; +using osuTK; + +namespace osu.Game.Rulesets.Osu.Tests +{ + [TestFixture] + public class OsuHitObjectGenerationUtilsTest + { + private static Slider createTestSlider() + { + var slider = new Slider + { + Position = new Vector2(128, 128), + Path = new SliderPath + { + ControlPoints = + { + new PathControlPoint(new Vector2(), PathType.Linear), + new PathControlPoint(new Vector2(-64, -128), PathType.Linear), // absolute position: (64, 0) + new PathControlPoint(new Vector2(-128, 0), PathType.Linear) // absolute position: (0, 128) + } + }, + RepeatCount = 1 + }; + slider.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); + return slider; + } + + [Test] + public void TestReflectSliderHorizontallyAlongPlayfield() + { + var slider = createTestSlider(); + + OsuHitObjectGenerationUtils.ReflectHorizontallyAlongPlayfield(slider); + + Assert.That(slider.Position, Is.EqualTo(new Vector2(OsuPlayfield.BASE_SIZE.X - 128, 128))); + Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(OsuPlayfield.BASE_SIZE.X - 0, 128))); + Assert.That(slider.Path.ControlPoints.Select(point => point.Position), Is.EquivalentTo(new[] + { + new Vector2(), + new Vector2(64, -128), + new Vector2(128, 0) + })); + } + + [Test] + public void TestReflectSliderVerticallyAlongPlayfield() + { + var slider = createTestSlider(); + + OsuHitObjectGenerationUtils.ReflectVerticallyAlongPlayfield(slider); + + Assert.That(slider.Position, Is.EqualTo(new Vector2(128, OsuPlayfield.BASE_SIZE.Y - 128))); + Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(0, OsuPlayfield.BASE_SIZE.Y - 128))); + Assert.That(slider.Path.ControlPoints.Select(point => point.Position), Is.EquivalentTo(new[] + { + new Vector2(), + new Vector2(-64, 128), + new Vector2(-128, 0) + })); + } + + [Test] + public void TestFlipSliderInPlaceHorizontally() + { + var slider = createTestSlider(); + + OsuHitObjectGenerationUtils.FlipSliderInPlaceHorizontally(slider); + + Assert.That(slider.Position, Is.EqualTo(new Vector2(128, 128))); + Assert.That(slider.NestedHitObjects.OfType().Single().Position, Is.EqualTo(new Vector2(256, 128))); + Assert.That(slider.Path.ControlPoints.Select(point => point.Position), Is.EquivalentTo(new[] + { + new Vector2(), + new Vector2(64, -128), + new Vector2(128, 0) + })); + } + } +} From e00c075482a0be3f9ac52284328e95c56ac7d377 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 8 Dec 2022 11:30:18 +0900 Subject: [PATCH 2539/2686] Fix incorrectly modified first lazer version --- osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs index 024b691de2..63094c5548 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs @@ -25,12 +25,12 @@ namespace osu.Game.Scoring.Legacy /// Database version in stable-compatible YYYYMMDD format. /// Should be incremented if any changes are made to the format/usage. /// - public const int LATEST_VERSION = FIRST_LAZER_VERSION; + public const int LATEST_VERSION = 30000001; /// /// The first stable-compatible YYYYMMDD format version given to lazer usage of replays. /// - public const int FIRST_LAZER_VERSION = 30000001; + public const int FIRST_LAZER_VERSION = 30000000; private readonly Score score; private readonly IBeatmap? beatmap; From f21e903a94609400f2af8d24587c17dac6e1969d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 8 Dec 2022 14:06:38 +0900 Subject: [PATCH 2540/2686] 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 61c968ebc9..a4900132b1 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fbac6f38b0..3cb569bdd4 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 4683437173..184e3303c8 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From cdf76077b290db2eb583161f71782607c1d8d6af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Dec 2022 05:38:06 +0000 Subject: [PATCH 2541/2686] Bump Newtonsoft.Json from 13.0.1 to 13.0.2 in /osu.Game Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 13.0.1 to 13.0.2. - [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases) - [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/13.0.1...13.0.2) --- updated-dependencies: - dependency-name: Newtonsoft.Json dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 3cb569bdd4..8639ce6361 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -29,7 +29,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 34ad1e1d61223d289a59879d34d44f6504178c74 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Thu, 8 Dec 2022 22:50:29 +0100 Subject: [PATCH 2542/2686] Fix Android linker removing `System.Globalisation.*Calendar` --- osu.Android.props | 3 +++ osu.Android/Linker.xml | 7 +++++++ 2 files changed, 10 insertions(+) create mode 100644 osu.Android/Linker.xml diff --git a/osu.Android.props b/osu.Android.props index a4900132b1..147d236d98 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -58,4 +58,7 @@ + + + diff --git a/osu.Android/Linker.xml b/osu.Android/Linker.xml new file mode 100644 index 0000000000..c7d31fe087 --- /dev/null +++ b/osu.Android/Linker.xml @@ -0,0 +1,7 @@ + + + + + + + From 27a96b8e6d92c93b5fa4a9323898d1c05be60569 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Thu, 8 Dec 2022 22:52:10 +0100 Subject: [PATCH 2543/2686] Add linker exception to iOS out of an abundance of caution --- osu.iOS/Linker.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.iOS/Linker.xml b/osu.iOS/Linker.xml index 04591c55d0..b55be3be39 100644 --- a/osu.iOS/Linker.xml +++ b/osu.iOS/Linker.xml @@ -24,4 +24,8 @@ + + + + From 3570fa8d930abc35d6ec5990161dba9f0e733055 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 9 Dec 2022 17:12:20 +0900 Subject: [PATCH 2544/2686] Fix hub clients not reconnecting after connection error --- osu.Game/Online/PersistentEndpointClientConnector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index be76644745..55e9190f99 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -150,7 +150,7 @@ namespace osu.Game.Online await disconnect(true); if (ex != null) - await handleErrorAndDelay(ex, cancellationToken).ConfigureAwait(false); + await handleErrorAndDelay(ex, CancellationToken.None).ConfigureAwait(false); else Logger.Log($"{ClientName} disconnected", LoggingTarget.Network); From 4a65f5c8647ec402904c9736c865f980e7c5c1ae Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 9 Dec 2022 16:05:36 +0900 Subject: [PATCH 2545/2686] Add score token to spectator state --- osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs | 2 +- .../Visual/Gameplay/TestSceneSpectatorPlayback.cs | 2 +- osu.Game/Online/Spectator/SpectatorClient.cs | 3 ++- osu.Game/Online/Spectator/SpectatorState.cs | 7 +++++-- osu.Game/Screens/Play/SubmittingPlayer.cs | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index 8f1eb98c79..4f319a7c34 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -261,7 +261,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestFinalFramesPurgedBeforeEndingPlay() { - AddStep("begin playing", () => spectatorClient.BeginPlaying(TestGameplayState.Create(new OsuRuleset()), new Score())); + AddStep("begin playing", () => spectatorClient.BeginPlaying(TestGameplayState.Create(new OsuRuleset()), new Score(), 0)); AddStep("send frames and finish play", () => { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs index 1ad1da0994..a949c0d79d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs @@ -147,7 +147,7 @@ namespace osu.Game.Tests.Visual.Gameplay } }; - spectatorClient.BeginPlaying(TestGameplayState.Create(new OsuRuleset()), recordingScore); + spectatorClient.BeginPlaying(TestGameplayState.Create(new OsuRuleset()), recordingScore, 0); spectatorClient.OnNewFrames += onNewFrames; }); } diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index b0ee0bc37b..c532cb266d 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -159,7 +159,7 @@ namespace osu.Game.Online.Spectator return Task.CompletedTask; } - public void BeginPlaying(GameplayState state, Score score) + public void BeginPlaying(GameplayState state, Score score, long? token) { // This schedule is only here to match the one below in `EndPlaying`. Schedule(() => @@ -175,6 +175,7 @@ namespace osu.Game.Online.Spectator currentState.Mods = score.ScoreInfo.Mods.Select(m => new APIMod(m)).ToArray(); currentState.State = SpectatedUserState.Playing; currentState.MaximumScoringValues = state.ScoreProcessor.MaximumScoringValues; + currentState.ScoreToken = token; currentBeatmap = state.Beatmap; currentScore = score; diff --git a/osu.Game/Online/Spectator/SpectatorState.cs b/osu.Game/Online/Spectator/SpectatorState.cs index 766b274e63..34dbefd2a5 100644 --- a/osu.Game/Online/Spectator/SpectatorState.cs +++ b/osu.Game/Online/Spectator/SpectatorState.cs @@ -33,14 +33,17 @@ namespace osu.Game.Online.Spectator [Key(4)] public ScoringValues MaximumScoringValues { get; set; } + [Key(5)] + public long? ScoreToken { get; set; } + public bool Equals(SpectatorState other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return BeatmapID == other.BeatmapID && Mods.SequenceEqual(other.Mods) && RulesetID == other.RulesetID && State == other.State; + return BeatmapID == other.BeatmapID && Mods.SequenceEqual(other.Mods) && RulesetID == other.RulesetID && State == other.State && ScoreToken == other.ScoreToken; } - public override string ToString() => $"Beatmap:{BeatmapID} Mods:{string.Join(',', Mods)} Ruleset:{RulesetID} State:{State}"; + public override string ToString() => $"Beatmap:{BeatmapID} Mods:{string.Join(',', Mods)} Ruleset:{RulesetID} State:{State} Token:{ScoreToken}"; } } diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index 14453c8cbe..81c4e9ab2a 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -148,7 +148,7 @@ namespace osu.Game.Screens.Play realmBeatmap.LastPlayed = DateTimeOffset.Now; }); - spectatorClient.BeginPlaying(GameplayState, Score); + spectatorClient.BeginPlaying(GameplayState, Score, token); } public override bool OnExiting(ScreenExitEvent e) From e9998f1690003675f8b8642b98f34e72c18584c2 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 9 Dec 2022 20:15:07 +0900 Subject: [PATCH 2546/2686] Store maximum statistics to spectator state --- .../Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs | 6 ++---- osu.Game/Online/Spectator/SpectatorClient.cs | 2 +- osu.Game/Online/Spectator/SpectatorScoreProcessor.cs | 4 ++-- osu.Game/Online/Spectator/SpectatorState.cs | 4 ++-- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 7 ++----- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs index fa7d2c04f4..649c662e41 100644 --- a/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/MultiplayerGameplayLeaderboardTestScene.cs @@ -117,11 +117,9 @@ namespace osu.Game.Tests.Visual.Multiplayer BeatmapID = 0, RulesetID = 0, Mods = user.Mods, - MaximumScoringValues = new ScoringValues + MaximumStatistics = new Dictionary { - BaseScore = 10000, - MaxCombo = 1000, - CountBasicHitObjects = 1000 + { HitResult.Perfect, 100 } } }; } diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index b0ee0bc37b..0a499a202c 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -174,7 +174,7 @@ namespace osu.Game.Online.Spectator currentState.RulesetID = score.ScoreInfo.RulesetID; currentState.Mods = score.ScoreInfo.Mods.Select(m => new APIMod(m)).ToArray(); currentState.State = SpectatedUserState.Playing; - currentState.MaximumScoringValues = state.ScoreProcessor.MaximumScoringValues; + currentState.MaximumStatistics = state.ScoreProcessor.MaximumStatistics; currentBeatmap = state.Beatmap; currentScore = score; diff --git a/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs b/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs index c97871c3aa..75b6a6e83b 100644 --- a/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs +++ b/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs @@ -152,12 +152,12 @@ namespace osu.Game.Online.Spectator scoreInfo.MaxCombo = frame.Header.MaxCombo; scoreInfo.Statistics = frame.Header.Statistics; + scoreInfo.MaximumStatistics = spectatorState.MaximumStatistics; Accuracy.Value = frame.Header.Accuracy; Combo.Value = frame.Header.Combo; - scoreProcessor.ExtractScoringValues(frame.Header, out var currentScoringValues, out _); - TotalScore.Value = scoreProcessor.ComputeScore(Mode.Value, currentScoringValues, spectatorState.MaximumScoringValues); + TotalScore.Value = scoreProcessor.ComputeScore(Mode.Value, scoreInfo); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Online/Spectator/SpectatorState.cs b/osu.Game/Online/Spectator/SpectatorState.cs index 766b274e63..91df05bf96 100644 --- a/osu.Game/Online/Spectator/SpectatorState.cs +++ b/osu.Game/Online/Spectator/SpectatorState.cs @@ -9,7 +9,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using MessagePack; using osu.Game.Online.API; -using osu.Game.Scoring; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Online.Spectator { @@ -31,7 +31,7 @@ namespace osu.Game.Online.Spectator public SpectatedUserState State { get; set; } [Key(4)] - public ScoringValues MaximumScoringValues { get; set; } + public Dictionary MaximumStatistics { get; set; } = new Dictionary(); public bool Equals(SpectatorState other) { diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 18c88dff2a..b2b31c5394 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -90,17 +90,14 @@ namespace osu.Game.Rulesets.Scoring private readonly double accuracyPortion; private readonly double comboPortion; - /// - /// Scoring values for a perfect play. - /// - public ScoringValues MaximumScoringValues + public Dictionary MaximumStatistics { get { if (!beatmapApplied) throw new InvalidOperationException($"Cannot access maximum scoring values before calling {nameof(ApplyBeatmap)}."); - return maximumScoringValues; + return maximumResultCounts.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); } } From 0372e38f577e7ef82a5ca5e6a0907125823df671 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 11 Dec 2022 13:00:12 +0900 Subject: [PATCH 2547/2686] Add nullability assertion to appease CI --- osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs index 2f7727ac49..15ed992c3e 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Diagnostics; using System.IO; using System.Linq; using Newtonsoft.Json; @@ -105,6 +106,9 @@ namespace osu.Game.Scoring.Legacy readCompressedData(compressedScoreInfo, reader => { LegacyReplaySoloScoreInfo readScore = JsonConvert.DeserializeObject(reader.ReadToEnd()); + + Debug.Assert(readScore != null); + score.ScoreInfo.Statistics = readScore.Statistics; score.ScoreInfo.MaximumStatistics = readScore.MaximumStatistics; score.ScoreInfo.Mods = readScore.Mods.Select(m => m.ToMod(currentRuleset)).ToArray(); From 85039209f80347462f9d25d0026dfdaa966015b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Dec 2022 01:56:32 +0900 Subject: [PATCH 2548/2686] Fix parsing of ruleset configuration values being incorrect on some locales Closes #21611. --- osu.Game/Rulesets/Configuration/RulesetConfigManager.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs b/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs index 4ff4f66665..0eea1ff215 100644 --- a/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs +++ b/osu.Game/Rulesets/Configuration/RulesetConfigManager.cs @@ -5,9 +5,11 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using osu.Framework.Bindables; using osu.Framework.Configuration; +using osu.Framework.Extensions; using osu.Game.Configuration; using osu.Game.Database; @@ -67,7 +69,7 @@ namespace osu.Game.Rulesets.Configuration { var setting = r.All().First(s => s.RulesetName == rulesetName && s.Variant == variant && s.Key == c.ToString()); - setting.Value = ConfigStore[c].ToString(); + setting.Value = ConfigStore[c].ToString(CultureInfo.InvariantCulture); } }); @@ -89,7 +91,7 @@ namespace osu.Game.Rulesets.Configuration setting = new RealmRulesetSetting { Key = lookup.ToString(), - Value = bindable.Value.ToString(), + Value = bindable.ToString(CultureInfo.InvariantCulture), RulesetName = rulesetName, Variant = variant, }; From 133256879685caf181defefe128ddd9e752e51cd Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 12 Dec 2022 03:10:13 +0300 Subject: [PATCH 2549/2686] Fix SettingsButton receiving input at padded area --- .../UserInterface/TestSceneSettingsButton.cs | 41 +++++++++++++++++++ osu.Game/Overlays/Settings/SettingsButton.cs | 4 ++ 2 files changed, 45 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneSettingsButton.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsButton.cs new file mode 100644 index 0000000000..4353e7ffef --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsButton.cs @@ -0,0 +1,41 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Game.Overlays.Settings; +using NUnit.Framework; +using osuTK; +using osu.Game.Overlays; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public partial class TestSceneSettingsButton : OsuManualInputManagerTestScene + { + private readonly SettingsButton settingsButton; + + public TestSceneSettingsButton() + { + Add(new Container + { + AutoSizeAxes = Axes.Y, + Width = 500, + Child = settingsButton = new SettingsButton + { + Enabled = { Value = true }, + Text = "Test settings button" + } + }); + } + + [Test] + public void TestInputAtPaddedArea() + { + AddStep("Move cursor to button", () => InputManager.MoveMouseTo(settingsButton)); + AddAssert("Button is hovered", () => settingsButton.IsHovered); + AddStep("Move cursor to padded area", () => InputManager.MoveMouseTo(settingsButton.ScreenSpaceDrawQuad.TopLeft + new Vector2(SettingsPanel.CONTENT_MARGINS / 2f, 10))); + AddAssert("Cursor within a button", () => settingsButton.ScreenSpaceDrawQuad.Contains(InputManager.CurrentState.Mouse.Position)); + AddAssert("Button is not hovered", () => !settingsButton.IsHovered); + } + } +} diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index 5091ddc2d0..68cb95a2d8 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -9,11 +9,15 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterfaceV2; +using osuTK; namespace osu.Game.Overlays.Settings { public partial class SettingsButton : RoundedButton, IHasTooltip, IConditionalFilterable { + // We don't want to receive input at the padded area + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Content.ReceivePositionalInputAt(screenSpacePos); + public SettingsButton() { RelativeSizeAxes = Axes.X; From 5e8d75bbbfdf02e10eba7a7b95cd07920a9baaa6 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 12 Dec 2022 11:39:03 +0900 Subject: [PATCH 2550/2686] Remove unused overload --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 25 --------------------- 1 file changed, 25 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index b2b31c5394..cdef3e5afb 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -487,31 +487,6 @@ namespace osu.Game.Rulesets.Scoring extractScoringValues(scoreInfo.MaximumStatistics, out _, out maximum); } - /// - /// Applies a best-effort extraction of hit statistics into . - /// - /// - /// This method is useful in a variety of situations, with a few drawbacks that need to be considered: - /// - /// The maximum will always be 0. - /// The current and maximum will always be the same value. - /// - /// Consumers are expected to more accurately fill in the above values through external means. - /// - /// Ensure to fill in the maximum for use in - /// . - /// - /// - /// The replay frame header to extract scoring values from. - /// The "current" scoring values, representing the hit statistics as they appear. - /// The "maximum" scoring values, representing the hit statistics as if the maximum hit result was attained each time. - [Pure] - internal void ExtractScoringValues(FrameHeader header, out ScoringValues current, out ScoringValues maximum) - { - extractScoringValues(header.Statistics, out current, out maximum); - current.MaxCombo = header.MaxCombo; - } - /// /// Applies a best-effort extraction of hit statistics into . /// From 6e41efede88ba6bdabd2e54a645f7303c256e898 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 12 Dec 2022 11:40:15 +0900 Subject: [PATCH 2551/2686] Simplify dictionary construction --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index cdef3e5afb..7e94ea2b36 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -95,9 +95,9 @@ namespace osu.Game.Rulesets.Scoring get { if (!beatmapApplied) - throw new InvalidOperationException($"Cannot access maximum scoring values before calling {nameof(ApplyBeatmap)}."); + throw new InvalidOperationException($"Cannot access maximum statistics before calling {nameof(ApplyBeatmap)}."); - return maximumResultCounts.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + return new Dictionary(maximumResultCounts); } } From 7a54bcac57b193a9b2c1f268fe4751a9da691703 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 12 Dec 2022 11:41:07 +0900 Subject: [PATCH 2552/2686] Remove unused using --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 7e94ea2b36..5e05c7e2a6 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -10,7 +10,6 @@ using osu.Framework.Bindables; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Extensions; -using osu.Game.Online.Spectator; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; From e76c56b03b1039b75010528a20cd9284b0833949 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 11 Dec 2022 20:10:06 -0800 Subject: [PATCH 2553/2686] Fix changelog single build dates disappearing before being off screen --- osu.Game/Overlays/Changelog/ChangelogBuild.cs | 10 ++++-- .../Changelog/ChangelogSingleBuild.cs | 32 ++++++++++--------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs index fd7a3f8791..96d5203d14 100644 --- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs @@ -68,11 +68,15 @@ namespace osu.Game.Overlays.Changelog Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, + Direction = FillDirection.Vertical, Margin = new MarginPadding { Top = 20 }, - Children = new Drawable[] + Child = new FillFlowContainer { - new OsuHoverContainer + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Child = new OsuHoverContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index ddee6ff8bb..902aa72178 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -104,27 +104,29 @@ namespace osu.Game.Overlays.Changelog { var fill = base.CreateHeader(); - foreach (var existing in fill.Children.OfType()) + var nestedFill = fill.Children.OfType().First(); + + var buildDisplay = nestedFill.Children.OfType().First(); + + buildDisplay.Scale = new Vector2(1.25f); + buildDisplay.Action = null; + + fill.Add(date = new OsuSpriteText { - existing.Scale = new Vector2(1.25f); - existing.Action = null; + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = Build.CreatedAt.Date.ToString("dd MMMM yyyy"), + Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 14), + Margin = new MarginPadding { Top = 5 }, + Scale = new Vector2(1.25f), + }); - existing.Add(date = new OsuSpriteText - { - Text = Build.CreatedAt.Date.ToString("dd MMMM yyyy"), - Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 14), - Anchor = Anchor.BottomCentre, - Origin = Anchor.TopCentre, - Margin = new MarginPadding { Top = 5 }, - }); - } - - fill.Insert(-1, new NavigationIconButton(Build.Versions?.Previous) + nestedFill.Insert(-1, new NavigationIconButton(Build.Versions?.Previous) { Icon = FontAwesome.Solid.ChevronLeft, SelectBuild = b => SelectBuild(b) }); - fill.Insert(1, new NavigationIconButton(Build.Versions?.Next) + nestedFill.Insert(1, new NavigationIconButton(Build.Versions?.Next) { Icon = FontAwesome.Solid.ChevronRight, SelectBuild = b => SelectBuild(b) From 731184eb39b7ad0f6d11c4aeaf32eaef52a11316 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Dec 2022 13:43:01 +0900 Subject: [PATCH 2554/2686] Revert "Merge pull request #21614 from EVAST9919/button-fix" This reverts commit 4bd196684fe26b146986b04f8af5c75735774817, reversing changes made to a1d22ef77a0dd71aff97b17fd656ac68d347d4d7. --- .../UserInterface/TestSceneSettingsButton.cs | 41 ------------------- osu.Game/Overlays/Settings/SettingsButton.cs | 4 -- 2 files changed, 45 deletions(-) delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneSettingsButton.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsButton.cs deleted file mode 100644 index 4353e7ffef..0000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSettingsButton.cs +++ /dev/null @@ -1,41 +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.Graphics.Containers; -using osu.Framework.Graphics; -using osu.Game.Overlays.Settings; -using NUnit.Framework; -using osuTK; -using osu.Game.Overlays; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public partial class TestSceneSettingsButton : OsuManualInputManagerTestScene - { - private readonly SettingsButton settingsButton; - - public TestSceneSettingsButton() - { - Add(new Container - { - AutoSizeAxes = Axes.Y, - Width = 500, - Child = settingsButton = new SettingsButton - { - Enabled = { Value = true }, - Text = "Test settings button" - } - }); - } - - [Test] - public void TestInputAtPaddedArea() - { - AddStep("Move cursor to button", () => InputManager.MoveMouseTo(settingsButton)); - AddAssert("Button is hovered", () => settingsButton.IsHovered); - AddStep("Move cursor to padded area", () => InputManager.MoveMouseTo(settingsButton.ScreenSpaceDrawQuad.TopLeft + new Vector2(SettingsPanel.CONTENT_MARGINS / 2f, 10))); - AddAssert("Cursor within a button", () => settingsButton.ScreenSpaceDrawQuad.Contains(InputManager.CurrentState.Mouse.Position)); - AddAssert("Button is not hovered", () => !settingsButton.IsHovered); - } - } -} diff --git a/osu.Game/Overlays/Settings/SettingsButton.cs b/osu.Game/Overlays/Settings/SettingsButton.cs index 68cb95a2d8..5091ddc2d0 100644 --- a/osu.Game/Overlays/Settings/SettingsButton.cs +++ b/osu.Game/Overlays/Settings/SettingsButton.cs @@ -9,15 +9,11 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterfaceV2; -using osuTK; namespace osu.Game.Overlays.Settings { public partial class SettingsButton : RoundedButton, IHasTooltip, IConditionalFilterable { - // We don't want to receive input at the padded area - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Content.ReceivePositionalInputAt(screenSpacePos); - public SettingsButton() { RelativeSizeAxes = Axes.X; From f27603dd6de7521a8fb0bd98334325de5dffe6ad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 17:46:01 +0900 Subject: [PATCH 2555/2686] Use hard links instead of file copy when available --- osu.Game/Database/RealmFileStore.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index 036b15ea17..56ea8f23bc 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -4,6 +4,8 @@ using System; using System.IO; using System.Linq; +using System.Runtime.InteropServices; +using osu.Framework; using osu.Framework.Extensions; using osu.Framework.IO.Stores; using osu.Framework.Logging; @@ -60,6 +62,13 @@ namespace osu.Game.Database private void copyToStore(RealmFile file, Stream data) { + if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows && data is FileStream fs) + { + // attempt to do a fast hard link rather than copy. + if (CreateHardLink(Storage.GetFullPath(file.GetStoragePath()), fs.Name, IntPtr.Zero)) + return; + } + data.Seek(0, SeekOrigin.Begin); using (var output = Storage.CreateFileSafely(file.GetStoragePath())) @@ -68,6 +77,13 @@ namespace osu.Game.Database data.Seek(0, SeekOrigin.Begin); } + [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)] + private static extern bool CreateHardLink( + string lpFileName, + string lpExistingFileName, + IntPtr lpSecurityAttributes + ); + private bool checkFileExistsAndMatchesHash(RealmFile file) { string path = file.GetStoragePath(); From 3b1920c060b9352654b3f2d429548bffcbbbc4a0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 18:18:29 +0900 Subject: [PATCH 2556/2686] Add code to check whether a file is a hard link --- osu.Game/Database/RealmFileStore.cs | 48 +++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index 56ea8f23bc..4aa65dd50a 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -5,6 +5,8 @@ using System; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using Microsoft.Win32.SafeHandles; using osu.Framework; using osu.Framework.Extensions; using osu.Framework.IO.Stores; @@ -77,6 +79,20 @@ namespace osu.Game.Database data.Seek(0, SeekOrigin.Begin); } + public static int GetFileLinkCount(string filePath) + { + int result = 0; + SafeFileHandle handle = CreateFile(filePath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Archive, IntPtr.Zero); + + ByHandleFileInformation fileInfo; + + if (GetFileInformationByHandle(handle, out fileInfo)) + result = (int)fileInfo.NumberOfLinks; + CloseHandle(handle); + + return result; + } + [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)] private static extern bool CreateHardLink( string lpFileName, @@ -84,6 +100,38 @@ namespace osu.Game.Database IntPtr lpSecurityAttributes ); + [StructLayout(LayoutKind.Sequential)] + private struct ByHandleFileInformation + { + public readonly uint FileAttributes; + public readonly FILETIME CreationTime; + public readonly FILETIME LastAccessTime; + public readonly FILETIME LastWriteTime; + public readonly uint VolumeSerialNumber; + public readonly uint FileSizeHigh; + public readonly uint FileSizeLow; + public readonly uint NumberOfLinks; + public readonly uint FileIndexHigh; + public readonly uint FileIndexLow; + } + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern SafeFileHandle CreateFile( + string lpFileName, + [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess, + [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, + IntPtr lpSecurityAttributes, + [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, + [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes, + IntPtr hTemplateFile); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool GetFileInformationByHandle(SafeFileHandle handle, out ByHandleFileInformation lpFileInformation); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool CloseHandle(SafeHandle hObject); + private bool checkFileExistsAndMatchesHash(RealmFile file) { string path = file.GetStoragePath(); From 902dff15e38be4259e79d022bec5b39c3a466861 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 18:20:49 +0900 Subject: [PATCH 2557/2686] Add todo regarding validity check --- osu.Game/Beatmaps/WorkingBeatmapCache.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/WorkingBeatmapCache.cs b/osu.Game/Beatmaps/WorkingBeatmapCache.cs index adb5f8c433..e6f96330e7 100644 --- a/osu.Game/Beatmaps/WorkingBeatmapCache.cs +++ b/osu.Game/Beatmaps/WorkingBeatmapCache.cs @@ -141,6 +141,9 @@ namespace osu.Game.Beatmaps try { string fileStorePath = BeatmapSetInfo.GetPathForFile(BeatmapInfo.Path); + + // TODO: check validity of file + var stream = GetStream(fileStorePath); if (stream == null) From d8de99bbe452d000896d4ac75e036e854038dda9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Oct 2022 18:39:52 +0900 Subject: [PATCH 2558/2686] Check for hard link support in first run overlay --- osu.Game/Database/LegacyImportManager.cs | 21 +++++++++++++++++++ osu.Game/Database/RealmFileStore.cs | 2 +- .../FirstRunSetup/ScreenImportFromStable.cs | 4 ++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/osu.Game/Database/LegacyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs index b5338fbe1f..80c8e9c19e 100644 --- a/osu.Game/Database/LegacyImportManager.cs +++ b/osu.Game/Database/LegacyImportManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using osu.Framework; @@ -54,6 +55,26 @@ namespace osu.Game.Database public void UpdateStorage(string stablePath) => cachedStorage = new StableStorage(stablePath, gameHost as DesktopGameHost); + public bool CheckHardLinkAvailability() + { + if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) + return false; + + var stableStorage = GetCurrentStableStorage(); + + if (stableStorage == null || gameHost is not DesktopGameHost desktopGameHost) + return false; + + const string test_filename = "_hard_link_test"; + + desktopGameHost.Storage.Delete(test_filename); + + string testExistingPath = stableStorage.GetFullPath(stableStorage.GetFiles(string.Empty).First()); + string testDestinationPath = desktopGameHost.Storage.GetFullPath(test_filename); + + return RealmFileStore.CreateHardLink(testDestinationPath, testExistingPath, IntPtr.Zero); + } + public virtual async Task GetImportCount(StableContent content, CancellationToken cancellationToken) { var stableStorage = GetCurrentStableStorage(); diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index 4aa65dd50a..99033e2c88 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -94,7 +94,7 @@ namespace osu.Game.Database } [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)] - private static extern bool CreateHardLink( + public static extern bool CreateHardLink( string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 29cf3824fd..8227106ac2 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; +using osu.Framework.Logging; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -105,6 +106,9 @@ namespace osu.Game.Overlays.FirstRunSetup toggleInteraction(true); stableLocatorTextBox.Current.Value = storage.GetFullPath(string.Empty); importButton.Enabled.Value = true; + + bool available = legacyImportManager.CheckHardLinkAvailability(); + Logger.Log($"Hard link support is {available}"); } private void runImport() From 726943cb14150f8673b6ef0b71a2805bd6e43e9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 7 Dec 2022 17:01:28 +0900 Subject: [PATCH 2559/2686] Add information attempting to explain hard links to the end user --- ...RunOverlayImportFromStableScreenStrings.cs | 4 ++-- .../FirstRunSetup/ScreenImportFromStable.cs | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/FirstRunOverlayImportFromStableScreenStrings.cs b/osu.Game/Localisation/FirstRunOverlayImportFromStableScreenStrings.cs index deac7d8628..f0620245c3 100644 --- a/osu.Game/Localisation/FirstRunOverlayImportFromStableScreenStrings.cs +++ b/osu.Game/Localisation/FirstRunOverlayImportFromStableScreenStrings.cs @@ -15,10 +15,10 @@ namespace osu.Game.Localisation public static LocalisableString Header => new TranslatableString(getKey(@"header"), @"Import"); /// - /// "If you have an installation of a previous osu! version, you can choose to migrate your existing content. Note that this will create a copy, and not affect your existing installation." + /// "If you have an installation of a previous osu! version, you can choose to migrate your existing content. Note that this will not affect your existing installation's files in any way." /// public static LocalisableString Description => new TranslatableString(getKey(@"description"), - @"If you have an installation of a previous osu! version, you can choose to migrate your existing content. Note that this will create a copy, and not affect your existing installation."); + @"If you have an installation of a previous osu! version, you can choose to migrate your existing content. Note that this will not affect your existing installation's files in any way."); /// /// "previous osu! install" diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 8227106ac2..d1221d4174 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; @@ -40,6 +41,8 @@ namespace osu.Game.Overlays.FirstRunSetup private StableLocatorLabelledTextBox stableLocatorTextBox = null!; + private OsuTextFlowContainer copyInformation = null!; + private IEnumerable contentCheckboxes => Content.Children.OfType(); [BackgroundDependencyLoader(permitNulls: true)] @@ -63,6 +66,12 @@ namespace osu.Game.Overlays.FirstRunSetup new ImportCheckbox(CommonStrings.Scores, StableContent.Scores), new ImportCheckbox(CommonStrings.Skins, StableContent.Skins), new ImportCheckbox(CommonStrings.Collections, StableContent.Collections), + copyInformation = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: CONTENT_FONT_SIZE)) + { + Colour = OverlayColourProvider.Content1, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, importButton = new ProgressRoundedButton { Size = button_size, @@ -109,6 +118,18 @@ namespace osu.Game.Overlays.FirstRunSetup bool available = legacyImportManager.CheckHardLinkAvailability(); Logger.Log($"Hard link support is {available}"); + + if (available) + { + copyInformation.Text = "Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation."; + } + else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) + copyInformation.Text = "Hard links are not supported on this operating system, so a copy of all files will be made during import."; + else + { + copyInformation.Text = + "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install and the file system is NTFS."; + } } private void runImport() From e2d8909e7355d5773d69cb1245a3536d61973a09 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 11 Dec 2022 20:17:04 +0900 Subject: [PATCH 2560/2686] Add link to change folder location if it isn't on the same drive as import path --- .../FirstRunSetup/ScreenImportFromStable.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index d1221d4174..4af80c6fbb 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -16,12 +16,14 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Logging; +using osu.Framework.Screens; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Localisation; using osu.Game.Overlays.Settings; +using osu.Game.Overlays.Settings.Sections.Maintenance; using osu.Game.Screens.Edit.Setup; using osuTK; @@ -41,7 +43,7 @@ namespace osu.Game.Overlays.FirstRunSetup private StableLocatorLabelledTextBox stableLocatorTextBox = null!; - private OsuTextFlowContainer copyInformation = null!; + private LinkFlowContainer copyInformation = null!; private IEnumerable contentCheckboxes => Content.Children.OfType(); @@ -50,7 +52,7 @@ namespace osu.Game.Overlays.FirstRunSetup { Content.Children = new Drawable[] { - new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: CONTENT_FONT_SIZE)) + new LinkFlowContainer(cp => cp.Font = OsuFont.Default.With(size: CONTENT_FONT_SIZE)) { Colour = OverlayColourProvider.Content1, Text = FirstRunOverlayImportFromStableScreenStrings.Description, @@ -66,7 +68,7 @@ namespace osu.Game.Overlays.FirstRunSetup new ImportCheckbox(CommonStrings.Scores, StableContent.Scores), new ImportCheckbox(CommonStrings.Skins, StableContent.Skins), new ImportCheckbox(CommonStrings.Collections, StableContent.Collections), - copyInformation = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: CONTENT_FONT_SIZE)) + copyInformation = new LinkFlowContainer(cp => cp.Font = OsuFont.Default.With(size: CONTENT_FONT_SIZE)) { Colour = OverlayColourProvider.Content1, RelativeSizeAxes = Axes.X, @@ -93,6 +95,9 @@ namespace osu.Game.Overlays.FirstRunSetup stableLocatorTextBox.Current.BindValueChanged(_ => updateStablePath(), true); } + [Resolved(canBeNull: true)] + private OsuGame? game { get; set; } + private void updateStablePath() { var storage = legacyImportManager.GetCurrentStableStorage(); @@ -124,11 +129,15 @@ namespace osu.Game.Overlays.FirstRunSetup copyInformation.Text = "Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation."; } else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) - copyInformation.Text = "Hard links are not supported on this operating system, so a copy of all files will be made during import."; + copyInformation.Text = "Lightweight linking of files are not supported on your operating system yet, so a copy of all files will be made during import."; else { copyInformation.Text = - "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install and the file system is NTFS."; + "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system is NTFS). "; + copyInformation.AddLink(GeneralSettingsStrings.ChangeFolderLocation, () => + { + game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())); + }); } } From caa0b7c290acdc70a61440d6ff209b77236c1325 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 12 Dec 2022 13:59:27 +0900 Subject: [PATCH 2561/2686] Move score token to BeginPlaying --- osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs | 2 +- .../Visual/Gameplay/TestSceneSpectatorPlayback.cs | 2 +- osu.Game/Online/Spectator/ISpectatorServer.cs | 3 ++- osu.Game/Online/Spectator/OnlineSpectatorClient.cs | 6 +++--- osu.Game/Online/Spectator/SpectatorClient.cs | 11 ++++++----- osu.Game/Online/Spectator/SpectatorState.cs | 7 ++----- osu.Game/Screens/Play/SubmittingPlayer.cs | 2 +- .../Tests/Visual/Spectator/TestSpectatorClient.cs | 2 +- 8 files changed, 17 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index 4f319a7c34..ffd034e4d2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -261,7 +261,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestFinalFramesPurgedBeforeEndingPlay() { - AddStep("begin playing", () => spectatorClient.BeginPlaying(TestGameplayState.Create(new OsuRuleset()), new Score(), 0)); + AddStep("begin playing", () => spectatorClient.BeginPlaying(0, TestGameplayState.Create(new OsuRuleset()), new Score())); AddStep("send frames and finish play", () => { diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs index a949c0d79d..794860b9ec 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs @@ -147,7 +147,7 @@ namespace osu.Game.Tests.Visual.Gameplay } }; - spectatorClient.BeginPlaying(TestGameplayState.Create(new OsuRuleset()), recordingScore, 0); + spectatorClient.BeginPlaying(0, TestGameplayState.Create(new OsuRuleset()), recordingScore); spectatorClient.OnNewFrames += onNewFrames; }); } diff --git a/osu.Game/Online/Spectator/ISpectatorServer.cs b/osu.Game/Online/Spectator/ISpectatorServer.cs index 25785f60a4..fa9d04792a 100644 --- a/osu.Game/Online/Spectator/ISpectatorServer.cs +++ b/osu.Game/Online/Spectator/ISpectatorServer.cs @@ -15,8 +15,9 @@ namespace osu.Game.Online.Spectator /// /// Signal the start of a new play session. /// + /// The score submission token. /// The state of gameplay. - Task BeginPlaySession(SpectatorState state); + Task BeginPlaySession(long? scoreToken, SpectatorState state); /// /// Send a bundle of frame data for the current play session. diff --git a/osu.Game/Online/Spectator/OnlineSpectatorClient.cs b/osu.Game/Online/Spectator/OnlineSpectatorClient.cs index d69bd81b57..d5c1e56761 100644 --- a/osu.Game/Online/Spectator/OnlineSpectatorClient.cs +++ b/osu.Game/Online/Spectator/OnlineSpectatorClient.cs @@ -47,7 +47,7 @@ namespace osu.Game.Online.Spectator } } - protected override async Task BeginPlayingInternal(SpectatorState state) + protected override async Task BeginPlayingInternal(long? scoreToken, SpectatorState state) { if (!IsConnected.Value) return; @@ -56,7 +56,7 @@ namespace osu.Game.Online.Spectator try { - await connection.InvokeAsync(nameof(ISpectatorServer.BeginPlaySession), state); + await connection.InvokeAsync(nameof(ISpectatorServer.BeginPlaySession), scoreToken, state); } catch (Exception exception) { @@ -65,7 +65,7 @@ namespace osu.Game.Online.Spectator Debug.Assert(connector != null); await connector.Reconnect(); - await BeginPlayingInternal(state); + await BeginPlayingInternal(scoreToken, state); } // Exceptions can occur if, for instance, the locally played beatmap doesn't have a server-side counterpart. diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index c532cb266d..71b1896922 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -76,6 +76,7 @@ namespace osu.Game.Online.Spectator private IBeatmap? currentBeatmap; private Score? currentScore; + private long? currentScoreToken; private readonly Queue pendingFrameBundles = new Queue(); @@ -108,7 +109,7 @@ namespace osu.Game.Online.Spectator // re-send state in case it wasn't received if (IsPlaying) // TODO: this is likely sent out of order after a reconnect scenario. needs further consideration. - BeginPlayingInternal(currentState); + BeginPlayingInternal(currentScoreToken, currentState); } else { @@ -159,7 +160,7 @@ namespace osu.Game.Online.Spectator return Task.CompletedTask; } - public void BeginPlaying(GameplayState state, Score score, long? token) + public void BeginPlaying(long? scoreToken, GameplayState state, Score score) { // This schedule is only here to match the one below in `EndPlaying`. Schedule(() => @@ -175,12 +176,12 @@ namespace osu.Game.Online.Spectator currentState.Mods = score.ScoreInfo.Mods.Select(m => new APIMod(m)).ToArray(); currentState.State = SpectatedUserState.Playing; currentState.MaximumScoringValues = state.ScoreProcessor.MaximumScoringValues; - currentState.ScoreToken = token; currentBeatmap = state.Beatmap; currentScore = score; + currentScoreToken = scoreToken; - BeginPlayingInternal(currentState); + BeginPlayingInternal(currentScoreToken, currentState); }); } @@ -265,7 +266,7 @@ namespace osu.Game.Online.Spectator }); } - protected abstract Task BeginPlayingInternal(SpectatorState state); + protected abstract Task BeginPlayingInternal(long? scoreToken, SpectatorState state); protected abstract Task SendFramesInternal(FrameDataBundle bundle); diff --git a/osu.Game/Online/Spectator/SpectatorState.cs b/osu.Game/Online/Spectator/SpectatorState.cs index 34dbefd2a5..766b274e63 100644 --- a/osu.Game/Online/Spectator/SpectatorState.cs +++ b/osu.Game/Online/Spectator/SpectatorState.cs @@ -33,17 +33,14 @@ namespace osu.Game.Online.Spectator [Key(4)] public ScoringValues MaximumScoringValues { get; set; } - [Key(5)] - public long? ScoreToken { get; set; } - public bool Equals(SpectatorState other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return BeatmapID == other.BeatmapID && Mods.SequenceEqual(other.Mods) && RulesetID == other.RulesetID && State == other.State && ScoreToken == other.ScoreToken; + return BeatmapID == other.BeatmapID && Mods.SequenceEqual(other.Mods) && RulesetID == other.RulesetID && State == other.State; } - public override string ToString() => $"Beatmap:{BeatmapID} Mods:{string.Join(',', Mods)} Ruleset:{RulesetID} State:{State} Token:{ScoreToken}"; + public override string ToString() => $"Beatmap:{BeatmapID} Mods:{string.Join(',', Mods)} Ruleset:{RulesetID} State:{State}"; } } diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index 81c4e9ab2a..4c507f8c67 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -148,7 +148,7 @@ namespace osu.Game.Screens.Play realmBeatmap.LastPlayed = DateTimeOffset.Now; }); - spectatorClient.BeginPlaying(GameplayState, Score, token); + spectatorClient.BeginPlaying(token, GameplayState, Score); } public override bool OnExiting(ScreenExitEvent e) diff --git a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs index a76f6c7052..1db35b3aaa 100644 --- a/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs +++ b/osu.Game/Tests/Visual/Spectator/TestSpectatorClient.cs @@ -126,7 +126,7 @@ namespace osu.Game.Tests.Visual.Spectator } } - protected override Task BeginPlayingInternal(SpectatorState state) + protected override Task BeginPlayingInternal(long? scoreToken, SpectatorState state) { // Track the local user's playing beatmap ID. Debug.Assert(state.BeatmapID != null); From 05b59498108925db6d2934c5ba96d29870728361 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Dec 2022 17:38:39 +0900 Subject: [PATCH 2562/2686] Use explicit casts --- osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index 902aa72178..a729ef2cc8 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -4,7 +4,6 @@ #nullable disable using System; -using System.Linq; using System.Threading; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -104,9 +103,9 @@ namespace osu.Game.Overlays.Changelog { var fill = base.CreateHeader(); - var nestedFill = fill.Children.OfType().First(); + var nestedFill = (FillFlowContainer)fill.Child; - var buildDisplay = nestedFill.Children.OfType().First(); + var buildDisplay = (OsuHoverContainer)nestedFill.Child; buildDisplay.Scale = new Vector2(1.25f); buildDisplay.Action = null; From 7b48c91fe255c838784939dc9295307ab9690a90 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Mon, 12 Dec 2022 18:56:43 +0900 Subject: [PATCH 2563/2686] Only show local results in multi-spectator results screen --- .../Spectate/MultiSpectatorPlayer.cs | 3 +++ .../Spectate/MultiSpectatorResultsScreen.cs | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorResultsScreen.cs diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 5a686ffa72..930bea4497 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -7,6 +7,7 @@ using osu.Framework.Audio; using osu.Game.Beatmaps; using osu.Game.Scoring; using osu.Game.Screens.Play; +using osu.Game.Screens.Ranking; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { @@ -70,5 +71,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate clockAdjustmentsFromMods.BindAdjustments(gameplayClockContainer.AdjustmentsFromMods); return gameplayClockContainer; } + + protected override ResultsScreen CreateResults(ScoreInfo score) => new MultiSpectatorResultsScreen(score); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorResultsScreen.cs new file mode 100644 index 0000000000..fe3f02466d --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorResultsScreen.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable disable + +using System; +using System.Collections.Generic; +using osu.Game.Online.API; +using osu.Game.Scoring; +using osu.Game.Screens.Play; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate +{ + public partial class MultiSpectatorResultsScreen : SpectatorResultsScreen + { + public MultiSpectatorResultsScreen(ScoreInfo score) + : base(score) + { + } + + protected override APIRequest FetchScores(Action> scoresCallback) => null; + + protected override APIRequest FetchNextPage(int direction, Action> scoresCallback) => null; + } +} From df94af44956e06f9c7cce10daef7794262f1b5ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Dec 2022 19:22:09 +0900 Subject: [PATCH 2564/2686] Inline `ScoringValues` and make some more methods `private` inside `ScoreProcessor` --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 38 +++++++++++++++--- osu.Game/Scoring/ScoringValues.cs | 43 --------------------- 2 files changed, 32 insertions(+), 49 deletions(-) delete mode 100644 osu.Game/Scoring/ScoringValues.cs diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 5e05c7e2a6..b048566c8a 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -264,7 +264,7 @@ namespace osu.Game.Rulesets.Scoring private void updateScore() { Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1; - TotalScore.Value = ComputeScore(Mode.Value, currentScoringValues, maximumScoringValues); + TotalScore.Value = computeScore(Mode.Value, currentScoringValues, maximumScoringValues); } /// @@ -299,9 +299,9 @@ namespace osu.Game.Rulesets.Scoring if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset)) throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\"."); - ExtractScoringValues(scoreInfo, out var current, out var maximum); + extractScoringValues(scoreInfo, out var current, out var maximum); - return ComputeScore(mode, current, maximum); + return computeScore(mode, current, maximum); } /// @@ -312,7 +312,7 @@ namespace osu.Game.Rulesets.Scoring /// The maximum scoring values. /// The total score computed from the given scoring values. [Pure] - public long ComputeScore(ScoringMode mode, ScoringValues current, ScoringValues maximum) + private long computeScore(ScoringMode mode, ScoringValues current, ScoringValues maximum) { double accuracyRatio = maximum.BaseScore > 0 ? (double)current.BaseScore / maximum.BaseScore : 1; double comboRatio = maximum.MaxCombo > 0 ? (double)current.MaxCombo / maximum.MaxCombo : 1; @@ -470,14 +470,14 @@ namespace osu.Game.Rulesets.Scoring /// Consumers are expected to more accurately fill in the above values through external means. /// /// Ensure to fill in the maximum for use in - /// . + /// . /// /// /// The score to extract scoring values from. /// The "current" scoring values, representing the hit statistics as they appear. /// The "maximum" scoring values, representing the hit statistics as if the maximum hit result was attained each time. [Pure] - internal void ExtractScoringValues(ScoreInfo scoreInfo, out ScoringValues current, out ScoringValues maximum) + private void extractScoringValues(ScoreInfo scoreInfo, out ScoringValues current, out ScoringValues maximum) { extractScoringValues(scoreInfo.Statistics, out current, out maximum); current.MaxCombo = scoreInfo.MaxCombo; @@ -560,6 +560,32 @@ namespace osu.Game.Rulesets.Scoring base.Dispose(isDisposing); hitEvents.Clear(); } + + /// + /// Stores the required scoring data that fulfils the minimum requirements for a to calculate score. + /// + private struct ScoringValues + { + /// + /// The sum of all "basic" scoring values. See: and . + /// + public long BaseScore; + + /// + /// The sum of all "bonus" scoring values. See: and . + /// + public long BonusScore; + + /// + /// The highest achieved combo. + /// + public int MaxCombo; + + /// + /// The count of "basic" s. See: . + /// + public int CountBasicHitObjects; + } } public enum ScoringMode diff --git a/osu.Game/Scoring/ScoringValues.cs b/osu.Game/Scoring/ScoringValues.cs deleted file mode 100644 index 471067c9db..0000000000 --- a/osu.Game/Scoring/ScoringValues.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using MessagePack; -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Scoring; - -namespace osu.Game.Scoring -{ - /// - /// Stores the required scoring data that fulfils the minimum requirements for a to calculate score. - /// - [MessagePackObject] - public struct ScoringValues - { - /// - /// The sum of all "basic" scoring values. See: and . - /// - [Key(0)] - public long BaseScore; - - /// - /// The sum of all "bonus" scoring values. See: and . - /// - [Key(1)] - public long BonusScore; - - /// - /// The highest achieved combo. - /// - [Key(2)] - public int MaxCombo; - - /// - /// The count of "basic" s. See: . - /// - [Key(3)] - public int CountBasicHitObjects; - } -} From 37a075632163e6acea5aa7125a8bceaadebbd0f8 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 12 Dec 2022 14:38:24 +0300 Subject: [PATCH 2565/2686] Add tests --- .../UserInterface/TestSceneButtonsInput.cs | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs new file mode 100644 index 0000000000..b8bcf583bf --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs @@ -0,0 +1,92 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Game.Overlays.Settings; +using NUnit.Framework; +using osuTK; +using osu.Game.Overlays; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Graphics.UserInterface; +using osu.Framework.Allocation; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public partial class TestSceneButtonsInput : OsuManualInputManagerTestScene + { + private const int width = 500; + + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); + + private readonly SettingsButton settingsButton; + private readonly RoundedButton roundedButton; + private readonly ShearedButton shearedButton; + + public TestSceneButtonsInput() + { + Add(new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + Width = 500, + Spacing = new Vector2(0, 5), + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + settingsButton = new SettingsButton + { + Enabled = { Value = true }, + Text = "Settings button" + }, + roundedButton = new RoundedButton + { + RelativeSizeAxes = Axes.X, + Enabled = { Value = true }, + Text = "Rounded button" + }, + shearedButton = new ShearedButton(width) + { + Text = "Sheared button", + LighterColour = Colour4.FromHex("#FFFFFF"), + DarkerColour = Colour4.FromHex("#FFCC22"), + TextColour = Colour4.Black, + Height = 40, + Enabled = { Value = true }, + Padding = new MarginPadding(0) + } + } + }); + } + + [Test] + public void TestSettingsButtonInput() + { + AddStep("Move cursor to button", () => InputManager.MoveMouseTo(settingsButton)); + AddAssert("Button is hovered", () => settingsButton.IsHovered); + AddStep("Move cursor to padded area", () => InputManager.MoveMouseTo(settingsButton.ScreenSpaceDrawQuad.TopLeft + new Vector2(SettingsPanel.CONTENT_MARGINS / 2f, 10))); + AddAssert("Cursor within a button", () => settingsButton.ScreenSpaceDrawQuad.Contains(InputManager.CurrentState.Mouse.Position)); + AddAssert("Button is not hovered", () => !settingsButton.IsHovered); + } + + [Test] + public void TestRoundedButtonInput() + { + AddStep("Move cursor to button", () => InputManager.MoveMouseTo(roundedButton)); + AddAssert("Button is hovered", () => roundedButton.IsHovered); + AddStep("Move cursor to corner", () => InputManager.MoveMouseTo(roundedButton.ScreenSpaceDrawQuad.TopLeft + Vector2.One)); + AddAssert("Cursor within a button", () => roundedButton.ScreenSpaceDrawQuad.Contains(InputManager.CurrentState.Mouse.Position)); + AddAssert("Button is not hovered", () => !roundedButton.IsHovered); + } + + [Test] + public void TestShearedButtonInput() + { + AddStep("Move cursor to button", () => InputManager.MoveMouseTo(shearedButton)); + AddAssert("Button is hovered", () => shearedButton.IsHovered); + AddStep("Move cursor to corner", () => InputManager.MoveMouseTo(shearedButton.ScreenSpaceDrawQuad.TopLeft + Vector2.One)); + AddAssert("Cursor within a button", () => shearedButton.ScreenSpaceDrawQuad.Contains(InputManager.CurrentState.Mouse.Position)); + AddAssert("Button is not hovered", () => !shearedButton.IsHovered); + } + } +} From 7e39f171fbd787339e59ed0ceee38f6e51be4654 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 12 Dec 2022 14:40:38 +0300 Subject: [PATCH 2566/2686] Fix OsuButton input receiving --- osu.Game/Graphics/UserInterface/OsuButton.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index fa61b06cff..70f76fb453 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -13,6 +11,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; +using osuTK; using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface @@ -66,6 +65,8 @@ namespace osu.Game.Graphics.UserInterface protected override Container Content { get; } + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Content.ReceivePositionalInputAt(screenSpacePos); + protected Box Hover; protected Box Background; protected SpriteText SpriteText; @@ -115,7 +116,7 @@ namespace osu.Game.Graphics.UserInterface }); if (hoverSounds.HasValue) - AddInternal(new HoverClickSounds(hoverSounds.Value) { Enabled = { BindTarget = Enabled } }); + Add(new HoverClickSounds(hoverSounds.Value) { Enabled = { BindTarget = Enabled } }); } [BackgroundDependencyLoader] From d2b3533356d22d3ac0350e3c8f3eb08a561413de Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 12 Dec 2022 14:42:50 +0300 Subject: [PATCH 2567/2686] Fix OsuClickableContainer input receiving --- .../Graphics/Containers/OsuClickableContainer.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index 4729ddf1a8..945ebbb02d 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -1,14 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; +using osuTK; namespace osu.Game.Graphics.Containers { @@ -18,6 +17,8 @@ namespace osu.Game.Graphics.Containers private readonly Container content = new Container { RelativeSizeAxes = Axes.Both }; + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Content.ReceivePositionalInputAt(screenSpacePos); + protected override Container Content => content; protected virtual HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet) { Enabled = { BindTarget = Enabled } }; @@ -38,11 +39,8 @@ namespace osu.Game.Graphics.Containers content.AutoSizeAxes = AutoSizeAxes; } - InternalChildren = new Drawable[] - { - content, - CreateHoverSounds(sampleSet) - }; + AddInternal(content); + Add(CreateHoverSounds(sampleSet)); } } } From b0d475cd8b2f641d5cece506ad05a46b4552ae71 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 12 Dec 2022 14:57:07 +0300 Subject: [PATCH 2568/2686] CI fix --- osu.Game/Graphics/UserInterface/OsuButton.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 70f76fb453..9216b41170 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -23,12 +23,8 @@ namespace osu.Game.Graphics.UserInterface { public LocalisableString Text { - get => SpriteText?.Text ?? default; - set - { - if (SpriteText != null) - SpriteText.Text = value; - } + get => SpriteText.Text; + set => SpriteText.Text = value; } private Color4? backgroundColour; From 890dd9cd061d34eaf693ad81c219937324f7192f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 12 Dec 2022 15:10:03 +0300 Subject: [PATCH 2569/2686] Fix input doesn't take original drawable modifications into account --- .../UserInterface/TestSceneButtonsInput.cs | 37 +++++++++++++++++++ .../Containers/OsuClickableContainer.cs | 2 +- osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs index b8bcf583bf..985f613b63 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneButtonsInput.cs @@ -10,6 +10,10 @@ using osu.Game.Overlays; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Graphics.UserInterface; using osu.Framework.Allocation; +using osu.Game.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osuTK.Graphics; +using osu.Game.Graphics.Sprites; namespace osu.Game.Tests.Visual.UserInterface { @@ -21,6 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green); private readonly SettingsButton settingsButton; + private readonly OsuClickableContainer clickableContainer; private readonly RoundedButton roundedButton; private readonly ShearedButton shearedButton; @@ -34,6 +39,28 @@ namespace osu.Game.Tests.Visual.UserInterface Direction = FillDirection.Vertical, Children = new Drawable[] { + clickableContainer = new OsuClickableContainer + { + RelativeSizeAxes = Axes.X, + Height = 40, + Enabled = { Value = true }, + Masking = true, + CornerRadius = 20, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Red + }, + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Rounded clickable container" + } + } + }, settingsButton = new SettingsButton { Enabled = { Value = true }, @@ -88,5 +115,15 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("Cursor within a button", () => shearedButton.ScreenSpaceDrawQuad.Contains(InputManager.CurrentState.Mouse.Position)); AddAssert("Button is not hovered", () => !shearedButton.IsHovered); } + + [Test] + public void TestRoundedClickableContainerInput() + { + AddStep("Move cursor to button", () => InputManager.MoveMouseTo(clickableContainer)); + AddAssert("Button is hovered", () => clickableContainer.IsHovered); + AddStep("Move cursor to corner", () => InputManager.MoveMouseTo(clickableContainer.ScreenSpaceDrawQuad.TopLeft + Vector2.One)); + AddAssert("Cursor within a button", () => clickableContainer.ScreenSpaceDrawQuad.Contains(InputManager.CurrentState.Mouse.Position)); + AddAssert("Button is not hovered", () => !clickableContainer.IsHovered); + } } } diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index 945ebbb02d..ecae456e88 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Graphics.Containers private readonly Container content = new Container { RelativeSizeAxes = Axes.Both }; - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Content.ReceivePositionalInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) && Content.ReceivePositionalInputAt(screenSpacePos); protected override Container Content => content; diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 9216b41170..00cd3b13e5 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -61,7 +61,7 @@ namespace osu.Game.Graphics.UserInterface protected override Container Content { get; } - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Content.ReceivePositionalInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) && Content.ReceivePositionalInputAt(screenSpacePos); protected Box Hover; protected Box Background; From 15bd82add819fb7ee61a2b2c785b8153094493de Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 12 Dec 2022 18:24:49 +0300 Subject: [PATCH 2570/2686] Fix DrawableUsername being affected --- osu.Game/Overlays/Chat/DrawableUsername.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs index 7026d519a5..6bae498a6c 100644 --- a/osu.Game/Overlays/Chat/DrawableUsername.cs +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays.Chat public Color4 AccentColour { get; } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => - Child.ReceivePositionalInputAt(screenSpacePos); + colouredDrawable.ReceivePositionalInputAt(screenSpacePos); public float FontSize { @@ -87,13 +87,13 @@ namespace osu.Game.Overlays.Chat { AccentColour = default_colours[user.Id % default_colours.Length]; - Child = colouredDrawable = drawableText; + Add(colouredDrawable = drawableText); } else { AccentColour = Color4Extensions.FromHex(user.Colour); - Child = new Container + Add(new Container { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -127,7 +127,7 @@ namespace osu.Game.Overlays.Chat } } } - }; + }); } } From 0dd4e0cf940a5650f013bc0845aee59303b9e238 Mon Sep 17 00:00:00 2001 From: Dylan Nantz Date: Mon, 12 Dec 2022 21:18:01 -0500 Subject: [PATCH 2571/2686] hide cursor in catch --- ...tchRelaxCursorContainer.cs => CatchCursorContainer.cs} | 4 ++-- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) rename osu.Game.Rulesets.Catch/UI/{CatchRelaxCursorContainer.cs => CatchCursorContainer.cs} (78%) diff --git a/osu.Game.Rulesets.Catch/UI/CatchRelaxCursorContainer.cs b/osu.Game.Rulesets.Catch/UI/CatchCursorContainer.cs similarity index 78% rename from osu.Game.Rulesets.Catch/UI/CatchRelaxCursorContainer.cs rename to osu.Game.Rulesets.Catch/UI/CatchCursorContainer.cs index f30b8f0f36..4ae61ef8c7 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchRelaxCursorContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchCursorContainer.cs @@ -6,9 +6,9 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Catch.UI { - public partial class CatchRelaxCursorContainer : GameplayCursorContainer + public partial class CatchCursorContainer : GameplayCursorContainer { - // Just hide the cursor in relax. + // Just hide the cursor. // The main goal here is to show that we have a cursor so the game never shows the global one. protected override Drawable CreateCursor() => Empty(); } diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 184ff38cc6..2c7b52b1b5 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -52,13 +52,7 @@ namespace osu.Game.Rulesets.Catch.UI this.difficulty = difficulty; } - protected override GameplayCursorContainer CreateCursor() - { - if (Mods != null && Mods.Any(m => m is ModRelax)) - return new CatchRelaxCursorContainer(); - - return base.CreateCursor(); - } + protected override GameplayCursorContainer CreateCursor() => new CatchCursorContainer(); [BackgroundDependencyLoader] private void load() From ad7554cc7d60b3449433abd1df84e07b75d0a6cb Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 13 Dec 2022 16:15:14 +0900 Subject: [PATCH 2572/2686] Allow keeping stream open after encoding scores --- osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs index 63094c5548..5452e4b9eb 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs @@ -53,9 +53,9 @@ namespace osu.Game.Scoring.Legacy throw new ArgumentException(@"Only scores in the osu, taiko, catch, or mania rulesets can be encoded to the legacy score format.", nameof(score)); } - public void Encode(Stream stream) + public void Encode(Stream stream, bool leaveOpen = false) { - using (SerializationWriter sw = new SerializationWriter(stream)) + using (SerializationWriter sw = new SerializationWriter(stream, leaveOpen)) { sw.Write((byte)(score.ScoreInfo.Ruleset.OnlineID)); sw.Write(LATEST_VERSION); From 775952380fe2927ed901b5248220598bd6fb3be2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Dec 2022 18:57:17 +0900 Subject: [PATCH 2573/2686] Remove unused using statements --- osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs index 2c7b52b1b5..6167ee53f6 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs @@ -3,14 +3,12 @@ #nullable disable -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects.Drawables; using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; From cf2719d4c0661bf2f0b34e668069ec8f5bf660ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Dec 2022 23:56:11 +0900 Subject: [PATCH 2574/2686] Convert `batchImport` parameter to parameters class to allow further import configuration --- .../Database/BeatmapImporterTests.cs | 2 +- ...eneOnlinePlayBeatmapAvailabilityTracker.cs | 4 +-- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 3 +- osu.Game/Beatmaps/BeatmapImporter.cs | 6 ++-- osu.Game/Beatmaps/BeatmapManager.cs | 26 +++++++++++++++-- .../Database/RealmArchiveModelImporter.cs | 29 ++++++++++--------- osu.Game/Scoring/ScoreImporter.cs | 4 +-- osu.Game/Scoring/ScoreManager.cs | 4 +-- osu.Game/Skinning/SkinManager.cs | 10 +++++-- 9 files changed, 57 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index 56964aa8b2..cbaa7bf972 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -1052,7 +1052,7 @@ namespace osu.Game.Tests.Database { string? temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack); - var importedSet = await importer.Import(new ImportTask(temp), batchImport); + var importedSet = await importer.Import(new ImportTask(temp), new ImportParameters { Batch = batchImport }); Assert.NotNull(importedSet); Debug.Assert(importedSet != null); diff --git a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs index e1d8e08c5e..585fd516bd 100644 --- a/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs +++ b/osu.Game.Tests/Online/TestSceneOnlinePlayBeatmapAvailabilityTracker.cs @@ -226,12 +226,12 @@ namespace osu.Game.Tests.Online this.testBeatmapManager = testBeatmapManager; } - public override Live ImportModel(BeatmapSetInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) + public override Live ImportModel(BeatmapSetInfo item, ArchiveReader archive = null, ImportParameters parameters = default, CancellationToken cancellationToken = default) { if (!testBeatmapManager.AllowImport.Wait(TimeSpan.FromSeconds(10), cancellationToken)) throw new TimeoutException("Timeout waiting for import to be allowed."); - return (testBeatmapManager.CurrentImport = base.ImportModel(item, archive, batchImport, cancellationToken)); + return (testBeatmapManager.CurrentImport = base.ImportModel(item, archive, parameters, cancellationToken)); } } } diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index 5c20f46787..f90c983627 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -12,6 +12,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Platform; +using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Extensions; using osu.Game.IO; @@ -360,7 +361,7 @@ namespace osu.Game.Tests.Skins.IO private async Task> loadSkinIntoOsu(OsuGameBase osu, ImportTask import, bool batchImport = false) { var skinManager = osu.Dependencies.Get(); - return await skinManager.Import(import, batchImport); + return await skinManager.Import(import, new ImportParameters { Batch = batchImport }); } } } diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index bcb1d7f961..303e85b83a 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -203,10 +203,10 @@ namespace osu.Game.Beatmaps } } - protected override void PostImport(BeatmapSetInfo model, Realm realm, bool batchImport) + protected override void PostImport(BeatmapSetInfo model, Realm realm, ImportParameters parameters) { - base.PostImport(model, realm, batchImport); - ProcessBeatmap?.Invoke((model, batchImport)); + base.PostImport(model, realm, parameters); + ProcessBeatmap?.Invoke((model, parameters.Batch)); } private void validateOnlineIds(BeatmapSetInfo beatmapSet, Realm realm) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 965cc43815..e288239d74 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -460,11 +460,11 @@ namespace osu.Game.Beatmaps public Task>> Import(ProgressNotification notification, params ImportTask[] tasks) => beatmapImporter.Import(notification, tasks); - public Task?> Import(ImportTask task, bool batchImport = false, CancellationToken cancellationToken = default) => - beatmapImporter.Import(task, batchImport, cancellationToken); + public Task?> Import(ImportTask task, ImportParameters parameters = default, CancellationToken cancellationToken = default) => + beatmapImporter.Import(task, parameters, cancellationToken); public Live? Import(BeatmapSetInfo item, ArchiveReader? archive = null, CancellationToken cancellationToken = default) => - beatmapImporter.ImportModel(item, archive, false, cancellationToken); + beatmapImporter.ImportModel(item, archive, default, cancellationToken); public IEnumerable HandledExtensions => beatmapImporter.HandledExtensions; @@ -526,4 +526,24 @@ namespace osu.Game.Beatmaps public override string HumanisedModelName => "beatmap"; } + + public struct ImportParameters + { + /// + /// Whether this import is part of a larger batch. + /// + /// + /// May skip intensive pre-import checks in favour of faster processing. + /// + /// More specifically, imports will be skipped before they begin, given an existing model matches on hash and filenames. Should generally only be used for large batch imports, as it may defy user expectations when updating an existing model. + /// + /// Will also change scheduling behaviour to run at a lower priority. + /// + public bool Batch { get; set; } + + /// + /// Whether this import should use hard links rather than file copy operations if available. + /// + public bool PreferHardLinks { get; set; } + } } diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index 0286815569..41e491bce6 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -13,6 +13,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Threading; +using osu.Game.Beatmaps; using osu.Game.Extensions; using osu.Game.IO.Archives; using osu.Game.Models; @@ -115,7 +116,7 @@ namespace osu.Game.Database try { - var model = await Import(task, isBatchImport, notification.CancellationToken).ConfigureAwait(false); + var model = await Import(task, new ImportParameters { Batch = isBatchImport }, notification.CancellationToken).ConfigureAwait(false); lock (imported) { @@ -176,16 +177,16 @@ namespace osu.Game.Database /// Note that this bypasses the UI flow and should only be used for special cases or testing. /// /// The containing data about the to import. - /// Whether this import is part of a larger batch. + /// Parameters to further configure the import process. /// An optional cancellation token. /// The imported model, if successful. - public async Task?> Import(ImportTask task, bool batchImport = false, CancellationToken cancellationToken = default) + public async Task?> Import(ImportTask task, ImportParameters parameters = default, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); Live? import; using (ArchiveReader reader = task.GetReader()) - import = await importFromArchive(reader, batchImport, cancellationToken).ConfigureAwait(false); + import = await importFromArchive(reader, parameters, cancellationToken).ConfigureAwait(false); // We may or may not want to delete the file depending on where it is stored. // e.g. reconstructing/repairing database with items from default storage. @@ -211,9 +212,9 @@ namespace osu.Game.Database /// This method also handled queueing the import task on a relevant import thread pool. /// /// The archive to be imported. - /// Whether this import is part of a larger batch. + /// Parameters to further configure the import process. /// An optional cancellation token. - private async Task?> importFromArchive(ArchiveReader archive, bool batchImport = false, CancellationToken cancellationToken = default) + private async Task?> importFromArchive(ArchiveReader archive, ImportParameters parameters = default, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); @@ -236,10 +237,10 @@ namespace osu.Game.Database return null; } - var scheduledImport = Task.Factory.StartNew(() => ImportModel(model, archive, batchImport, cancellationToken), + var scheduledImport = Task.Factory.StartNew(() => ImportModel(model, archive, parameters, cancellationToken), cancellationToken, TaskCreationOptions.HideScheduler, - batchImport ? import_scheduler_batch : import_scheduler); + parameters.Batch ? import_scheduler_batch : import_scheduler); return await scheduledImport.ConfigureAwait(false); } @@ -249,15 +250,15 @@ namespace osu.Game.Database /// /// The model to be imported. /// An optional archive to use for model population. - /// If true, imports will be skipped before they begin, given an existing model matches on hash and filenames. Should generally only be used for large batch imports, as it may defy user expectations when updating an existing model. + /// Parameters to further configure the import process. /// An optional cancellation token. - public virtual Live? ImportModel(TModel item, ArchiveReader? archive = null, bool batchImport = false, CancellationToken cancellationToken = default) => Realm.Run(realm => + public virtual Live? ImportModel(TModel item, ArchiveReader? archive = null, ImportParameters parameters = default, CancellationToken cancellationToken = default) => Realm.Run(realm => { cancellationToken.ThrowIfCancellationRequested(); TModel? existing; - if (batchImport && archive != null) + if (parameters.Batch && archive != null) { // this is a fast bail condition to improve large import performance. item.Hash = computeHashFast(archive); @@ -358,7 +359,7 @@ namespace osu.Game.Database // import to store realm.Add(item); - PostImport(item, realm, batchImport); + PostImport(item, realm, parameters); transaction.Commit(); } @@ -493,8 +494,8 @@ namespace osu.Game.Database /// /// The model prepared for import. /// The current realm context. - /// Whether the import was part of a batch. - protected virtual void PostImport(TModel model, Realm realm, bool batchImport) + /// Parameters to further configure the import process. + protected virtual void PostImport(TModel model, Realm realm, ImportParameters parameters) { } diff --git a/osu.Game/Scoring/ScoreImporter.cs b/osu.Game/Scoring/ScoreImporter.cs index 5c8e21014c..4656f02897 100644 --- a/osu.Game/Scoring/ScoreImporter.cs +++ b/osu.Game/Scoring/ScoreImporter.cs @@ -145,9 +145,9 @@ namespace osu.Game.Scoring #pragma warning restore CS0618 } - protected override void PostImport(ScoreInfo model, Realm realm, bool batchImport) + protected override void PostImport(ScoreInfo model, Realm realm, ImportParameters parameters) { - base.PostImport(model, realm, batchImport); + base.PostImport(model, realm, parameters); var userRequest = new GetUserRequest(model.RealmUser.Username); diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index b2944ad219..a57db0eccf 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -179,8 +179,8 @@ namespace osu.Game.Scoring public Task> ImportAsUpdate(ProgressNotification notification, ImportTask task, ScoreInfo original) => scoreImporter.ImportAsUpdate(notification, task, original); - public Live Import(ScoreInfo item, ArchiveReader archive = null, bool batchImport = false, CancellationToken cancellationToken = default) => - scoreImporter.ImportModel(item, archive, batchImport, cancellationToken); + public Live Import(ScoreInfo item, ArchiveReader archive = null, ImportParameters parameters = default, CancellationToken cancellationToken = default) => + scoreImporter.ImportModel(item, archive, parameters, cancellationToken); /// /// Populates the for a given . diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 4a5277f3bf..40c43563b2 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -22,6 +22,7 @@ using osu.Framework.Testing; using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Audio; +using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.IO; using osu.Game.Overlays.Notifications; @@ -274,11 +275,14 @@ namespace osu.Game.Skinning public IEnumerable HandledExtensions => skinImporter.HandledExtensions; - public Task>> Import(ProgressNotification notification, params ImportTask[] tasks) => skinImporter.Import(notification, tasks); + public Task>> Import(ProgressNotification notification, params ImportTask[] tasks) => + skinImporter.Import(notification, tasks); - public Task> ImportAsUpdate(ProgressNotification notification, ImportTask task, SkinInfo original) => skinImporter.ImportAsUpdate(notification, task, original); + public Task> ImportAsUpdate(ProgressNotification notification, ImportTask task, SkinInfo original) => + skinImporter.ImportAsUpdate(notification, task, original); - public Task> Import(ImportTask task, bool batchImport = false, CancellationToken cancellationToken = default) => skinImporter.Import(task, batchImport, cancellationToken); + public Task> Import(ImportTask task, ImportParameters parameters = default, CancellationToken cancellationToken = default) => + skinImporter.Import(task, parameters, cancellationToken); #endregion From 1d4230993dfceca084d0195318a336622d386a94 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Dec 2022 00:56:27 +0900 Subject: [PATCH 2575/2686] Hook up parameter with `RealmFileStore` to complete the chain --- .../Database/RealmArchiveModelImporter.cs | 2 +- osu.Game/Database/RealmFileStore.cs | 110 +++++++++--------- 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index 41e491bce6..1f9debc46f 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -304,7 +304,7 @@ namespace osu.Game.Database foreach (var filenames in getShortenedFilenames(archive)) { using (Stream s = archive.GetStream(filenames.original)) - files.Add(new RealmNamedFileUsage(Files.Add(s, realm, false), filenames.shortened)); + files.Add(new RealmNamedFileUsage(Files.Add(s, realm, false, parameters.PreferHardLinks), filenames.shortened)); } } diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index 99033e2c88..87d347fbfa 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -45,7 +45,8 @@ namespace osu.Game.Database /// The file data stream. /// The realm instance to add to. Should already be in a transaction. /// Whether the should immediately be added to the underlying realm. If false is provided here, the instance must be manually added. - public RealmFile Add(Stream data, Realm realm, bool addToRealm = true) + /// Whether this import should use hard links rather than file copy operations if available. + public RealmFile Add(Stream data, Realm realm, bool addToRealm = true, bool preferHardLinks = false) { string hash = data.ComputeSHA2Hash(); @@ -54,7 +55,7 @@ namespace osu.Game.Database var file = existing ?? new RealmFile { Hash = hash }; if (!checkFileExistsAndMatchesHash(file)) - copyToStore(file, data); + copyToStore(file, data, preferHardLinks); if (addToRealm && !file.IsManaged) realm.Add(file); @@ -62,9 +63,9 @@ namespace osu.Game.Database return file; } - private void copyToStore(RealmFile file, Stream data) + private void copyToStore(RealmFile file, Stream data, bool preferHardLinks) { - if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows && data is FileStream fs) + if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows && data is FileStream fs && preferHardLinks) { // attempt to do a fast hard link rather than copy. if (CreateHardLink(Storage.GetFullPath(file.GetStoragePath()), fs.Name, IntPtr.Zero)) @@ -79,6 +80,58 @@ namespace osu.Game.Database data.Seek(0, SeekOrigin.Begin); } + private bool checkFileExistsAndMatchesHash(RealmFile file) + { + string path = file.GetStoragePath(); + + // we may be re-adding a file to fix missing store entries. + if (!Storage.Exists(path)) + return false; + + // even if the file already exists, check the existing checksum for safety. + using (var stream = Storage.GetStream(path)) + return stream.ComputeSHA2Hash() == file.Hash; + } + + public void Cleanup() + { + Logger.Log(@"Beginning realm file store cleanup"); + + int totalFiles = 0; + int removedFiles = 0; + + // can potentially be run asynchronously, although we will need to consider operation order for disk deletion vs realm removal. + realm.Write(r => + { + // TODO: consider using a realm native query to avoid iterating all files (https://github.com/realm/realm-dotnet/issues/2659#issuecomment-927823707) + var files = r.All().ToList(); + + foreach (var file in files) + { + totalFiles++; + + if (file.BacklinksCount > 0) + continue; + + try + { + removedFiles++; + Storage.Delete(file.GetStoragePath()); + r.Remove(file); + } + catch (Exception e) + { + Logger.Error(e, $@"Could not delete databased file {file.Hash}"); + } + } + }); + + Logger.Log($@"Finished realm file store cleanup ({removedFiles} of {totalFiles} deleted)"); + } + + #region Windows hard link support + + // For future use (to detect if a file is a hard link with other references existing on disk). public static int GetFileLinkCount(string filePath) { int result = 0; @@ -132,53 +185,6 @@ namespace osu.Game.Database [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseHandle(SafeHandle hObject); - private bool checkFileExistsAndMatchesHash(RealmFile file) - { - string path = file.GetStoragePath(); - - // we may be re-adding a file to fix missing store entries. - if (!Storage.Exists(path)) - return false; - - // even if the file already exists, check the existing checksum for safety. - using (var stream = Storage.GetStream(path)) - return stream.ComputeSHA2Hash() == file.Hash; - } - - public void Cleanup() - { - Logger.Log(@"Beginning realm file store cleanup"); - - int totalFiles = 0; - int removedFiles = 0; - - // can potentially be run asynchronously, although we will need to consider operation order for disk deletion vs realm removal. - realm.Write(r => - { - // TODO: consider using a realm native query to avoid iterating all files (https://github.com/realm/realm-dotnet/issues/2659#issuecomment-927823707) - var files = r.All().ToList(); - - foreach (var file in files) - { - totalFiles++; - - if (file.BacklinksCount > 0) - continue; - - try - { - removedFiles++; - Storage.Delete(file.GetStoragePath()); - r.Remove(file); - } - catch (Exception e) - { - Logger.Error(e, $@"Could not delete databased file {file.Hash}"); - } - } - }); - - Logger.Log($@"Finished realm file store cleanup ({removedFiles} of {totalFiles} deleted)"); - } + #endregion } } From bbf931c746341c1e80239670dbcc7e3ce4ccdf01 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Dec 2022 19:53:12 +0900 Subject: [PATCH 2576/2686] Move hard link helper functions to their own class --- osu.Game/Database/LegacyImportManager.cs | 2 +- osu.Game/Database/RealmFileStore.cs | 64 +--------------------- osu.Game/IO/HardLinkHelper.cs | 68 ++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 63 deletions(-) create mode 100644 osu.Game/IO/HardLinkHelper.cs diff --git a/osu.Game/Database/LegacyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs index 80c8e9c19e..ec8eac611c 100644 --- a/osu.Game/Database/LegacyImportManager.cs +++ b/osu.Game/Database/LegacyImportManager.cs @@ -72,7 +72,7 @@ namespace osu.Game.Database string testExistingPath = stableStorage.GetFullPath(stableStorage.GetFiles(string.Empty).First()); string testDestinationPath = desktopGameHost.Storage.GetFullPath(test_filename); - return RealmFileStore.CreateHardLink(testDestinationPath, testExistingPath, IntPtr.Zero); + return HardLinkHelper.CreateHardLink(testDestinationPath, testExistingPath, IntPtr.Zero); } public virtual async Task GetImportCount(StableContent content, CancellationToken cancellationToken) diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index 87d347fbfa..71ea6cba58 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -4,9 +4,6 @@ using System; using System.IO; using System.Linq; -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; -using Microsoft.Win32.SafeHandles; using osu.Framework; using osu.Framework.Extensions; using osu.Framework.IO.Stores; @@ -14,6 +11,7 @@ using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Extensions; +using osu.Game.IO; using osu.Game.Models; using Realms; @@ -68,7 +66,7 @@ namespace osu.Game.Database if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows && data is FileStream fs && preferHardLinks) { // attempt to do a fast hard link rather than copy. - if (CreateHardLink(Storage.GetFullPath(file.GetStoragePath()), fs.Name, IntPtr.Zero)) + if (HardLinkHelper.CreateHardLink(Storage.GetFullPath(file.GetStoragePath()), fs.Name, IntPtr.Zero)) return; } @@ -128,63 +126,5 @@ namespace osu.Game.Database Logger.Log($@"Finished realm file store cleanup ({removedFiles} of {totalFiles} deleted)"); } - - #region Windows hard link support - - // For future use (to detect if a file is a hard link with other references existing on disk). - public static int GetFileLinkCount(string filePath) - { - int result = 0; - SafeFileHandle handle = CreateFile(filePath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Archive, IntPtr.Zero); - - ByHandleFileInformation fileInfo; - - if (GetFileInformationByHandle(handle, out fileInfo)) - result = (int)fileInfo.NumberOfLinks; - CloseHandle(handle); - - return result; - } - - [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)] - public static extern bool CreateHardLink( - string lpFileName, - string lpExistingFileName, - IntPtr lpSecurityAttributes - ); - - [StructLayout(LayoutKind.Sequential)] - private struct ByHandleFileInformation - { - public readonly uint FileAttributes; - public readonly FILETIME CreationTime; - public readonly FILETIME LastAccessTime; - public readonly FILETIME LastWriteTime; - public readonly uint VolumeSerialNumber; - public readonly uint FileSizeHigh; - public readonly uint FileSizeLow; - public readonly uint NumberOfLinks; - public readonly uint FileIndexHigh; - public readonly uint FileIndexLow; - } - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] - private static extern SafeFileHandle CreateFile( - string lpFileName, - [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess, - [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, - IntPtr lpSecurityAttributes, - [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, - [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes, - IntPtr hTemplateFile); - - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool GetFileInformationByHandle(SafeFileHandle handle, out ByHandleFileInformation lpFileInformation); - - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool CloseHandle(SafeHandle hObject); - - #endregion } } diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs new file mode 100644 index 0000000000..4b6f871719 --- /dev/null +++ b/osu.Game/IO/HardLinkHelper.cs @@ -0,0 +1,68 @@ +// 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.IO; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using Microsoft.Win32.SafeHandles; + +namespace osu.Game.IO +{ + internal static class HardLinkHelper + { + // For future use (to detect if a file is a hard link with other references existing on disk). + public static int GetFileLinkCount(string filePath) + { + int result = 0; + SafeFileHandle handle = CreateFile(filePath, FileAccess.Read, FileShare.Read, IntPtr.Zero, FileMode.Open, FileAttributes.Archive, IntPtr.Zero); + + ByHandleFileInformation fileInfo; + + if (GetFileInformationByHandle(handle, out fileInfo)) + result = (int)fileInfo.NumberOfLinks; + CloseHandle(handle); + + return result; + } + + [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)] + public static extern bool CreateHardLink( + string lpFileName, + string lpExistingFileName, + IntPtr lpSecurityAttributes + ); + + [StructLayout(LayoutKind.Sequential)] + private struct ByHandleFileInformation + { + public readonly uint FileAttributes; + public readonly FILETIME CreationTime; + public readonly FILETIME LastAccessTime; + public readonly FILETIME LastWriteTime; + public readonly uint VolumeSerialNumber; + public readonly uint FileSizeHigh; + public readonly uint FileSizeLow; + public readonly uint NumberOfLinks; + public readonly uint FileIndexHigh; + public readonly uint FileIndexLow; + } + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + private static extern SafeFileHandle CreateFile( + string lpFileName, + [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess, + [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, + IntPtr lpSecurityAttributes, + [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, + [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes, + IntPtr hTemplateFile); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool GetFileInformationByHandle(SafeFileHandle handle, out ByHandleFileInformation lpFileInformation); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool CloseHandle(SafeHandle hObject); + } +} From 6bb612ce697a8d7bd09bb4dee2ff1572f542ef91 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Dec 2022 20:02:57 +0900 Subject: [PATCH 2577/2686] Move hard link availability check to helper class --- osu.Game/Database/LegacyImportManager.cs | 14 +---- osu.Game/IO/HardLinkHelper.cs | 80 ++++++++++++++++++------ 2 files changed, 63 insertions(+), 31 deletions(-) diff --git a/osu.Game/Database/LegacyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs index ec8eac611c..3f1ddb1eda 100644 --- a/osu.Game/Database/LegacyImportManager.cs +++ b/osu.Game/Database/LegacyImportManager.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading; using System.Threading.Tasks; using osu.Framework; @@ -57,22 +56,15 @@ namespace osu.Game.Database public bool CheckHardLinkAvailability() { - if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) - return false; - var stableStorage = GetCurrentStableStorage(); if (stableStorage == null || gameHost is not DesktopGameHost desktopGameHost) return false; - const string test_filename = "_hard_link_test"; + string testExistingPath = stableStorage.GetFullPath(string.Empty); + string testDestinationPath = desktopGameHost.Storage.GetFullPath(string.Empty); - desktopGameHost.Storage.Delete(test_filename); - - string testExistingPath = stableStorage.GetFullPath(stableStorage.GetFiles(string.Empty).First()); - string testDestinationPath = desktopGameHost.Storage.GetFullPath(test_filename); - - return HardLinkHelper.CreateHardLink(testDestinationPath, testExistingPath, IntPtr.Zero); + return HardLinkHelper.CheckAvailability(testDestinationPath, testExistingPath); } public virtual async Task GetImportCount(StableContent content, CancellationToken cancellationToken) diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index 4b6f871719..7e1f92c0ad 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -6,11 +6,55 @@ using System.IO; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using Microsoft.Win32.SafeHandles; +using osu.Framework; namespace osu.Game.IO { internal static class HardLinkHelper { + public static bool CheckAvailability(string testDestinationPath, string testSourcePath) + { + // We can support other operating systems quite easily in the future. + // Let's handle the most common one for now, though. + if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) + return false; + + const string test_filename = "_hard_link_test"; + + testDestinationPath = Path.Combine(testDestinationPath, test_filename); + testSourcePath = Path.Combine(testSourcePath, test_filename); + + cleanupFiles(); + + try + { + File.WriteAllText(testSourcePath, string.Empty); + + // Test availability by creating an arbitrary hard link between the source and destination paths. + return CreateHardLink(testDestinationPath, testSourcePath, IntPtr.Zero); + } + catch + { + return false; + } + finally + { + cleanupFiles(); + } + + void cleanupFiles() + { + try + { + File.Delete(testDestinationPath); + File.Delete(testSourcePath); + } + catch + { + } + } + } + // For future use (to detect if a file is a hard link with other references existing on disk). public static int GetFileLinkCount(string filePath) { @@ -27,26 +71,7 @@ namespace osu.Game.IO } [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)] - public static extern bool CreateHardLink( - string lpFileName, - string lpExistingFileName, - IntPtr lpSecurityAttributes - ); - - [StructLayout(LayoutKind.Sequential)] - private struct ByHandleFileInformation - { - public readonly uint FileAttributes; - public readonly FILETIME CreationTime; - public readonly FILETIME LastAccessTime; - public readonly FILETIME LastWriteTime; - public readonly uint VolumeSerialNumber; - public readonly uint FileSizeHigh; - public readonly uint FileSizeLow; - public readonly uint NumberOfLinks; - public readonly uint FileIndexHigh; - public readonly uint FileIndexLow; - } + public static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern SafeFileHandle CreateFile( @@ -64,5 +89,20 @@ namespace osu.Game.IO [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseHandle(SafeHandle hObject); + + [StructLayout(LayoutKind.Sequential)] + private struct ByHandleFileInformation + { + public readonly uint FileAttributes; + public readonly FILETIME CreationTime; + public readonly FILETIME LastAccessTime; + public readonly FILETIME LastWriteTime; + public readonly uint VolumeSerialNumber; + public readonly uint FileSizeHigh; + public readonly uint FileSizeLow; + public readonly uint NumberOfLinks; + public readonly uint FileIndexHigh; + public readonly uint FileIndexLow; + } } } From cb16d62700f3c107588c96fef4537501a9de4cc7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Dec 2022 21:03:25 +0900 Subject: [PATCH 2578/2686] Hook up `ImportParameter` flow with `IModelImporter` caller methods --- osu.Game.Tests/Database/BeatmapImporterTests.cs | 2 +- osu.Game/Beatmaps/BeatmapImporter.cs | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 4 ++-- osu.Game/Database/ICanAcceptFiles.cs | 4 +++- osu.Game/Database/IModelImporter.cs | 4 +++- osu.Game/Database/LegacyModelImporter.cs | 8 +++++++- osu.Game/Database/ModelDownloader.cs | 2 +- osu.Game/Database/RealmArchiveModelImporter.cs | 10 +++++----- osu.Game/OsuGame.cs | 4 ++-- osu.Game/OsuGameBase_Importing.cs | 5 +++-- .../Overlays/FirstRunSetup/ScreenImportFromStable.cs | 3 ++- osu.Game/Scoring/ScoreManager.cs | 4 ++-- osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs | 3 ++- osu.Game/Skinning/Editor/SkinEditor.cs | 3 ++- osu.Game/Skinning/SkinManager.cs | 6 +++--- 15 files changed, 39 insertions(+), 25 deletions(-) diff --git a/osu.Game.Tests/Database/BeatmapImporterTests.cs b/osu.Game.Tests/Database/BeatmapImporterTests.cs index cbaa7bf972..446eb72b04 100644 --- a/osu.Game.Tests/Database/BeatmapImporterTests.cs +++ b/osu.Game.Tests/Database/BeatmapImporterTests.cs @@ -564,7 +564,7 @@ namespace osu.Game.Tests.Database var imported = await importer.Import( progressNotification, - new ImportTask(zipStream, string.Empty) + new[] { new ImportTask(zipStream, string.Empty) } ); realm.Run(r => r.Refresh()); diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index 303e85b83a..8a6315fc65 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -44,7 +44,7 @@ namespace osu.Game.Beatmaps public override async Task?> ImportAsUpdate(ProgressNotification notification, ImportTask importTask, BeatmapSetInfo original) { - var imported = await Import(notification, importTask); + var imported = await Import(notification, new[] { importTask }); if (!imported.Any()) return null; diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index e288239d74..f0fd8bd2e0 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -456,9 +456,9 @@ namespace osu.Game.Beatmaps public Task Import(params string[] paths) => beatmapImporter.Import(paths); - public Task Import(params ImportTask[] tasks) => beatmapImporter.Import(tasks); + public Task Import(ImportTask[] tasks, ImportParameters parameters = default) => beatmapImporter.Import(tasks, parameters); - public Task>> Import(ProgressNotification notification, params ImportTask[] tasks) => beatmapImporter.Import(notification, tasks); + public Task>> Import(ProgressNotification notification, ImportTask[] tasks, ImportParameters parameters = default) => beatmapImporter.Import(notification, tasks, parameters); public Task?> Import(ImportTask task, ImportParameters parameters = default, CancellationToken cancellationToken = default) => beatmapImporter.Import(task, parameters, cancellationToken); diff --git a/osu.Game/Database/ICanAcceptFiles.cs b/osu.Game/Database/ICanAcceptFiles.cs index 3ce343249b..4fdedd4688 100644 --- a/osu.Game/Database/ICanAcceptFiles.cs +++ b/osu.Game/Database/ICanAcceptFiles.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Threading.Tasks; +using osu.Game.Beatmaps; namespace osu.Game.Database { @@ -31,7 +32,8 @@ namespace osu.Game.Database /// This will post notifications tracking progress. /// /// The import tasks from which the files should be imported. - Task Import(params ImportTask[] tasks); + /// Parameters to further configure the import process. + Task Import(ImportTask[] tasks, ImportParameters parameters = default); /// /// An array of accepted file extensions (in the standard format of ".abc"). diff --git a/osu.Game/Database/IModelImporter.cs b/osu.Game/Database/IModelImporter.cs index 4085f122d0..5896715a8f 100644 --- a/osu.Game/Database/IModelImporter.cs +++ b/osu.Game/Database/IModelImporter.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using osu.Game.Beatmaps; using osu.Game.Overlays.Notifications; namespace osu.Game.Database @@ -20,8 +21,9 @@ namespace osu.Game.Database /// /// The notification to update. /// The import tasks. + /// Parameters to further configure the import process. /// The imported models. - Task>> Import(ProgressNotification notification, params ImportTask[] tasks); + Task>> Import(ProgressNotification notification, ImportTask[] tasks, ImportParameters parameters = default); /// /// Process a single import as an update for an existing model. diff --git a/osu.Game/Database/LegacyModelImporter.cs b/osu.Game/Database/LegacyModelImporter.cs index df354a856e..176c660e61 100644 --- a/osu.Game/Database/LegacyModelImporter.cs +++ b/osu.Game/Database/LegacyModelImporter.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Logging; using osu.Framework.Platform; +using osu.Game.Beatmaps; using osu.Game.IO; namespace osu.Game.Database @@ -57,7 +58,12 @@ namespace osu.Game.Database return Task.CompletedTask; } - return Task.Run(async () => await Importer.Import(GetStableImportPaths(storage).ToArray()).ConfigureAwait(false)); + return Task.Run(async () => + { + var tasks = GetStableImportPaths(storage).Select(p => new ImportTask(p)).ToArray(); + + await Importer.Import(tasks, new ImportParameters { Batch = true, PreferHardLinks = true }).ConfigureAwait(false); + }); } /// diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index 3e2d034937..2f082306d0 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -73,7 +73,7 @@ namespace osu.Game.Database if (originalModel != null) importSuccessful = (await importer.ImportAsUpdate(notification, new ImportTask(filename), originalModel)) != null; else - importSuccessful = (await importer.Import(notification, new ImportTask(filename))).Any(); + importSuccessful = (await importer.Import(notification, new[] { new ImportTask(filename) })).Any(); // for now a failed import will be marked as a failed download for simplicity. if (!importSuccessful) diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index 1f9debc46f..bf51e8d49e 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -82,16 +82,16 @@ namespace osu.Game.Database public Task Import(params string[] paths) => Import(paths.Select(p => new ImportTask(p)).ToArray()); - public Task Import(params ImportTask[] tasks) + public Task Import(ImportTask[] tasks, ImportParameters parameters = default) { var notification = new ProgressNotification { State = ProgressNotificationState.Active }; PostNotification?.Invoke(notification); - return Import(notification, tasks); + return Import(notification, tasks, parameters); } - public async Task>> Import(ProgressNotification notification, params ImportTask[] tasks) + public async Task>> Import(ProgressNotification notification, ImportTask[] tasks, ImportParameters parameters = default) { if (tasks.Length == 0) { @@ -107,7 +107,7 @@ namespace osu.Game.Database var imported = new List>(); - bool isBatchImport = tasks.Length >= minimum_items_considered_batch_import; + parameters.Batch |= tasks.Length >= minimum_items_considered_batch_import; await Task.WhenAll(tasks.Select(async task => { @@ -116,7 +116,7 @@ namespace osu.Game.Database try { - var model = await Import(task, new ImportParameters { Batch = isBatchImport }, notification.CancellationToken).ConfigureAwait(false); + var model = await Import(task, parameters, notification.CancellationToken).ConfigureAwait(false); lock (imported) { diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 5565fa7ef3..8fb6806c27 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -616,14 +616,14 @@ namespace osu.Game }, validScreens: validScreens); } - public override Task Import(params ImportTask[] imports) + public override Task Import(ImportTask[] imports, ImportParameters parameters = default) { // encapsulate task as we don't want to begin the import process until in a ready state. // ReSharper disable once AsyncVoidLambda // TODO: This is bad because `new Task` doesn't have a Func override. // Only used for android imports and a bit of a mess. Probably needs rethinking overall. - var importTask = new Task(async () => await base.Import(imports).ConfigureAwait(false)); + var importTask = new Task(async () => await base.Import(imports, parameters).ConfigureAwait(false)); waitForReady(() => this, _ => importTask.Start()); diff --git a/osu.Game/OsuGameBase_Importing.cs b/osu.Game/OsuGameBase_Importing.cs index e34e48f21d..565b0f37ae 100644 --- a/osu.Game/OsuGameBase_Importing.cs +++ b/osu.Game/OsuGameBase_Importing.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using osu.Game.Beatmaps; using osu.Game.Database; namespace osu.Game @@ -44,13 +45,13 @@ namespace osu.Game } } - public virtual async Task Import(params ImportTask[] tasks) + public virtual async Task Import(ImportTask[] tasks, ImportParameters parameters = default) { var tasksPerExtension = tasks.GroupBy(t => Path.GetExtension(t.Path).ToLowerInvariant()); await Task.WhenAll(tasksPerExtension.Select(taskGroup => { var importer = fileImporters.FirstOrDefault(i => i.HandledExtensions.Contains(taskGroup.Key)); - return importer?.Import(taskGroup.ToArray()) ?? Task.CompletedTask; + return importer?.Import(taskGroup.ToArray(), parameters) ?? Task.CompletedTask; })).ConfigureAwait(false); } diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 4af80c6fbb..bf8092fbfa 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Screens; +using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -269,7 +270,7 @@ namespace osu.Game.Overlays.FirstRunSetup return Task.CompletedTask; } - Task ICanAcceptFiles.Import(params ImportTask[] tasks) => throw new NotImplementedException(); + Task ICanAcceptFiles.Import(ImportTask[] tasks, ImportParameters parameters) => throw new NotImplementedException(); protected override void Dispose(bool isDisposing) { diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index a57db0eccf..5ec96a951b 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -169,13 +169,13 @@ namespace osu.Game.Scoring public Task Import(params string[] paths) => scoreImporter.Import(paths); - public Task Import(params ImportTask[] tasks) => scoreImporter.Import(tasks); + public Task Import(ImportTask[] imports, ImportParameters parameters = default) => scoreImporter.Import(imports, parameters); public override bool IsAvailableLocally(ScoreInfo model) => Realm.Run(realm => realm.All().Any(s => s.OnlineID == model.OnlineID)); public IEnumerable HandledExtensions => scoreImporter.HandledExtensions; - public Task>> Import(ProgressNotification notification, params ImportTask[] tasks) => scoreImporter.Import(notification, tasks); + public Task>> Import(ProgressNotification notification, ImportTask[] tasks, ImportParameters parameters = default) => scoreImporter.Import(notification, tasks); public Task> ImportAsUpdate(ProgressNotification notification, ImportTask task, ScoreInfo original) => scoreImporter.ImportAsUpdate(notification, task, original); diff --git a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs index 57d28824b1..b7ca84776b 100644 --- a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs +++ b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs @@ -16,6 +16,7 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Platform; +using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics.UserInterfaceV2; using osuTK; @@ -91,7 +92,7 @@ namespace osu.Game.Screens.Edit.Setup return Task.CompletedTask; } - Task ICanAcceptFiles.Import(params ImportTask[] tasks) => throw new NotImplementedException(); + Task ICanAcceptFiles.Import(ImportTask[] tasks, ImportParameters parameters) => throw new NotImplementedException(); protected override void Dispose(bool isDisposing) { diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 1dd9c93845..5531e08d3c 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -18,6 +18,7 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Framework.Testing; +using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -411,7 +412,7 @@ namespace osu.Game.Skinning.Editor return Task.CompletedTask; } - public Task Import(params ImportTask[] tasks) => throw new NotImplementedException(); + Task ICanAcceptFiles.Import(ImportTask[] tasks, ImportParameters parameters) => throw new NotImplementedException(); public IEnumerable HandledExtensions => new[] { ".jpg", ".jpeg", ".png" }; diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 40c43563b2..467a88c864 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -271,12 +271,12 @@ namespace osu.Game.Skinning public Task Import(params string[] paths) => skinImporter.Import(paths); - public Task Import(params ImportTask[] tasks) => skinImporter.Import(tasks); + public Task Import(ImportTask[] imports, ImportParameters parameters = default) => skinImporter.Import(imports, parameters); public IEnumerable HandledExtensions => skinImporter.HandledExtensions; - public Task>> Import(ProgressNotification notification, params ImportTask[] tasks) => - skinImporter.Import(notification, tasks); + public Task>> Import(ProgressNotification notification, ImportTask[] tasks, ImportParameters parameters = default) => + skinImporter.Import(notification, tasks, parameters); public Task> ImportAsUpdate(ProgressNotification notification, ImportTask task, SkinInfo original) => skinImporter.ImportAsUpdate(notification, task, original); From b8904fe7474e17bf48a7dbbbd60ae338dd77529c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Dec 2022 21:41:26 +0900 Subject: [PATCH 2579/2686] Move `ImportParameters` to better home --- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 1 - osu.Game/Beatmaps/BeatmapManager.cs | 20 --------------- osu.Game/Database/ICanAcceptFiles.cs | 1 - osu.Game/Database/IModelImporter.cs | 1 - osu.Game/Database/ImportParameters.cs | 25 +++++++++++++++++++ osu.Game/Database/LegacyModelImporter.cs | 1 - .../Database/RealmArchiveModelImporter.cs | 1 - osu.Game/OsuGameBase_Importing.cs | 1 - .../FirstRunSetup/ScreenImportFromStable.cs | 1 - .../Screens/Edit/Setup/LabelledFileChooser.cs | 1 - osu.Game/Skinning/Editor/SkinEditor.cs | 1 - osu.Game/Skinning/SkinManager.cs | 1 - 12 files changed, 25 insertions(+), 30 deletions(-) create mode 100644 osu.Game/Database/ImportParameters.cs diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index f90c983627..0bd40e9962 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -12,7 +12,6 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Platform; -using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Extensions; using osu.Game.IO; diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index f0fd8bd2e0..f0533f27be 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -526,24 +526,4 @@ namespace osu.Game.Beatmaps public override string HumanisedModelName => "beatmap"; } - - public struct ImportParameters - { - /// - /// Whether this import is part of a larger batch. - /// - /// - /// May skip intensive pre-import checks in favour of faster processing. - /// - /// More specifically, imports will be skipped before they begin, given an existing model matches on hash and filenames. Should generally only be used for large batch imports, as it may defy user expectations when updating an existing model. - /// - /// Will also change scheduling behaviour to run at a lower priority. - /// - public bool Batch { get; set; } - - /// - /// Whether this import should use hard links rather than file copy operations if available. - /// - public bool PreferHardLinks { get; set; } - } } diff --git a/osu.Game/Database/ICanAcceptFiles.cs b/osu.Game/Database/ICanAcceptFiles.cs index 4fdedd4688..da970a29d4 100644 --- a/osu.Game/Database/ICanAcceptFiles.cs +++ b/osu.Game/Database/ICanAcceptFiles.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Threading.Tasks; -using osu.Game.Beatmaps; namespace osu.Game.Database { diff --git a/osu.Game/Database/IModelImporter.cs b/osu.Game/Database/IModelImporter.cs index 5896715a8f..dcbbad0d35 100644 --- a/osu.Game/Database/IModelImporter.cs +++ b/osu.Game/Database/IModelImporter.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using osu.Game.Beatmaps; using osu.Game.Overlays.Notifications; namespace osu.Game.Database diff --git a/osu.Game/Database/ImportParameters.cs b/osu.Game/Database/ImportParameters.cs new file mode 100644 index 0000000000..83ca0ac694 --- /dev/null +++ b/osu.Game/Database/ImportParameters.cs @@ -0,0 +1,25 @@ +// 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.Database +{ + public struct ImportParameters + { + /// + /// Whether this import is part of a larger batch. + /// + /// + /// May skip intensive pre-import checks in favour of faster processing. + /// + /// More specifically, imports will be skipped before they begin, given an existing model matches on hash and filenames. Should generally only be used for large batch imports, as it may defy user expectations when updating an existing model. + /// + /// Will also change scheduling behaviour to run at a lower priority. + /// + public bool Batch { get; set; } + + /// + /// Whether this import should use hard links rather than file copy operations if available. + /// + public bool PreferHardLinks { get; set; } + } +} diff --git a/osu.Game/Database/LegacyModelImporter.cs b/osu.Game/Database/LegacyModelImporter.cs index 176c660e61..29386a1103 100644 --- a/osu.Game/Database/LegacyModelImporter.cs +++ b/osu.Game/Database/LegacyModelImporter.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Logging; using osu.Framework.Platform; -using osu.Game.Beatmaps; using osu.Game.IO; namespace osu.Game.Database diff --git a/osu.Game/Database/RealmArchiveModelImporter.cs b/osu.Game/Database/RealmArchiveModelImporter.cs index bf51e8d49e..4e8b27e0b4 100644 --- a/osu.Game/Database/RealmArchiveModelImporter.cs +++ b/osu.Game/Database/RealmArchiveModelImporter.cs @@ -13,7 +13,6 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Framework.Threading; -using osu.Game.Beatmaps; using osu.Game.Extensions; using osu.Game.IO.Archives; using osu.Game.Models; diff --git a/osu.Game/OsuGameBase_Importing.cs b/osu.Game/OsuGameBase_Importing.cs index 565b0f37ae..cf65460bab 100644 --- a/osu.Game/OsuGameBase_Importing.cs +++ b/osu.Game/OsuGameBase_Importing.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using osu.Game.Beatmaps; using osu.Game.Database; namespace osu.Game diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index bf8092fbfa..8ce92dab12 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -17,7 +17,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Framework.Screens; -using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; diff --git a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs index b7ca84776b..d14357e875 100644 --- a/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs +++ b/osu.Game/Screens/Edit/Setup/LabelledFileChooser.cs @@ -16,7 +16,6 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Platform; -using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics.UserInterfaceV2; using osuTK; diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 5531e08d3c..0ed4e5afd2 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -18,7 +18,6 @@ using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Framework.Testing; -using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics; using osu.Game.Graphics.Containers; diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 467a88c864..2ad62dbb61 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -22,7 +22,6 @@ using osu.Framework.Testing; using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Audio; -using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.IO; using osu.Game.Overlays.Notifications; From edc78205d5312e9278f2a22ef156fd34af492595 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Dec 2022 22:06:03 +0900 Subject: [PATCH 2580/2686] Add comments about why both positional input checks are required in `OsuClickableContainer` --- osu.Game/Graphics/Containers/OsuClickableContainer.cs | 6 +++++- osu.Game/Graphics/UserInterface/OsuButton.cs | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index ecae456e88..6ec393df4b 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -17,7 +17,11 @@ namespace osu.Game.Graphics.Containers private readonly Container content = new Container { RelativeSizeAxes = Axes.Both }; - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) && Content.ReceivePositionalInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + // base call is checked for cases when `OsuClickableContainer` has masking applied to it directly (ie. externally in object initialisation). + base.ReceivePositionalInputAt(screenSpacePos) + // Implementations often apply masking / edge rounding at a content level, so it's imperative to check that as well. + && Content.ReceivePositionalInputAt(screenSpacePos); protected override Container Content => content; diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 00cd3b13e5..3fccf51cc2 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -61,7 +61,11 @@ namespace osu.Game.Graphics.UserInterface protected override Container Content { get; } - public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) && Content.ReceivePositionalInputAt(screenSpacePos); + public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => + // base call is checked for cases when `OsuClickableContainer` has masking applied to it directly (ie. externally in object initialisation). + base.ReceivePositionalInputAt(screenSpacePos) + // Implementations often apply masking / edge rounding at a content level, so it's imperative to check that as well. + && Content.ReceivePositionalInputAt(screenSpacePos); protected Box Hover; protected Box Background; From efe057176e26b82ec320cce03115a7e121fb3d0d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Dec 2022 22:13:48 +0900 Subject: [PATCH 2581/2686] Make `OsuButton` `abstract` --- .../UserInterface/TestSceneOsuButton.cs | 47 ------------------- osu.Game/Graphics/UserInterface/OsuButton.cs | 4 +- 2 files changed, 2 insertions(+), 49 deletions(-) delete mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs deleted file mode 100644 index 41e5d47093..0000000000 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuButton.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -#nullable disable - -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; -using osuTK; - -namespace osu.Game.Tests.Visual.UserInterface -{ - public partial class TestSceneOsuButton : OsuTestScene - { - [Test] - public void TestToggleEnabled() - { - OsuButton button = null; - - AddStep("add button", () => Child = button = new OsuButton - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(200), - Text = "Button" - }); - - AddToggleStep("toggle enabled", toggle => - { - for (int i = 0; i < 6; i++) - button.Action = toggle ? () => { } : null; - }); - } - - [Test] - public void TestInitiallyDisabled() - { - AddStep("add button", () => Child = new OsuButton - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(200), - Text = "Button" - }); - } - } -} diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 3fccf51cc2..805dfcaa95 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -19,7 +19,7 @@ namespace osu.Game.Graphics.UserInterface /// /// A button with added default sound effects. /// - public partial class OsuButton : Button + public abstract partial class OsuButton : Button { public LocalisableString Text { @@ -73,7 +73,7 @@ namespace osu.Game.Graphics.UserInterface private readonly Box flashLayer; - public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Button) + protected OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Button) { Height = 40; From bf56f5f8c08583927a35cc02da3881dba40a196a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Dec 2022 18:27:14 +0900 Subject: [PATCH 2582/2686] Show error message on attempting to open a URL with an unsupported protocol --- osu.Game.Tests/Chat/MessageFormatterTests.cs | 10 ++++++++++ osu.Game/OsuGame.cs | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/osu.Game.Tests/Chat/MessageFormatterTests.cs b/osu.Game.Tests/Chat/MessageFormatterTests.cs index ebfa9bd8b7..3c35dc311f 100644 --- a/osu.Game.Tests/Chat/MessageFormatterTests.cs +++ b/osu.Game.Tests/Chat/MessageFormatterTests.cs @@ -26,6 +26,16 @@ namespace osu.Game.Tests.Chat MessageFormatter.WebsiteRootUrl = originalWebsiteRootUrl; } + [Test] + public void TestUnsupportedProtocolLink() + { + Message result = MessageFormatter.FormatMessage(new Message { Content = "This is a gopher://really-old-protocol we don't support." }); + + Assert.AreEqual(result.Content, result.DisplayContent); + Assert.AreEqual(1, result.Links.Count); + Assert.AreEqual("gopher://really-old-protocol", result.Links[0].Url); + } + [Test] public void TestBareLink() { diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 5565fa7ef3..bd33ab6545 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -16,6 +16,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Configuration; +using osu.Framework.Extensions; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics; @@ -406,6 +407,16 @@ namespace osu.Game if (url.StartsWith('/')) url = $"{API.APIEndpointUrl}{url}"; + if (!url.CheckIsValidUrl()) + { + Notifications.Post(new SimpleErrorNotification + { + Text = $"The URL {url} has an unsupported or dangerous protocol and will not be opened.", + }); + + return; + } + externalLinkOpener.OpenUrlExternally(url, bypassExternalUrlWarning); }); From 3d65984a893533166df3a93e3396625d79b84abd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 13 Dec 2022 22:34:01 +0900 Subject: [PATCH 2583/2686] 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 147d236d98..c2c74e2c0e 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8639ce6361..31cd851c03 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 184e3303c8..b2aa3caa14 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -62,7 +62,7 @@ - + @@ -82,7 +82,7 @@ - + From f4316a9827d89fcf62120419f46b290c9a2a4e6c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Dec 2022 11:30:01 +0900 Subject: [PATCH 2584/2686] Fix incorrect grammar in hard link explanation text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 8ce92dab12..04aa976ff1 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -129,7 +129,7 @@ namespace osu.Game.Overlays.FirstRunSetup copyInformation.Text = "Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation."; } else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) - copyInformation.Text = "Lightweight linking of files are not supported on your operating system yet, so a copy of all files will be made during import."; + copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import."; else { copyInformation.Text = From a3c3112f897a0d9c327c4aaf6fa96c00bff3abe4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 14 Dec 2022 11:34:06 +0900 Subject: [PATCH 2585/2686] Add `SetLastError` hint to `CreateHardLink` pinvoke method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/IO/HardLinkHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/IO/HardLinkHelper.cs b/osu.Game/IO/HardLinkHelper.cs index 7e1f92c0ad..1393bf26fd 100644 --- a/osu.Game/IO/HardLinkHelper.cs +++ b/osu.Game/IO/HardLinkHelper.cs @@ -70,7 +70,7 @@ namespace osu.Game.IO return result; } - [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)] + [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] From fb85eaee950ed490e9238fa261766eeef58802a1 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Wed, 14 Dec 2022 18:30:31 +0900 Subject: [PATCH 2586/2686] Add description for lazer score version 30000001 --- osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs index 5452e4b9eb..a78ae24da2 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreEncoder.cs @@ -25,6 +25,11 @@ namespace osu.Game.Scoring.Legacy /// Database version in stable-compatible YYYYMMDD format. /// Should be incremented if any changes are made to the format/usage. /// + /// + /// + /// 30000001: Appends to the end of scores. + /// + /// public const int LATEST_VERSION = 30000001; /// From 6bf1477939980b597d07784744dfa65cb85e0c65 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Dec 2022 14:17:28 +0900 Subject: [PATCH 2587/2686] Fix some hard links not being created due to missing directory structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Database/RealmFileStore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/RealmFileStore.cs b/osu.Game/Database/RealmFileStore.cs index 71ea6cba58..04b503b808 100644 --- a/osu.Game/Database/RealmFileStore.cs +++ b/osu.Game/Database/RealmFileStore.cs @@ -66,7 +66,7 @@ namespace osu.Game.Database if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows && data is FileStream fs && preferHardLinks) { // attempt to do a fast hard link rather than copy. - if (HardLinkHelper.CreateHardLink(Storage.GetFullPath(file.GetStoragePath()), fs.Name, IntPtr.Zero)) + if (HardLinkHelper.CreateHardLink(Storage.GetFullPath(file.GetStoragePath(), true), fs.Name, IntPtr.Zero)) return; } From a7f3e139461d1c63a4aa4fb98a01b859e3ab6cb9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Dec 2022 16:56:09 +0900 Subject: [PATCH 2588/2686] Fix `MultipleSelectionFilter` not correctly handling initial selection --- .../BeatmapSearchMultipleSelectionFilterRow.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index 79a794a9ad..5d1ccbd58b 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.Collections.Specialized; using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; @@ -18,6 +19,7 @@ using osuTK; namespace osu.Game.Overlays.BeatmapListing { public partial class BeatmapSearchMultipleSelectionFilterRow : BeatmapSearchFilterRow> + where T : Enum { public new readonly BindableList Current = new BindableList(); @@ -31,7 +33,7 @@ namespace osu.Game.Overlays.BeatmapListing [BackgroundDependencyLoader] private void load() { - Current.BindTo(filter.Current); + filter.Current.BindTo(Current); } protected sealed override Drawable CreateFilter() => filter = CreateMultipleSelectionFilter(); @@ -64,6 +66,14 @@ namespace osu.Game.Overlays.BeatmapListing foreach (var item in Children) item.Active.BindValueChanged(active => toggleItem(item.Value, active.NewValue)); + + Current.BindCollectionChanged(currentChanged, true); + } + + private void currentChanged(object sender, NotifyCollectionChangedEventArgs e) + { + foreach (var c in Children) + c.Active.Value = Current.Contains(c.Value); } /// @@ -79,7 +89,10 @@ namespace osu.Game.Overlays.BeatmapListing private void toggleItem(T value, bool active) { if (active) - Current.Add(value); + { + if (!Current.Contains(value)) + Current.Add(value); + } else Current.Remove(value); } From 78bc94d3cb179c390c2753c1b1a5073085ab274d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Dec 2022 16:57:39 +0900 Subject: [PATCH 2589/2686] Set featured artists filter to enabled by default --- osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index f28ec9c295..23de1cf76d 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -146,6 +146,7 @@ namespace osu.Game.Overlays.BeatmapListing } }); + generalFilter.Current.Add(SearchGeneral.FeaturedArtists); categoryFilter.Current.Value = SearchCategory.Leaderboard; } From 0763b86236bad6fe3b1839f0103746ca2c47a8e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Dec 2022 17:32:27 +0900 Subject: [PATCH 2590/2686] Add more padding around text in dialog popups --- osu.Game/Overlays/Dialog/PopupDialog.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 80e0ffe427..f5a7e9e43d 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -198,6 +198,7 @@ namespace osu.Game.Overlays.Dialog TextAnchor = Anchor.TopCentre, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(5), }, }, }, From d2b98b803d398c5ecf4284dbbcdd5b13edad3192 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Dec 2022 17:35:39 +0900 Subject: [PATCH 2591/2686] Turn on featured artist filter by default and add disclaimer when toggling for the first time --- osu.Game/Configuration/SessionStatics.cs | 4 +- .../Localisation/BeatmapOverlayStrings.cs | 34 ++++++++++ .../BeatmapSearchGeneralFilterRow.cs | 63 +++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Localisation/BeatmapOverlayStrings.cs diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 12a30a0c84..276563e163 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -19,6 +19,7 @@ namespace osu.Game.Configuration SetDefault(Static.LoginOverlayDisplayed, false); SetDefault(Static.MutedAudioNotificationShownOnce, false); SetDefault(Static.LowBatteryNotificationShownOnce, false); + SetDefault(Static.FeaturedArtistDisclaimerShownOnce, false); SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null); SetDefault(Static.SeasonalBackgrounds, null); } @@ -42,6 +43,7 @@ namespace osu.Game.Configuration LoginOverlayDisplayed, MutedAudioNotificationShownOnce, LowBatteryNotificationShownOnce, + FeaturedArtistDisclaimerShownOnce, /// /// Info about seasonal backgrounds available fetched from API - see . @@ -53,6 +55,6 @@ namespace osu.Game.Configuration /// The last playback time in milliseconds of a hover sample (from ). /// Used to debounce hover sounds game-wide to avoid volume saturation, especially in scrolling views with many UI controls like . /// - LastHoverSoundPlaybackTime + LastHoverSoundPlaybackTime, } } diff --git a/osu.Game/Localisation/BeatmapOverlayStrings.cs b/osu.Game/Localisation/BeatmapOverlayStrings.cs new file mode 100644 index 0000000000..efa9fcf155 --- /dev/null +++ b/osu.Game/Localisation/BeatmapOverlayStrings.cs @@ -0,0 +1,34 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class BeatmapOverlayStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.BeatmapOverlayStrings"; + + /// + /// "User content disclaimer" + /// + public static LocalisableString UserContentDisclaimer => new TranslatableString(getKey(@"user_content_disclaimer"), @"User content disclaimer"); + + /// + /// "By turning off the "featured artist" filter, all user uploaded content will be displayed. + /// + /// This includes content which may not be correctly licensed for use and as such may not be safe for streaming, sharing, or consumption." + /// + public static LocalisableString ByTurningOffTheFeatured => new TranslatableString(getKey(@"by_turning_off_the_featured"), + @"By turning off the ""featured artist"" filter, all user uploaded content will be displayed. + +This includes content which may not be correctly licensed for use and as such may not be safe for streaming, sharing, or consumption."); + + /// + /// "I understand" + /// + public static LocalisableString Understood => new TranslatableString(getKey(@"understood"), @"I understand"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs index 10ec66e396..41a78473e5 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs @@ -3,10 +3,18 @@ #nullable disable +using System; using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osu.Game.Configuration; using osu.Game.Graphics; +using osu.Game.Localisation; +using osu.Game.Overlays.Dialog; using osu.Game.Resources.Localisation.Web; using osuTK.Graphics; +using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Overlays.BeatmapListing { @@ -32,6 +40,8 @@ namespace osu.Game.Overlays.BeatmapListing private partial class FeaturedArtistsTabItem : MultipleSelectionFilterTabItem { + private Bindable disclaimerShown; + public FeaturedArtistsTabItem() : base(SearchGeneral.FeaturedArtists) { @@ -40,7 +50,60 @@ namespace osu.Game.Overlays.BeatmapListing [Resolved] private OsuColour colours { get; set; } + [Resolved] + private SessionStatics sessionStatics { get; set; } + + [Resolved(canBeNull: true)] + private IDialogOverlay dialogOverlay { get; set; } + protected override Color4 GetStateColour() => colours.Orange1; + + protected override void LoadComplete() + { + base.LoadComplete(); + + disclaimerShown = sessionStatics.GetBindable(Static.FeaturedArtistDisclaimerShownOnce); + } + + protected override bool OnClick(ClickEvent e) + { + if (!disclaimerShown.Value && dialogOverlay != null) + { + dialogOverlay.Push(new FeaturedArtistConfirmDialog(() => + { + disclaimerShown.Value = true; + base.OnClick(e); + })); + + return true; + } + + return base.OnClick(e); + } + } + } + + internal partial class FeaturedArtistConfirmDialog : PopupDialog + { + public FeaturedArtistConfirmDialog(Action confirm) + { + HeaderText = BeatmapOverlayStrings.UserContentDisclaimer; + BodyText = BeatmapOverlayStrings.ByTurningOffTheFeatured; + + Icon = FontAwesome.Solid.ExclamationTriangle; + + Buttons = new PopupDialogButton[] + { + new PopupDialogDangerousButton + { + Text = BeatmapOverlayStrings.Understood, + Action = confirm + }, + new PopupDialogCancelButton + { + Text = CommonStrings.ButtonsCancel, + }, + }; } } } From 57048f0ebaaf11ef14253c78005bfcd84a5f603d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Dec 2022 18:42:58 +0900 Subject: [PATCH 2592/2686] Add test coverage of featured artist filter confirmation process --- .../Navigation/TestSceneScreenNavigation.cs | 23 +++++++++++++++++++ .../Online/TestSceneBeatmapListingOverlay.cs | 9 ++++++++ 2 files changed, 32 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index d8fda5b21f..ddb01b90ce 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -19,6 +19,7 @@ using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; +using osu.Game.Overlays.BeatmapListing; using osu.Game.Overlays.Mods; using osu.Game.Overlays.Toolbar; using osu.Game.Rulesets.Mods; @@ -515,6 +516,28 @@ namespace osu.Game.Tests.Visual.Navigation AddWaitStep("wait two frames", 2); } + [Test] + public void TestFeaturedArtistDisclaimerDialog() + { + BeatmapListingOverlay getBeatmapListingOverlay() => Game.ChildrenOfType().FirstOrDefault(); + + AddStep("Wait for notifications to load", () => Game.SearchBeatmapSet(string.Empty)); + AddUntilStep("wait for dialog overlay", () => Game.ChildrenOfType().SingleOrDefault() != null); + + AddUntilStep("Wait for beatmap overlay to load", () => getBeatmapListingOverlay()?.State.Value == Visibility.Visible); + AddAssert("featured artist filter is on", () => getBeatmapListingOverlay().ChildrenOfType().First().Current.Contains(SearchGeneral.FeaturedArtists)); + AddStep("toggle featured artist filter", + () => getBeatmapListingOverlay().ChildrenOfType>().First(i => i.Value == SearchGeneral.FeaturedArtists).TriggerClick()); + + AddAssert("disclaimer dialog is shown", () => Game.ChildrenOfType().Single().CurrentDialog != null); + AddAssert("featured artist filter is still on", () => getBeatmapListingOverlay().ChildrenOfType().First().Current.Contains(SearchGeneral.FeaturedArtists)); + + AddStep("confirm", () => InputManager.Key(Key.Enter)); + AddAssert("dialog dismissed", () => Game.ChildrenOfType().Single().CurrentDialog == null); + + AddUntilStep("featured artist filter is off", () => !getBeatmapListingOverlay().ChildrenOfType().First().Current.Contains(SearchGeneral.FeaturedArtists)); + } + [Test] public void TestMainOverlaysClosesNotificationOverlay() { diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs index c64343b47b..5e49cb633e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs @@ -80,6 +80,15 @@ namespace osu.Game.Tests.Visual.Online AddStep("reset size", () => localConfig.SetValue(OsuSetting.BeatmapListingCardSize, BeatmapCardSize.Normal)); } + [Test] + public void TestFeaturedArtistFilter() + { + AddAssert("is visible", () => overlay.State.Value == Visibility.Visible); + AddAssert("featured artist filter is on", () => overlay.ChildrenOfType().First().Current.Contains(SearchGeneral.FeaturedArtists)); + AddStep("toggle featured artist filter", () => overlay.ChildrenOfType>().First(i => i.Value == SearchGeneral.FeaturedArtists).TriggerClick()); + AddAssert("featured artist filter is off", () => !overlay.ChildrenOfType().First().Current.Contains(SearchGeneral.FeaturedArtists)); + } + [Test] public void TestHideViaBack() { From 91adf2e80f62f7ffd296474c3836d7e8ef7f5510 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Dec 2022 22:44:47 +0900 Subject: [PATCH 2593/2686] Apply the wala-hyphen Co-authored-by: Walavouchey <36758269+Walavouchey@users.noreply.github.com> --- osu.Game/Localisation/BeatmapOverlayStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/BeatmapOverlayStrings.cs b/osu.Game/Localisation/BeatmapOverlayStrings.cs index efa9fcf155..b2625dc0e6 100644 --- a/osu.Game/Localisation/BeatmapOverlayStrings.cs +++ b/osu.Game/Localisation/BeatmapOverlayStrings.cs @@ -15,12 +15,12 @@ namespace osu.Game.Localisation public static LocalisableString UserContentDisclaimer => new TranslatableString(getKey(@"user_content_disclaimer"), @"User content disclaimer"); /// - /// "By turning off the "featured artist" filter, all user uploaded content will be displayed. + /// "By turning off the "Featured Artist" filter, all user-uploaded content will be displayed. /// /// This includes content which may not be correctly licensed for use and as such may not be safe for streaming, sharing, or consumption." /// public static LocalisableString ByTurningOffTheFeatured => new TranslatableString(getKey(@"by_turning_off_the_featured"), - @"By turning off the ""featured artist"" filter, all user uploaded content will be displayed. + @"By turning off the ""Featured Artist"" filter, all user-uploaded content will be displayed. This includes content which may not be correctly licensed for use and as such may not be safe for streaming, sharing, or consumption."); From 9813bc95444466b723608aab2b4ae72e0111f7df Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 15 Dec 2022 22:46:31 +0900 Subject: [PATCH 2594/2686] Reword disclaimer and fix translation keys --- osu.Game/Localisation/BeatmapOverlayStrings.cs | 11 +++++------ .../BeatmapListing/BeatmapSearchGeneralFilterRow.cs | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game/Localisation/BeatmapOverlayStrings.cs b/osu.Game/Localisation/BeatmapOverlayStrings.cs index b2625dc0e6..fc818f7596 100644 --- a/osu.Game/Localisation/BeatmapOverlayStrings.cs +++ b/osu.Game/Localisation/BeatmapOverlayStrings.cs @@ -12,22 +12,21 @@ namespace osu.Game.Localisation /// /// "User content disclaimer" /// - public static LocalisableString UserContentDisclaimer => new TranslatableString(getKey(@"user_content_disclaimer"), @"User content disclaimer"); + public static LocalisableString UserContentDisclaimerHeader => new TranslatableString(getKey(@"user_content_disclaimer"), @"User content disclaimer"); /// /// "By turning off the "Featured Artist" filter, all user-uploaded content will be displayed. /// - /// This includes content which may not be correctly licensed for use and as such may not be safe for streaming, sharing, or consumption." + /// This includes content that may not be correctly licensed for osu! usage. Browse at your own risk." /// - public static LocalisableString ByTurningOffTheFeatured => new TranslatableString(getKey(@"by_turning_off_the_featured"), - @"By turning off the ""Featured Artist"" filter, all user-uploaded content will be displayed. + public static LocalisableString UserContentDisclaimerDescription => new TranslatableString(getKey(@"by_turning_off_the_featured"), @"By turning off the ""Featured Artist"" filter, all user-uploaded content will be displayed. -This includes content which may not be correctly licensed for use and as such may not be safe for streaming, sharing, or consumption."); +This includes content that may not be correctly licensed for osu! usage. Browse at your own risk."); /// /// "I understand" /// - public static LocalisableString Understood => new TranslatableString(getKey(@"understood"), @"I understand"); + public static LocalisableString UserContentConfirmButtonText => new TranslatableString(getKey(@"understood"), @"I understand"); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs index 41a78473e5..a4a914db55 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs @@ -87,8 +87,8 @@ namespace osu.Game.Overlays.BeatmapListing { public FeaturedArtistConfirmDialog(Action confirm) { - HeaderText = BeatmapOverlayStrings.UserContentDisclaimer; - BodyText = BeatmapOverlayStrings.ByTurningOffTheFeatured; + HeaderText = BeatmapOverlayStrings.UserContentDisclaimerHeader; + BodyText = BeatmapOverlayStrings.UserContentDisclaimerDescription; Icon = FontAwesome.Solid.ExclamationTriangle; @@ -96,7 +96,7 @@ namespace osu.Game.Overlays.BeatmapListing { new PopupDialogDangerousButton { - Text = BeatmapOverlayStrings.Understood, + Text = BeatmapOverlayStrings.UserContentConfirmButtonText, Action = confirm }, new PopupDialogCancelButton From 467e87902198e8ba3a83653dde6992e2382769f9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 12 Dec 2022 01:25:56 +0300 Subject: [PATCH 2595/2686] Migrate osu! iOS to .NET 6 and target iOS 13.4 --- README.md | 2 +- .../Application.cs | 3 +- osu.Game.Rulesets.Catch.Tests.iOS/Info.plist | 2 +- .../osu.Game.Rulesets.Catch.Tests.iOS.csproj | 28 +--- .../Application.cs | 3 +- osu.Game.Rulesets.Mania.Tests.iOS/Info.plist | 2 +- .../osu.Game.Rulesets.Mania.Tests.iOS.csproj | 28 +--- .../Application.cs | 3 +- osu.Game.Rulesets.Osu.Tests.iOS/Info.plist | 2 +- .../osu.Game.Rulesets.Osu.Tests.iOS.csproj | 29 +---- .../Application.cs | 3 +- osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist | 2 +- .../osu.Game.Rulesets.Taiko.Tests.iOS.csproj | 28 +--- osu.Game.Tests.iOS/Application.cs | 3 +- osu.Game.Tests.iOS/Info.plist | 2 +- osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj | 44 ++----- osu.iOS.props | 80 +++--------- osu.iOS/Application.cs | 3 +- osu.iOS/Info.plist | 2 +- osu.iOS/osu.iOS.csproj | 123 ++---------------- 20 files changed, 72 insertions(+), 320 deletions(-) diff --git a/README.md b/README.md index 75d61dad4d..0de82eba75 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ If you are looking to install or test osu! without setting up a development envi **Latest build:** -| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | macOS 10.15+ ([Intel](https://github.com/ppy/osu/releases/latest/download/osu.app.Intel.zip), [Apple Silicon](https://github.com/ppy/osu/releases/latest/download/osu.app.Apple.Silicon.zip)) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) | +| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | macOS 10.15+ ([Intel](https://github.com/ppy/osu/releases/latest/download/osu.app.Intel.zip), [Apple Silicon](https://github.com/ppy/osu/releases/latest/download/osu.app.Apple.Silicon.zip)) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 13.4+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) | | ------------- | ------------- | ------------- | ------------- | ------------- | - The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets. diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs index 71d943ece1..1fcb0aa427 100644 --- a/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs +++ b/osu.Game.Rulesets.Catch.Tests.iOS/Application.cs @@ -3,7 +3,6 @@ #nullable disable -using osu.Framework.iOS; using UIKit; namespace osu.Game.Rulesets.Catch.Tests.iOS @@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Catch.Tests.iOS { public static void Main(string[] args) { - UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate)); + UIApplication.Main(args, null, typeof(AppDelegate)); } } } diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist b/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist index 16a2b99997..5ace6c07f5 100644 --- a/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist +++ b/osu.Game.Rulesets.Catch.Tests.iOS/Info.plist @@ -13,7 +13,7 @@ LSRequiresIPhoneOS MinimumOSVersion - 10.0 + 13.4 UIDeviceFamily 1 diff --git a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj index be6044bbd0..acf12bb0ac 100644 --- a/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Catch.Tests.iOS/osu.Game.Rulesets.Catch.Tests.iOS.csproj @@ -1,35 +1,19 @@ - - + - Debug - iPhoneSimulator - {4004C7B7-1A62-43F1-9DF2-52450FA67E70} Exe + net6.0-ios + 13.4 osu.Game.Rulesets.Catch.Tests osu.Game.Rulesets.Catch.Tests.iOS - - - - Linker.xml - - - %(RecursiveDir)%(Filename)%(Extension) - - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} - osu.Game - - - {58F6C80C-1253-4A0E-A465-B8C85EBEADF3} - osu.Game.Rulesets.Catch - + + - - \ No newline at end of file + diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs index 2d1015387a..a508198f7f 100644 --- a/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs +++ b/osu.Game.Rulesets.Mania.Tests.iOS/Application.cs @@ -3,7 +3,6 @@ #nullable disable -using osu.Framework.iOS; using UIKit; namespace osu.Game.Rulesets.Mania.Tests.iOS @@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Tests.iOS { public static void Main(string[] args) { - UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate)); + UIApplication.Main(args, null, typeof(AppDelegate)); } } } diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist b/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist index 82d1c8ea24..ff5dde856e 100644 --- a/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist +++ b/osu.Game.Rulesets.Mania.Tests.iOS/Info.plist @@ -13,7 +13,7 @@ LSRequiresIPhoneOS MinimumOSVersion - 10.0 + 13.4 UIDeviceFamily 1 diff --git a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj index 88ad484bc1..51e07dd6c1 100644 --- a/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Mania.Tests.iOS/osu.Game.Rulesets.Mania.Tests.iOS.csproj @@ -1,35 +1,19 @@ - - + - Debug - iPhoneSimulator - {39FD990E-B6CE-4B2A-999F-BC008CF2C64C} Exe + net6.0-ios + 13.4 osu.Game.Rulesets.Mania.Tests osu.Game.Rulesets.Mania.Tests.iOS - - - - Linker.xml - - - %(RecursiveDir)%(Filename)%(Extension) - - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} - osu.Game - - - {48F4582B-7687-4621-9CBE-5C24197CB536} - osu.Game.Rulesets.Mania - + + - - \ No newline at end of file + diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs b/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs index ad23f3ee33..6ef29fa68e 100644 --- a/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs +++ b/osu.Game.Rulesets.Osu.Tests.iOS/Application.cs @@ -3,7 +3,6 @@ #nullable disable -using osu.Framework.iOS; using UIKit; namespace osu.Game.Rulesets.Osu.Tests.iOS @@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Tests.iOS { public static void Main(string[] args) { - UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate)); + UIApplication.Main(args, null, typeof(AppDelegate)); } } } diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist b/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist index a88b74695c..1e33f2ff16 100644 --- a/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist +++ b/osu.Game.Rulesets.Osu.Tests.iOS/Info.plist @@ -13,7 +13,7 @@ LSRequiresIPhoneOS MinimumOSVersion - 10.0 + 13.4 UIDeviceFamily 1 diff --git a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj index 545abcec6c..7d50deb8ba 100644 --- a/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Osu.Tests.iOS/osu.Game.Rulesets.Osu.Tests.iOS.csproj @@ -1,35 +1,20 @@ - - + - Debug - iPhoneSimulator - {6653CA6F-DB06-4604-A3FD-762E25C2AF96} + Exe + net6.0-ios + 13.4 Exe osu.Game.Rulesets.Osu.Tests osu.Game.Rulesets.Osu.Tests.iOS - - - - Linker.xml - - - %(RecursiveDir)%(Filename)%(Extension) - - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} - osu.Game - - - {C92A607B-1FDD-4954-9F92-03FF547D9080} - osu.Game.Rulesets.Osu - + + - - \ No newline at end of file + diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs b/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs index 1ebbd61a94..0e3a953728 100644 --- a/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs +++ b/osu.Game.Rulesets.Taiko.Tests.iOS/Application.cs @@ -3,7 +3,6 @@ #nullable disable -using osu.Framework.iOS; using UIKit; namespace osu.Game.Rulesets.Taiko.Tests.iOS @@ -12,7 +11,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.iOS { public static void Main(string[] args) { - UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate)); + UIApplication.Main(args, null, typeof(AppDelegate)); } } } diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist b/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist index 9628475b3e..76cb3c0db0 100644 --- a/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist +++ b/osu.Game.Rulesets.Taiko.Tests.iOS/Info.plist @@ -13,7 +13,7 @@ LSRequiresIPhoneOS MinimumOSVersion - 10.0 + 13.4 UIDeviceFamily 1 diff --git a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj index 8ee640cd99..e648a11299 100644 --- a/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj +++ b/osu.Game.Rulesets.Taiko.Tests.iOS/osu.Game.Rulesets.Taiko.Tests.iOS.csproj @@ -1,35 +1,19 @@ - - + - Debug - iPhoneSimulator - {7E408809-66AC-49D1-AF4D-98834F9B979A} Exe + net6.0-ios + 13.4 osu.Game.Rulesets.Taiko.Tests osu.Game.Rulesets.Taiko.Tests.iOS - - - - Linker.xml - - - %(RecursiveDir)%(Filename)%(Extension) - - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} - osu.Game - - - {F167E17A-7DE6-4AF5-B920-A5112296C695} - osu.Game.Rulesets.Taiko - + + - - \ No newline at end of file + diff --git a/osu.Game.Tests.iOS/Application.cs b/osu.Game.Tests.iOS/Application.cs index cf36fea139..4678be4fb8 100644 --- a/osu.Game.Tests.iOS/Application.cs +++ b/osu.Game.Tests.iOS/Application.cs @@ -3,7 +3,6 @@ #nullable disable -using osu.Framework.iOS; using UIKit; namespace osu.Game.Tests.iOS @@ -12,7 +11,7 @@ namespace osu.Game.Tests.iOS { public static void Main(string[] args) { - UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate)); + UIApplication.Main(args, null, typeof(AppDelegate)); } } } diff --git a/osu.Game.Tests.iOS/Info.plist b/osu.Game.Tests.iOS/Info.plist index 31e2b3f257..ac661f6263 100644 --- a/osu.Game.Tests.iOS/Info.plist +++ b/osu.Game.Tests.iOS/Info.plist @@ -13,7 +13,7 @@ LSRequiresIPhoneOS MinimumOSVersion - 10.0 + 13.4 UIDeviceFamily 1 diff --git a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj index 05b3cad6da..79771fcd50 100644 --- a/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj +++ b/osu.Game.Tests.iOS/osu.Game.Tests.iOS.csproj @@ -1,54 +1,26 @@ - - + - Debug - iPhoneSimulator Exe - {65FF8E19-6934-469B-B690-23C6D6E56A17} + net6.0-ios + 13.4 osu.Game.Tests osu.Game.Tests.iOS - - - - Linker.xml - - - %(RecursiveDir)%(Filename)%(Extension) - - $(NoWarn);CA2007 - - - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} - osu.Game - - - {C92A607B-1FDD-4954-9F92-03FF547D9080} - osu.Game.Rulesets.Osu - - - {58F6C80C-1253-4A0E-A465-B8C85EBEADF3} - osu.Game.Rulesets.Catch - - - {48F4582B-7687-4621-9CBE-5C24197CB536} - osu.Game.Rulesets.Mania - - - {F167E17A-7DE6-4AF5-B920-A5112296C695} - osu.Game.Rulesets.Taiko - + + + + + - diff --git a/osu.iOS.props b/osu.iOS.props index 184e3303c8..d67248f8e0 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -1,72 +1,14 @@  - 8.0 - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Resources - PackageReference - bin\$(Platform)\$(Configuration) - cjk,mideast,other,rare,west - false - NSUrlSessionHandler - iPhone Developer + true true - - - --nosymbolstrip=BASS_FX_BPM_BeatCallbackReset --nosymbolstrip=BASS_FX_BPM_BeatCallbackSet --nosymbolstrip=BASS_FX_BPM_BeatDecodeGet --nosymbolstrip=BASS_FX_BPM_BeatFree --nosymbolstrip=BASS_FX_BPM_BeatGetParameters --nosymbolstrip=BASS_FX_BPM_BeatSetParameters --nosymbolstrip=BASS_FX_BPM_CallbackReset --nosymbolstrip=BASS_FX_BPM_CallbackSet --nosymbolstrip=BASS_FX_BPM_DecodeGet --nosymbolstrip=BASS_FX_BPM_Free --nosymbolstrip=BASS_FX_BPM_Translate --nosymbolstrip=BASS_FX_GetVersion --nosymbolstrip=BASS_FX_ReverseCreate --nosymbolstrip=BASS_FX_ReverseGetSource --nosymbolstrip=BASS_FX_TempoCreate --nosymbolstrip=BASS_FX_TempoGetRateRatio --nosymbolstrip=BASS_FX_TempoGetSource --nosymbolstrip=BASS_Mixer_ChannelFlags --nosymbolstrip=BASS_Mixer_ChannelGetData --nosymbolstrip=BASS_Mixer_ChannelGetEnvelopePos --nosymbolstrip=BASS_Mixer_ChannelGetLevel --nosymbolstrip=BASS_Mixer_ChannelGetLevelEx --nosymbolstrip=BASS_Mixer_ChannelGetMatrix --nosymbolstrip=BASS_Mixer_ChannelGetMixer --nosymbolstrip=BASS_Mixer_ChannelGetPosition --nosymbolstrip=BASS_Mixer_ChannelGetPositionEx --nosymbolstrip=BASS_Mixer_ChannelIsActive --nosymbolstrip=BASS_Mixer_ChannelRemove --nosymbolstrip=BASS_Mixer_ChannelRemoveSync --nosymbolstrip=BASS_Mixer_ChannelSetEnvelope --nosymbolstrip=BASS_Mixer_ChannelSetEnvelopePos --nosymbolstrip=BASS_Mixer_ChannelSetMatrix --nosymbolstrip=BASS_Mixer_ChannelSetMatrixEx --nosymbolstrip=BASS_Mixer_ChannelSetPosition --nosymbolstrip=BASS_Mixer_ChannelSetSync --nosymbolstrip=BASS_Mixer_GetVersion --nosymbolstrip=BASS_Mixer_StreamAddChannel --nosymbolstrip=BASS_Mixer_StreamAddChannelEx --nosymbolstrip=BASS_Mixer_StreamCreate --nosymbolstrip=BASS_Mixer_StreamGetChannels --nosymbolstrip=BASS_Split_StreamCreate --nosymbolstrip=BASS_Split_StreamGetAvailable --nosymbolstrip=BASS_Split_StreamGetSource --nosymbolstrip=BASS_Split_StreamGetSplits --nosymbolstrip=BASS_Split_StreamReset --nosymbolstrip=BASS_Split_StreamResetEx - - --nolinkaway --nostrip $(GeneratedMtouchSymbolStripFlags) - - - true - full - false - DEBUG;ENABLE_TEST_CLOUD; - true - true - - - pdbonly - true + + ios-arm64 - x86_64 - None - - - true - SdkOnly - ARM64 - Entitlements.plist - - - true - 25823 - false - - - true - - - true - 28126 - - - - - - - - - - - - - - - - $(NoWarn);NU1605 + iossimulator-x64 @@ -77,6 +19,9 @@ none + + + @@ -86,7 +31,16 @@ - + + + + + + <_LinkerFrameworks Remove="Quartz"/> + + diff --git a/osu.iOS/Application.cs b/osu.iOS/Application.cs index c5b2d0b451..64eb5c63f5 100644 --- a/osu.iOS/Application.cs +++ b/osu.iOS/Application.cs @@ -3,7 +3,6 @@ #nullable disable -using osu.Framework.iOS; using UIKit; namespace osu.iOS @@ -12,7 +11,7 @@ namespace osu.iOS { public static void Main(string[] args) { - UIApplication.Main(args, typeof(GameUIApplication), typeof(AppDelegate)); + UIApplication.Main(args, null, typeof(AppDelegate)); } } } diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist index 16cb68fa7d..c4b08ab78e 100644 --- a/osu.iOS/Info.plist +++ b/osu.iOS/Info.plist @@ -15,7 +15,7 @@ LSRequiresIPhoneOS MinimumOSVersion - 10.0 + 13.4 UIDeviceFamily 1 diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj index b9da874f30..95ca3e2142 100644 --- a/osu.iOS/osu.iOS.csproj +++ b/osu.iOS/osu.iOS.csproj @@ -1,124 +1,19 @@ - - - - Debug - iPhoneSimulator + + + net6.0-ios + 13.4 Exe - {3F082D0B-A964-43D7-BDF7-C256D76A50D0} - osu.iOS - osu.iOS false - - - - - - - - - - - - - - - - - - - - - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} - osu.Game - - - {58F6C80C-1253-4A0E-A465-B8C85EBEADF3} - osu.Game.Rulesets.Catch - - - {48F4582B-7687-4621-9CBE-5C24197CB536} - osu.Game.Rulesets.Mania - - - {C92A607B-1FDD-4954-9F92-03FF547D9080} - osu.Game.Rulesets.Osu - - - {F167E17A-7DE6-4AF5-B920-A5112296C695} - osu.Game.Rulesets.Taiko - - - - - - - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - - - false - + + + + + - From c900965a82d5c0ab86d9c017015a17eef45e4773 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 12 Dec 2022 01:26:13 +0300 Subject: [PATCH 2596/2686] Replace `Xamarin.Essentials` with .NET MAUI Essentials --- osu.iOS/OsuGameIOS.cs | 2 +- osu.iOS/osu.iOS.csproj | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.iOS/OsuGameIOS.cs b/osu.iOS/OsuGameIOS.cs index b3194e497b..cb3b260033 100644 --- a/osu.iOS/OsuGameIOS.cs +++ b/osu.iOS/OsuGameIOS.cs @@ -5,6 +5,7 @@ using System; using Foundation; +using Microsoft.Maui.Devices; using osu.Framework.Graphics; using osu.Framework.Input.Handlers; using osu.Framework.iOS.Input; @@ -12,7 +13,6 @@ using osu.Game; using osu.Game.Overlays.Settings; using osu.Game.Updater; using osu.Game.Utils; -using Xamarin.Essentials; namespace osu.iOS { diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj index 95ca3e2142..ce19cb7ee6 100644 --- a/osu.iOS/osu.iOS.csproj +++ b/osu.iOS/osu.iOS.csproj @@ -4,6 +4,7 @@ 13.4 Exe false + true @@ -13,7 +14,4 @@ - - - From e85975b5f1269c7c2a106be6e677fd4d029630e0 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 12 Dec 2022 01:28:01 +0300 Subject: [PATCH 2597/2686] Work around JIT compilation error in Realm --- osu.iOS.props | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.iOS.props b/osu.iOS.props index d67248f8e0..4a0fe55d4e 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -3,6 +3,8 @@ iPhone Developer true true + + true ios-arm64 From 660cc72f2a36f89c75567f3910bdaee52b8e955b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 12 Dec 2022 01:30:49 +0300 Subject: [PATCH 2598/2686] Avoid configuring web proxies on iOS for now --- osu.Game/Online/HubClientConnector.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index ca6d2932f7..ff63c0657c 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -59,11 +59,15 @@ namespace osu.Game.Online var builder = new HubConnectionBuilder() .WithUrl(endpoint, options => { - // Use HttpClient.DefaultProxy once on net6 everywhere. - // The credential setter can also be removed at this point. - options.Proxy = WebRequest.DefaultWebProxy; - if (options.Proxy != null) - options.Proxy.Credentials = CredentialCache.DefaultCredentials; + // Configuring proxies is not supported on iOS, see https://github.com/xamarin/xamarin-macios/issues/14632. + if (RuntimeInfo.OS != RuntimeInfo.Platform.iOS) + { + // Use HttpClient.DefaultProxy once on net6 everywhere. + // The credential setter can also be removed at this point. + options.Proxy = WebRequest.DefaultWebProxy; + if (options.Proxy != null) + options.Proxy.Credentials = CredentialCache.DefaultCredentials; + } options.Headers.Add("Authorization", $"Bearer {api.AccessToken}"); options.Headers.Add("OsuVersionHash", versionHash); From 5fbd4ad3b467414e925b29e118654e91637fe8c1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 14 Dec 2022 17:01:05 +0300 Subject: [PATCH 2599/2686] Update usages of `SupportsJIT` in line with framework changes --- osu.Game/Online/HubClientConnector.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index ff63c0657c..8fd79bd703 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Net; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR.Client; @@ -73,7 +74,7 @@ namespace osu.Game.Online options.Headers.Add("OsuVersionHash", versionHash); }); - if (RuntimeInfo.SupportsJIT && preferMessagePack) + if (RuntimeFeature.IsDynamicCodeCompiled && preferMessagePack) { builder.AddMessagePackProtocol(options => { From b488421c7aa0fd7431043d09695f2f0a4978a808 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 15 Dec 2022 12:24:17 +0300 Subject: [PATCH 2600/2686] Remove `MtouchUseLlvm` key for now I haven't found a way to disable LLVM, and the issue may potentially be resolved (doesn't occur for me), so we might as well just remove the key for now. --- osu.iOS/osu.iOS.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj index ce19cb7ee6..def538af1a 100644 --- a/osu.iOS/osu.iOS.csproj +++ b/osu.iOS/osu.iOS.csproj @@ -3,7 +3,6 @@ net6.0-ios 13.4 Exe - false true From d791bc56e7b64980b2969c8ea1ceefe4b4450da7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 15 Dec 2022 14:43:41 +0300 Subject: [PATCH 2601/2686] Remove transitive dependencies --- osu.iOS.props | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/osu.iOS.props b/osu.iOS.props index 4a0fe55d4e..064ee5cceb 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -2,7 +2,6 @@ iPhone Developer true - true true @@ -24,19 +23,6 @@ - - - - - - - - - - - - - From 2c78fed5e4511c43c2d02e6a8fb268a28f80a967 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 15 Dec 2022 18:21:23 +0300 Subject: [PATCH 2602/2686] Update workflows in line with framework changes --- .github/workflows/ci.yml | 8 ++++---- appveyor.yml | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56b3ebe87b..798e54e155 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -132,8 +132,8 @@ jobs: with: dotnet-version: "6.0.x" - # Contrary to seemingly any other msbuild, msbuild running on macOS/Mono - # cannot accept .sln(f) files as arguments. - # Build just the main game for now. + - name: Install .NET Workloads + run: dotnet workload install maui-ios + - name: Build - run: msbuild osu.iOS/osu.iOS.csproj /restore /p:Configuration=Debug + run: dotnet build -c Debug osu.iOS diff --git a/appveyor.yml b/appveyor.yml index 5be73f9875..19ef6ae63f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,6 @@ clone_depth: 1 version: '{branch}-{build}' -image: Visual Studio 2019 +image: Visual Studio 2022 cache: - '%LOCALAPPDATA%\NuGet\v3-cache -> appveyor.yml' @@ -11,6 +11,7 @@ dotnet_csproj: before_build: - cmd: dotnet --info # Useful when version mismatch between CI and local + - cmd: dotnet workload install maui-ios # Change to `dotnet workload restore` once there's no old projects - cmd: nuget restore -verbosity quiet # Only nuget.exe knows both new (.NET Core) and old (Xamarin) projects build: From 67787da4cfbc25d4a077e5ebd3b400167039d2f9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Dec 2022 00:46:32 +0300 Subject: [PATCH 2603/2686] Suppress MT7091 --- osu.iOS.props | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.iOS.props b/osu.iOS.props index 064ee5cceb..9168c019ba 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -4,6 +4,10 @@ true true + + $(NoWarn);MT7091 ios-arm64 From 0f34d908c791692c4d10ff516f8274b0d56a4413 Mon Sep 17 00:00:00 2001 From: Susko3 Date: Fri, 16 Dec 2022 00:05:47 +0100 Subject: [PATCH 2604/2686] Use `LocalisableString`s for date and time formats --- osu.Game/Graphics/DateTooltip.cs | 5 +++-- osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs | 5 ++--- osu.Game/Overlays/Changelog/ChangelogListing.cs | 3 ++- osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs | 3 ++- osu.Game/Overlays/Chat/ChatLine.cs | 5 ++--- .../Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs | 5 +++-- osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs | 5 +++-- osu.Game/Overlays/News/Sidebar/MonthSection.cs | 3 ++- osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs | 3 ++- .../Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs | 4 +++- 10 files changed, 24 insertions(+), 17 deletions(-) diff --git a/osu.Game/Graphics/DateTooltip.cs b/osu.Game/Graphics/DateTooltip.cs index d9bb2b610a..c62f53f1d4 100644 --- a/osu.Game/Graphics/DateTooltip.cs +++ b/osu.Game/Graphics/DateTooltip.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; using osuTK; @@ -69,8 +70,8 @@ namespace osu.Game.Graphics { DateTimeOffset localDate = date.ToLocalTime(); - dateText.Text = $"{localDate:d MMMM yyyy} "; - timeText.Text = $"{localDate:HH:mm:ss \"UTC\"z}"; + dateText.Text = LocalisableString.Interpolate($"{localDate:d MMMM yyyy} "); + timeText.Text = LocalisableString.Interpolate($"{localDate:HH:mm:ss \"UTC\"z}"); } public void Move(Vector2 pos) => Position = pos; diff --git a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs index 170f266307..0b2e401f57 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScoreTooltip.cs @@ -136,9 +136,8 @@ namespace osu.Game.Online.Leaderboards { if (displayedScore != null) { - timestampLabel.Text = prefer24HourTime.Value - ? $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy HH:mm}" - : $"Played on {displayedScore.Date.ToLocalTime():d MMMM yyyy h:mm tt}"; + timestampLabel.Text = LocalisableString.Format("Played on {0}", + displayedScore.Date.ToLocalTime().ToLocalisableString(prefer24HourTime.Value ? @"d MMMM yyyy HH:mm" : @"d MMMM yyyy h:mm tt")); } } diff --git a/osu.Game/Overlays/Changelog/ChangelogListing.cs b/osu.Game/Overlays/Changelog/ChangelogListing.cs index d30fd97652..d7c9ff67fe 100644 --- a/osu.Game/Overlays/Changelog/ChangelogListing.cs +++ b/osu.Game/Overlays/Changelog/ChangelogListing.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -51,7 +52,7 @@ namespace osu.Game.Overlays.Changelog Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Margin = new MarginPadding { Top = 20 }, - Text = build.CreatedAt.Date.ToString("dd MMMM yyyy"), + Text = build.CreatedAt.Date.ToLocalisableString("dd MMMM yyyy"), Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 24), }); diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index a729ef2cc8..13a19de22a 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -7,6 +7,7 @@ using System; using System.Threading; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -114,7 +115,7 @@ namespace osu.Game.Overlays.Changelog { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = Build.CreatedAt.Date.ToString("dd MMMM yyyy"), + Text = Build.CreatedAt.Date.ToLocalisableString("dd MMMM yyyy"), Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 14), Margin = new MarginPadding { Top = 5 }, Scale = new Vector2(1.25f), diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 2b8718939e..70c3bf181c 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -175,9 +176,7 @@ namespace osu.Game.Overlays.Chat private void updateTimestamp() { - drawableTimestamp.Text = prefer24HourTime.Value - ? $@"{message.Timestamp.LocalDateTime:HH:mm:ss}" - : $@"{message.Timestamp.LocalDateTime:hh:mm:ss tt}"; + drawableTimestamp.Text = message.Timestamp.LocalDateTime.ToLocalisableString(prefer24HourTime.Value ? @"HH:mm:ss" : @"hh:mm:ss tt"); } } } diff --git a/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs b/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs index 3066d253eb..dabe65964a 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -167,7 +168,7 @@ namespace osu.Game.Overlays.Dashboard.Home.News Origin = Anchor.TopRight, Font = OsuFont.GetFont(weight: FontWeight.Bold), // using Bold since there is no 800 weight alternative Colour = colourProvider.Light1, - Text = $"{date:dd}" + Text = date.ToLocalisableString(@"dd") }, new TextFlowContainer(f => { @@ -178,7 +179,7 @@ namespace osu.Game.Overlays.Dashboard.Home.News Anchor = Anchor.TopRight, Origin = Anchor.TopRight, AutoSizeAxes = Axes.Both, - Text = $"{date:MMM yyyy}" + Text = date.ToLocalisableString(@"MMM yyyy") } } }; diff --git a/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs b/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs index e277a5fa16..9b27d1a193 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -98,12 +99,12 @@ namespace osu.Game.Overlays.Dashboard.Home.News Margin = new MarginPadding { Vertical = 5 } }; - textFlow.AddText($"{date:dd}", t => + textFlow.AddText(date.ToLocalisableString(@"dd"), t => { t.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold); }); - textFlow.AddText($"{date: MMM}", t => + textFlow.AddText(date.ToLocalisableString(@" MMM"), t => { t.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Regular); }); diff --git a/osu.Game/Overlays/News/Sidebar/MonthSection.cs b/osu.Game/Overlays/News/Sidebar/MonthSection.cs index d205fcb908..30d29048ba 100644 --- a/osu.Game/Overlays/News/Sidebar/MonthSection.cs +++ b/osu.Game/Overlays/News/Sidebar/MonthSection.cs @@ -19,6 +19,7 @@ using osu.Framework.Graphics.Sprites; using System.Diagnostics; using osu.Framework.Audio; using osu.Framework.Audio.Sample; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Platform; namespace osu.Game.Overlays.News.Sidebar @@ -99,7 +100,7 @@ namespace osu.Game.Overlays.News.Sidebar Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), - Text = date.ToString("MMM yyyy") + Text = date.ToLocalisableString(@"MMM yyyy") }, icon = new SpriteIcon { diff --git a/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs b/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs index bc803db739..ada2f6ff86 100644 --- a/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs +++ b/osu.Game/Overlays/Toolbar/DigitalClockDisplay.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -69,7 +70,7 @@ namespace osu.Game.Overlays.Toolbar protected override void UpdateDisplay(DateTimeOffset now) { - realTime.Text = use24HourDisplay ? $"{now:HH:mm:ss}" : $"{now:h:mm:ss tt}"; + realTime.Text = now.ToLocalisableString(use24HourDisplay ? @"HH:mm:ss" : @"h:mm:ss tt"); gameTime.Text = $"running {new TimeSpan(TimeSpan.TicksPerSecond * (int)(Clock.CurrentTime / 1000)):c}"; } diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index 8fe0ae509b..f23b469f5c 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -9,6 +9,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; @@ -309,7 +310,8 @@ namespace osu.Game.Screens.Ranking.Expanded private void updateDisplay() { - Text = prefer24HourTime.Value ? $"Played on {time.ToLocalTime():d MMMM yyyy HH:mm}" : $"Played on {time.ToLocalTime():d MMMM yyyy h:mm tt}"; + Text = LocalisableString.Format("Played on {0}", + time.ToLocalTime().ToLocalisableString(prefer24HourTime.Value ? @"d MMMM yyyy HH:mm" : @"d MMMM yyyy h:mm tt")); } } } From e63b544167f4d0aa8c7e808e7a5f38805b360915 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Dec 2022 17:02:51 +0900 Subject: [PATCH 2605/2686] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index c2c74e2c0e..0e5714e90f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 31cd851c03..9e757b1802 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 9168c019ba..98d3e129d4 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -25,7 +25,7 @@ - + + true true - - osu.licenseheader - - - - - - - - - - - - @@ -61,4 +19,9 @@ + + + true + diff --git a/osu.Android/Properties/AndroidManifest.xml b/osu.Android/AndroidManifest.xml similarity index 98% rename from osu.Android/Properties/AndroidManifest.xml rename to osu.Android/AndroidManifest.xml index 165a64a424..be326be5eb 100644 --- a/osu.Android/Properties/AndroidManifest.xml +++ b/osu.Android/AndroidManifest.xml @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index be40db7508..ca3d628447 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using Android.App; using Android.Content; @@ -74,11 +75,23 @@ namespace osu.Android Debug.Assert(Resources?.DisplayMetrics != null); Point displaySize = new Point(); +#pragma warning disable 618 // GetSize is deprecated WindowManager.DefaultDisplay.GetSize(displaySize); +#pragma warning restore 618 float smallestWidthDp = Math.Min(displaySize.X, displaySize.Y) / Resources.DisplayMetrics.Density; bool isTablet = smallestWidthDp >= 600f; RequestedOrientation = DefaultOrientation = isTablet ? ScreenOrientation.FullUser : ScreenOrientation.SensorLandscape; + + // Currently (SDK 6.0.200), BundleAssemblies is not runnable for net6-android. + // The assembly files are not available as files either after native AOT. + // Manually load them so that they can be loaded by RulesetStore.loadFromAppDomain. + // REMEMBER to fully uninstall previous version every time when investigating this! + // Don't forget osu.Game.Tests.Android too. + Assembly.Load("osu.Game.Rulesets.Osu"); + Assembly.Load("osu.Game.Rulesets.Taiko"); + Assembly.Load("osu.Game.Rulesets.Catch"); + Assembly.Load("osu.Game.Rulesets.Mania"); } protected override void OnNewIntent(Intent intent) => handleIntent(intent); @@ -127,7 +140,7 @@ namespace osu.Android cursor.MoveToFirst(); - int filenameColumn = cursor.GetColumnIndex(OpenableColumns.DisplayName); + int filenameColumn = cursor.GetColumnIndex(IOpenableColumns.DisplayName); string filename = cursor.GetString(filenameColumn); // SharpCompress requires archive streams to be seekable, which the stream opened by diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs index 1c6f41a7ec..0227d2aec2 100644 --- a/osu.Android/OsuGameAndroid.cs +++ b/osu.Android/OsuGameAndroid.cs @@ -5,7 +5,7 @@ using System; using Android.App; -using Android.OS; +using Microsoft.Maui.Devices; using osu.Framework.Allocation; using osu.Framework.Android.Input; using osu.Framework.Input.Handlers; @@ -14,7 +14,6 @@ using osu.Game; using osu.Game.Overlays.Settings; using osu.Game.Updater; using osu.Game.Utils; -using Xamarin.Essentials; namespace osu.Android { @@ -48,7 +47,7 @@ namespace osu.Android // https://stackoverflow.com/questions/52977079/android-sdk-28-versioncode-in-packageinfo-has-been-deprecated string versionName = string.Empty; - if (Build.VERSION.SdkInt >= BuildVersionCodes.P) + if (OperatingSystem.IsAndroidVersionAtLeast(28)) { versionName = packageInfo.LongVersionCode.ToString(); // ensure we only read the trailing portion of long (the part we are interested in). diff --git a/osu.Android/osu.Android.csproj b/osu.Android/osu.Android.csproj index 004cc8c39c..de53e5dd59 100644 --- a/osu.Android/osu.Android.csproj +++ b/osu.Android/osu.Android.csproj @@ -1,73 +1,19 @@ - - + - Debug - AnyCPU - 8.0.30703 - 2.0 - {D1D5F9A8-B40B-40E6-B02F-482D03346D3D} - {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {122416d6-6b49-4ee2-a1e8-b825f31c79fe} + net6.0-android + Exe osu.Android osu.Android - Properties\AndroidManifest.xml - armeabi-v7a;x86;arm64-v8a - false - - - cjk;mideast;other;rare;west - d8 - r8 - - - None - cjk;mideast;other;rare;west - true + true + + false - - - - - - + + + + + - - - - - - {58f6c80c-1253-4a0e-a465-b8c85ebeadf3} - osu.Game.Rulesets.Catch - - - {48f4582b-7687-4621-9cbe-5c24197cb536} - osu.Game.Rulesets.Mania - - - {c92a607b-1fdd-4954-9f92-03ff547d9080} - osu.Game.Rulesets.Osu - - - {f167e17a-7de6-4af5-b920-a5112296c695} - osu.Game.Rulesets.Taiko - - - {2a66dd92-adb1-4994-89e2-c94e04acda0d} - osu.Game - - - - - - - - 5.0.0 - - - - - - - \ No newline at end of file + diff --git a/osu.Game.Rulesets.Catch.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml similarity index 98% rename from osu.Game.Rulesets.Catch.Tests.Android/Properties/AndroidManifest.xml rename to osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml index f8c3fcd894..bf7c0bfeca 100644 --- a/osu.Game.Rulesets.Catch.Tests.Android/Properties/AndroidManifest.xml +++ b/osu.Game.Rulesets.Catch.Tests.Android/AndroidManifest.xml @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj b/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj index 94fdba4a3e..4ee3219442 100644 --- a/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj +++ b/osu.Game.Rulesets.Catch.Tests.Android/osu.Game.Rulesets.Catch.Tests.Android.csproj @@ -1,49 +1,24 @@ - - + - Debug - AnyCPU - 8.0.30703 - 2.0 - {C5379ECB-3A94-4D2F-AC3B-2615AC23EB0D} - {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {122416d6-6b49-4ee2-a1e8-b825f31c79fe} + net6.0-android + Exe osu.Game.Rulesets.Catch.Tests osu.Game.Rulesets.Catch.Tests.Android - Properties\AndroidManifest.xml - armeabi-v7a;x86;arm64-v8a - - - None - cjk;mideast;other;rare;west - true - - - - - - - + %(RecursiveDir)%(Filename)%(Extension) + + + %(RecursiveDir)%(Filename)%(Extension) + Android\%(RecursiveDir)%(Filename)%(Extension) + - - {58f6c80c-1253-4a0e-a465-b8c85ebeadf3} - osu.Game.Rulesets.Catch - - - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} - osu.Game - + + - - - 5.0.0 - - - \ No newline at end of file diff --git a/osu.Game.Rulesets.Mania.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml similarity index 98% rename from osu.Game.Rulesets.Mania.Tests.Android/Properties/AndroidManifest.xml rename to osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml index de7935b2ef..4a1545a423 100644 --- a/osu.Game.Rulesets.Mania.Tests.Android/Properties/AndroidManifest.xml +++ b/osu.Game.Rulesets.Mania.Tests.Android/AndroidManifest.xml @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj b/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj index 9674186039..25335754d2 100644 --- a/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj +++ b/osu.Game.Rulesets.Mania.Tests.Android/osu.Game.Rulesets.Mania.Tests.Android.csproj @@ -1,49 +1,24 @@ - - + - Debug - AnyCPU - 8.0.30703 - 2.0 - {531F1092-DB27-445D-AA33-2A77C7187C99} - {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {122416d6-6b49-4ee2-a1e8-b825f31c79fe} + net6.0-android + Exe osu.Game.Rulesets.Mania.Tests osu.Game.Rulesets.Mania.Tests.Android - Properties\AndroidManifest.xml - armeabi-v7a;x86;arm64-v8a - - - None - cjk;mideast;other;rare;west - true - - - - - - - + %(RecursiveDir)%(Filename)%(Extension) + + + %(RecursiveDir)%(Filename)%(Extension) + Android\%(RecursiveDir)%(Filename)%(Extension) + - - {48f4582b-7687-4621-9cbe-5c24197cb536} - osu.Game.Rulesets.Mania - - - {2A66DD92-ADB1-4994-89E2-C94E04ACDA0D} - osu.Game - + + - - - 5.0.0 - - - \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml similarity index 98% rename from osu.Game.Rulesets.Osu.Tests.Android/Properties/AndroidManifest.xml rename to osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml index 3ce17ccc27..45d27dda70 100644 --- a/osu.Game.Rulesets.Osu.Tests.Android/Properties/AndroidManifest.xml +++ b/osu.Game.Rulesets.Osu.Tests.Android/AndroidManifest.xml @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj b/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj index f4b673f10b..e8a46a9828 100644 --- a/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj +++ b/osu.Game.Rulesets.Osu.Tests.Android/osu.Game.Rulesets.Osu.Tests.Android.csproj @@ -1,49 +1,27 @@ - - + - Debug - AnyCPU - 8.0.30703 - 2.0 - {90CAB706-39CB-4B93-9629-3218A6FF8E9B} - {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {122416d6-6b49-4ee2-a1e8-b825f31c79fe} + net6.0-android + Exe osu.Game.Rulesets.Osu.Tests osu.Game.Rulesets.Osu.Tests.Android - Properties\AndroidManifest.xml - armeabi-v7a;x86;arm64-v8a - - - None - cjk;mideast;other;rare;west - true - - - - - - - + %(RecursiveDir)%(Filename)%(Extension) + + + %(RecursiveDir)%(Filename)%(Extension) + Android\%(RecursiveDir)%(Filename)%(Extension) + - - {c92a607b-1fdd-4954-9f92-03ff547d9080} - osu.Game.Rulesets.Osu - - - {2a66dd92-adb1-4994-89e2-c94e04acda0d} - osu.Game - + + - - 5.0.0 - + - \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml similarity index 98% rename from osu.Game.Rulesets.Taiko.Tests.Android/Properties/AndroidManifest.xml rename to osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml index d9de0fde4e..452b9683ec 100644 --- a/osu.Game.Rulesets.Taiko.Tests.Android/Properties/AndroidManifest.xml +++ b/osu.Game.Rulesets.Taiko.Tests.Android/AndroidManifest.xml @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj b/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj index 4d4dabebe6..a639326ebd 100644 --- a/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj +++ b/osu.Game.Rulesets.Taiko.Tests.Android/osu.Game.Rulesets.Taiko.Tests.Android.csproj @@ -1,49 +1,24 @@ - - + - Debug - AnyCPU - 8.0.30703 - 2.0 - {3701A0A1-8476-42C6-B5C4-D24129B4A484} - {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {122416d6-6b49-4ee2-a1e8-b825f31c79fe} + net6.0-android + Exe osu.Game.Rulesets.Taiko.Tests osu.Game.Rulesets.Taiko.Tests.Android - Properties\AndroidManifest.xml - armeabi-v7a;x86;arm64-v8a - - - None - cjk;mideast;other;rare;west - true - - - - - - - + %(RecursiveDir)%(Filename)%(Extension) + + + %(RecursiveDir)%(Filename)%(Extension) + Android\%(RecursiveDir)%(Filename)%(Extension) + - - {f167e17a-7de6-4af5-b920-a5112296c695} - osu.Game.Rulesets.Taiko - - - {2a66dd92-adb1-4994-89e2-c94e04acda0d} - osu.Game - + + - - - 5.0.0 - - - \ No newline at end of file diff --git a/osu.Game.Tests.Android/Properties/AndroidManifest.xml b/osu.Game.Tests.Android/AndroidManifest.xml similarity index 98% rename from osu.Game.Tests.Android/Properties/AndroidManifest.xml rename to osu.Game.Tests.Android/AndroidManifest.xml index 4a63f0c357..f25b2e5328 100644 --- a/osu.Game.Tests.Android/Properties/AndroidManifest.xml +++ b/osu.Game.Tests.Android/AndroidManifest.xml @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/osu.Game.Tests.Android/MainActivity.cs b/osu.Game.Tests.Android/MainActivity.cs index 6c4f9bac58..bdb947fbb4 100644 --- a/osu.Game.Tests.Android/MainActivity.cs +++ b/osu.Game.Tests.Android/MainActivity.cs @@ -3,7 +3,9 @@ #nullable disable +using System.Reflection; using Android.App; +using Android.OS; using osu.Framework.Android; namespace osu.Game.Tests.Android @@ -12,5 +14,16 @@ namespace osu.Game.Tests.Android public class MainActivity : AndroidGameActivity { protected override Framework.Game CreateGame() => new OsuTestBrowser(); + + protected override void OnCreate(Bundle savedInstanceState) + { + base.OnCreate(savedInstanceState); + + // See the comment in OsuGameActivity + Assembly.Load("osu.Game.Rulesets.Osu"); + Assembly.Load("osu.Game.Rulesets.Taiko"); + Assembly.Load("osu.Game.Rulesets.Catch"); + Assembly.Load("osu.Game.Rulesets.Mania"); + } } } diff --git a/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj index afafec6b1f..b745d91980 100644 --- a/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj +++ b/osu.Game.Tests.Android/osu.Game.Tests.Android.csproj @@ -1,88 +1,34 @@ - - + - Debug - AnyCPU - 8.0.30703 - 2.0 - {5CC222DC-5716-4499-B897-DCBDDA4A5CF9} - {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - {122416d6-6b49-4ee2-a1e8-b825f31c79fe} + net6.0-android + Exe osu.Game.Tests osu.Game.Tests.Android - Properties\AndroidManifest.xml - armeabi-v7a;x86;arm64-v8a - - - - - - $(NoWarn);CA2007 - - None - cjk;mideast;other;rare;west - true - - + %(RecursiveDir)%(Filename)%(Extension) - - + + %(RecursiveDir)%(Filename)%(Extension) - - - %(RecursiveDir)%(Filename)%(Extension) - - - %(RecursiveDir)%(Filename)%(Extension) - - - %(RecursiveDir)%(Filename)%(Extension) - - - %(RecursiveDir)%(Filename)%(Extension) - - - %(RecursiveDir)%(Filename)%(Extension) - - - %(RecursiveDir)%(Filename)%(Extension) - + Android\%(RecursiveDir)%(Filename)%(Extension) + - - {58f6c80c-1253-4a0e-a465-b8c85ebeadf3} - osu.Game.Rulesets.Catch - - - {48f4582b-7687-4621-9cbe-5c24197cb536} - osu.Game.Rulesets.Mania - - - {c92a607b-1fdd-4954-9f92-03ff547d9080} - osu.Game.Rulesets.Osu - - - {f167e17a-7de6-4af5-b920-a5112296c695} - osu.Game.Rulesets.Taiko - - - {2a66dd92-adb1-4994-89e2-c94e04acda0d} - osu.Game - + + + + + - - 5.0.0 - - diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs index 8d82843134..d925141510 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentActions.cs @@ -189,7 +189,7 @@ namespace osu.Game.Tests.Visual.Online if (request is not CommentDeleteRequest req) return false; - req.TriggerFailure(new Exception()); + req.TriggerFailure(new InvalidOperationException()); delete = true; return false; }; diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs index e47b7e25a8..11d55bc0bd 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneUpdateBeatmapSetButton.cs @@ -136,7 +136,7 @@ namespace osu.Game.Tests.Visual.SongSelect if (testRequest.Progress >= 0.5f) { - testRequest.TriggerFailure(new Exception()); + testRequest.TriggerFailure(new InvalidOperationException()); return true; } } diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index adebbe6181..4114a3ed1e 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -114,7 +114,10 @@ namespace osu.Game.Rulesets { try { - string[] files = Directory.GetFiles(RuntimeInfo.StartupDirectory, @$"{ruleset_library_prefix}.*.dll"); + // On net6-android (Debug), StartupDirectory can be different from where assemblies are placed. + // Search sub-directories too. + + string[] files = Directory.GetFiles(RuntimeInfo.StartupDirectory, @$"{ruleset_library_prefix}.*.dll", SearchOption.AllDirectories); foreach (string file in files.Where(f => !Path.GetFileName(f).Contains("Tests"))) loadRulesetFromFile(file); diff --git a/osu.sln b/osu.sln index aeec0843be..5b23ff9ae6 100644 --- a/osu.sln +++ b/osu.sln @@ -63,6 +63,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution CodeAnalysis\osu.ruleset = CodeAnalysis\osu.ruleset osu.sln.DotSettings = osu.sln.DotSettings osu.TestProject.props = osu.TestProject.props + global.json = global.json EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Benchmarks", "osu.Game.Benchmarks\osu.Game.Benchmarks.csproj", "{93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}" From d3995693a012a2d1cd6f3306d41d44ec9c6a7084 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Dec 2022 16:39:03 +0900 Subject: [PATCH 2621/2686] Use `maui-android` --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 834b2b68a1..213c5082ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,7 +114,7 @@ jobs: dotnet-version: "6.0.x" - name: Install .NET workloads - run: dotnet workload install android + run: dotnet workload install maui-android - name: Compile run: dotnet build -c Debug osu.Android.slnf diff --git a/appveyor.yml b/appveyor.yml index 3757cbf41f..ed48a997e8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,7 +11,7 @@ dotnet_csproj: before_build: - cmd: dotnet --info # Useful when version mismatch between CI and local - - cmd: dotnet workload install android # Change to `dotnet workload restore` once there's no old projects + - cmd: dotnet workload install maui-android # Change to `dotnet workload restore` once there's no old projects - cmd: dotnet workload install maui-ios # Change to `dotnet workload restore` once there's no old projects - cmd: nuget restore -verbosity quiet # Only nuget.exe knows both new (.NET Core) and old (Xamarin) projects From 8a01a2261277047aad86b2ce7620026150490cd1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Dec 2022 16:41:04 +0900 Subject: [PATCH 2622/2686] Fix two null refrences in `OsuGame` --- osu.Game/OsuGame.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index db521cd379..a0a45e18a8 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -333,7 +333,7 @@ namespace osu.Game /// The link to load. public void HandleLink(LinkDetails link) => Schedule(() => { - string argString = link.Argument.ToString(); + string argString = link.Argument.ToString() ?? string.Empty; switch (link.Action) { @@ -1042,6 +1042,8 @@ namespace osu.Game { if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database) return; + Debug.Assert(entry.Target != null); + const int short_term_display_limit = 3; if (recentLogCount < short_term_display_limit) @@ -1054,7 +1056,7 @@ namespace osu.Game } else if (recentLogCount == short_term_display_limit) { - string logFile = $@"{entry.Target.ToString().ToLowerInvariant()}.log"; + string logFile = $@"{entry.Target.Value.ToString().ToLowerInvariant()}.log"; Schedule(() => Notifications.Post(new SimpleNotification { From 4a7d7c6ed96a1208841d9dea928078e424b71c40 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Dec 2022 16:42:21 +0900 Subject: [PATCH 2623/2686] Use `MaxBy` in all locations that can and update inspection level to match `dotnet-build` --- osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs | 4 +--- osu.Game.Tournament/Screens/Ladder/LadderScreen.cs | 4 ++-- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 4 ++-- osu.Game/Rulesets/RulesetStore.cs | 5 +---- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 +- osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs | 4 +--- osu.Game/Scoring/ScoreImporter.cs | 3 +-- .../Screens/Edit/Compose/Components/BeatDivisorControl.cs | 2 +- osu.Game/Screens/Edit/Compose/ComposeScreen.cs | 2 +- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs | 4 +--- osu.Game/Storyboards/Storyboard.cs | 4 ++-- osu.Game/Storyboards/StoryboardSprite.cs | 2 +- osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs | 4 +--- osu.sln.DotSettings | 1 + 14 files changed, 17 insertions(+), 28 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs b/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs index e5cdcf706c..43918bda57 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchDistanceSnapGrid.cs @@ -121,9 +121,7 @@ namespace osu.Game.Rulesets.Catch.Edit return new SnapResult(originPosition, StartTime); } - return enumerateSnappingCandidates(time) - .OrderBy(pos => Vector2.DistanceSquared(screenSpacePosition, pos.ScreenSpacePosition)) - .FirstOrDefault(); + return enumerateSnappingCandidates(time).MinBy(pos => Vector2.DistanceSquared(screenSpacePosition, pos.ScreenSpacePosition)); } private IEnumerable enumerateSnappingCandidates(double time) diff --git a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs index f976f2b16b..176c06c0e5 100644 --- a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs +++ b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs @@ -158,7 +158,7 @@ namespace osu.Game.Tournament.Screens.Ladder foreach (var round in LadderInfo.Rounds) { - var topMatch = MatchesContainer.Where(p => !p.Match.Losers.Value && p.Match.Round.Value == round).OrderBy(p => p.Y).FirstOrDefault(); + var topMatch = MatchesContainer.Where(p => !p.Match.Losers.Value && p.Match.Round.Value == round).MinBy(p => p.Y); if (topMatch == null) continue; @@ -172,7 +172,7 @@ namespace osu.Game.Tournament.Screens.Ladder foreach (var round in LadderInfo.Rounds) { - var topMatch = MatchesContainer.Where(p => p.Match.Losers.Value && p.Match.Round.Value == round).OrderBy(p => p.Y).FirstOrDefault(); + var topMatch = MatchesContainer.Where(p => p.Match.Losers.Value && p.Match.Round.Value == round).MinBy(p => p.Y); if (topMatch == null) continue; diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 5d308bd2bb..55119c800a 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -70,14 +70,14 @@ namespace osu.Game.Beatmaps.ControlPoints /// [JsonIgnore] public double BPMMaximum => - 60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? TimingControlPoint.DEFAULT).BeatLength; + 60000 / (TimingPoints.MinBy(c => c.BeatLength) ?? TimingControlPoint.DEFAULT).BeatLength; /// /// Finds the minimum BPM represented by any timing control point. /// [JsonIgnore] public double BPMMinimum => - 60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? TimingControlPoint.DEFAULT).BeatLength; + 60000 / (TimingPoints.MaxBy(c => c.BeatLength) ?? TimingControlPoint.DEFAULT).BeatLength; /// /// Remove all s and return to a pristine state. diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 4114a3ed1e..881b09bd1b 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -75,10 +75,7 @@ namespace osu.Game.Rulesets return false; return args.Name.Contains(name, StringComparison.Ordinal); - }) - // Pick the greatest assembly version. - .OrderByDescending(a => a.GetName().Version) - .FirstOrDefault(); + }).MaxBy(a => a.GetName().Version); if (domainAssembly != null) return domainAssembly; diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index b048566c8a..4228840461 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -534,7 +534,7 @@ namespace osu.Game.Rulesets.Scoring break; default: - maxResult = maxBasicResult ??= ruleset.GetHitResults().OrderByDescending(kvp => Judgement.ToNumericResult(kvp.result)).First().result; + maxResult = maxBasicResult ??= ruleset.GetHitResults().MaxBy(kvp => Judgement.ToNumericResult(kvp.result)).result; break; } diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index d068f8d016..d2244df3b8 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -79,9 +79,7 @@ namespace osu.Game.Rulesets.UI // We need to use lifetime entries to find the next object (we can't just use `hitObjectContainer.Objects` due to pooling - it may even be empty). // If required, we can make this lookup more efficient by adding support to get next-future-entry in LifetimeEntryManager. fallbackObject = hitObjectContainer.Entries - .Where(e => e.Result?.HasResult != true) - .OrderBy(e => e.HitObject.StartTime) - .FirstOrDefault(); + .Where(e => e.Result?.HasResult != true).MinBy(e => e.HitObject.StartTime); // In the case there are no unjudged objects, the last hit object should be used instead. fallbackObject ??= hitObjectContainer.Entries.LastOrDefault(); diff --git a/osu.Game/Scoring/ScoreImporter.cs b/osu.Game/Scoring/ScoreImporter.cs index 4656f02897..797d80b7fa 100644 --- a/osu.Game/Scoring/ScoreImporter.cs +++ b/osu.Game/Scoring/ScoreImporter.cs @@ -101,8 +101,7 @@ namespace osu.Game.Scoring // Populate the maximum statistics. HitResult maxBasicResult = rulesetInstance.GetHitResults() .Select(h => h.result) - .Where(h => h.IsBasic()) - .OrderByDescending(Judgement.ToNumericResult).First(); + .Where(h => h.IsBasic()).MaxBy(Judgement.ToNumericResult); foreach ((HitResult result, int count) in score.Statistics) { diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs index 903c117422..9f422d5aa9 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs @@ -479,7 +479,7 @@ namespace osu.Game.Screens.Edit.Compose.Components // copied from SliderBar so we can do custom spacing logic. float xPosition = (ToLocalSpace(screenSpaceMousePosition).X - RangePadding) / UsableWidth; - CurrentNumber.Value = beatDivisor.ValidDivisors.Value.Presets.OrderBy(d => Math.Abs(getMappedPosition(d) - xPosition)).First(); + CurrentNumber.Value = beatDivisor.ValidDivisors.Value.Presets.MinBy(d => Math.Abs(getMappedPosition(d) - xPosition)); OnUserChange(Current.Value); } diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 3af7a400e2..dc026f7eac 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -152,7 +152,7 @@ namespace osu.Game.Screens.Edit.Compose if (composer == null) return string.Empty; - double displayTime = EditorBeatmap.SelectedHitObjects.OrderBy(h => h.StartTime).FirstOrDefault()?.StartTime ?? clock.CurrentTime; + double displayTime = EditorBeatmap.SelectedHitObjects.MinBy(h => h.StartTime)?.StartTime ?? clock.CurrentTime; string selectionAsString = composer.ConvertSelectionToString(); return !string.IsNullOrEmpty(selectionAsString) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 33ca806696..2d2aa0f1d5 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -171,9 +171,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate if (!isCandidateAudioSource(currentAudioSource?.SpectatorPlayerClock)) { - currentAudioSource = instances.Where(i => isCandidateAudioSource(i.SpectatorPlayerClock)) - .OrderBy(i => Math.Abs(i.SpectatorPlayerClock.CurrentTime - syncManager.CurrentMasterTime)) - .FirstOrDefault(); + currentAudioSource = instances.Where(i => isCandidateAudioSource(i.SpectatorPlayerClock)).MinBy(i => Math.Abs(i.SpectatorPlayerClock.CurrentTime - syncManager.CurrentMasterTime)); // Only bind adjustments if there's actually a valid source, else just use the previous ones to ensure no sudden changes to audio. if (currentAudioSource != null) diff --git a/osu.Game/Storyboards/Storyboard.cs b/osu.Game/Storyboards/Storyboard.cs index 8133244e89..566e064aad 100644 --- a/osu.Game/Storyboards/Storyboard.cs +++ b/osu.Game/Storyboards/Storyboard.cs @@ -32,7 +32,7 @@ namespace osu.Game.Storyboards /// /// This iterates all elements and as such should be used sparingly or stored locally. /// - public double? EarliestEventTime => Layers.SelectMany(l => l.Elements).OrderBy(e => e.StartTime).FirstOrDefault()?.StartTime; + public double? EarliestEventTime => Layers.SelectMany(l => l.Elements).MinBy(e => e.StartTime)?.StartTime; /// /// Across all layers, find the latest point in time that a storyboard element ends at. @@ -42,7 +42,7 @@ namespace osu.Game.Storyboards /// This iterates all elements and as such should be used sparingly or stored locally. /// Videos and samples return StartTime as their EndTIme. /// - public double? LatestEventTime => Layers.SelectMany(l => l.Elements).OrderBy(e => e.GetEndTime()).LastOrDefault()?.GetEndTime(); + public double? LatestEventTime => Layers.SelectMany(l => l.Elements).MaxBy(e => e.GetEndTime())?.GetEndTime(); /// /// Depth of the currently front-most storyboard layer, excluding the overlay layer. diff --git a/osu.Game/Storyboards/StoryboardSprite.cs b/osu.Game/Storyboards/StoryboardSprite.cs index cd7788bb08..5b7b194be7 100644 --- a/osu.Game/Storyboards/StoryboardSprite.cs +++ b/osu.Game/Storyboards/StoryboardSprite.cs @@ -48,7 +48,7 @@ namespace osu.Game.Storyboards if (alphaCommands.Count > 0) { - var firstAlpha = alphaCommands.OrderBy(t => t.startTime).First(); + var firstAlpha = alphaCommands.MinBy(t => t.startTime); if (firstAlpha.isZeroStartValue) return firstAlpha.startTime; diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 765c665966..ad5e3f6c4d 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -108,9 +108,7 @@ namespace osu.Game.Tests.Visual.Multiplayer // simulate the server's automatic assignment of users to teams on join. // the "best" team is the one with the least users on it. int bestTeam = teamVersus.Teams - .Select(team => (teamID: team.ID, userCount: ServerRoom.Users.Count(u => (u.MatchState as TeamVersusUserState)?.TeamID == team.ID))) - .OrderBy(pair => pair.userCount) - .First().teamID; + .Select(team => (teamID: team.ID, userCount: ServerRoom.Users.Count(u => (u.MatchState as TeamVersusUserState)?.TeamID == team.ID))).MinBy(pair => pair.userCount).teamID; user.MatchState = new TeamVersusUserState { TeamID = bestTeam }; ((IMultiplayerClient)this).MatchUserStateChanged(clone(user.UserID), clone(user.MatchState)).WaitSafely(); diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 154ad0fe8c..ef3b08e1f5 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -218,6 +218,7 @@ WARNING WARNING WARNING + WARNING WARNING HINT WARNING From 12c77cca26b66c70e8efb0ae8d9a594c62b27fb8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Dec 2022 15:44:10 +0900 Subject: [PATCH 2624/2686] Remove `rollForward` rule for now --- global.json | 6 ------ osu.sln | 1 - 2 files changed, 7 deletions(-) delete mode 100644 global.json diff --git a/global.json b/global.json deleted file mode 100644 index f20ff84190..0000000000 --- a/global.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "sdk": { - "version": "6.0.300", - "rollForward": "major" - } -} diff --git a/osu.sln b/osu.sln index 5b23ff9ae6..aeec0843be 100644 --- a/osu.sln +++ b/osu.sln @@ -63,7 +63,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution CodeAnalysis\osu.ruleset = CodeAnalysis\osu.ruleset osu.sln.DotSettings = osu.sln.DotSettings osu.TestProject.props = osu.TestProject.props - global.json = global.json EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Benchmarks", "osu.Game.Benchmarks\osu.Game.Benchmarks.csproj", "{93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}" From 99ad78cdd631e5b999dd8ebcef6e978906fcb63c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Dec 2022 22:01:13 +0900 Subject: [PATCH 2625/2686] Remove no longer necessary workarounds from mobile props files --- osu.Android.props | 4 ---- osu.iOS.props | 9 --------- 2 files changed, 13 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 5da7eae380..a0ad0cdcdc 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -12,10 +12,6 @@ - - - - diff --git a/osu.iOS.props b/osu.iOS.props index 98d3e129d4..4dac17c024 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -15,15 +15,6 @@ iossimulator-x64 - - - - none - - - none - - From ecac6299c6679d6c29133cb9fab88e53520b7104 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 19 Dec 2022 22:01:20 +0900 Subject: [PATCH 2626/2686] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index a0ad0cdcdc..31670bedb5 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8bb68faf7b..8b4fa2dc6b 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 4dac17c024..0ff4fafb31 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -16,7 +16,7 @@ iossimulator-x64 - + - - - <_LinkerFrameworks Remove="Quartz"/> - - From 2249c97a6f1232f9c626ff0648fbf2c43714281a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 19 Dec 2022 18:27:19 +0300 Subject: [PATCH 2628/2686] Pin certain system package versions to avoid downgrade errors --- osu.iOS.props | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.iOS.props b/osu.iOS.props index b5f470eda1..c6798cd5e4 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,5 +17,10 @@ + + + + + From d47a8b2e26df2146e468e4606de0b3adf8690130 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 19 Dec 2022 18:42:51 +0300 Subject: [PATCH 2629/2686] Remove unnecessary discard --- osu.iOS/OsuGameIOS.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS/OsuGameIOS.cs b/osu.iOS/OsuGameIOS.cs index cb3b260033..3e79bc6ad6 100644 --- a/osu.iOS/OsuGameIOS.cs +++ b/osu.iOS/OsuGameIOS.cs @@ -33,7 +33,7 @@ namespace osu.iOS { switch (handler) { - case IOSMouseHandler _: + case IOSMouseHandler: return new IOSMouseSettings(); default: From 36c620287b1a17faff7c6317dfa0159344b974ae Mon Sep 17 00:00:00 2001 From: Susko3 Date: Mon, 19 Dec 2022 18:11:05 +0100 Subject: [PATCH 2630/2686] Remove no longer needed `Linker.xml` configurations for mobile projects --- osu.Android.props | 3 --- osu.Android/Linker.xml | 7 ------- osu.iOS/Linker.xml | 31 ------------------------------- 3 files changed, 41 deletions(-) delete mode 100644 osu.Android/Linker.xml delete mode 100644 osu.iOS/Linker.xml diff --git a/osu.Android.props b/osu.Android.props index 31670bedb5..e934b2da6a 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -12,9 +12,6 @@ - - - diff --git a/osu.Android/Linker.xml b/osu.Android/Linker.xml deleted file mode 100644 index c7d31fe087..0000000000 --- a/osu.Android/Linker.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/osu.iOS/Linker.xml b/osu.iOS/Linker.xml deleted file mode 100644 index b55be3be39..0000000000 --- a/osu.iOS/Linker.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 186ccc64fd26e5e56a5cffbeff25302a9c3d2aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Dec 2022 18:19:26 +0100 Subject: [PATCH 2631/2686] Fix welcome screen language buttons not working --- osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs index fe3aaeb9d8..f6133e3643 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -147,7 +147,7 @@ namespace osu.Game.Overlays.FirstRunSetup [BackgroundDependencyLoader] private void load() { - InternalChildren = new Drawable[] + AddRange(new Drawable[] { backgroundBox = new Box { @@ -162,7 +162,7 @@ namespace osu.Game.Overlays.FirstRunSetup Colour = colourProvider.Light1, Text = Language.GetDescription(), } - }; + }); } protected override void LoadComplete() From 0dce8996344e162e746bf783f43d2c193e4d146f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Dec 2022 18:25:45 +0100 Subject: [PATCH 2632/2686] Throw on `OsuClickableContainer.ClearInternal()` invocations As they may cause critical failure due to getting rid of the `Content`. --- osu.Game/Graphics/Containers/OsuClickableContainer.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index 6ec393df4b..ce50dbdc39 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -46,5 +47,8 @@ namespace osu.Game.Graphics.Containers AddInternal(content); Add(CreateHoverSounds(sampleSet)); } + + protected override void ClearInternal(bool disposeChildren = true) => + throw new InvalidOperationException($"Clearing {nameof(InternalChildren)} will cause critical failure. Use {nameof(Clear)} instead."); } } From 6e55f2f779f69d942df61ca62676766c717d04b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 16 Dec 2022 20:57:27 +0100 Subject: [PATCH 2633/2686] Add test for markdown footnotes --- .../Visual/Online/TestSceneWikiMarkdownContainer.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index b486f800c6..c0a7b9b921 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -199,6 +199,17 @@ Line after image"; }); } + [Test] + public void TestFootnotes() + { + AddStep("set content", () => markdownContainer.Text = @"This text has a footnote[^test]. + +Here's some more text[^test2] with another footnote! + +[^test]: This is a **footnote**. +[^test2]: This is another footnote [with a link](https://google.com/)!"); + } + private partial class TestMarkdownContainer : WikiMarkdownContainer { public LinkInline Link; From 112613c2f09c717d75ec32b30fab8ef3336bde5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 16 Dec 2022 20:59:14 +0100 Subject: [PATCH 2634/2686] Add styling for footnote links --- .../Footnotes/OsuMarkdownFootnoteLink.cs | 70 +++++++++++++++++ .../Footnotes/OsuMarkdownFootnoteTooltip.cs | 76 +++++++++++++++++++ .../Markdown/OsuMarkdownContainer.cs | 2 + .../Markdown/OsuMarkdownTextFlowContainer.cs | 4 + 4 files changed, 152 insertions(+) create mode 100644 osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteLink.cs create mode 100644 osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteTooltip.cs diff --git a/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteLink.cs b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteLink.cs new file mode 100644 index 0000000000..b35c08e335 --- /dev/null +++ b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteLink.cs @@ -0,0 +1,70 @@ +// 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 Markdig.Extensions.Footnotes; +using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Overlays; + +namespace osu.Game.Graphics.Containers.Markdown.Footnotes +{ + public partial class OsuMarkdownFootnoteLink : OsuHoverContainer, IHasCustomTooltip + { + private readonly FootnoteLink footnoteLink; + + private SpriteText spriteText = null!; + + [Resolved] + private IMarkdownTextComponent parentTextComponent { get; set; } = null!; + + [Resolved] + private OverlayColourProvider colourProvider { get; set; } = null!; + + [Resolved] + private OsuMarkdownContainer markdownContainer { get; set; } = null!; + + protected override IEnumerable EffectTargets => spriteText.Yield(); + + public OsuMarkdownFootnoteLink(FootnoteLink footnoteLink) + { + this.footnoteLink = footnoteLink; + + AutoSizeAxes = Axes.Both; + Action = () => { }; // TODO + } + + [BackgroundDependencyLoader] + private void load() + { + IdleColour = colourProvider.Light2; + HoverColour = colourProvider.Light1; + + spriteText = parentTextComponent.CreateSpriteText(); + + Add(spriteText.With(t => + { + float baseSize = t.Font.Size; + t.Font = t.Font.With(size: baseSize * 0.58f); + t.Margin = new MarginPadding { Bottom = 0.33f * baseSize }; + t.Text = LocalisableString.Format("[{0}]", footnoteLink.Index); + })); + } + + public object TooltipContent + { + get + { + var span = footnoteLink.Footnote.LastChild.Span; + return markdownContainer.Text.Substring(span.Start, span.Length); + } + } + + public ITooltip GetCustomTooltip() => new OsuMarkdownFootnoteTooltip(colourProvider); + } +} diff --git a/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteTooltip.cs b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteTooltip.cs new file mode 100644 index 0000000000..af64913212 --- /dev/null +++ b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteTooltip.cs @@ -0,0 +1,76 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig.Extensions.Footnotes; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Graphics.Containers.Markdown.Footnotes +{ + public partial class OsuMarkdownFootnoteTooltip : CompositeDrawable, ITooltip + { + private readonly FootnoteMarkdownContainer markdownContainer; + + [Cached] + private OverlayColourProvider colourProvider; + + public OsuMarkdownFootnoteTooltip(OverlayColourProvider colourProvider) + { + this.colourProvider = colourProvider; + + Masking = true; + Width = 200; + AutoSizeAxes = Axes.Y; + CornerRadius = 4; + + InternalChildren = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background6 + }, + markdownContainer = new FootnoteMarkdownContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + DocumentMargin = new MarginPadding(), + DocumentPadding = new MarginPadding { Horizontal = 10, Vertical = 5 } + } + }; + } + + public void Move(Vector2 pos) => Position = pos; + + public void SetContent(object content) => markdownContainer.SetContent((string)content); + + private partial class FootnoteMarkdownContainer : OsuMarkdownContainer + { + private string? lastFootnote; + + public void SetContent(string footnote) + { + if (footnote == lastFootnote) + return; + + lastFootnote = Text = footnote; + } + + public override MarkdownTextFlowContainer CreateTextFlow() => new FootnoteMarkdownTextFlowContainer(); + } + + private partial class FootnoteMarkdownTextFlowContainer : OsuMarkdownTextFlowContainer + { + protected override void AddFootnoteBacklink(FootnoteLink footnoteBacklink) + { + // we don't want footnote backlinks to show up in tooltips. + } + } + } +} diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs index e884b5db69..a7d518c693 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs @@ -11,6 +11,7 @@ using Markdig.Extensions.Footnotes; using Markdig.Extensions.Tables; using Markdig.Extensions.Yaml; using Markdig.Syntax; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; @@ -19,6 +20,7 @@ using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.Containers.Markdown { + [Cached] public partial class OsuMarkdownContainer : MarkdownContainer { /// diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs index 7de63fe09c..0cafb68648 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs @@ -6,6 +6,7 @@ using System; using System.Linq; using Markdig.Extensions.CustomContainers; +using Markdig.Extensions.Footnotes; using Markdig.Syntax.Inlines; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -13,6 +14,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics.Containers.Markdown.Footnotes; using osu.Game.Overlays; using osu.Game.Users; using osu.Game.Users.Drawables; @@ -36,6 +38,8 @@ namespace osu.Game.Graphics.Containers.Markdown Text = codeInline.Content }); + protected override void AddFootnoteLink(FootnoteLink footnoteLink) => AddDrawable(new OsuMarkdownFootnoteLink(footnoteLink)); + protected override SpriteText CreateEmphasisedSpriteText(bool bold, bool italic) => CreateSpriteText().With(t => t.Font = t.Font.With(weight: bold ? FontWeight.Bold : FontWeight.Regular, italics: italic)); From 73a4310935a857f18c455c25579aa8a212c453d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 16 Dec 2022 21:26:13 +0100 Subject: [PATCH 2635/2686] Add styling for footnote groups --- .../Markdown/Footnotes/OsuMarkdownFootnote.cs | 30 +++++++++++ .../Footnotes/OsuMarkdownFootnoteBacklink.cs | 52 +++++++++++++++++++ .../Markdown/OsuMarkdownContainer.cs | 7 +++ .../Markdown/OsuMarkdownTextFlowContainer.cs | 2 + 4 files changed, 91 insertions(+) create mode 100644 osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnote.cs create mode 100644 osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteBacklink.cs diff --git a/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnote.cs b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnote.cs new file mode 100644 index 0000000000..e92d866eed --- /dev/null +++ b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnote.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig.Extensions.Footnotes; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Framework.Graphics.Containers.Markdown.Footnotes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; + +namespace osu.Game.Graphics.Containers.Markdown.Footnotes +{ + public partial class OsuMarkdownFootnote : MarkdownFootnote + { + public OsuMarkdownFootnote(Footnote footnote) + : base(footnote) + { + } + + public override SpriteText CreateOrderMarker(int order) => CreateSpriteText().With(marker => + { + marker.Text = LocalisableString.Format("{0}.", order); + }); + + public override MarkdownTextFlowContainer CreateTextFlow() => base.CreateTextFlow().With(textFlow => + { + textFlow.Margin = new MarginPadding { Left = 30 }; + }); + } +} diff --git a/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteBacklink.cs b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteBacklink.cs new file mode 100644 index 0000000000..a401eadaa3 --- /dev/null +++ b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteBacklink.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 System.Collections.Generic; +using Markdig.Extensions.Footnotes; +using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Framework.Graphics.Sprites; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Graphics.Containers.Markdown.Footnotes +{ + public partial class OsuMarkdownFootnoteBacklink : OsuHoverContainer + { + private readonly FootnoteLink backlink; + + private SpriteIcon spriteIcon = null!; + + [Resolved] + private IMarkdownTextComponent parentTextComponent { get; set; } = null!; + + protected override IEnumerable EffectTargets => spriteIcon.Yield(); + + public OsuMarkdownFootnoteBacklink(FootnoteLink backlink) + { + this.backlink = backlink; + AutoSizeAxes = Axes.X; + } + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + float fontSize = parentTextComponent.CreateSpriteText().Font.Size; + Height = fontSize; + + IdleColour = colourProvider.Light2; + HoverColour = colourProvider.Light1; + + Add(spriteIcon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Left = 5 }, + Size = new Vector2(fontSize / 2), + Icon = FontAwesome.Solid.ArrowUp, + }); + } + } +} diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs index a7d518c693..65e1749261 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs @@ -15,8 +15,11 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; +using osu.Framework.Graphics.Containers.Markdown.Footnotes; using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics.Containers.Markdown.Footnotes; using osu.Game.Graphics.Sprites; +using osuTK; namespace osu.Game.Graphics.Containers.Markdown { @@ -101,6 +104,10 @@ namespace osu.Game.Graphics.Containers.Markdown return new OsuMarkdownUnorderedListItem(level); } + protected override MarkdownFootnoteGroup CreateFootnoteGroup(FootnoteGroup footnoteGroup) => base.CreateFootnoteGroup(footnoteGroup).With(g => g.Spacing = new Vector2(5)); + + protected override MarkdownFootnote CreateFootnote(Footnote footnote) => new OsuMarkdownFootnote(footnote); + // reference: https://github.com/ppy/osu-web/blob/05488a96b25b5a09f2d97c54c06dd2bae59d1dc8/app/Libraries/Markdown/OsuMarkdown.php#L301 protected override MarkdownPipeline CreateBuilder() { diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs index 0cafb68648..5f5b9acf56 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownTextFlowContainer.cs @@ -40,6 +40,8 @@ namespace osu.Game.Graphics.Containers.Markdown protected override void AddFootnoteLink(FootnoteLink footnoteLink) => AddDrawable(new OsuMarkdownFootnoteLink(footnoteLink)); + protected override void AddFootnoteBacklink(FootnoteLink footnoteBacklink) => AddDrawable(new OsuMarkdownFootnoteBacklink(footnoteBacklink)); + protected override SpriteText CreateEmphasisedSpriteText(bool bold, bool italic) => CreateSpriteText().With(t => t.Font = t.Font.With(weight: bold ? FontWeight.Bold : FontWeight.Regular, italics: italic)); From 3c1a46605ef59a6a8b633c5961d3d7989bfa4025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 16 Dec 2022 21:34:12 +0100 Subject: [PATCH 2636/2686] Set up test for two-way navigation testing --- .../Online/TestSceneWikiMarkdownContainer.cs | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index c0a7b9b921..b1edea1e4e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -31,6 +31,8 @@ namespace osu.Game.Tests.Visual.Online [SetUp] public void Setup() => Schedule(() => { + OverlayScrollContainer scrollContainer; + Children = new Drawable[] { new Box @@ -38,15 +40,25 @@ namespace osu.Game.Tests.Visual.Online Colour = overlayColour.Background5, RelativeSizeAxes = Axes.Both, }, - new BasicScrollContainer + scrollContainer = new OverlayScrollContainer { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding(20), - Child = markdownContainer = new TestMarkdownContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - } + } + }; + + scrollContainer.Child = new DependencyProvidingContainer + { + CachedDependencies = new (Type, object)[] + { + (typeof(OverlayScrollContainer), scrollContainer) + }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = markdownContainer = new TestMarkdownContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, } }; }); @@ -206,6 +218,16 @@ Line after image"; Here's some more text[^test2] with another footnote! +# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam efficitur laoreet posuere. Ut accumsan tortor in ipsum tincidunt ultrices. Suspendisse a malesuada tellus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce a sagittis nibh. In et velit sit amet mauris aliquet consectetur quis vehicula lorem. Etiam sit amet tellus ac velit ornare maximus. Donec quis metus eget libero ullamcorper imperdiet id vitae arcu. Vivamus iaculis rhoncus purus malesuada mollis. Vestibulum dictum at nisi sed tincidunt. Suspendisse finibus, ipsum ut dapibus commodo, leo eros porttitor sapien, non scelerisque nisi ligula sed ex. Pellentesque magna orci, hendrerit eu iaculis sit amet, ullamcorper in urna. Vivamus dictum mauris orci, nec facilisis dolor fringilla eu. Sed at porttitor nisi, at venenatis urna. Ut at orci vitae libero semper ullamcorper eu ut risus. Mauris hendrerit varius enim, ut varius nisi feugiat mattis. + +## In at eros urna. Sed ipsum lorem, tempor sit amet purus in, vehicula pellentesque leo. Fusce volutpat pellentesque velit sit amet porttitor. Nulla eget erat ex. Praesent eu lacinia est, quis vehicula lacus. Donec consequat ultrices neque, at finibus quam efficitur vel. Vestibulum molestie nisl sit amet metus semper, at vestibulum massa rhoncus. Quisque imperdiet suscipit augue, et dignissim odio eleifend ut. + +Aliquam sed vestibulum mauris, ut lobortis elit. Sed quis lacinia erat. Nam ultricies, risus non pellentesque sollicitudin, mauris dolor tincidunt neque, ac porta ipsum dui quis libero. Integer eget velit neque. Vestibulum venenatis mauris vitae rutrum vestibulum. Maecenas suscipit eu purus eu tempus. Nam dui nisl, bibendum condimentum mollis et, gravida vel dui. Sed et eros rutrum, facilisis sapien eu, mattis ligula. Fusce finibus pulvinar dolor quis consequat. + +Donec ipsum felis, feugiat vel fermentum at, commodo eu sapien. Suspendisse nec enim vitae felis laoreet laoreet. Phasellus purus quam, fermentum a pharetra vel, tempor et urna. Integer vitae quam diam. Aliquam tincidunt tortor a iaculis convallis. Suspendisse potenti. Cras quis risus quam. Nullam tincidunt in lorem posuere sagittis. + +Phasellus eu nunc nec ligula semper fringilla. Aliquam magna neque, placerat sed urna tristique, laoreet pharetra nulla. Vivamus maximus turpis purus, eu viverra dolor sodales porttitor. Praesent bibendum sapien purus, sed ultricies dolor iaculis sed. Fusce congue hendrerit malesuada. Nulla nulla est, auctor ac fringilla sed, ornare a lorem. Donec quis velit imperdiet, imperdiet sem non, pellentesque sapien. Maecenas in orci id ipsum placerat facilisis non sed nisi. Duis dictum lorem sodales odio dictum eleifend. Vestibulum bibendum euismod quam, eget pharetra orci facilisis sed. Vivamus at diam non ipsum consequat tristique. Pellentesque gravida dignissim pellentesque. Donec ullamcorper lacinia orci, id consequat purus faucibus quis. Phasellus metus nunc, iaculis a interdum vel, congue sed erat. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam eros libero, hendrerit luctus nulla vitae, luctus maximus nunc. + [^test]: This is a **footnote**. [^test2]: This is another footnote [with a link](https://google.com/)!"); } From 5fb2a83f12bf10f85cacc7b000847394a1691379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 16 Dec 2022 21:53:31 +0100 Subject: [PATCH 2637/2686] Add failing test case for footnote link navigation --- .../Online/TestSceneWikiMarkdownContainer.cs | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index b1edea1e4e..3ec29d5e7c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -16,13 +16,16 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Graphics.Containers.Markdown; +using osu.Game.Graphics.Containers.Markdown.Footnotes; using osu.Game.Overlays; using osu.Game.Overlays.Wiki.Markdown; +using osuTK.Input; namespace osu.Game.Tests.Visual.Online { - public partial class TestSceneWikiMarkdownContainer : OsuTestScene + public partial class TestSceneWikiMarkdownContainer : OsuManualInputManagerTestScene { + private OverlayScrollContainer scrollContainer; private TestMarkdownContainer markdownContainer; [Cached] @@ -31,8 +34,6 @@ namespace osu.Game.Tests.Visual.Online [SetUp] public void Setup() => Schedule(() => { - OverlayScrollContainer scrollContainer; - Children = new Drawable[] { new Box @@ -230,6 +231,31 @@ Phasellus eu nunc nec ligula semper fringilla. Aliquam magna neque, placerat sed [^test]: This is a **footnote**. [^test2]: This is another footnote [with a link](https://google.com/)!"); + AddStep("shrink scroll height", () => scrollContainer.Height = 0.5f); + + AddStep("press second footnote link", () => + { + InputManager.MoveMouseTo(markdownContainer.ChildrenOfType().ElementAt(1)); + InputManager.Click(MouseButton.Left); + }); + AddUntilStep("second footnote scrolled into view", () => + { + var footnote = markdownContainer.ChildrenOfType().ElementAt(1); + return scrollContainer.ScreenSpaceDrawQuad.Contains(footnote.ScreenSpaceDrawQuad.TopLeft) + && scrollContainer.ScreenSpaceDrawQuad.Contains(footnote.ScreenSpaceDrawQuad.BottomRight); + }); + + AddStep("press first footnote backlink", () => + { + InputManager.MoveMouseTo(markdownContainer.ChildrenOfType().First()); + InputManager.Click(MouseButton.Left); + }); + AddUntilStep("first footnote link scrolled into view", () => + { + var footnote = markdownContainer.ChildrenOfType().First(); + return scrollContainer.ScreenSpaceDrawQuad.Contains(footnote.ScreenSpaceDrawQuad.TopLeft) + && scrollContainer.ScreenSpaceDrawQuad.Contains(footnote.ScreenSpaceDrawQuad.BottomRight); + }); } private partial class TestMarkdownContainer : WikiMarkdownContainer From a88812861e933820a76fbd11b29f585f0b98268a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 16 Dec 2022 21:56:32 +0100 Subject: [PATCH 2638/2686] Implement bidirectional footnote link navigation --- .../Footnotes/OsuMarkdownFootnoteBacklink.cs | 18 ++++++++++---- .../Footnotes/OsuMarkdownFootnoteLink.cs | 24 +++++++++++++------ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteBacklink.cs b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteBacklink.cs index a401eadaa3..22c02ea720 100644 --- a/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteBacklink.cs +++ b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteBacklink.cs @@ -2,12 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Linq; using Markdig.Extensions.Footnotes; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Sprites; +using osu.Framework.Testing; using osu.Game.Overlays; using osuTK; @@ -27,14 +29,13 @@ namespace osu.Game.Graphics.Containers.Markdown.Footnotes public OsuMarkdownFootnoteBacklink(FootnoteLink backlink) { this.backlink = backlink; - AutoSizeAxes = Axes.X; } - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + [BackgroundDependencyLoader(true)] + private void load(OverlayColourProvider colourProvider, OsuMarkdownContainer markdownContainer, OverlayScrollContainer? scrollContainer) { float fontSize = parentTextComponent.CreateSpriteText().Font.Size; - Height = fontSize; + Size = new Vector2(fontSize); IdleColour = colourProvider.Light2; HoverColour = colourProvider.Light1; @@ -47,6 +48,15 @@ namespace osu.Game.Graphics.Containers.Markdown.Footnotes Size = new Vector2(fontSize / 2), Icon = FontAwesome.Solid.ArrowUp, }); + + if (scrollContainer != null) + { + Action = () => + { + var footnoteLink = markdownContainer.ChildrenOfType().Single(footnoteLink => footnoteLink.FootnoteLink.Index == backlink.Index); + scrollContainer.ScrollIntoView(footnoteLink); + }; + } } } } diff --git a/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteLink.cs b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteLink.cs index b35c08e335..c9bd408e9e 100644 --- a/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteLink.cs +++ b/osu.Game/Graphics/Containers/Markdown/Footnotes/OsuMarkdownFootnoteLink.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 Markdig.Extensions.Footnotes; using osu.Framework.Allocation; using osu.Framework.Extensions.IEnumerableExtensions; @@ -10,13 +11,14 @@ using osu.Framework.Graphics.Containers.Markdown; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Framework.Testing; using osu.Game.Overlays; namespace osu.Game.Graphics.Containers.Markdown.Footnotes { public partial class OsuMarkdownFootnoteLink : OsuHoverContainer, IHasCustomTooltip { - private readonly FootnoteLink footnoteLink; + public readonly FootnoteLink FootnoteLink; private SpriteText spriteText = null!; @@ -33,14 +35,13 @@ namespace osu.Game.Graphics.Containers.Markdown.Footnotes public OsuMarkdownFootnoteLink(FootnoteLink footnoteLink) { - this.footnoteLink = footnoteLink; + FootnoteLink = footnoteLink; AutoSizeAxes = Axes.Both; - Action = () => { }; // TODO } - [BackgroundDependencyLoader] - private void load() + [BackgroundDependencyLoader(true)] + private void load(OsuMarkdownContainer markdownContainer, OverlayScrollContainer? scrollContainer) { IdleColour = colourProvider.Light2; HoverColour = colourProvider.Light1; @@ -52,15 +53,24 @@ namespace osu.Game.Graphics.Containers.Markdown.Footnotes float baseSize = t.Font.Size; t.Font = t.Font.With(size: baseSize * 0.58f); t.Margin = new MarginPadding { Bottom = 0.33f * baseSize }; - t.Text = LocalisableString.Format("[{0}]", footnoteLink.Index); + t.Text = LocalisableString.Format("[{0}]", FootnoteLink.Index); })); + + if (scrollContainer != null) + { + Action = () => + { + var footnote = markdownContainer.ChildrenOfType().Single(footnote => footnote.Footnote.Label == FootnoteLink.Footnote.Label); + scrollContainer.ScrollIntoView(footnote); + }; + } } public object TooltipContent { get { - var span = footnoteLink.Footnote.LastChild.Span; + var span = FootnoteLink.Footnote.LastChild.Span; return markdownContainer.Text.Substring(span.Start, span.Length); } } From db1380a346799cd00ef2a4a26227087cd5ae1d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Dec 2022 20:16:36 +0100 Subject: [PATCH 2639/2686] Refactor markdown extension management --- .../Markdown/OsuMarkdownContainer.cs | 48 +++------------ .../Markdown/OsuMarkdownContainerOptions.cs | 61 +++++++++++++++++++ .../Comments/CommentMarkdownContainer.cs | 5 +- .../Wiki/Markdown/WikiMarkdownContainer.cs | 7 ++- 4 files changed, 77 insertions(+), 44 deletions(-) create mode 100644 osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainerOptions.cs diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs index e884b5db69..7e9581c056 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainer.cs @@ -4,10 +4,6 @@ #nullable disable using Markdig; -using Markdig.Extensions.AutoLinks; -using Markdig.Extensions.CustomContainers; -using Markdig.Extensions.EmphasisExtras; -using Markdig.Extensions.Footnotes; using Markdig.Extensions.Tables; using Markdig.Extensions.Yaml; using Markdig.Syntax; @@ -21,24 +17,6 @@ namespace osu.Game.Graphics.Containers.Markdown { public partial class OsuMarkdownContainer : MarkdownContainer { - /// - /// Allows this markdown container to parse and link footnotes. - /// - /// - protected virtual bool Footnotes => false; - - /// - /// Allows this markdown container to make URL text clickable. - /// - /// - protected virtual bool Autolinks => false; - - /// - /// Allows this markdown container to parse custom containers (used for flags and infoboxes). - /// - /// - protected virtual bool CustomContainers => false; - public OsuMarkdownContainer() { LineSpacing = 21; @@ -99,25 +77,13 @@ namespace osu.Game.Graphics.Containers.Markdown return new OsuMarkdownUnorderedListItem(level); } - // reference: https://github.com/ppy/osu-web/blob/05488a96b25b5a09f2d97c54c06dd2bae59d1dc8/app/Libraries/Markdown/OsuMarkdown.php#L301 - protected override MarkdownPipeline CreateBuilder() - { - var pipeline = new MarkdownPipelineBuilder() - .UseAutoIdentifiers() - .UsePipeTables() - .UseEmphasisExtras(EmphasisExtraOptions.Strikethrough) - .UseYamlFrontMatter(); + protected sealed override MarkdownPipeline CreateBuilder() + => Options.BuildPipeline(); - if (Footnotes) - pipeline = pipeline.UseFootnotes(); - - if (Autolinks) - pipeline = pipeline.UseAutoLinks(); - - if (CustomContainers) - pipeline.UseCustomContainers(); - - return pipeline.Build(); - } + /// + /// Creates a instance which is used to determine + /// which CommonMark/Markdig extensions should be enabled for this . + /// + protected virtual OsuMarkdownContainerOptions Options => new OsuMarkdownContainerOptions(); } } diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainerOptions.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainerOptions.cs new file mode 100644 index 0000000000..f2fd0e06a6 --- /dev/null +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainerOptions.cs @@ -0,0 +1,61 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig; +using Markdig.Extensions.AutoLinks; +using Markdig.Extensions.CustomContainers; +using Markdig.Extensions.EmphasisExtras; +using Markdig.Extensions.Footnotes; + +namespace osu.Game.Graphics.Containers.Markdown +{ + /// + /// Groups options of customising the set of available extensions to instances. + /// + public class OsuMarkdownContainerOptions + { + /// + /// Allows the to parse and link footnotes. + /// + /// + public bool Footnotes { get; init; } + + /// + /// Allows the container to make URL text clickable. + /// + /// + public bool Autolinks { get; init; } + + /// + /// Allows the to parse custom containers (used for flags and infoboxes). + /// + /// + public bool CustomContainers { get; init; } + + /// + /// Returns a prepared according to the options specified by the current instance. + /// + /// + /// Compare: https://github.com/ppy/osu-web/blob/05488a96b25b5a09f2d97c54c06dd2bae59d1dc8/app/Libraries/Markdown/OsuMarkdown.php#L301 + /// + public MarkdownPipeline BuildPipeline() + { + var pipeline = new MarkdownPipelineBuilder() + .UseAutoIdentifiers() + .UsePipeTables() + .UseEmphasisExtras(EmphasisExtraOptions.Strikethrough) + .UseYamlFrontMatter(); + + if (Footnotes) + pipeline = pipeline.UseFootnotes(); + + if (Autolinks) + pipeline = pipeline.UseAutoLinks(); + + if (CustomContainers) + pipeline.UseCustomContainers(); + + return pipeline.Build(); + } + } +} diff --git a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs index 664946fc63..9cc20caa05 100644 --- a/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs +++ b/osu.Game/Overlays/Comments/CommentMarkdownContainer.cs @@ -11,7 +11,10 @@ namespace osu.Game.Overlays.Comments { public partial class CommentMarkdownContainer : OsuMarkdownContainer { - protected override bool Autolinks => true; + protected override OsuMarkdownContainerOptions Options => new OsuMarkdownContainerOptions + { + Autolinks = true + }; protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) => new CommentMarkdownHeading(headingBlock); diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index 4ef9be90c9..bb296c5d41 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -16,8 +16,11 @@ namespace osu.Game.Overlays.Wiki.Markdown { public partial class WikiMarkdownContainer : OsuMarkdownContainer { - protected override bool Footnotes => true; - protected override bool CustomContainers => true; + protected override OsuMarkdownContainerOptions Options => new OsuMarkdownContainerOptions + { + Footnotes = true, + CustomContainers = true + }; public string CurrentPath { From 12aa2e96db35ebff527dc153760048e2c6bf0e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Dec 2022 21:21:18 +0100 Subject: [PATCH 2640/2686] Add test case covering failure --- .../Visual/Online/TestSceneWikiMarkdownContainer.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index b486f800c6..6185c43f99 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -199,6 +199,16 @@ Line after image"; }); } + [Test] + public void TestHeadingWithIdAttribute() + { + AddStep("Add heading with ID", () => + { + markdownContainer.Text = "# This is a heading with an ID {#this-is-the-id}"; + }); + AddAssert("ID not visible", () => markdownContainer.ChildrenOfType().All(spriteText => spriteText.Text != "{#this-is-the-id}")); + } + private partial class TestMarkdownContainer : WikiMarkdownContainer { public LinkInline Link; From 7c282d9def40871269abd7532a9545d2b6383bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Dec 2022 20:23:01 +0100 Subject: [PATCH 2641/2686] Enable generic attribute support for wiki markdown containers --- .../Extensions/BlockAttributeExtension.cs | 34 +++++++++++++++++++ .../Extensions/OsuMarkdownExtensions.cs | 21 ++++++++++++ .../Markdown/OsuMarkdownContainerOptions.cs | 12 ++++++- .../Wiki/Markdown/WikiMarkdownContainer.cs | 3 +- 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Graphics/Containers/Markdown/Extensions/BlockAttributeExtension.cs create mode 100644 osu.Game/Graphics/Containers/Markdown/Extensions/OsuMarkdownExtensions.cs diff --git a/osu.Game/Graphics/Containers/Markdown/Extensions/BlockAttributeExtension.cs b/osu.Game/Graphics/Containers/Markdown/Extensions/BlockAttributeExtension.cs new file mode 100644 index 0000000000..caed4b26b9 --- /dev/null +++ b/osu.Game/Graphics/Containers/Markdown/Extensions/BlockAttributeExtension.cs @@ -0,0 +1,34 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig; +using Markdig.Extensions.GenericAttributes; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace osu.Game.Graphics.Containers.Markdown.Extensions +{ + /// + /// A variant of + /// which only handles generic attributes in the current markdown and ignores inline generic attributes. + /// + /// + /// For rationale, see implementation of . + /// + public class BlockAttributeExtension : IMarkdownExtension + { + private readonly GenericAttributesExtension genericAttributesExtension = new GenericAttributesExtension(); + + public void Setup(MarkdownPipelineBuilder pipeline) + { + genericAttributesExtension.Setup(pipeline); + + // GenericAttributesExtension registers a GenericAttributesParser in pipeline.InlineParsers. + // this conflicts with the CustomContainerExtension, leading to some custom containers (e.g. flags) not displaying. + // as a workaround, remove the inline parser here before it can do damage. + pipeline.InlineParsers.RemoveAll(parser => parser is GenericAttributesParser); + } + + public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) => genericAttributesExtension.Setup(pipeline, renderer); + } +} diff --git a/osu.Game/Graphics/Containers/Markdown/Extensions/OsuMarkdownExtensions.cs b/osu.Game/Graphics/Containers/Markdown/Extensions/OsuMarkdownExtensions.cs new file mode 100644 index 0000000000..10542abe71 --- /dev/null +++ b/osu.Game/Graphics/Containers/Markdown/Extensions/OsuMarkdownExtensions.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig; + +namespace osu.Game.Graphics.Containers.Markdown.Extensions +{ + public static class OsuMarkdownExtensions + { + /// + /// Uses the block attributes extension. + /// + /// The pipeline. + /// The modified pipeline. + public static MarkdownPipelineBuilder UseBlockAttributes(this MarkdownPipelineBuilder pipeline) + { + pipeline.Extensions.AddIfNotAlready(); + return pipeline; + } + } +} diff --git a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainerOptions.cs b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainerOptions.cs index f2fd0e06a6..1648ffbf90 100644 --- a/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainerOptions.cs +++ b/osu.Game/Graphics/Containers/Markdown/OsuMarkdownContainerOptions.cs @@ -6,6 +6,7 @@ using Markdig.Extensions.AutoLinks; using Markdig.Extensions.CustomContainers; using Markdig.Extensions.EmphasisExtras; using Markdig.Extensions.Footnotes; +using osu.Game.Graphics.Containers.Markdown.Extensions; namespace osu.Game.Graphics.Containers.Markdown { @@ -32,6 +33,12 @@ namespace osu.Game.Graphics.Containers.Markdown /// public bool CustomContainers { get; init; } + /// + /// Allows the to parse custom attributes in block elements (used e.g. for custom anchor names in the wiki). + /// + /// + public bool BlockAttributes { get; init; } + /// /// Returns a prepared according to the options specified by the current instance. /// @@ -53,7 +60,10 @@ namespace osu.Game.Graphics.Containers.Markdown pipeline = pipeline.UseAutoLinks(); if (CustomContainers) - pipeline.UseCustomContainers(); + pipeline = pipeline.UseCustomContainers(); + + if (BlockAttributes) + pipeline = pipeline.UseBlockAttributes(); return pipeline.Build(); } diff --git a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs index bb296c5d41..7c36caa62f 100644 --- a/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs +++ b/osu.Game/Overlays/Wiki/Markdown/WikiMarkdownContainer.cs @@ -19,7 +19,8 @@ namespace osu.Game.Overlays.Wiki.Markdown protected override OsuMarkdownContainerOptions Options => new OsuMarkdownContainerOptions { Footnotes = true, - CustomContainers = true + CustomContainers = true, + BlockAttributes = true }; public string CurrentPath From 30b9f5d92e901279ae75ca997f47f12e19ecc196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 19 Dec 2022 21:31:54 +0100 Subject: [PATCH 2642/2686] Add test coverage for correct operation of flag extension --- osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs index 6185c43f99..b7989d3f44 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiMarkdownContainer.cs @@ -18,6 +18,7 @@ using osu.Framework.Utils; using osu.Game.Graphics.Containers.Markdown; using osu.Game.Overlays; using osu.Game.Overlays.Wiki.Markdown; +using osu.Game.Users.Drawables; namespace osu.Game.Tests.Visual.Online { @@ -197,6 +198,7 @@ Line after image"; markdownContainer.CurrentPath = @"https://dev.ppy.sh"; markdownContainer.Text = "::{flag=\"AU\"}:: ::{flag=\"ZZ\"}::"; }); + AddAssert("Two flags visible", () => markdownContainer.ChildrenOfType().Count(), () => Is.EqualTo(2)); } [Test] From c119d41a2dac3c8d50304aeb7b16484281404212 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 20 Dec 2022 17:52:53 +0900 Subject: [PATCH 2643/2686] Only show song select for now at ui scale adjust first run screen Having both was a bit too much. Still not happy with this but it's a bit less sensory overload. I think while it's cool being able to show nested screens like this, it needs more thought to actually be a good experience. --- osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index 63688841d0..a3969883e0 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays.FirstRunSetup Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, RelativeSizeAxes = Axes.None, - Size = new Vector2(screen_width, screen_width / 16f * 9 / 2), + Size = new Vector2(screen_width, screen_width / 16f * 9), Children = new Drawable[] { new GridContainer @@ -68,7 +68,6 @@ namespace osu.Game.Overlays.FirstRunSetup { new Drawable[] { - new SampleScreenContainer(new PinnedMainMenu()), new SampleScreenContainer(new NestedSongSelect()), }, // TODO: add more screens here in the future (gameplay / results) @@ -109,17 +108,6 @@ namespace osu.Game.Overlays.FirstRunSetup public override bool? AllowTrackAdjustments => false; } - private partial class PinnedMainMenu : MainMenu - { - public override void OnEntering(ScreenTransitionEvent e) - { - base.OnEntering(e); - - Buttons.ReturnToTopOnIdle = false; - Buttons.State = ButtonSystemState.TopLevel; - } - } - private partial class UIScaleSlider : OsuSliderBar { public override LocalisableString TooltipText => base.TooltipText + "x"; From 439b8ac56ae50fdb77f8d8fd174925a1a6b52324 Mon Sep 17 00:00:00 2001 From: wiskerz76 Date: Mon, 19 Dec 2022 16:33:35 -0500 Subject: [PATCH 2644/2686] Fix file select popup getting stuck when switching first run screens while selecting Closes #21663 Supersedes #21724 --- .../FirstRunSetup/ScreenImportFromStable.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs index 04aa976ff1..8b85bb49a5 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs @@ -126,7 +126,8 @@ namespace osu.Game.Overlays.FirstRunSetup if (available) { - copyInformation.Text = "Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation."; + copyInformation.Text = + "Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation."; } else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows) copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import."; @@ -173,6 +174,18 @@ namespace osu.Game.Overlays.FirstRunSetup c.Current.Disabled = !allow; } + public override void OnSuspending(ScreenTransitionEvent e) + { + stableLocatorTextBox.HidePopover(); + base.OnSuspending(e); + } + + public override bool OnExiting(ScreenExitEvent e) + { + stableLocatorTextBox.HidePopover(); + return base.OnExiting(e); + } + private partial class ImportCheckbox : SettingsCheckbox { public readonly StableContent StableContent; From 2f0c772dcb4d5110727de6389db3f1e9c31d474c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 12 Dec 2022 15:52:29 +0900 Subject: [PATCH 2645/2686] Add argon pro skin --- .../Overlays/Settings/Sections/SkinSection.cs | 1 + osu.Game/Skinning/ArgonProSkin.cs | 48 +++++++++++++++++++ osu.Game/Skinning/ArgonSkin.cs | 6 +-- osu.Game/Skinning/SkinInfo.cs | 1 + osu.Game/Skinning/SkinManager.cs | 1 + osu.Game/Skinning/SkinnableSprite.cs | 1 + 6 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Skinning/ArgonProSkin.cs diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 826a1e7404..f75656cc99 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -105,6 +105,7 @@ namespace osu.Game.Overlays.Settings.Sections dropdownItems.Clear(); dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.ARGON_SKIN).ToLive(realm)); + dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.ARGON_PRO_SKIN).ToLive(realm)); dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.TRIANGLES_SKIN).ToLive(realm)); dropdownItems.Add(sender.Single(s => s.ID == SkinInfo.CLASSIC_SKIN).ToLive(realm)); diff --git a/osu.Game/Skinning/ArgonProSkin.cs b/osu.Game/Skinning/ArgonProSkin.cs new file mode 100644 index 0000000000..2bc8e55ec0 --- /dev/null +++ b/osu.Game/Skinning/ArgonProSkin.cs @@ -0,0 +1,48 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Framework.Audio.Sample; +using osu.Game.Audio; +using osu.Game.Extensions; +using osu.Game.IO; + +namespace osu.Game.Skinning +{ + public class ArgonProSkin : ArgonSkin + { + public new static SkinInfo CreateInfo() => new SkinInfo + { + ID = Skinning.SkinInfo.ARGON_PRO_SKIN, + Name = "osu! \"argon\" pro (2022)", + Creator = "team osu!", + Protected = true, + InstantiationInfo = typeof(ArgonProSkin).GetInvariantInstantiationInfo() + }; + + public override ISample? GetSample(ISampleInfo sampleInfo) + { + foreach (string lookup in sampleInfo.LookupNames) + { + string remappedLookup = lookup.Replace("Gameplay/", "Gameplay/Pro/"); + + var sample = Samples?.Get(remappedLookup) ?? Resources.AudioManager?.Samples.Get(remappedLookup); + if (sample != null) + return sample; + } + + return null; + } + + public ArgonProSkin(IStorageResourceProvider resources) + : this(CreateInfo(), resources) + { + } + + [UsedImplicitly(ImplicitUseKindFlags.InstantiatedWithFixedConstructorSignature)] + public ArgonProSkin(SkinInfo skin, IStorageResourceProvider resources) + : base(skin, resources) + { + } + } +} diff --git a/osu.Game/Skinning/ArgonSkin.cs b/osu.Game/Skinning/ArgonSkin.cs index 6a0c4a23e5..d78147aaea 100644 --- a/osu.Game/Skinning/ArgonSkin.cs +++ b/osu.Game/Skinning/ArgonSkin.cs @@ -30,7 +30,7 @@ namespace osu.Game.Skinning InstantiationInfo = typeof(ArgonSkin).GetInvariantInstantiationInfo() }; - private readonly IStorageResourceProvider resources; + protected readonly IStorageResourceProvider Resources; public ArgonSkin(IStorageResourceProvider resources) : this(CreateInfo(), resources) @@ -41,7 +41,7 @@ namespace osu.Game.Skinning public ArgonSkin(SkinInfo skin, IStorageResourceProvider resources) : base(skin, resources) { - this.resources = resources; + Resources = resources; Configuration.CustomComboColours = new List { @@ -72,7 +72,7 @@ namespace osu.Game.Skinning { foreach (string lookup in sampleInfo.LookupNames) { - var sample = Samples?.Get(lookup) ?? resources.AudioManager?.Samples.Get(lookup); + var sample = Samples?.Get(lookup) ?? Resources.AudioManager?.Samples.Get(lookup); if (sample != null) return sample; } diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index 7b31c8fe88..9ad91f8725 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -20,6 +20,7 @@ namespace osu.Game.Skinning { internal static readonly Guid TRIANGLES_SKIN = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD"); internal static readonly Guid ARGON_SKIN = new Guid("CFFA69DE-B3E3-4DEE-8563-3C4F425C05D0"); + internal static readonly Guid ARGON_PRO_SKIN = new Guid("9FC9CF5D-0F16-4C71-8256-98868321AC43"); internal static readonly Guid CLASSIC_SKIN = new Guid("81F02CD3-EEC6-4865-AC23-FAE26A386187"); internal static readonly Guid RANDOM_SKIN = new Guid("D39DFEFB-477C-4372-B1EA-2BCEA5FB8908"); diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 2ad62dbb61..f750bfad8a 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -84,6 +84,7 @@ namespace osu.Game.Skinning DefaultClassicSkin = new DefaultLegacySkin(this), trianglesSkin = new TrianglesSkin(this), argonSkin = new ArgonSkin(this), + new ArgonProSkin(this), }; // Ensure the default entries are present. diff --git a/osu.Game/Skinning/SkinnableSprite.cs b/osu.Game/Skinning/SkinnableSprite.cs index 1a8a3a26c9..a66f3e0549 100644 --- a/osu.Game/Skinning/SkinnableSprite.cs +++ b/osu.Game/Skinning/SkinnableSprite.cs @@ -111,6 +111,7 @@ namespace osu.Game.Skinning // Temporarily used to exclude undesirable ISkin implementations static bool isUserSkin(ISkin skin) => skin.GetType() == typeof(TrianglesSkin) + || skin.GetType() == typeof(ArgonProSkin) || skin.GetType() == typeof(ArgonSkin) || skin.GetType() == typeof(DefaultLegacySkin) || skin.GetType() == typeof(LegacySkin); From f7c854f1b0ebd59bac44c175dd54694c90ec4b39 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Tue, 20 Dec 2022 21:18:32 +0900 Subject: [PATCH 2646/2686] Change asset folder --- osu.Game/Skinning/ArgonProSkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/ArgonProSkin.cs b/osu.Game/Skinning/ArgonProSkin.cs index 2bc8e55ec0..b753dd8fbe 100644 --- a/osu.Game/Skinning/ArgonProSkin.cs +++ b/osu.Game/Skinning/ArgonProSkin.cs @@ -24,7 +24,7 @@ namespace osu.Game.Skinning { foreach (string lookup in sampleInfo.LookupNames) { - string remappedLookup = lookup.Replace("Gameplay/", "Gameplay/Pro/"); + string remappedLookup = lookup.Replace(@"Gameplay/", @"Gameplay/ArgonPro/"); var sample = Samples?.Get(remappedLookup) ?? Resources.AudioManager?.Samples.Get(remappedLookup); if (sample != null) From 2c402d474035be888284b7318050aabb9abb3423 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Dec 2022 01:24:41 +0900 Subject: [PATCH 2647/2686] Update resources --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8b4fa2dc6b..83dbf7e370 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ - + From bf074adb137c2178eebd38dd285fbaec82c86364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 20 Dec 2022 18:24:26 +0100 Subject: [PATCH 2648/2686] Remove unused using directive --- osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index a3969883e0..1bcb1bcdf4 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Textures; using osu.Framework.Localisation; -using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics; From cebd5f6dc2384d6468f56f31385cda8e7c035d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 20 Dec 2022 20:36:27 +0100 Subject: [PATCH 2649/2686] Fix restore default button having a minuscule hit area Another casualty of edc78205d5312e9278f2a22ef156fd34af492595. This particular button was actually *relying* on receiving positional events from its entire bounding box rather than `Content`, in order for the button to be htitable more easily, which broke as other buttons were fixed to behave more in line with expectations. Upon closer inspection this is another case of a weird carried-over construction. The button doesn't really need to inherit `OsuButton` or do any of the arcane stuff that it was doing, so it's now a plain `OsuClickableContainer` with less `Content` hackery. --- .../Overlays/RestoreDefaultValueButton.cs | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 24dec44588..9d5e5db6e6 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -7,18 +7,20 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osuTK; namespace osu.Game.Overlays { - public partial class RestoreDefaultValueButton : OsuButton, IHasTooltip, IHasCurrentValue + public partial class RestoreDefaultValueButton : OsuClickableContainer, IHasCurrentValue { public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; @@ -51,15 +53,32 @@ namespace osu.Game.Overlays private const float size = 4; + private CircularContainer circle = null!; + private Box background = null!; + + public RestoreDefaultValueButton() + : base(HoverSampleSet.Button) + { + } + [BackgroundDependencyLoader] private void load(OsuColour colour) { - BackgroundColour = colour.Lime1; + // size intentionally much larger than actual drawn content, so that the button is easier to click. Size = new Vector2(3 * size); - Content.RelativeSizeAxes = Axes.None; - Content.Size = new Vector2(size); - Content.CornerRadius = size / 2; + Add(circle = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(size), + Masking = true, + Child = background = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colour.Lime1 + } + }); Alpha = 0f; @@ -77,7 +96,7 @@ namespace osu.Game.Overlays FinishTransforms(true); } - public LocalisableString TooltipText => "revert to default"; + public override LocalisableString TooltipText => "revert to default"; protected override bool OnHover(HoverEvent e) { @@ -104,8 +123,8 @@ namespace osu.Game.Overlays if (!Current.Disabled) { this.FadeTo(Current.IsDefault ? 0 : 1, fade_duration, Easing.OutQuint); - Background.FadeColour(IsHovered ? colours.Lime0 : colours.Lime1, fade_duration, Easing.OutQuint); - Content.TweenEdgeEffectTo(new EdgeEffectParameters + background.FadeColour(IsHovered ? colours.Lime0 : colours.Lime1, fade_duration, Easing.OutQuint); + circle.TweenEdgeEffectTo(new EdgeEffectParameters { Colour = (IsHovered ? colours.Lime1 : colours.Lime3).Opacity(0.4f), Radius = IsHovered ? 8 : 4, @@ -114,8 +133,8 @@ namespace osu.Game.Overlays } else { - Background.FadeColour(colours.Lime3, fade_duration, Easing.OutQuint); - Content.TweenEdgeEffectTo(new EdgeEffectParameters + background.FadeColour(colours.Lime3, fade_duration, Easing.OutQuint); + circle.TweenEdgeEffectTo(new EdgeEffectParameters { Colour = colours.Lime3.Opacity(0.1f), Radius = 2, From b03291330f2fb89dd482a53b62c23caeeb1b0757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 20 Dec 2022 21:23:50 +0100 Subject: [PATCH 2650/2686] Add score processed callback to spectator client --- osu.Game/Online/Spectator/ISpectatorClient.cs | 7 +++++++ osu.Game/Online/Spectator/OnlineSpectatorClient.cs | 1 + osu.Game/Online/Spectator/SpectatorClient.cs | 12 ++++++++++++ 3 files changed, 20 insertions(+) diff --git a/osu.Game/Online/Spectator/ISpectatorClient.cs b/osu.Game/Online/Spectator/ISpectatorClient.cs index ccba280001..605ebc4ef0 100644 --- a/osu.Game/Online/Spectator/ISpectatorClient.cs +++ b/osu.Game/Online/Spectator/ISpectatorClient.cs @@ -32,5 +32,12 @@ namespace osu.Game.Online.Spectator /// The user. /// The frame data. Task UserSentFrames(int userId, FrameDataBundle data); + + /// + /// Signals that a user's submitted score was fully processed. + /// + /// The ID of the user who achieved the score. + /// The ID of the score. + Task UserScoreProcessed(int userId, long scoreId); } } diff --git a/osu.Game/Online/Spectator/OnlineSpectatorClient.cs b/osu.Game/Online/Spectator/OnlineSpectatorClient.cs index 01b775549e..3118e05053 100644 --- a/osu.Game/Online/Spectator/OnlineSpectatorClient.cs +++ b/osu.Game/Online/Spectator/OnlineSpectatorClient.cs @@ -41,6 +41,7 @@ namespace osu.Game.Online.Spectator connection.On(nameof(ISpectatorClient.UserBeganPlaying), ((ISpectatorClient)this).UserBeganPlaying); connection.On(nameof(ISpectatorClient.UserSentFrames), ((ISpectatorClient)this).UserSentFrames); connection.On(nameof(ISpectatorClient.UserFinishedPlaying), ((ISpectatorClient)this).UserFinishedPlaying); + connection.On(nameof(ISpectatorClient.UserScoreProcessed), ((ISpectatorClient)this).UserScoreProcessed); }; IsConnected.BindTo(connector.IsConnected); diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index fce61c019b..b60cef2835 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -64,6 +64,11 @@ namespace osu.Game.Online.Spectator /// public virtual event Action? OnUserFinishedPlaying; + /// + /// Called whenever a user-submitted score has been fully processed. + /// + public virtual event Action? OnUserScoreProcessed; + /// /// A dictionary containing all users currently being watched, with the number of watching components for each user. /// @@ -160,6 +165,13 @@ namespace osu.Game.Online.Spectator return Task.CompletedTask; } + Task ISpectatorClient.UserScoreProcessed(int userId, long scoreId) + { + Schedule(() => OnUserScoreProcessed?.Invoke(userId, scoreId)); + + return Task.CompletedTask; + } + public void BeginPlaying(long? scoreToken, GameplayState state, Score score) { // This schedule is only here to match the one below in `EndPlaying`. From 19f66c806e7a7df51dee54d8ff935cdf0b96e5a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 21 Dec 2022 16:31:53 +0800 Subject: [PATCH 2651/2686] Fix language dropdown in settings not updating after changing language in first run dialog Closes #21744. --- .../Overlays/Settings/Sections/General/LanguageSettings.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs index a4ec919658..982cbec376 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs @@ -44,10 +44,13 @@ namespace osu.Game.Overlays.Settings.Sections.General }, }; - localisationParameters.BindValueChanged(p - => languageSelection.Current.Value = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, p.NewValue), true); + frameworkLocale.BindValueChanged(_ => updateSelection()); + localisationParameters.BindValueChanged(_ => updateSelection(), true); languageSelection.Current.BindValueChanged(val => frameworkLocale.Value = val.NewValue.ToCultureCode()); } + + private void updateSelection() => + languageSelection.Current.Value = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, localisationParameters.Value); } } From 3ec31a5f51762fc1d9ed81256bc40a13597cf04e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 21 Dec 2022 19:30:21 +0100 Subject: [PATCH 2652/2686] Fix language selector in first run dialog not updating after changing language in settings --- .../Overlays/FirstRunSetup/ScreenWelcome.cs | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs index f6133e3643..4af40e5ad6 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -87,18 +87,21 @@ namespace osu.Game.Overlays.FirstRunSetup }); frameworkLocale = frameworkConfig.GetBindable(FrameworkSetting.Locale); + frameworkLocale.BindValueChanged(_ => onLanguageChange()); localisationParameters = localisation.CurrentParameters.GetBoundCopy(); - localisationParameters.BindValueChanged(p => - { - var language = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, p.NewValue); + localisationParameters.BindValueChanged(_ => onLanguageChange(), true); + } - // Changing language may cause a short period of blocking the UI thread while the new glyphs are loaded. - // Scheduling ensures the button animation plays smoothly after any blocking operation completes. - // Note that a delay is required (the alternative would be a double-schedule; delay feels better). - updateSelectedDelegate?.Cancel(); - updateSelectedDelegate = Scheduler.AddDelayed(() => updateSelectedStates(language), 50); - }, true); + private void onLanguageChange() + { + var language = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, localisationParameters.Value); + + // Changing language may cause a short period of blocking the UI thread while the new glyphs are loaded. + // Scheduling ensures the button animation plays smoothly after any blocking operation completes. + // Note that a delay is required (the alternative would be a double-schedule; delay feels better). + updateSelectedDelegate?.Cancel(); + updateSelectedDelegate = Scheduler.AddDelayed(() => updateSelectedStates(language), 50); } private void updateSelectedStates(Language language) From 0a49c8c5d67b67c7148ba2ca9fe92c89bb070b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 21 Dec 2022 20:03:46 +0100 Subject: [PATCH 2653/2686] Add missing unsubscriptions in multiple mania components --- osu.Game.Rulesets.Mania/UI/Column.cs | 3 +++ osu.Game.Rulesets.Mania/UI/Stage.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 6a31fb3fda..10460f52fd 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -134,6 +134,9 @@ namespace osu.Game.Rulesets.Mania.UI protected override void Dispose(bool isDisposing) { + // must happen before children are disposed in base call to prevent illegal accesses to the hit explosion pool. + NewResult -= OnNewResult; + base.Dispose(isDisposing); if (skin != null) diff --git a/osu.Game.Rulesets.Mania/UI/Stage.cs b/osu.Game.Rulesets.Mania/UI/Stage.cs index fc38a96a35..c1d3e85bf1 100644 --- a/osu.Game.Rulesets.Mania/UI/Stage.cs +++ b/osu.Game.Rulesets.Mania/UI/Stage.cs @@ -156,6 +156,9 @@ namespace osu.Game.Rulesets.Mania.UI protected override void Dispose(bool isDisposing) { + // must happen before children are disposed in base call to prevent illegal accesses to the judgement pool. + NewResult -= OnNewResult; + base.Dispose(isDisposing); if (currentSkin != null) From 6948035a3cc89d6cba9ad7263e73f89d1f94aacc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 21 Dec 2022 21:59:46 +0100 Subject: [PATCH 2654/2686] Ensure score submission attempt completion before notifying spectator server when exiting play early When a `SubmittingPlayer` gameplay session ends with the successful completion of a beatmap, `PrepareScoreForResultsAsync()` ensures that the score submission request is sent to and responded to by osu-web before calling `ISpectatorClient.EndPlaying()`. While previously this was mostly an implementation detail, this becomes important when considering that more and more server-side flows (replay upload, notifying about score processing completion) hook into `EndPlaying()`, and assume that by the point that message arrives at osu-spectator-server, the score has already been submitted and has been assigned a score ID that corresponds to the score submission token. As it turns out, in the early-exit path (when the user exits the play midway through, retries, or just fails), the same ordering guarantees were not provided. The score's submission ran concurrently to the spectator client `EndPlaying()` call, therefore creating a network race. osu-server-spectator components that implciitly relied on the ordering provided by the happy path, could therefore fail to unmap the score submission token to a score ID. Note that as written, the osu-server-spectator replay upload flow is not really affected by this, as it self-corrects by essentially polling the database and trying to unmap the score submission token to a score ID for up to 30 seconds. However, this change would have the benefit of reducing the polls required in such cases to just one DB retrieval. --- osu.Game/Screens/Play/SubmittingPlayer.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/SubmittingPlayer.cs b/osu.Game/Screens/Play/SubmittingPlayer.cs index 1eec71f33a..5fa6508a31 100644 --- a/osu.Game/Screens/Play/SubmittingPlayer.cs +++ b/osu.Game/Screens/Play/SubmittingPlayer.cs @@ -13,6 +13,7 @@ using osu.Framework.Screens; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Online.API; +using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; @@ -158,8 +159,11 @@ namespace osu.Game.Screens.Play if (LoadedBeatmapSuccessfully) { - submitScore(Score.DeepClone()); - spectatorClient.EndPlaying(GameplayState); + Task.Run(async () => + { + await submitScore(Score.DeepClone()).ConfigureAwait(false); + spectatorClient.EndPlaying(GameplayState); + }).FireAndForget(); } return exiting; From f5b3988dd2bd7ccc82437e191592d89650d34a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Dec 2022 08:01:52 +0100 Subject: [PATCH 2655/2686] Add data structure for delivering statistics updates --- osu.Game/Online/Solo/SoloStatisticsUpdate.cs | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 osu.Game/Online/Solo/SoloStatisticsUpdate.cs diff --git a/osu.Game/Online/Solo/SoloStatisticsUpdate.cs b/osu.Game/Online/Solo/SoloStatisticsUpdate.cs new file mode 100644 index 0000000000..cb9dac97c7 --- /dev/null +++ b/osu.Game/Online/Solo/SoloStatisticsUpdate.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.Game.Scoring; +using osu.Game.Users; + +namespace osu.Game.Online.Solo +{ + /// + /// Contains data about the change in a user's profile statistics after completing a score. + /// + public class SoloStatisticsUpdate + { + /// + /// The score set by the user that triggered the update. + /// + public ScoreInfo Score { get; } + + /// + /// The user's profile statistics prior to the score being set. + /// + public UserStatistics Before { get; } + + /// + /// The user's profile statistics after the score was set. + /// + public UserStatistics After { get; } + + /// + /// Creates a new . + /// + /// The score set by the user that triggered the update. + /// The user's profile statistics prior to the score being set. + /// The user's profile statistics after the score was set. + public SoloStatisticsUpdate(ScoreInfo score, UserStatistics before, UserStatistics after) + { + Score = score; + Before = before; + After = after; + } + } +} From 422fdd8ae5a3f8deae62b788fb41d84f8e8608e8 Mon Sep 17 00:00:00 2001 From: Flutterish Date: Thu, 22 Dec 2022 16:56:27 +0100 Subject: [PATCH 2656/2686] dont post notifications from custom log targets --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index a0a45e18a8..af58a72ae8 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1040,7 +1040,7 @@ namespace osu.Game Logger.NewEntry += entry => { - if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database) return; + if (entry.Level < LogLevel.Important || entry.Target is null or > LoggingTarget.Database) return; Debug.Assert(entry.Target != null); From 5df440e20eb8389e14e029879af28d1bab630a94 Mon Sep 17 00:00:00 2001 From: Flutterish Date: Thu, 22 Dec 2022 17:27:55 +0100 Subject: [PATCH 2657/2686] dont use `is..or` syntax --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index af58a72ae8..b5e1023ac6 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1040,7 +1040,7 @@ namespace osu.Game Logger.NewEntry += entry => { - if (entry.Level < LogLevel.Important || entry.Target is null or > LoggingTarget.Database) return; + if (entry.Level < LogLevel.Important || entry.Target == null || entry.Target > LoggingTarget.Database) return; Debug.Assert(entry.Target != null); From 8be6350c019bddbb8064d73aa013ffbc71e58c09 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 22 Dec 2022 20:07:53 +0300 Subject: [PATCH 2658/2686] Remove no longer necessary assert --- osu.Game/OsuGame.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b5e1023ac6..de9a009f44 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1040,9 +1040,7 @@ namespace osu.Game Logger.NewEntry += entry => { - if (entry.Level < LogLevel.Important || entry.Target == null || entry.Target > LoggingTarget.Database) return; - - Debug.Assert(entry.Target != null); + if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database || entry.Target == null) return; const int short_term_display_limit = 3; From ac872fac9e562b4e4cba19ecf5a8bc31ba269f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Dec 2022 09:04:53 +0100 Subject: [PATCH 2659/2686] Implement solo statistics watcher --- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 osu.Game/Online/Solo/SoloStatisticsWatcher.cs diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs new file mode 100644 index 0000000000..197ad410a9 --- /dev/null +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -0,0 +1,140 @@ +// 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.Diagnostics; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; +using osu.Framework.Graphics; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Spectator; +using osu.Game.Scoring; +using osu.Game.Users; + +namespace osu.Game.Online.Solo +{ + /// + /// A persistent component that binds to the spectator server and API in order to deliver updates about the logged in user's gameplay statistics. + /// + public partial class SoloStatisticsWatcher : Component + { + [Resolved] + private SpectatorClient spectatorClient { get; set; } = null!; + + [Resolved] + private IAPIProvider api { get; set; } = null!; + + private readonly Dictionary callbacks = new Dictionary(); + private readonly HashSet scoresWithoutCallback = new HashSet(); + + private readonly Dictionary latestStatistics = new Dictionary(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + api.LocalUser.BindValueChanged(user => onUserChanged(user.NewValue), true); + spectatorClient.OnUserScoreProcessed += userScoreProcessed; + } + + /// + /// Registers for a user statistics update after the given has been processed server-side. + /// + /// The score to listen for the statistics update for. + /// The callback to be invoked once the statistics update has been prepared. + public void RegisterForStatisticsUpdateAfter(ScoreInfo score, Action onUpdateReady) => Schedule(() => + { + if (!api.IsLoggedIn) + return; + + var callback = new StatisticsUpdateCallback(score, onUpdateReady); + + if (scoresWithoutCallback.Remove(score.OnlineID)) + { + requestStatisticsUpdate(api.LocalUser.Value.Id, callback); + return; + } + + callbacks[score.OnlineID] = callback; + }); + + private void onUserChanged(APIUser? localUser) => Schedule(() => + { + callbacks.Clear(); + scoresWithoutCallback.Clear(); + latestStatistics.Clear(); + + if (!api.IsLoggedIn) + return; + + Debug.Assert(localUser != null && localUser.OnlineID > 1); + + var userRequest = new GetUsersRequest(new[] { localUser.OnlineID }); + userRequest.Success += response => Schedule(() => + { + foreach (var rulesetStats in response.Users.Single().RulesetsStatistics) + latestStatistics.Add(rulesetStats.Key, rulesetStats.Value); + }); + api.Queue(userRequest); + }); + + private void userScoreProcessed(int userId, long scoreId) + { + if (userId != api.LocalUser.Value?.OnlineID) + return; + + if (!callbacks.TryGetValue(scoreId, out var callback)) + { + scoresWithoutCallback.Add(scoreId); + return; + } + + requestStatisticsUpdate(userId, callback); + callbacks.Remove(scoreId); + } + + private void requestStatisticsUpdate(int userId, StatisticsUpdateCallback callback) + { + var request = new GetUserRequest(userId, callback.Score.Ruleset); + request.Success += user => Schedule(() => dispatchStatisticsUpdate(callback, user.Statistics)); + api.Queue(request); + } + + private void dispatchStatisticsUpdate(StatisticsUpdateCallback callback, UserStatistics updatedStatistics) + { + string rulesetName = callback.Score.Ruleset.ShortName; + + if (!latestStatistics.TryGetValue(rulesetName, out var latestRulesetStatistics)) + return; + + var update = new SoloStatisticsUpdate(callback.Score, latestRulesetStatistics, updatedStatistics); + callback.OnUpdateReady.Invoke(update); + + latestStatistics[rulesetName] = updatedStatistics; + } + + protected override void Dispose(bool isDisposing) + { + if (spectatorClient.IsNotNull()) + spectatorClient.OnUserScoreProcessed -= userScoreProcessed; + + base.Dispose(isDisposing); + } + + private class StatisticsUpdateCallback + { + public ScoreInfo Score { get; } + public Action OnUpdateReady { get; } + + public StatisticsUpdateCallback(ScoreInfo score, Action onUpdateReady) + { + Score = score; + OnUpdateReady = onUpdateReady; + } + } + } +} From 722cf48614fb696a8f9f8ff01512da826edeac90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Dec 2022 10:14:37 +0100 Subject: [PATCH 2660/2686] Add test coverage for statistics watcher --- .../Online/TestSceneSoloStatisticsWatcher.cs | 241 ++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs new file mode 100644 index 0000000000..0797113ca1 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs @@ -0,0 +1,241 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Testing; +using osu.Game.Models; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Solo; +using osu.Game.Online.Spectator; +using osu.Game.Rulesets.Osu; +using osu.Game.Scoring; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.Online +{ + [HeadlessTest] + public partial class TestSceneSoloStatisticsWatcher : OsuTestScene + { + protected override bool UseOnlineAPI => false; + + private SoloStatisticsWatcher watcher = null!; + + [Resolved] + private SpectatorClient spectatorClient { get; set; } = null!; + + private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; + + private Action? handleGetUsersRequest; + private Action? handleGetUserRequest; + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("set up request handling", () => + { + handleGetUserRequest = null; + handleGetUsersRequest = null; + + dummyAPI.HandleRequest = request => + { + switch (request) + { + case GetUsersRequest getUsersRequest: + handleGetUsersRequest?.Invoke(getUsersRequest); + return true; + + case GetUserRequest getUserRequest: + handleGetUserRequest?.Invoke(getUserRequest); + return true; + + default: + return false; + } + }; + }); + + AddStep("create watcher", () => + { + Child = watcher = new SoloStatisticsWatcher(); + }); + } + + [Test] + public void TestStatisticsUpdateFiredAfterRegistrationAddedAndScoreProcessed() + { + AddStep("fetch initial stats", () => + { + handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1234)); + dummyAPI.LocalUser.Value = new APIUser { Id = 1234 }; + }); + + SoloStatisticsUpdate? update = null; + + AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( + new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) + { + Ruleset = new OsuRuleset().RulesetInfo, + OnlineID = 5678 + }, + receivedUpdate => update = receivedUpdate)); + + AddStep("feign score processing", + () => handleGetUserRequest = + req => req.TriggerSuccess(createIncrementalUserResponse(1234, 5_000_000))); + + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1234, 5678)); + AddUntilStep("update received", () => update != null); + AddAssert("values before are correct", () => update?.Before.TotalScore, () => Is.EqualTo(4_000_000)); + AddAssert("values after are correct", () => update?.After.TotalScore, () => Is.EqualTo(5_000_000)); + } + + [Test] + public void TestStatisticsUpdateFiredAfterScoreProcessedAndRegistrationAdded() + { + AddStep("fetch initial stats", () => + { + handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1235)); + dummyAPI.LocalUser.Value = new APIUser { Id = 1235 }; + }); + + AddStep("feign score processing", + () => handleGetUserRequest = + req => req.TriggerSuccess(createIncrementalUserResponse(1235, 5_000_000))); + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1235, 5678)); + + SoloStatisticsUpdate? update = null; + + // note ordering - this test checks that even if the registration is late, it will receive data. + AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( + new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) + { + Ruleset = new OsuRuleset().RulesetInfo, + OnlineID = 5678 + }, + receivedUpdate => update = receivedUpdate)); + AddUntilStep("update received", () => update != null); + AddAssert("values before are correct", () => update?.Before.TotalScore, () => Is.EqualTo(4_000_000)); + AddAssert("values after are correct", () => update?.After.TotalScore, () => Is.EqualTo(5_000_000)); + } + + [Test] + public void TestStatisticsUpdateNotFiredIfUserLoggedOut() + { + AddStep("fetch initial stats", () => + { + handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1236)); + dummyAPI.LocalUser.Value = new APIUser { Id = 1236 }; + }); + + SoloStatisticsUpdate? update = null; + + AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( + new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) + { + Ruleset = new OsuRuleset().RulesetInfo, + OnlineID = 5678 + }, + receivedUpdate => update = receivedUpdate)); + + AddStep("feign score processing", + () => handleGetUserRequest = + req => req.TriggerSuccess(createIncrementalUserResponse(1236, 5_000_000))); + + AddStep("log out user", () => dummyAPI.Logout()); + + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1236, 5678)); + AddWaitStep("wait a bit", 5); + AddAssert("update not received", () => update == null); + } + + [Test] + public void TestStatisticsUpdateNotFiredIfAnotherUserLoggedIn() + { + AddStep("fetch initial stats", () => + { + handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1237)); + dummyAPI.LocalUser.Value = new APIUser { Id = 1237 }; + }); + + SoloStatisticsUpdate? update = null; + + AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( + new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) + { + Ruleset = new OsuRuleset().RulesetInfo, + OnlineID = 5678 + }, + receivedUpdate => update = receivedUpdate)); + + AddStep("feign score processing", + () => handleGetUserRequest = + req => req.TriggerSuccess(createIncrementalUserResponse(1237, 5_000_000))); + + AddStep("log out user", () => dummyAPI.LocalUser.Value = new APIUser { Id = 5555 }); + + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1237, 5678)); + AddWaitStep("wait a bit", 5); + AddAssert("update not received", () => update == null); + } + + [Test] + public void TestStatisticsUpdateNotFiredIfScoreIdDoesNotMatch() + { + AddStep("fetch initial stats", () => + { + handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1238)); + dummyAPI.LocalUser.Value = new APIUser { Id = 1238 }; + }); + + SoloStatisticsUpdate? update = null; + + AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( + new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) + { + Ruleset = new OsuRuleset().RulesetInfo, + OnlineID = 5678 + }, + receivedUpdate => update = receivedUpdate)); + + AddStep("feign score processing", + () => handleGetUserRequest = + req => req.TriggerSuccess(createIncrementalUserResponse(1238, 5_000_000))); + + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1238, 9012)); + AddWaitStep("wait a bit", 5); + AddAssert("update not received", () => update == null); + } + + private GetUsersResponse createInitialUserResponse(int userId) => new GetUsersResponse + { + Users = new List + { + new APIUser + { + Id = userId, + RulesetsStatistics = new Dictionary + { + ["osu"] = new UserStatistics { TotalScore = 4_000_000 }, + ["taiko"] = new UserStatistics { TotalScore = 3_000_000 }, + ["fruits"] = new UserStatistics { TotalScore = 2_000_000 }, + ["mania"] = new UserStatistics { TotalScore = 1_000_000 } + } + } + } + }; + + private APIUser createIncrementalUserResponse(int userId, long totalScore) => new APIUser + { + Id = userId, + Statistics = new UserStatistics + { + TotalScore = totalScore + } + }; + } +} From 48dc2332fd5bc60d977897e3a4d6477dc8b0deec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Dec 2022 11:10:33 +0100 Subject: [PATCH 2661/2686] Refactor test to be easier to work with --- .../Online/TestSceneSoloStatisticsWatcher.cs | 241 +++++++++--------- .../Online/API/Requests/GetUsersRequest.cs | 6 +- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 2 +- 3 files changed, 130 insertions(+), 119 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs index 0797113ca1..008d54be63 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Testing; @@ -12,6 +13,7 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Solo; using osu.Game.Online.Spectator; +using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Scoring; using osu.Game.Users; @@ -33,9 +35,12 @@ namespace osu.Game.Tests.Visual.Online private Action? handleGetUsersRequest; private Action? handleGetUserRequest; + private readonly Dictionary<(int userId, string rulesetName), UserStatistics> serverSideStatistics = new Dictionary<(int userId, string rulesetName), UserStatistics>(); + [SetUpSteps] public void SetUpSteps() { + AddStep("clear server-side stats", () => serverSideStatistics.Clear()); AddStep("set up request handling", () => { handleGetUserRequest = null; @@ -46,11 +51,52 @@ namespace osu.Game.Tests.Visual.Online switch (request) { case GetUsersRequest getUsersRequest: - handleGetUsersRequest?.Invoke(getUsersRequest); + if (handleGetUsersRequest != null) + { + handleGetUsersRequest?.Invoke(getUsersRequest); + } + else + { + int userId = getUsersRequest.UserIds.Single(); + var response = new GetUsersResponse + { + Users = new List + { + new APIUser + { + Id = userId, + RulesetsStatistics = new Dictionary + { + ["osu"] = tryGetStatistics(userId, "osu"), + ["taiko"] = tryGetStatistics(userId, "taiko"), + ["fruits"] = tryGetStatistics(userId, "fruits"), + ["mania"] = tryGetStatistics(userId, "mania"), + } + } + } + }; + getUsersRequest.TriggerSuccess(response); + } + return true; case GetUserRequest getUserRequest: - handleGetUserRequest?.Invoke(getUserRequest); + if (handleGetUserRequest != null) + { + handleGetUserRequest.Invoke(getUserRequest); + } + else + { + int userId = int.Parse(getUserRequest.Lookup); + string rulesetName = getUserRequest.Ruleset.ShortName; + var response = new APIUser + { + Id = userId, + Statistics = tryGetStatistics(userId, rulesetName) + }; + getUserRequest.TriggerSuccess(response); + } + return true; default: @@ -65,120 +111,90 @@ namespace osu.Game.Tests.Visual.Online }); } + private UserStatistics tryGetStatistics(int userId, string rulesetName) + => serverSideStatistics.TryGetValue((userId, rulesetName), out var stats) ? stats : new UserStatistics(); + [Test] public void TestStatisticsUpdateFiredAfterRegistrationAddedAndScoreProcessed() { - AddStep("fetch initial stats", () => - { - handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1234)); - dummyAPI.LocalUser.Value = new APIUser { Id = 1234 }; - }); + int userId = getUserId(); + long scoreId = getScoreId(); + setUpUser(userId); + + var ruleset = new OsuRuleset().RulesetInfo; SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) - { - Ruleset = new OsuRuleset().RulesetInfo, - OnlineID = 5678 - }, - receivedUpdate => update = receivedUpdate)); + feignScoreProcessing(userId, ruleset, 5_000_000); - AddStep("feign score processing", - () => handleGetUserRequest = - req => req.TriggerSuccess(createIncrementalUserResponse(1234, 5_000_000))); - - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1234, 5678)); + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId)); AddUntilStep("update received", () => update != null); - AddAssert("values before are correct", () => update?.Before.TotalScore, () => Is.EqualTo(4_000_000)); - AddAssert("values after are correct", () => update?.After.TotalScore, () => Is.EqualTo(5_000_000)); + AddAssert("values before are correct", () => update!.Before.TotalScore, () => Is.EqualTo(4_000_000)); + AddAssert("values after are correct", () => update!.After.TotalScore, () => Is.EqualTo(5_000_000)); } [Test] public void TestStatisticsUpdateFiredAfterScoreProcessedAndRegistrationAdded() { - AddStep("fetch initial stats", () => - { - handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1235)); - dummyAPI.LocalUser.Value = new APIUser { Id = 1235 }; - }); + int userId = getUserId(); + setUpUser(userId); - AddStep("feign score processing", - () => handleGetUserRequest = - req => req.TriggerSuccess(createIncrementalUserResponse(1235, 5_000_000))); - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1235, 5678)); + long scoreId = getScoreId(); + var ruleset = new OsuRuleset().RulesetInfo; + + // note ordering - in this test processing completes *before* the registration is added. + feignScoreProcessing(userId, ruleset, 5_000_000); SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - // note ordering - this test checks that even if the registration is late, it will receive data. - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) - { - Ruleset = new OsuRuleset().RulesetInfo, - OnlineID = 5678 - }, - receivedUpdate => update = receivedUpdate)); + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId)); AddUntilStep("update received", () => update != null); - AddAssert("values before are correct", () => update?.Before.TotalScore, () => Is.EqualTo(4_000_000)); - AddAssert("values after are correct", () => update?.After.TotalScore, () => Is.EqualTo(5_000_000)); + AddAssert("values before are correct", () => update!.Before.TotalScore, () => Is.EqualTo(4_000_000)); + AddAssert("values after are correct", () => update!.After.TotalScore, () => Is.EqualTo(5_000_000)); } [Test] public void TestStatisticsUpdateNotFiredIfUserLoggedOut() { - AddStep("fetch initial stats", () => - { - handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1236)); - dummyAPI.LocalUser.Value = new APIUser { Id = 1236 }; - }); + int userId = getUserId(); + setUpUser(userId); + + long scoreId = getScoreId(); + var ruleset = new OsuRuleset().RulesetInfo; SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) - { - Ruleset = new OsuRuleset().RulesetInfo, - OnlineID = 5678 - }, - receivedUpdate => update = receivedUpdate)); - - AddStep("feign score processing", - () => handleGetUserRequest = - req => req.TriggerSuccess(createIncrementalUserResponse(1236, 5_000_000))); + feignScoreProcessing(userId, ruleset, 5_000_000); AddStep("log out user", () => dummyAPI.Logout()); - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1236, 5678)); + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId)); AddWaitStep("wait a bit", 5); AddAssert("update not received", () => update == null); + + AddStep("log in user", () => dummyAPI.Login("user", "password")); } [Test] public void TestStatisticsUpdateNotFiredIfAnotherUserLoggedIn() { - AddStep("fetch initial stats", () => - { - handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1237)); - dummyAPI.LocalUser.Value = new APIUser { Id = 1237 }; - }); + int userId = getUserId(); + setUpUser(userId); + + long scoreId = getScoreId(); + var ruleset = new OsuRuleset().RulesetInfo; SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) - { - Ruleset = new OsuRuleset().RulesetInfo, - OnlineID = 5678 - }, - receivedUpdate => update = receivedUpdate)); + feignScoreProcessing(userId, ruleset, 5_000_000); - AddStep("feign score processing", - () => handleGetUserRequest = - req => req.TriggerSuccess(createIncrementalUserResponse(1237, 5_000_000))); + AddStep("change user", () => dummyAPI.LocalUser.Value = new APIUser { Id = getUserId() }); - AddStep("log out user", () => dummyAPI.LocalUser.Value = new APIUser { Id = 5555 }); - - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1237, 5678)); + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, scoreId)); AddWaitStep("wait a bit", 5); AddAssert("update not received", () => update == null); } @@ -186,56 +202,51 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestStatisticsUpdateNotFiredIfScoreIdDoesNotMatch() { - AddStep("fetch initial stats", () => - { - handleGetUsersRequest = req => req.TriggerSuccess(createInitialUserResponse(1238)); - dummyAPI.LocalUser.Value = new APIUser { Id = 1238 }; - }); + int userId = getUserId(); + setUpUser(userId); + + long scoreId = getScoreId(); + var ruleset = new OsuRuleset().RulesetInfo; SoloStatisticsUpdate? update = null; + registerForUpdates(scoreId, ruleset, receivedUpdate => update = receivedUpdate); - AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( - new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) - { - Ruleset = new OsuRuleset().RulesetInfo, - OnlineID = 5678 - }, - receivedUpdate => update = receivedUpdate)); + feignScoreProcessing(userId, ruleset, 5_000_000); - AddStep("feign score processing", - () => handleGetUserRequest = - req => req.TriggerSuccess(createIncrementalUserResponse(1238, 5_000_000))); - - AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(1238, 9012)); + AddStep("signal another score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, getScoreId())); AddWaitStep("wait a bit", 5); AddAssert("update not received", () => update == null); } - private GetUsersResponse createInitialUserResponse(int userId) => new GetUsersResponse - { - Users = new List - { - new APIUser - { - Id = userId, - RulesetsStatistics = new Dictionary - { - ["osu"] = new UserStatistics { TotalScore = 4_000_000 }, - ["taiko"] = new UserStatistics { TotalScore = 3_000_000 }, - ["fruits"] = new UserStatistics { TotalScore = 2_000_000 }, - ["mania"] = new UserStatistics { TotalScore = 1_000_000 } - } - } - } - }; + private int nextUserId = 2000; + private long nextScoreId = 50000; - private APIUser createIncrementalUserResponse(int userId, long totalScore) => new APIUser + private int getUserId() => ++nextUserId; + private long getScoreId() => ++nextScoreId; + + private void setUpUser(int userId) { - Id = userId, - Statistics = new UserStatistics + AddStep("fetch initial stats", () => { - TotalScore = totalScore - } - }; + serverSideStatistics[(userId, "osu")] = new UserStatistics { TotalScore = 4_000_000 }; + serverSideStatistics[(userId, "taiko")] = new UserStatistics { TotalScore = 3_000_000 }; + serverSideStatistics[(userId, "fruits")] = new UserStatistics { TotalScore = 2_000_000 }; + serverSideStatistics[(userId, "mania")] = new UserStatistics { TotalScore = 1_000_000 }; + + dummyAPI.LocalUser.Value = new APIUser { Id = userId }; + }); + } + + private void registerForUpdates(long scoreId, RulesetInfo rulesetInfo, Action onUpdateReady) => + AddStep("register for updates", () => watcher.RegisterForStatisticsUpdateAfter( + new ScoreInfo(Beatmap.Value.BeatmapInfo, new OsuRuleset().RulesetInfo, new RealmUser()) + { + Ruleset = rulesetInfo, + OnlineID = scoreId + }, + onUpdateReady)); + + private void feignScoreProcessing(int userId, RulesetInfo rulesetInfo, long newTotalScore) + => AddStep("feign score processing", () => serverSideStatistics[(userId, rulesetInfo.ShortName)] = new UserStatistics { TotalScore = newTotalScore }); } } diff --git a/osu.Game/Online/API/Requests/GetUsersRequest.cs b/osu.Game/Online/API/Requests/GetUsersRequest.cs index bbaf241384..b57bb215aa 100644 --- a/osu.Game/Online/API/Requests/GetUsersRequest.cs +++ b/osu.Game/Online/API/Requests/GetUsersRequest.cs @@ -9,7 +9,7 @@ namespace osu.Game.Online.API.Requests { public class GetUsersRequest : APIRequest { - private readonly int[] userIds; + public readonly int[] UserIds; private const int max_ids_per_request = 50; @@ -18,9 +18,9 @@ namespace osu.Game.Online.API.Requests if (userIds.Length > max_ids_per_request) throw new ArgumentException($"{nameof(GetUsersRequest)} calls only support up to {max_ids_per_request} IDs at once"); - this.userIds = userIds; + UserIds = userIds; } - protected override string Target => "users/?ids[]=" + string.Join("&ids[]=", userIds); + protected override string Target => "users/?ids[]=" + string.Join("&ids[]=", UserIds); } } diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 197ad410a9..1befbe2af0 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -71,7 +71,7 @@ namespace osu.Game.Online.Solo if (!api.IsLoggedIn) return; - Debug.Assert(localUser != null && localUser.OnlineID > 1); + Debug.Assert(localUser != null); var userRequest = new GetUsersRequest(new[] { localUser.OnlineID }); userRequest.Success += response => Schedule(() => From fa2d50fe3164612e17bedb6d1892294cc9af0a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Dec 2022 19:29:51 +0100 Subject: [PATCH 2662/2686] Limit tracking unhandled scores to just the last one --- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 1befbe2af0..48f39504a3 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -29,7 +29,7 @@ namespace osu.Game.Online.Solo private IAPIProvider api { get; set; } = null!; private readonly Dictionary callbacks = new Dictionary(); - private readonly HashSet scoresWithoutCallback = new HashSet(); + private long? lastProcessedScoreId; private readonly Dictionary latestStatistics = new Dictionary(); @@ -53,7 +53,7 @@ namespace osu.Game.Online.Solo var callback = new StatisticsUpdateCallback(score, onUpdateReady); - if (scoresWithoutCallback.Remove(score.OnlineID)) + if (lastProcessedScoreId == score.OnlineID) { requestStatisticsUpdate(api.LocalUser.Value.Id, callback); return; @@ -65,7 +65,7 @@ namespace osu.Game.Online.Solo private void onUserChanged(APIUser? localUser) => Schedule(() => { callbacks.Clear(); - scoresWithoutCallback.Clear(); + lastProcessedScoreId = null; latestStatistics.Clear(); if (!api.IsLoggedIn) @@ -87,11 +87,10 @@ namespace osu.Game.Online.Solo if (userId != api.LocalUser.Value?.OnlineID) return; + lastProcessedScoreId = scoreId; + if (!callbacks.TryGetValue(scoreId, out var callback)) - { - scoresWithoutCallback.Add(scoreId); return; - } requestStatisticsUpdate(userId, callback); callbacks.Remove(scoreId); From 27afeb9e301d0392be3a22155643389468c04448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 22 Dec 2022 19:46:41 +0100 Subject: [PATCH 2663/2686] Add test coverage of merging ignored score updates --- .../Online/TestSceneSoloStatisticsWatcher.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs index 008d54be63..b1badc6282 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneSoloStatisticsWatcher.cs @@ -218,6 +218,34 @@ namespace osu.Game.Tests.Visual.Online AddAssert("update not received", () => update == null); } + // the behaviour exercised in this test may not be final, it is mostly assumed for simplicity. + // in the long run we may want each score's update to be entirely isolated from others, rather than have prior unobserved updates merge into the latest. + [Test] + public void TestIgnoredScoreUpdateIsMergedIntoNextOne() + { + int userId = getUserId(); + setUpUser(userId); + + long firstScoreId = getScoreId(); + var ruleset = new OsuRuleset().RulesetInfo; + + feignScoreProcessing(userId, ruleset, 5_000_000); + + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, firstScoreId)); + + long secondScoreId = getScoreId(); + + feignScoreProcessing(userId, ruleset, 6_000_000); + + SoloStatisticsUpdate? update = null; + registerForUpdates(secondScoreId, ruleset, receivedUpdate => update = receivedUpdate); + + AddStep("signal score processed", () => ((ISpectatorClient)spectatorClient).UserScoreProcessed(userId, secondScoreId)); + AddUntilStep("update received", () => update != null); + AddAssert("values before are correct", () => update!.Before.TotalScore, () => Is.EqualTo(4_000_000)); + AddAssert("values after are correct", () => update!.After.TotalScore, () => Is.EqualTo(6_000_000)); + } + private int nextUserId = 2000; private long nextScoreId = 50000; From 08d2fbeb8e99cc2ed2b658f1ce1d30f859108c2b Mon Sep 17 00:00:00 2001 From: Berkan Diler Date: Thu, 22 Dec 2022 21:27:59 +0100 Subject: [PATCH 2664/2686] Use new ArgumentNullException.ThrowIfNull throw-helper API --- .../Beatmaps/Patterns/Legacy/PatternGenerator.cs | 4 ++-- .../Beatmaps/Patterns/PatternGenerator.cs | 6 +++--- osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs | 3 +-- osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs | 3 +-- osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs | 4 ++-- osu.Game.Tournament/Components/TournamentBeatmapPanel.cs | 2 +- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 3 +-- osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs | 3 +-- osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs | 3 +-- osu.Game/Beatmaps/Formats/Decoder.cs | 3 +-- osu.Game/Graphics/Containers/LogoTrackingContainer.cs | 3 +-- osu.Game/Graphics/UserInterface/Nub.cs | 3 +-- osu.Game/IO/FileAbstraction/StreamFileAbstraction.cs | 3 +-- osu.Game/Online/Chat/ChannelManager.cs | 6 ++---- osu.Game/Overlays/ChangelogOverlay.cs | 6 +++--- osu.Game/Overlays/OnScreenDisplay.cs | 4 ++-- osu.Game/Overlays/Volume/MuteButton.cs | 3 +-- osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs | 3 +-- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 3 +-- osu.Game/Rulesets/UI/JudgementContainer.cs | 2 +- osu.Game/Scoring/ScoreImporter.cs | 4 ++-- osu.Game/Screens/Menu/LogoVisualisation.cs | 2 +- osu.Game/Screens/Play/HUD/ModDisplay.cs | 3 +-- osu.Game/Screens/Play/HUD/ModFlowDisplay.cs | 3 +-- osu.Game/Screens/Play/KeyCounterDisplay.cs | 2 +- osu.Game/Users/Drawables/DrawableFlag.cs | 3 +-- osu.Game/Users/UserPanel.cs | 3 +-- 27 files changed, 36 insertions(+), 54 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs index 308238d87a..77f93b4ef9 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/PatternGenerator.cs @@ -35,8 +35,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy protected PatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap) : base(hitObject, beatmap, previousPattern) { - if (random == null) throw new ArgumentNullException(nameof(random)); - if (originalBeatmap == null) throw new ArgumentNullException(nameof(originalBeatmap)); + ArgumentNullException.ThrowIfNull(random); + ArgumentNullException.ThrowIfNull(originalBeatmap); Random = random; OriginalBeatmap = originalBeatmap; diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs index b2e89c3410..931673f337 100644 --- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs +++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/PatternGenerator.cs @@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns protected PatternGenerator(HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern) { - if (hitObject == null) throw new ArgumentNullException(nameof(hitObject)); - if (beatmap == null) throw new ArgumentNullException(nameof(beatmap)); - if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern)); + ArgumentNullException.ThrowIfNull(hitObject); + ArgumentNullException.ThrowIfNull(beatmap); + ArgumentNullException.ThrowIfNull(previousPattern); HitObject = hitObject; Beatmap = beatmap; diff --git a/osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs b/osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs index 1a67117c03..4d93826240 100644 --- a/osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs +++ b/osu.Game.Rulesets.Mania/MathUtils/LegacySortHelper.cs @@ -22,8 +22,7 @@ namespace osu.Game.Rulesets.Mania.MathUtils public static void Sort(T[] keys, IComparer comparer) { - if (keys == null) - throw new ArgumentNullException(nameof(keys)); + ArgumentNullException.ThrowIfNull(keys); if (keys.Length == 0) return; diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 01e9926ad7..e3ebadc836 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -29,8 +29,7 @@ namespace osu.Game.Rulesets.Mania.UI public ManiaPlayfield(List stageDefinitions) { - if (stageDefinitions == null) - throw new ArgumentNullException(nameof(stageDefinitions)); + ArgumentNullException.ThrowIfNull(stageDefinitions); if (stageDefinitions.Count <= 0) throw new ArgumentException("Can't have zero or fewer stages."); diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs index 2f62968029..74e16f7e0b 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs @@ -84,8 +84,8 @@ namespace osu.Game.Rulesets.Osu.Replays { public int Compare(ReplayFrame? f1, ReplayFrame? f2) { - if (f1 == null) throw new ArgumentNullException(nameof(f1)); - if (f2 == null) throw new ArgumentNullException(nameof(f2)); + ArgumentNullException.ThrowIfNull(f1); + ArgumentNullException.ThrowIfNull(f2); return f1.Time.CompareTo(f2.Time); } diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs index 52769321a9..1157b50377 100644 --- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs +++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs @@ -32,7 +32,7 @@ namespace osu.Game.Tournament.Components public TournamentBeatmapPanel(TournamentBeatmap beatmap, string mod = null) { - if (beatmap == null) throw new ArgumentNullException(nameof(beatmap)); + ArgumentNullException.ThrowIfNull(beatmap); Beatmap = beatmap; this.mod = mod; diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 55119c800a..29b7191ecf 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -211,8 +211,7 @@ namespace osu.Game.Beatmaps.ControlPoints public static T BinarySearch(IReadOnlyList list, double time) where T : class, IControlPoint { - if (list == null) - throw new ArgumentNullException(nameof(list)); + ArgumentNullException.ThrowIfNull(list); if (list.Count == 0) return null; diff --git a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs index d31a7ae2fe..767504fcb1 100644 --- a/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs +++ b/osu.Game/Beatmaps/Drawables/BeatmapBackgroundSprite.cs @@ -15,8 +15,7 @@ namespace osu.Game.Beatmaps.Drawables public BeatmapBackgroundSprite(IWorkingBeatmap working) { - if (working == null) - throw new ArgumentNullException(nameof(working)); + ArgumentNullException.ThrowIfNull(working); this.working = working; } diff --git a/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs index e4ffc1d553..fc7c14e734 100644 --- a/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs +++ b/osu.Game/Beatmaps/Drawables/OnlineBeatmapSetCover.cs @@ -18,8 +18,7 @@ namespace osu.Game.Beatmaps.Drawables public OnlineBeatmapSetCover(IBeatmapSetOnlineInfo set, BeatmapSetCoverType type = BeatmapSetCoverType.Cover) { - if (set == null) - throw new ArgumentNullException(nameof(set)); + ArgumentNullException.ThrowIfNull(set); this.set = set; this.type = type; diff --git a/osu.Game/Beatmaps/Formats/Decoder.cs b/osu.Game/Beatmaps/Formats/Decoder.cs index ca1bcc97fd..4f0f11d053 100644 --- a/osu.Game/Beatmaps/Formats/Decoder.cs +++ b/osu.Game/Beatmaps/Formats/Decoder.cs @@ -57,8 +57,7 @@ namespace osu.Game.Beatmaps.Formats public static Decoder GetDecoder(LineBufferedReader stream) where T : new() { - if (stream == null) - throw new ArgumentNullException(nameof(stream)); + ArgumentNullException.ThrowIfNull(stream); if (!decoders.TryGetValue(typeof(T), out var typedDecoders)) throw new IOException(@"Unknown decoder type"); diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs index 735b8b4e7d..984d60d35e 100644 --- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs +++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs @@ -36,8 +36,7 @@ namespace osu.Game.Graphics.Containers /// The easing type of the initial transform. public void StartTracking(OsuLogo logo, double duration = 0, Easing easing = Easing.None) { - if (logo == null) - throw new ArgumentNullException(nameof(logo)); + ArgumentNullException.ThrowIfNull(logo); if (logo.IsTracking && Logo == null) throw new InvalidOperationException($"Cannot track an instance of {typeof(OsuLogo)} to multiple {typeof(LogoTrackingContainer)}s"); diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 4f56872f42..7921dcf593 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -114,8 +114,7 @@ namespace osu.Game.Graphics.UserInterface get => current; set { - if (value == null) - throw new ArgumentNullException(nameof(value)); + ArgumentNullException.ThrowIfNull(value); current.UnbindBindings(); current.BindTo(value); diff --git a/osu.Game/IO/FileAbstraction/StreamFileAbstraction.cs b/osu.Game/IO/FileAbstraction/StreamFileAbstraction.cs index 8e6c3e5f3d..d47f936eb3 100644 --- a/osu.Game/IO/FileAbstraction/StreamFileAbstraction.cs +++ b/osu.Game/IO/FileAbstraction/StreamFileAbstraction.cs @@ -23,8 +23,7 @@ namespace osu.Game.IO.FileAbstraction public void CloseStream(Stream stream) { - if (stream == null) - throw new ArgumentNullException(nameof(stream)); + ArgumentNullException.ThrowIfNull(stream); stream.Close(); } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index a4661dcbd7..5d55374373 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -118,8 +118,7 @@ namespace osu.Game.Online.Chat /// public void OpenChannel(string name) { - if (name == null) - throw new ArgumentNullException(nameof(name)); + ArgumentNullException.ThrowIfNull(name); CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) ?? throw new ChannelNotFoundException(name); } @@ -130,8 +129,7 @@ namespace osu.Game.Online.Chat /// The user the private channel is opened with. public void OpenPrivateChannel(APIUser user) { - if (user == null) - throw new ArgumentNullException(nameof(user)); + ArgumentNullException.ThrowIfNull(user); if (user.Id == api.LocalUser.Value.Id) return; diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index 90863a90a2..671d649dcf 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -70,7 +70,7 @@ namespace osu.Game.Overlays /// are specified, the header will instantly display them. public void ShowBuild([NotNull] APIChangelogBuild build) { - if (build == null) throw new ArgumentNullException(nameof(build)); + ArgumentNullException.ThrowIfNull(build); Current.Value = build; Show(); @@ -78,8 +78,8 @@ namespace osu.Game.Overlays public void ShowBuild([NotNull] string updateStream, [NotNull] string version) { - if (updateStream == null) throw new ArgumentNullException(nameof(updateStream)); - if (version == null) throw new ArgumentNullException(nameof(version)); + ArgumentNullException.ThrowIfNull(updateStream); + ArgumentNullException.ThrowIfNull(version); performAfterFetch(() => { diff --git a/osu.Game/Overlays/OnScreenDisplay.cs b/osu.Game/Overlays/OnScreenDisplay.cs index d60077cfa9..4f2dba7b2c 100644 --- a/osu.Game/Overlays/OnScreenDisplay.cs +++ b/osu.Game/Overlays/OnScreenDisplay.cs @@ -58,7 +58,7 @@ namespace osu.Game.Overlays /// If is already being tracked from the same . public void BeginTracking(object source, ITrackableConfigManager configManager) { - if (configManager == null) throw new ArgumentNullException(nameof(configManager)); + ArgumentNullException.ThrowIfNull(configManager); if (trackedConfigManagers.ContainsKey((source, configManager))) throw new InvalidOperationException($"{nameof(configManager)} is already registered."); @@ -82,7 +82,7 @@ namespace osu.Game.Overlays /// If is not being tracked from the same . public void StopTracking(object source, ITrackableConfigManager configManager) { - if (configManager == null) throw new ArgumentNullException(nameof(configManager)); + ArgumentNullException.ThrowIfNull(configManager); if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing)) return; diff --git a/osu.Game/Overlays/Volume/MuteButton.cs b/osu.Game/Overlays/Volume/MuteButton.cs index 3bea1c840e..9cc346a38b 100644 --- a/osu.Game/Overlays/Volume/MuteButton.cs +++ b/osu.Game/Overlays/Volume/MuteButton.cs @@ -28,8 +28,7 @@ namespace osu.Game.Overlays.Volume get => current; set { - if (value == null) - throw new ArgumentNullException(nameof(value)); + ArgumentNullException.ThrowIfNull(value); current.UnbindBindings(); current.BindTo(value); diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs index 9d9c10b3ea..38ced4c9e7 100644 --- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs +++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs @@ -126,8 +126,7 @@ namespace osu.Game.Rulesets.Mods get => this; set { - if (value == null) - throw new ArgumentNullException(nameof(value)); + ArgumentNullException.ThrowIfNull(value); if (currentBound != null) UnbindFrom(currentBound); BindTo(currentBound = value); diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 096132d024..be5a7f71e7 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -208,8 +208,7 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public void Apply([NotNull] HitObject hitObject) { - if (hitObject == null) - throw new ArgumentNullException($"Cannot apply a null {nameof(HitObject)}."); + ArgumentNullException.ThrowIfNull(hitObject); Apply(new SyntheticHitObjectEntry(hitObject)); } diff --git a/osu.Game/Rulesets/UI/JudgementContainer.cs b/osu.Game/Rulesets/UI/JudgementContainer.cs index 8381e6d6b5..7181e80206 100644 --- a/osu.Game/Rulesets/UI/JudgementContainer.cs +++ b/osu.Game/Rulesets/UI/JudgementContainer.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.UI { public override void Add(T judgement) { - if (judgement == null) throw new ArgumentNullException(nameof(judgement)); + ArgumentNullException.ThrowIfNull(judgement); // remove any existing judgements for the judged object. // this can be the case when rewinding. diff --git a/osu.Game/Scoring/ScoreImporter.cs b/osu.Game/Scoring/ScoreImporter.cs index 797d80b7fa..a3d7fe5de0 100644 --- a/osu.Game/Scoring/ScoreImporter.cs +++ b/osu.Game/Scoring/ScoreImporter.cs @@ -71,8 +71,8 @@ namespace osu.Game.Scoring // These properties are known to be non-null, but these final checks ensure a null hasn't come from somewhere (or the refetch has failed). // Under no circumstance do we want these to be written to realm as null. - if (model.BeatmapInfo == null) throw new ArgumentNullException(nameof(model.BeatmapInfo)); - if (model.Ruleset == null) throw new ArgumentNullException(nameof(model.Ruleset)); + ArgumentNullException.ThrowIfNull(model.BeatmapInfo); + ArgumentNullException.ThrowIfNull(model.Ruleset); PopulateMaximumStatistics(model); diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs index c67850bdf6..5000a97b3d 100644 --- a/osu.Game/Screens/Menu/LogoVisualisation.cs +++ b/osu.Game/Screens/Menu/LogoVisualisation.cs @@ -147,7 +147,7 @@ namespace osu.Game.Screens.Menu private void addAmplitudesFromSource(IHasAmplitudes source) { - if (source == null) throw new ArgumentNullException(nameof(source)); + ArgumentNullException.ThrowIfNull(source); var amplitudes = source.CurrentAmplitudes.FrequencyAmplitudes.Span; diff --git a/osu.Game/Screens/Play/HUD/ModDisplay.cs b/osu.Game/Screens/Play/HUD/ModDisplay.cs index 3b50a22e3c..8b2b8f9464 100644 --- a/osu.Game/Screens/Play/HUD/ModDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ModDisplay.cs @@ -33,8 +33,7 @@ namespace osu.Game.Screens.Play.HUD get => current.Current; set { - if (value == null) - throw new ArgumentNullException(nameof(value)); + ArgumentNullException.ThrowIfNull(value); current.Current = value; } diff --git a/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs b/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs index 23030e640b..38027c64ac 100644 --- a/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs +++ b/osu.Game/Screens/Play/HUD/ModFlowDisplay.cs @@ -30,8 +30,7 @@ namespace osu.Game.Screens.Play.HUD get => current.Current; set { - if (value == null) - throw new ArgumentNullException(nameof(value)); + ArgumentNullException.ThrowIfNull(value); current.Current = value; } diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs index d9ad3cfaf7..bb50d4a539 100644 --- a/osu.Game/Screens/Play/KeyCounterDisplay.cs +++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Play public override void Add(KeyCounter key) { - if (key == null) throw new ArgumentNullException(nameof(key)); + ArgumentNullException.ThrowIfNull(key); base.Add(key); key.IsCounting = IsCounting; diff --git a/osu.Game/Users/Drawables/DrawableFlag.cs b/osu.Game/Users/Drawables/DrawableFlag.cs index 0d209f47e8..929a29251d 100644 --- a/osu.Game/Users/Drawables/DrawableFlag.cs +++ b/osu.Game/Users/Drawables/DrawableFlag.cs @@ -27,8 +27,7 @@ namespace osu.Game.Users.Drawables [BackgroundDependencyLoader] private void load(TextureStore ts) { - if (ts == null) - throw new ArgumentNullException(nameof(ts)); + ArgumentNullException.ThrowIfNull(ts); string textureName = countryCode == CountryCode.Unknown ? "__" : countryCode.ToString(); Texture = ts.Get($@"Flags/{textureName}") ?? ts.Get(@"Flags/__"); diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index e7af127a30..2f7232d5ea 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -36,8 +36,7 @@ namespace osu.Game.Users protected UserPanel(APIUser user) : base(HoverSampleSet.Button) { - if (user == null) - throw new ArgumentNullException(nameof(user)); + ArgumentNullException.ThrowIfNull(user); User = user; } From a6650136269a8d8841fabea30bf9310fc07e639f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 23 Dec 2022 00:56:37 +0300 Subject: [PATCH 2665/2686] Add failing test case --- .../TestSceneZoomableScrollContainer.cs | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs index 6bc2922253..a141e4d431 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneZoomableScrollContainer.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Editing { public partial class TestSceneZoomableScrollContainer : OsuManualInputManagerTestScene { - private ZoomableScrollContainer scrollContainer; + private TestZoomableScrollContainer scrollContainer; private Drawable innerBox; [SetUpSteps] @@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Editing RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(30) }, - scrollContainer = new ZoomableScrollContainer(1, 60, 1) + scrollContainer = new TestZoomableScrollContainer(1, 60, 1) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -93,6 +93,14 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("Inner container width matches scroll container", () => innerBox.DrawWidth == scrollContainer.DrawWidth); } + [Test] + public void TestWidthUpdatesOnSecondZoomSetup() + { + AddAssert("Inner container width = 1x", () => innerBox.DrawWidth == scrollContainer.DrawWidth); + AddStep("reload zoom", () => scrollContainer.SetupZoom(10, 10, 60)); + AddAssert("Inner container width = 10x", () => innerBox.DrawWidth == scrollContainer.DrawWidth * 10); + } + [Test] public void TestZoom0() { @@ -190,5 +198,15 @@ namespace osu.Game.Tests.Visual.Editing private Quad scrollQuad => scrollContainer.ScreenSpaceDrawQuad; private Quad boxQuad => innerBox.ScreenSpaceDrawQuad; + + private partial class TestZoomableScrollContainer : ZoomableScrollContainer + { + public TestZoomableScrollContainer(int minimum, float maximum, float initial) + : base(minimum, maximum, initial) + { + } + + public new void SetupZoom(float initial, float minimum, float maximum) => base.SetupZoom(initial, minimum, maximum); + } } } From 0cb9b7983498cbc313a070174868a487a254e247 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 23 Dec 2022 00:56:02 +0300 Subject: [PATCH 2666/2686] Fix `ZoomableScrollContainer` potentially not updating content width on setup --- .../Compose/Components/Timeline/ZoomableScrollContainer.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index 28f7731354..951f4129d4 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -99,9 +99,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline minZoom = minimum; maxZoom = maximum; - CurrentZoom = zoomTarget = initial; - isZoomSetUp = true; + CurrentZoom = zoomTarget = initial; + zoomedContentWidthCache.Invalidate(); + + isZoomSetUp = true; zoomedContent.Show(); } From 5eccafe19046c331468c6c6e2c9b47c84ead38a2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Dec 2022 16:45:40 +0800 Subject: [PATCH 2667/2686] Fix wiki overlay showing error message when load is cancelled --- osu.Game/Overlays/WikiOverlay.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index a06c180948..9ccd0af2b6 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -118,7 +118,11 @@ namespace osu.Game.Overlays Loading.Show(); request.Success += response => Schedule(() => onSuccess(response)); - request.Failure += _ => Schedule(onFail); + request.Failure += ex => + { + if (ex is not OperationCanceledException) + Schedule(onFail); + }; api.PerformAsync(request); } From a677c8be0651e3440f0f21a0546160100f9be035 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Dec 2022 21:17:42 +0800 Subject: [PATCH 2668/2686] Change path on error --- osu.Game/Overlays/WikiOverlay.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 9ccd0af2b6..a9a131e481 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -21,6 +21,8 @@ namespace osu.Game.Overlays { private const string index_path = @"main_page"; + public string CurrentPath => path.Value; + private readonly Bindable path = new Bindable(index_path); private readonly Bindable wikiData = new Bindable(); @@ -105,6 +107,9 @@ namespace osu.Game.Overlays if (e.NewValue == wikiData.Value?.Path) return; + if (e.NewValue == "error") + return; + cancellationToken?.Cancel(); request?.Cancel(); @@ -152,6 +157,7 @@ namespace osu.Game.Overlays private void onFail() { + path.Value = "error"; LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/", $"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page).")); } From 4a69cb4aae964ea8bd61178337e2b203a0e5cdc8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 23 Dec 2022 21:19:04 +0800 Subject: [PATCH 2669/2686] Add test coverage of wiki cancellation not causing error --- osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs index 620fd710e3..4ad03c052f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.Linq; using System.Net; using NUnit.Framework; using osu.Game.Online.API; @@ -29,6 +30,15 @@ namespace osu.Game.Tests.Visual.Online AddStep("Show main page", () => wiki.Show()); } + [Test] + public void TestCancellationDoesntShowError() + { + AddStep("Show main page", () => wiki.Show()); + AddStep("Show another page", () => wiki.ShowPage("Article_styling_criteria/Formatting")); + + AddUntilStep("Current path is not error", () => wiki.CurrentPath != "error"); + } + [Test] public void TestArticlePage() { From 137a32ade66cf6bc2b3e0a7cffcfbe1049a072c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 23 Dec 2022 16:39:35 +0100 Subject: [PATCH 2670/2686] Remove unused using directive --- osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs index 4ad03c052f..806d231cb4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs @@ -4,7 +4,6 @@ #nullable disable using System; -using System.Linq; using System.Net; using NUnit.Framework; using osu.Game.Online.API; From 3dfbb47b010aa6351951310dc9b008ce3cd2b6cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 23 Dec 2022 16:42:24 +0100 Subject: [PATCH 2671/2686] Add test coverage for wrong error message --- osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs index 806d231cb4..b0e4303ca4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs @@ -4,8 +4,11 @@ #nullable disable using System; +using System.Linq; using System.Net; using NUnit.Framework; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Testing; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -65,7 +68,9 @@ namespace osu.Game.Tests.Visual.Online public void TestErrorPage() { setUpWikiResponse(responseArticlePage); - AddStep("Show Error Page", () => wiki.ShowPage("Error")); + AddStep("Show nonexistent page", () => wiki.ShowPage("This_page_will_error_out")); + AddUntilStep("Wait for error page", () => wiki.CurrentPath == "error"); + AddUntilStep("Error message correct", () => wiki.ChildrenOfType().Any(text => text.Text == "\"This_page_will_error_out\".")); } private void setUpWikiResponse(APIWikiPage r, string redirectionPath = null) From 9a2cc043611ab6e78feef7c18958747baa795061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 23 Dec 2022 16:42:46 +0100 Subject: [PATCH 2672/2686] Fix wrong path being used in fail handler --- osu.Game/Overlays/WikiOverlay.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index a9a131e481..88dc2cd7a4 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -126,7 +126,7 @@ namespace osu.Game.Overlays request.Failure += ex => { if (ex is not OperationCanceledException) - Schedule(onFail); + Schedule(onFail, request.Path); }; api.PerformAsync(request); @@ -155,11 +155,11 @@ namespace osu.Game.Overlays } } - private void onFail() + private void onFail(string originalPath) { path.Value = "error"; LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/", - $"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page).")); + $"Something went wrong when trying to fetch page \"{originalPath}\".\n\n[Return to the main page](Main_Page).")); } private void showParentPage() From 727ac00f6d5b744c6e83be66b7a6a98c7d6a984c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 24 Dec 2022 03:22:04 +0800 Subject: [PATCH 2673/2686] Combine base class for `JudgementPiece` --- .../Skinning/Argon/ArgonJudgementPiece.cs | 11 ++----- .../Skinning/Argon/ArgonJudgementPiece.cs | 11 ++----- .../Skinning/Argon/ArgonJudgementPiece.cs | 11 ++----- .../Skinning/Argon/ArgonJudgementPiece.cs | 11 ++----- .../Judgements/DefaultJudgementPiece.cs | 12 ++------ .../Rulesets/Judgements/JudgementPiece.cs | 29 +++++++++++++++++++ 6 files changed, 39 insertions(+), 46 deletions(-) create mode 100644 osu.Game/Rulesets/Judgements/JudgementPiece.cs diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs index 82d10e500d..5cb03f6536 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs @@ -3,11 +3,9 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -18,20 +16,16 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Argon { - public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class ArgonJudgementPiece : JudgementPiece, IAnimatableJudgement { - protected readonly HitResult Result; - - protected SpriteText JudgementText { get; private set; } = null!; - private RingExplosion? ringExplosion; [Resolved] private OsuColour colours { get; set; } = null!; public ArgonJudgementPiece(HitResult result) + : base(result) { - Result = result; Origin = Anchor.Centre; Y = 160; } @@ -47,7 +41,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Argon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = Result.GetDescription().ToUpperInvariant(), Colour = colours.ForHitResult(Result), Blending = BlendingParameters.Additive, Spacing = new Vector2(10, 0), diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs index 2dbf475c7e..870a142ca7 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs @@ -3,11 +3,9 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -18,20 +16,16 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Mania.Skinning.Argon { - public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class ArgonJudgementPiece : JudgementPiece, IAnimatableJudgement { - protected readonly HitResult Result; - - protected SpriteText JudgementText { get; private set; } = null!; - private RingExplosion? ringExplosion; [Resolved] private OsuColour colours { get; set; } = null!; public ArgonJudgementPiece(HitResult result) + : base(result) { - Result = result; Origin = Anchor.Centre; Y = 160; } @@ -47,7 +41,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = Result.GetDescription().ToUpperInvariant(), Colour = colours.ForHitResult(Result), Blending = BlendingParameters.Additive, Spacing = new Vector2(10, 0), diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs index f5f410210b..7b1a0d8d08 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs @@ -3,10 +3,8 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -17,20 +15,16 @@ using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Argon { - public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class ArgonJudgementPiece : JudgementPiece, IAnimatableJudgement { - protected readonly HitResult Result; - - protected SpriteText JudgementText { get; private set; } = null!; - private RingExplosion? ringExplosion; [Resolved] private OsuColour colours { get; set; } = null!; public ArgonJudgementPiece(HitResult result) + : base(result) { - Result = result; Origin = Anchor.Centre; } @@ -45,7 +39,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = Result.GetDescription().ToUpperInvariant(), Colour = colours.ForHitResult(Result), Blending = BlendingParameters.Additive, Spacing = new Vector2(5, 0), diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs index 6756001089..e8240911b0 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs @@ -3,11 +3,9 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -18,20 +16,16 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Taiko.Skinning.Argon { - public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class ArgonJudgementPiece : JudgementPiece, IAnimatableJudgement { - protected readonly HitResult Result; - - protected SpriteText JudgementText { get; private set; } = null!; - private RingExplosion? ringExplosion; [Resolved] private OsuColour colours { get; set; } = null!; public ArgonJudgementPiece(HitResult result) + : base(result) { - Result = result; RelativePositionAxes = Axes.Both; RelativeSizeAxes = Axes.Both; } @@ -45,7 +39,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = Result.GetDescription().ToUpperInvariant(), Colour = colours.ForHitResult(Result), Blending = BlendingParameters.Additive, Spacing = new Vector2(10, 0), diff --git a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs index 2b8bd08ede..485e2b409d 100644 --- a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs +++ b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs @@ -4,10 +4,7 @@ #nullable disable using osu.Framework.Allocation; -using osu.Framework.Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Scoring; @@ -15,18 +12,14 @@ using osuTK; namespace osu.Game.Rulesets.Judgements { - public partial class DefaultJudgementPiece : CompositeDrawable, IAnimatableJudgement + public partial class DefaultJudgementPiece : JudgementPiece, IAnimatableJudgement { - protected readonly HitResult Result; - - protected SpriteText JudgementText { get; private set; } - [Resolved] private OsuColour colours { get; set; } public DefaultJudgementPiece(HitResult result) + : base(result) { - Result = result; Origin = Anchor.Centre; } @@ -41,7 +34,6 @@ namespace osu.Game.Rulesets.Judgements { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = Result.GetDescription().ToUpperInvariant(), Colour = colours.ForHitResult(Result), Font = OsuFont.Numeric.With(size: 20), Scale = new Vector2(0.85f, 1), diff --git a/osu.Game/Rulesets/Judgements/JudgementPiece.cs b/osu.Game/Rulesets/Judgements/JudgementPiece.cs new file mode 100644 index 0000000000..4e9b495cb5 --- /dev/null +++ b/osu.Game/Rulesets/Judgements/JudgementPiece.cs @@ -0,0 +1,29 @@ +// 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.Extensions; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Rulesets.Scoring; + +namespace osu.Game.Rulesets.Judgements +{ + public abstract partial class JudgementPiece : CompositeDrawable + { + protected readonly HitResult Result; + + protected SpriteText JudgementText { get; set; } = null!; + + protected JudgementPiece(HitResult result) + { + Result = result; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + JudgementText.Text = Result.GetDescription().ToUpperInvariant(); + } + } +} From e8a0f8996cfbf76747647c2ab1a0573007393063 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 24 Dec 2022 03:35:27 +0800 Subject: [PATCH 2674/2686] Remove unused osu!catch `ArgonJudgementPiece` --- .../Skinning/Argon/ArgonJudgementPiece.cs | 186 ------------------ 1 file changed, 186 deletions(-) delete mode 100644 osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs diff --git a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs deleted file mode 100644 index 5cb03f6536..0000000000 --- a/osu.Game.Rulesets.Catch/Skinning/Argon/ArgonJudgementPiece.cs +++ /dev/null @@ -1,186 +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 osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Utils; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Scoring; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Rulesets.Catch.Skinning.Argon -{ - public partial class ArgonJudgementPiece : JudgementPiece, IAnimatableJudgement - { - private RingExplosion? ringExplosion; - - [Resolved] - private OsuColour colours { get; set; } = null!; - - public ArgonJudgementPiece(HitResult result) - : base(result) - { - Origin = Anchor.Centre; - Y = 160; - } - - [BackgroundDependencyLoader] - private void load() - { - AutoSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - JudgementText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.ForHitResult(Result), - Blending = BlendingParameters.Additive, - Spacing = new Vector2(10, 0), - Font = OsuFont.Default.With(size: 28, weight: FontWeight.Regular), - }, - }; - - if (Result.IsHit()) - { - AddInternal(ringExplosion = new RingExplosion(Result) - { - Colour = colours.ForHitResult(Result), - }); - } - } - - /// - /// Plays the default animation for this judgement piece. - /// - /// - /// The base implementation only handles fade (for all result types) and misses. - /// Individual rulesets are recommended to implement their appropriate hit animations. - /// - public virtual void PlayAnimation() - { - switch (Result) - { - default: - JudgementText - .ScaleTo(Vector2.One) - .ScaleTo(new Vector2(1.4f), 1800, Easing.OutQuint); - break; - - case HitResult.Miss: - this.ScaleTo(1.6f); - this.ScaleTo(1, 100, Easing.In); - - this.MoveTo(Vector2.Zero); - this.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint); - - this.RotateTo(0); - this.RotateTo(40, 800, Easing.InQuint); - break; - } - - this.FadeOutFromOne(800); - - ringExplosion?.PlayAnimation(); - } - - public Drawable? GetAboveHitObjectsProxiedContent() => null; - - private partial class RingExplosion : CompositeDrawable - { - private readonly float travel = 52; - - public RingExplosion(HitResult result) - { - const float thickness = 4; - - const float small_size = 9; - const float large_size = 14; - - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - - Blending = BlendingParameters.Additive; - - int countSmall = 0; - int countLarge = 0; - - switch (result) - { - case HitResult.Meh: - countSmall = 3; - travel *= 0.3f; - break; - - case HitResult.Ok: - case HitResult.Good: - countSmall = 4; - travel *= 0.6f; - break; - - case HitResult.Great: - case HitResult.Perfect: - countSmall = 4; - countLarge = 4; - break; - } - - for (int i = 0; i < countSmall; i++) - AddInternal(new RingPiece(thickness) { Size = new Vector2(small_size) }); - - for (int i = 0; i < countLarge; i++) - AddInternal(new RingPiece(thickness) { Size = new Vector2(large_size) }); - } - - public void PlayAnimation() - { - foreach (var c in InternalChildren) - { - const float start_position_ratio = 0.3f; - - float direction = RNG.NextSingle(0, 360); - float distance = RNG.NextSingle(travel / 2, travel); - - c.MoveTo(new Vector2( - MathF.Cos(direction) * distance * start_position_ratio, - MathF.Sin(direction) * distance * start_position_ratio - )); - - c.MoveTo(new Vector2( - MathF.Cos(direction) * distance, - MathF.Sin(direction) * distance - ), 600, Easing.OutQuint); - } - - this.FadeOutFromOne(1000, Easing.OutQuint); - } - - public partial class RingPiece : CircularContainer - { - public RingPiece(float thickness = 9) - { - Anchor = Anchor.Centre; - Origin = Anchor.Centre; - - Masking = true; - BorderThickness = thickness; - BorderColour = Color4.White; - - Child = new Box - { - AlwaysPresent = true, - Alpha = 0, - RelativeSizeAxes = Axes.Both - }; - } - } - } - } -} From 03603f8b548bc6869dac942543db678edf9ecc7a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 24 Dec 2022 03:35:44 +0800 Subject: [PATCH 2675/2686] Don't show great or higher judgements when using argon "pro" skin --- .../Skinning/Argon/ManiaArgonSkinTransformer.cs | 4 ++++ .../Skinning/Argon/OsuArgonSkinTransformer.cs | 4 ++++ .../Skinning/Argon/TaikoArgonSkinTransformer.cs | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs index eb7f63fbe2..057b7eb0d9 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ManiaArgonSkinTransformer.cs @@ -27,6 +27,10 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon switch (lookup) { case GameplaySkinComponentLookup resultComponent: + // This should eventually be moved to a skin setting, when supported. + if (Skin is ArgonProSkin && resultComponent.Component >= HitResult.Great) + return Drawable.Empty(); + return new ArgonJudgementPiece(resultComponent.Component); case ManiaSkinComponentLookup maniaComponent: diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs index 86194d2c43..f98a47097d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/OsuArgonSkinTransformer.cs @@ -19,6 +19,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon switch (lookup) { case GameplaySkinComponentLookup resultComponent: + // This should eventually be moved to a skin setting, when supported. + if (Skin is ArgonProSkin && resultComponent.Component >= HitResult.Great) + return Drawable.Empty(); + return new ArgonJudgementPiece(resultComponent.Component); case OsuSkinComponentLookup osuComponent: diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs index a5d091a1c8..780018af4e 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/TaikoArgonSkinTransformer.cs @@ -19,6 +19,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon switch (component) { case GameplaySkinComponentLookup resultComponent: + // This should eventually be moved to a skin setting, when supported. + if (Skin is ArgonProSkin && resultComponent.Component >= HitResult.Great) + return Drawable.Empty(); + return new ArgonJudgementPiece(resultComponent.Component); case TaikoSkinComponentLookup taikoComponent: From 5e9fb1063a9ad5c4775205497cd5a4904f01c699 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 24 Dec 2022 12:22:36 +0800 Subject: [PATCH 2676/2686] Move judgement text creation to base class and tidy things up --- .../Skinning/Argon/ArgonJudgementPiece.cs | 28 ++++++++--------- .../Skinning/Argon/ArgonJudgementPiece.cs | 28 ++++++++--------- .../Skinning/Argon/ArgonJudgementPiece.cs | 26 ++++++++-------- .../Judgements/DefaultJudgementPiece.cs | 30 +++++++------------ .../Rulesets/Judgements/JudgementPiece.cs | 15 ++++++++-- 5 files changed, 61 insertions(+), 66 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs index 870a142ca7..4ce3c50f7c 100644 --- a/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Mania/Skinning/Argon/ArgonJudgementPiece.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -26,6 +27,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon public ArgonJudgementPiece(HitResult result) : base(result) { + AutoSizeAxes = Axes.Both; + Origin = Anchor.Centre; Y = 160; } @@ -33,21 +36,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon [BackgroundDependencyLoader] private void load() { - AutoSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - JudgementText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.ForHitResult(Result), - Blending = BlendingParameters.Additive, - Spacing = new Vector2(10, 0), - Font = OsuFont.Default.With(size: 28, weight: FontWeight.Regular), - }, - }; - if (Result.IsHit()) { AddInternal(ringExplosion = new RingExplosion(Result) @@ -57,6 +45,16 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon } } + protected override SpriteText CreateJudgementText() => + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Spacing = new Vector2(10, 0), + Font = OsuFont.Default.With(size: 28, weight: FontWeight.Regular), + }; + /// /// Plays the default animation for this judgement piece. /// diff --git a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs index 7b1a0d8d08..6f55d93eff 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Argon/ArgonJudgementPiece.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -25,27 +26,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon public ArgonJudgementPiece(HitResult result) : base(result) { + AutoSizeAxes = Axes.Both; + Origin = Anchor.Centre; } [BackgroundDependencyLoader] private void load() { - AutoSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - JudgementText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.ForHitResult(Result), - Blending = BlendingParameters.Additive, - Spacing = new Vector2(5, 0), - Font = OsuFont.Default.With(size: 20, weight: FontWeight.Bold), - }, - }; - if (Result.IsHit()) { AddInternal(ringExplosion = new RingExplosion(Result) @@ -55,6 +43,16 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon } } + protected override SpriteText CreateJudgementText() => + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Spacing = new Vector2(5, 0), + Font = OsuFont.Default.With(size: 20, weight: FontWeight.Bold), + }; + /// /// Plays the default animation for this judgement piece. /// diff --git a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs index e8240911b0..bbd62ff85b 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Argon/ArgonJudgementPiece.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -33,20 +34,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon [BackgroundDependencyLoader] private void load() { - InternalChildren = new Drawable[] - { - JudgementText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.ForHitResult(Result), - Blending = BlendingParameters.Additive, - Spacing = new Vector2(10, 0), - RelativePositionAxes = Axes.Both, - Font = OsuFont.Default.With(size: 20, weight: FontWeight.Regular), - }, - }; - if (Result.IsHit()) { AddInternal(ringExplosion = new RingExplosion(Result) @@ -57,6 +44,17 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon } } + protected override SpriteText CreateJudgementText() => + new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Blending = BlendingParameters.Additive, + Spacing = new Vector2(10, 0), + RelativePositionAxes = Axes.Both, + Font = OsuFont.Default.With(size: 20, weight: FontWeight.Regular), + }; + /// /// Plays the default animation for this judgement piece. /// diff --git a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs index 485e2b409d..6551752826 100644 --- a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs +++ b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.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. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Scoring; @@ -15,31 +14,24 @@ namespace osu.Game.Rulesets.Judgements public partial class DefaultJudgementPiece : JudgementPiece, IAnimatableJudgement { [Resolved] - private OsuColour colours { get; set; } + private OsuColour colours { get; set; } = null!; public DefaultJudgementPiece(HitResult result) : base(result) { + AutoSizeAxes = Axes.Both; + Origin = Anchor.Centre; } - [BackgroundDependencyLoader] - private void load() - { - AutoSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] + protected override SpriteText CreateJudgementText() => + new OsuSpriteText { - JudgementText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Colour = colours.ForHitResult(Result), - Font = OsuFont.Numeric.With(size: 20), - Scale = new Vector2(0.85f, 1), - } + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.Numeric.With(size: 20), + Scale = new Vector2(0.85f, 1), }; - } /// /// Plays the default animation for this judgement piece. @@ -67,6 +59,6 @@ namespace osu.Game.Rulesets.Judgements this.FadeOutFromOne(800); } - public Drawable GetAboveHitObjectsProxiedContent() => null; + public Drawable? GetAboveHitObjectsProxiedContent() => null; } } diff --git a/osu.Game/Rulesets/Judgements/JudgementPiece.cs b/osu.Game/Rulesets/Judgements/JudgementPiece.cs index 4e9b495cb5..9c31c6aa34 100644 --- a/osu.Game/Rulesets/Judgements/JudgementPiece.cs +++ b/osu.Game/Rulesets/Judgements/JudgementPiece.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Judgements @@ -12,18 +14,25 @@ namespace osu.Game.Rulesets.Judgements { protected readonly HitResult Result; - protected SpriteText JudgementText { get; set; } = null!; + protected SpriteText JudgementText { get; private set; } = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; protected JudgementPiece(HitResult result) { Result = result; } - protected override void LoadComplete() + [BackgroundDependencyLoader] + private void load() { - base.LoadComplete(); + JudgementText = CreateJudgementText(); + JudgementText.Colour = colours.ForHitResult(Result); JudgementText.Text = Result.GetDescription().ToUpperInvariant(); } + + protected abstract SpriteText CreateJudgementText(); } } From 91bde14fb345c034589738e8361fd5ad39df991a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 24 Dec 2022 15:42:22 +0800 Subject: [PATCH 2677/2686] Add button to settings to show lazer upgrade guide --- .../Settings/Sections/GeneralSection.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index c62d44fd30..2ca932f2ac 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -1,12 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; +using osu.Game.Graphics; using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.General; @@ -15,7 +14,10 @@ namespace osu.Game.Overlays.Settings.Sections public partial class GeneralSection : SettingsSection { [Resolved(CanBeNull = true)] - private FirstRunSetupOverlay firstRunSetupOverlay { get; set; } + private FirstRunSetupOverlay? firstRunSetupOverlay { get; set; } + + [Resolved(CanBeNull = true)] + private OsuGame? game { get; set; } public override LocalisableString Header => GeneralSettingsStrings.GeneralSectionHeader; @@ -24,15 +26,24 @@ namespace osu.Game.Overlays.Settings.Sections Icon = FontAwesome.Solid.Cog }; - public GeneralSection() + [BackgroundDependencyLoader] + private void load(OsuColour colours) { Children = new Drawable[] { new SettingsButton { Text = GeneralSettingsStrings.RunSetupWizard, + TooltipText = FirstRunSetupOverlayStrings.FirstRunSetupDescription, Action = () => firstRunSetupOverlay?.Show(), }, + new SettingsButton + { + Text = "Learn more about lazer", + TooltipText = "Check out the feature comparison and FAQ", + BackgroundColour = colours.YellowDark, + Action = () => game?.ShowWiki(@"Help_centre/Upgrading_to_lazer") + }, new LanguageSettings(), new UpdateSettings(), }; From f973befcd4f0f24701917117b5a9fe41d345b7fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 24 Dec 2022 09:34:30 +0100 Subject: [PATCH 2678/2686] Remove unused resolved member --- osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs index 6551752826..d5f586dc35 100644 --- a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs +++ b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs @@ -1,7 +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.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; @@ -13,9 +12,6 @@ namespace osu.Game.Rulesets.Judgements { public partial class DefaultJudgementPiece : JudgementPiece, IAnimatableJudgement { - [Resolved] - private OsuColour colours { get; set; } = null!; - public DefaultJudgementPiece(HitResult result) : base(result) { From 80de5dac66776d9da6348ff60421bb1e0c66a49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 24 Dec 2022 09:37:40 +0100 Subject: [PATCH 2679/2686] Fix judgement text never being added to hierarchy --- osu.Game/Rulesets/Judgements/JudgementPiece.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Judgements/JudgementPiece.cs b/osu.Game/Rulesets/Judgements/JudgementPiece.cs index 9c31c6aa34..03f211c318 100644 --- a/osu.Game/Rulesets/Judgements/JudgementPiece.cs +++ b/osu.Game/Rulesets/Judgements/JudgementPiece.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Judgements [BackgroundDependencyLoader] private void load() { - JudgementText = CreateJudgementText(); + AddInternal(JudgementText = CreateJudgementText()); JudgementText.Colour = colours.ForHitResult(Result); JudgementText.Text = Result.GetDescription().ToUpperInvariant(); From 2c060ac8d44bbf0857e3177cbfd9ab4babf332fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 24 Dec 2022 17:32:04 +0800 Subject: [PATCH 2680/2686] Add localisation support for new button's strings --- osu.Game/Localisation/GeneralSettingsStrings.cs | 10 ++++++++++ osu.Game/Overlays/Settings/Sections/GeneralSection.cs | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index 3278b20983..a525af508b 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -64,6 +64,16 @@ namespace osu.Game.Localisation /// public static LocalisableString RunSetupWizard => new TranslatableString(getKey(@"run_setup_wizard"), @"Run setup wizard"); + /// + /// "Learn more about lazer" + /// + public static LocalisableString LearnMoreAboutLazer => new TranslatableString(getKey(@"learn_more_about_lazer"), @"Learn more about lazer"); + + /// + /// "Check out the feature comparison and FAQ" + /// + public static LocalisableString LearnMoreAboutLazerTooltip => new TranslatableString(getKey(@"check_out_the_feature_comparison"), @"Check out the feature comparison and FAQ"); + /// /// "You are running the latest release ({0})" /// diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 2ca932f2ac..84c1f3cfb6 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -39,8 +39,8 @@ namespace osu.Game.Overlays.Settings.Sections }, new SettingsButton { - Text = "Learn more about lazer", - TooltipText = "Check out the feature comparison and FAQ", + Text = GeneralSectionStrings.LearnMoreAboutLazer, + TooltipText = GeneralSectionStrings.CheckOutTheFeatureComparison, BackgroundColour = colours.YellowDark, Action = () => game?.ShowWiki(@"Help_centre/Upgrading_to_lazer") }, From 301eb71e22dc81e88d0537ac1299ce224648f81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 24 Dec 2022 10:39:05 +0100 Subject: [PATCH 2681/2686] Fix wrong member names --- osu.Game/Overlays/Settings/Sections/GeneralSection.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 84c1f3cfb6..d4fd78f0c8 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -39,8 +39,8 @@ namespace osu.Game.Overlays.Settings.Sections }, new SettingsButton { - Text = GeneralSectionStrings.LearnMoreAboutLazer, - TooltipText = GeneralSectionStrings.CheckOutTheFeatureComparison, + Text = GeneralSettingsStrings.LearnMoreAboutLazer, + TooltipText = GeneralSettingsStrings.LearnMoreAboutLazerTooltip, BackgroundColour = colours.YellowDark, Action = () => game?.ShowWiki(@"Help_centre/Upgrading_to_lazer") }, From d6e079a2b4e09cb80a30189c84a57c9eb3605f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 24 Dec 2022 11:28:46 +0100 Subject: [PATCH 2682/2686] Ignore statistics update requests from third-party rulesets for now --- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 48f39504a3..1209747132 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -8,6 +8,7 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; +using osu.Game.Extensions; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -51,6 +52,9 @@ namespace osu.Game.Online.Solo if (!api.IsLoggedIn) return; + if (!score.Ruleset.IsLegacyRuleset()) + return; + var callback = new StatisticsUpdateCallback(score, onUpdateReady); if (lastProcessedScoreId == score.OnlineID) From fd9110a61e8424384ad90fbea0def6101e3ed430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 24 Dec 2022 13:28:25 +0100 Subject: [PATCH 2683/2686] Fix solo statistics watcher firing requests for invalid user with id 1 Can happen during login flow (see `APIAccess.attemptConnect()`). --- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 1209747132..0dfe8ebb8d 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.ObjectExtensions; @@ -72,11 +71,9 @@ namespace osu.Game.Online.Solo lastProcessedScoreId = null; latestStatistics.Clear(); - if (!api.IsLoggedIn) + if (localUser == null || localUser.OnlineID <= 1) return; - Debug.Assert(localUser != null); - var userRequest = new GetUsersRequest(new[] { localUser.OnlineID }); userRequest.Success += response => Schedule(() => { From 3c26016b61bd43e85c386c69e447665aece584e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 24 Dec 2022 13:30:54 +0100 Subject: [PATCH 2684/2686] Ensure latest stats are cleared on successful profile fetch --- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 0dfe8ebb8d..268483ab91 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -77,6 +77,7 @@ namespace osu.Game.Online.Solo var userRequest = new GetUsersRequest(new[] { localUser.OnlineID }); userRequest.Success += response => Schedule(() => { + latestStatistics.Clear(); foreach (var rulesetStats in response.Users.Single().RulesetsStatistics) latestStatistics.Add(rulesetStats.Key, rulesetStats.Value); }); From 6c4ca387e01fcbbe82b1b29c49e0b0011f2cb1d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 24 Dec 2022 13:42:32 +0100 Subject: [PATCH 2685/2686] Fix wrong handling of missing ruleset statistics --- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 268483ab91..383f6a202d 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -31,7 +31,7 @@ namespace osu.Game.Online.Solo private readonly Dictionary callbacks = new Dictionary(); private long? lastProcessedScoreId; - private readonly Dictionary latestStatistics = new Dictionary(); + private Dictionary? latestStatistics; protected override void LoadComplete() { @@ -69,7 +69,7 @@ namespace osu.Game.Online.Solo { callbacks.Clear(); lastProcessedScoreId = null; - latestStatistics.Clear(); + latestStatistics = null; if (localUser == null || localUser.OnlineID <= 1) return; @@ -77,7 +77,7 @@ namespace osu.Game.Online.Solo var userRequest = new GetUsersRequest(new[] { localUser.OnlineID }); userRequest.Success += response => Schedule(() => { - latestStatistics.Clear(); + latestStatistics = new Dictionary(); foreach (var rulesetStats in response.Users.Single().RulesetsStatistics) latestStatistics.Add(rulesetStats.Key, rulesetStats.Value); }); @@ -109,9 +109,12 @@ namespace osu.Game.Online.Solo { string rulesetName = callback.Score.Ruleset.ShortName; - if (!latestStatistics.TryGetValue(rulesetName, out var latestRulesetStatistics)) + if (latestStatistics == null) return; + latestStatistics.TryGetValue(rulesetName, out UserStatistics? latestRulesetStatistics); + latestRulesetStatistics ??= new UserStatistics(); + var update = new SoloStatisticsUpdate(callback.Score, latestRulesetStatistics, updatedStatistics); callback.OnUpdateReady.Invoke(update); From 78c47a3695a9e8c1bbfa1ef8f07eb7ae2f3df5f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 24 Dec 2022 13:45:04 +0100 Subject: [PATCH 2686/2686] Add callback to dictionary rather than overwrite Attempting to overwrite will henceforth throw an exception. --- osu.Game/Online/Solo/SoloStatisticsWatcher.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs index 383f6a202d..33344044b9 100644 --- a/osu.Game/Online/Solo/SoloStatisticsWatcher.cs +++ b/osu.Game/Online/Solo/SoloStatisticsWatcher.cs @@ -62,7 +62,7 @@ namespace osu.Game.Online.Solo return; } - callbacks[score.OnlineID] = callback; + callbacks.Add(score.OnlineID, callback); }); private void onUserChanged(APIUser? localUser) => Schedule(() =>